summaryrefslogtreecommitdiffstats
path: root/trunk/source
diff options
context:
space:
mode:
authorpeterb12 <peterb12@c06c8d41-db1a-0410-9941-cceddc491573>2005-07-21 02:34:44 +0000
committerpeterb12 <peterb12@c06c8d41-db1a-0410-9941-cceddc491573>2005-07-21 02:34:44 +0000
commit673bdae75485d14f759af597c3c62b99601f9a43 (patch)
tree368103f29fe0ce5dcf98060d9b5faa04590085fb /trunk/source
parent7e900be770db24b0405fd2162491c405a425873e (diff)
downloadcrawl-ref-673bdae75485d14f759af597c3c62b99601f9a43.tar.gz
crawl-ref-673bdae75485d14f759af597c3c62b99601f9a43.zip
Initial revision
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@3 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'trunk/source')
-rw-r--r--trunk/source/AppHdr.h441
-rw-r--r--trunk/source/FixAry.h73
-rw-r--r--trunk/source/FixVec.h133
-rw-r--r--trunk/source/MacString.cc199
-rw-r--r--trunk/source/MacString.h71
-rw-r--r--trunk/source/abl-show.cc2168
-rw-r--r--trunk/source/abl-show.h46
-rw-r--r--trunk/source/abyss.cc379
-rw-r--r--trunk/source/abyss.h37
-rw-r--r--trunk/source/acr.cc3051
-rw-r--r--trunk/source/acrawl.gdtbin0 -> 21643 bytes
-rw-r--r--trunk/source/acrawl.gprbin0 -> 115246 bytes
-rw-r--r--trunk/source/beam.cc4213
-rw-r--r--trunk/source/beam.h94
-rw-r--r--trunk/source/chardump.cc893
-rw-r--r--trunk/source/chardump.h24
-rw-r--r--trunk/source/cloud.cc130
-rw-r--r--trunk/source/cloud.h22
-rw-r--r--trunk/source/command.cc515
-rw-r--r--trunk/source/command.h58
-rw-r--r--trunk/source/crawl.gdtbin0 -> 6182 bytes
-rw-r--r--trunk/source/crawl.gprbin0 -> 11237 bytes
-rw-r--r--trunk/source/debug.cc1701
-rw-r--r--trunk/source/debug.h147
-rw-r--r--trunk/source/decks.cc906
-rw-r--r--trunk/source/decks.h22
-rw-r--r--trunk/source/defines.h160
-rw-r--r--trunk/source/delay.cc549
-rw-r--r--trunk/source/delay.h19
-rw-r--r--trunk/source/describe.cc6689
-rw-r--r--trunk/source/describe.h58
-rw-r--r--trunk/source/direct.cc1195
-rw-r--r--trunk/source/direct.h41
-rw-r--r--trunk/source/dungeon.cc8446
-rw-r--r--trunk/source/dungeon.h49
-rw-r--r--trunk/source/effects.cc1374
-rw-r--r--trunk/source/effects.h92
-rw-r--r--trunk/source/enum.h3116
-rw-r--r--trunk/source/externs.h553
-rw-r--r--trunk/source/fight.cc4014
-rw-r--r--trunk/source/fight.h52
-rw-r--r--trunk/source/files.cc1863
-rw-r--r--trunk/source/files.h67
-rw-r--r--trunk/source/food.cc1303
-rw-r--r--trunk/source/food.h57
-rw-r--r--trunk/source/hiscores.cc1824
-rw-r--r--trunk/source/hiscores.h35
-rw-r--r--trunk/source/initfile.cc968
-rw-r--r--trunk/source/initfile.h40
-rw-r--r--trunk/source/insult.cc672
-rw-r--r--trunk/source/insult.h11
-rw-r--r--trunk/source/invent.cc631
-rw-r--r--trunk/source/invent.h48
-rw-r--r--trunk/source/it_use2.cc523
-rw-r--r--trunk/source/it_use2.h43
-rw-r--r--trunk/source/it_use3.cc1065
-rw-r--r--trunk/source/it_use3.h44
-rw-r--r--trunk/source/item_use.cc3107
-rw-r--r--trunk/source/item_use.h123
-rw-r--r--trunk/source/itemname.cc3196
-rw-r--r--trunk/source/itemname.h156
-rw-r--r--trunk/source/items.cc2551
-rw-r--r--trunk/source/items.h125
-rw-r--r--trunk/source/lev-pand.cc166
-rw-r--r--trunk/source/lev-pand.h30
-rw-r--r--trunk/source/libemx.cc233
-rw-r--r--trunk/source/libemx.h38
-rw-r--r--trunk/source/liblinux.cc757
-rw-r--r--trunk/source/liblinux.h53
-rw-r--r--trunk/source/libmac.cc2114
-rw-r--r--trunk/source/libmac.h91
-rw-r--r--trunk/source/libutil.cc93
-rw-r--r--trunk/source/libutil.h24
-rw-r--r--trunk/source/libw32c.cc753
-rw-r--r--trunk/source/libw32c.h46
-rw-r--r--trunk/source/machdr.h185
-rw-r--r--trunk/source/macro.cc525
-rw-r--r--trunk/source/macro.h40
-rw-r--r--trunk/source/makefile38
-rw-r--r--trunk/source/makefile.bor53
-rw-r--r--trunk/source/makefile.bsd62
-rw-r--r--trunk/source/makefile.dos53
-rw-r--r--trunk/source/makefile.emx53
-rw-r--r--trunk/source/makefile.lnx472
-rw-r--r--trunk/source/makefile.osx67
-rw-r--r--trunk/source/makefile.sgi54
-rw-r--r--trunk/source/makefile.sol3112
-rw-r--r--trunk/source/maps.cc3641
-rw-r--r--trunk/source/maps.h25
-rw-r--r--trunk/source/message.cc526
-rw-r--r--trunk/source/message.h77
-rw-r--r--trunk/source/misc.cc1767
-rw-r--r--trunk/source/misc.h135
-rw-r--r--trunk/source/misc/header10
-rw-r--r--trunk/source/misc/pfix6.pl312
-rw-r--r--trunk/source/mon-data.h3838
-rw-r--r--trunk/source/mon-pick.cc2727
-rw-r--r--trunk/source/mon-pick.h58
-rw-r--r--trunk/source/mon-spll.h734
-rw-r--r--trunk/source/mon-util.cc1983
-rw-r--r--trunk/source/mon-util.h460
-rw-r--r--trunk/source/monplace.cc1300
-rw-r--r--trunk/source/monplace.h79
-rw-r--r--trunk/source/monspeak.cc2325
-rw-r--r--trunk/source/monspeak.h8
-rw-r--r--trunk/source/monstuff.cc4949
-rw-r--r--trunk/source/monstuff.h151
-rw-r--r--trunk/source/mstuff2.cc1665
-rw-r--r--trunk/source/mstuff2.h117
-rw-r--r--trunk/source/mutation.cc2326
-rw-r--r--trunk/source/mutation.h71
-rw-r--r--trunk/source/newgame.cc4430
-rw-r--r--trunk/source/newgame.h24
-rw-r--r--trunk/source/ouch.cc996
-rw-r--r--trunk/source/ouch.h74
-rw-r--r--trunk/source/output.cc539
-rw-r--r--trunk/source/output.h22
-rw-r--r--trunk/source/overmap.cc539
-rw-r--r--trunk/source/overmap.h51
-rw-r--r--trunk/source/player.cc3885
-rw-r--r--trunk/source/player.h446
-rw-r--r--trunk/source/randart.cc1988
-rw-r--r--trunk/source/randart.h111
-rw-r--r--trunk/source/religion.cc2569
-rw-r--r--trunk/source/religion.h116
-rw-r--r--trunk/source/shopping.cc1597
-rw-r--r--trunk/source/shopping.h43
-rw-r--r--trunk/source/skills.cc438
-rw-r--r--trunk/source/skills.h26
-rw-r--r--trunk/source/skills2.cc2365
-rw-r--r--trunk/source/skills2.h95
-rw-r--r--trunk/source/spells1.cc1058
-rw-r--r--trunk/source/spells1.h142
-rw-r--r--trunk/source/spells2.cc1516
-rw-r--r--trunk/source/spells2.h177
-rw-r--r--trunk/source/spells3.cc1090
-rw-r--r--trunk/source/spells3.h142
-rw-r--r--trunk/source/spells4.cc3211
-rw-r--r--trunk/source/spells4.h61
-rw-r--r--trunk/source/spl-book.cc1524
-rw-r--r--trunk/source/spl-book.h63
-rw-r--r--trunk/source/spl-cast.cc3542
-rw-r--r--trunk/source/spl-cast.h49
-rw-r--r--trunk/source/spl-data.h1286
-rw-r--r--trunk/source/spl-util.cc786
-rw-r--r--trunk/source/spl-util.h87
-rw-r--r--trunk/source/stuff.cc661
-rw-r--r--trunk/source/stuff.h197
-rw-r--r--trunk/source/tags.cc1831
-rw-r--r--trunk/source/tags.h97
-rw-r--r--trunk/source/transfor.cc551
-rw-r--r--trunk/source/transfor.h46
-rw-r--r--trunk/source/unrand.h1138
-rw-r--r--trunk/source/version.h51
-rw-r--r--trunk/source/view.cc3524
-rw-r--r--trunk/source/view.h100
-rw-r--r--trunk/source/winhdr.h70
-rw-r--r--trunk/source/wpn-misc.cc268
-rw-r--r--trunk/source/wpn-misc.h67
159 files changed, 142267 insertions, 0 deletions
diff --git a/trunk/source/AppHdr.h b/trunk/source/AppHdr.h
new file mode 100644
index 0000000000..78de443b9d
--- /dev/null
+++ b/trunk/source/AppHdr.h
@@ -0,0 +1,441 @@
+/*
+ * File: AppHdr.h
+ * Summary: Precompiled header used by Crawl.
+ * Written by: Jesse Jones
+ *
+ * Abstract: CodeWarrior and MSVC both support precompiled headers which can
+ * significantly speed up compiles. Unlike CodeWarrior MSVC imposes
+ * some annoying restrictions on precompiled headers: the precompiled
+ * header *must* be the first include in all cc files. Any includes or
+ * other statements that occur before the pch include are ignored. This
+ * is really stupid and can lead to bizarre errors, but it does mean
+ * that we shouldn't run into any problems on systems without precompiled
+ * headers.
+ *
+ * Copyright © 1999 Jesse Jones.
+ *
+ * Change History (most recent first):
+ *
+ * <9> 9 Aug 2001 MV Added USE_RIVERS,USE_NEW_UNRANDS
+ * and MISSILE_TRAILS_OFF #define
+ * <8> 10 May 2001 GDL Added FreeBSD support
+ * courtesy Andrew E. Filonov
+ * <7> 9 May 2000 GDL Added Windows 32 bit console support
+ * <6> 24mar2000 jmf Added a whole slew of new options, which
+ * ought to be mandatory :-)
+ * <5> 10/12/99 BCR Added USE_NEW_RANDOM #define
+ * <4> 9/25/99 CDL linuxlib -> liblinux
+ * <3> 6/18/99 BCR Moved the CHARACTER_SET #define here from
+ * linuxlib.cc. Also wrapped the #define
+ * USE_MACROS to prevent it from being used by
+ * Linux.
+ * <2> 6/17/99 BCR Removed 'linux' check, replaced it with
+ * 'LINUX' check. Now need to be -DLINUX
+ * during compile. Also moved
+ * CHARACTER_SET #define here from
+ * linuxlib.cc
+ * <1> 5/30/99 JDJ Created (from config.h)
+ */
+
+
+#ifndef APPHDR_H
+#define APPHDR_H
+
+#if _MSC_VER >= 1100 // note that we can't just check for _MSC_VER: most compilers will wind up defining this in order to work with the SDK headers...
+#pragma message("Compiling AppHeader.h (this message should only appear once)")
+#endif
+
+
+// =========================================================================
+// System Defines
+// =========================================================================
+// Define plain_term for linux and similar, and dos_term for DOS and EMX.
+#ifdef LINUX
+
+ #define PLAIN_TERM
+ // #define CHARACTER_SET A_ALTCHARSET
+ #define CHARACTER_SET 0
+ #define USE_ASCII_CHARACTERS
+ #define MULTIUSER
+
+ // Set curses include file if you don't want the default curses.h
+ #define USE_CURSES
+ // #define CURSES_INCLUDE_FILE <ncurses.h>
+ #define EOL "\n"
+
+ // This is used for Posix termios.
+ #define USE_POSIX_TERMIOS
+
+ // This is used for BSD tchars type ioctl, use this if you can't
+ // use the Posix support above.
+ // #define USE_TCHARS_IOCTL
+ //
+ // This uses Unix signal control to block some things, may be
+ // useful in conjunction with USE_TCHARS_IOCTL.
+ //
+ #define USE_UNIX_SIGNALS
+
+ #include <string>
+ #include "liblinux.h"
+
+#elif defined(SOLARIS)
+ // Most of the linux stuff applies, and so we want it
+ #define LINUX
+ #define PLAIN_TERM
+ #define MULTIUSER
+ #include "liblinux.h"
+
+ // The ALTCHARSET may come across as DEC characters/JIS on non-ibm platforms
+ #define CHARACTER_SET 0
+
+ // Set curses include file if you don't want the default curses.h
+ #define USE_CURSES
+ // #define CURSES_INCLUDE_FILE <ncurses.h>
+ #define EOL "\n"
+
+ // This is used for Posix termios.
+ #define USE_POSIX_TERMIOS
+
+ // This is used for BSD tchars type ioctl, use this if you can't
+ // use the Posix support above.
+ // #define USE_TCHARS_IOCTL
+
+ // This uses Unix signal control to block SIGQUIT and SIGINT,
+ // which can be annoying (especially since control-Y sends
+ // SIGQUIT).
+ #define USE_UNIX_SIGNALS
+
+ // This is for older versions of Solaris... comment if you have it.
+ // #define NEED_USLEEP
+
+ // Default to non-ibm character set
+ #define USE_ASCII_CHARACTERS
+
+#elif defined (HPUX)
+ // Most of the linux stuff applies, and so we want it
+ #define LINUX
+ #define PLAIN_TERM
+ #define MULTIUSER
+ #include "liblinux.h"
+
+ // The ALTCHARSET may come across as DEC characters/JIS on non-ibm platforms
+ #define CHARACTER_SET 0
+
+ // Set curses include file if you don't want the default curses.h
+ // Under HP-UX its typically easier to use ncurses than try and
+ // get the colour curses library to work. -- bwr
+ #define USE_CURSES
+ #define CURSES_INCLUDE_FILE <ncurses.h>
+ #define EOL "\n"
+
+ // This is used for Posix termios.
+ #define USE_POSIX_TERMIOS
+
+ // This is used for BSD tchars type ioctl, use this if you can't
+ // use the Posix support above.
+ // #define USE_TCHARS_IOCTL
+ //
+ // This uses Unix signal control to block some things, may be
+ // useful in conjunction with USE_TCHARS_IOCTL.
+ //
+ #define USE_UNIX_SIGNALS
+
+ // This is for systems with no usleep... comment if you have it.
+ // #define NEED_USLEEP
+
+ // Default to non-ibm character set
+ #define USE_ASCII_CHARACTERS
+
+// Define plain_term for linux and similar, and dos_term for DOS and EMX.
+#elif defined ( BSD )
+ // Most of the linux stuff applies, and so we want it
+ #define LINUX
+ #define PLAIN_TERM
+//#define MULTIUSER
+ #include "liblinux.h"
+
+ // The ALTCHARSET may come across as DEC characters/JIS on non-ibm platforms
+ #define CHARACTER_SET 0
+
+ // Set curses include file if you don't want the default curses.h
+ #define USE_CURSES
+ // #define CURSES_INCLUDE_FILE <ncurses.h>
+ #define EOL "\n"
+
+ // This is used for Posix termios.
+ #define USE_POSIX_TERMIOS
+
+ // This is used for BSD tchars type ioctl, use this if you can't
+ // use the Posix support above.
+ #define USE_TCHARS_IOCTL
+
+ // This uses Unix signal control to block some things, may be
+ // useful in conjunction with USE_TCHARS_IOCTL.
+ //
+ // #define USE_UNIX_SIGNALS
+
+ // Default to non-ibm character set
+ #define USE_ASCII_CHARACTERS
+
+
+// To compile with EMX for OS/2 define USE_EMX macro with compiler command line
+// (already defined in supplied makefile.emx)
+#elif defined(USE_EMX)
+ #define DOS_TERM
+ #define EOL "\n"
+ #define CHARACTER_SET A_ALTCHARSET
+
+ #include <string>
+ #include "libemx.h"
+
+#elif _MSC_VER >= 1100
+ #include <string>
+ #include "WinHdr.h"
+ #error MSVC is not supported yet
+ #define CHARACTER_SET A_ALTCHARSET
+
+// macintosh is predefined on all the common Mac compilers
+#elif defined(macintosh)
+ #define PLAIN_TERM
+ #define HAS_NAMESPACES 1
+ #define EOL "\r"
+ #define CHARACTER_SET A_ALTCHARSET
+ #include <string>
+ #include "libmac.h"
+
+#if OSX
+ #define USE_8_COLOUR_TERM_MAP
+
+ // Darkgrey is a particular problem in the 8 colour mode. Popular v
+ // alues for replacing it around here are: WHITE, BLUE, and MAGENTA.
+ #define COL_TO_REPLACE_DARKGREY MAGENTA
+#endif
+
+#elif defined(DOS)
+ #define DOS_TERM
+ #define SHORT_FILE_NAMES
+ #define EOL "\n\r"
+ #define CHARACTER_SET A_ALTCHARSET
+
+ #include <string>
+
+ #ifdef __DJGPP__
+ #define NEED_SNPRINTF
+ #endif
+
+#elif defined(WIN32CONSOLE) && (defined(__IBMCPP__) || defined(__BCPLUSPLUS__))
+ #include "libw32c.h"
+ #define PLAIN_TERM
+ #define SHORT_FILE_NAMES
+ #define EOL "\n"
+ #define CHARACTER_SET A_ALTCHARSET
+ #define getstr(X,Y) getConsoleString(X,Y)
+#else
+ #error unsupported compiler
+#endif
+
+
+// =========================================================================
+// Debugging Defines
+// =========================================================================
+#ifdef FULLDEBUG
+ // Bounds checking and asserts
+ #define DEBUG 1
+
+ // Outputs many "hidden" details, defaults to wizard on.
+ #define DEBUG_DIAGNOSTICS 1
+
+ // Scan for bad items before every input (may be slow)
+ //
+ // This function might slow things down quite a bit
+ // on slow machines because it's going to go through
+ // every item on the level and do string comparisons
+ // against the name. Still, it is nice to know the
+ // turn in which "bad" items appear.
+ #define DEBUG_ITEM_SCAN 1
+#endif
+
+#ifdef _DEBUG // this is how MSVC signals a debug build
+ #define DEBUG 1
+#else
+// #define DEBUG 0 // leave this undefined for those lamers who use #ifdef
+#endif
+
+#if DEBUG
+ #if __MWERKS__
+ #define MSIPL_DEBUG_MODE
+ #endif
+#else
+ #if !defined(NDEBUG)
+ #define NDEBUG // used by <assert.h>
+ #endif
+#endif
+
+// =========================================================================
+// Curses features:
+// =========================================================================
+#ifdef USE_CURSES
+ // This will allow using the standout attribute in curses to
+ // mark friendly monsters... results depend on the type of
+ // term used... under X Windows try "rxvt".
+ #define USE_COLOUR_OPTS
+
+ // For cases when the game will be played on terms that don't support the
+ // curses "bold == lighter" 16 colour mode. -- bwr
+ //
+ // Darkgrey is a particular problem in the 8 colour mode. Popular values
+ // for replacing it around here are: WHITE, BLUE, and MAGENTA. THis
+ // option has no affect in 16 colour mode. -- bwr
+ //
+ // #define USE_8_COLOUR_TERM_MAP
+ // #define COL_TO_REPLACE_DARKGREY MAGENTA
+#endif
+
+// =========================================================================
+// Game Play Defines
+// =========================================================================
+// number of back messages saved during play (currently none saved into files)
+#define NUM_STORED_MESSAGES 1000
+
+// if this works out okay, eventually we can change this to USE_OLD_RANDOM
+#define USE_NEW_RANDOM
+
+// Uncomment this if you find the labyrinth to be buggy and want to
+// remove it from the game.
+// #define SHUT_LABYRINTH
+
+// Define USE_MACRO if you want to use the macro patch in macro.cc.
+#define USE_MACROS
+
+// Set this to the number of runes that will be required to enter Zot's
+// domain. You shouldn't set this really high unless you want to
+// make players spend far too much time in Pandemonium/The Abyss.
+//
+// Traditional setting of this is one rune, but three is pretty standard now.
+#define NUMBER_OF_RUNES_NEEDED 3
+
+// Number of top scores to keep.
+#define SCORE_FILE_ENTRIES 100
+
+// Option to allow scoring of wizard characters. Note that even if
+// you define this option, wizard characters are still tagged as such
+// in the score file.
+// #define SCORE_WIZARD_CHARACTERS
+
+// ================================================= --------------------------
+//jmf: New defines for a bunch of optional features.
+// ================================================= --------------------------
+
+// New silence code -- seems to actually work! Use it!
+#define USE_SILENCE_CODE
+
+// Use special colours for various channels of messages
+#define USE_COLOUR_MESSAGES
+
+// Wizard death option (needed to test new death messages)
+#define USE_OPTIONAL_WIZARD_DEATH
+
+// Semi-Controlled Blink
+#define USE_SEMI_CONTROLLED_BLINK
+
+// Use new system for weighting str and dex based on weapon type, -- bwr
+#define USE_NEW_COMBAT_STATS
+
+// Use this is you want the occasional spellcaster or ranger type wanderer
+// to show up... comment it if you find these types silly or too powerful,
+// or just want fighter type wanderers.
+// #define USE_SPELLCASTER_AND_RANGER_WANDERER_TEMPLATES
+
+//mv: (new 9 Aug 01) switches on new rivers & lakes code
+#define USE_RIVERS
+
+//mv: (new 9 Aug 01) switches on new unrands
+#define USE_NEW_UNRANDS
+
+// mv: (new 9 Aug 01) turns off missile trails, might be slow on some computers
+// #define MISSILE_TRAILS_OFF
+
+// bwr: allow player to destroy items in inventory (but not equiped items)
+// See comment at items.cc::cmd_destroy_item() for details/issues.
+// #define ALLOW_DESTROY_ITEM_COMMAND
+
+// bwr: set this to non-zero if you want to know the pluses, "runed" status
+// of the monster's weapons in the hiscore file.
+// #define HISCORE_WEAPON_DETAIL 1
+
+// ====================== -----------------------------------------------------
+//jmf: end of new defines
+// ====================== -----------------------------------------------------
+
+
+#ifdef MULTIUSER
+ // Define SAVE_DIR to the directory where saves, bones, and score file
+ // will go... end it with a '\'. Since all player files will be in the
+ // same directory, the players UID will be appended when this option
+ // is set.
+ //
+ // Setting it to nothing or not setting it will cause all game files to
+ // be dumped in the current directory.
+ //
+ #define SAVE_DIR_PATH "/opt/crawl/lib/"
+
+ // will make this little thing go away. Define SAVE_PACKAGE_CMD
+ // to a command to compress and bundle the save game files into a
+ // single unit... the two %s will be replaced with the players
+ // save file name. Define LOAD_UNPACKAGE_CMD to undo this process
+ // the %s is the same as above.
+ //
+ // PACKAGE_SUFFIX is used when the package file name is needed
+ //
+ // Comment these lines out if you want to leave the save files uncompressed.
+ //
+ #define SAVE_PACKAGE_CMD "/usr/bin/zip -m -q -j -1 %s.zip %s.*"
+ #define LOAD_UNPACKAGE_CMD "/usr/bin/unzip -q -o %s.zip -d" SAVE_DIR_PATH
+ #define PACKAGE_SUFFIX ".zip"
+
+ // This provides some rudimentary protection against people using
+ // save file cheats on multi-user systems.
+ #define DO_ANTICHEAT_CHECKS
+
+ // This defines the chmod permissions for score and bones files.
+ #define SHARED_FILES_CHMOD_PRIVATE 0664
+ #define SHARED_FILES_CHMOD_PUBLIC 0664
+
+ // If we're on a multiuser system, file locking of shared files is
+ // very important (else things will just keep getting corrupted)
+ #define USE_FILE_LOCKING
+
+ // Define this if you'd rather have the game block on locked files,
+ // commenting it will poll the file lock once a second for thirty
+ // seconds before giving up.
+ #define USE_BLOCKING_LOCK
+
+// some files needed for file locking
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#endif
+
+// ===========================================================================
+// Misc
+// ===========================================================================
+#if HAS_NAMESPACES
+ using namespace std;
+#endif
+
+// Uncomment these if you can't find these functions on your system
+// #define NEED_USLEEP
+// #define NEED_SNPRINTF
+
+// Must include libutil.h here if one of the above is defined.
+#include "libutil.h"
+
+template < class T >
+inline void UNUSED(const volatile T &)
+{
+} // Note that this generates no code with CodeWarrior or MSVC (if inlining is on).
+
+#endif
diff --git a/trunk/source/FixAry.h b/trunk/source/FixAry.h
new file mode 100644
index 0000000000..58db5bb58d
--- /dev/null
+++ b/trunk/source/FixAry.h
@@ -0,0 +1,73 @@
+/*
+ * File: FixAry.h
+ * Summary: Fixed size 2D vector class that asserts if you do something bad.
+ * Written by: Jesse Jones
+ *
+ * Change History (most recent first):
+ *
+ * <1> 6/16/00 JDJ Created
+ */
+
+#ifndef FIXARY_H
+#define FIXARY_H
+
+#include "FixVec.h"
+
+
+// ==========================================================================
+// class FixedArray
+// ==========================================================================
+template <class TYPE, int WIDTH, int HEIGHT> class FixedArray {
+
+//-----------------------------------
+// Types
+//
+public:
+ typedef TYPE value_type;
+ typedef TYPE& reference;
+ typedef const TYPE& const_reference;
+ typedef TYPE* pointer;
+ typedef const TYPE* const_pointer;
+
+ typedef unsigned long size_type;
+ typedef long difference_type;
+
+ typedef FixedVector<TYPE, HEIGHT> Column; // operator[] needs to return one of these to avoid breaking client code (if inlining is on there won't be a speed hit)
+
+//-----------------------------------
+// Initialization/Destruction
+//
+public:
+ ~FixedArray() {}
+
+ FixedArray() {}
+
+private:
+ FixedArray(const FixedArray& rhs);
+
+ FixedArray& operator=(const FixedArray& rhs);
+
+//-----------------------------------
+// API
+//
+public:
+ // ----- Size -----
+ bool empty() const {return WIDTH == 0 || HEIGHT == 0;}
+ int size() const {return WIDTH*HEIGHT;}
+
+ int width() const {return WIDTH;}
+ int height() const {return HEIGHT;}
+
+ // ----- Access -----
+ Column& operator[](unsigned long index) {return mData[index];}
+ const Column& operator[](unsigned long index) const {return mData[index];}
+
+//-----------------------------------
+// Member Data
+//
+protected:
+ FixedVector<Column, WIDTH> mData;
+};
+
+
+#endif // FIXARY_H
diff --git a/trunk/source/FixVec.h b/trunk/source/FixVec.h
new file mode 100644
index 0000000000..b0afb34e82
--- /dev/null
+++ b/trunk/source/FixVec.h
@@ -0,0 +1,133 @@
+/*
+ * File: FixVec.h
+ * Summary: Fixed size vector class that asserts if you do something bad.
+ * Written by: Jesse Jones
+ *
+ * Change History (most recent first):
+ *
+ * <2> 7/29/00 JDJ Added a variable argument ctor.
+ * <1> 6/16/00 JDJ Created
+ */
+
+#ifndef FIXVEC_H
+#define FIXVEC_H
+
+#include <stdarg.h>
+
+#include "debug.h"
+
+
+// ==========================================================================
+// class FixedVector
+// ==========================================================================
+
+template <class TYPE, int SIZE> class FixedVector {
+
+//-----------------------------------
+// Types
+//
+public:
+ typedef TYPE value_type;
+ typedef TYPE& reference;
+ typedef const TYPE& const_reference;
+ typedef TYPE* pointer;
+ typedef const TYPE* const_pointer;
+
+ typedef unsigned long size_type;
+ typedef long difference_type;
+
+ typedef TYPE* iterator;
+ typedef const TYPE* const_iterator;
+
+#if 0
+#if MSVC >= 1100
+ typedef std::reverse_iterator<const_iterator, const TYPE> const_reverse_iterator;
+ typedef std::reverse_iterator<iterator, TYPE> reverse_iterator;
+#else
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+#endif
+#endif
+
+//-----------------------------------
+// Initialization/Destruction
+//
+public:
+ ~FixedVector() {}
+
+ FixedVector() {}
+
+ FixedVector(TYPE value0, TYPE value1, ...);
+ // Allows for something resembling C array initialization, eg
+ // instead of "int a[3] = {0, 1, 2}" you'd use "FixedVector<int, 3>
+ // a(0, 1, 2)". Note that there must be SIZE arguments.
+
+// public:
+// FixedVector(const FixedVector& rhs);
+//
+// FixedVector& operator=(const FixedVector& rhs);
+
+//-----------------------------------
+// API
+//
+public:
+ // ----- Size -----
+ bool empty() const {return SIZE == 0;}
+ int size() const {return SIZE;}
+
+ // ----- Access -----
+ TYPE& operator[](unsigned long index) {ASSERT(index < SIZE); return mData[index];}
+ const TYPE& operator[](unsigned long index) const {ASSERT(index < SIZE); return mData[index];}
+
+ TYPE& front() {ASSERT(SIZE > 0); return mData[0];}
+ const TYPE& front() const {ASSERT(SIZE > 0); return mData[0];}
+
+ TYPE& back() {ASSERT(SIZE > 0); return mData[SIZE - 1];}
+ const TYPE& back() const {ASSERT(SIZE > 0); return mData[SIZE - 1];}
+
+ TYPE* buffer() {return mData;}
+ const TYPE* buffer() const {return mData;}
+
+ // ----- Iterating -----
+ iterator begin() {return mData;}
+ const_iterator begin() const {return mData;}
+
+ iterator end() {return this->begin() + this->size();}
+ const_iterator end() const {return this->begin() + this->size();}
+
+// reverse_iterator rbegin() {return reverse_iterator(this->end());}
+// const_reverse_iterator rbegin() const {return const_reverse_iterator(this->end());}
+
+// reverse_iterator rend() {return reverse_iterator(this->begin());}
+// const_reverse_iterator rend() const {return const_reverse_iterator(this->begin());}
+
+//-----------------------------------
+// Member Data
+//
+protected:
+ TYPE mData[SIZE];
+};
+
+
+// ==========================================================================
+// Outlined Methods
+// ==========================================================================
+template <class TYPE, int SIZE>
+FixedVector<TYPE, SIZE>::FixedVector(TYPE value0, TYPE value1, ...)
+{
+ mData[0] = value0;
+ mData[1] = value1;
+
+ va_list ap;
+ va_start(ap, value1); // second argument is last fixed parameter
+
+ for (int index = 2; index < SIZE; index++) {
+ TYPE value = va_arg(ap, TYPE);
+
+ mData[index] = value;
+ }
+
+ va_end(ap);
+}
+
+#endif // FIXVEC_H
diff --git a/trunk/source/MacString.cc b/trunk/source/MacString.cc
new file mode 100644
index 0000000000..2d5c14442e
--- /dev/null
+++ b/trunk/source/MacString.cc
@@ -0,0 +1,199 @@
+/*
+ * File: MacString.cc
+ * Summary: Wrapper around an immutable CFString.
+ * Written by: Jesse Jones (jesjones@mindspring.com)
+ *
+ * Change History (most recent first):
+ *
+ * <1> 6/04/02 JDJ Created
+ */
+
+#include "AppHdr.h"
+#include "MacString.h"
+
+#if macintosh
+
+#include <CoreFoundation/CFString.h>
+
+#include "debug.h"
+
+
+// ========================================================================
+// Internal Functions
+// ========================================================================
+
+//---------------------------------------------------------------
+//
+// ThrowIf
+//
+//---------------------------------------------------------------
+static void ThrowIf(bool predicate, const std::string& text)
+{
+ if (predicate)
+ throw std::runtime_error(text);
+}
+
+#if __MWERKS__
+#pragma mark -
+#endif
+
+// ============================================================================
+// class MacString
+// ============================================================================
+
+//---------------------------------------------------------------
+//
+// MacString::~MacString
+//
+//---------------------------------------------------------------
+MacString::~MacString()
+{
+ CFRelease(mString);
+}
+
+
+//---------------------------------------------------------------
+//
+// MacString::MacString ()
+//
+//---------------------------------------------------------------
+MacString::MacString()
+{
+ mString = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, NULL, 0);
+ ThrowIf(mString == NULL, "Couldn't create the CFString");
+}
+
+
+//---------------------------------------------------------------
+//
+// MacString::MacString (unsigned char*)
+//
+//---------------------------------------------------------------
+MacString::MacString(const unsigned char* str)
+{
+ ASSERT(str != NULL);
+
+ CFStringEncoding encoding = CFStringGetSystemEncoding();
+ mString = CFStringCreateWithPascalString(kCFAllocatorSystemDefault, str, encoding);
+ ThrowIf(mString == NULL, "Couldn't create the CFString");
+}
+
+
+//---------------------------------------------------------------
+//
+// MacString::MacString (char*)
+//
+//---------------------------------------------------------------
+MacString::MacString(const char* str)
+{
+ ASSERT(str != NULL);
+
+ CFStringEncoding encoding = CFStringGetSystemEncoding();
+ mString = CFStringCreateWithCString(kCFAllocatorSystemDefault, str, encoding);
+ ThrowIf(mString == NULL, "Couldn't create the CFString");
+}
+
+
+//---------------------------------------------------------------
+//
+// MacString::MacString (CFStringRef)
+//
+//---------------------------------------------------------------
+MacString::MacString(CFStringRef str)
+{
+ ASSERT(str != NULL);
+
+ mString = str;
+ CFRetain(mString);
+}
+
+
+//---------------------------------------------------------------
+//
+// MacString::MacString (CFMutableStringRef)
+//
+//---------------------------------------------------------------
+MacString::MacString(CFMutableStringRef str)
+{
+ ASSERT(str != NULL);
+
+ mString = CFStringCreateCopy(kCFAllocatorSystemDefault, str);
+ ThrowIf(mString == NULL, "Couldn't create the CFString");
+}
+
+
+//---------------------------------------------------------------
+//
+// MacString::MacString (int)
+//
+//---------------------------------------------------------------
+MacString::MacString(int value)
+{
+ char buffer[32];
+ sprintf(buffer, "%d", value);
+
+ CFStringEncoding encoding = CFStringGetSystemEncoding();
+ mString = CFStringCreateWithCString(kCFAllocatorSystemDefault, buffer, encoding);
+ ThrowIf(mString == NULL, "Couldn't create the CFString");
+}
+
+
+//---------------------------------------------------------------
+//
+// MacString::MacString (MacString)
+//
+//---------------------------------------------------------------
+MacString::MacString(const MacString& str)
+{
+ mString = str.mString; // immutable so we can refcount
+ CFRetain(mString);
+}
+
+
+//---------------------------------------------------------------
+//
+// MacString::operator= (MacString)
+//
+//---------------------------------------------------------------
+MacString& MacString::operator=(const MacString& rhs)
+{
+ if (this != &rhs)
+ {
+ CFRelease(mString);
+
+ mString = rhs.mString; // immutable so we can refcount
+ CFRetain(mString);
+ }
+
+ return *this;
+}
+
+
+//---------------------------------------------------------------
+//
+// MacString::length
+//
+//---------------------------------------------------------------
+size_t MacString::length() const
+{
+ size_t len = (size_t) CFStringGetLength(mString);
+
+ return len;
+}
+
+
+//---------------------------------------------------------------
+//
+// MacString::CopyTo
+//
+//---------------------------------------------------------------
+void MacString::CopyTo(unsigned char* buffer, CFIndex bytes)
+{
+ ASSERT(buffer != NULL || bytes == 0);
+
+ bool converted = CFStringGetPascalString(mString, buffer, bytes, CFStringGetSystemEncoding());
+ ThrowIf(!converted, "Couldn't convert the CFString into a Pascal string");
+}
+
+
+#endif // macintosh
diff --git a/trunk/source/MacString.h b/trunk/source/MacString.h
new file mode 100644
index 0000000000..d2cad4b1be
--- /dev/null
+++ b/trunk/source/MacString.h
@@ -0,0 +1,71 @@
+/*
+ * File: MacString.h
+ * Summary: Wrapper around an immutable CFString.
+ * Written by: Jesse Jones (jesjones@mindspring.com)
+ *
+ * Change History (most recent first):
+ *
+ * <1> 6/04/02 JDJ Created
+ */
+
+#ifndef MAC_STRING_H
+#define MAC_STRING_H
+
+#if macintosh
+
+#include <CoreFoundation/CFBase.h>
+
+
+// ============================================================================
+// class MacString
+//! Wrapper around an immutable CFString.
+// ============================================================================
+class MacString {
+
+//-----------------------------------
+// Initialization/Destruction
+//
+public:
+ ~MacString();
+
+ MacString();
+
+ MacString(const char* str);
+ MacString(const unsigned char* str);
+ /**< Uses default system encoding. */
+
+ MacString(CFStringRef str);
+ /**< Bumps the ref count. */
+
+ MacString(CFMutableStringRef str);
+ /**< Makes a copy. */
+
+ explicit MacString(int value);
+
+ MacString(const MacString& str);
+ MacString& operator=(const MacString& rhs);
+
+//-----------------------------------
+// API
+//
+public:
+ // ----- Size -----
+ size_t length() const;
+ size_t size() const {return this->length();}
+ bool empty() const {return this->length() == 0;}
+
+ // ----- Access -----
+ void CopyTo(unsigned char* buffer, CFIndex bytes);
+
+ operator CFStringRef() const {return mString;}
+
+//-----------------------------------
+// Member Data
+//
+private:
+ CFStringRef mString;
+};
+
+
+#endif // macintosh
+#endif // MAC_STRING_H
diff --git a/trunk/source/abl-show.cc b/trunk/source/abl-show.cc
new file mode 100644
index 0000000000..867919159e
--- /dev/null
+++ b/trunk/source/abl-show.cc
@@ -0,0 +1,2168 @@
+/*
+ * File: abl-show.cc
+ * Summary: Functions related to special abilities.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <6> 19mar2000 jmf added elvish Glamour
+ * <5> 11/06/99 cdl reduced power of minor destruction
+ *
+ * <4> 9/25/99 cdl linuxlib -> liblinux
+ *
+ * <3> 5/20/99 BWR Now use scan_randarts to
+ * check for flags, rather than
+ * only checking the weapon.
+ *
+ * <2> 5/20/99 BWR Extended screen line support
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "abl-show.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#include "externs.h"
+
+#include "beam.h"
+#include "effects.h"
+#include "food.h"
+#include "it_use2.h"
+#include "macro.h"
+#include "message.h"
+#include "misc.h"
+#include "monplace.h"
+#include "player.h"
+#include "religion.h"
+#include "skills.h"
+#include "skills2.h"
+#include "spl-cast.h"
+#include "spl-util.h"
+#include "spells1.h"
+#include "spells2.h"
+#include "spells3.h"
+#include "spells4.h"
+#include "stuff.h"
+#include "transfor.h"
+#include "view.h"
+
+
+#ifdef LINUX
+#include "liblinux.h"
+#endif
+
+// this all needs to be split into data/util/show files
+// and the struct mechanism here needs to be rewritten (again)
+// along with the display routine to piece the strings
+// together dynamically ... I'm getting to it now {dlb}
+
+// it makes more sense to think of them as an array
+// of structs than two arrays that share common index
+// values -- well, doesn't it? {dlb}
+struct talent
+{
+ int which;
+ int fail;
+ bool is_invocation;
+};
+
+static FixedVector< talent, 52 > Curr_abil;
+
+static bool insert_ability( int which_ability );
+
+// The description screen was way out of date with the actual costs.
+// This table puts all the information in one place... -- bwr
+//
+// The four numerical fields are: MP, HP, food, and piety.
+// Note: food_cost = val + random2avg( val, 2 )
+// piety_cost = val + random2( (val + 1) / 2 + 1 );
+static const struct ability_def Ability_List[] =
+{
+ // NON_ABILITY should always come first
+ { ABIL_NON_ABILITY, "No ability", 0, 0, 0, 0, ABFLAG_NONE },
+ { ABIL_SPIT_POISON, "Spit Poison", 0, 0, 40, 0, ABFLAG_BREATH },
+ { ABIL_GLAMOUR, "Glamour", 5, 0, 40, 0, ABFLAG_DELAY },
+
+ { ABIL_MAPPING, "Sense Surroundings", 0, 0, 30, 0, ABFLAG_NONE },
+ { ABIL_TELEPORTATION, "Teleportation", 3, 0, 200, 0, ABFLAG_NONE },
+ { ABIL_BLINK, "Blink", 1, 0, 50, 0, ABFLAG_NONE },
+
+ { ABIL_BREATHE_FIRE, "Breathe Fire", 0, 0, 125, 0, ABFLAG_BREATH },
+ { ABIL_BREATHE_FROST, "Breathe Frost", 0, 0, 125, 0, ABFLAG_BREATH },
+ { ABIL_BREATHE_POISON, "Breathe Poison Gas", 0, 0, 125, 0, ABFLAG_BREATH },
+ { ABIL_BREATHE_LIGHTNING, "Breathe Lightning", 0, 0, 125, 0, ABFLAG_BREATH },
+ { ABIL_BREATHE_POWER, "Breathe Power", 0, 0, 125, 0, ABFLAG_BREATH },
+ { ABIL_BREATHE_STICKY_FLAME, "Breathe Sticky Flame", 0, 0, 125, 0, ABFLAG_BREATH },
+ { ABIL_BREATHE_STEAM, "Breathe Steam", 0, 0, 75, 0, ABFLAG_BREATH },
+
+ // Handled with breath weapons, but doesn't cause a breathing delay
+ { ABIL_SPIT_ACID, "Spit Acid", 0, 0, 125, 0, ABFLAG_NONE },
+
+ { ABIL_FLY, "Fly", 3, 0, 100, 0, ABFLAG_NONE },
+ { ABIL_SUMMON_MINOR_DEMON, "Summon Minor Demon", 3, 3, 75, 0, ABFLAG_NONE },
+ { ABIL_SUMMON_DEMON, "Summon Demon", 5, 5, 150, 0, ABFLAG_NONE },
+ { ABIL_HELLFIRE, "Hellfire", 8, 8, 200, 0, ABFLAG_NONE },
+ { ABIL_TORMENT, "Torment", 9, 0, 250, 0, ABFLAG_PAIN },
+ { ABIL_RAISE_DEAD, "Raise Dead", 5, 5, 150, 0, ABFLAG_NONE },
+ { ABIL_CONTROL_DEMON, "Control Demon", 4, 4, 100, 0, ABFLAG_NONE },
+ { ABIL_TO_PANDEMONIUM, "Gate Yourself to Pandemonium", 7, 0, 200, 0, ABFLAG_NONE },
+ { ABIL_CHANNELING, "Channeling", 1, 0, 30, 0, ABFLAG_NONE },
+ { ABIL_THROW_FLAME, "Throw Flame", 1, 1, 50, 0, ABFLAG_NONE },
+ { ABIL_THROW_FROST, "Throw Frost", 1, 1, 50, 0, ABFLAG_NONE },
+ { ABIL_BOLT_OF_DRAINING, "Bolt of Draining", 4, 4, 100, 0, ABFLAG_NONE },
+
+ // FLY_II used to have ABFLAG_EXHAUSTION, but that's somewhat meaningless
+ // as exhaustion's only (and designed) effect is preventing Berserk. -- bwr
+ { ABIL_FLY_II, "Fly", 0, 0, 25, 0, ABFLAG_NONE },
+ { ABIL_DELAYED_FIREBALL, "Release Delayed Fireball", 0, 0, 0, 0, ABFLAG_INSTANT },
+ { ABIL_MUMMY_RESTORATION, "Restoration", 1, 0, 0, 0, ABFLAG_PERMANENT_MP },
+
+ // EVOKE abilities use Evocations and come from items:
+ // Mapping, Teleportation, and Blink can also come from mutations
+ // so we have to distinguish them (see above). The off items
+ // below are labeled EVOKE because they only work now if the
+ // player has an item with the evocable power (not just because
+ // you used a wand, potion, or miscast effect). I didn't see
+ // any reason to label them as "Evoke" in the text, they don't
+ // use or train Evocations (the others do). -- bwr
+ { ABIL_EVOKE_MAPPING, "Evoke Sense Surroundings", 0, 0, 30, 0, ABFLAG_NONE },
+ { ABIL_EVOKE_TELEPORTATION, "Evoke Teleportation", 3, 0, 200, 0, ABFLAG_NONE },
+ { ABIL_EVOKE_BLINK, "Evoke Blink", 1, 0, 50, 0, ABFLAG_NONE },
+
+ { ABIL_EVOKE_BERSERK, "Evoke Berserk Rage", 0, 0, 0, 0, ABFLAG_NONE },
+
+ { ABIL_EVOKE_TURN_INVISIBLE, "Evoke Invisibility", 2, 0, 250, 0, ABFLAG_NONE },
+ { ABIL_EVOKE_TURN_VISIBLE, "Turn Visible", 0, 0, 0, 0, ABFLAG_NONE },
+ { ABIL_EVOKE_LEVITATE, "Evoke Levitation", 1, 0, 100, 0, ABFLAG_NONE },
+ { ABIL_EVOKE_STOP_LEVITATING, "Stop Levitating", 0, 0, 0, 0, ABFLAG_NONE },
+
+ { ABIL_END_TRANSFORMATION, "End Transformation", 0, 0, 0, 0, ABFLAG_NONE },
+
+ // INVOCATIONS:
+ // Zin
+ { ABIL_ZIN_REPEL_UNDEAD, "Repel Undead", 1, 0, 100, 0, ABFLAG_NONE },
+ { ABIL_ZIN_HEALING, "Minor Healing", 2, 0, 50, 1, ABFLAG_NONE },
+ { ABIL_ZIN_PESTILENCE, "Pestilence", 3, 0, 100, 2, ABFLAG_NONE },
+ { ABIL_ZIN_HOLY_WORD, "Holy Word", 6, 0, 150, 3, ABFLAG_NONE },
+ { ABIL_ZIN_SUMMON_GUARDIAN, "Summon Guardian", 7, 0, 150, 4, ABFLAG_NONE },
+
+ // The Shining One
+ { ABIL_TSO_REPEL_UNDEAD, "Repel Undead", 1, 0, 100, 0, ABFLAG_NONE },
+ { ABIL_TSO_SMITING, "Smiting", 3, 0, 50, 2, ABFLAG_NONE },
+ { ABIL_TSO_ANNIHILATE_UNDEAD, "Annihilate Undead", 3, 0, 50, 2, ABFLAG_NONE },
+ { ABIL_TSO_THUNDERBOLT, "Thunderbolt", 5, 0, 100, 2, ABFLAG_NONE },
+ { ABIL_TSO_SUMMON_DAEVA, "Summon Daeva", 8, 0, 150, 4, ABFLAG_NONE },
+
+ // Kikubaaqudgha
+ { ABIL_KIKU_RECALL_UNDEAD_SLAVES, "Recall Undead Slaves", 2, 0, 50, 0, ABFLAG_NONE },
+ { ABIL_KIKU_ENSLAVE_UNDEAD, "Enslave Undead", 4, 0, 150, 3, ABFLAG_NONE },
+ { ABIL_KIKU_INVOKE_DEATH, "Invoke Death", 4, 0, 250, 3, ABFLAG_NONE },
+
+ // Yredelemnul
+ { ABIL_YRED_ANIMATE_CORPSE, "Animate Corpse", 1, 0, 50, 0, ABFLAG_NONE },
+ { ABIL_YRED_RECALL_UNDEAD, "Recall Undead Slaves", 2, 0, 50, 0, ABFLAG_NONE },
+ { ABIL_YRED_ANIMATE_DEAD, "Animate Dead", 3, 0, 100, 1, ABFLAG_NONE },
+ { ABIL_YRED_DRAIN_LIFE, "Drain Life", 6, 0, 200, 2, ABFLAG_NONE },
+ { ABIL_YRED_CONTROL_UNDEAD, "Control Undead", 5, 0, 150, 2, ABFLAG_NONE },
+
+ // Vehumet
+ { ABIL_VEHUMET_CHANNEL_ENERGY, "Channel Energy", 0, 0, 50, 0, ABFLAG_NONE },
+
+ // Okawaru
+ { ABIL_OKAWARU_MIGHT, "Might", 2, 0, 50, 1, ABFLAG_NONE },
+ { ABIL_OKAWARU_HEALING, "Healing", 2, 0, 75, 1, ABFLAG_NONE },
+ { ABIL_OKAWARU_HASTE, "Haste", 5, 0, 100, 3, ABFLAG_NONE },
+
+ // Makhleb
+ { ABIL_MAKHLEB_MINOR_DESTRUCTION, "Minor Destruction", 1, 0, 20, 0, ABFLAG_NONE },
+ { ABIL_MAKHLEB_LESSER_SERVANT_OF_MAKHLEB, "Lesser Servant of Makhleb", 2, 0, 50, 1, ABFLAG_NONE },
+ { ABIL_MAKHLEB_MAJOR_DESTRUCTION, "Major Destruction", 4, 0, 100, 2, ABFLAG_NONE },
+ { ABIL_MAKHLEB_GREATER_SERVANT_OF_MAKHLEB, "Greater Servant of Makhleb", 6, 0, 100, 3, ABFLAG_NONE },
+
+ // Sif Muna
+ { ABIL_SIF_MUNA_FORGET_SPELL, "Forget Spell", 5, 0, 0, 8, ABFLAG_NONE },
+
+ // Trog
+ { ABIL_TROG_BERSERK, "Berserk", 0, 0, 200, 0, ABFLAG_NONE },
+ { ABIL_TROG_MIGHT, "Might", 0, 0, 200, 1, ABFLAG_NONE },
+ { ABIL_TROG_HASTE_SELF, "Haste Self", 0, 0, 250, 3, ABFLAG_NONE },
+
+ // Elyvilon
+ { ABIL_ELYVILON_LESSER_HEALING, "Lesser Healing", 1, 0, 100, 0, ABFLAG_NONE },
+ { ABIL_ELYVILON_PURIFICATION, "Purification", 2, 0, 150, 1, ABFLAG_NONE },
+ { ABIL_ELYVILON_HEALING, "Healing", 2, 0, 250, 2, ABFLAG_NONE },
+ { ABIL_ELYVILON_RESTORATION, "Restoration", 3, 0, 400, 3, ABFLAG_NONE },
+ { ABIL_ELYVILON_GREATER_HEALING, "Greater Healing", 6, 0, 600, 4, ABFLAG_NONE },
+
+ // These six are unused "evil" god abilities:
+ { ABIL_CHARM_SNAKE, "Charm Snake", 6, 0, 200, 5, ABFLAG_NONE },
+ { ABIL_TRAN_SERPENT_OF_HELL, "Turn into Demonic Serpent", 16, 0, 600, 8, ABFLAG_NONE },
+ { ABIL_BREATHE_HELLFIRE, "Breathe Hellfire", 0, 8, 200, 0, ABFLAG_BREATH },
+
+ { ABIL_ROTTING, "Rotting", 4, 4, 0, 2, ABFLAG_NONE },
+ { ABIL_TORMENT_II, "Call Torment", 9, 0, 0, 3, ABFLAG_PAIN },
+ { ABIL_SHUGGOTH_SEED, "Sow Shuggoth Seed", 12, 8, 0, 6, ABFLAG_NONE },
+
+ { ABIL_RENOUNCE_RELIGION, "Renounce Religion", 0, 0, 0, 0, ABFLAG_NONE },
+};
+
+
+const struct ability_def & get_ability_def( int abil )
+/****************************************************/
+{
+ for (unsigned int i = 0; i < sizeof( Ability_List ); i++)
+ {
+ if (Ability_List[i].ability == abil)
+ return (Ability_List[i]);
+ }
+
+ return (Ability_List[0]);
+}
+
+
+const char * get_ability_name_by_index( char index )
+/**************************************************/
+{
+ const struct ability_def &abil = get_ability_def( Curr_abil[index].which );
+
+ return (abil.name);
+}
+
+
+const std::string make_cost_description( const struct ability_def &abil )
+/***********************************************************************/
+{
+ char tmp_buff[80]; // avoiding string steams for portability
+ std::string ret = "";
+
+ if (abil.mp_cost)
+ {
+ snprintf( tmp_buff, sizeof(tmp_buff), "%d%s MP",
+ abil.mp_cost,
+ (abil.flags & ABFLAG_PERMANENT_MP) ? " Permanent" : "" );
+
+ ret += tmp_buff;
+ }
+
+ if (abil.hp_cost)
+ {
+ if (ret.length())
+ ret += ", ";
+
+ snprintf( tmp_buff, sizeof(tmp_buff), "%d%s HP",
+ abil.hp_cost,
+ (abil.flags & ABFLAG_PERMANENT_HP) ? " Permanent" : "" );
+
+ ret += tmp_buff;
+ }
+
+ if (abil.food_cost)
+ {
+ if (ret.length())
+ ret += ", ";
+
+ ret += "Food"; // randomized and amount hidden from player
+ }
+
+ if (abil.piety_cost)
+ {
+ if (ret.length())
+ ret += ", ";
+
+ ret += "Piety"; // randomized and amount hidden from player
+ }
+
+ if (abil.flags & ABFLAG_BREATH)
+ {
+ if (ret.length())
+ ret += ", ";
+
+ ret += "Breath";
+ }
+
+ if (abil.flags & ABFLAG_DELAY)
+ {
+ if (ret.length())
+ ret += ", ";
+
+ ret += "Delay";
+ }
+
+ if (abil.flags & ABFLAG_PAIN)
+ {
+ if (ret.length())
+ ret += ", ";
+
+ ret += "Pain";
+ }
+
+ if (abil.flags & ABFLAG_EXHAUSTION)
+ {
+ if (ret.length())
+ ret += ", ";
+
+ ret += "Exhaustion";
+ }
+
+ if (abil.flags & ABFLAG_INSTANT)
+ {
+ if (ret.length())
+ ret += ", ";
+
+ ret += "Instant"; // not really a cost, more of a bonus -bwr
+ }
+
+ // If we haven't output anything so far, then the effect has no cost
+ if (!ret.length())
+ ret += "None";
+
+ return (ret);
+}
+
+
+/*
+ Activates a menu which gives player access to all of their non-spell
+ special abilities - Eg naga's spit poison, or the Invocations you get
+ from worshipping. Generated dynamically - the function checks to see which
+ abilities you have every time.
+ */
+bool activate_ability(void)
+/*************************/
+{
+ unsigned char keyin = 0;
+ unsigned char spc, spc2;
+
+ int power;
+ struct dist abild;
+ struct bolt beam;
+ struct dist spd;
+
+ unsigned char abil_used;
+
+ // early returns prior to generation of ability list {dlb}:
+ if (you.conf)
+ {
+ mpr("You're too confused!");
+ return (false);
+ }
+
+ if (you.berserker)
+ {
+ canned_msg(MSG_TOO_BERSERK);
+ return (false);
+ }
+
+ // populate the array of structs {dlb}:
+ if (!generate_abilities())
+ {
+ mpr("Sorry, you're not good enough to have a special ability.");
+ return (false);
+ }
+
+ bool need_redraw = false;
+ bool need_prompt = true;
+ bool need_getch = true;
+
+ for (;;)
+ {
+ if (need_redraw)
+ {
+ mesclr( true );
+ redraw_screen();
+ }
+
+ if (need_prompt)
+ mpr( "Use which ability? (? or * to list)", MSGCH_PROMPT );
+
+ if (need_getch)
+ keyin = get_ch();
+
+ need_redraw = false;
+ need_prompt = true;
+ need_getch = true;
+
+ if (isalpha( keyin ))
+ {
+ break;
+ }
+ else if (keyin == '?' || keyin == '*')
+ {
+ keyin = show_abilities();
+
+ need_getch = false;
+ need_redraw = true;
+ need_prompt = true;
+ }
+ else if (keyin == ESCAPE || keyin == ' '
+ || keyin == '\r' || keyin == '\n')
+ {
+ canned_msg( MSG_OK );
+ return (false);
+ }
+ }
+
+ spc = (int) keyin;
+
+ if (!isalpha( spc ))
+ {
+ mpr("You can't do that.");
+ return (false);
+ }
+
+ spc2 = letter_to_index(spc);
+
+ if (Curr_abil[spc2].which == -1)
+ {
+ mpr("You can't do that.");
+ return (false);
+ }
+
+ abil_used = spc2;
+
+ // some abilities don't need a hunger check
+ bool hungerCheck = true;
+ switch (Curr_abil[abil_used].which)
+ {
+ case ABIL_RENOUNCE_RELIGION:
+ case ABIL_EVOKE_STOP_LEVITATING:
+ case ABIL_EVOKE_TURN_VISIBLE:
+ case ABIL_END_TRANSFORMATION:
+ case ABIL_DELAYED_FIREBALL:
+ case ABIL_MUMMY_RESTORATION:
+ hungerCheck = false;
+ break;
+ default:
+ break;
+ }
+
+ if (hungerCheck && you.hunger_state < HS_HUNGRY)
+ {
+ mpr("You're too hungry.");
+ return (false);
+ }
+
+ // no turning back now... {dlb}
+ const struct ability_def abil = get_ability_def(Curr_abil[abil_used].which);
+
+ // currently only delayed fireball is instantaneous -- bwr
+ you.turn_is_over = ((abil.flags & ABFLAG_INSTANT) ? 0 : 1);
+
+ if (random2avg(100, 3) < Curr_abil[abil_used].fail)
+ {
+ mpr("You fail to use your ability.");
+ return (false);
+ }
+
+ if (!enough_mp( abil.mp_cost, false ))
+ return (false);
+
+ if (!enough_hp( abil.hp_cost, false ))
+ return (false);
+
+ // Note: the costs will not be applied until after this switch
+ // statement... it's assumed that only failures have returned! -- bwr
+ switch (abil.ability)
+ {
+ case ABIL_MUMMY_RESTORATION:
+ mpr( "You infuse your body with magical energy." );
+ restore_stat( STAT_ALL, false );
+ unrot_hp( 100 );
+ break;
+
+ case ABIL_DELAYED_FIREBALL:
+ // Note: power level of ball calculated at release -- bwr
+ fireball( calc_spell_power( SPELL_DELAYED_FIREBALL, true ) );
+
+ // only one allowed since this is instantaneous -- bwr
+ you.attribute[ ATTR_DELAYED_FIREBALL ] = 0;
+ break;
+
+ case ABIL_GLAMOUR:
+ if (you.duration[DUR_GLAMOUR])
+ {
+ canned_msg(MSG_CANNOT_DO_YET);
+ return (false);
+ }
+
+ mpr("You use your Elvish wiles.");
+
+ cast_glamour( 10 + random2(you.experience_level)
+ + random2(you.experience_level) );
+
+ you.duration[DUR_GLAMOUR] = 20 + random2avg(13, 3);
+ break;
+
+ case ABIL_SPIT_POISON: // Naga + spit poison mutation
+ if (you.duration[DUR_BREATH_WEAPON])
+ {
+ canned_msg(MSG_CANNOT_DO_YET);
+ return (false);
+ }
+ else if (spell_direction(abild, beam) == -1)
+ {
+ canned_msg(MSG_OK);
+ return (false);
+ }
+ else
+ {
+ mpr("You spit poison.");
+
+ zapping( ZAP_SPIT_POISON,
+ you.experience_level
+ + you.mutation[MUT_SPIT_POISON] * 5
+ + (you.species == SP_NAGA) * 10,
+ beam );
+
+ you.duration[DUR_BREATH_WEAPON] = 3 + random2(5);
+ }
+ break;
+
+ case ABIL_EVOKE_MAPPING: // randarts
+ mpr("You sense your surroundings.");
+
+ magic_mapping( 3 + roll_dice( 2, you.skills[SK_EVOCATIONS] ),
+ 40 + roll_dice( 2, you.skills[SK_EVOCATIONS] ) );
+
+ exercise( SK_EVOCATIONS, 1 );
+ break;
+
+ case ABIL_MAPPING: // Gnome + sense surrounds mut
+ mpr("You sense your surroundings.");
+
+ magic_mapping( 3 + roll_dice( 2, you.experience_level )
+ + you.mutation[MUT_MAPPING] * 10,
+ 40 + roll_dice( 2, you.experience_level ) );
+ break;
+
+ case ABIL_EVOKE_TELEPORTATION: // ring of teleportation
+ case ABIL_TELEPORTATION: // teleport mut
+ if (you.mutation[MUT_TELEPORT_AT_WILL] == 3)
+ you_teleport2( true, true ); // instant and to new area of Abyss
+ else
+ you_teleport();
+
+ if (abil.ability == ABIL_EVOKE_TELEPORTATION)
+ exercise( SK_EVOCATIONS, 1 );
+ break;
+
+ case ABIL_BREATHE_FIRE:
+ case ABIL_BREATHE_FROST:
+ case ABIL_BREATHE_POISON:
+ case ABIL_BREATHE_LIGHTNING:
+ case ABIL_SPIT_ACID:
+ case ABIL_BREATHE_POWER:
+ case ABIL_BREATHE_STICKY_FLAME:
+ case ABIL_BREATHE_STEAM:
+ if (you.duration[DUR_BREATH_WEAPON]
+ && Curr_abil[abil_used].which != ABIL_SPIT_ACID)
+ {
+ canned_msg(MSG_CANNOT_DO_YET);
+ return (false);
+ }
+ else if (spell_direction( abild, beam ) == -1)
+ {
+ canned_msg(MSG_OK);
+ return (false);
+ }
+
+ switch (Curr_abil[abil_used].which)
+ {
+ case ABIL_BREATHE_FIRE:
+ power = you.experience_level;
+ power += you.mutation[MUT_BREATHE_FLAMES] * 4;
+
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON)
+ power += 12;
+
+ // don't check for hell serpents - they get hell fire,
+ // never regular fire (GDL)
+
+ snprintf( info, INFO_SIZE, "You breathe fire%c", (power < 15)?'.':'!');
+ mpr(info);
+
+ zapping( ZAP_BREATHE_FIRE, power, beam);
+ break;
+
+ case ABIL_BREATHE_FROST:
+ mpr("You exhale a wave of freezing cold.");
+ zapping(ZAP_BREATHE_FROST, you.experience_level, beam);
+ break;
+
+ case ABIL_BREATHE_POISON:
+ mpr("You exhale a blast of poison gas.");
+ zapping(ZAP_BREATHE_POISON, you.experience_level, beam);
+ break;
+
+ case ABIL_BREATHE_LIGHTNING:
+ mpr("You spit a bolt of lightning.");
+ zapping(ZAP_LIGHTNING, (you.experience_level * 2), beam);
+ break;
+
+ case ABIL_SPIT_ACID:
+ mpr("You spit acid.");
+ zapping(ZAP_BREATHE_ACID, you.experience_level, beam);
+ break;
+
+ case ABIL_BREATHE_POWER:
+ mpr("You spit a bolt of incandescent energy.");
+ zapping(ZAP_BREATHE_POWER, you.experience_level, beam);
+ break;
+
+ case ABIL_BREATHE_STICKY_FLAME:
+ mpr("You spit a glob of burning liquid.");
+ zapping(ZAP_STICKY_FLAME, you.experience_level, beam);
+ break;
+
+ case ABIL_BREATHE_STEAM:
+ mpr("You exhale a blast of scalding steam.");
+ zapping(ZAP_BREATHE_STEAM, you.experience_level, beam);
+ break;
+
+ }
+
+ if (Curr_abil[abil_used].which != ABIL_SPIT_ACID)
+ {
+ you.duration[DUR_BREATH_WEAPON] = 3 + random2(5)
+ + random2(30 - you.experience_level);
+ }
+
+ if (Curr_abil[abil_used].which == ABIL_BREATHE_STEAM)
+ {
+ you.duration[DUR_BREATH_WEAPON] /= 2;
+ }
+ break;
+
+ case ABIL_EVOKE_BLINK: // randarts
+ case ABIL_BLINK: // mutation
+ random_blink(true);
+
+ if (abil.ability == ABIL_EVOKE_BLINK)
+ exercise( SK_EVOCATIONS, 1 );
+ break;
+
+ case ABIL_EVOKE_BERSERK: // amulet of rage, randarts
+ if (you.hunger_state < HS_SATIATED)
+ {
+ mpr("You're too hungry to berserk.");
+ return (false);
+ }
+
+ go_berserk(true);
+ exercise( SK_EVOCATIONS, 1 );
+ break;
+
+ // fly (kenku) -- eventually becomes permanent (see acr.cc)
+ case ABIL_FLY:
+ cast_fly( you.experience_level * 4 );
+
+ if (you.experience_level > 14)
+ {
+ mpr("You feel very comfortable in the air.");
+ you.levitation = 100;
+ you.duration[DUR_CONTROLLED_FLIGHT] = 100;
+ }
+ break;
+
+ case ABIL_FLY_II: // Fly (Draconians, or anything else with wings)
+ if (you.exhausted)
+ {
+ mpr("You're too exhausted to fly.");
+ return (false);
+ }
+ else if (you.burden_state != BS_UNENCUMBERED)
+ {
+ mpr("You're carrying too much weight to fly.");
+ return (false);
+ }
+ else
+ {
+ cast_fly( you.experience_level * 2 );
+ // you.attribute[ATTR_EXPENSIVE_FLIGHT] = 1; // unused
+ }
+ break;
+
+ // DEMONIC POWERS:
+ case ABIL_SUMMON_MINOR_DEMON:
+ summon_ice_beast_etc( you.experience_level * 4,
+ summon_any_demon(DEMON_LESSER) );
+ break;
+
+ case ABIL_SUMMON_DEMON:
+ summon_ice_beast_etc( you.experience_level * 4,
+ summon_any_demon(DEMON_COMMON) );
+ break;
+
+ case ABIL_HELLFIRE:
+ your_spells(SPELL_HELLFIRE, 20 + you.experience_level, false);
+ break;
+
+ case ABIL_TORMENT:
+ if (you.is_undead)
+ {
+ mpr("The unliving cannot use this ability.");
+ return (false);
+ }
+
+ torment(you.x_pos, you.y_pos);
+ break;
+
+ case ABIL_RAISE_DEAD:
+ your_spells(SPELL_ANIMATE_DEAD, you.experience_level * 5, false);
+ break;
+
+ case ABIL_CONTROL_DEMON:
+ if (spell_direction(abild, beam) == -1)
+ {
+ canned_msg(MSG_OK);
+ return (false);
+ }
+
+ zapping(ZAP_CONTROL_DEMON, you.experience_level * 5, beam);
+ break;
+
+ case ABIL_TO_PANDEMONIUM:
+ if (you.level_type == LEVEL_PANDEMONIUM)
+ {
+ mpr("You're already here.");
+ return (false);
+ }
+
+ banished(DNGN_ENTER_PANDEMONIUM);
+ break;
+
+ case ABIL_CHANNELING:
+ mpr("You channel some magical energy.");
+ inc_mp(1 + random2(5), false);
+ break;
+
+ case ABIL_THROW_FLAME:
+ case ABIL_THROW_FROST:
+ if (spell_direction(abild, beam) == -1)
+ {
+ canned_msg(MSG_OK);
+ return (false);
+ }
+
+ zapping( (Curr_abil[abil_used].which == ABIL_THROW_FLAME ? ZAP_FLAME
+ : ZAP_FROST),
+ you.experience_level * 3,
+ beam );
+ break;
+
+ case ABIL_BOLT_OF_DRAINING:
+ if (spell_direction(abild, beam) == -1)
+ {
+ canned_msg(MSG_OK);
+ return (false);
+ }
+
+ zapping(ZAP_NEGATIVE_ENERGY, you.experience_level * 6, beam);
+ break;
+
+ case ABIL_EVOKE_TURN_INVISIBLE: // ring, randarts, darkness items
+ if (you.hunger_state < HS_SATIATED)
+ {
+ mpr("You're too hungry to turn invisible.");
+ return (false);
+ }
+
+ potion_effect( POT_INVISIBILITY, 2 * you.skills[SK_EVOCATIONS] + 5 );
+ contaminate_player( 1 + random2(3) );
+ exercise( SK_EVOCATIONS, 1 );
+ break;
+
+ case ABIL_EVOKE_TURN_VISIBLE:
+ mpr("You feel less transparent.");
+ you.invis = 1;
+ break;
+
+ case ABIL_EVOKE_LEVITATE: // ring, boots, randarts
+ potion_effect( POT_LEVITATION, 2 * you.skills[SK_EVOCATIONS] + 30 );
+ exercise( SK_EVOCATIONS, 1 );
+ break;
+
+ case ABIL_EVOKE_STOP_LEVITATING:
+ mpr("You feel heavy.");
+ you.levitation = 1;
+ break;
+
+ case ABIL_END_TRANSFORMATION:
+ mpr("You feel almost normal.");
+ you.duration[DUR_TRANSFORMATION] = 2;
+ break;
+
+ // INVOCATIONS:
+ case ABIL_ZIN_REPEL_UNDEAD:
+ case ABIL_TSO_REPEL_UNDEAD:
+ turn_undead(you.piety);
+
+ if (!you.duration[DUR_REPEL_UNDEAD])
+ mpr( "You feel a holy aura protecting you." );
+
+ you.duration[DUR_REPEL_UNDEAD] += 8
+ + roll_dice(2, 2 * you.skills[SK_INVOCATIONS]);
+
+ if (you.duration[ DUR_REPEL_UNDEAD ] > 50)
+ you.duration[ DUR_REPEL_UNDEAD ] = 50;
+
+ exercise(SK_INVOCATIONS, 1);
+ break;
+
+ case ABIL_ZIN_HEALING:
+ if (!cast_healing( 3 + (you.skills[SK_INVOCATIONS] / 6) ))
+ break;
+
+ exercise(SK_INVOCATIONS, 1 + random2(3));
+ break;
+
+ case ABIL_ZIN_PESTILENCE:
+ mpr( "You call forth a swarm of pestilential beasts!" );
+
+ if (!summon_swarm( you.skills[SK_INVOCATIONS] * 8, false, true ))
+ mpr( "Nothing seems to have answered your call." );
+
+ exercise( SK_INVOCATIONS, 2 + random2(4) );
+ break;
+
+ case ABIL_ZIN_HOLY_WORD:
+ holy_word( you.skills[SK_INVOCATIONS] * 8 );
+ exercise(SK_INVOCATIONS, 3 + random2(5));
+ break;
+
+ case ABIL_ZIN_SUMMON_GUARDIAN:
+ summon_ice_beast_etc(you.skills[SK_INVOCATIONS] * 4, MONS_ANGEL);
+ exercise(SK_INVOCATIONS, 8 + random2(10));
+ break;
+
+ case ABIL_TSO_SMITING:
+ cast_smiting( you.skills[SK_INVOCATIONS] * 6 );
+ exercise( SK_INVOCATIONS, (coinflip()? 3 : 2) );
+ break;
+
+ case ABIL_TSO_ANNIHILATE_UNDEAD:
+ if (spell_direction(spd, beam) == -1)
+ {
+ canned_msg(MSG_OK);
+ return (false);
+ }
+
+ zapping(ZAP_DISPEL_UNDEAD, you.skills[SK_INVOCATIONS] * 6, beam);
+ exercise(SK_INVOCATIONS, 2 + random2(4));
+ break;
+
+ case ABIL_TSO_THUNDERBOLT:
+ if (spell_direction(spd, beam) == -1)
+ {
+ canned_msg(MSG_OK);
+ return (false);
+ }
+
+ zapping(ZAP_LIGHTNING, you.skills[SK_INVOCATIONS] * 6, beam);
+ exercise(SK_INVOCATIONS, 3 + random2(6));
+ break;
+
+ case ABIL_TSO_SUMMON_DAEVA:
+ summon_ice_beast_etc(you.skills[SK_INVOCATIONS] * 4, MONS_DAEVA);
+ exercise(SK_INVOCATIONS, 8 + random2(10));
+ break;
+
+ case ABIL_KIKU_RECALL_UNDEAD_SLAVES:
+ recall(1);
+ exercise(SK_INVOCATIONS, 1);
+ break;
+
+ case ABIL_KIKU_ENSLAVE_UNDEAD:
+ if (spell_direction(spd, beam) == -1)
+ {
+ canned_msg(MSG_OK);
+ return (false);
+ }
+
+ zapping( ZAP_ENSLAVE_UNDEAD, you.skills[SK_INVOCATIONS] * 8, beam );
+ exercise(SK_INVOCATIONS, 5 + random2(5));
+ break;
+
+ case ABIL_KIKU_INVOKE_DEATH:
+ summon_ice_beast_etc(20 + you.skills[SK_INVOCATIONS] * 3, MONS_REAPER);
+ exercise(SK_INVOCATIONS, 10 + random2(14));
+ break;
+
+ case ABIL_YRED_ANIMATE_CORPSE:
+ mpr("You call on the dead to walk for you...");
+
+ animate_a_corpse( you.x_pos, you.y_pos, BEH_FRIENDLY,
+ you.pet_target, CORPSE_BODY );
+
+ exercise(SK_INVOCATIONS, 2 + random2(4));
+ break;
+
+ case ABIL_YRED_RECALL_UNDEAD:
+ recall(1);
+ exercise(SK_INVOCATIONS, 2 + random2(4));
+ break;
+
+ case ABIL_YRED_ANIMATE_DEAD:
+ mpr("You call on the dead to walk for you...");
+
+ animate_dead( 1 + you.skills[SK_INVOCATIONS], BEH_FRIENDLY,
+ you.pet_target, 1 );
+
+ exercise(SK_INVOCATIONS, 2 + random2(4));
+ break;
+
+ case ABIL_YRED_DRAIN_LIFE:
+ drain_life( you.skills[SK_INVOCATIONS] );
+ exercise(SK_INVOCATIONS, 2 + random2(4));
+ break;
+
+ case ABIL_YRED_CONTROL_UNDEAD:
+ mass_enchantment( ENCH_CHARM, you.skills[SK_INVOCATIONS] * 8, MHITYOU );
+ exercise(SK_INVOCATIONS, 3 + random2(4));
+ break;
+
+ case ABIL_VEHUMET_CHANNEL_ENERGY:
+ mpr("You channel some magical energy.");
+
+ inc_mp(1 + random2(you.skills[SK_INVOCATIONS] / 4 + 2), false);
+ exercise(SK_INVOCATIONS, 1 + random2(3));
+ break;
+
+ case ABIL_OKAWARU_MIGHT:
+ potion_effect( POT_MIGHT, you.skills[SK_INVOCATIONS] * 8 );
+ exercise(SK_INVOCATIONS, 1 + random2(3));
+ break;
+
+ case ABIL_OKAWARU_HEALING:
+ if (!cast_healing( 3 + (you.skills[SK_INVOCATIONS] / 6) ))
+ break;
+
+ exercise(SK_INVOCATIONS, 2 + random2(5));
+ break;
+
+ case ABIL_OKAWARU_HASTE:
+ potion_effect( POT_SPEED, you.skills[SK_INVOCATIONS] * 8 );
+ exercise(SK_INVOCATIONS, 3 + random2(7));
+ break;
+
+ case ABIL_MAKHLEB_MINOR_DESTRUCTION:
+ if (spell_direction(spd, beam) == -1)
+ {
+ canned_msg(MSG_OK);
+ return (false);
+ }
+
+ power = you.skills[SK_INVOCATIONS]
+ + random2( 1 + you.skills[SK_INVOCATIONS] )
+ + random2( 1 + you.skills[SK_INVOCATIONS] );
+
+ switch (random2(5))
+ {
+ case 0: zapping( ZAP_FLAME, power, beam ); break;
+ case 1: zapping( ZAP_PAIN, power, beam ); break;
+ case 2: zapping( ZAP_STONE_ARROW, power, beam ); break;
+ case 3: zapping( ZAP_ELECTRICITY, power, beam ); break;
+ case 4: zapping( ZAP_BREATHE_ACID, power / 2, beam ); break;
+ }
+
+ exercise(SK_INVOCATIONS, 1);
+ break;
+
+ case ABIL_MAKHLEB_LESSER_SERVANT_OF_MAKHLEB:
+ summon_ice_beast_etc( 20 + you.skills[SK_INVOCATIONS] * 3,
+ MONS_NEQOXEC + random2(5) );
+
+ exercise(SK_INVOCATIONS, 2 + random2(3));
+ break;
+
+ case ABIL_MAKHLEB_MAJOR_DESTRUCTION:
+ if (spell_direction(spd, beam) == -1)
+ {
+ canned_msg(MSG_OK);
+ return (false);
+ }
+
+ power = you.skills[SK_INVOCATIONS] * 3
+ + random2( 1 + you.skills[SK_INVOCATIONS] )
+ + random2( 1 + you.skills[SK_INVOCATIONS] );
+
+ switch (random2(8))
+ {
+ case 0: zapping( ZAP_FIRE, power, beam ); break;
+ case 1: zapping( ZAP_FIREBALL, power, beam ); break;
+ case 2: zapping( ZAP_LIGHTNING, power, beam ); break;
+ case 3: zapping( ZAP_NEGATIVE_ENERGY, power, beam ); break;
+ case 4: zapping( ZAP_STICKY_FLAME, power, beam ); break;
+ case 5: zapping( ZAP_IRON_BOLT, power, beam ); break;
+ case 6: zapping( ZAP_ORB_OF_ELECTRICITY, power, beam ); break;
+
+ case 7:
+ you.attribute[ATTR_DIVINE_LIGHTNING_PROTECTION] = 1;
+ mpr("Makhleb hurls a blast of lightning!");
+
+ // make a divine lightning bolt...
+ beam.beam_source = NON_MONSTER;
+ beam.type = SYM_BURST;
+ beam.damage = dice_def( 3, 30 );
+ beam.flavour = BEAM_ELECTRICITY;
+ beam.target_x = you.x_pos;
+ beam.target_y = you.y_pos;
+ strcpy(beam.beam_name, "blast of lightning");
+ beam.colour = LIGHTCYAN;
+ beam.thrower = KILL_YOU;
+ beam.aux_source = "Makhleb's lightning strike";
+ beam.ex_size = 1 + you.skills[SK_INVOCATIONS] / 8;
+ beam.isTracer = false;
+
+ // ... and fire!
+ explosion(beam);
+
+ // protection down
+ mpr("Your divine protection wanes.");
+ you.attribute[ATTR_DIVINE_LIGHTNING_PROTECTION] = 0;
+ break;
+ }
+
+ exercise(SK_INVOCATIONS, 3 + random2(5));
+ break;
+
+ case ABIL_MAKHLEB_GREATER_SERVANT_OF_MAKHLEB:
+ summon_ice_beast_etc( 20 + you.skills[SK_INVOCATIONS] * 3,
+ MONS_EXECUTIONER + random2(5) );
+
+ exercise(SK_INVOCATIONS, 6 + random2(6));
+ break;
+
+ case ABIL_TROG_BERSERK:
+ // Trog abilities don't use or train invocations.
+ if (you.hunger_state < HS_SATIATED)
+ {
+ mpr("You're too hungry to berserk.");
+ return (false);
+ }
+
+ go_berserk(true);
+ break;
+
+ case ABIL_TROG_MIGHT:
+ // Trog abilities don't use or train invocations.
+ potion_effect( POT_MIGHT, 150 );
+ break;
+
+ case ABIL_TROG_HASTE_SELF:
+ // Trog abilities don't use or train invocations.
+ potion_effect( POT_SPEED, 150 );
+ break;
+
+ case ABIL_SIF_MUNA_FORGET_SPELL:
+ cast_selective_amnesia(true);
+ break;
+
+ case ABIL_ELYVILON_LESSER_HEALING:
+ if (!cast_healing( 3 + (you.skills[SK_INVOCATIONS] / 6) ))
+ break;
+
+ exercise( SK_INVOCATIONS, 1 );
+ break;
+
+ case ABIL_ELYVILON_PURIFICATION:
+ purification();
+ exercise( SK_INVOCATIONS, 2 + random2(3) );
+ break;
+
+ case ABIL_ELYVILON_HEALING:
+ if (!cast_healing( 10 + (you.skills[SK_INVOCATIONS] / 3) ))
+ break;
+
+ exercise( SK_INVOCATIONS, 3 + random2(5) );
+ break;
+
+ case ABIL_ELYVILON_RESTORATION:
+ restore_stat( STAT_ALL, false );
+ unrot_hp( 100 );
+
+ exercise( SK_INVOCATIONS, 4 + random2(6) );
+ break;
+
+ case ABIL_ELYVILON_GREATER_HEALING:
+ if (!cast_healing( 20 + you.skills[SK_INVOCATIONS] * 2 ))
+ break;
+
+ exercise( SK_INVOCATIONS, 6 + random2(10) );
+ break;
+
+ //jmf: intended as invocations from evil god(s):
+ case ABIL_CHARM_SNAKE:
+ cast_snake_charm( you.experience_level * 2
+ + you.skills[SK_INVOCATIONS] * 3 );
+
+ exercise(SK_INVOCATIONS, 2 + random2(4));
+ break;
+
+ case ABIL_TRAN_SERPENT_OF_HELL:
+ transform(10 + (you.experience_level * 2) +
+ (you.skills[SK_INVOCATIONS] * 3), TRAN_SERPENT_OF_HELL);
+
+ exercise(SK_INVOCATIONS, 6 + random2(9));
+ break;
+
+ case ABIL_BREATHE_HELLFIRE:
+ if (you.duration[DUR_BREATH_WEAPON])
+ {
+ canned_msg(MSG_CANNOT_DO_YET);
+ return (false);
+ }
+
+ your_spells( SPELL_HELLFIRE, 20 + you.experience_level, false );
+
+ you.duration[DUR_BREATH_WEAPON] +=
+ 3 + random2(5) + random2(30 - you.experience_level);
+ break;
+
+ case ABIL_ROTTING:
+ cast_rotting(you.experience_level * 2 + you.skills[SK_INVOCATIONS] * 3);
+ exercise(SK_INVOCATIONS, 2 + random2(4));
+ break;
+
+ case ABIL_TORMENT_II:
+ if (you.is_undead)
+ {
+ mpr("The unliving cannot use this ability.");
+ return (false);
+ }
+
+ torment(you.x_pos, you.y_pos);
+ exercise(SK_INVOCATIONS, 2 + random2(4));
+ break;
+
+ case ABIL_SHUGGOTH_SEED:
+ if (you.duration[DUR_SHUGGOTH_SEED_RELOAD])
+ {
+ canned_msg(MSG_CANNOT_DO_YET);
+ return (false);
+ }
+
+ cast_shuggoth_seed( you.experience_level * 2
+ + you.skills[SK_INVOCATIONS] * 3 );
+
+ you.duration[DUR_SHUGGOTH_SEED_RELOAD] = 10 + random2avg(39, 2);
+ exercise(SK_INVOCATIONS, 2 + random2(4));
+ break;
+
+ case ABIL_RENOUNCE_RELIGION:
+ if (yesno("Really renounce your faith, foregoing its fabulous benefits?")
+ && yesno( "Are you sure you won't change your mind later?" ))
+ {
+ excommunication();
+ }
+ else
+ {
+ canned_msg(MSG_OK);
+ }
+ break;
+
+ default:
+ mpr("Sorry, you can't do that.");
+ break;
+ }
+
+ // All failures should have returned by this point, so we'll
+ // apply the costs -- its not too neat, but it works for now. -- bwr
+ const int food_cost = abil.food_cost + random2avg(abil.food_cost, 2);
+ const int piety_cost = abil.piety_cost + random2((abil.piety_cost + 1) / 2 + 1);
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "Cost: mp=%d; hp=%d; food=%d; piety=%d",
+ abil.mp_cost, abil.hp_cost, food_cost, piety_cost );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ if (abil.mp_cost)
+ {
+ dec_mp( abil.mp_cost );
+ if (abil.flags & ABFLAG_PERMANENT_MP)
+ rot_mp(1);
+ }
+
+ if (abil.hp_cost)
+ {
+ dec_hp( abil.hp_cost, false );
+ if (abil.flags & ABFLAG_PERMANENT_HP)
+ rot_hp(1);
+ }
+
+ if (food_cost)
+ make_hungry( food_cost, false );
+
+ if (piety_cost)
+ lose_piety( piety_cost );
+
+ return (true);
+} // end activate_ability()
+
+
+// Lists any abilities the player may possess
+char show_abilities( void )
+/*************************/
+{
+ int loopy = 0;
+ char lines = 0;
+ unsigned char anything = 0;
+ char ki;
+ bool can_invoke = false;
+
+ const int num_lines = get_number_of_lines();
+
+ for (loopy = 0; loopy < 52; loopy++)
+ {
+ if (Curr_abil[loopy].is_invocation)
+ {
+ can_invoke = true;
+ break;
+ }
+ }
+
+
+#ifdef DOS_TERM
+ char buffer[4800];
+
+ gettext(1, 1, 80, 25, buffer);
+ window(1, 1, 80, 25);
+#endif
+
+ clrscr();
+ cprintf(" Ability Cost Success");
+ lines++;
+
+ for (int do_invoke = 0; do_invoke < (can_invoke ? 2 : 1); do_invoke++)
+ {
+ if (do_invoke)
+ {
+ anything++;
+ textcolor(BLUE);
+ cprintf(EOL " Invocations - ");
+ textcolor(LIGHTGREY);
+ lines++;
+ }
+
+ for (loopy = 0; loopy < 52; loopy++)
+ {
+ if (lines > num_lines - 2)
+ {
+ gotoxy(1, num_lines);
+ cprintf("-more-");
+
+ ki = getch();
+
+ if (ki == ESCAPE)
+ {
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+#endif
+ return (ESCAPE);
+ }
+
+ if (ki >= 'A' && ki <= 'z')
+ {
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+#endif
+ return (ki);
+ }
+
+ if (ki == 0)
+ ki = getch();
+
+ lines = 0;
+ clrscr();
+ gotoxy(1, 1);
+ anything = 0;
+ }
+
+ if (Curr_abil[loopy].which != ABIL_NON_ABILITY
+ && (do_invoke == Curr_abil[loopy].is_invocation))
+ {
+ anything++;
+
+ if (lines > 0)
+ cprintf(EOL);
+
+ lines++;
+
+ const struct ability_def abil = get_ability_def( Curr_abil[loopy].which );
+
+ cprintf( " %c - %s", index_to_letter(loopy), abil.name );
+
+ // Output costs:
+ gotoxy( 35, wherey() );
+
+ std::string cost_str = make_cost_description( abil );
+
+ if (cost_str.length() > 24)
+ cost_str = cost_str.substr( 0, 24 );
+
+ cprintf( cost_str.c_str() );
+
+ gotoxy(60, wherey());
+
+ int spell_f = Curr_abil[loopy].fail;
+
+ cprintf( (spell_f >= 100) ? "Useless" :
+ (spell_f > 90) ? "Terrible" :
+ (spell_f > 80) ? "Cruddy" :
+ (spell_f > 70) ? "Bad" :
+ (spell_f > 60) ? "Very Poor" :
+ (spell_f > 50) ? "Poor" :
+ (spell_f > 40) ? "Fair" :
+ (spell_f > 30) ? "Good" :
+ (spell_f > 20) ? "Very Good" :
+ (spell_f > 10) ? "Great" :
+ (spell_f > 0) ? "Excellent" :
+ "Perfect" );
+
+ gotoxy(70, wherey());
+ } // end if conditional
+ } // end "for loopy"
+ }
+
+ if (anything > 0)
+ {
+ ki = getch();
+
+ if (ki >= 'A' && ki <= 'z')
+ {
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+#endif
+ return (ki);
+ }
+
+ if (ki == 0)
+ ki = getch();
+
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+#endif
+
+ return (ki);
+ }
+
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+#endif
+
+ ki = getch();
+
+ return (ki);
+} // end show_abilities()
+
+
+bool generate_abilities( void )
+/*****************************/
+{
+ int loopy;
+ int ability = -1; // used with draconian checks {dlb}
+
+ // fill array of structs with "empty" values {dlb}:
+ for (loopy = 0; loopy < 52; loopy++)
+ {
+ Curr_abil[loopy].which = ABIL_NON_ABILITY;
+ Curr_abil[loopy].fail = 100;
+ Curr_abil[loopy].is_invocation = false;
+ }
+
+ // first we do the racial abilities:
+
+ // Mummies get the ability to restore HPs and stats, but it
+ // costs permanent MP (and those can never be recovered). -- bwr
+ if (you.species == SP_MUMMY && you.experience_level >= 13)
+ {
+ insert_ability( ABIL_MUMMY_RESTORATION );
+ }
+
+ // checking for species-related abilities and mutagenic counterparts {dlb}:
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_NONE
+ && ((you.species == SP_GREY_ELF && you.experience_level >= 5)
+ || (you.species == SP_HIGH_ELF && you.experience_level >= 15)))
+ {
+ insert_ability( ABIL_GLAMOUR );
+ }
+
+ if (you.species == SP_NAGA)
+ {
+ if (you.mutation[MUT_BREATHE_POISON])
+ insert_ability( ABIL_BREATHE_POISON );
+ else
+ insert_ability( ABIL_SPIT_POISON );
+ }
+ else if (you.mutation[MUT_SPIT_POISON])
+ {
+ insert_ability( ABIL_SPIT_POISON );
+ }
+
+ if (player_genus(GENPC_DRACONIAN))
+ {
+ if (you.experience_level >= 7)
+ {
+ ability = (
+ (you.species == SP_GREEN_DRACONIAN) ? ABIL_BREATHE_POISON :
+ (you.species == SP_RED_DRACONIAN) ? ABIL_BREATHE_FIRE :
+ (you.species == SP_WHITE_DRACONIAN) ? ABIL_BREATHE_FROST :
+ (you.species == SP_GOLDEN_DRACONIAN) ? ABIL_SPIT_ACID :
+ (you.species == SP_BLACK_DRACONIAN) ? ABIL_BREATHE_LIGHTNING :
+ (you.species == SP_PURPLE_DRACONIAN) ? ABIL_BREATHE_POWER :
+ (you.species == SP_PALE_DRACONIAN) ? ABIL_BREATHE_STEAM :
+ (you.species == SP_MOTTLED_DRACONIAN)? ABIL_BREATHE_STICKY_FLAME:
+ -1);
+
+ if (ability != -1)
+ insert_ability( ability );
+ }
+ }
+
+ //jmf: alternately put check elsewhere
+ if ((you.level_type == LEVEL_DUNGEON
+ && (you.species == SP_GNOME || you.mutation[MUT_MAPPING]))
+ || (you.level_type == LEVEL_PANDEMONIUM
+ && you.mutation[MUT_MAPPING] == 3))
+ {
+ insert_ability( ABIL_MAPPING );
+ }
+
+ if (!you.duration[DUR_CONTROLLED_FLIGHT] && !player_is_levitating())
+ {
+ // kenku can fly, but only from the ground
+ // (until levitation 15, when it becomes permanent until revoked)
+ //jmf: "upgrade" for draconians -- expensive flight
+ if (you.species == SP_KENKU && you.experience_level >= 5)
+ insert_ability( ABIL_FLY );
+ else if (player_genus(GENPC_DRACONIAN) && you.mutation[MUT_BIG_WINGS])
+ insert_ability( ABIL_FLY_II );
+ }
+
+ // demonic powers {dlb}:
+ if (you.mutation[MUT_SUMMON_MINOR_DEMONS])
+ insert_ability( ABIL_SUMMON_MINOR_DEMON );
+
+ if (you.mutation[MUT_SUMMON_DEMONS])
+ insert_ability( ABIL_SUMMON_DEMON );
+
+ if (you.mutation[MUT_HURL_HELLFIRE])
+ insert_ability( ABIL_HELLFIRE );
+
+ if (you.mutation[MUT_CALL_TORMENT])
+ insert_ability( ABIL_TORMENT );
+
+ if (you.mutation[MUT_RAISE_DEAD])
+ insert_ability( ABIL_RAISE_DEAD );
+
+ if (you.mutation[MUT_CONTROL_DEMONS])
+ insert_ability( ABIL_CONTROL_DEMON );
+
+ if (you.mutation[MUT_PANDEMONIUM])
+ insert_ability( ABIL_TO_PANDEMONIUM );
+
+ if (you.mutation[MUT_CHANNEL_HELL])
+ insert_ability( ABIL_CHANNELING );
+
+ if (you.mutation[MUT_THROW_FLAMES])
+ insert_ability( ABIL_THROW_FLAME );
+
+ if (you.mutation[MUT_THROW_FROST])
+ insert_ability( ABIL_THROW_FROST );
+
+ if (you.mutation[MUT_SMITE])
+ insert_ability( ABIL_BOLT_OF_DRAINING );
+
+ if (you.duration[DUR_TRANSFORMATION])
+ insert_ability( ABIL_END_TRANSFORMATION );
+
+ if (you.mutation[MUT_BLINK])
+ insert_ability( ABIL_BLINK );
+
+ if (you.mutation[MUT_TELEPORT_AT_WILL])
+ insert_ability( ABIL_TELEPORTATION );
+
+ // gods take abilities away until penance completed -- bwr
+ if (!player_under_penance() && !silenced( you.x_pos, you.y_pos ))
+ {
+ switch (you.religion)
+ {
+ case GOD_ZIN:
+ if (you.piety >= 30)
+ insert_ability( ABIL_ZIN_REPEL_UNDEAD );
+ if (you.piety >= 50)
+ insert_ability( ABIL_ZIN_HEALING );
+ if (you.piety >= 75)
+ insert_ability( ABIL_ZIN_PESTILENCE );
+ if (you.piety >= 100)
+ insert_ability( ABIL_ZIN_HOLY_WORD );
+ if (you.piety >= 120)
+ insert_ability( ABIL_ZIN_SUMMON_GUARDIAN );
+ break;
+
+ case GOD_SHINING_ONE:
+ if (you.piety >= 30)
+ insert_ability( ABIL_TSO_REPEL_UNDEAD );
+ if (you.piety >= 50)
+ insert_ability( ABIL_TSO_SMITING );
+ if (you.piety >= 75)
+ insert_ability( ABIL_TSO_ANNIHILATE_UNDEAD );
+ if (you.piety >= 100)
+ insert_ability( ABIL_TSO_THUNDERBOLT );
+ if (you.piety >= 120)
+ insert_ability( ABIL_TSO_SUMMON_DAEVA );
+ break;
+
+ case GOD_YREDELEMNUL:
+ if (you.piety >= 30)
+ insert_ability( ABIL_YRED_ANIMATE_CORPSE );
+ if (you.piety >= 50)
+ insert_ability( ABIL_YRED_RECALL_UNDEAD );
+ if (you.piety >= 75)
+ insert_ability( ABIL_YRED_ANIMATE_DEAD );
+ if (you.piety >= 100)
+ insert_ability( ABIL_YRED_DRAIN_LIFE );
+ if (you.piety >= 120)
+ insert_ability( ABIL_YRED_CONTROL_UNDEAD );
+ break;
+
+ case GOD_ELYVILON:
+ if (you.piety >= 30)
+ insert_ability( ABIL_ELYVILON_LESSER_HEALING );
+ if (you.piety >= 50)
+ insert_ability( ABIL_ELYVILON_PURIFICATION );
+ if (you.piety >= 75)
+ insert_ability( ABIL_ELYVILON_HEALING );
+ if (you.piety >= 100)
+ insert_ability( ABIL_ELYVILON_RESTORATION );
+ if (you.piety >= 120)
+ insert_ability( ABIL_ELYVILON_GREATER_HEALING );
+ break;
+
+ case GOD_MAKHLEB:
+ if (you.piety >= 50)
+ insert_ability( ABIL_MAKHLEB_MINOR_DESTRUCTION );
+ if (you.piety >= 75)
+ insert_ability( ABIL_MAKHLEB_LESSER_SERVANT_OF_MAKHLEB );
+ if (you.piety >= 100)
+ insert_ability( ABIL_MAKHLEB_MAJOR_DESTRUCTION );
+ if (you.piety >= 120)
+ insert_ability( ABIL_MAKHLEB_GREATER_SERVANT_OF_MAKHLEB );
+ break;
+
+ case GOD_KIKUBAAQUDGHA:
+ if (you.piety >= 30)
+ insert_ability( ABIL_KIKU_RECALL_UNDEAD_SLAVES );
+ if (you.piety >= 75)
+ insert_ability( ABIL_KIKU_ENSLAVE_UNDEAD );
+ if (you.piety >= 120)
+ insert_ability( ABIL_KIKU_INVOKE_DEATH );
+ break;
+
+ case GOD_OKAWARU:
+ if (you.piety >= 30)
+ insert_ability( ABIL_OKAWARU_MIGHT );
+ if (you.piety >= 50)
+ insert_ability( ABIL_OKAWARU_HEALING );
+ if (you.piety >= 120)
+ insert_ability( ABIL_OKAWARU_HASTE );
+ break;
+
+ case GOD_TROG:
+ if (you.piety >= 30)
+ insert_ability( ABIL_TROG_BERSERK );
+ if (you.piety >= 50)
+ insert_ability( ABIL_TROG_MIGHT );
+ if (you.piety >= 100)
+ insert_ability( ABIL_TROG_HASTE_SELF );
+ break;
+
+ case GOD_SIF_MUNA:
+ if (you.piety >= 50)
+ insert_ability( ABIL_SIF_MUNA_FORGET_SPELL );
+ break;
+
+ case GOD_VEHUMET:
+ if (you.piety >= 100)
+ insert_ability( ABIL_VEHUMET_CHANNEL_ENERGY );
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // and finally, the ability to opt-out of your faith {dlb}:
+ if (you.religion != GOD_NO_GOD && !silenced( you.x_pos, you.y_pos ))
+ insert_ability( ABIL_RENOUNCE_RELIGION );
+
+ //jmf: check for breath weapons -- they're exclusive of each other I hope!
+ // better make better ones first.
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_SERPENT_OF_HELL)
+ {
+ insert_ability( ABIL_BREATHE_HELLFIRE );
+ }
+ else if (you.attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON
+ || you.mutation[MUT_BREATHE_FLAMES])
+ {
+ insert_ability( ABIL_BREATHE_FIRE );
+ }
+
+ // checking for unreleased delayed fireball
+ if (you.attribute[ ATTR_DELAYED_FIREBALL ])
+ {
+ insert_ability( ABIL_DELAYED_FIREBALL );
+ }
+
+ // evocations from items:
+ if (scan_randarts(RAP_BLINK))
+ insert_ability( ABIL_EVOKE_BLINK );
+
+ if (wearing_amulet(AMU_RAGE) || scan_randarts(RAP_BERSERK))
+ insert_ability( ABIL_EVOKE_BERSERK );
+
+ if (scan_randarts( RAP_MAPPING ))
+ insert_ability( ABIL_EVOKE_MAPPING );
+
+ if (player_equip( EQ_RINGS, RING_INVISIBILITY )
+ || player_equip_ego_type( EQ_ALL_ARMOUR, SPARM_DARKNESS )
+ || scan_randarts( RAP_INVISIBLE ))
+ {
+ // Now you can only turn invisibility off if you have an
+ // activatable item. Wands and potions allow will have
+ // to time out. -- bwr
+ if (you.invis)
+ insert_ability( ABIL_EVOKE_TURN_VISIBLE );
+ else
+ insert_ability( ABIL_EVOKE_TURN_INVISIBLE );
+ }
+
+ //jmf: "upgrade" for draconians -- expensive flight
+ // note: this ability only applies to this counter
+ if (player_equip( EQ_RINGS, RING_LEVITATION )
+ || player_equip_ego_type( EQ_BOOTS, SPARM_LEVITATION )
+ || scan_randarts( RAP_LEVITATE ))
+ {
+ // Now you can only turn levitation off if you have an
+ // activatable item. Potions and miscast effects will
+ // have to time out (this makes the miscast effect actually
+ // a bit annoying). -- bwr
+ if (you.levitation)
+ insert_ability( ABIL_EVOKE_STOP_LEVITATING );
+ else
+ insert_ability( ABIL_EVOKE_LEVITATE );
+ }
+
+ if (player_equip( EQ_RINGS, RING_TELEPORTATION )
+ || scan_randarts( RAP_CAN_TELEPORT ))
+ {
+ insert_ability( ABIL_EVOKE_TELEPORTATION );
+ }
+
+ // this is a shameless kludge for the time being {dlb}:
+ // still shameless. -- bwr
+ for (loopy = 0; loopy < 52; loopy++)
+ {
+ if (Curr_abil[loopy].which != ABIL_NON_ABILITY)
+ return (true);
+ }
+
+ return (false);
+} // end generate_abilities()
+
+// Note: we're trying for a behaviour where the player gets
+// to keep their assigned invocation slots if they get excommunicated
+// and then rejoin (but if they spend time with another god we consider
+// the old invocation slots void and erase them). We also try to
+// protect any bindings the character might have made into the
+// traditional invocation slots (A-E and X). -- bwr
+void set_god_ability_helper( int abil, char letter )
+/**************************************************/
+{
+ int i;
+ const int index = letter_to_index( letter );
+
+ for (i = 0; i < 52; i++)
+ {
+ if (you.ability_letter_table[i] == abil)
+ break;
+ }
+
+ if (i == 52) // ability is not already assigned
+ {
+ // if slot is unoccupied, move in
+ if (you.ability_letter_table[index] == ABIL_NON_ABILITY)
+ you.ability_letter_table[index] = abil;
+ }
+}
+
+void set_god_ability_slots( void )
+/********************************/
+{
+ ASSERT( you.religion != GOD_NO_GOD );
+
+ int i;
+
+ set_god_ability_helper( ABIL_RENOUNCE_RELIGION, 'X' );
+
+ int num_abil = 0;
+ int abil_start = ABIL_NON_ABILITY;
+
+ switch (you.religion)
+ {
+ case GOD_ZIN:
+ abil_start = ABIL_ZIN_REPEL_UNDEAD;
+ num_abil = 5;
+ break;
+
+ case GOD_SHINING_ONE:
+ abil_start = ABIL_TSO_REPEL_UNDEAD;
+ num_abil = 5;
+ break;
+
+ case GOD_KIKUBAAQUDGHA:
+ abil_start = ABIL_KIKU_RECALL_UNDEAD_SLAVES;
+ num_abil = 3;
+ break;
+
+ case GOD_YREDELEMNUL:
+ abil_start = ABIL_YRED_ANIMATE_CORPSE;
+ num_abil = 5;
+ break;
+
+ case GOD_VEHUMET:
+ abil_start = ABIL_VEHUMET_CHANNEL_ENERGY;
+ num_abil = 1;
+ break;
+
+ case GOD_OKAWARU:
+ abil_start = ABIL_OKAWARU_MIGHT;
+ num_abil = 3;
+ break;
+
+ case GOD_MAKHLEB:
+ abil_start = ABIL_MAKHLEB_MINOR_DESTRUCTION;
+ num_abil = 4;
+ break;
+
+ case GOD_SIF_MUNA:
+ abil_start = ABIL_SIF_MUNA_FORGET_SPELL;
+ num_abil = 1;
+ break;
+
+ case GOD_TROG:
+ abil_start = ABIL_TROG_BERSERK;
+ num_abil = 3;
+ break;
+
+ case GOD_ELYVILON:
+ abil_start = ABIL_ELYVILON_LESSER_HEALING;
+ num_abil = 5;
+ break;
+
+ case GOD_NEMELEX_XOBEH:
+ case GOD_XOM:
+ default:
+ break;
+ }
+
+ // clear out other god invocations:
+ for (i = 0; i < 52; i++)
+ {
+ const int abil = you.ability_letter_table[i];
+
+ if ((abil >= ABIL_ZIN_REPEL_UNDEAD // is a god ability
+ && abil <= ABIL_ELYVILON_GREATER_HEALING)
+ && (num_abil == 0 // current god does have abilities
+ || abil < abil_start // not one of current god's abilities
+ || abil >= abil_start + num_abil))
+ {
+ you.ability_letter_table[i] = ABIL_NON_ABILITY;
+ }
+ }
+
+ // finally, add in current god's invocaions in traditional slots:
+ if (num_abil)
+ {
+ for (i = 0; i < num_abil; i++)
+ {
+ set_god_ability_helper( abil_start + i,
+ (Options.lowercase_invocations ? 'a' : 'A') + i );
+ }
+ }
+}
+
+
+// returns index to Curr_abil, -1 on failure
+static int find_ability_slot( int which_ability )
+/***********************************************/
+{
+ int slot;
+ for (slot = 0; slot < 52; slot++)
+ {
+ if (you.ability_letter_table[slot] == which_ability)
+ break;
+ }
+
+ // no requested slot, find new one and make it prefered.
+ if (slot == 52)
+ {
+ // skip over a-e if player prefers them for invocations
+ for (slot = (Options.lowercase_invocations ? 5 : 0); slot < 52; slot++)
+ {
+ if (you.ability_letter_table[slot] == ABIL_NON_ABILITY)
+ break;
+ }
+
+ // if we skipped over a-e to reserve them, try them now
+ if (Options.lowercase_invocations && slot == 52)
+ {
+ for (slot = 5; slot >= 0; slot--)
+ {
+ if (you.ability_letter_table[slot] == ABIL_NON_ABILITY)
+ break;
+ }
+ }
+
+ // All letters are assigned, check Curr_abil and try to steal a letter
+ if (slot == 52)
+ {
+ // backwards, to protect the low lettered slots from replacement
+ for (slot = 51; slot >= 0; slot--)
+ {
+ if (Curr_abil[slot].which == ABIL_NON_ABILITY)
+ break;
+ }
+
+ // no slots at all == no hope of adding
+ if (slot < 0)
+ return (-1);
+ }
+
+ // this ability now takes over this slot
+ you.ability_letter_table[slot] = which_ability;
+ }
+
+ return (slot);
+}
+
+static bool insert_ability( int which_ability )
+/**********************************************/
+{
+ ASSERT( which_ability != ABIL_NON_ABILITY );
+
+ int failure = 0;
+ bool perfect = false; // is perfect
+ bool invoc = false;
+
+ // Look through the table to see if there's a preference, else
+ // find a new empty slot for this ability. -- bwr
+ const int slot = find_ability_slot( which_ability );
+ if (slot == -1)
+ return (false);
+
+ Curr_abil[slot].which = which_ability;
+
+ switch (which_ability)
+ {
+ // begin spell abilities
+ case ABIL_DELAYED_FIREBALL:
+ case ABIL_MUMMY_RESTORATION:
+ perfect = true;
+ failure = 0;
+ break;
+
+ // begin species abilities - some are mutagenic, too {dlb}
+ case ABIL_GLAMOUR:
+ failure = 50 - (you.experience_level * 2);
+ break;
+
+ case ABIL_SPIT_POISON:
+ failure = ((you.species == SP_NAGA) ? 20 : 40)
+ - 10 * you.mutation[MUT_SPIT_POISON]
+ - you.experience_level;
+ break;
+
+ case ABIL_EVOKE_MAPPING:
+ failure = 30 - you.skills[SK_EVOCATIONS];
+ break;
+
+ case ABIL_MAPPING:
+ failure = ((you.species == SP_GNOME) ? 20 : 40)
+ - 10 * you.mutation[MUT_MAPPING]
+ - you.experience_level;
+ break;
+
+ case ABIL_BREATHE_FIRE:
+ failure = ((you.species == SP_RED_DRACONIAN) ? 30 : 50)
+ - 10 * you.mutation[MUT_BREATHE_FLAMES]
+ - you.experience_level;
+
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON)
+ failure -= 20;
+ break;
+
+ case ABIL_BREATHE_FROST:
+ case ABIL_BREATHE_POISON:
+ case ABIL_SPIT_ACID:
+ case ABIL_BREATHE_LIGHTNING:
+ case ABIL_BREATHE_POWER:
+ case ABIL_BREATHE_STICKY_FLAME:
+ failure = 30 - you.experience_level;
+
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON)
+ failure -= 20;
+ break;
+
+ case ABIL_BREATHE_STEAM:
+ failure = 20 - you.experience_level;
+
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON)
+ failure -= 20;
+ break;
+
+ case ABIL_FLY: // this is for kenku {dlb}
+ failure = 45 - (3 * you.experience_level);
+ break;
+
+ case ABIL_FLY_II: // this is for draconians {dlb}
+ failure = 45 - (you.experience_level + you.strength);
+ break;
+ // end species abilties (some mutagenic)
+
+ // begin demonic powers {dlb}
+ case ABIL_THROW_FLAME:
+ case ABIL_THROW_FROST:
+ failure = 10 - you.experience_level;
+ break;
+
+ case ABIL_SUMMON_MINOR_DEMON:
+ failure = 27 - you.experience_level;
+ break;
+
+ case ABIL_CHANNELING:
+ case ABIL_BOLT_OF_DRAINING:
+ failure = 30 - you.experience_level;
+ break;
+
+ case ABIL_CONTROL_DEMON:
+ failure = 35 - you.experience_level;
+ break;
+
+ case ABIL_SUMMON_DEMON:
+ failure = 40 - you.experience_level;
+ break;
+
+ case ABIL_TO_PANDEMONIUM:
+ failure = 57 - (you.experience_level * 2);
+ break;
+
+ case ABIL_HELLFIRE:
+ case ABIL_RAISE_DEAD:
+ failure = 50 - you.experience_level;
+ break;
+
+ case ABIL_TORMENT:
+ failure = 60 - you.experience_level;
+ break;
+
+ case ABIL_BLINK:
+ failure = 30 - (10 * you.mutation[MUT_BLINK]) - you.experience_level;
+ break;
+
+ case ABIL_TELEPORTATION:
+ failure = ((you.mutation[MUT_TELEPORT_AT_WILL] > 1) ? 30 : 50)
+ - you.experience_level;
+ break;
+ // end demonic powers {dlb}
+
+ // begin transformation abilities {dlb}
+ case ABIL_END_TRANSFORMATION:
+ perfect = true;
+ failure = 0;
+ break;
+
+ case ABIL_BREATHE_HELLFIRE:
+ failure = 32 - you.experience_level;
+ break;
+ // end transformation abilities {dlb}
+ //
+ // begin item abilities - some possibly mutagenic {dlb}
+ case ABIL_EVOKE_TURN_INVISIBLE:
+ case ABIL_EVOKE_TELEPORTATION:
+ failure = 60 - 2 * you.skills[SK_EVOCATIONS];
+ break;
+
+ case ABIL_EVOKE_TURN_VISIBLE:
+ case ABIL_EVOKE_STOP_LEVITATING:
+ perfect = true;
+ failure = 0;
+ break;
+
+ case ABIL_EVOKE_LEVITATE:
+ case ABIL_EVOKE_BLINK:
+ failure = 40 - 2 * you.skills[SK_EVOCATIONS];
+ break;
+
+ case ABIL_EVOKE_BERSERK:
+ failure = 50 - 2 * you.skills[SK_EVOCATIONS];
+
+ if (you.species == SP_TROLL)
+ failure -= 30;
+ else if (player_genus(GENPC_DWARVEN) || you.species == SP_HILL_ORC
+ || you.species == SP_OGRE)
+ {
+ failure -= 10;
+ }
+ break;
+ // end item abilities - some possibly mutagenic {dlb}
+
+ // begin invocations {dlb}
+ case ABIL_ELYVILON_PURIFICATION:
+ invoc = true;
+ failure = 20 - (you.piety / 20) - (5 * you.skills[SK_INVOCATIONS]);
+ break;
+
+ case ABIL_ZIN_REPEL_UNDEAD:
+ case ABIL_TSO_REPEL_UNDEAD:
+ case ABIL_KIKU_RECALL_UNDEAD_SLAVES:
+ case ABIL_OKAWARU_MIGHT:
+ case ABIL_ELYVILON_LESSER_HEALING:
+ invoc = true;
+ failure = 30 - (you.piety / 20) - (6 * you.skills[SK_INVOCATIONS]);
+ break;
+
+ // These three are Trog abilities... Invocations means nothing -- bwr
+ case ABIL_TROG_BERSERK: // piety >= 30
+ invoc = true;
+ failure = 30 - you.piety; // starts at 0%
+ break;
+
+ case ABIL_TROG_MIGHT: // piety >= 50
+ invoc = true;
+ failure = 80 - you.piety; // starts at 30%
+ break;
+
+ case ABIL_TROG_HASTE_SELF: // piety >= 100
+ invoc = true;
+ failure = 160 - you.piety; // starts at 60%
+ break;
+
+ case ABIL_YRED_ANIMATE_CORPSE:
+ invoc = true;
+ failure = 40 - (you.piety / 20) - (3 * you.skills[SK_INVOCATIONS]);
+ break;
+
+ case ABIL_ZIN_HEALING:
+ case ABIL_TSO_SMITING:
+ case ABIL_OKAWARU_HEALING:
+ case ABIL_MAKHLEB_MINOR_DESTRUCTION:
+ case ABIL_SIF_MUNA_FORGET_SPELL:
+ case ABIL_KIKU_ENSLAVE_UNDEAD:
+ case ABIL_YRED_ANIMATE_DEAD:
+ case ABIL_MAKHLEB_LESSER_SERVANT_OF_MAKHLEB:
+ case ABIL_ELYVILON_HEALING:
+ invoc = true;
+ failure = 40 - (you.piety / 20) - (5 * you.skills[SK_INVOCATIONS]);
+ break;
+
+ case ABIL_VEHUMET_CHANNEL_ENERGY:
+ invoc = true;
+ failure = 40 - you.intel - you.skills[SK_INVOCATIONS];
+ break;
+
+ case ABIL_YRED_RECALL_UNDEAD:
+ invoc = true;
+ failure = 50 - (you.piety / 20) - (you.skills[SK_INVOCATIONS] * 4);
+ break;
+
+ case ABIL_ZIN_PESTILENCE:
+ case ABIL_TSO_ANNIHILATE_UNDEAD:
+ invoc = true;
+ failure = 60 - (you.piety / 20) - (5 * you.skills[SK_INVOCATIONS]);
+ break;
+
+ case ABIL_MAKHLEB_MAJOR_DESTRUCTION:
+ case ABIL_YRED_DRAIN_LIFE:
+ invoc = true;
+ failure = 60 - (you.piety / 25) - (you.skills[SK_INVOCATIONS] * 4);
+ break;
+
+ case ABIL_ZIN_HOLY_WORD:
+ case ABIL_TSO_THUNDERBOLT:
+ case ABIL_ELYVILON_RESTORATION:
+ case ABIL_YRED_CONTROL_UNDEAD:
+ case ABIL_OKAWARU_HASTE:
+ case ABIL_MAKHLEB_GREATER_SERVANT_OF_MAKHLEB:
+ invoc = true;
+ failure = 70 - (you.piety / 25) - (you.skills[SK_INVOCATIONS] * 4);
+ break;
+
+ case ABIL_ZIN_SUMMON_GUARDIAN:
+ case ABIL_TSO_SUMMON_DAEVA:
+ case ABIL_KIKU_INVOKE_DEATH:
+ case ABIL_ELYVILON_GREATER_HEALING:
+ invoc = true;
+ failure = 80 - (you.piety / 25) - (you.skills[SK_INVOCATIONS] * 4);
+ break;
+
+ //jmf: following for to-be-created gods
+ case ABIL_CHARM_SNAKE:
+ invoc = true;
+ failure = 40 - (you.piety / 20) - (3 * you.skills[SK_INVOCATIONS]);
+ break;
+
+ case ABIL_TRAN_SERPENT_OF_HELL:
+ invoc = true;
+ failure = 80 - (you.piety / 25) - (you.skills[SK_INVOCATIONS] * 4);
+ break;
+
+ case ABIL_ROTTING:
+ invoc = true;
+ failure = 60 - (you.piety / 20) - (5 * you.skills[SK_INVOCATIONS]);
+ break;
+
+ case ABIL_TORMENT_II:
+ invoc = true;
+ failure = 70 - (you.piety / 25) - (you.skills[SK_INVOCATIONS] * 4);
+ break;
+
+ case ABIL_SHUGGOTH_SEED:
+ invoc = true;
+ failure = 85 - (you.piety / 25) - (you.skills[SK_INVOCATIONS] * 3);
+ break;
+
+ case ABIL_RENOUNCE_RELIGION:
+ invoc = true;
+ perfect = true;
+ failure = 0;
+ break;
+
+ // end invocations {dlb}
+ default:
+ failure = -1;
+ break;
+ }
+
+ // Perfect abilities are things like "renounce religion", which
+ // shouldn't have a failure rate ever. -- bwr
+ if (failure <= 0 && !perfect)
+ failure = 1;
+
+ if (failure > 100)
+ failure = 100;
+
+ Curr_abil[slot].fail = failure;
+ Curr_abil[slot].is_invocation = invoc;
+
+ return (true);
+} // end insert_ability()
diff --git a/trunk/source/abl-show.h b/trunk/source/abl-show.h
new file mode 100644
index 0000000000..de4a42a690
--- /dev/null
+++ b/trunk/source/abl-show.h
@@ -0,0 +1,46 @@
+/*
+ * File: abl-show.h
+ * Summary: Functions related to special abilities.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> --/--/-- LRH Created
+ */
+
+
+#ifndef ABLSHOW_H
+#define ABLSHOW_H
+
+#include <string>
+
+// Structure for representing an ability:
+struct ability_def
+{
+ int ability;
+ const char * name;
+ unsigned int mp_cost; // magic cost of ability
+ unsigned int hp_cost; // hit point cost of ability
+ unsigned int food_cost; // + rand2avg( food_cost, 2 )
+ unsigned int piety_cost; // + random2( (piety_cost + 1) / 2 + 1 )
+ unsigned int flags; // used for additonal cost notices
+};
+
+const struct ability_def & get_ability_def( int abil );
+
+const char * get_ability_name_by_index( char index );
+
+const std::string make_cost_description( const struct ability_def &abil );
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+bool activate_ability( void ); // handles all special abilities now
+char show_abilities( void );
+bool generate_abilities( void );
+
+void set_god_ability_slots( void );
+
+
+#endif
diff --git a/trunk/source/abyss.cc b/trunk/source/abyss.cc
new file mode 100644
index 0000000000..3f48ed7b35
--- /dev/null
+++ b/trunk/source/abyss.cc
@@ -0,0 +1,379 @@
+/*
+ * File: abyss.cc
+ * Summary: Misc functions (most of which don't appear to be related to priests).
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <2> 10/11/99 BCR Added Daniel's crash patch
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "abyss.h"
+
+#include <stdlib.h>
+
+#include "externs.h"
+
+#include "cloud.h"
+#include "monplace.h"
+#include "dungeon.h"
+#include "items.h"
+#include "lev-pand.h"
+#include "randart.h"
+#include "stuff.h"
+
+// public for abyss generation
+void generate_abyss(void)
+{
+ int i, j; // loop variables
+ int temp_rand; // probability determination {dlb}
+
+ for (i = 5; i < (GXM - 5); i++)
+ {
+ for (j = 5; j < (GYM - 5); j++)
+ {
+ temp_rand = random2(4000);
+
+ grd[i][j] = ((temp_rand > 999) ? DNGN_FLOOR : // 75.0%
+ (temp_rand > 400) ? DNGN_ROCK_WALL : // 15.0%
+ (temp_rand > 100) ? DNGN_STONE_WALL : // 7.5%
+ (temp_rand > 0) ? DNGN_METAL_WALL // 2.5%
+ : DNGN_CLOSED_DOOR); // 1 in 4000
+ }
+ }
+
+ grd[45][35] = DNGN_FLOOR;
+} // end generate_abyss()
+
+
+static void generate_area(unsigned char gx1, unsigned char gy1,
+ unsigned char gx2, unsigned char gy2)
+{
+ unsigned char i, j;
+ unsigned char x1, x2, y1, y2;
+ unsigned char items_placed = 0;
+ int thickness = random2(70) + 30;
+ int thing_created;
+ unsigned int rooms_done = 0;
+ unsigned int rooms_to_do = 0;
+
+ int temp_rand; // probability determination {dlb}
+
+ FixedVector < unsigned char, 5 > replaced;
+
+ // nuke map
+ for (i = 0; i < GXM; i++)
+ {
+ for (j = 0; j < GYM; j++)
+ {
+ env.map[i][j] = 0;
+ }
+ }
+
+ // generate level composition vector
+ for (i = 0; i < 5; i++)
+ {
+ temp_rand = random2(10000);
+
+ replaced[i] = ((temp_rand > 4926) ? DNGN_ROCK_WALL : // 50.73%
+ (temp_rand > 2918) ? DNGN_STONE_WALL : // 20.08%
+ (temp_rand > 2004) ? DNGN_METAL_WALL : // 9.14%
+ (temp_rand > 1282) ? DNGN_LAVA : // 7.22%
+ (temp_rand > 616) ? DNGN_SHALLOW_WATER :// 6.66%
+ (temp_rand > 15) ? DNGN_DEEP_WATER // 6.01%
+ : DNGN_CLOSED_DOOR); // 0.16%
+ }
+
+ if (one_chance_in(3))
+ {
+ rooms_to_do = 1 + random2(10);
+
+ while(true)
+ {
+ x1 = 10 + random2(GXM - 20);
+ y1 = 10 + random2(GYM - 20);
+ x2 = x1 + 1 + random2(10);
+ y2 = y1 + 1 + random2(10);
+
+ if (one_chance_in(100))
+ goto out_of_rooms;
+
+ for (i = x1; i < x2; i++) // that is, [10,(GXM-1)] {dlb}
+ {
+ for (j = y1; j < y2; j++) // that is, [10,(GYM-1)] {dlb}
+ {
+ if (grd[i][j] != DNGN_UNSEEN)
+ goto continued;
+ }
+ }
+
+ for (i = x1; i < x2; i++) // that is, [10,(GXM-1)] {dlb}
+ {
+ for (j = y1; j < y2; j++) // that is, [10,(GYM-1)] {dlb}
+ {
+ grd[i][j] = DNGN_FLOOR;
+ }
+ }
+
+ continued:
+ rooms_done++;
+
+ if (rooms_done >= rooms_to_do)
+ break;
+ }
+ }
+
+ out_of_rooms:
+ for (i = gx1; i < gx2 + 1; i++)
+ {
+ for (j = gy1; j < gy2 + 1; j++)
+ {
+ if (grd[i][j] == DNGN_UNSEEN && random2(100) <= thickness)
+ {
+ grd[i][j] = DNGN_FLOOR;
+
+ if (items_placed < 150 && one_chance_in(200))
+ {
+ if (one_chance_in(500))
+ {
+ thing_created = items(1, OBJ_MISCELLANY,
+ MISC_RUNE_OF_ZOT, true, 51, 51);
+ }
+ else
+ {
+ thing_created = items(1, OBJ_RANDOM, OBJ_RANDOM, true,
+ 51, 250);
+ }
+
+ move_item_to_grid( &thing_created, i, j );
+
+ if (thing_created != NON_ITEM)
+ items_placed++;
+ }
+ }
+ }
+ }
+
+ for (i = gx1; i < gx2 + 1; i++)
+ {
+ for (j = gy1; j < gy2 + 1; j++)
+ {
+ if (grd[i][j] == DNGN_UNSEEN)
+ grd[i][j] = replaced[random2(5)];
+
+ if (one_chance_in(7500))
+ grd[i][j] = DNGN_EXIT_ABYSS;
+
+ if (one_chance_in(10000))
+ {
+ do
+ {
+ grd[i][j] = DNGN_ALTAR_ZIN + random2(12);
+ }
+ while (grd[i][j] == DNGN_ALTAR_YREDELEMNUL
+ || grd[i][j] == DNGN_ALTAR_VEHUMET
+ || grd[i][j] == DNGN_ALTAR_NEMELEX_XOBEH);
+ }
+ }
+ }
+}
+
+
+void area_shift(void)
+/*******************/
+{
+ for (unsigned int i = 0; i < MAX_MONSTERS; i++)
+ {
+ if (menv[i].type == -1)
+ {
+ continue;
+ }
+
+ // remove non-nearby monsters
+ if (menv[i].x < you.x_pos - 10
+ || menv[i].x >= you.x_pos + 11
+ || menv[i].y < you.y_pos - 10 || menv[i].y >= you.y_pos + 11)
+ {
+ menv[i].type = -1;
+
+ mgrd[menv[i].x][menv[i].y] = NON_MONSTER;
+
+ for (unsigned int j = 0; j < NUM_MONSTER_SLOTS; j++)
+ {
+ if (menv[i].inv[j] != NON_ITEM)
+ {
+ destroy_item( menv[i].inv[j] );
+ menv[i].inv[j] = NON_ITEM;
+ }
+ }
+ }
+ }
+
+ for (int i = 5; i < (GXM - 5); i++)
+ {
+ for (int j = 5; j < (GYM - 5); j++)
+ {
+ // don't modify terrain by player
+ if (i >= you.x_pos - 10 && i < you.x_pos + 11
+ && j >= you.y_pos - 10 && j < you.y_pos + 11)
+ {
+ continue;
+ }
+
+ // nuke terrain otherwise
+ grd[i][j] = DNGN_UNSEEN;
+
+ // nuke items
+ destroy_item_stack( i, j );
+ }
+ }
+
+ // shift all monsters & items to new area
+ for (int i = you.x_pos - 10; i < you.x_pos + 11; i++)
+ {
+ if (i < 0 || i >= GXM)
+ continue;
+
+ for (int j = you.y_pos - 10; j < you.y_pos + 11; j++)
+ {
+ if (j < 0 || j >= GYM)
+ continue;
+
+ const int ipos = 45 + i - you.x_pos;
+ const int jpos = 35 + j - you.y_pos;
+
+ // move terrain
+ grd[ipos][jpos] = grd[i][j];
+
+ // move item
+ move_item_stack_to_grid( i, j, ipos, jpos );
+
+ // move monster
+ mgrd[ipos][jpos] = mgrd[i][j];
+ if (mgrd[i][j] != NON_MONSTER)
+ {
+ menv[mgrd[ipos][jpos]].x = ipos;
+ menv[mgrd[ipos][jpos]].y = jpos;
+ mgrd[i][j] = NON_MONSTER;
+ }
+
+ // move cloud
+ if (env.cgrid[i][j] != EMPTY_CLOUD)
+ move_cloud( env.cgrid[i][j], ipos, jpos );
+ }
+ }
+
+
+ for (unsigned int i = 0; i < MAX_CLOUDS; i++)
+ {
+ if (env.cloud[i].type == CLOUD_NONE)
+ continue;
+
+ if (env.cloud[i].x < 35 || env.cloud[i].x > 55
+ || env.cloud[i].y < 25 || env.cloud[i].y > 45)
+ {
+ delete_cloud( i );
+ }
+ }
+
+ you.x_pos = 45;
+ you.y_pos = 35;
+
+ generate_area(5, 5, (GXM - 5), (GYM - 5));
+
+ for (unsigned int mcount = 0; mcount < 15; mcount++)
+ {
+ mons_place( RANDOM_MONSTER, BEH_HOSTILE, MHITNOT, false, 1, 1,
+ LEVEL_ABYSS, PROX_AWAY_FROM_PLAYER ); // PROX_ANYWHERE?
+ }
+}
+
+
+void abyss_teleport( bool new_area )
+/**********************************/
+{
+ int x, y, i, j, k;
+
+ if (!new_area)
+ {
+ // try to find a good spot within the shift zone:
+ for (i = 0; i < 100; i++)
+ {
+ x = 16 + random2( GXM - 32 );
+ y = 16 + random2( GYM - 32 );
+
+ if ((grd[x][y] == DNGN_FLOOR
+ || grd[x][y] == DNGN_SHALLOW_WATER)
+ && mgrd[x][y] == NON_MONSTER
+ && env.cgrid[x][y] == EMPTY_CLOUD)
+ {
+ break;
+ }
+ }
+
+ if (i < 100)
+ {
+ you.x_pos = x;
+ you.y_pos = y;
+ return;
+ }
+ }
+
+ // teleport to a new area of the abyss:
+
+ init_pandemonium(); /* changes colours */
+
+ env.floor_colour = (mcolour[env.mons_alloc[9]] == BLACK)
+ ? LIGHTGREY : mcolour[env.mons_alloc[9]];
+
+ env.rock_colour = (mcolour[env.mons_alloc[8]] == BLACK)
+ ? LIGHTGREY : mcolour[env.mons_alloc[8]];
+
+ // Orbs and fixed artefacts are marked as "lost in the abyss"
+ for (k = 0; k < MAX_ITEMS; k++)
+ {
+ if (is_valid_item( mitm[k] ))
+ {
+ if (mitm[k].base_type == OBJ_ORBS)
+ {
+ set_unique_item_status( OBJ_ORBS, mitm[k].sub_type,
+ UNIQ_LOST_IN_ABYSS );
+ }
+ else if (is_fixed_artefact( mitm[k] ))
+ {
+ set_unique_item_status( OBJ_WEAPONS, mitm[k].special,
+ UNIQ_LOST_IN_ABYSS );
+ }
+
+ destroy_item( k );
+ }
+ }
+
+ for (i = 0; i < MAX_MONSTERS; i++)
+ menv[i].type = -1;
+
+ for (i = 0; i < MAX_CLOUDS; i++)
+ delete_cloud( i );
+
+ for (i = 10; i < (GXM - 9); i++)
+ {
+ for (j = 10; j < (GYM - 9); j++)
+ {
+ grd[i][j] = DNGN_UNSEEN; // so generate_area will pick it up
+ igrd[i][j] = NON_ITEM;
+ mgrd[i][j] = NON_MONSTER;
+ env.cgrid[i][j] = EMPTY_CLOUD;
+ }
+ }
+
+ ASSERT( env.cloud_no == 0 );
+
+ you.x_pos = 45;
+ you.y_pos = 35;
+
+ generate_area( 10, 10, (GXM - 10), (GYM - 10) );
+
+ grd[you.x_pos][you.y_pos] = DNGN_FLOOR;
+}
diff --git a/trunk/source/abyss.h b/trunk/source/abyss.h
new file mode 100644
index 0000000000..9ecef56114
--- /dev/null
+++ b/trunk/source/abyss.h
@@ -0,0 +1,37 @@
+/*
+ * File: abyss.h
+ * Summary: Misc functions (most of which don't appear to be related to priests).
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef ABYSS_H
+#define ABYSS_H
+
+
+// last updated 02apr2001 {gdl}
+/* ***********************************************************************
+ * called from: dungeon
+ * *********************************************************************** */
+void generate_abyss(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void area_shift(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: spells1 - spells3 - spells4
+ * *********************************************************************** */
+void abyss_teleport( bool new_area );
+
+
+#endif
diff --git a/trunk/source/acr.cc b/trunk/source/acr.cc
new file mode 100644
index 0000000000..c8af933091
--- /dev/null
+++ b/trunk/source/acr.cc
@@ -0,0 +1,3051 @@
+/*
+ * File: acr.cc
+ * Summary: Main entry point, event loop, and some initialization functions
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <18> 7/29/00 JDJ values.h isn't included on Macs
+ * <17> 19jun2000 GDL added Windows console support
+ * <16> 06mar2000 bwr changes to berserk
+ * <15> 09jan2000 BCR new Wiz command: blink
+ * <14> 10/13/99 BCR Added auto door opening,
+ * move "you have no
+ * religion" to describe.cc
+ * <13> 10/11/99 BCR Added Daniel's wizard patch
+ * <12> 10/9/99 BCR swapped 'v' and 'V' commands,
+ * added wizard help command
+ * <11> 10/7/99 BCR haste and slow now take amulet of
+ * resist slow into account
+ * <10> 9/25/99 CDL Changes to Linux input
+ * switch on command enums
+ * <9> 6/12/99 BWR New init code, restructured
+ * wiz commands, added equipment
+ * listing commands
+ * <8> 6/7/99 DML Autopickup
+ * <7> 5/30/99 JDJ Added game_has_started.
+ * <6> 5/25/99 BWR Changed move() to move_player()
+ * <5> 5/20/99 BWR New berserk code, checking
+ * scan_randarts for NO_TELEPORT
+ * and NO_SPELLCASTING.
+ * <4> 5/12/99 BWR Solaris support.
+ * <3> 5/09/99 JDJ look_around no longer prints a prompt.
+ * <2> 5/08/99 JDJ you and env are no longer arrays.
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+
+#include <string>
+
+// I don't seem to need values.h for VACPP..
+#if !defined(__IBMCPP__) && !defined(MAC)
+#include <limits.h>
+#endif
+
+#if DEBUG
+ // this contains the DBL_MAX constant
+ #include <float.h>
+#endif
+
+#include <time.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#ifdef DOS
+#include <conio.h>
+#include <file.h>
+#endif
+
+#ifdef USE_UNIX_SIGNALS
+#include <signal.h>
+#endif
+
+#ifdef USE_EMX
+#include <sys/types.h>
+#endif
+
+#ifdef OS9
+#include <stat.h>
+#else
+#include <sys/stat.h>
+#endif
+
+#include "externs.h"
+
+#include "abl-show.h"
+#include "abyss.h"
+#include "chardump.h"
+#include "command.h"
+#include "debug.h"
+#include "delay.h"
+#include "describe.h"
+#include "direct.h"
+#include "dungeon.h"
+#include "effects.h"
+#include "fight.h"
+#include "files.h"
+#include "food.h"
+#include "hiscores.h"
+#include "initfile.h"
+#include "invent.h"
+#include "item_use.h"
+#include "it_use2.h"
+#include "it_use3.h"
+#include "itemname.h"
+#include "items.h"
+#include "lev-pand.h"
+#include "macro.h"
+#include "misc.h"
+#include "monplace.h"
+#include "monstuff.h"
+#include "mon-util.h"
+#include "mutation.h"
+#include "newgame.h"
+#include "ouch.h"
+#include "output.h"
+#include "overmap.h"
+#include "player.h"
+#include "randart.h"
+#include "religion.h"
+#include "shopping.h"
+#include "skills.h"
+#include "skills2.h"
+#include "spells1.h"
+#include "spells3.h"
+#include "spells4.h"
+#include "spl-book.h"
+#include "spl-cast.h"
+#include "spl-util.h"
+#include "stuff.h"
+#include "tags.h"
+#include "transfor.h"
+#include "view.h"
+#include "wpn-misc.h"
+
+struct crawl_environment env;
+struct player you;
+struct system_environment SysEnv;
+
+char info[ INFO_SIZE ]; // messaging queue extern'd everywhere {dlb}
+
+int stealth; // externed in view.h // no it is not {dlb}
+char use_colour = 1;
+
+FixedVector< char, NUM_STATUE_TYPES > Visible_Statue;
+
+// set to true once a new game starts or an old game loads
+bool game_has_started = false;
+
+// Clockwise, around the compass from north (same order as enum RUN_DIR)
+static const struct coord_def Compass[8] =
+{
+ { 0, -1 }, { 1, -1 }, { 1, 0 }, { 1, 1 },
+ { 0, 1 }, { -1, 1 }, { -1, 0 }, { -1, -1 },
+};
+
+/*
+
+ Functions needed:
+ New:
+ int player_speed(player you);
+ hit_player(damage, flavour, then last two ouch values, env);
+
+
+ Old:
+ wield(player you);
+ show_map
+ noisy()
+ losight
+
+*/
+
+void (*viewwindow) (char, bool);
+
+/* these are all defined in view.cc: */
+extern unsigned char (*mapch) (unsigned char);
+extern unsigned char (*mapch2) (unsigned char);
+unsigned char mapchar(unsigned char ldfk);
+unsigned char mapchar2(unsigned char ldfk);
+unsigned char mapchar3(unsigned char ldfk);
+unsigned char mapchar4(unsigned char ldfk);
+
+/*
+ Function pointers are used to make switching between Linux and DOS char sets
+ possible as a runtime option (command-line -c)
+*/
+
+// these two are defined in view.cc. What does the player look like?
+// (changed for shapechanging)
+extern unsigned char your_sign;
+extern unsigned char your_colour;
+
+// Functions in main module
+static void close_door(char move_x, char move_y);
+static void do_berserk_no_combat_penalty(void);
+static bool initialise(void);
+static void input(void);
+static void move_player(char move_x, char move_y);
+static void open_door(char move_x, char move_y);
+
+/*
+ It all starts here. Some initialisations are run first, then straight to
+ new_game and then input.
+*/
+int main( int argc, char *argv[] )
+{
+#ifdef USE_ASCII_CHARACTERS
+ // Default to the non-ibm set when it makes sense.
+ viewwindow = &viewwindow3;
+ mapch = &mapchar3;
+ mapch2 = &mapchar4;
+#else
+ // Use the standard ibm default
+ viewwindow = &viewwindow2;
+ mapch = &mapchar;
+ mapch2 = &mapchar2;
+#endif
+
+ // Load in the system environment variables
+ get_system_environment();
+
+ // parse command line args -- look only for initfile & crawl_dir entries
+ if (!parse_args(argc, argv, true))
+ {
+ // print help
+ puts("Command line options:");
+ puts(" -name <string> character name");
+ puts(" -race <arg> preselect race (by letter, abbreviation, or name)");
+ puts(" -class <arg> preselect class (by letter, abbreviation, or name)");
+ puts(" -pizza <string> crawl pizza");
+ puts(" -plain don't use IBM extended characters");
+ puts(" -dir <path> crawl directory");
+ puts(" -rc <file> init file name");
+ puts("");
+ puts("Command line options override init file options, which override");
+ puts("environment options (CRAWL_NAME, CRAWL_PIZZA, CRAWL_DIR, CRAWL_RC).");
+ puts("");
+ puts("Highscore list options: (Can now be redirected to more, etc)");
+ puts(" -scores [N] highscore list");
+ puts(" -tscores [N] terse highscore list");
+ puts(" -vscores [N] verbose highscore list");
+ exit(1);
+ }
+
+ // Read the init file
+ read_init_file();
+
+ // now parse the args again, looking for everything else.
+ parse_args( argc, argv, false );
+
+ if (Options.sc_entries > 0)
+ {
+ printf( " Best Crawlers -" EOL );
+ hiscores_print_list( Options.sc_entries, Options.sc_format );
+ exit(0);
+ }
+
+#ifdef LINUX
+ lincurses_startup();
+#endif
+
+#ifdef MAC
+ init_mac();
+#endif
+
+#ifdef WIN32CONSOLE
+ init_libw32c();
+#endif
+
+#ifdef USE_MACROS
+ // Load macros
+ macro_init();
+#endif
+
+ init_overmap(); // in overmap.cc (duh?)
+ clear_ids(); // in itemname.cc
+
+ bool game_start = initialise();
+
+ if (game_start || Options.always_greet)
+ {
+ snprintf( info, INFO_SIZE, "Welcome, %s the %s %s.",
+ you.your_name, species_name( you.species,you.experience_level ), you.class_name );
+
+ mpr( info );
+
+ // Starting messages can go here as this should only happen
+ // at the start of a new game -- bwr
+ // This message isn't appropriate for Options.always_greet
+ if (you.char_class == JOB_WANDERER && game_start)
+ {
+ int skill_levels = 0;
+ for (int i = 0; i <= NUM_SKILLS; i++)
+ skill_levels += you.skills[ i ];
+
+ if (skill_levels <= 2)
+ {
+ // Demigods and Demonspawn wanderers stand to not be
+ // able to see any of their skills at the start of
+ // the game (one or two skills should be easily guessed
+ // from starting equipment)... Anyways, we'll give the
+ // player a message to warn them (and give a reason why). -- bwr
+ mpr("You wake up in a daze, and can't recall much.");
+ }
+ }
+
+ // These need some work -- should make sure that the god's
+ // name is metioned, else the message might be confusing.
+ switch (you.religion)
+ {
+ case GOD_ZIN:
+ simple_god_message( " says: Spread the light, my child." );
+ break;
+ case GOD_SHINING_ONE:
+ simple_god_message( " says: Smite the infidels!" );
+ break;
+ case GOD_KIKUBAAQUDGHA:
+ case GOD_YREDELEMNUL:
+ case GOD_NEMELEX_XOBEH:
+ simple_god_message( " says: Welcome..." );
+ break;
+ case GOD_XOM:
+ if (game_start)
+ simple_god_message( " says: A new plaything!" );
+ break;
+ case GOD_VEHUMET:
+ god_speaks( you.religion, "Let it end in hellfire!");
+ break;
+ case GOD_OKAWARU:
+ simple_god_message(" says: Welcome, disciple.");
+ break;
+ case GOD_MAKHLEB:
+ god_speaks( you.religion, "Blood and souls for Makhleb!" );
+ break;
+ case GOD_SIF_MUNA:
+ simple_god_message( " whispers: I know many secrets...");
+ break;
+ case GOD_TROG:
+ simple_god_message( " says: Kill them all!" );
+ break;
+ case GOD_ELYVILON:
+ simple_god_message( " says: Go forth and aid the weak!" );
+ break;
+ default:
+ break;
+ }
+
+ // warn player about their weapon, if unsuitable
+ wield_warning(false);
+ }
+
+ while (true)
+ {
+ input();
+ // cprintf("x");
+ }
+
+ // Should never reach this stage, right?
+
+#ifdef LINUX
+ lincurses_shutdown();
+#endif
+
+#ifdef MAC
+ deinit_mac();
+#endif
+
+#ifdef USE_EMX
+ deinit_emx();
+#endif
+
+ return 0;
+} // end main()
+
+#ifdef WIZARD
+static void handle_wizard_command( void )
+{
+ int wiz_command, i, j, tmp;
+ char specs[256];
+
+ // WIZ_NEVER gives protection for those who have wiz compiles,
+ // and don't want to risk their characters.
+ if (Options.wiz_mode == WIZ_NEVER)
+ return;
+
+ if (!you.wizard)
+ {
+ mpr( "WARNING: ABOUT TO ENTER WIZARD MODE!", MSGCH_WARN );
+
+#ifndef SCORE_WIZARD_MODE
+ mpr( "If you continue, your game will not be scored!", MSGCH_WARN );
+#endif
+
+ if (!yesno( "Do you really want to enter wizard mode?", false ))
+ return;
+
+ you.wizard = true;
+ redraw_screen();
+ }
+
+ mpr( "Enter Wizard Command: ", MSGCH_PROMPT );
+ wiz_command = getch();
+
+ switch (wiz_command)
+ {
+ case '?':
+ list_commands(true); // tell it to list wizard commands
+ redraw_screen();
+ break;
+
+ case CONTROL('G'):
+ save_ghost(true);
+ break;
+
+ case 'x':
+ you.experience = 1 + exp_needed( 2 + you.experience_level );
+ level_change();
+ break;
+
+ case 's':
+ you.exp_available = 20000;
+ you.redraw_experience = 1;
+ break;
+
+ case 'S':
+ debug_set_skills();
+ break;
+
+ case 'A':
+ debug_set_all_skills();
+ break;
+
+ case '$':
+ you.gold += 1000;
+ you.redraw_gold = 1;
+ break;
+
+ case 'a':
+ acquirement( OBJ_RANDOM );
+ break;
+
+ case 'v':
+ // this command isn't very exciting... feel free to replace
+ i = prompt_invent_item( "Value of which item?", -1 );
+ if (i == PROMPT_ABORT || !is_random_artefact( you.inv[i] ))
+ {
+ canned_msg( MSG_OK );
+ break;
+ }
+ else
+ {
+ snprintf( info, INFO_SIZE, "randart val: %d", randart_value( you.inv[i] ) );
+ mpr( info );
+ }
+ break;
+
+ case '+':
+ i = prompt_invent_item( "Make an artefact out of which item?", -1 );
+ if (i == PROMPT_ABORT)
+ {
+ canned_msg( MSG_OK );
+ break;
+ }
+
+ // set j == equipment slot of chosen item, remove old randart benefits
+ for (j = 0; j < NUM_EQUIP; j++)
+ {
+ if (you.equip[j] == i)
+ {
+ if (j == EQ_WEAPON)
+ you.wield_change = true;
+
+ if (is_random_artefact( you.inv[i] ))
+ unuse_randart( i );
+
+ break;
+ }
+ }
+
+ make_item_randart( you.inv[i] );
+
+ // if equiped, apply new randart benefits
+ if (j != NUM_EQUIP)
+ use_randart( i );
+
+ item_name( you.inv[i], DESC_INVENTORY_EQUIP, info );
+ mpr( info );
+ break;
+
+ case '|':
+ // create all unrand arts
+ for (tmp = 1; tmp < NO_UNRANDARTS; tmp++)
+ {
+ int islot = get_item_slot();
+ if (islot == NON_ITEM)
+ break;
+
+ make_item_unrandart( mitm[islot], tmp );
+
+ mitm[ islot ].quantity = 1;
+ set_ident_flags( mitm[ islot ], ISFLAG_IDENT_MASK );
+
+ move_item_to_grid( &islot, you.x_pos, you.y_pos );
+ }
+
+ // create all fixed artefacts
+ for (tmp = SPWPN_SINGING_SWORD; tmp <= SPWPN_STAFF_OF_WUCAD_MU; tmp++)
+ {
+ int islot = get_item_slot();
+ if (islot == NON_ITEM)
+ break;
+
+ if (make_item_fixed_artefact( mitm[ islot ], false, tmp ))
+ {
+ mitm[ islot ].quantity = 1;
+ item_colour( mitm[ islot ] );
+ set_ident_flags( mitm[ islot ], ISFLAG_IDENT_MASK );
+
+ move_item_to_grid( &islot, you.x_pos, you.y_pos );
+ }
+ }
+ break;
+
+ case 'B':
+ if (you.level_type != LEVEL_ABYSS)
+ banished( DNGN_ENTER_ABYSS );
+ else
+ {
+ grd[you.x_pos][you.y_pos] = DNGN_EXIT_ABYSS;
+ down_stairs(true, you.your_level);
+ untag_followers();
+ }
+ break;
+
+ case 'g':
+ debug_add_skills();
+ break;
+
+ case 'G':
+ // Genocide... "unsummon" all the monsters from the level.
+ for (int mon = 0; mon < MAX_MONSTERS; mon++)
+ {
+ struct monsters *monster = &menv[mon];
+
+ if (monster->type == -1)
+ continue;
+
+ monster_die(monster, KILL_RESET, 0);
+
+ }
+ break;
+
+ case 'h':
+ you.rotting = 0;
+ you.poison = 0;
+ you.disease = 0;
+ set_hp( abs(you.hp_max), false );
+ set_hunger( 5000 + abs(you.hunger), true );
+ break;
+
+ case 'H':
+ you.rotting = 0;
+ you.poison = 0;
+ you.disease = 0;
+ inc_hp( 10, true );
+ set_hp( you.hp_max, false );
+ set_hunger( 12000, true );
+ you.redraw_hit_points = 1;
+ break;
+
+ case 'b':
+ blink(); // wizards can always blink
+ break;
+
+ case '\"':
+ case '~':
+ level_travel(0);
+ break;
+
+ case 'd':
+ case 'D':
+ level_travel(1);
+ break;
+
+ case 'u':
+ case 'U':
+ level_travel(-1);
+ break;
+
+ case '%':
+ case 'o':
+ create_spec_object();
+ break;
+
+ case 't':
+ tweak_object();
+ break;
+
+ case 'm':
+ create_spec_monster();
+ break;
+
+ case 'M':
+ create_spec_monster_name();
+ break;
+
+ case 'r':
+ debug_change_species();
+ break;
+
+ case '>':
+ grd[you.x_pos][you.y_pos] = DNGN_STONE_STAIRS_DOWN_I;
+ break;
+
+ case '<':
+ grd[you.x_pos][you.y_pos] = DNGN_ROCK_STAIRS_UP;
+ break;
+
+ case 'p':
+ grd[you.x_pos][you.y_pos] = DNGN_ENTER_PANDEMONIUM;
+ break;
+
+ case 'l':
+ grd[you.x_pos][you.y_pos] = DNGN_ENTER_LABYRINTH;
+ break;
+
+ case 'i':
+ mpr( "You feel a rush of knowledge." );
+ for (i = 0; i < ENDOFPACK; i++)
+ {
+ if (is_valid_item( you.inv[i] ))
+ {
+ set_ident_type( you.inv[i].base_type, you.inv[i].sub_type,
+ ID_KNOWN_TYPE );
+
+ set_ident_flags( you.inv[i], ISFLAG_IDENT_MASK );
+ }
+ }
+ you.wield_change = true;
+ break;
+
+ case 'I':
+ mpr( "You feel a rush of antiknowledge." );
+ for (i = 0; i < ENDOFPACK; i++)
+ {
+ if (is_valid_item( you.inv[i] ))
+ {
+ set_ident_type( you.inv[i].base_type, you.inv[i].sub_type,
+ ID_UNKNOWN_TYPE );
+
+ unset_ident_flags( you.inv[i], ISFLAG_IDENT_MASK );
+ }
+ }
+ you.wield_change = true;
+ break;
+
+ case 'X':
+ Xom_acts(true, 20, true);
+ break;
+
+ case 'z':
+ cast_spec_spell();
+ break; /* cast spell by number */
+
+ case 'Z':
+ cast_spec_spell_name();
+ break; /* cast spell by name */
+
+ case '(':
+ mpr( "Create which feature (by number)? ", MSGCH_PROMPT );
+ get_input_line( specs, sizeof( specs ) );
+
+ if (specs[0] != '\0')
+ grd[you.x_pos][you.y_pos] = atoi(specs);
+ break;
+
+ case ']':
+ if (!debug_add_mutation())
+ mpr( "Failure to give mutation." );
+ break;
+
+ case '[':
+ demonspawn();
+ break;
+
+ case ':':
+ j = 0;
+ for (i = 0; i < 20; i++)
+ {
+ if (you.branch_stairs[i] == 0)
+ continue;
+
+ snprintf( info, INFO_SIZE, "Branch %2d is on level %2d",
+ i, you.branch_stairs[i] + 1 );
+
+ mpr(info);
+ }
+ break;
+
+ case '{':
+ magic_mapping(99, 100);
+ break;
+
+ case '^':
+ {
+ int old_piety = you.piety;
+
+ gain_piety(50);
+ snprintf( info, INFO_SIZE, "Congratulations, your piety went from %d to %d!",
+ old_piety, you.piety);
+ mpr(info);
+ }
+ break;
+
+ case '=':
+ snprintf( info, INFO_SIZE,
+ "Cost level: %d Skill points: %d Next cost level: %d",
+ you.skill_cost_level, you.total_skill_points,
+ skill_cost_needed( you.skill_cost_level + 1 ) );
+
+ mpr( info );
+ break;
+
+ case '_':
+ debug_get_religion();
+ break;
+
+ case '\'':
+ for (i = 0; i < MAX_ITEMS; i++)
+ {
+ if (mitm[i].link == NON_ITEM)
+ continue;
+
+ snprintf( info, INFO_SIZE, "item:%3d link:%3d cl:%3d ty:%3d pl:%3d pl2:%3d sp:%3ld q:%3d",
+ i, mitm[i].link,
+ mitm[i].base_type, mitm[i].sub_type,
+ mitm[i].plus, mitm[i].plus2, mitm[i].special,
+ mitm[i].quantity );
+
+ mpr(info);
+ }
+
+ strcpy(info, "igrid:");
+ mpr(info);
+
+ for (i = 0; i < GXM; i++)
+ {
+ for (j = 0; j < GYM; j++)
+ {
+ if (igrd[i][j] != NON_ITEM)
+ {
+ snprintf( info, INFO_SIZE, "%3d at (%2d,%2d), cl:%3d ty:%3d pl:%3d pl2:%3d sp:%3ld q:%3d",
+ igrd[i][j], i, j,
+ mitm[i].base_type, mitm[i].sub_type,
+ mitm[i].plus, mitm[i].plus2, mitm[i].special,
+ mitm[i].quantity );
+
+ mpr(info);
+ }
+ }
+ }
+ break;
+
+ default:
+ mpr("Not a Wizard Command.");
+ break;
+ }
+}
+#endif
+
+// This function creates "equivalence classes" so that undiscovered
+// traps and secret doors aren't running stopping points.
+static char base_grid_type( char grid )
+{
+ // Don't stop for undiscovered traps:
+ if (grid == DNGN_UNDISCOVERED_TRAP)
+ return (DNGN_FLOOR);
+
+ // Or secret doors (which currently always look like rock walls):
+ if (grid == DNGN_SECRET_DOOR)
+ return (DNGN_ROCK_WALL);
+
+ return (grid);
+}
+
+// Set up the front facing array for detecting terrain based stops
+static void set_run_check( int index, int dir )
+{
+ you.run_check[index].dx = Compass[dir].x;
+ you.run_check[index].dy = Compass[dir].y;
+
+ const int targ_x = you.x_pos + Compass[dir].x;
+ const int targ_y = you.y_pos + Compass[dir].y;
+
+ you.run_check[index].grid = base_grid_type( grd[ targ_x ][ targ_y ] );
+}
+
+// Set up the running variables for the current run.
+static void start_running( int dir, char mode )
+{
+ if (dir == RDIR_REST)
+ {
+ you.run_x = 0;
+ you.run_y = 0;
+ you.running = mode;
+ return;
+ }
+
+ ASSERT( dir >= 0 && dir <= 7 );
+
+ you.run_x = Compass[dir].x;
+ you.run_y = Compass[dir].y;
+ you.running = mode;
+
+ // Get the compass point to the left/right of intended travel:
+ const int left = (dir - 1 < 0) ? 7 : (dir - 1);
+ const int right = (dir + 1 > 7) ? 0 : (dir + 1);
+
+ // Record the direction and starting tile type for later reference:
+ set_run_check( 0, left );
+ set_run_check( 1, dir );
+ set_run_check( 2, right );
+}
+
+// Returns true if one of the front three grids has changed.
+static bool check_stop_running( void )
+{
+ if (env.cgrid[you.x_pos + you.run_x][you.y_pos + you.run_y] != EMPTY_CLOUD)
+ return (true);
+
+ if (mgrd[you.x_pos + you.run_x][you.y_pos + you.run_y] != NON_MONSTER)
+ return (true);
+
+ for (int i = 0; i < 3; i++)
+ {
+ const int targ_x = you.x_pos + you.run_check[i].dx;
+ const int targ_y = you.y_pos + you.run_check[i].dy;
+ const int targ_grid = base_grid_type( grd[ targ_x ][ targ_y ] );
+
+ if (you.run_check[i].grid != targ_grid)
+ return (true);
+ }
+
+ return (false);
+}
+
+
+/*
+ This function handles the player's input. It's called from main(), from
+ inside an endless loop.
+ */
+static void input(void)
+{
+
+ bool its_quiet; //jmf: for silence messages
+ FixedVector < int, 2 > plox;
+ char move_x = 0;
+ char move_y = 0;
+
+ int keyin = 0;
+
+#ifdef LINUX
+ // Stuff for the Unix keypad kludge
+ bool running = false;
+ bool opening = false;
+#endif
+
+ you.shield_blocks = 0; // no blocks this round
+
+ you.time_taken = player_speed();
+
+#ifdef LINUX
+ update_screen();
+#else
+ window( 1, 1, 80, get_number_of_lines() );
+#endif
+
+ textcolor(LIGHTGREY);
+
+ set_redraw_status( REDRAW_LINE_2_MASK | REDRAW_LINE_3_MASK );
+ print_stats();
+
+ if (you.paralysis)
+ {
+ keyin = '.'; // end of if you.paralysis == 0
+ }
+ else
+ {
+ handle_delay();
+
+ gotoxy(18, 9);
+
+ if (you_are_delayed())
+ keyin = '.';
+ else
+ {
+
+ if (you.running > 0)
+ {
+ keyin = 128;
+
+ move_x = you.run_x;
+ move_y = you.run_y;
+
+ if (kbhit())
+ {
+ you.running = 0;
+ goto gutch;
+ }
+
+ if (you.run_x == 0 && you.run_y == 0)
+ {
+ you.running--;
+ keyin = '.';
+ }
+ }
+ else
+ {
+
+#if DEBUG_DIAGNOSTICS
+ // save hunger at start of round
+ // for use with hunger "delta-meter" in output.cc
+ you.old_hunger = you.hunger;
+#endif
+
+#if DEBUG_ITEM_SCAN
+ debug_item_scan();
+#endif
+
+ gutch:
+ flush_input_buffer( FLUSH_BEFORE_COMMAND );
+ keyin = getch_with_command_macros();
+ }
+
+ mesclr();
+
+#ifdef LINUX
+ // Kludging running and opening as two character sequences
+ // for Unix systems. This is an easy way out... all the
+ // player has to do is find a termcap and numlock setting
+ // that will get curses the numbers from the keypad. This
+ // will hopefully be easy.
+
+ if (keyin == '*')
+ {
+ opening = true;
+ keyin = getch();
+ }
+ else if (keyin == '/')
+ {
+ running = true;
+ keyin = getch();
+ }
+
+ // Translate keypad codes into command enums
+ keyin = key_to_command(keyin);
+#else
+ // Old DOS keypad support
+ if (keyin == 0) // ALT also works - see ..\KEYTEST.CPP
+ {
+ keyin = getch();
+ switch (keyin)
+ {
+ case 'O': move_x = -1; move_y = 1; break;
+ case 'P': move_x = 0; move_y = 1; break;
+ case 'I': move_x = 1; move_y = -1; break;
+ case 'H': move_x = 0; move_y = -1; break;
+ case 'G': move_x = -1; move_y = -1; break;
+ case 'K': move_x = -1; move_y = 0; break;
+ case 'Q': move_x = 1; move_y = 1; break;
+ case 'M': move_x = 1; move_y = 0; break;
+
+ case 119: open_door(-1, -1); move_x = 0; move_y = 0; break;
+ case 141: open_door( 0, -1); move_x = 0; move_y = 0; break;
+ case 132: open_door( 1, -1); move_x = 0; move_y = 0; break;
+ case 116: open_door( 1, 0); move_x = 0; move_y = 0; break;
+ case 118: open_door( 1, 1); move_x = 0; move_y = 0; break;
+ case 145: open_door( 0, 1); move_x = 0; move_y = 0; break;
+ case 117: open_door(-1, 1); move_x = 0; move_y = 0; break;
+ case 115: open_door(-1, 0); move_x = 0; move_y = 0; break;
+
+ case 76:
+ case 'S':
+ keyin = '.';
+ goto get_keyin_again;
+ }
+
+ keyin = 128;
+ }
+#endif
+ }
+ }
+
+ if (keyin != 128)
+ {
+ move_x = 0;
+ move_y = 0;
+ you.turn_is_over = 0;
+ }
+
+#ifndef LINUX
+ get_keyin_again:
+#endif //jmf: just stops an annoying gcc warning
+
+
+
+ switch (keyin)
+ {
+ case CONTROL('Y'):
+ case CMD_OPEN_DOOR_UP_RIGHT:
+ open_door(-1, -1); move_x = 0; move_y = 0; break;
+
+ case CONTROL('K'):
+ case CMD_OPEN_DOOR_UP:
+ open_door( 0, -1); move_x = 0; move_y = 0; break;
+
+ case CONTROL('U'):
+ case CMD_OPEN_DOOR_UP_LEFT:
+ open_door( 1, -1); move_x = 0; move_y = 0; break;
+
+ case CONTROL('L'):
+ case CMD_OPEN_DOOR_RIGHT:
+ open_door( 1, 0); move_x = 0; move_y = 0; break;
+
+ case CONTROL('N'):
+ case CMD_OPEN_DOOR_DOWN_RIGHT:
+ open_door( 1, 1); move_x = 0; move_y = 0; break;
+
+ case CONTROL('J'):
+ case CMD_OPEN_DOOR_DOWN:
+ open_door( 0, 1); move_x = 0; move_y = 0; break;
+
+ case CONTROL('B'):
+ case CMD_OPEN_DOOR_DOWN_LEFT:
+ open_door(-1, 1); move_x = 0; move_y = 0; break;
+
+ case CONTROL('H'):
+ case CMD_OPEN_DOOR_LEFT:
+ open_door(-1, 0); move_x = 0; move_y = 0; break;
+
+ case 'b': case CMD_MOVE_DOWN_LEFT: move_x = -1; move_y = 1; break;
+ case 'j': case CMD_MOVE_DOWN: move_y = 1; move_x = 0; break;
+ case 'u': case CMD_MOVE_UP_RIGHT: move_x = 1; move_y = -1; break;
+ case 'k': case CMD_MOVE_UP: move_y = -1; move_x = 0; break;
+ case 'y': case CMD_MOVE_UP_LEFT: move_y = -1; move_x = -1; break;
+ case 'h': case CMD_MOVE_LEFT: move_x = -1; move_y = 0; break;
+ case 'n': case CMD_MOVE_DOWN_RIGHT: move_y = 1; move_x = 1; break;
+ case 'l': case CMD_MOVE_RIGHT: move_x = 1; move_y = 0; break;
+
+ case CMD_REST:
+ // Yes this is backwards, but everyone here is used to using
+ // straight 5s for long rests... might need to define a roguelike
+ // rest key and get people switched over. -- bwr
+
+#ifdef LINUX
+ if (!running && !opening)
+ start_running( RDIR_REST, 100 );
+ else
+ {
+ search_around();
+ move_x = 0;
+ move_y = 0;
+ you.turn_is_over = 1;
+ }
+#endif
+ break;
+
+ case 'B': case CMD_RUN_DOWN_LEFT:
+ start_running( RDIR_DOWN_LEFT, 2 ); break;
+
+ case 'J': case CMD_RUN_DOWN:
+ start_running( RDIR_DOWN, 2 ); break;
+
+ case 'U': case CMD_RUN_UP_RIGHT:
+ start_running( RDIR_UP_RIGHT, 2 ); break;
+
+ case 'K': case CMD_RUN_UP:
+ start_running( RDIR_UP, 2 ); break;
+
+ case 'Y': case CMD_RUN_UP_LEFT:
+ start_running( RDIR_UP_LEFT, 2 ); break;
+
+ case 'H': case CMD_RUN_LEFT:
+ start_running( RDIR_LEFT, 2 ); break;
+
+ case 'N': case CMD_RUN_DOWN_RIGHT:
+ start_running( RDIR_DOWN_RIGHT, 2 ); break;
+
+ case 'L': case CMD_RUN_RIGHT:
+ start_running( RDIR_RIGHT, 2 ); break;
+
+#ifdef LINUX
+ // taken care of via key -> command mapping
+#else
+ // Old DOS keypad support
+ case '1': start_running( RDIR_DOWN_LEFT, 2 ); break;
+ case '2': start_running( RDIR_DOWN, 2 ); break;
+ case '9': start_running( RDIR_UP_RIGHT, 2 ); break;
+ case '8': start_running( RDIR_UP, 2 ); break;
+ case '7': start_running( RDIR_UP_LEFT, 2 ); break;
+ case '4': start_running( RDIR_LEFT, 2 ); break;
+ case '3': start_running( RDIR_DOWN_RIGHT, 2 ); break;
+ case '6': start_running( RDIR_RIGHT, 2 ); break;
+ case '5': start_running( RDIR_REST, 100 ); break;
+
+#endif
+
+ case CONTROL('A'):
+ case CMD_TOGGLE_AUTOPICKUP:
+ autopickup_on = !autopickup_on;
+ strcpy(info, "Autopickup is now ");
+ strcat(info, (autopickup_on) ? "on" : "off");
+ strcat(info, ".");
+ mpr(info);
+ break;
+
+ case '<':
+ case CMD_GO_UPSTAIRS:
+ if (grd[you.x_pos][you.y_pos] == DNGN_ENTER_SHOP)
+ {
+ shop();
+ break;
+ }
+ else if ((grd[you.x_pos][you.y_pos] < DNGN_STONE_STAIRS_UP_I
+ || grd[you.x_pos][you.y_pos] > DNGN_ROCK_STAIRS_UP)
+ && (grd[you.x_pos][you.y_pos] < DNGN_RETURN_FROM_ORCISH_MINES
+ || grd[you.x_pos][you.y_pos] >= 150))
+ {
+ mpr( "You can't go up here!" );
+ break;
+ }
+
+ tag_followers(); // only those beside us right now can follow
+ start_delay( DELAY_ASCENDING_STAIRS,
+ 1 + (you.burden_state > BS_UNENCUMBERED) );
+ break;
+
+ case '>':
+ case CMD_GO_DOWNSTAIRS:
+ if ((grd[you.x_pos][you.y_pos] < DNGN_ENTER_LABYRINTH
+ || grd[you.x_pos][you.y_pos] > DNGN_ROCK_STAIRS_DOWN)
+ && grd[you.x_pos][you.y_pos] != DNGN_ENTER_HELL
+ && ((grd[you.x_pos][you.y_pos] < DNGN_ENTER_DIS
+ || grd[you.x_pos][you.y_pos] > DNGN_TRANSIT_PANDEMONIUM)
+ && grd[you.x_pos][you.y_pos] != DNGN_STONE_ARCH)
+ && !(grd[you.x_pos][you.y_pos] >= DNGN_ENTER_ORCISH_MINES
+ && grd[you.x_pos][you.y_pos] < DNGN_RETURN_FROM_ORCISH_MINES))
+ {
+ mpr( "You can't go down here!" );
+ break;
+ }
+
+ tag_followers(); // only those beside us right now can follow
+ start_delay( DELAY_DESCENDING_STAIRS,
+ 1 + (you.burden_state > BS_UNENCUMBERED),
+ you.your_level );
+ break;
+
+ case 'O':
+ case CMD_DISPLAY_OVERMAP:
+ display_overmap();
+ break;
+
+ case 'o':
+ case CMD_OPEN_DOOR:
+ open_door(0, 0);
+ break;
+ case 'c':
+ case CMD_CLOSE_DOOR:
+ close_door(0, 0);
+ break;
+
+ case 'd':
+ case CMD_DROP:
+ drop();
+ break;
+
+ case 'D':
+ case CMD_BUTCHER:
+ butchery();
+ break;
+
+ case 'i':
+ case CMD_DISPLAY_INVENTORY:
+ get_invent(-1);
+ break;
+
+ case 'I':
+ case CMD_OBSOLETE_INVOKE:
+ // We'll leave this message in for a while. Eventually, this
+ // might be some special for of inventory command, or perhaps
+ // actual god invocations will be split to here from abilities. -- bwr
+ mpr( "This command is now 'E'voke wielded item.", MSGCH_WARN );
+ break;
+
+ case 'E':
+ case CMD_EVOKE:
+ if (!evoke_wielded())
+ flush_input_buffer( FLUSH_ON_FAILURE );
+ break;
+
+ case 'g':
+ case ',':
+ case CMD_PICKUP:
+ pickup();
+ break;
+
+ case ';':
+ case CMD_INSPECT_FLOOR:
+ item_check(';');
+ break;
+
+ case 'w':
+ case CMD_WIELD_WEAPON:
+ wield_weapon(false);
+ break;
+
+ case 't':
+ case CMD_THROW:
+ throw_anything();
+ break;
+
+ case 'f':
+ case CMD_FIRE:
+ shoot_thing();
+ break;
+
+ case 'W':
+ case CMD_WEAR_ARMOUR:
+ wear_armour();
+ break;
+
+ case 'T':
+ case CMD_REMOVE_ARMOUR:
+ {
+ int index=0;
+
+ if (armour_prompt("Take off which item?", &index))
+ takeoff_armour(index);
+ }
+ break;
+
+ case 'R':
+ case CMD_REMOVE_JEWELLERY:
+ remove_ring();
+ break;
+ case 'P':
+ case CMD_WEAR_JEWELLERY:
+ puton_ring();
+ break;
+
+ case '=':
+ case CMD_ADJUST_INVENTORY:
+ adjust();
+ return;
+
+ case 'M':
+ case CMD_MEMORISE_SPELL:
+ if (!learn_spell())
+ flush_input_buffer( FLUSH_ON_FAILURE );
+ break;
+
+ case 'z':
+ case CMD_ZAP_WAND:
+ zap_wand();
+ break;
+
+ case 'e':
+ case CMD_EAT:
+ eat_food();
+ break;
+
+ case 'a':
+ case CMD_USE_ABILITY:
+ if (!activate_ability())
+ flush_input_buffer( FLUSH_ON_FAILURE );
+ break;
+
+ case 'A':
+ case CMD_DISPLAY_MUTATIONS:
+ display_mutations();
+ redraw_screen();
+ break;
+
+ case 'v':
+ case CMD_EXAMINE_OBJECT:
+ original_name();
+ break;
+
+ case 'p':
+ case CMD_PRAY:
+ pray();
+ break;
+
+ case '^':
+ case CMD_DISPLAY_RELIGION:
+ describe_god( you.religion, true );
+ redraw_screen();
+ break;
+
+ case '.':
+ case CMD_MOVE_NOWHERE:
+ search_around();
+ move_x = 0;
+ move_y = 0;
+ you.turn_is_over = 1;
+ break;
+
+ case 'q':
+ case CMD_QUAFF:
+ drink();
+ break;
+
+ case 'r':
+ case CMD_READ:
+ read_scroll();
+ break;
+
+ case 'x':
+ case CMD_LOOK_AROUND:
+ mpr("Move the cursor around to observe a square.", MSGCH_PROMPT);
+ mpr("Press '?' for a monster description.", MSGCH_PROMPT);
+
+ struct dist lmove;
+ look_around( lmove, true );
+ break;
+
+ case 's':
+ case CMD_SEARCH:
+ search_around();
+ you.turn_is_over = 1;
+ break;
+
+ case 'Z':
+ case CMD_CAST_SPELL:
+ /* randart wpns */
+ if (scan_randarts(RAP_PREVENT_SPELLCASTING))
+ {
+ mpr("Something interferes with your magic!");
+ flush_input_buffer( FLUSH_ON_FAILURE );
+ break;
+ }
+
+ if (!cast_a_spell())
+ flush_input_buffer( FLUSH_ON_FAILURE );
+ break;
+
+ case '\'':
+ case CMD_WEAPON_SWAP:
+ wield_weapon(true);
+ break;
+
+ case 'X':
+ case CMD_DISPLAY_MAP:
+#if (!DEBUG_DIAGNOSTICS)
+ if (you.level_type == LEVEL_LABYRINTH || you.level_type == LEVEL_ABYSS)
+ {
+ mpr("It would help if you knew where you were, first.");
+ break;
+ }
+#endif
+ plox[0] = 0;
+ show_map(plox);
+ redraw_screen();
+ break;
+
+ case '\\':
+ case CMD_DISPLAY_KNOWN_OBJECTS:
+ check_item_knowledge(); //nothing = check_item_knowledge();
+ redraw_screen();
+ break;
+
+#ifdef ALLOW_DESTROY_ITEM_COMMAND
+ case CONTROL('D'):
+ case CMD_DESTROY_ITEM:
+ cmd_destroy_item();
+ break;
+#endif
+
+ case CONTROL('P'):
+ case CMD_REPLAY_MESSAGES:
+ replay_messages();
+ redraw_screen();
+ break;
+
+ case CONTROL('R'):
+ case CMD_REDRAW_SCREEN:
+ redraw_screen();
+ break;
+
+ case CONTROL('X'):
+ case CMD_SAVE_GAME_NOW:
+ mpr("Saving game... please wait.");
+ save_game(true);
+ break;
+
+#ifdef USE_UNIX_SIGNALS
+ case CONTROL('Z'):
+ case CMD_SUSPEND_GAME:
+ // CTRL-Z suspend behaviour is implemented here,
+ // because we want to have CTRL-Y available...
+ // and unfortuantely they tend to be stuck together.
+ clrscr();
+ lincurses_shutdown();
+ kill(0, SIGTSTP);
+ lincurses_startup();
+ redraw_screen();
+ break;
+#endif
+
+ case '?':
+ case CMD_DISPLAY_COMMANDS:
+ list_commands(false);
+ redraw_screen();
+ break;
+
+ case 'C':
+ case CMD_EXPERIENCE_CHECK:
+ snprintf( info, INFO_SIZE, "You are a level %d %s %s.", you.experience_level,
+ species_name(you.species,you.experience_level), you.class_name);
+ mpr(info);
+
+ if (you.experience_level < 27)
+ {
+ int xp_needed = (exp_needed(you.experience_level+2) - you.experience) + 1;
+ snprintf( info, INFO_SIZE, "Level %d requires %ld experience (%d point%s to go!)",
+ you.experience_level + 1,
+ exp_needed(you.experience_level + 2) + 1,
+ xp_needed,
+ (xp_needed > 1) ? "s" : "");
+ mpr(info);
+ }
+ else
+ {
+ mpr( "I'm sorry, level 27 is as high as you can go." );
+ mpr( "With the way you've been playing, I'm surprised you got this far." );
+ }
+
+ if (you.real_time != -1)
+ {
+ const time_t curr = you.real_time + (time(NULL) - you.start_time);
+ char buff[200];
+
+ make_time_string( curr, buff, sizeof(buff) );
+
+ snprintf( info, INFO_SIZE, "Play time: %s (%ld turns)",
+ buff, you.num_turns );
+
+ mpr( info );
+ }
+ break;
+
+
+ case '!':
+ case CMD_SHOUT:
+ yell(); /* in effects.cc */
+ break;
+
+ case '@':
+ case CMD_DISPLAY_CHARACTER_STATUS:
+ display_char_status();
+ break;
+
+ case 'm':
+ case CMD_DISPLAY_SKILLS:
+ show_skills();
+ redraw_screen();
+ break;
+
+ case '#':
+ case CMD_CHARACTER_DUMP:
+ char name_your[kNameLen+1];
+
+ strncpy(name_your, you.your_name, kNameLen);
+ name_your[kNameLen] = '\0';
+ if (dump_char( name_your, false ))
+ strcpy(info, "Char dumped successfully.");
+ else
+ strcat(info, "Char dump unsuccessful! Sorry about that.");
+ mpr(info);
+ break;
+
+#ifdef USE_MACROS
+ case '`':
+ case CMD_MACRO_ADD:
+ macro_add_query();
+ break;
+ case '~':
+ case CMD_MACRO_SAVE:
+ mpr("Saving macros.");
+ macro_save();
+ break;
+#endif
+
+ case ')':
+ case CMD_LIST_WEAPONS:
+ list_weapons();
+ return;
+
+ case ']':
+ case CMD_LIST_ARMOUR:
+ list_armour();
+ return;
+
+ case '"':
+ case CMD_LIST_JEWELLERY:
+ list_jewellery();
+ return;
+
+#ifdef WIZARD
+ case CONTROL('W'):
+ case CMD_WIZARD:
+ case '&':
+ handle_wizard_command();
+ break;
+#endif
+
+ case 'S':
+ case CMD_SAVE_GAME:
+ if (yesno("Save game and exit?", false))
+ save_game(true);
+ break;
+
+ case 'Q':
+ case CMD_QUIT:
+ quit_game();
+ break;
+
+ case 'V':
+ case CMD_GET_VERSION:
+ version();
+ break;
+
+ case 128: // Can't use this char -- it's the special value 128
+ break;
+
+ default:
+ case CMD_NO_CMD:
+ mpr("Unknown command.");
+ break;
+
+ }
+
+#ifdef LINUX
+ // New Unix keypad stuff
+ if (running)
+ {
+ int dir = -1;
+
+ // XXX: ugly hack to interface this with the new running code. -- bwr
+ for (int i = 0; i < 8; i++)
+ {
+ if (Compass[i].x == move_x && Compass[i].y == move_y)
+ {
+ dir = i;
+ break;
+ }
+ }
+
+ if (dir != -1)
+ {
+ start_running( dir, 2 );
+ move_x = 0;
+ move_y = 0;
+ }
+ }
+ else if (opening)
+ {
+ open_door(move_x, move_y);
+ move_x = 0;
+ move_y = 0;
+ }
+#endif
+
+ if (move_x != 0 || move_y != 0)
+ move_player(move_x, move_y);
+ else if (you.turn_is_over) // we did something other than move/attack
+ do_berserk_no_combat_penalty();
+
+ if (!you.turn_is_over)
+ {
+ viewwindow(1, false);
+ return;
+ }
+
+ if (you.num_turns != -1)
+ you.num_turns++;
+
+ //if (random2(10) < you.skills [SK_TRAPS_DOORS] + 2) search_around();
+
+ stealth = check_stealth();
+
+#if 0
+ // too annoying for regular diagnostics
+ snprintf( info, INFO_SIZE, "stealth: %d", stealth );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ if (you.special_wield != SPWLD_NONE)
+ special_wielded();
+
+ if (one_chance_in(10))
+ {
+ // this is instantaneous
+ if (player_teleport() > 0 && one_chance_in(100 / player_teleport()))
+ you_teleport2( true );
+ else if (you.level_type == LEVEL_ABYSS && one_chance_in(30))
+ you_teleport2( false, true ); // to new area of the Abyss
+ }
+
+ if (env.cgrid[you.x_pos][you.y_pos] != EMPTY_CLOUD)
+ in_a_cloud();
+
+ if (you.duration[DUR_REPEL_UNDEAD] > 1)
+ you.duration[DUR_REPEL_UNDEAD]--;
+
+ if (you.duration[DUR_REPEL_UNDEAD] == 4)
+ {
+ mpr( "Your holy aura is starting to fade.", MSGCH_DURATION );
+ you.duration[DUR_REPEL_UNDEAD] -= random2(3);
+ }
+
+ if (you.duration[DUR_REPEL_UNDEAD] == 1)
+ {
+ mpr( "Your holy aura fades away.", MSGCH_DURATION );
+ you.duration[DUR_REPEL_UNDEAD] = 0;
+ }
+
+ // paradox: it both lasts longer & does more damage overall if you're
+ // moving slower.
+ // rationalisation: I guess it gets rubbed off/falls off/etc if you
+ // move around more.
+ if (you.duration[DUR_LIQUID_FLAMES] > 0)
+ you.duration[DUR_LIQUID_FLAMES]--;
+
+ if (you.duration[DUR_LIQUID_FLAMES] != 0)
+ {
+ const int res_fire = player_res_fire();
+
+ mpr( "You are covered in liquid flames!", MSGCH_WARN );
+ scrolls_burn(8, OBJ_SCROLLS);
+
+ if (res_fire > 0)
+ {
+ ouch( (((random2avg(9, 2) + 1) * you.time_taken) /
+ (1 + (res_fire * res_fire))) / 10, 0, KILLED_BY_BURNING );
+ }
+
+ if (res_fire <= 0)
+ {
+ ouch(((random2avg(9, 2) + 1) * you.time_taken) / 10, 0,
+ KILLED_BY_BURNING);
+ }
+
+ if (res_fire < 0)
+ {
+ ouch(((random2avg(9, 2) + 1) * you.time_taken) / 10, 0,
+ KILLED_BY_BURNING);
+ }
+
+ if (you.duration[DUR_CONDENSATION_SHIELD] > 0)
+ {
+ mpr("Your icy shield dissipates!", MSGCH_DURATION);
+ you.duration[DUR_CONDENSATION_SHIELD] = 0;
+ you.redraw_armour_class = 1;
+ }
+ }
+
+ if (you.duration[DUR_ICY_ARMOUR] > 1)
+ {
+ you.duration[DUR_ICY_ARMOUR]--;
+ //scrolls_burn(4, OBJ_POTIONS);
+ }
+ else if (you.duration[DUR_ICY_ARMOUR] == 1)
+ {
+ mpr("Your icy armour evaporates.", MSGCH_DURATION);
+ you.redraw_armour_class = 1; // is this needed? 2apr2000 {dlb}
+ you.duration[DUR_ICY_ARMOUR] = 0;
+ }
+
+ if (you.duration[DUR_REPEL_MISSILES] > 1)
+ {
+ you.duration[DUR_REPEL_MISSILES]--;
+ if (you.duration[DUR_REPEL_MISSILES] == 6)
+ {
+ mpr("Your repel missiles spell is about to expire...", MSGCH_DURATION);
+ if (coinflip())
+ you.duration[DUR_REPEL_MISSILES]--;
+ }
+ }
+ else if (you.duration[DUR_REPEL_MISSILES] == 1)
+ {
+ mpr("You feel less protected from missiles.", MSGCH_DURATION);
+ you.duration[DUR_REPEL_MISSILES] = 0;
+ }
+
+ if (you.duration[DUR_DEFLECT_MISSILES] > 1)
+ {
+ you.duration[DUR_DEFLECT_MISSILES]--;
+ if (you.duration[DUR_DEFLECT_MISSILES] == 6)
+ {
+ mpr("Your deflect missiles spell is about to expire...", MSGCH_DURATION);
+ if (coinflip())
+ you.duration[DUR_DEFLECT_MISSILES]--;
+ }
+ }
+ else if (you.duration[DUR_DEFLECT_MISSILES] == 1)
+ {
+ mpr("You feel less protected from missiles.", MSGCH_DURATION);
+ you.duration[DUR_DEFLECT_MISSILES] = 0;
+ }
+
+ if (you.duration[DUR_REGENERATION] > 1)
+ {
+ you.duration[DUR_REGENERATION]--;
+
+ if (you.duration[DUR_REGENERATION] == 6)
+ {
+ mpr("Your skin is crawling a little less now.", MSGCH_DURATION);
+ if (coinflip())
+ you.duration[DUR_REGENERATION]--;
+ }
+ }
+ else if (you.duration[DUR_REGENERATION] == 1)
+ {
+ mpr("Your skin stops crawling.", MSGCH_DURATION);
+ you.duration[DUR_REGENERATION] = 0;
+ }
+
+ if (you.duration[DUR_PRAYER] > 1)
+ you.duration[DUR_PRAYER]--;
+ else if (you.duration[DUR_PRAYER] == 1)
+ {
+ god_speaks(you.religion, "Your prayer is over.");
+ you.duration[DUR_PRAYER] = 0;
+ }
+
+
+ //jmf: more flexible weapon branding code
+ if (you.duration[DUR_WEAPON_BRAND] > 1)
+ you.duration[DUR_WEAPON_BRAND]--;
+ else if (you.duration[DUR_WEAPON_BRAND] == 1)
+ {
+ const int wpn = you.equip[EQ_WEAPON];
+ const int temp_effect = get_weapon_brand( you.inv[wpn] );
+
+ you.duration[DUR_WEAPON_BRAND] = 0;
+
+ char str_pass[ITEMNAME_SIZE];
+
+ set_item_ego_type( you.inv[wpn], OBJ_WEAPONS, SPWPN_NORMAL );
+ in_name(wpn, DESC_CAP_YOUR, str_pass);
+ strncpy(info, str_pass, INFO_SIZE);
+
+ switch (temp_effect)
+ {
+ case SPWPN_VORPAL:
+ if (damage_type(you.inv[you.equip[EQ_WEAPON]].base_type,
+ you.inv[you.equip[EQ_WEAPON]].sub_type) != DVORP_CRUSHING)
+ {
+ strcat(info, " seems blunter.");
+ }
+ else
+ {
+ //jmf: for Maxwell's Silver Hammer
+ strcat(info, " feels lighter.");
+ }
+ break;
+
+ case SPWPN_FLAMING:
+ strcat(info, " goes out.");
+ break;
+ case SPWPN_FREEZING:
+ strcat(info, " stops glowing.");
+ break;
+ case SPWPN_VENOM:
+ strcat(info, " stops dripping with poison.");
+ break;
+ case SPWPN_DRAINING:
+ strcat(info, " stops crackling.");
+ break;
+ case SPWPN_DISTORTION:
+ strcat( info, " seems straighter." );
+ miscast_effect( SPTYP_TRANSLOCATION, 9, 90, 100, "a distortion effect" );
+ break;
+ default:
+ strcat(info, " seems inexplicably less special.");
+ break;
+ }
+
+ //you.attribute[ATTR_WEAPON_BRAND] = 0;
+ mpr(info, MSGCH_DURATION);
+ you.wield_change = true;
+ }
+
+ if (you.duration[DUR_BREATH_WEAPON] > 1)
+ you.duration[DUR_BREATH_WEAPON]--;
+ else if (you.duration[DUR_BREATH_WEAPON] == 1)
+ {
+ mpr("You have got your breath back.", MSGCH_RECOVERY);
+ you.duration[DUR_BREATH_WEAPON] = 0;
+ }
+
+ if (you.duration[DUR_TRANSFORMATION] > 1)
+ {
+ you.duration[DUR_TRANSFORMATION]--;
+
+ if (you.duration[DUR_TRANSFORMATION] == 10)
+ {
+ mpr("Your transformation is almost over.", MSGCH_DURATION);
+ you.duration[DUR_TRANSFORMATION] -= random2(3);
+ }
+ }
+ else if (you.duration[DUR_TRANSFORMATION] == 1)
+ {
+ untransform();
+ you.duration[DUR_BREATH_WEAPON] = 0;
+ }
+
+ if (you.duration[DUR_SWIFTNESS] > 1)
+ {
+ you.duration[DUR_SWIFTNESS]--;
+ if (you.duration[DUR_SWIFTNESS] == 6)
+ {
+ mpr("You start to feel a little slower.", MSGCH_DURATION);
+ if (coinflip())
+ you.duration[DUR_SWIFTNESS]--;
+ }
+ }
+ else if (you.duration[DUR_SWIFTNESS] == 1)
+ {
+ mpr("You feel sluggish.", MSGCH_DURATION);
+ you.duration[DUR_SWIFTNESS] = 0;
+ }
+
+ if (you.duration[DUR_INSULATION] > 1)
+ {
+ you.duration[DUR_INSULATION]--;
+ if (you.duration[DUR_INSULATION] == 6)
+ {
+ mpr("You start to feel a little less insulated.", MSGCH_DURATION);
+ if (coinflip())
+ you.duration[DUR_INSULATION]--;
+ }
+ }
+ else if (you.duration[DUR_INSULATION] == 1)
+ {
+ mpr("You feel conductive.", MSGCH_DURATION);
+ you.duration[DUR_INSULATION] = 0;
+ }
+
+ if (you.duration[DUR_STONEMAIL] > 1)
+ {
+ you.duration[DUR_STONEMAIL]--;
+ if (you.duration[DUR_STONEMAIL] == 6)
+ {
+ mpr("Your scaley stone armour is starting to flake away.", MSGCH_DURATION);
+ you.redraw_armour_class = 1;
+ if (coinflip())
+ you.duration[DUR_STONEMAIL]--;
+ }
+ }
+ else if (you.duration[DUR_STONEMAIL] == 1)
+ {
+ mpr("Your scaley stone armour disappears.", MSGCH_DURATION);
+ you.duration[DUR_STONEMAIL] = 0;
+ you.redraw_armour_class = 1;
+ burden_change();
+ }
+
+ if (you.duration[DUR_FORESCRY] > 1) //jmf: added
+ you.duration[DUR_FORESCRY]--;
+ else if (you.duration[DUR_FORESCRY] == 1)
+ {
+ mpr("You feel firmly rooted in the present.", MSGCH_DURATION);
+ you.duration[DUR_FORESCRY] = 0;
+ you.redraw_evasion = 1;
+ }
+
+ if (you.duration[DUR_SEE_INVISIBLE] > 1) //jmf: added
+ you.duration[DUR_SEE_INVISIBLE]--;
+ else if (you.duration[DUR_SEE_INVISIBLE] == 1)
+ {
+ you.duration[DUR_SEE_INVISIBLE] = 0;
+
+ if (!player_see_invis())
+ mpr("Your eyesight blurs momentarily.", MSGCH_DURATION);
+ }
+
+ if (you.duration[DUR_SILENCE] > 0) //jmf: cute message handled elsewhere
+ you.duration[DUR_SILENCE]--;
+
+ if (you.duration[DUR_CONDENSATION_SHIELD] > 1)
+ {
+ you.duration[DUR_CONDENSATION_SHIELD]--;
+
+ scrolls_burn( 1, OBJ_POTIONS );
+
+ if (player_res_cold() < 0)
+ {
+ mpr( "You feel very cold." );
+ ouch( 2 + random2avg(13, 2), 0, KILLED_BY_FREEZING );
+ }
+ }
+ else if (you.duration[DUR_CONDENSATION_SHIELD] == 1)
+ {
+ you.duration[DUR_CONDENSATION_SHIELD] = 0;
+ mpr("Your icy shield evaporates.", MSGCH_DURATION);
+ you.redraw_armour_class = 1;
+ }
+
+ if (you.duration[DUR_STONESKIN] > 1)
+ you.duration[DUR_STONESKIN]--;
+ else if (you.duration[DUR_STONESKIN] == 1)
+ {
+ mpr("Your skin feels tender.", MSGCH_DURATION);
+ you.redraw_armour_class = 1;
+ you.duration[DUR_STONESKIN] = 0;
+ }
+
+ if (you.duration[DUR_GLAMOUR] > 1) //jmf: actually GLAMOUR_RELOAD, like
+ you.duration[DUR_GLAMOUR]--; // the breath weapon delay
+ else if (you.duration[DUR_GLAMOUR] == 1)
+ {
+ you.duration[DUR_GLAMOUR] = 0;
+ //FIXME: cute message or not?
+ }
+
+ if (you.duration[DUR_TELEPORT] > 1)
+ you.duration[DUR_TELEPORT]--;
+ else if (you.duration[DUR_TELEPORT] == 1)
+ {
+ // only to a new area of the abyss sometimes (for abyss teleports)
+ you_teleport2( true, one_chance_in(5) );
+ you.duration[DUR_TELEPORT] = 0;
+ }
+
+ if (you.duration[DUR_CONTROL_TELEPORT] > 1)
+ {
+ you.duration[DUR_CONTROL_TELEPORT]--;
+
+ if (you.duration[DUR_CONTROL_TELEPORT] == 6)
+ {
+ mpr("You start to feel a little uncertain.", MSGCH_DURATION);
+ if (coinflip())
+ you.duration[DUR_CONTROL_TELEPORT]--;
+ }
+ }
+ else if (you.duration[DUR_CONTROL_TELEPORT] == 1)
+ {
+ mpr("You feel uncertain.", MSGCH_DURATION);
+ you.duration[DUR_CONTROL_TELEPORT] = 0;
+ you.attribute[ATTR_CONTROL_TELEPORT]--;
+ }
+
+ if (you.duration[DUR_RESIST_POISON] > 1)
+ {
+ you.duration[DUR_RESIST_POISON]--;
+ if (you.duration[DUR_RESIST_POISON] == 6)
+ {
+ mpr("Your poison resistance is about to expire.", MSGCH_DURATION);
+ if (coinflip())
+ you.duration[DUR_RESIST_POISON]--;
+ }
+ }
+ else if (you.duration[DUR_RESIST_POISON] == 1)
+ {
+ mpr("Your poison resistance expires.", MSGCH_DURATION);
+ you.duration[DUR_RESIST_POISON] = 0;
+ }
+
+ if (you.duration[DUR_DEATH_CHANNEL] > 1)
+ {
+ you.duration[DUR_DEATH_CHANNEL]--;
+ if (you.duration[DUR_DEATH_CHANNEL] == 6)
+ {
+ mpr("Your unholy channel is weakening.", MSGCH_DURATION);
+ if (coinflip())
+ you.duration[DUR_DEATH_CHANNEL]--;
+ }
+ }
+ else if (you.duration[DUR_DEATH_CHANNEL] == 1)
+ {
+ mpr("Your unholy channel expires.", MSGCH_DURATION); // Death channel wore off
+ you.duration[DUR_DEATH_CHANNEL] = 0;
+ }
+
+ if (you.duration[DUR_SHUGGOTH_SEED_RELOAD] > 0) //jmf: added
+ you.duration[DUR_SHUGGOTH_SEED_RELOAD]--;
+
+ if (you.duration[DUR_INFECTED_SHUGGOTH_SEED] > 1)
+ you.duration[DUR_INFECTED_SHUGGOTH_SEED]--;
+ else if (you.duration[DUR_INFECTED_SHUGGOTH_SEED] == 1)
+ {
+ //jmf: use you.max_hp instead? or would that be too evil?
+ you.duration[DUR_INFECTED_SHUGGOTH_SEED] = 0;
+ mpr("A horrible thing bursts from your chest!", MSGCH_WARN);
+ ouch(1 + you.hp / 2, 0, KILLED_BY_SHUGGOTH);
+ make_shuggoth(you.x_pos, you.y_pos, 1 + you.hp / 2);
+ }
+
+ if (you.invis > 1)
+ {
+ you.invis--;
+
+ if (you.invis == 6)
+ {
+ mpr("You flicker for a moment.", MSGCH_DURATION);
+ if (coinflip())
+ you.invis--;
+ }
+ }
+ else if (you.invis == 1)
+ {
+ mpr("You flicker back into view.", MSGCH_DURATION);
+ you.invis = 0;
+ }
+
+ if (you.conf > 0)
+ reduce_confuse_player(1);
+
+ if (you.paralysis > 1)
+ you.paralysis--;
+ else if (you.paralysis == 1)
+ {
+ mpr("You can move again.", MSGCH_DURATION);
+ you.paralysis = 0;
+ }
+
+ if (you.exhausted > 1)
+ you.exhausted--;
+ else if (you.exhausted == 1)
+ {
+ mpr("You feel less fatigued.", MSGCH_DURATION);
+ you.exhausted = 0;
+ }
+
+ dec_slow_player();
+ dec_haste_player();
+
+ if (you.might > 1)
+ you.might--;
+ else if (you.might == 1)
+ {
+ mpr("You feel a little less mighty now.", MSGCH_DURATION);
+ you.might = 0;
+ modify_stat(STAT_STRENGTH, -5, true);
+ }
+
+ if (you.berserker > 1)
+ you.berserker--;
+ else if (you.berserker == 1)
+ {
+ mpr( "You are no longer berserk.", MSGCH_DURATION );
+ you.berserker = 0;
+
+ //jmf: guilty for berserking /after/ berserk
+ naughty( NAUGHTY_STIMULANTS, 6 + random2(6) );
+
+ //
+ // Sometimes berserk leaves us physically drained
+ //
+
+ // chance of passing out:
+ // - mutation gives a large plus in order to try and
+ // avoid the mutation being a "death sentence" to
+ // certain characters.
+ // - knowing the spell gives an advantage just
+ // so that people who have invested 3 spell levels
+ // are better off than the casual potion drinker...
+ // this should make it a bit more interesting for
+ // Crusaders again.
+ // - similarly for the amulet
+ int chance = 10 + you.mutation[MUT_BERSERK] * 25
+ + (wearing_amulet( AMU_RAGE ) ? 10 : 0)
+ + (player_has_spell( SPELL_BERSERKER_RAGE ) ? 5 : 0);
+
+ // Note the beauty of Trog! They get an extra save that's at
+ // the very least 20% and goes up to 100%.
+ if (you.berserk_penalty == NO_BERSERK_PENALTY
+ || (you.religion == GOD_TROG && you.piety > random2(150))
+ || !one_chance_in( chance ))
+ {
+ mpr("You are exhausted.");
+ }
+ else
+ {
+ mpr("You pass out from exhaustion.", MSGCH_WARN);
+ you.paralysis += roll_dice( 1, 4 );
+ }
+
+ // this resets from an actual penalty or from NO_BERSERK_PENALTY
+ you.berserk_penalty = 0;
+
+ int dur = 12 + roll_dice( 2, 12 );
+ you.exhausted += dur;
+ slow_player( dur );
+
+ make_hungry(700, true);
+
+ if (you.hunger < 50)
+ you.hunger = 50;
+
+ calc_hp();
+ }
+
+ if (you.confusing_touch > 1)
+ you.confusing_touch--;
+ else if (you.confusing_touch == 1)
+ {
+ snprintf( info, INFO_SIZE, "Your %s stop glowing.", your_hand(true) );
+ mpr( info, MSGCH_DURATION );
+ you.confusing_touch = 0;
+ }
+
+ if (you.sure_blade > 1)
+ you.sure_blade--;
+ else if (you.sure_blade == 1)
+ {
+ mpr("The bond with your blade fades away.", MSGCH_DURATION);
+ you.sure_blade = 0;
+ }
+
+ if (you.levitation > 1)
+ {
+ if (you.species != SP_KENKU || you.experience_level < 15)
+ you.levitation--;
+
+ if (player_equip_ego_type( EQ_BOOTS, SPARM_LEVITATION ))
+ you.levitation = 2;
+
+ if (you.levitation == 10)
+ {
+ mpr("You are starting to lose your buoyancy!", MSGCH_DURATION);
+ you.levitation -= random2(6);
+
+ if (you.duration[DUR_CONTROLLED_FLIGHT] > 0)
+ you.duration[DUR_CONTROLLED_FLIGHT] = you.levitation;
+ }
+ }
+ else if (you.levitation == 1)
+ {
+ mpr("You float gracefully downwards.", MSGCH_DURATION);
+ you.levitation = 0;
+ burden_change();
+ you.duration[DUR_CONTROLLED_FLIGHT] = 0;
+
+ if (grd[you.x_pos][you.y_pos] == DNGN_LAVA
+ || grd[you.x_pos][you.y_pos] == DNGN_DEEP_WATER
+ || grd[you.x_pos][you.y_pos] == DNGN_SHALLOW_WATER)
+ {
+ if (you.species == SP_MERFOLK
+ && grd[you.x_pos][you.y_pos] != DNGN_LAVA)
+ {
+ mpr("You dive into the water and return to your normal form.");
+ merfolk_start_swimming();
+ }
+
+ if (grd[you.x_pos][you.y_pos] != DNGN_SHALLOW_WATER)
+ fall_into_a_pool(true, grd[you.x_pos][you.y_pos]);
+ }
+ }
+
+ if (you.rotting > 0)
+ {
+ // XXX: Mummies have an ability (albeit an expensive one) that
+ // can fix rotted HPs now... it's probably impossible for them
+ // to even start rotting right now, but that could be changed. -- bwr
+ if (you.species == SP_MUMMY)
+ you.rotting = 0;
+ else if (random2(20) <= (you.rotting - 1))
+ {
+ mpr("You feel your flesh rotting away.", MSGCH_WARN);
+ ouch(1, 0, KILLED_BY_ROTTING);
+ rot_hp(1);
+ you.rotting--;
+ }
+ }
+
+ // ghoul rotting is special, but will deduct from you.rotting
+ // if it happens to be positive - because this is placed after
+ // the "normal" rotting check, rotting attacks can be somewhat
+ // more painful on ghouls - reversing order would make rotting
+ // attacks somewhat less painful, but that seems wrong-headed {dlb}:
+ if (you.species == SP_GHOUL)
+ {
+ if (one_chance_in(400))
+ {
+ mpr("You feel your flesh rotting away.", MSGCH_WARN);
+ ouch(1, 0, KILLED_BY_ROTTING);
+ rot_hp(1);
+
+ if (you.rotting > 0)
+ you.rotting--;
+ }
+ }
+
+ dec_disease_player();
+
+ if (you.poison > 0)
+ {
+ if (random2(5) <= (you.poison - 1))
+ {
+ if (you.poison > 10 && random2(you.poison) >= 8)
+ {
+ ouch(random2(10) + 5, 0, KILLED_BY_POISON);
+ mpr("You feel extremely sick.", MSGCH_DANGER);
+ }
+ else if (you.poison > 5 && coinflip())
+ {
+ ouch((coinflip()? 3 : 2), 0, KILLED_BY_POISON);
+ mpr("You feel very sick.", MSGCH_WARN);
+ }
+ else
+ {
+ // the poison running through your veins.");
+ ouch(1, 0, KILLED_BY_POISON);
+ mpr("You feel sick.");
+ }
+
+ if ((you.hp == 1 && one_chance_in(3)) || one_chance_in(8))
+ reduce_poison_player(1);
+ }
+ }
+
+ if (you.deaths_door)
+ {
+ if (you.hp > allowed_deaths_door_hp())
+ {
+ mpr("Your life is in your own hands once again.", MSGCH_DURATION);
+ you.paralysis += 5 + random2(5);
+ confuse_player( 10 + random2(10) );
+ you.hp_max--;
+ deflate_hp(you.hp_max, false);
+ you.deaths_door = 0;
+ }
+ else
+ you.deaths_door--;
+
+ if (you.deaths_door == 10)
+ {
+ mpr("Your time is quickly running out!", MSGCH_DURATION);
+ you.deaths_door -= random2(6);
+ }
+ if (you.deaths_door == 1)
+ {
+ mpr("Your life is in your own hands again!", MSGCH_DURATION);
+ more();
+ }
+ }
+
+ const int food_use = player_hunger_rate();
+
+ if (food_use > 0 && you.hunger >= 40)
+ make_hungry( food_use, true );
+
+ // XXX: using an int tmp to fix the fact that hit_points_regeneration
+ // is only an unsigned char and is thus likely to overflow. -- bwr
+ int tmp = static_cast< int >( you.hit_points_regeneration );
+
+ if (you.hp < you.hp_max && !you.disease && !you.deaths_door)
+ tmp += player_regen();
+
+ while (tmp >= 100)
+ {
+ if (you.hp >= you.hp_max - 1
+ && you.running && you.run_x == 0 && you.run_y == 0)
+ {
+ you.running = 0;
+ }
+
+ inc_hp(1, false);
+ tmp -= 100;
+ }
+
+ ASSERT( tmp >= 0 && tmp < 100 );
+ you.hit_points_regeneration = static_cast< unsigned char >( tmp );
+
+ // XXX: Doing the same as the above, although overflow isn't an
+ // issue with magic point regeneration, yet. -- bwr
+ tmp = static_cast< int >( you.magic_points_regeneration );
+
+ if (you.magic_points < you.max_magic_points)
+ tmp += 7 + you.max_magic_points / 2;
+
+ while (tmp >= 100)
+ {
+ if (you.magic_points >= you.max_magic_points - 1
+ && you.running && you.run_x == 0 && you.run_y == 0)
+ {
+ you.running = 0;
+ }
+
+ inc_mp(1, false);
+ tmp -= 100;
+ }
+
+ ASSERT( tmp >= 0 && tmp < 100 );
+ you.magic_points_regeneration = static_cast< unsigned char >( tmp );
+
+ viewwindow(1, true);
+
+ handle_monsters();
+
+ ASSERT(you.time_taken >= 0);
+ // make sure we don't overflow
+ ASSERT(DBL_MAX - you.elapsed_time > you.time_taken);
+
+ you.elapsed_time += you.time_taken;
+
+ if (you.synch_time <= you.time_taken)
+ {
+ handle_time(200 + (you.time_taken - you.synch_time));
+ you.synch_time = 200;
+ }
+ else
+ {
+ you.synch_time -= you.time_taken;
+ }
+
+ manage_clouds();
+
+ if (you.fire_shield > 0)
+ manage_fire_shield();
+
+ // There used to be signs of intent to have statues as some sort
+ // of more complex state machine... I'm boiling them down to bare
+ // basics for now. -- bwr
+ if (Visible_Statue[ STATUE_SILVER ])
+ {
+ if ((!you.invis && one_chance_in(3)) || one_chance_in(5))
+ {
+ char wc[30];
+
+ weird_colours( random2(256), wc );
+ snprintf(info, INFO_SIZE, "The silver statue's eyes glow %s.", wc);
+ mpr( info, MSGCH_WARN );
+
+ create_monster( summon_any_demon((coinflip() ? DEMON_COMMON
+ : DEMON_LESSER)),
+ ENCH_ABJ_V, BEH_HOSTILE,
+ you.x_pos, you.y_pos,
+ MHITYOU, 250 );
+ }
+
+ Visible_Statue[ STATUE_SILVER ] = 0;
+ }
+
+ if (Visible_Statue[ STATUE_ORANGE_CRYSTAL ])
+ {
+ if ((!you.invis && coinflip()) || one_chance_in(4))
+ {
+ mpr("A hostile presence attacks your mind!", MSGCH_WARN);
+
+ miscast_effect( SPTYP_DIVINATION, random2(15), random2(150), 100,
+ "an orange crystal statue" );
+ }
+
+ Visible_Statue[ STATUE_ORANGE_CRYSTAL ] = 0;
+ }
+
+ // food death check:
+ if (you.is_undead != US_UNDEAD && you.hunger <= 500)
+ {
+ if (!you.paralysis && one_chance_in(40))
+ {
+ mpr("You lose consciousness!", MSGCH_FOOD);
+ you.paralysis += 5 + random2(8);
+
+ if (you.paralysis > 13)
+ you.paralysis = 13;
+ }
+
+ if (you.hunger <= 100)
+ {
+ mpr( "You have starved to death.", MSGCH_FOOD );
+ ouch( -9999, 0, KILLED_BY_STARVATION );
+ }
+ }
+
+ //jmf: added silence messages
+ its_quiet = silenced(you.x_pos, you.y_pos);
+
+ if (you.attribute[ATTR_WAS_SILENCED] != its_quiet)
+ {
+ if (its_quiet)
+ {
+ if (random2(30))
+ mpr("You are enveloped in profound silence.", MSGCH_WARN);
+ else
+ mpr("The dungeon seems quiet ... too quiet!", MSGCH_WARN);
+ }
+ else
+ {
+ mpr("Your hearing returns.", MSGCH_RECOVERY);
+ }
+
+ you.attribute[ATTR_WAS_SILENCED] = its_quiet;
+ }
+
+ viewwindow(1, false);
+
+ if (you.paralysis > 0 && any_messages())
+ more();
+
+ // place normal dungeon monsters, but not in player LOS
+ if (you.level_type == LEVEL_DUNGEON
+ && !player_in_branch( BRANCH_ECUMENICAL_TEMPLE )
+ && one_chance_in((you.char_direction == DIR_DESCENDING) ? 240 : 10))
+ {
+ int prox = (one_chance_in(10) ? PROX_NEAR_STAIRS
+ : PROX_AWAY_FROM_PLAYER);
+
+ // The rules change once the player has picked up the Orb...
+ if (you.char_direction == DIR_ASCENDING)
+ prox = (one_chance_in(10) ? PROX_CLOSE_TO_PLAYER : PROX_ANYWHERE);
+
+ mons_place( WANDERING_MONSTER, BEH_HOSTILE, MHITNOT, false,
+ 50, 50, LEVEL_DUNGEON, prox );
+ }
+
+ // place Abyss monsters.
+ if (you.level_type == LEVEL_ABYSS && one_chance_in(5))
+ {
+ mons_place( WANDERING_MONSTER, BEH_HOSTILE, MHITNOT, false,
+ 50, 50, LEVEL_ABYSS, PROX_ANYWHERE );
+ }
+
+ // place Pandemonium monsters
+ if (you.level_type == LEVEL_PANDEMONIUM && one_chance_in(50))
+ pandemonium_mons();
+
+ // No monsters in the Labyrinth, or Ecumenical Temple
+ return;
+}
+
+/*
+ Opens doors and handles some aspects of untrapping. If either move_x or
+ move_y are non-zero, the pair carries a specific direction for the door
+ to be opened (eg if you type ctrl - dir).
+ */
+static void open_door(char move_x, char move_y)
+{
+ struct dist door_move;
+ int dx, dy; // door x, door y
+
+ door_move.dx = move_x;
+ door_move.dy = move_y;
+
+ if (move_x || move_y)
+ {
+ // convenience
+ dx = you.x_pos + move_x;
+ dy = you.y_pos + move_y;
+
+ const int mon = mgrd[dx][dy];
+
+ if (mon != NON_MONSTER && !mons_has_ench( &menv[mon], ENCH_SUBMERGED ))
+ {
+ you_attack(mgrd[dx][dy], true);
+ you.turn_is_over = 1;
+
+ if (you.berserk_penalty != NO_BERSERK_PENALTY)
+ you.berserk_penalty = 0;
+
+ return;
+ }
+
+ if (grd[dx][dy] >= DNGN_TRAP_MECHANICAL && grd[dx][dy] <= DNGN_TRAP_III)
+ {
+ if (env.cgrid[dx][dy] != EMPTY_CLOUD)
+ {
+ mpr("You can't get to that trap right now.");
+ return;
+ }
+
+ disarm_trap(door_move);
+ return;
+ }
+
+ }
+ else
+ {
+ mpr("Which direction?", MSGCH_PROMPT);
+ direction( door_move, DIR_DIR );
+ if (!door_move.isValid)
+ return;
+
+ // convenience
+ dx = you.x_pos + door_move.dx;
+ dy = you.y_pos + door_move.dy;
+ }
+
+ if (grd[dx][dy] == DNGN_CLOSED_DOOR)
+ {
+ int skill = you.dex + (you.skills[SK_TRAPS_DOORS] + you.skills[SK_STEALTH]) / 2;
+
+ if (one_chance_in(skill) && !silenced(you.x_pos, you.y_pos))
+ {
+ mpr( "As you open the door, it creaks loudly!" );
+ noisy( 10, you.x_pos, you.y_pos );
+ }
+ else
+ {
+ mpr( player_is_levitating() ? "You reach down and open the door."
+ : "You open the door." );
+ }
+
+ grd[dx][dy] = DNGN_OPEN_DOOR;
+ you.turn_is_over = 1;
+ }
+ else
+ {
+ mpr("You swing at nothing.");
+ make_hungry(3, true);
+ you.turn_is_over = 1;
+ }
+} // end open_door()
+
+/*
+ Similar to open_door. Can you spot the difference?
+ */
+static void close_door(char door_x, char door_y)
+{
+ struct dist door_move;
+ int dx, dy; // door x, door y
+
+ door_move.dx = door_x;
+ door_move.dy = door_y;
+
+ if (!(door_x || door_y))
+ {
+ mpr("Which direction?", MSGCH_PROMPT);
+ direction( door_move, DIR_DIR );
+ if (!door_move.isValid)
+ return;
+ }
+
+ if (door_move.dx == 0 && door_move.dy == 0)
+ {
+ mpr("You can't close doors on yourself!");
+ return;
+ }
+
+ // convenience
+ dx = you.x_pos + door_move.dx;
+ dy = you.y_pos + door_move.dy;
+
+ if (grd[dx][dy] == DNGN_OPEN_DOOR)
+ {
+ if (mgrd[dx][dy] != NON_MONSTER)
+ {
+ // Need to make sure that turn_is_over = 1 if creature is invisible
+ mpr("There's a creature in the doorway!");
+ door_move.dx = 0;
+ door_move.dy = 0;
+ return;
+ }
+
+ if (igrd[dx][dy] != NON_ITEM)
+ {
+ mpr("There's something blocking the doorway.");
+ door_move.dx = 0;
+ door_move.dy = 0;
+ return;
+ }
+
+ int skill = you.dex + (you.skills[SK_TRAPS_DOORS] + you.skills[SK_STEALTH]) / 2;
+
+ if (one_chance_in(skill) && !silenced(you.x_pos, you.y_pos))
+ {
+ mpr("As you close the door, it creaks loudly!");
+ noisy( 10, you.x_pos, you.y_pos );
+ }
+ else
+ {
+ mpr( player_is_levitating() ? "You reach down and close the door."
+ : "You close the door." );
+ }
+
+ grd[dx][dy] = DNGN_CLOSED_DOOR;
+ you.turn_is_over = 1;
+ }
+ else
+ {
+ mpr("There isn't anything that you can close there!");
+ }
+} // end open_door()
+
+
+// initialise whole lot of stuff...
+// returns true if a new character
+static bool initialise(void)
+{
+ bool ret;
+
+ int i = 0, j = 0; // counter variables {dlb}
+
+ your_sign = '@';
+ your_colour = LIGHTGREY;
+
+ // system initialisation stuff:
+ textbackground(0);
+
+#ifdef DOS
+ directvideo = 1;
+#endif
+
+#ifdef USE_EMX
+ init_emx();
+#endif
+
+ srandom(time(NULL));
+ srand(time(NULL));
+ cf_setseed(); // required for stuff::coinflip()
+
+ mons_init(mcolour); // this needs to be way up top {dlb}
+ init_playerspells(); // this needs to be way up top {dlb}
+
+ clrscr();
+
+ // init item array:
+ for (i = 1; i < MAX_ITEMS; i++)
+ init_item( i );
+
+ // empty messaging string
+ strcpy(info, "");
+
+ for (i = 0; i < MAX_MONSTERS; i++)
+ {
+ menv[i].type = -1;
+ menv[i].speed_increment = 10;
+ menv[i].flags = 0;
+ menv[i].behaviour = BEH_SLEEP;
+
+ menv[i].foe = NON_MONSTER;
+ menv[i].attitude = ATT_HOSTILE;
+
+ for (j = 0; j < NUM_MON_ENCHANTS; j++)
+ menv[i].enchantment[j] = ENCH_NONE;
+
+ for (j = 0; j < NUM_MONSTER_SLOTS; j++)
+ menv[i].inv[j] = NON_ITEM;
+
+ menv[i].number = 0;
+ }
+
+ for (i = 0; i < GXM; i++)
+ {
+ for (j = 0; j < GYM; j++)
+ {
+ igrd[i][j] = NON_ITEM;
+ mgrd[i][j] = NON_MONSTER;
+ env.map[i][j] = 0;
+ }
+ }
+
+ for (i = 0; i < 50; i++)
+ {
+ you.unique_creatures[i] = 0;
+ you.unique_items[i] = UNIQ_NOT_EXISTS;
+ }
+
+ for (i = 0; i < NUM_STATUE_TYPES; i++)
+ Visible_Statue[i] = 0;
+
+ // initialize tag system before we try loading anything!
+ tag_init();
+
+ // sets up a new game:
+ bool newc = new_game();
+ ret = newc; // newc will be mangled later so we'll take a copy --bwr
+
+ if (!newc)
+ restore_game();
+
+ game_has_started = true;
+
+ calc_hp();
+ calc_mp();
+
+ load( 82, (newc ? LOAD_START_GAME : LOAD_RESTART_GAME), false, 0,
+ you.where_are_you );
+
+#if DEBUG_DIAGNOSTICS
+ // Debug compiles display a lot of "hidden" information, so we auto-wiz
+ you.wizard = true;
+#endif
+
+ init_properties();
+ burden_change();
+ make_hungry(0,true);
+
+ you.redraw_strength = 1;
+ you.redraw_intelligence = 1;
+ you.redraw_dexterity = 1;
+ you.redraw_armour_class = 1;
+ you.redraw_evasion = 1;
+ you.redraw_experience = 1;
+ you.redraw_gold = 1;
+ you.wield_change = true;
+
+ you.start_time = time( NULL ); // start timer on session
+
+ draw_border();
+ new_level();
+
+ // set vision radius to player's current vision
+ setLOSRadius( you.current_vision );
+ viewwindow(1, false); // This just puts the view up for the first turn.
+ item();
+
+ return (ret);
+}
+
+// An attempt to tone down berserk a little bit. -- bwross
+//
+// This function does the accounting for not attacking while berserk
+// This gives a triangluar number function for the additional penalty
+// Turn: 1 2 3 4 5 6 7 8
+// Penalty: 1 3 6 10 15 21 28 36
+//
+// Total penalty (including the standard one during upkeep is:
+// 2 5 9 14 20 27 35 44
+//
+static void do_berserk_no_combat_penalty(void)
+{
+ // Butchering/eating a corpse will maintain a blood rage.
+ const int delay = current_delay_action();
+ if (delay == DELAY_BUTCHER || delay == DELAY_EAT)
+ return;
+
+ if (you.berserk_penalty == NO_BERSERK_PENALTY)
+ return;
+
+ if (you.berserker)
+ {
+ you.berserk_penalty++;
+
+ switch (you.berserk_penalty)
+ {
+ case 2:
+ mpr("You feel a strong urge to attack something.", MSGCH_DURATION);
+ break;
+ case 4:
+ mpr("You feel your anger subside.", MSGCH_DURATION);
+ break;
+ case 6:
+ mpr("Your blood rage is quickly leaving you.", MSGCH_DURATION);
+ break;
+ }
+
+ // I do these three separately, because the might and
+ // haste counters can be different.
+ you.berserker -= you.berserk_penalty;
+ if (you.berserker < 1)
+ you.berserker = 1;
+
+ you.might -= you.berserk_penalty;
+ if (you.might < 1)
+ you.might = 1;
+
+ you.haste -= you.berserk_penalty;
+ if (you.haste < 1)
+ you.haste = 1;
+ }
+ return;
+} // end do_berserk_no_combat_penalty()
+
+
+// Called when the player moves by walking/running. Also calls
+// attack function and trap function etc when necessary.
+static void move_player(char move_x, char move_y)
+{
+ bool attacking = false;
+ bool moving = true; // used to prevent eventual movement (swap)
+
+ int i;
+ bool trap_known;
+
+ if (you.conf)
+ {
+ if (!one_chance_in(3))
+ {
+ move_x = random2(3) - 1;
+ move_y = random2(3) - 1;
+ }
+
+ const int new_targ_x = you.x_pos + move_x;
+ const int new_targ_y = you.y_pos + move_y;
+ const unsigned char new_targ_grid = grd[ new_targ_x ][ new_targ_y ];
+
+ if (new_targ_grid < MINMOVE)
+ {
+ you.turn_is_over = 1;
+ mpr("Ouch!");
+ return;
+ }
+
+ if (new_targ_grid == DNGN_LAVA
+ && you.duration[DUR_CONDENSATION_SHIELD] > 0)
+ {
+ mpr("Your icy shield dissipates!", MSGCH_DURATION);
+ you.duration[DUR_CONDENSATION_SHIELD] = 0;
+ you.redraw_armour_class = 1;
+ }
+
+ if ((new_targ_grid == DNGN_LAVA
+ || new_targ_grid == DNGN_DEEP_WATER
+ || new_targ_grid == DNGN_SHALLOW_WATER)
+ && !player_is_levitating())
+ {
+ if (you.species == SP_MERFOLK && new_targ_grid != DNGN_LAVA)
+ {
+ mpr("You stumble into the water and return to your normal form.");
+ merfolk_start_swimming();
+ }
+
+ if (new_targ_grid != DNGN_SHALLOW_WATER)
+ fall_into_a_pool( false, new_targ_grid );
+
+ you.turn_is_over = 1;
+ do_berserk_no_combat_penalty();
+ return;
+ }
+ } // end of if you.conf
+
+ if (you.running > 0 && you.running != 2 && check_stop_running())
+ {
+ you.running = 0;
+ move_x = 0;
+ move_y = 0;
+ you.turn_is_over = 0;
+ return;
+ }
+
+ const int targ_x = you.x_pos + move_x;
+ const int targ_y = you.y_pos + move_y;
+ const unsigned char old_grid = grd[ you.x_pos ][ you.y_pos ];
+ const unsigned char targ_grid = grd[ targ_x ][ targ_y ];
+ const unsigned char targ_monst = mgrd[ targ_x ][ targ_y ];
+
+ if (targ_monst != NON_MONSTER)
+ {
+ struct monsters *mon = &menv[targ_monst];
+
+ if (mons_has_ench( mon, ENCH_SUBMERGED ))
+ goto break_out;
+
+ // you can swap places with a friendly monster if you
+ // can see it and you're not confused
+ if (mons_friendly( mon ) && player_monster_visible( mon ) && !you.conf)
+ {
+ if (!swap_places( mon ))
+ moving = false;
+
+ goto break_out;
+ }
+
+ you_attack( targ_monst, true );
+ you.turn_is_over = 1;
+
+ // we don't want to create a penalty if there isn't
+ // supposed to be one
+ if (you.berserk_penalty != NO_BERSERK_PENALTY)
+ you.berserk_penalty = 0;
+
+ attacking = true;
+ }
+
+ break_out:
+ if (targ_grid == DNGN_LAVA && you.duration[DUR_CONDENSATION_SHIELD] > 0)
+ {
+ mpr("Your icy shield dissipates!", MSGCH_DURATION);
+ you.duration[DUR_CONDENSATION_SHIELD] = 0;
+ you.redraw_armour_class = 1;
+ }
+
+ // Handle dangerous tiles
+ if ((targ_grid == DNGN_LAVA
+ || targ_grid == DNGN_DEEP_WATER
+ || targ_grid == DNGN_SHALLOW_WATER)
+ && !attacking && !player_is_levitating() && moving)
+ {
+ // Merfold automatically enter deep water... every other case
+ // we ask for confirmation.
+ if (you.species == SP_MERFOLK && targ_grid != DNGN_LAVA)
+ {
+ // Only mention diving if we just entering the water.
+ if (!player_in_water())
+ {
+ mpr("You dive into the water and return to your normal form.");
+ merfolk_start_swimming();
+ }
+ }
+ else if (targ_grid != DNGN_SHALLOW_WATER)
+ {
+ bool enter = yesno("Do you really want to step there?", false);
+
+ if (enter)
+ {
+ fall_into_a_pool( false, targ_grid );
+ you.turn_is_over = 1;
+ do_berserk_no_combat_penalty();
+ return;
+ }
+ else
+ {
+ canned_msg(MSG_OK);
+ return;
+ }
+ }
+ }
+
+ if (!attacking && targ_grid >= MINMOVE && moving)
+ {
+ if (targ_grid == DNGN_UNDISCOVERED_TRAP
+ && random2(you.skills[SK_TRAPS_DOORS] + 1) > 3)
+ {
+ strcpy(info, "Wait a moment, ");
+ strcat(info, you.your_name);
+ strcat(info, "! Do you really want to step there?");
+ mpr(info, MSGCH_WARN);
+ more();
+ you.turn_is_over = 0;
+
+ i = trap_at_xy( targ_x, targ_y );
+ if (i != -1)
+ grd[ targ_x ][ targ_y ] = trap_category(env.trap[i].type);
+ return;
+ }
+
+ you.x_pos += move_x;
+ you.y_pos += move_y;
+
+ if (targ_grid == DNGN_SHALLOW_WATER && !player_is_levitating())
+ {
+ if (you.species != SP_MERFOLK)
+ {
+ if (one_chance_in(3) && !silenced(you.x_pos, you.y_pos))
+ {
+ mpr("Splash!");
+ noisy( 10, you.x_pos, you.y_pos );
+ }
+
+ you.time_taken *= 13 + random2(8);
+ you.time_taken /= 10;
+
+ if (old_grid != DNGN_SHALLOW_WATER)
+ {
+ mpr( "You enter the shallow water. "
+ "Moving in this stuff is going to be slow." );
+
+ if (you.invis)
+ mpr( "And don't expect to remain undetected." );
+ }
+ }
+ else if (old_grid != DNGN_SHALLOW_WATER
+ && old_grid != DNGN_DEEP_WATER)
+ {
+ mpr("You return to your normal form as you enter the water.");
+ merfolk_start_swimming();
+ }
+ }
+
+ move_x = 0;
+ move_y = 0;
+
+ you.time_taken *= player_movement_speed();
+ you.time_taken /= 10;
+
+ you.turn_is_over = 1;
+ item_check(0);
+
+ if (targ_grid >= DNGN_TRAP_MECHANICAL
+ && targ_grid <= DNGN_UNDISCOVERED_TRAP)
+ {
+ if (targ_grid == DNGN_UNDISCOVERED_TRAP)
+ {
+ i = trap_at_xy(you.x_pos, you.y_pos);
+ if (i != -1)
+ grd[ you.x_pos ][ you.y_pos ] = trap_category(env.trap[i].type);
+ trap_known = false;
+ }
+ else
+ {
+ trap_known = true;
+ }
+
+ i = trap_at_xy( you.x_pos, you.y_pos );
+ if (i != -1)
+ {
+ if (player_is_levitating()
+ && trap_category(env.trap[i].type) == DNGN_TRAP_MECHANICAL)
+ {
+ goto out_of_traps; // can fly over mechanical traps
+ }
+
+ handle_traps(env.trap[i].type, i, trap_known);
+ }
+ } // end of if another grd == trap
+ }
+
+ out_of_traps:
+ // BCR - Easy doors single move
+ if (targ_grid == DNGN_CLOSED_DOOR && Options.easy_open)
+ open_door(move_x, move_y);
+ else if (targ_grid <= MINMOVE)
+ {
+ you.running = 0;
+ move_x = 0;
+ move_y = 0;
+ you.turn_is_over = 0;
+ }
+
+ if (you.running == 2)
+ you.running = 1;
+
+ if (you.level_type == LEVEL_ABYSS
+ && (you.x_pos <= 15 || you.x_pos >= (GXM - 16)
+ || you.y_pos <= 15 || you.y_pos >= (GYM - 16)))
+ {
+ area_shift();
+ you.pet_target = MHITNOT;
+
+#if DEBUG_DIAGNOSTICS
+ mpr( "Shifting.", MSGCH_DIAGNOSTICS );
+ int igly = 0;
+ int ig2 = 0;
+
+ for (igly = 0; igly < MAX_ITEMS; igly++)
+ {
+ if (is_valid_item( mitm[igly] ))
+ ig2++;
+ }
+
+ snprintf( info, INFO_SIZE, "Number of items present: %d", ig2 );
+ mpr( info, MSGCH_DIAGNOSTICS );
+
+ ig2 = 0;
+ for (igly = 0; igly < MAX_MONSTERS; igly++)
+ {
+ if (menv[igly].type != -1)
+ ig2++;
+ }
+
+ snprintf( info, INFO_SIZE, "Number of monsters present: %d", ig2 );
+ mpr( info, MSGCH_DIAGNOSTICS );
+
+ snprintf( info, INFO_SIZE, "Number of clouds present: %d", env.cloud_no );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+ }
+
+ if (!attacking)
+ {
+ do_berserk_no_combat_penalty();
+ }
+} // end move_player()
diff --git a/trunk/source/acrawl.gdt b/trunk/source/acrawl.gdt
new file mode 100644
index 0000000000..3406830926
--- /dev/null
+++ b/trunk/source/acrawl.gdt
Binary files differ
diff --git a/trunk/source/acrawl.gpr b/trunk/source/acrawl.gpr
new file mode 100644
index 0000000000..321e91e8e3
--- /dev/null
+++ b/trunk/source/acrawl.gpr
Binary files differ
diff --git a/trunk/source/beam.cc b/trunk/source/beam.cc
new file mode 100644
index 0000000000..8745271286
--- /dev/null
+++ b/trunk/source/beam.cc
@@ -0,0 +1,4213 @@
+/*
+ * File: beam.cc
+ * Summary: Functions related to ranged attacks.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <7> 21mar2001 GDL Replaced all FP arithmetic with integer*100 math
+ * <6> 07jan2001 GDL complete rewrite.
+ * <5> 22July2000 GDL allowed 'dummy' missiles from monsters
+ * <4> 11/14/99 cdl evade beams with random40(ev) vice random2(ev)
+ * all armour now protects against shrapnel
+ * <3> 6/ 2/99 DML Added enums
+ * <2> 5/20/99 BWR Added refreshs for curses
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "beam.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef DOS
+#include <dos.h>
+#include <conio.h>
+#endif
+#if DEBUG_DIAGNOSTICS
+#include <stdio.h>
+#endif
+
+#include "externs.h"
+
+#include "cloud.h"
+#include "effects.h"
+#include "enum.h"
+#include "it_use2.h"
+#include "itemname.h"
+#include "items.h"
+#include "misc.h"
+#include "monplace.h"
+#include "monstuff.h"
+#include "mon-util.h"
+#include "mstuff2.h"
+#include "ouch.h"
+#include "player.h"
+#include "religion.h"
+#include "skills.h"
+#include "spells1.h"
+#include "spells3.h"
+#include "spells4.h"
+#include "stuff.h"
+#include "view.h"
+
+#define BEAM_STOP 1000 // all beams stopped by subtracting this
+ // from remaining range
+#define MON_RESIST 0 // monster resisted
+#define MON_UNAFFECTED 1 // monster unaffected
+#define MON_AFFECTED 2 // monster was unaffected
+
+extern FixedVector< char, NUM_STATUE_TYPES > Visible_Statue; // in acr.cc
+
+static int spreadx[] = { 0, 0, 1, -1 };
+static int spready[] = { -1, 1, 0, 0 };
+static int opdir[] = { 2, 1, 4, 3 };
+static FixedArray < bool, 19, 19 > explode_map;
+
+// helper functions (some of these, esp. affect(), should probably
+// be public):
+static void sticky_flame_monster( int mn, bool source, int hurt_final );
+static bool affectsWalls(struct bolt &beam);
+static int affect(struct bolt &beam, int x, int y);
+static bool isBouncy(struct bolt &beam);
+static void beam_drop_object( struct bolt &beam, item_def *item, int x, int y );
+static bool beam_term_on_target(struct bolt &beam);
+static void beam_explodes(struct bolt &beam, int x, int y);
+static int bounce(int &step1, int &step2, int w1, int w2, int &n1, int &n2,
+ int l1, int l2, int &t1, int &t2, bool topBlocked, bool sideBlocked);
+static bool fuzzyLine(int nx, int ny, int &tx, int &ty, int lx, int ly,
+ int stepx, int stepy, bool roundX, bool roundY);
+static int affect_wall(struct bolt &beam, int x, int y);
+static int affect_place_clouds(struct bolt &beam, int x, int y);
+static void affect_place_explosion_clouds(struct bolt &beam, int x, int y);
+static int affect_player(struct bolt &beam);
+static void affect_items(struct bolt &beam, int x, int y);
+static int affect_monster(struct bolt &beam, struct monsters *mon);
+static int affect_monster_enchantment(struct bolt &beam, struct monsters *mon);
+static int range_used_on_hit(struct bolt &beam);
+static void explosion1(struct bolt &pbolt);
+static void explosion_map(struct bolt &beam, int x, int y,
+ int count, int dir, int r);
+static void explosion_cell(struct bolt &beam, int x, int y, bool drawOnly);
+
+static void zappy(char z_type, int power, struct bolt &pbolt);
+
+void zapping(char ztype, int power, struct bolt &pbolt)
+{
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "zapping: power=%d", power );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ // GDL: note that rangeMax is set to 0, which means that max range is
+ // equal to range. This is OK, since rangeMax really only matters for
+ // stuff monsters throw/zap.
+
+ // all of the following might be changed by zappy():
+ pbolt.range = 8 + random2(5); // default for "0" beams (I think)
+ pbolt.rangeMax = 0;
+ pbolt.hit = 0; // default for "0" beams (I think)
+ pbolt.damage = dice_def( 1, 0 ); // default for "0" beams (I think)
+ pbolt.type = 0; // default for "0" beams
+ pbolt.flavour = BEAM_MAGIC; // default for "0" beams
+ pbolt.ench_power = power;
+ pbolt.obviousEffect = false;
+ pbolt.isBeam = false; // default for all beams.
+ pbolt.isTracer = false; // default for all player beams
+ pbolt.thrower = KILL_YOU_MISSILE; // missile from player
+ pbolt.aux_source = NULL; // additional source info, unused
+
+ // fill in the bolt structure
+ zappy( ztype, power, pbolt );
+
+ if (ztype == ZAP_LIGHTNING && !silenced(you.x_pos, you.y_pos))
+ // needs to check silenced at other location, too {dlb}
+ {
+ mpr("You hear a mighty clap of thunder!");
+ noisy( 25, you.x_pos, you.y_pos );
+ }
+
+ fire_beam(pbolt);
+
+ return;
+} // end zapping()
+
+dice_def calc_dice( int num_dice, int max_damage )
+{
+ dice_def ret( num_dice, 0 );
+
+ if (num_dice <= 1)
+ {
+ ret.num = 1;
+ ret.size = max_damage;
+ }
+ else if (max_damage <= num_dice)
+ {
+ ret.num = max_damage;
+ ret.size = 1;
+ }
+ else
+ {
+ // Divied the damage among the dice, and add one
+ // occasionally to make up for the fractions. -- bwr
+ ret.size = max_damage / num_dice;
+ ret.size += (random2( num_dice ) < max_damage % num_dice);
+ }
+
+ return (ret);
+}
+
+// *do not* call this function directly (duh - it's static), need to
+// see zapping() for default values not set within this function {dlb}
+static void zappy( char z_type, int power, struct bolt &pbolt )
+{
+ int temp_rand = 0; // probability determination {dlb}
+
+ // Note: The incoming power is not linear in the case of spellcasting.
+ // The power curve currently allows for the character to reasonably
+ // get up to a power level of about a 100, but more than that will
+ // be very hard (and the maximum is 200). The low level power caps
+ // provide the useful feature in that they allow for low level spells
+ // to have quick advancement, but don't cause them to obsolete the
+ // higher level spells. -- bwr
+ //
+ // I've added some example characters below to show how little
+ // people should be concerned about the power caps.
+ //
+ // The example characters are simplified to three stats:
+ //
+ // - Intelligence: This magifies power, its very useful.
+ //
+ // - Skills: This represents the character having Spellcasting
+ // and the average of the component skills at this level.
+ // Although, Spellcasting probably isn't quite as high as
+ // other spell skills for a lot of characters, note that it
+ // contributes much less to the total power (about 20%).
+ //
+ // - Enhancers: These are equipment that the player can use to
+ // apply additional magnifiers (x1.5) to power. There are
+ // also inhibitors that reduce power (/2.0), but we're not
+ // concerned about those here. Anyways, the character can
+ // currently have up to 3 levels (for x1.5, x2.25, x3.375).
+ // The lists below should help to point out the difficulty
+ // and cost of getting more than one level of enhancement.
+ //
+ // Here's a list of current magnifiers:
+ //
+ // - rings of fire/cold
+ // - staff of fire/cold/air/earth/poison/death/conjure/enchant/summon
+ // - staff of Olgreb (poison)
+ // - robe of the Archmagi (necro, conjure, enchant, summon)
+ // - Mummy intrinsic (+1 necromancy at level 13, +2 at level 26)
+ // - Necromutation (+1 to necromancy -- note: undead can't use this)
+ // - Ring of Fire (+1 to fire)
+ //
+ // The maximum enhancement, by school (but capped at 3):
+ //
+ // - Necromancy: 4 (Mummies), 3 (others)
+ // - Fire: 4
+ // - Cold: 3
+ // - Conjuration: 2
+ // - Enchantment: 2
+ // - Summoning: 2
+ // - Air: 1
+ // - Earth: 1
+ // - Poison: 1
+ // - Translocations, Transmigrations, Divinations intentionally 0
+
+ switch (z_type)
+ {
+ // level 1
+ //
+ // This cap is to keep these easy and very cheap spells from
+ // becoming too powerful.
+ //
+ // Example characters with about 25 power:
+ //
+ // - int 5, skills 20, 0 enhancers
+ // - int 5, skills 14, 1 enhancer
+ // - int 10, skills 10, 0 enhancers
+ // - int 10, skills 7, 1 enhancers
+ // - int 15, skills 7, 0 enhancers
+ // - int 20, skills 6, 0 enhancers
+ case ZAP_STRIKING:
+ case ZAP_MAGIC_DARTS:
+ case ZAP_STING:
+ case ZAP_ELECTRICITY:
+ case ZAP_FLAME_TONGUE:
+ case ZAP_SMALL_SANDBLAST:
+ case ZAP_DISRUPTION: // ench_power boosted below
+ case ZAP_PAIN: // ench_power boosted below
+ if (power > 25)
+ power = 25;
+ break;
+
+ // level 2/3
+ //
+ // The following examples should make it clear that in the
+ // early game this cap is only limiting to serious spellcasters
+ // (they could easily reach the 20-10-0 example).
+ //
+ // Example characters with about 50 power:
+ //
+ // - int 10, skills 20, 0 enhancers
+ // - int 10, skills 14, 1 enhancer
+ // - int 15, skills 14, 0 enhancers
+ // - int 15, skills 10, 1 enhancer
+ // - int 20, skills 10, 0 enhancers
+ // - int 20, skills 7, 1 enhancer
+ // - int 25, skills 8, 0 enhancers
+ case ZAP_SANDBLAST:
+ case ZAP_FLAME: // also ability (pow = lev * 2)
+ case ZAP_FROST: // also ability (pow = lev * 2)
+ case ZAP_STONE_ARROW:
+ if (power > 50)
+ power = 50;
+ break;
+
+ // Here are some examples that show that its fairly safe to assume
+ // that a high level character can easily have 75 power.
+ //
+ // Example characters with about 75 power:
+ //
+ // - int 10, skills 27, 1 enhancer
+ // - int 15, skills 27, 0 enhancers
+ // - int 15, skills 16, 1 enhancer
+ // - int 20, skills 20, 0 enhancers
+ // - int 20, skills 14, 1 enhancer
+ // - int 25, skills 16, 0 enhancers
+
+ // level 4
+ //
+ // The following examples should make it clear that this is the
+ // effective maximum power. Its not easy to get to 100 power,
+ // but 20-20-1 or 25-16-1 is certainly attainable by a high level
+ // spellcaster. As you can see from the examples at 150 and 200,
+ // getting much power beyond this is very difficult.
+ //
+ // Level 3 and 4 spells cannot be overpowered.
+ //
+ // Example characters with about 100 power:
+ //
+ // - int 10, skills 27, 2 enhancers
+ // - int 15, skills 27, 1 enhancer
+ // - int 20, skills 20, 1 enhancer
+ // - int 25, skills 24, 0 enhancers
+ // - int 25, skills 16, 1 enhancer
+ case ZAP_MYSTIC_BLAST:
+ case ZAP_STICKY_FLAME:
+ case ZAP_ICE_BOLT:
+ case ZAP_DISPEL_UNDEAD: // ench_power raised below
+ if (power > 100)
+ power = 100;
+ break;
+
+ // levels 5-7
+ //
+ // These spells used to be capped, but its very hard to raise
+ // power over 100, and these examples should show that.
+ // Only the twinkiest of characters are expected to get to 150.
+ //
+ // Example characters with about 150 power:
+ //
+ // - int 15, skills 27, 3 enhancers (actually, only 146)
+ // - int 20, skills 27, 2 enhancers (actually, only 137)
+ // - int 20, skills 21, 3 enhancers
+ // - int 25, skills 26, 2 enhancers
+ // - int 30, skills 21, 2 enhancers
+ // - int 40, skills 24, 1 enhancer
+ // - int 70, skills 20, 0 enhancers
+ case ZAP_FIRE:
+ case ZAP_COLD:
+ case ZAP_VENOM_BOLT:
+ case ZAP_MAGMA:
+ case ZAP_AGONY:
+ case ZAP_LIGHTNING: // also invoc * 6 or lev * 2 (abils)
+ case ZAP_NEGATIVE_ENERGY: // also ability (pow = lev * 6)
+ case ZAP_IRON_BOLT:
+ case ZAP_DISINTEGRATION:
+ case ZAP_FIREBALL:
+ case ZAP_ORB_OF_ELECTRICITY:
+ case ZAP_ORB_OF_FRAGMENTATION:
+ case ZAP_POISON_ARROW:
+ // if (power > 150)
+ // power = 150;
+ break;
+
+ // levels 8-9
+ //
+ // These spells are capped at 200 (which is the cap in calc_spell_power).
+ // As an example of how little of a cap that is, consider the fact
+ // that a 70-27-3 character has an uncapped power of 251. Characters
+ // are never expected to get to this cap.
+ //
+ // Example characters with about 200 power:
+ //
+ // - int 30, skills 27, 3 enhancers (actually, only 190)
+ // - int 40, skills 27, 2 enhancers (actually, only 181)
+ // - int 40, skills 23, 3 enhancers
+ // - int 70, skills 27, 0 enhancers (actually, only 164)
+ // - int 70, skills 27, 1 enhancers (actually, only 194)
+ // - int 70, skills 20, 2 enhancers
+ // - int 70, skills 13, 3 enhancers
+ case ZAP_CRYSTAL_SPEAR:
+ case ZAP_HELLFIRE:
+ case ZAP_ICE_STORM:
+ case ZAP_CLEANSING_FLAME:
+ // if (power > 200)
+ // power = 200;
+ break;
+
+ // unlimited power (needs a good reason)
+ case ZAP_BONE_SHARDS: // incoming power is modified for mass
+ case ZAP_BEAM_OF_ENERGY: // inaccuracy (only on staff, hardly hits)
+ break;
+
+ // natural/mutant breath/spit powers (power ~= characer level)
+ case ZAP_SPIT_POISON: // lev + mut * 5
+ case ZAP_BREATHE_FIRE: // lev + mut * 4 + 12 (if dragonform)
+ case ZAP_BREATHE_FROST: // lev
+ case ZAP_BREATHE_ACID: // lev (or invoc * 3 from minor destr)
+ case ZAP_BREATHE_POISON: // lev
+ case ZAP_BREATHE_POWER: // lev
+ case ZAP_BREATHE_STEAM: // lev
+ if (power > 50)
+ power = 50;
+ break;
+
+ // enchantments and other resistable effects
+ case ZAP_SLOWING:
+ case ZAP_HASTING:
+ case ZAP_PARALYSIS:
+ case ZAP_BACKLIGHT:
+ case ZAP_SLEEP:
+ case ZAP_CONFUSION:
+ case ZAP_INVISIBILITY:
+ case ZAP_ENSLAVEMENT:
+ case ZAP_TELEPORTATION:
+ case ZAP_DIGGING:
+ case ZAP_POLYMORPH_OTHER:
+ case ZAP_DEGENERATION:
+ case ZAP_BANISHMENT:
+ // This is the only power that matters. We magnify it apparently
+ // to get values that work better with magic resistance checks...
+ // those checks will scale down this value and max it out at 120.
+ pbolt.ench_power *= 3;
+ pbolt.ench_power /= 2;
+ break;
+
+ // anything else we cap to 100
+ default:
+ if (power > 100)
+ power = 100;
+ break;
+ }
+
+ // Note: I'm only displaying the top damage and such here, that's
+ // because it's really not been known before (since the above caps
+ // didn't exist), so they were all pretty much unlimited before.
+ // Also note, that the high end damage occurs at the cap, only
+ // players that are that powerful can get that damage... and
+ // although these numbers might seem small, you should remember
+ // that Dragons in this game are 60-90 hp monsters, and very
+ // few monsters have more than 100 hp (and that 1d5 damage is
+ // still capable of taking a good sized chunk (and possibly killing)
+ // any monster you're likely to meet in the first three levels). -- bwr
+
+ // Note: damage > 100 signals that "random2(damage - 100)" will be
+ // applied three times, which not only ups the damage but gives
+ // a more normal distribution.
+ switch (z_type)
+ {
+ case ZAP_STRIKING: // cap 25
+ strcpy(pbolt.beam_name, "force bolt");
+ pbolt.colour = BLACK;
+ pbolt.range = 8 + random2(5);
+ pbolt.damage = dice_def( 1, 5 ); // dam: 5
+ pbolt.hit = 8 + power / 10; // 25: 10
+ pbolt.type = SYM_SPACE;
+ pbolt.flavour = BEAM_MMISSILE; // unresistable
+ pbolt.obviousEffect = true;
+ break;
+
+ case ZAP_MAGIC_DARTS: // cap 25
+ strcpy(pbolt.beam_name, "magic dart");
+ pbolt.colour = LIGHTMAGENTA;
+ pbolt.range = random2(5) + 8;
+ pbolt.damage = dice_def( 1, 3 + power / 5 ); // 25: 1d8
+ pbolt.hit = 1500; // hits always
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_MMISSILE; // unresistable
+ pbolt.obviousEffect = true;
+ break;
+
+ case ZAP_STING: // cap 25
+ strcpy(pbolt.beam_name, "sting");
+ pbolt.colour = GREEN;
+ pbolt.range = 8 + random2(5);
+ pbolt.damage = dice_def( 1, 3 + power / 5 ); // 25: 1d8
+ pbolt.hit = 8 + power / 5; // 25: 13
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_POISON; // extra damage
+
+ pbolt.obviousEffect = true;
+ break;
+
+ case ZAP_ELECTRICITY: // cap 20
+ strcpy(pbolt.beam_name, "zap");
+ pbolt.colour = LIGHTCYAN;
+ pbolt.range = 6 + random2(8); // extended in beam
+ pbolt.damage = dice_def( 1, 3 + random2(power) / 2 ); // 25: 1d11
+ pbolt.hit = 8 + power / 7; // 25: 11
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_ELECTRICITY; // beams & reflects
+
+ pbolt.obviousEffect = true;
+ pbolt.isBeam = true;
+ break;
+
+ case ZAP_DISRUPTION: // cap 25
+ strcpy(pbolt.beam_name, "0");
+ pbolt.flavour = BEAM_DISINTEGRATION;
+ pbolt.range = 7 + random2(8);
+ pbolt.damage = dice_def( 1, 4 + power / 5 ); // 25: 1d9
+ pbolt.ench_power *= 3;
+ break;
+
+ case ZAP_PAIN: // cap 25
+ strcpy(pbolt.beam_name, "0");
+ pbolt.flavour = BEAM_PAIN;
+ pbolt.range = 7 + random2(8);
+ pbolt.damage = dice_def( 1, 4 + power / 5 ); // 25: 1d9
+ pbolt.ench_power *= 7;
+ pbolt.ench_power /= 2;
+ break;
+
+ case ZAP_FLAME_TONGUE: // cap 25
+ strcpy(pbolt.beam_name, "flame");
+ pbolt.colour = RED;
+
+ pbolt.range = 1 + random2(2) + random2(power) / 10;
+ if (pbolt.range > 4)
+ pbolt.range = 4;
+
+ pbolt.damage = dice_def( 1, 8 + power / 4 ); // 25: 1d14
+ pbolt.hit = 7 + power / 6; // 25: 11
+ pbolt.type = SYM_BOLT;
+ pbolt.flavour = BEAM_FIRE;
+
+ pbolt.obviousEffect = true;
+ break;
+
+ case ZAP_SMALL_SANDBLAST: // cap 25
+ strcpy(pbolt.beam_name, "blast of ");
+
+ temp_rand = random2(4);
+
+ strcat(pbolt.beam_name, (temp_rand == 0) ? "dust" :
+ (temp_rand == 1) ? "dirt" :
+ (temp_rand == 2) ? "grit" : "sand");
+
+ pbolt.colour = BROWN;
+ pbolt.range = (random2(power) > random2(30)) ? 2 : 1;
+ pbolt.damage = dice_def( 1, 8 + power / 4 ); // 25: 1d14
+ pbolt.hit = 8 + power / 5; // 25: 13
+ pbolt.type = SYM_BOLT;
+ pbolt.flavour = BEAM_FRAG; // extra AC resist
+
+ pbolt.obviousEffect = true;
+ break;
+
+ case ZAP_SANDBLAST: // cap 50
+ strcpy(pbolt.beam_name, coinflip() ? "blast of rock" : "rocky blast");
+ pbolt.colour = BROWN;
+
+ pbolt.range = 2 + random2(power) / 20;
+ if (pbolt.range > 4)
+ pbolt.range = 4;
+
+ pbolt.damage = dice_def( 2, 4 + power / 3 ); // 25: 2d12
+ pbolt.hit = 13 + power / 10; // 25: 15
+ pbolt.type = SYM_BOLT;
+ pbolt.flavour = BEAM_FRAG; // extra AC resist
+
+ pbolt.obviousEffect = true;
+ break;
+
+ case ZAP_BONE_SHARDS:
+ strcpy(pbolt.beam_name, "spray of bone shards");
+ pbolt.colour = LIGHTGREY;
+ pbolt.range = 7 + random2(10);
+
+ // Incoming power is highly dependant on mass (see spells3.cc).
+ // Basic function is power * 15 + mass... with the largest
+ // available mass (3000) we get a power of 4500 at a power
+ // level of 100 (for 3d20).
+ pbolt.damage = dice_def( 3, 2 + (power / 250) );
+ pbolt.hit = 8 + (power / 100); // max hit: 53
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_MAGIC; // unresisted
+
+ pbolt.obviousEffect = true;
+ pbolt.isBeam = true;
+ break;
+
+ case ZAP_FLAME: // cap 50
+ strcpy(pbolt.beam_name, "puff of flame");
+ pbolt.colour = RED;
+ pbolt.range = 8 + random2(5);
+ pbolt.damage = dice_def( 2, 4 + power / 10 ); // 25: 2d6 50: 2d9
+ pbolt.hit = 8 + power / 10; // 25: 10 50: 13
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_FIRE;
+
+ pbolt.obviousEffect = true;
+ break;
+
+ case ZAP_FROST: // cap 50
+ strcpy(pbolt.beam_name, "puff of frost");
+ pbolt.colour = WHITE;
+ pbolt.range = 8 + random2(5);
+ pbolt.damage = dice_def( 2, 4 + power / 10 ); // 25: 2d6 50: 2d9
+ pbolt.hit = 8 + power / 10; // 50: 10 50: 13
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_COLD;
+
+ pbolt.obviousEffect = true;
+ break;
+
+ case ZAP_STONE_ARROW: // cap 100
+ strcpy(pbolt.beam_name, "stone arrow");
+ pbolt.colour = LIGHTGREY;
+ pbolt.range = 8 + random2(5);
+ pbolt.damage = dice_def( 2, 4 + power / 8 ); // 25: 2d7 50: 2d10
+ pbolt.hit = 5 + power / 10; // 25: 6 50: 7
+ pbolt.type = SYM_MISSILE;
+ pbolt.flavour = BEAM_MMISSILE; // unresistable
+
+ pbolt.obviousEffect = true;
+ break;
+
+ case ZAP_STICKY_FLAME: // cap 100
+ strcpy(pbolt.beam_name, "sticky flame"); // extra damage
+ pbolt.colour = RED;
+ pbolt.range = 8 + random2(5);
+ pbolt.damage = dice_def( 2, 3 + power / 12 ); // 50: 2d7 100: 2d11
+ pbolt.hit = 11 + power / 10; // 50: 16 100: 21
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_FIRE;
+
+ pbolt.obviousEffect = true;
+ break;
+
+ case ZAP_MYSTIC_BLAST: // cap 100
+ strcpy(pbolt.beam_name, "orb of energy");
+ pbolt.colour = LIGHTMAGENTA;
+ pbolt.range = 8 + random2(5);
+ pbolt.damage = calc_dice( 2, 15 + (power * 2) / 5 );
+ pbolt.hit = 10 + power / 7; // 50: 17 100: 24
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_MMISSILE; // unresistable
+
+ pbolt.obviousEffect = true;
+ break;
+
+ case ZAP_ICE_BOLT: // cap 100
+ strcpy(pbolt.beam_name, "bolt of ice");
+ pbolt.colour = WHITE;
+ pbolt.range = 8 + random2(5);
+ pbolt.damage = calc_dice( 3, 10 + power / 2 );
+ pbolt.hit = 9 + power / 12; // 50: 13 100: 17
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_ICE; // half resistable
+ break;
+
+ case ZAP_DISPEL_UNDEAD: // cap 100
+ strcpy(pbolt.beam_name, "0");
+ pbolt.flavour = BEAM_DISPEL_UNDEAD;
+ pbolt.range = 7 + random2(8);
+ pbolt.damage = calc_dice( 3, 20 + (power * 3) / 4 );
+ pbolt.ench_power *= 3;
+ pbolt.ench_power /= 2;
+ break;
+
+ case ZAP_MAGMA: // cap 150
+ strcpy(pbolt.beam_name, "bolt of magma");
+ pbolt.colour = RED;
+ pbolt.range = 5 + random2(4);
+ pbolt.damage = calc_dice( 4, 10 + (power * 3) / 5 );
+ pbolt.hit = 8 + power / 25; // 50: 10 100: 14
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_LAVA;
+
+ pbolt.obviousEffect = true;
+ pbolt.isBeam = true;
+ break;
+
+ case ZAP_FIRE: // cap 150
+ strcpy(pbolt.beam_name, "bolt of fire");
+ pbolt.colour = RED;
+ pbolt.range = 7 + random2(10);
+ pbolt.damage = calc_dice( 6, 20 + (power * 3) / 4 );
+ pbolt.hit = 10 + power / 25; // 50: 12 100: 14
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_FIRE;
+
+ pbolt.obviousEffect = true;
+ pbolt.isBeam = true;
+ break;
+
+ case ZAP_COLD: // cap 150
+ strcpy(pbolt.beam_name, "bolt of cold");
+ pbolt.colour = WHITE;
+ pbolt.range = 7 + random2(10);
+ pbolt.damage = calc_dice( 6, 20 + (power * 3) / 4 );
+ pbolt.hit = 10 + power / 25; // 50: 12 100: 14
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_COLD;
+
+ pbolt.obviousEffect = true;
+ pbolt.isBeam = true;
+ break;
+
+ case ZAP_VENOM_BOLT: // cap 150
+ strcpy(pbolt.beam_name, "bolt of poison");
+ pbolt.colour = LIGHTGREEN;
+ pbolt.range = 8 + random2(10);
+ pbolt.damage = calc_dice( 4, 15 + power / 2 );
+ pbolt.hit = 8 + power / 20; // 50: 10 100: 13
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_POISON; // extra damage
+
+ pbolt.obviousEffect = true;
+ pbolt.isBeam = true;
+ break;
+
+ case ZAP_NEGATIVE_ENERGY: // cap 150
+ strcpy(pbolt.beam_name, "bolt of negative energy");
+ pbolt.colour = DARKGREY;
+ pbolt.range = 7 + random2(10);
+ pbolt.damage = calc_dice( 4, 15 + (power * 3) / 5 );
+ pbolt.hit = 8 + power / 20; // 50: 10 100: 13
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_NEG; // drains levels
+
+ pbolt.obviousEffect = true;
+ pbolt.isBeam = true;
+ break;
+
+ case ZAP_IRON_BOLT: // cap 150
+ strcpy(pbolt.beam_name, "iron bolt");
+ pbolt.colour = LIGHTCYAN;
+ pbolt.range = 5 + random2(5);
+ pbolt.damage = calc_dice( 9, 15 + (power * 3) / 4 );
+ pbolt.hit = 7 + power / 15; // 50: 10 100: 13
+ pbolt.type = SYM_MISSILE;
+ pbolt.flavour = BEAM_MMISSILE; // unresistable
+ pbolt.obviousEffect = true;
+ break;
+
+ case ZAP_POISON_ARROW: // cap 150
+ strcpy(pbolt.beam_name, "poison arrow");
+ pbolt.colour = LIGHTGREEN;
+ pbolt.range = 8 + random2(5);
+ pbolt.damage = calc_dice( 4, 15 + power );
+ pbolt.hit = 5 + power / 10; // 50: 10 100: 15
+ pbolt.type = SYM_MISSILE;
+ pbolt.flavour = BEAM_POISON_ARROW; // extra damage
+ pbolt.obviousEffect = true;
+ break;
+
+
+ case ZAP_DISINTEGRATION: // cap 150
+ strcpy(pbolt.beam_name, "0");
+ pbolt.flavour = BEAM_DISINTEGRATION;
+ pbolt.range = 7 + random2(8);
+ pbolt.damage = calc_dice( 3, 15 + (power * 3) / 4 );
+ pbolt.ench_power *= 5;
+ pbolt.ench_power /= 2;
+ pbolt.isBeam = true;
+ break;
+
+ case ZAP_LIGHTNING: // cap 150
+ // also for breath (at pow = lev * 2; max dam: 33)
+ strcpy(pbolt.beam_name, "bolt of lightning");
+ pbolt.colour = LIGHTCYAN;
+ pbolt.range = 8 + random2(10); // extended in beam
+ pbolt.damage = calc_dice( 1, 10 + (power * 3) / 5 );
+ pbolt.hit = 7 + random2(power) / 20; // 50: 7-9 100: 7-12
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_ELECTRICITY; // beams & reflects
+
+ pbolt.obviousEffect = true;
+ pbolt.isBeam = true;
+ break;
+
+ case ZAP_FIREBALL: // cap 150
+ strcpy(pbolt.beam_name, "fireball");
+ pbolt.colour = RED;
+ pbolt.range = 8 + random2(5);
+ pbolt.damage = calc_dice( 3, 10 + power / 2 );
+ pbolt.hit = 40; // hit: 40
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_EXPLOSION; // fire
+ break;
+
+ case ZAP_ORB_OF_ELECTRICITY: // cap 150
+ strcpy(pbolt.beam_name, "orb of electricity");
+ pbolt.colour = LIGHTBLUE;
+ pbolt.range = 9 + random2(12);
+ pbolt.damage = calc_dice( 1, 15 + (power * 4) / 5 );
+ pbolt.damage.num = 0; // only does explosion damage
+ pbolt.hit = 40; // hit: 40
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_ELECTRICITY;
+ break;
+
+ case ZAP_ORB_OF_FRAGMENTATION: // cap 150
+ strcpy(pbolt.beam_name, "metal orb");
+ pbolt.colour = CYAN;
+ pbolt.range = 9 + random2(7);
+ pbolt.damage = calc_dice( 3, 30 + (power * 3) / 4 );
+ pbolt.hit = 20; // hit: 20
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_FRAG; // extra AC resist
+ break;
+
+ case ZAP_CLEANSING_FLAME: // cap 200
+ strcpy(pbolt.beam_name, "golden flame");
+ pbolt.colour = YELLOW;
+ pbolt.range = 7 + random2(10);
+ pbolt.damage = calc_dice( 6, 30 + power );
+ pbolt.hit = 20; // hit: 20
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_HOLY;
+
+ pbolt.obviousEffect = true;
+ pbolt.isBeam = true;
+ break;
+
+ case ZAP_CRYSTAL_SPEAR: // cap 200
+ strcpy(pbolt.beam_name, "crystal spear");
+ pbolt.colour = WHITE;
+ pbolt.range = 7 + random2(10);
+ pbolt.damage = calc_dice( 12, 30 + (power * 4) / 3 );
+ pbolt.hit = 10 + power / 15; // 50: 13 100: 16
+ pbolt.type = SYM_MISSILE;
+ pbolt.flavour = BEAM_MMISSILE; // unresistable
+
+ pbolt.obviousEffect = true;
+ break;
+
+ case ZAP_HELLFIRE: // cap 200
+ strcpy(pbolt.beam_name, "hellfire");
+ pbolt.colour = RED;
+ pbolt.range = 7 + random2(10);
+ pbolt.damage = calc_dice( 3, 10 + (power * 3) / 4 );
+ pbolt.hit = 20 + power / 10; // 50: 25 100: 30
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_EXPLOSION;
+
+ pbolt.obviousEffect = true;
+ pbolt.isBeam = true;
+ break;
+
+ case ZAP_ICE_STORM: // cap 200
+ strcpy(pbolt.beam_name, "great blast of cold");
+ pbolt.colour = BLUE;
+ pbolt.range = 9 + random2(5);
+ pbolt.damage = calc_dice( 6, 15 + power );
+ pbolt.damage.num = 0; // only does explosion damage
+ pbolt.hit = 20 + power / 10; // 50: 25 100: 30
+ pbolt.ench_power = power; // used for radius
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_ICE; // half resisted
+ break;
+
+ case ZAP_BEAM_OF_ENERGY: // bolt of innacuracy
+ strcpy(pbolt.beam_name, "narrow beam of energy");
+ pbolt.colour = YELLOW;
+ pbolt.range = 7 + random2(10);
+ pbolt.damage = calc_dice( 12, 40 + (power * 3) / 2 );
+ pbolt.hit = 2; // hit: 2 (very hard)
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_ENERGY; // unresisted
+
+ pbolt.obviousEffect = true;
+ pbolt.isBeam = true;
+ break;
+
+ case ZAP_SPIT_POISON: // cap 50
+ // max pow = lev + mut * 5 = 42
+ strcpy(pbolt.beam_name, "splash of poison");
+ pbolt.colour = GREEN;
+
+ pbolt.range = 3 + random2( 1 + power / 2 );
+ if (pbolt.range > 9)
+ pbolt.range = 9;
+
+ pbolt.damage = dice_def( 1, 4 + power / 2 ); // max dam: 25
+ pbolt.hit = 5 + random2( 1 + power / 3 ); // max hit: 19
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_POISON;
+ pbolt.obviousEffect = true;
+ break;
+
+ case ZAP_BREATHE_FIRE: // cap 50
+ // max pow = lev + mut * 4 + 12 = 51 (capped to 50)
+ strcpy(pbolt.beam_name, "fiery breath");
+ pbolt.colour = RED;
+
+ pbolt.range = 3 + random2( 1 + power / 2 );
+ if (pbolt.range > 9)
+ pbolt.range = 9;
+
+ pbolt.damage = dice_def( 3, 4 + power / 3 ); // max dam: 60
+ pbolt.hit = 8 + random2( 1 + power / 3 ); // max hit: 25
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_FIRE;
+
+ pbolt.obviousEffect = true;
+ pbolt.isBeam = true;
+ break;
+
+ case ZAP_BREATHE_FROST: // cap 50
+ // max power = lev = 27
+ strcpy(pbolt.beam_name, "freezing breath");
+ pbolt.colour = WHITE;
+
+ pbolt.range = 3 + random2( 1 + power / 2 );
+ if (pbolt.range > 9)
+ pbolt.range = 9;
+
+ pbolt.damage = dice_def( 3, 4 + power / 3 ); // max dam: 39
+ pbolt.hit = 8 + random2( 1 + power / 3 );
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_COLD;
+
+ pbolt.obviousEffect = true;
+ pbolt.isBeam = true;
+ break;
+
+ case ZAP_BREATHE_ACID: // cap 50
+ // max power = lev for ability, 50 for minor destruction (max dam: 57)
+ strcpy(pbolt.beam_name, "acid");
+ pbolt.colour = YELLOW;
+
+ pbolt.range = 3 + random2( 1 + power / 2 );
+ if (pbolt.range > 9)
+ pbolt.range = 9;
+
+ pbolt.damage = dice_def( 3, 3 + power / 3 ); // max dam: 36
+ pbolt.hit = 5 + random2( 1 + power / 3 );
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_ACID;
+
+ pbolt.obviousEffect = true;
+ pbolt.isBeam = true;
+ break;
+
+ case ZAP_BREATHE_POISON: // leaves clouds of gas // cap 50
+ // max power = lev = 27
+ strcpy(pbolt.beam_name, "poison gas");
+ pbolt.colour = GREEN;
+
+ pbolt.range = 3 + random2( 1 + power / 2 );
+ if (pbolt.range > 9)
+ pbolt.range = 9;
+
+ pbolt.damage = dice_def( 3, 2 + power / 6 ); // max dam: 18
+ pbolt.hit = 6 + random2( 1 + power / 3 );
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_POISON;
+
+ pbolt.obviousEffect = true;
+ pbolt.isBeam = true;
+ break;
+
+ case ZAP_BREATHE_POWER: // cap 50
+ strcpy(pbolt.beam_name, "bolt of energy");
+ // max power = lev = 27
+
+ pbolt.colour = BLUE;
+ if (random2(power) >= 8)
+ pbolt.colour = LIGHTBLUE;
+ if (random2(power) >= 12)
+ pbolt.colour = MAGENTA;
+ if (random2(power) >= 17)
+ pbolt.colour = LIGHTMAGENTA;
+
+ pbolt.range = 6 + random2( 1 + power / 2 );
+ if (pbolt.range > 9)
+ pbolt.range = 9;
+
+ pbolt.damage = dice_def( 3, 3 + power / 3 ); // max dam: 36
+ pbolt.hit = 5 + random2( 1 + power / 3 );
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_MMISSILE; // unresistable
+
+ pbolt.obviousEffect = true;
+ pbolt.isBeam = true;
+ break;
+
+ case ZAP_BREATHE_STEAM: // cap 50
+ // max power = lev = 27
+ strcpy(pbolt.beam_name, "ball of steam");
+ pbolt.colour = LIGHTGREY;
+
+ pbolt.range = 6 + random2(5);
+ if (pbolt.range > 9)
+ pbolt.range = 9;
+
+ pbolt.damage = dice_def( 3, 4 + power / 5 ); // max dam: 27
+ pbolt.hit = 10 + random2( 1 + power / 5 );
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_FIRE;
+
+ pbolt.obviousEffect = true;
+ pbolt.isBeam = true;
+ break;
+
+ case ZAP_SLOWING:
+ strcpy(pbolt.beam_name, "0");
+ pbolt.flavour = BEAM_SLOW;
+ // pbolt.isBeam = true;
+ break;
+
+ case ZAP_HASTING:
+ strcpy(pbolt.beam_name, "0");
+ pbolt.flavour = BEAM_HASTE;
+ // pbolt.isBeam = true;
+ break;
+
+ case ZAP_PARALYSIS:
+ strcpy(pbolt.beam_name, "0");
+ pbolt.flavour = BEAM_PARALYSIS;
+ // pbolt.isBeam = true;
+ break;
+
+ case ZAP_CONFUSION:
+ strcpy(pbolt.beam_name, "0");
+ pbolt.flavour = BEAM_CONFUSION;
+ // pbolt.isBeam = true;
+ break;
+
+ case ZAP_INVISIBILITY:
+ strcpy(pbolt.beam_name, "0");
+ pbolt.flavour = BEAM_INVISIBILITY;
+ // pbolt.isBeam = true;
+ break;
+
+ case ZAP_HEALING:
+ strcpy(pbolt.beam_name, "0");
+ pbolt.flavour = BEAM_HEALING;
+ pbolt.damage = dice_def( 1, 7 + power / 3 );
+ // pbolt.isBeam = true;
+ break;
+
+ case ZAP_DIGGING:
+ strcpy(pbolt.beam_name, "0");
+ pbolt.flavour = BEAM_DIGGING;
+ // not ordinary "0" beam range {dlb}
+ pbolt.range = 3 + random2( power / 5 ) + random2(5);
+ pbolt.isBeam = true;
+ break;
+
+ case ZAP_TELEPORTATION:
+ strcpy(pbolt.beam_name, "0");
+ pbolt.flavour = BEAM_TELEPORT;
+ pbolt.range = 9 + random2(5);
+ // pbolt.isBeam = true;
+ break;
+
+ case ZAP_POLYMORPH_OTHER:
+ strcpy(pbolt.beam_name, "0");
+ pbolt.flavour = BEAM_POLYMORPH;
+ pbolt.range = 9 + random2(5);
+ // pbolt.isBeam = true;
+ break;
+
+ case ZAP_ENSLAVEMENT:
+ strcpy(pbolt.beam_name, "0");
+ pbolt.flavour = BEAM_CHARM;
+ pbolt.range = 7 + random2(5);
+ // pbolt.isBeam = true;
+ break;
+
+ case ZAP_BANISHMENT:
+ strcpy(pbolt.beam_name, "0");
+ pbolt.flavour = BEAM_BANISH;
+ pbolt.range = 7 + random2(5);
+ // pbolt.isBeam = true;
+ break;
+
+ case ZAP_DEGENERATION:
+ strcpy(pbolt.beam_name, "0");
+ pbolt.flavour = BEAM_DEGENERATE;
+ pbolt.range = 7 + random2(5);
+ // pbolt.isBeam = true;
+ break;
+
+ case ZAP_ENSLAVE_UNDEAD:
+ strcpy(pbolt.beam_name, "0");
+ pbolt.flavour = BEAM_ENSLAVE_UNDEAD;
+ pbolt.range = 7 + random2(5);
+ // pbolt.isBeam = true;
+ break;
+
+ case ZAP_AGONY:
+ strcpy(pbolt.beam_name, "0agony");
+ pbolt.flavour = BEAM_PAIN;
+ pbolt.range = 7 + random2(8);
+ pbolt.ench_power *= 5;
+ // pbolt.isBeam = true;
+ break;
+
+ case ZAP_CONTROL_DEMON:
+ strcpy(pbolt.beam_name, "0");
+ pbolt.flavour = BEAM_ENSLAVE_DEMON;
+ pbolt.range = 7 + random2(5);
+ pbolt.ench_power *= 3;
+ pbolt.ench_power /= 2;
+ // pbolt.isBeam = true;
+ break;
+
+ case ZAP_SLEEP: //jmf: added
+ strcpy(pbolt.beam_name, "0");
+ pbolt.flavour = BEAM_SLEEP;
+ pbolt.range = 7 + random2(5);
+ // pbolt.isBeam = true;
+ break;
+
+ case ZAP_BACKLIGHT: //jmf: added
+ strcpy(pbolt.beam_name, "0");
+ pbolt.flavour = BEAM_BACKLIGHT;
+ pbolt.colour = BLUE;
+ pbolt.range = 7 + random2(5);
+ // pbolt.isBeam = true;
+ break;
+
+ case ZAP_DEBUGGING_RAY:
+ strcpy( pbolt.beam_name, "debugging ray" );
+ pbolt.colour = random_colour();
+ pbolt.range = 7 + random2(10);
+ pbolt.damage = dice_def( 1500, 1 ); // dam: 1500
+ pbolt.hit = 1500; // hit: 1500
+ pbolt.type = SYM_DEBUG;
+ pbolt.flavour = BEAM_MMISSILE; // unresistable
+
+ pbolt.obviousEffect = true;
+ break;
+
+ default:
+ strcpy(pbolt.beam_name, "buggy beam");
+ pbolt.colour = random_colour();
+ pbolt.range = 7 + random2(10);
+ pbolt.damage = dice_def( 1, 0 );
+ pbolt.hit = 60;
+ pbolt.type = SYM_DEBUG;
+ pbolt.flavour = BEAM_MMISSILE; // unresistable
+
+ pbolt.obviousEffect = true;
+ break;
+ } // end of switch
+} // end zappy()
+
+/* NEW (GDL):
+ * Now handles all beamed/thrown items and spells, tracers, and their effects.
+ * item is used for items actually thrown/launched
+ *
+ * if item is NULL, there is no physical object being thrown that could
+ * land on the ground.
+ */
+
+
+/*
+ * Beam pseudo code:
+ *
+ * 1. Calculate stepx and stepy - algorithms depend on finding a step axis
+ * which results in a line of rise 1 or less (ie 45 degrees or less)
+ * 2. Calculate range. Tracers always have max range, otherwise the beam
+ * will have somewhere between range and rangeMax
+ * 3. Loop tracing out the line:
+ * 3a. Check for walls and wall affecting beams
+ * 3b. If no valid move is found, try a fuzzy move
+ * 3c. If no valid move is yet found, try bouncing
+ * 3d. If no valid move or bounce is found, break
+ * 4. Check for beam termination on target
+ * 5. Affect the cell which the beam just moved into -> affect()
+ * 6. Decrease remaining range appropriately
+ * 7. Check for early out due to aimedAtFeet
+ * 8. Draw the beam
+ * 9. Drop an object where the beam 'landed'
+ *10. Beams explode where the beam 'landed'
+ *11. If no message generated yet, send "nothing happens" (enchantments only)
+ *
+ */
+
+
+void fire_beam( struct bolt &pbolt, item_def *item )
+{
+ int dx, dy; // total delta between source & target
+ int lx, ly; // last affected x,y
+ int stepx, stepy; // x,y increment - FP
+ int wx, wy; // 'working' x,y - FP
+ bool beamTerminate; // has beam been 'stopped' by something?
+ int nx, ny; // test(new) x,y - FP
+ int tx, ty; // test(new) x,y - integer
+ bool roundX, roundY; // which to round?
+ int rangeRemaining;
+ bool fuzzyOK; // fuzzification resulted in OK move
+ bool sideBlocked, topBlocked, random_beam;
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "%s%s (%d,%d) to (%d,%d): ty=%d col=%d flav=%d hit=%d dam=%dd%d",
+ (pbolt.isBeam) ? "beam" : "missile",
+ (pbolt.isTracer) ? " tracer" : "",
+ pbolt.source_x, pbolt.source_y,
+ pbolt.target_x, pbolt.target_y,
+ pbolt.type, pbolt.colour, pbolt.flavour,
+ pbolt.hit, pbolt.damage.num, pbolt.damage.size );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ // init
+ pbolt.aimedAtFeet = false;
+ pbolt.msgGenerated = false;
+ pbolt.isExplosion = false;
+ roundY = false;
+ roundX = false;
+
+ // first, calculate beam step
+ dx = pbolt.target_x - pbolt.source_x;
+ dy = pbolt.target_y - pbolt.source_y;
+
+ // check for aim at feet
+ if (dx == 0 && dy == 0)
+ {
+ pbolt.aimedAtFeet = true;
+ stepx = 0;
+ stepy = 0;
+ tx = pbolt.source_x;
+ ty = pbolt.source_y;
+ }
+ else
+ {
+ if (abs(dx) >= abs(dy))
+ {
+ stepx = (dx > 0) ? 100 : -100;
+ stepy = 100 * dy / (abs(dx));
+ roundY = true;
+ }
+ else
+ {
+ stepy = (dy > 0) ? 100 : -100;
+ stepx = 100 * dx / (abs(dy));
+ roundX = true;
+ }
+ }
+
+ // give chance for beam to affect one cell even if aimedAtFeet.
+ beamTerminate = false;
+ // setup working coords
+ lx = pbolt.source_x;
+ wx = 100 * lx;
+ ly = pbolt.source_y;
+ wy = 100 * ly;
+ // setup range
+ rangeRemaining = pbolt.range;
+ if (pbolt.rangeMax > pbolt.range)
+ {
+ if (pbolt.isTracer)
+ rangeRemaining = pbolt.rangeMax;
+ else
+ rangeRemaining += random2((pbolt.rangeMax - pbolt.range) + 1);
+ }
+
+ // before we start drawing the beam, turn buffering off
+#ifdef WIN32CONSOLE
+ bool oldValue = true;
+ if (!pbolt.isTracer)
+ oldValue = setBuffering(false);
+#endif
+
+ // cannot use source_x, source_y, target_x, target_y during
+ // step algorithm due to bouncing.
+
+ // now, one step at a time, try to move towards target.
+ while(!beamTerminate)
+ {
+ nx = wx + stepx;
+ ny = wy + stepy;
+
+ if (roundY)
+ {
+ tx = nx / 100;
+ ty = (ny + 50) / 100;
+ }
+ if (roundX)
+ {
+ ty = ny / 100;
+ tx = (nx + 50) / 100;
+ }
+
+ // check that tx, ty are valid. If not, set to last
+ // x,y and break.
+ if (tx < 0 || tx >= GXM || ty < 0 || ty >= GYM)
+ {
+ tx = lx;
+ ty = ly;
+ break;
+ }
+
+ // see if tx, ty is blocked by something
+ if (grd[tx][ty] < MINMOVE)
+ {
+ // first, check to see if this beam affects walls.
+ if (affectsWalls(pbolt))
+ {
+ // should we ever get a tracer with a wall-affecting
+ // beam (possible I suppose), we'll quit tracing now.
+ if (!pbolt.isTracer)
+ rangeRemaining -= affect(pbolt, tx, ty);
+
+ // if it's still a wall, quit.
+ if (grd[tx][ty] < MINMOVE)
+ {
+ break; // breaks from line tracing
+ }
+ }
+ else
+ {
+ // BEGIN fuzzy line algorithm
+ fuzzyOK = fuzzyLine(nx,ny,tx,ty,lx,ly,stepx,stepy,roundX,roundY);
+ if (!fuzzyOK)
+ {
+ // BEGIN bounce case
+ if (!isBouncy(pbolt))
+ {
+ tx = lx;
+ ty = ly;
+ break; // breaks from line tracing
+ }
+
+ sideBlocked = false;
+ topBlocked = false;
+ // BOUNCE -- guaranteed to return reasonable tx, ty.
+ // if it doesn't, we'll quit in the next if stmt anyway.
+ if (roundY)
+ {
+ if ( grd[lx + stepx / 100][ly] < MINMOVE)
+ sideBlocked = true;
+
+ if (dy != 0)
+ {
+ if ( grd[lx][ly + (stepy>0?1:-1)] < MINMOVE)
+ topBlocked = true;
+ }
+
+ rangeRemaining -= bounce(stepx, stepy, wx, wy, nx, ny,
+ lx, ly, tx, ty, topBlocked, sideBlocked);
+ }
+ else
+ {
+ if ( grd[lx][ly + stepy / 100] < MINMOVE)
+ sideBlocked = true;
+
+ if (dx != 0)
+ {
+ if ( grd[lx + (stepx>0?1:-1)][ly] < MINMOVE)
+ topBlocked = true;
+ }
+
+ rangeRemaining -= bounce(stepy, stepx, wy, wx, ny, nx,
+ ly, lx, ty, tx, topBlocked, sideBlocked);
+ }
+ // END bounce case - range check
+ if (rangeRemaining < 1)
+ {
+ tx = lx;
+ ty = ly;
+ break;
+ }
+ }
+ } // end else - beam doesn't affect walls
+ } // endif - is tx, ty wall?
+
+ // at this point, if grd[tx][ty] is still a wall, we
+ // couldn't find any path: bouncy, fuzzy, or not - so break.
+ if (grd[tx][ty] < MINMOVE)
+ {
+ tx = lx;
+ ty = ly;
+ break;
+ }
+
+ // check for "target termination"
+ // occurs when beam can be targetted at empty
+ // cell (e.g. a mage wants an explosion to happen
+ // between two monsters)
+
+ // in this case, don't affect the cell - players
+ // /monsters have no chance to dodge or block such
+ // a beam, and we want to avoid silly messages.
+ if (tx == pbolt.target_x && ty == pbolt.target_y)
+ beamTerminate = beam_term_on_target(pbolt);
+
+ // affect the cell, except in the special case noted
+ // above -- affect() will early out if something gets
+ // hit and the beam is type 'term on target'.
+ if (!beamTerminate)
+ {
+ // random beams: randomize before affect
+ random_beam = false;
+ if (pbolt.flavour == BEAM_RANDOM)
+ {
+ random_beam = true;
+ pbolt.flavour = BEAM_FIRE + random2(7);
+ }
+
+ rangeRemaining -= affect(pbolt, tx, ty);
+
+ if (random_beam)
+ pbolt.flavour = BEAM_RANDOM;
+ }
+
+ // always decrease range by 1
+ rangeRemaining -= 1;
+
+ // check for range termination
+ if (rangeRemaining <= 0)
+ beamTerminate = true;
+
+ // special case - beam was aimed at feet
+ if (pbolt.aimedAtFeet)
+ beamTerminate = true;
+
+ // actually draw the beam/missile/whatever,
+ // if the player can see the cell.
+ if (!pbolt.isTracer && pbolt.beam_name[0] != '0' && see_grid(tx,ty))
+ {
+ // we don't clean up the old position.
+ // first, most people like seeing the full path,
+ // and second, it is hard to do it right with
+ // respect to killed monsters, cloud trails, etc.
+
+ // draw new position
+ int drawx = tx - you.x_pos + 18;
+ int drawy = ty - you.y_pos + 9;
+ // bounds check
+ if (drawx > 8 && drawx < 26 && drawy > 0 && drawy < 18)
+ {
+ if (pbolt.colour == BLACK)
+ textcolor(random_colour());
+ else
+ textcolor(pbolt.colour);
+
+ gotoxy(drawx, drawy);
+ putch(pbolt.type);
+
+#ifdef LINUX
+ // get curses to update the screen so we can see the beam
+ update_screen();
+#endif
+
+ delay(15);
+
+#ifdef MISSILE_TRAILS_OFF
+ if (!pbolt.isBeam || pbolt.beam_name[0] == '0')
+ viewwindow(1,false); // mv: added. It's not optimal but
+ // is usually enough
+#endif
+ }
+
+ }
+
+ // set some stuff up for the next iteration
+ lx = tx;
+ ly = ty;
+
+ wx = nx;
+ wy = ny;
+
+ } // end- while !beamTerminate
+
+ // the beam has finished, and terminated at tx, ty
+
+ // leave an object, if applicable
+ if (item)
+ beam_drop_object( pbolt, item, tx, ty );
+
+ // check for explosion. NOTE that for tracers, we have to make a copy
+ // of target co'ords and then reset after calling this -- tracers should
+ // never change any non-tracers fields in the beam structure. -- GDL
+ int ox = pbolt.target_x;
+ int oy = pbolt.target_y;
+
+ beam_explodes(pbolt, tx, ty);
+
+ if (pbolt.isTracer)
+ {
+ pbolt.target_x = ox;
+ pbolt.target_y = oy;
+ }
+
+ // canned msg for enchantments that affected no-one
+ if (pbolt.beam_name[0] == '0' && pbolt.flavour != BEAM_DIGGING)
+ {
+ if (!pbolt.isTracer && !pbolt.msgGenerated && !pbolt.obviousEffect)
+ canned_msg(MSG_NOTHING_HAPPENS);
+ }
+
+ // that's it!
+#ifdef WIN32CONSOLE
+ if (!pbolt.isTracer)
+ setBuffering(oldValue);
+#endif
+} // end fire_beam();
+
+
+// returns damage taken by a monster from a "flavoured" (fire, ice, etc.)
+// attack -- damage from clouds and branded weapons handled elsewhere.
+int mons_adjust_flavoured( struct monsters *monster, struct bolt &pbolt,
+ int hurted, bool doFlavouredEffects )
+{
+ // if we're not doing flavored effects, must be preliminary
+ // damage check only; do not print messages or apply any side
+ // effects!
+ int resist;
+
+ switch (pbolt.flavour)
+ {
+ case BEAM_FIRE:
+ resist = mons_res_fire(monster);
+ if (resist > 1)
+ {
+ if (doFlavouredEffects)
+ simple_monster_message(monster, " appears unharmed.");
+
+ hurted = 0;
+ }
+ else if (resist == 1)
+ {
+ if (doFlavouredEffects)
+ simple_monster_message(monster, " resists.");
+
+ hurted /= 3;
+ }
+ else if (resist < 0)
+ {
+ if (monster->type == MONS_ICE_BEAST
+ || monster->type == MONS_SIMULACRUM_SMALL
+ || monster->type == MONS_SIMULACRUM_LARGE)
+ {
+ if (doFlavouredEffects)
+ simple_monster_message(monster, " melts!");
+ }
+ else
+ {
+ if (doFlavouredEffects)
+ simple_monster_message(monster, " is burned terribly!");
+ }
+
+ hurted *= 15;
+ hurted /= 10;
+ }
+ break;
+
+
+ case BEAM_COLD:
+ resist = mons_res_cold(monster);
+ if (resist > 1)
+ {
+ if (doFlavouredEffects)
+ simple_monster_message(monster, " appears unharmed.");
+
+ hurted = 0;
+ }
+ else if (resist == 1)
+ {
+ if (doFlavouredEffects)
+ simple_monster_message(monster, " resists.");
+
+ hurted /= 3;
+ }
+ else if (resist < 0)
+ {
+ if (doFlavouredEffects)
+ simple_monster_message(monster, " is frozen!");
+
+ hurted *= 15;
+ hurted /= 10;
+ }
+ break;
+
+ case BEAM_ELECTRICITY:
+ if (mons_res_elec(monster) > 0)
+ {
+ if (doFlavouredEffects)
+ simple_monster_message(monster, " appears unharmed.");
+
+ hurted = 0;
+ }
+ break;
+
+
+ case BEAM_POISON:
+ if (mons_res_poison(monster) > 0)
+ {
+ if (doFlavouredEffects)
+ simple_monster_message( monster, " appears unharmed." );
+
+ hurted = 0;
+ }
+ else if (doFlavouredEffects && !one_chance_in(3))
+ {
+ poison_monster( monster, YOU_KILL(pbolt.thrower) );
+ }
+ break;
+
+ case BEAM_POISON_ARROW:
+ if (mons_res_poison(monster) > 0)
+ {
+ if (doFlavouredEffects)
+ {
+ simple_monster_message( monster, " partially resists." );
+
+ // Poison arrow can poison any living thing regardless of
+ // poison resistance. -- bwr
+ const int holy = mons_holiness( monster->type );
+ if (holy == MH_PLANT || holy == MH_NATURAL)
+ poison_monster( monster, YOU_KILL(pbolt.thrower), 2, true );
+ }
+
+ hurted /= 2;
+ }
+ else if (doFlavouredEffects)
+ {
+ poison_monster( monster, YOU_KILL(pbolt.thrower), 4 );
+ }
+ break;
+
+ case BEAM_NEG:
+ if (mons_res_negative_energy(monster) > 0)
+ {
+ if (doFlavouredEffects)
+ simple_monster_message(monster, " appears unharmed.");
+
+ hurted = 0;
+ }
+ else
+ {
+ // early out for tracer/no side effects
+ if (!doFlavouredEffects)
+ return (hurted);
+
+ simple_monster_message(monster, " is drained.");
+
+ if (one_chance_in(5))
+ monster->hit_dice--;
+
+ monster->max_hit_points -= 2 + random2(3);
+ monster->hit_points -= 2 + random2(3);
+
+ if (monster->hit_points >= monster->max_hit_points)
+ monster->hit_points = monster->max_hit_points;
+
+ if (monster->hit_dice < 1)
+ monster->hit_points = 0;
+ } // end else
+ break;
+
+ case BEAM_HOLY: // flame of cleansing
+ if (mons_holiness(monster->type) == MH_NATURAL
+ || mons_holiness(monster->type) == MH_NONLIVING
+ || mons_holiness(monster->type) == MH_PLANT
+ || mons_holiness(monster->type) == MH_HOLY)
+ {
+ if (doFlavouredEffects)
+ simple_monster_message(monster, " appears unharmed.");
+
+ hurted = 0;
+ }
+ break;
+
+ case BEAM_ICE:
+ /* ice - about 50% of damage is cold, other 50% is impact and
+ can't be resisted (except by AC, of course) */
+ resist = mons_res_cold(monster);
+ if (resist > 0)
+ {
+ if (doFlavouredEffects)
+ simple_monster_message(monster, " partially resists.");
+
+ hurted /= 2;
+ }
+ else if (resist < 0)
+ {
+ if (doFlavouredEffects)
+ simple_monster_message(monster, " is frozen!");
+
+ hurted *= 13;
+ hurted /= 10;
+ }
+ break;
+ } /* end of switch */
+
+ if (pbolt.flavour == BEAM_LAVA) //jmf: lava != hellfire
+ {
+ resist = mons_res_fire(monster);
+ if (resist > 0)
+ {
+ if (doFlavouredEffects)
+ simple_monster_message(monster, " partially resists.");
+
+ hurted /= 2;
+ }
+ else if (resist < 0)
+ {
+ if (monster->type == MONS_ICE_BEAST
+ || monster->type == MONS_SIMULACRUM_SMALL
+ || monster->type == MONS_SIMULACRUM_LARGE)
+ {
+ if (doFlavouredEffects)
+ simple_monster_message(monster, " melts!");
+ }
+ else
+ {
+ if (doFlavouredEffects)
+ simple_monster_message(monster, " is burned terribly!");
+ }
+
+ hurted *= 12;
+ hurted /= 10;
+ }
+ }
+ else if (stricmp(pbolt.beam_name, "hellfire") == 0)
+ {
+ resist = mons_res_fire(monster);
+ if (resist > 2)
+ {
+ if (doFlavouredEffects)
+ simple_monster_message(monster, " appears unharmed.");
+
+ hurted = 0;
+ }
+ else if (resist > 0)
+ {
+ if (doFlavouredEffects)
+ simple_monster_message(monster, " partially resists.");
+
+ hurted /= 2;
+ }
+ else if (resist < 0)
+ {
+ if (monster->type == MONS_ICE_BEAST
+ || monster->type == MONS_SIMULACRUM_SMALL
+ || monster->type == MONS_SIMULACRUM_LARGE)
+ {
+ if (doFlavouredEffects)
+ simple_monster_message(monster, " melts!");
+ }
+ else
+ {
+ if (doFlavouredEffects)
+ simple_monster_message(monster, " is burned terribly!");
+ }
+
+ hurted *= 12; /* hellfire */
+ hurted /= 10;
+ }
+ }
+
+ return (hurted);
+} // end mons_adjust_flavoured()
+
+
+// Enchants all monsters in player's sight.
+bool mass_enchantment( int wh_enchant, int pow, int origin )
+{
+ int i; // loop variable {dlb}
+ bool msgGenerated = false;
+ struct monsters *monster;
+
+ viewwindow(0, false);
+
+ if (pow > 200)
+ pow = 200;
+
+ for (i = 0; i < MAX_MONSTERS; i++)
+ {
+ monster = &menv[i];
+
+ if (monster->type == -1 || !mons_near(monster))
+ continue;
+
+ // assuming that the only mass charm is control undead:
+ if (wh_enchant == ENCH_CHARM)
+ {
+ if (mons_friendly(monster))
+ continue;
+
+ if (mons_holiness(monster->type) != MH_UNDEAD)
+ continue;
+
+ if (check_mons_resist_magic( monster, pow ))
+ {
+ simple_monster_message(monster, " resists.");
+ continue;
+ }
+ }
+ else if (mons_holiness(monster->type) == MH_NATURAL)
+ {
+ if (check_mons_resist_magic( monster, pow ))
+ {
+ simple_monster_message(monster, " resists.");
+ continue;
+ }
+ }
+ else // trying to enchant an unnatural creature doesn't work
+ {
+ simple_monster_message(monster, " is unaffected.");
+ continue;
+ }
+
+ if (mons_has_ench(monster, wh_enchant))
+ continue;
+
+ if (mons_add_ench(monster, wh_enchant))
+ {
+ if (player_monster_visible( monster ))
+ {
+ // turn message on
+ msgGenerated = true;
+ switch (wh_enchant)
+ {
+ case ENCH_FEAR:
+ simple_monster_message(monster,
+ " looks frightened!");
+ break;
+ case ENCH_CONFUSION:
+ simple_monster_message(monster,
+ " looks rather confused.");
+ break;
+ case ENCH_CHARM:
+ simple_monster_message(monster,
+ " submits to your will.");
+ break;
+ default:
+ // oops, I guess not!
+ msgGenerated = false;
+ }
+ }
+
+ // extra check for fear (monster needs to reevaluate behaviour)
+ if (wh_enchant == ENCH_FEAR)
+ behaviour_event( monster, ME_SCARE, origin );
+ }
+ } // end "for i"
+
+ if (!msgGenerated)
+ canned_msg(MSG_NOTHING_HAPPENS);
+
+ return (msgGenerated);
+} // end mass_enchantmenet()
+
+/*
+ Monster has probably failed save, now it gets enchanted somehow.
+
+ returns MON_RESIST if monster is unaffected due to magic resist.
+ returns MON_UNAFFECTED if monster is immune to enchantment
+ returns MON_AFFECTED in all other cases (already enchanted, etc)
+ */
+int mons_ench_f2(struct monsters *monster, struct bolt &pbolt)
+{
+ bool is_near = mons_near(monster); // single caluclation permissible {dlb}
+ char buff[ ITEMNAME_SIZE ];
+
+ switch (pbolt.flavour) /* put in magic resistance */
+ {
+ case BEAM_SLOW: /* 0 = slow monster */
+ // try to remove haste, if monster is hasted
+ if (mons_del_ench(monster, ENCH_HASTE))
+ {
+ if (simple_monster_message(monster, " is no longer moving quickly."))
+ pbolt.obviousEffect = true;
+
+ return (MON_AFFECTED);
+ }
+
+ // not hasted, slow it
+ if (mons_add_ench(monster, ENCH_SLOW))
+ {
+ // put in an exception for fungi, plants and other things you won't
+ // notice slow down.
+ if (simple_monster_message(monster, " seems to slow down."))
+ pbolt.obviousEffect = true;
+ }
+ return (MON_AFFECTED);
+
+ case BEAM_HASTE: // 1 = haste
+ if (mons_del_ench(monster, ENCH_SLOW))
+ {
+ if (simple_monster_message(monster, " is no longer moving slowly."))
+ pbolt.obviousEffect = true;
+
+ return (MON_AFFECTED);
+ }
+
+ // not slowed, haste it
+ if (mons_add_ench(monster, ENCH_HASTE))
+ {
+ // put in an exception for fungi, plants and other things you won't
+ // notice speed up.
+ if (simple_monster_message(monster, " seems to speed up."))
+ pbolt.obviousEffect = true;
+ }
+ return (MON_AFFECTED);
+
+ case BEAM_HEALING: /* 2 = healing */
+ if (heal_monster( monster, 5 + roll_dice( pbolt.damage ), false ))
+ {
+ if (monster->hit_points == monster->max_hit_points)
+ {
+ if (simple_monster_message(monster,
+ "'s wounds heal themselves!"))
+ pbolt.obviousEffect = true;
+ }
+ else
+ {
+ if (simple_monster_message(monster, " is healed somewhat."))
+ pbolt.obviousEffect = true;
+ }
+ }
+ return (MON_AFFECTED);
+
+ case BEAM_PARALYSIS: /* 3 = paralysis */
+ monster->speed_increment = 0;
+
+ if (simple_monster_message(monster, " suddenly stops moving!"))
+ pbolt.obviousEffect = true;
+
+ if (grd[monster->x][monster->y] == DNGN_LAVA_X
+ || grd[monster->x][monster->y] == DNGN_WATER_X)
+ {
+ if (mons_flies(monster) == 1)
+ {
+ // don't worry about invisibility - you should be able to
+ // see if something has fallen into the lava
+ if (is_near)
+ {
+ strcpy(info, ptr_monam(monster, DESC_CAP_THE));
+ strcat(info, " falls into the ");
+ strcat(info, (grd[monster->x][monster->y] == DNGN_WATER_X)
+ ? "water" : "lava");
+ strcat(info, "!");
+ mpr(info);
+ }
+
+ switch (pbolt.thrower)
+ {
+ case KILL_YOU:
+ case KILL_YOU_MISSILE:
+ monster_die(monster, KILL_YOU, pbolt.beam_source);
+ break; /* " " */
+
+ case KILL_MON:
+ case KILL_MON_MISSILE:
+ monster_die(monster, KILL_MON_MISSILE, pbolt.beam_source);
+ break; /* dragon breath &c */
+ }
+ }
+ }
+ return (MON_AFFECTED);
+
+ case BEAM_CONFUSION: /* 4 = confusion */
+ if (mons_add_ench(monster, ENCH_CONFUSION))
+ {
+ // put in an exception for fungi, plants and other things you won't
+ // notice becoming confused.
+ if (simple_monster_message(monster, " appears confused."))
+ pbolt.obviousEffect = true;
+ }
+ return (MON_AFFECTED);
+
+ case BEAM_INVISIBILITY: /* 5 = invisibility */
+ // Store the monster name before it becomes an "it" -- bwr
+ strncpy( buff, ptr_monam( monster, DESC_CAP_THE ), sizeof(buff) );
+
+ if (mons_add_ench(monster, ENCH_INVIS))
+ {
+ // Can't use simple_monster_message here, since it checks
+ // for visibility of the monster (and its now invisible) -- bwr
+ if (mons_near( monster ))
+ {
+ snprintf( info, INFO_SIZE, "%s flickers %s",
+ buff, player_see_invis() ? "for a moment."
+ : "and vanishes!" );
+ mpr( info );
+ }
+
+ pbolt.obviousEffect = true;
+ }
+ return (MON_AFFECTED);
+
+ case BEAM_CHARM: /* 9 = charm */
+ if (mons_add_ench(monster, ENCH_CHARM))
+ {
+ // put in an exception for fungi, plants and other things you won't
+ // notice becoming charmed.
+ if (simple_monster_message(monster, " is charmed."))
+ pbolt.obviousEffect = true;
+ }
+ return (MON_AFFECTED);
+
+ default:
+ break;
+ } /* end of switch (beam_colour) */
+
+ return (MON_AFFECTED);
+} // end mons_ench_f2()
+
+// actually poisons a monster (w/ message)
+void poison_monster( struct monsters *monster, bool fromPlayer, int levels,
+ bool force )
+{
+ bool yourPoison = false;
+ int ench = ENCH_NONE;
+ int old_strength = 0;
+
+ if (monster->type == -1)
+ return;
+
+ if (!force && mons_res_poison(monster) > 0)
+ return;
+
+ // who gets the credit if monster dies of poison?
+ ench = mons_has_ench( monster, ENCH_POISON_I, ENCH_POISON_IV );
+ if (ench != ENCH_NONE)
+ {
+ old_strength = ench - ENCH_POISON_I;
+ }
+ else
+ {
+ ench = mons_has_ench(monster, ENCH_YOUR_POISON_I, ENCH_YOUR_POISON_IV);
+ if (ench != ENCH_NONE)
+ {
+ old_strength = ench - ENCH_YOUR_POISON_I;
+ yourPoison = true;
+ }
+ }
+
+ // delete old poison
+ mons_del_ench( monster, ENCH_POISON_I, ENCH_POISON_IV, true );
+ mons_del_ench( monster, ENCH_YOUR_POISON_I, ENCH_YOUR_POISON_IV, true );
+
+ // Calculate new strength:
+ int new_strength = old_strength + levels;
+ if (new_strength > 3)
+ new_strength = 3;
+
+ // now, if player poisons the monster at ANY TIME, they should
+ // get credit for the kill if the monster dies from poison. This
+ // really isn't that abusable -- GDL.
+ if (fromPlayer || yourPoison)
+ ench = ENCH_YOUR_POISON_I + new_strength;
+ else
+ ench = ENCH_POISON_I + new_strength;
+
+ // actually do the poisoning
+ // note: order important here
+ if (mons_add_ench( monster, ench ) && new_strength > old_strength)
+ {
+ simple_monster_message( monster,
+ (old_strength == 0) ? " looks ill."
+ : " looks even sicker." );
+ }
+
+ // finally, take care of deity preferences
+ if (fromPlayer)
+ {
+ naughty(NAUGHTY_POISON, 5 + random2(3)); //jmf: TSO now hates poison
+ done_good(GOOD_POISON, 5); //jmf: had test god who liked poison
+ }
+} // end poison_monster()
+
+// actually napalms a monster (w/ message)
+void sticky_flame_monster( int mn, bool fromPlayer, int levels )
+{
+ bool yourFlame = fromPlayer;
+ int currentFlame;
+ int currentStrength = 0;
+
+ struct monsters *monster = &menv[mn];
+
+ if (monster->type == -1)
+ return;
+
+ if (mons_res_fire(monster) > 0)
+ return;
+
+ // who gets the credit if monster dies of napalm?
+ currentFlame = mons_has_ench( monster, ENCH_STICKY_FLAME_I,
+ ENCH_STICKY_FLAME_IV );
+
+ if (currentFlame != ENCH_NONE)
+ {
+ currentStrength = currentFlame - ENCH_STICKY_FLAME_I;
+ yourFlame = false;
+ }
+ else
+ {
+ currentFlame = mons_has_ench( monster, ENCH_YOUR_STICKY_FLAME_I,
+ ENCH_YOUR_STICKY_FLAME_IV );
+
+ if (currentFlame != ENCH_NONE)
+ {
+ currentStrength = currentFlame - ENCH_YOUR_STICKY_FLAME_I;
+ yourFlame = true;
+ }
+ else
+ currentStrength = -1; // no flame yet!
+ }
+
+ // delete old flame
+ mons_del_ench( monster, ENCH_STICKY_FLAME_I, ENCH_STICKY_FLAME_IV, true );
+ mons_del_ench( monster, ENCH_YOUR_STICKY_FLAME_I, ENCH_YOUR_STICKY_FLAME_IV,
+ true );
+
+ // increase sticky flame strength, cap at 3 (level is 0..3)
+ currentStrength += levels;
+
+ if (currentStrength > 3)
+ currentStrength = 3;
+
+ // now, if player flames the monster at ANY TIME, they should
+ // get credit for the kill if the monster dies from napalm. This
+ // really isn't that abusable -- GDL.
+ if (fromPlayer || yourFlame)
+ currentStrength += ENCH_YOUR_STICKY_FLAME_I;
+ else
+ currentStrength += ENCH_STICKY_FLAME_I;
+
+ // actually do flame
+ if (mons_add_ench( monster, currentStrength ))
+ simple_monster_message(monster, " is covered in liquid fire!");
+
+} // end sticky_flame_monster
+
+/*
+ * Used by monsters in "planning" which spell to cast. Fires off a "tracer"
+ * which tells the monster what it'll hit if it breathes/casts etc.
+ *
+ * The output from this tracer function is four variables in the beam struct:
+ * fr_count, foe_count: a count of how many friends and foes will (probably)
+ * be hit by this beam
+ * fr_power, foe_power: a measure of how many 'friendly' hit dice it will
+ * affect, and how many 'unfriendly' hit dice.
+ *
+ * note that beam properties must be set, as the tracer will take them
+ * into account, as well as the monster's intelligence.
+ *
+ */
+void fire_tracer(struct monsters *monster, struct bolt &pbolt)
+{
+ // don't fiddle with any input parameters other than tracer stuff!
+ pbolt.isTracer = true;
+ pbolt.source_x = monster->x; // always safe to do.
+ pbolt.source_y = monster->y;
+ pbolt.beam_source = monster_index(monster);
+ pbolt.canSeeInvis = (mons_see_invis(monster) != 0);
+ pbolt.smartMonster = (mons_intel(monster->type) == I_HIGH ||
+ mons_intel(monster->type) == I_NORMAL);
+ pbolt.isFriendly = mons_friendly(monster);
+
+ // init tracer variables
+ pbolt.foe_count = pbolt.fr_count = 0;
+ pbolt.foe_power = pbolt.fr_power = 0;
+ pbolt.foeRatio = 80; // default - see mons_should_fire()
+
+ // foe ratio for summon gtr. demons & undead -- they may be
+ // summoned, but they're hostile and would love nothing better
+ // than to nuke the player and his minions
+ if (monster->attitude != ATT_FRIENDLY)
+ pbolt.foeRatio = 25;
+
+ // fire!
+ fire_beam(pbolt);
+
+ // unset tracer flag (convenience)
+ pbolt.isTracer = false;
+} // end tracer_f()
+
+
+/*
+ When a mimic is hit by a ranged attack, it teleports away (the slow way)
+ and changes its appearance - the appearance change is in monster_teleport
+ in mstuff2.
+ */
+void mimic_alert(struct monsters *mimic)
+{
+ if (mons_has_ench( mimic, ENCH_TP_I, ENCH_TP_IV ))
+ return;
+
+ monster_teleport( mimic, !one_chance_in(3) );
+} // end mimic_alert()
+
+static bool isBouncy(struct bolt &beam)
+{
+ // at present, only non-enchantment eletrcical beams bounce.
+ if (beam.beam_name[0] != '0' && beam.flavour == BEAM_ELECTRICITY)
+ return (true);
+
+ return (false);
+}
+
+static void beam_explodes(struct bolt &beam, int x, int y)
+{
+ int cloud_type;
+
+ // this will be the last thing this beam does.. set target_x
+ // and target_y to hold explosion co'ords.
+
+ beam.target_x = x;
+ beam.target_y = y;
+
+ // generic explosion
+ if (beam.flavour == BEAM_EXPLOSION || beam.flavour == BEAM_HOLY)
+ {
+ explosion1(beam);
+ return;
+ }
+
+ if (beam.flavour >= BEAM_POTION_STINKING_CLOUD
+ && beam.flavour <= BEAM_POTION_RANDOM)
+ {
+ switch (beam.flavour)
+ {
+ case BEAM_POTION_STINKING_CLOUD:
+ beam.colour = GREEN;
+ break;
+
+ case BEAM_POTION_POISON:
+ beam.colour = (coinflip() ? GREEN : LIGHTGREEN);
+ break;
+
+ case BEAM_POTION_MIASMA:
+ case BEAM_POTION_BLACK_SMOKE:
+ beam.colour = DARKGREY;
+ break;
+
+ case BEAM_POTION_STEAM:
+ beam.colour = LIGHTGREY;
+ break;
+
+ case BEAM_POTION_FIRE:
+ beam.colour = (coinflip() ? RED : LIGHTRED);
+ break;
+
+ case BEAM_POTION_COLD:
+ beam.colour = (coinflip() ? BLUE : LIGHTBLUE);
+ break;
+
+ case BEAM_POTION_BLUE_SMOKE:
+ beam.colour = LIGHTBLUE;
+ break;
+
+ case BEAM_POTION_PURP_SMOKE:
+ beam.colour = MAGENTA;
+ break;
+
+ case BEAM_POTION_RANDOM:
+ default:
+ // Leave it the colour of the potion, the clouds will colour
+ // themselves on the next refresh. -- bwr
+ break;
+ }
+
+ explosion1(beam);
+ return;
+ }
+
+
+ // cloud producer -- POISON BLAST
+ if (strcmp(beam.beam_name, "blast of poison") == 0)
+ {
+ cloud_type = YOU_KILL(beam.thrower) ? CLOUD_POISON : CLOUD_POISON_MON;
+ big_cloud( cloud_type, x, y, 0, 7 + random2(5) );
+ return;
+ }
+
+ // cloud producer -- FOUL VAPOR (SWAMP DRAKE?)
+ if (strcmp(beam.beam_name, "foul vapour") == 0)
+ {
+ cloud_type = YOU_KILL(beam.thrower) ? CLOUD_STINK : CLOUD_STINK_MON;
+ big_cloud( cloud_type, x, y, 0, 9 );
+ return;
+ }
+
+ // special cases - orbs & blasts of cold
+ if (strcmp(beam.beam_name, "orb of electricity") == 0
+ || strcmp(beam.beam_name, "metal orb") == 0
+ || strcmp(beam.beam_name, "great blast of cold") == 0)
+ {
+ explosion1( beam );
+ return;
+ }
+
+ // cloud producer only -- stinking cloud
+ if (strcmp(beam.beam_name, "ball of vapour") == 0)
+ {
+ explosion1( beam );
+ return;
+ }
+}
+
+static bool beam_term_on_target(struct bolt &beam)
+{
+
+ // generic - all explosion-type beams can be targetted at empty space,
+ // and will explode there. This semantic also means that a creature
+ // in the target cell will have no chance to dodge or block, so we
+ // DON'T affect() the cell if this function returns true!
+
+ if (beam.flavour == BEAM_EXPLOSION || beam.flavour == BEAM_HOLY)
+ return (true);
+
+ // POISON BLAST
+ if (strcmp(beam.beam_name, "blast of poison") == 0)
+ return (true);
+
+ // FOUL VAPOR (SWAMP DRAKE)
+ if (strcmp(beam.beam_name, "foul vapour") == 0)
+ return (true);
+
+ // STINKING CLOUD
+ if (strcmp(beam.beam_name, "ball of vapour") == 0)
+ return (true);
+
+ return (false);
+}
+
+static void beam_drop_object( struct bolt &beam, item_def *item, int x, int y )
+{
+ ASSERT( item != NULL );
+
+ // conditions: beam is missile and not tracer.
+ if (beam.isTracer || beam.flavour != BEAM_MISSILE)
+ return;
+
+ if (YOU_KILL(beam.thrower) // ie if you threw it.
+ && (grd[x][y] != DNGN_LAVA && grd[x][y] != DNGN_DEEP_WATER))
+ {
+ int chance;
+
+ // Using Throwing skill as the fletching/ammo preserving skill. -- bwr
+ switch (item->sub_type)
+ {
+ case MI_NEEDLE: chance = 6 + you.skills[SK_THROWING] / 6; break;
+ case MI_STONE: chance = 3 + you.skills[SK_THROWING] / 4; break;
+ case MI_DART: chance = 2 + you.skills[SK_THROWING] / 6; break;
+ case MI_ARROW: chance = 2 + you.skills[SK_THROWING] / 4; break;
+ case MI_BOLT: chance = 2 + you.skills[SK_THROWING] / 5; break;
+
+ case MI_LARGE_ROCK:
+ default:
+ chance = 20;
+ break;
+ }
+
+ if (item->base_type != OBJ_MISSILES || !one_chance_in(chance))
+ copy_item_to_grid( *item, x, y, 1 );
+ }
+ else if (MON_KILL(beam.thrower) // monster threw it.
+ && (grd[x][y] != DNGN_LAVA && grd[x][y] != DNGN_DEEP_WATER)
+ && coinflip())
+ {
+ copy_item_to_grid( *item, x, y, 1 );
+ } // if (thing_throw == 2) ...
+}
+
+// somewhat complicated BOUNCE function
+// returns # of times beam bounces during routine (usually 1)
+//
+// step 1 is always the step value from the stepping direction.
+#define B_HORZ 1
+#define B_VERT 2
+#define B_BOTH 3
+
+static int bounce(int &step1, int &step2, int w1, int w2, int &n1, int &n2,
+ int l1, int l2, int &t1, int &t2, bool topBlocked, bool sideBlocked)
+{
+ int bounceType = 0;
+ int bounceCount = 1;
+
+ if (topBlocked) bounceType = B_HORZ;
+ if (sideBlocked) bounceType = B_VERT;
+ if (topBlocked && sideBlocked)
+ {
+ // check for veritcal bounce only
+ if ((w2 + step2 - 50)/100 == (w2 - 50)/100)
+ bounceType = B_VERT;
+ else
+ bounceType = B_BOTH;
+ }
+
+ switch (bounceType)
+ {
+ case B_VERT: // easiest
+ n1 = w1;
+ n2 = w2 + step2;
+ step1 = -step1;
+ t1 = n1 / 100;
+ t2 = (n2 + 50)/100;
+ // check top
+ if (t2 != n2/100 && topBlocked)
+ t2 = n2/100;
+ break;
+ case B_HORZ: // a little tricky
+ if (step2 > 0)
+ n2 = (100 + 200*(w2/100)) - (w2 + step2);
+ else
+ n2 = (100 + 200*((w2 - 50)/100)) - (w2 + step2);
+ n1 = w1 + step1;
+ t1 = n1 /100;
+ t2 = (n2 + 50) / 100;
+ step2 = -step2;
+ break;
+ case B_BOTH:
+ // vertical:
+ n1 = w1;
+ t1 = l1;
+ t2 = l2;
+ // horizontal:
+ if (step2 > 0)
+ n2 = (100 + 200*(w2/100)) - (w2 + step2);
+ else
+ n2 = (100 + 200*((w2 - 50)/100)) - (w2 + step2);
+ // reverse both directions
+ step1 =- step1;
+ step2 =- step2;
+ bounceCount = 2;
+ break;
+ default:
+ bounceCount = 0;
+ break;
+ }
+
+ return (bounceCount);
+}
+
+static bool fuzzyLine(int nx, int ny, int &tx, int &ty, int lx, int ly,
+ int stepx, int stepy, bool roundX, bool roundY)
+{
+ bool fuzzyOK = false;
+ int fx, fy; // fuzzy x,y
+
+ // BEGIN fuzzy line algorithm
+ fx = tx;
+ fy = ty;
+ if (roundY)
+ {
+ // try up
+ fy = (ny + 100) / 100;
+ // check for monotonic
+ if (fy != ty && ((stepy>0 && fy >= ly)
+ || (stepy<0 && fy <= ly)))
+ fuzzyOK = true;
+ // see if up try is blocked
+ if (fuzzyOK && grd[tx][fy] < MINMOVE)
+ fuzzyOK = false;
+
+ // try down
+ if (!fuzzyOK)
+ fy = ny / 100;
+ // check for monotonic
+ if (fy != ty && ((stepy>0 && fy >= ly)
+ || (stepy<0 && fy <= ly)))
+ fuzzyOK = true;
+ if (fuzzyOK && grd[tx][fy] < MINMOVE)
+ fuzzyOK = false;
+ }
+ if (roundX)
+ {
+ // try up
+ fx = (nx + 100) / 100;
+ // check for monotonic
+ if (fx != tx && ((stepx>0 && fx >= lx)
+ || (stepx<0 && fx <= lx)))
+ fuzzyOK = true;
+ // see if up try is blocked
+ if (fuzzyOK && grd[fx][ty] < MINMOVE)
+ fuzzyOK = false;
+
+ // try down
+ if (!fuzzyOK)
+ fx = nx / 100;
+ // check for monotonic
+ if (fx != tx && ((stepx>0 && fx >= lx)
+ || (stepx<0 && fx <= lx)))
+ fuzzyOK = true;
+ if (fuzzyOK && grd[fx][ty] < MINMOVE)
+ fuzzyOK = false;
+ }
+ // END fuzzy line algorithm
+
+ if (fuzzyOK)
+ {
+ tx = fx;
+ ty = fy;
+ }
+
+ return (fuzzyOK);
+}
+
+// affects a single cell.
+// returns the amount of extra range 'used up' by this beam
+// during the affectation.
+//
+// pseudo-code:
+//
+// 1. If wall, and wall affecting non-tracer, affect the wall.
+// 1b. If for some reason the wall-affect didn't make it into
+// a non-wall, return affect_wall()
+// 2. for non-tracers, produce cloud effects affect_place_clouds()
+// 3. if cell holds player, affect player affect_player()
+// 4. if cell holds monster, affect monster affect_monster()
+// 5. return range used affectation.
+
+static int affect(struct bolt &beam, int x, int y)
+{
+ // extra range used by hitting something
+ int rangeUsed = 0;
+
+ if (grd[x][y] < MINMOVE)
+ {
+ if (beam.isTracer) // tracers always stop on walls.
+ return (BEAM_STOP);
+
+ if (affectsWalls(beam))
+ {
+ rangeUsed += affect_wall(beam, x, y);
+ }
+ // if it's still a wall, quit - we can't do anything else to
+ // a wall. Otherwise effects (like clouds, etc) are still possible.
+ if (grd[x][y] < MINMOVE)
+ return (rangeUsed);
+ }
+
+ // grd[x][y] will NOT be a wall for the remainder of this function.
+
+ // if not a tracer, place clouds
+ if (!beam.isTracer)
+ rangeUsed += affect_place_clouds(beam, x, y);
+
+ // if player is at this location, try to affect unless term_on_target
+ if (x == you.x_pos && y == you.y_pos)
+ {
+ if (beam_term_on_target(beam) && !beam.isExplosion)
+ return (BEAM_STOP);
+
+ rangeUsed += affect_player(beam);
+ }
+
+ // if there is a monster at this location, affect it
+ // submerged monsters aren't really there -- bwr
+ int mid = mgrd[x][y];
+ if (mid != NON_MONSTER && !mons_has_ench( &menv[mid], ENCH_SUBMERGED ))
+ {
+ if (beam_term_on_target(beam) && !beam.isExplosion)
+ return (BEAM_STOP);
+
+ struct monsters* monster = &menv[mid];
+ rangeUsed += affect_monster(beam, monster);
+ }
+
+ return (rangeUsed);
+}
+
+static bool affectsWalls(struct bolt &beam)
+{
+ // don't know of any explosion that affects walls. But change it here
+ // if there is.
+ if (beam.isExplosion)
+ return (false);
+
+ // digging
+ if (beam.flavour == BEAM_DIGGING)
+ return (true);
+
+ // Isn't this much nicer than the hack to remove ice bolts, disrupt,
+ // and needles (just because they were also coloured "white") -- bwr
+ if (beam.flavour == BEAM_DISINTEGRATION && beam.damage.num >= 3)
+ return (true);
+
+ // eye of devestation?
+ if (beam.flavour == BEAM_NUKE)
+ return (true);
+
+ return (false);
+}
+
+// return amount of extra range used up by affectation of this wall.
+static int affect_wall(struct bolt &beam, int x, int y)
+{
+ int rangeUsed = 0;
+
+ // DIGGING
+ if (beam.flavour == BEAM_DIGGING)
+ {
+ if (grd[x][y] == DNGN_STONE_WALL
+ || grd[x][y] == DNGN_METAL_WALL
+ || grd[x][y] == DNGN_PERMAROCK_WALL
+ || x <= 5 || x >= (GXM - 5)
+ || y <= 5 || y >= (GYM - 5))
+ {
+ return (0);
+ }
+
+ if (grd[x][y] == DNGN_ROCK_WALL)
+ {
+ grd[x][y] = DNGN_FLOOR;
+
+ if (!beam.msgGenerated)
+ {
+ if (!silenced(you.x_pos, you.y_pos))
+ {
+ mpr("You hear a grinding noise.");
+ beam.obviousEffect = true;
+ }
+
+ beam.msgGenerated = true;
+ }
+ }
+
+ return (rangeUsed);
+ }
+ // END DIGGING EFFECT
+
+ // NUKE / DISRUPT
+ if (beam.flavour == BEAM_DISINTEGRATION || beam.flavour == BEAM_NUKE)
+ {
+ int targ_grid = grd[x][y];
+
+ if ((targ_grid == DNGN_ROCK_WALL || targ_grid == DNGN_WAX_WALL)
+ && !(x <= 6 || y <= 6 || x >= (GXM - 6) || y >= (GYM - 6)))
+ {
+ grd[ x ][ y ] = DNGN_FLOOR;
+ if (!silenced(you.x_pos, you.y_pos))
+ {
+ mpr("You hear a grinding noise.");
+ beam.obviousEffect = true;
+ }
+ }
+
+ if (targ_grid == DNGN_ORCISH_IDOL || (targ_grid >= DNGN_SILVER_STATUE
+ && targ_grid <= DNGN_STATUE_39))
+ {
+ grd[x][y] = DNGN_FLOOR;
+
+ if (!silenced(you.x_pos, you.y_pos))
+ {
+ if (!see_grid( x, y ))
+ mpr("You hear a hideous screaming!");
+ else
+ mpr("The statue screams as its substance crumbles away!");
+ }
+ else
+ {
+ if (see_grid(x,y))
+ mpr("The statue twists and shakes as its substance crumbles away!");
+ }
+
+ if (targ_grid == DNGN_SILVER_STATUE)
+ Visible_Statue[ STATUE_SILVER ] = 0;
+ else if (targ_grid == DNGN_ORANGE_CRYSTAL_STATUE)
+ Visible_Statue[ STATUE_ORANGE_CRYSTAL ] = 0;
+
+ beam.obviousEffect = 1;
+ }
+
+ return (BEAM_STOP);
+ }
+
+ return (rangeUsed);
+}
+
+static int affect_place_clouds(struct bolt &beam, int x, int y)
+{
+ int cloud_type;
+
+ if (beam.isExplosion)
+ {
+ affect_place_explosion_clouds( beam, x, y );
+ return (0); // return value irrelevant for explosions
+ }
+
+ // check for CLOUD HITS
+ if (env.cgrid[x][y] != EMPTY_CLOUD) // hit a cloud
+ {
+ // polymorph randomly changes clouds in its path
+ if (beam.flavour == BEAM_POLYMORPH)
+ env.cloud[ env.cgrid[x][y] ].type = 1 + random2(8);
+
+ // now exit (all enchantments)
+ if (beam.beam_name[0] == '0')
+ return (0);
+
+ int clouty = env.cgrid[x][y];
+
+ // fire cancelling cold & vice versa
+ if (((env.cloud[clouty].type == CLOUD_COLD
+ || env.cloud[clouty].type == CLOUD_COLD_MON)
+ && (beam.flavour == BEAM_FIRE
+ || beam.flavour == BEAM_LAVA))
+ || ((env.cloud[clouty].type == CLOUD_FIRE
+ || env.cloud[clouty].type == CLOUD_FIRE_MON)
+ && beam.flavour == BEAM_COLD))
+ {
+ if (!silenced(x, y)
+ && !silenced(you.x_pos, you.y_pos))
+ {
+ mpr("You hear a sizzling sound!");
+ }
+
+ delete_cloud( clouty );
+ return (5);
+ }
+ }
+
+ // POISON BLAST
+ if (strcmp(beam.beam_name, "blast of poison") == 0)
+ {
+ cloud_type = YOU_KILL(beam.thrower) ? CLOUD_POISON : CLOUD_POISON_MON;
+
+ place_cloud( cloud_type, x, y, random2(4) + 2 );
+ }
+
+ // FIRE/COLD over water/lava
+ if ( (grd[x][y] == DNGN_LAVA && beam.flavour == BEAM_COLD)
+ || ((grd[x][y] == DNGN_DEEP_WATER || grd[x][y] == DNGN_SHALLOW_WATER)
+ && beam.flavour == BEAM_FIRE) )
+ {
+ cloud_type = YOU_KILL(beam.thrower) ? CLOUD_STEAM : CLOUD_STEAM_MON;
+ place_cloud( cloud_type, x, y, 2 + random2(5) );
+ }
+
+ // ORB OF ENERGY
+ if (strcmp(beam.beam_name, "orb of energy") == 0)
+ place_cloud( CLOUD_PURP_SMOKE, x, y, random2(5) + 1 );
+
+ // GREAT BLAST OF COLD
+ if (strcmp(beam.beam_name, "great blast of cold") == 0)
+ place_cloud( CLOUD_COLD, x, y, random2(5) + 3 );
+
+
+ // BALL OF STEAM
+ if (strcmp(beam.beam_name, "ball of steam") == 0)
+ {
+ cloud_type = YOU_KILL(beam.thrower) ? CLOUD_STEAM : CLOUD_STEAM_MON;
+ place_cloud( cloud_type, x, y, random2(5) + 2 );
+ }
+
+ // STICKY FLAME
+ if (strcmp(beam.beam_name, "sticky flame") == 0)
+ {
+ place_cloud( CLOUD_BLACK_SMOKE, x, y, random2(4) + 2 );
+ }
+
+ // POISON GAS
+ if (strcmp(beam.beam_name, "poison gas") == 0)
+ {
+ cloud_type = YOU_KILL(beam.thrower) ? CLOUD_POISON : CLOUD_POISON_MON;
+ place_cloud( cloud_type, x, y, random2(4) + 3 );
+ }
+
+ return (0);
+}
+
+// following two functions used with explosions:
+static void affect_place_explosion_clouds(struct bolt &beam, int x, int y)
+{
+ int cloud_type;
+ int duration;
+
+ // first check: FIRE/COLD over water/lava
+ if ( (grd[x][y] == DNGN_LAVA && beam.flavour == BEAM_COLD)
+ || ((grd[x][y] == DNGN_DEEP_WATER || grd[x][y] == DNGN_SHALLOW_WATER)
+ && beam.flavour == BEAM_FIRE) )
+ {
+ cloud_type = YOU_KILL(beam.thrower) ? CLOUD_STEAM : CLOUD_STEAM_MON;
+ place_cloud( cloud_type, x, y, 2 + random2(5) );
+ return;
+ }
+
+ if (beam.flavour >= BEAM_POTION_STINKING_CLOUD
+ && beam.flavour <= BEAM_POTION_RANDOM)
+ {
+ duration = roll_dice( 2, 3 + beam.ench_power / 20 );
+
+ switch (beam.flavour)
+ {
+ case BEAM_POTION_STINKING_CLOUD:
+ cloud_type = CLOUD_STINK;
+ break;
+
+ case BEAM_POTION_POISON:
+ cloud_type = CLOUD_POISON;
+ break;
+
+ case BEAM_POTION_MIASMA:
+ cloud_type = CLOUD_MIASMA;
+ break;
+
+ case BEAM_POTION_BLACK_SMOKE:
+ cloud_type = CLOUD_BLACK_SMOKE;
+ break;
+
+ case BEAM_POTION_FIRE:
+ cloud_type = CLOUD_FIRE;
+ break;
+
+ case BEAM_POTION_COLD:
+ cloud_type = CLOUD_COLD;
+ break;
+
+ case BEAM_POTION_BLUE_SMOKE:
+ cloud_type = CLOUD_BLUE_SMOKE;
+ break;
+
+ case BEAM_POTION_PURP_SMOKE:
+ cloud_type = CLOUD_PURP_SMOKE;
+ break;
+
+ case BEAM_POTION_RANDOM:
+ switch (random2(10))
+ {
+ case 0: cloud_type = CLOUD_FIRE; break;
+ case 1: cloud_type = CLOUD_STINK; break;
+ case 2: cloud_type = CLOUD_COLD; break;
+ case 3: cloud_type = CLOUD_POISON; break;
+ case 4: cloud_type = CLOUD_BLACK_SMOKE; break;
+ case 5: cloud_type = CLOUD_BLUE_SMOKE; break;
+ case 6: cloud_type = CLOUD_PURP_SMOKE; break;
+ default: cloud_type = CLOUD_STEAM; break;
+ }
+ break;
+
+ case BEAM_POTION_STEAM:
+ default:
+ cloud_type = CLOUD_STEAM;
+ break;
+ }
+
+ place_cloud( cloud_type, x, y, duration );
+ }
+
+ // then check for more specific explosion cloud types.
+ if (stricmp(beam.beam_name, "ice storm") == 0)
+ {
+ place_cloud( CLOUD_COLD, x, y, 2 + random2avg(5, 2) );
+ }
+
+ if (stricmp(beam.beam_name, "stinking cloud") == 0)
+ {
+ duration = 1 + random2(4) + random2( (beam.ench_power / 50) + 1 );
+ place_cloud( CLOUD_STINK, x, y, duration );
+ }
+
+ if (strcmp(beam.beam_name, "great blast of fire") == 0)
+ {
+ duration = 1 + random2(5) + roll_dice( 2, beam.ench_power / 5 );
+
+ if (duration > 20)
+ duration = 20 + random2(4);
+
+ place_cloud( CLOUD_FIRE, x, y, duration );
+
+ if (grd[x][y] == DNGN_FLOOR && mgrd[x][y] == NON_MONSTER
+ && one_chance_in(4))
+ {
+ mons_place( MONS_FIRE_VORTEX, BEH_HOSTILE, MHITNOT, true, x, y );
+ }
+ }
+}
+
+static void affect_items(struct bolt &beam, int x, int y)
+{
+ char objs_vulnerable = -1;
+
+ switch (beam.flavour)
+ {
+ case BEAM_FIRE:
+ case BEAM_LAVA:
+ objs_vulnerable = OBJ_SCROLLS;
+ break;
+ case BEAM_COLD:
+ objs_vulnerable = OBJ_POTIONS;
+ break;
+ case BEAM_SPORE:
+ objs_vulnerable = OBJ_FOOD;
+ break;
+ }
+
+ if (stricmp(beam.beam_name, "hellfire") == 0)
+ objs_vulnerable = OBJ_SCROLLS;
+
+ if (igrd[x][y] != NON_ITEM)
+ {
+ if (objs_vulnerable != -1 &&
+ mitm[igrd[x][y]].base_type == objs_vulnerable)
+ {
+ destroy_item( igrd[ x ][ y ] );
+
+ if (objs_vulnerable == OBJ_SCROLLS && see_grid(x,y))
+ {
+ mpr("You see a puff of smoke.");
+ }
+
+ if (objs_vulnerable == OBJ_POTIONS && !silenced(x,y)
+ && !silenced(you.x_pos, you.y_pos))
+ {
+ mpr("You hear glass shatter.");
+ }
+ }
+ }
+}
+
+// A little helper function to handle the calling of ouch()...
+static void beam_ouch( int dam, struct bolt &beam )
+{
+ // The order of this is important.
+ if (YOU_KILL( beam.thrower ) && !beam.aux_source)
+ {
+ ouch( dam, 0, KILLED_BY_TARGETTING );
+ }
+ else if (MON_KILL( beam.thrower ))
+ {
+ if (beam.flavour == BEAM_SPORE)
+ ouch( dam, beam.beam_source, KILLED_BY_SPORE );
+ else
+ ouch( dam, beam.beam_source, KILLED_BY_BEAM, beam.aux_source );
+ }
+ else // KILL_MISC || (YOU_KILL && aux_source)
+ {
+ ouch( dam, beam.beam_source, KILLED_BY_WILD_MAGIC, beam.aux_source );
+ }
+}
+
+// return amount of extra range used up by affectation of the player
+static int affect_player( struct bolt &beam )
+{
+ int beamHit;
+
+ // digging -- don't care.
+ if (beam.flavour == BEAM_DIGGING)
+ return (0);
+
+ // check for tracer
+ if (beam.isTracer)
+ {
+ // check can see player
+ // XXX: note the cheat to allow for ME_ALERT to target the player...
+ // replace this with a time since alert system, rather than just
+ // peeking to see if the character is still there. -- bwr
+ if (beam.canSeeInvis || !you.invis
+ || (you.x_pos == beam.target_x && you.y_pos == beam.target_y))
+ {
+ if (beam.isFriendly)
+ {
+ beam.fr_count += 1;
+ beam.fr_power += you.experience_level;
+ }
+ else
+ {
+ beam.foe_count += 1;
+ beam.foe_power += you.experience_level;
+ }
+ }
+ return (range_used_on_hit(beam));
+ }
+
+ // BEGIN real beam code
+ beam.msgGenerated = true;
+
+ // use beamHit, NOT beam.hit, for modification of tohit.. geez!
+ beamHit = beam.hit;
+
+ if (beam.beam_name[0] != '0')
+ {
+ if (!beam.isExplosion && !beam.aimedAtFeet)
+ {
+ // BEGIN BEAM/MISSILE
+ int dodge = random2limit( player_evasion(), 40 )
+ + random2( you.dex ) / 3 - 2;
+
+ if (beam.isBeam)
+ {
+ // beams can be dodged
+ if (player_light_armour()
+ && !beam.aimedAtFeet && coinflip())
+ {
+ exercise(SK_DODGING, 1);
+ }
+
+ if (you.duration[DUR_REPEL_MISSILES]
+ || you.mutation[MUT_REPULSION_FIELD] == 3)
+ {
+ beamHit -= random2(beamHit / 2);
+ }
+
+ if (you.duration[DUR_DEFLECT_MISSILES])
+ beamHit = random2(beamHit / 3);
+
+ if (beamHit < dodge)
+ {
+ strcpy(info, "The ");
+ strcat(info, beam.beam_name);
+ strcat(info, " misses you.");
+ mpr(info);
+ return (0); // no extra used by miss!
+ }
+ }
+ else
+ {
+ // non-beams can be blocked or dodged
+ if (you.equip[EQ_SHIELD] != -1
+ && !beam.aimedAtFeet
+ && player_shield_class() > 0)
+ {
+ int exer = one_chance_in(3) ? 1 : 0;
+ const int hit = random2( beam.hit * 5
+ + 10 * you.shield_blocks * you.shield_blocks );
+
+ const int block = random2(player_shield_class())
+ + (random2(you.dex) / 5) - 1;
+
+ if (hit < block)
+ {
+ you.shield_blocks++;
+ snprintf( info, INFO_SIZE, "You block the %s.",
+ beam.beam_name );
+ mpr( info );
+
+ exercise( SK_SHIELDS, exer + 1 );
+ return (BEAM_STOP);
+ }
+
+ // some training just for the "attempt"
+ exercise( SK_SHIELDS, exer );
+ }
+
+ if (player_light_armour() && !beam.aimedAtFeet
+ && coinflip())
+ exercise(SK_DODGING, 1);
+
+ if (you.duration[DUR_REPEL_MISSILES]
+ || you.mutation[MUT_REPULSION_FIELD] == 3)
+ {
+ beamHit = random2(beamHit);
+ }
+
+
+ // miss message
+ if (beamHit < dodge || you.duration[DUR_DEFLECT_MISSILES])
+ {
+ strcpy(info, "The ");
+ strcat(info, beam.beam_name);
+ strcat(info, " misses you.");
+ return (0);
+ }
+ }
+ }
+ }
+ else
+ {
+ // BEGIN enchantment beam
+ if (beam.flavour != BEAM_HASTE
+ && beam.flavour != BEAM_INVISIBILITY
+ && beam.flavour != BEAM_HEALING
+ && ((beam.flavour != BEAM_TELEPORT && beam.flavour != BEAM_BANISH)
+ || !beam.aimedAtFeet)
+ && you_resist_magic( beam.ench_power ))
+ {
+ canned_msg(MSG_YOU_RESIST);
+ return (range_used_on_hit(beam));
+ }
+
+ // these colors are misapplied - see mons_ench_f2() {dlb}
+ switch (beam.flavour)
+ {
+ case BEAM_SLOW:
+ potion_effect( POT_SLOWING, beam.ench_power );
+ beam.obviousEffect = true;
+ break; // slow
+
+ case BEAM_HASTE:
+ potion_effect( POT_SPEED, beam.ench_power );
+ contaminate_player( 1 );
+ beam.obviousEffect = true;
+ break; // haste
+
+ case BEAM_HEALING:
+ potion_effect( POT_HEAL_WOUNDS, beam.ench_power );
+ beam.obviousEffect = true;
+ break; // heal (heal wounds potion eff)
+
+ case BEAM_PARALYSIS:
+ potion_effect( POT_PARALYSIS, beam.ench_power );
+ beam.obviousEffect = true;
+ break; // paralysis
+
+ case BEAM_CONFUSION:
+ potion_effect( POT_CONFUSION, beam.ench_power );
+ beam.obviousEffect = true;
+ break; // confusion
+
+ case BEAM_INVISIBILITY:
+ potion_effect( POT_INVISIBILITY, beam.ench_power );
+ contaminate_player( 1 + random2(2) );
+ beam.obviousEffect = true;
+ break; // invisibility
+
+ // 6 is used by digging
+
+ case BEAM_TELEPORT:
+ you_teleport();
+ beam.obviousEffect = true;
+ break;
+
+ case BEAM_POLYMORPH:
+ mpr("This is polymorph other only!");
+ beam.obviousEffect = true;
+ break;
+
+ case BEAM_CHARM:
+ potion_effect( POT_CONFUSION, beam.ench_power );
+ beam.obviousEffect = true;
+ break; // enslavement - confusion?
+
+ case BEAM_BANISH:
+ if (you.level_type == LEVEL_ABYSS)
+ {
+ mpr("You feel trapped.");
+ break;
+ }
+ mpr("You are cast into the Abyss!");
+ more();
+ banished(DNGN_ENTER_ABYSS);
+ beam.obviousEffect = true;
+ break; // banishment to the abyss
+
+ case BEAM_PAIN: // pain
+ if (you.is_undead || you.mutation[MUT_TORMENT_RESISTANCE])
+ {
+ mpr("You are unaffected.");
+ break;
+ }
+
+ mpr("Pain shoots through your body!");
+
+ if (!beam.aux_source)
+ beam.aux_source = "by nerve-wracking pain";
+
+ beam_ouch( roll_dice( beam.damage ), beam );
+ beam.obviousEffect = true;
+ break;
+
+ case BEAM_DISPEL_UNDEAD:
+ if (!you.is_undead)
+ {
+ mpr("You are unaffected.");
+ break;
+ }
+
+ mpr( "You convulse!" );
+
+ if (!beam.aux_source)
+ beam.aux_source = "by dispel undead";
+
+ beam_ouch( roll_dice( beam.damage ), beam );
+ beam.obviousEffect = true;
+ break;
+
+ case BEAM_DISINTEGRATION:
+ mpr("You are blasted!");
+
+ if (!beam.aux_source)
+ beam.aux_source = "disintegration bolt";
+
+ beam_ouch( roll_dice( beam.damage ), beam );
+ beam.obviousEffect = true;
+ break;
+
+ default:
+ // _all_ enchantments should be enumerated here!
+ mpr("Software bugs nibble your toes!");
+ break;
+ } // end of switch (beam.colour)
+
+ // regardless of affect, we need to know if this is a stopper
+ // or not - it seems all of the above are.
+ return (range_used_on_hit(beam));
+
+ // END enchantment beam
+ }
+
+ // THE BEAM IS NOW GUARANTEED TO BE A NON-ENCHANTMENT WHICH HIT
+
+ snprintf( info, INFO_SIZE, "The %s %s you!",
+ beam.beam_name, (beam.isExplosion ? "engulfs" : "hits") );
+ mpr( info );
+
+ int hurted = 0;
+ int burn_power = (beam.isExplosion) ? 5 : ((beam.isBeam) ? 3 : 2);
+
+ // Roll the damage
+ hurted += roll_dice( beam.damage );
+
+#if DEBUG_DIAGNOSTICS
+ int roll = hurted;
+#endif
+
+ hurted -= random2( 1 + player_AC() );
+
+
+ // shrapnel
+ if (beam.flavour == BEAM_FRAG && !player_light_armour())
+ {
+ hurted -= random2( 1 + player_AC() );
+ hurted -= random2( 1 + player_AC() );
+ }
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "Player damage: rolled=%d; after AC=%d",
+ roll, hurted );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ if (you.equip[EQ_BODY_ARMOUR] != -1)
+ {
+ if (!player_light_armour() && one_chance_in(4)
+ && random2(1000) <= mass_item( you.inv[you.equip[EQ_BODY_ARMOUR]] ))
+ {
+ exercise( SK_ARMOUR, 1 );
+ }
+ }
+
+ if (hurted < 0)
+ hurted = 0;
+
+ hurted = check_your_resists( hurted, beam.flavour );
+
+ // poisoning
+ if (strstr(beam.beam_name, "poison") != NULL
+ && beam.flavour != BEAM_POISON
+ && beam.flavour != BEAM_POISON_ARROW
+ && !player_res_poison())
+ {
+ if (hurted || (strstr( beam.beam_name, "needle" ) != NULL
+ && random2(100) < 90 - (3 * player_AC())))
+ {
+ poison_player( 1 + random2(3) );
+ }
+ }
+
+ // sticky flame
+ if (strcmp(beam.beam_name, "sticky flame") == 0
+ && (you.species != SP_MOTTLED_DRACONIAN
+ || you.experience_level < 6))
+ {
+ if (!player_equip( EQ_BODY_ARMOUR, ARM_MOTTLED_DRAGON_ARMOUR ))
+ you.duration[DUR_LIQUID_FLAMES] += random2avg(7, 3) + 1;
+ }
+
+ // simple cases for scroll burns
+ if (beam.flavour == BEAM_LAVA || stricmp(beam.beam_name, "hellfire") == 0)
+ scrolls_burn( burn_power, OBJ_SCROLLS );
+
+ // more complex (geez..)
+ if (beam.flavour == BEAM_FIRE && strcmp(beam.beam_name, "ball of steam") != 0)
+ scrolls_burn( burn_power, OBJ_SCROLLS );
+
+ // potions exploding
+ if (beam.flavour == BEAM_COLD)
+ scrolls_burn( burn_power, OBJ_POTIONS );
+
+ if (beam.flavour == BEAM_ACID)
+ splash_with_acid(5);
+
+ // spore pops
+ if (beam.isExplosion && beam.flavour == BEAM_SPORE)
+ scrolls_burn( 2, OBJ_FOOD );
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "Damage: %d", hurted );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ beam_ouch( hurted, beam );
+
+ return (range_used_on_hit( beam ));
+}
+
+// return amount of range used up by affectation of this monster
+static int affect_monster(struct bolt &beam, struct monsters *mon)
+{
+ int tid = mgrd[mon->x][mon->y];
+ int hurt;
+ int hurt_final;
+
+ // digging -- don't care.
+ if (beam.flavour == BEAM_DIGGING)
+ return (0);
+
+ // fire storm creates these, so we'll avoid affecting them
+ if (strcmp(beam.beam_name, "great blast of fire") == 0
+ && mon->type == MONS_FIRE_VORTEX)
+ {
+ return (0);
+ }
+
+ // check for tracer
+ if (beam.isTracer)
+ {
+ // check can see other monster
+ if (!beam.canSeeInvis && mons_has_ench(&menv[tid], ENCH_INVIS))
+ {
+ // can't see this monster, ignore it
+ return 0;
+ }
+ }
+
+ if (beam.beam_name[0] == '0')
+ {
+ if (beam.isTracer)
+ {
+ // enchant case -- enchantments always hit, so update target immed.
+ if (beam.isFriendly ^ mons_friendly(mon))
+ {
+ beam.foe_count += 1;
+ beam.foe_power += mons_power(tid);
+ }
+ else
+ {
+ beam.fr_count += 1;
+ beam.fr_power += mons_power(tid);
+ }
+
+ return (range_used_on_hit(beam));
+ }
+
+ // BEGIN non-tracer enchantment
+
+ // nasty enchantments will annoy the monster, and are considered
+ // naughty (even if a monster might resist)
+ if (nasty_beam(mon, beam))
+ {
+ if (mons_friendly(mon) && YOU_KILL(beam.thrower))
+ naughty(NAUGHTY_ATTACK_FRIEND, 5);
+
+ behaviour_event( mon, ME_ANNOY,
+ MON_KILL(beam.thrower) ? beam.beam_source : MHITYOU );
+ }
+ else
+ {
+ behaviour_event( mon, ME_ALERT,
+ MON_KILL(beam.thrower) ? beam.beam_source : MHITYOU );
+ }
+
+ // !@#*( affect_monster_enchantment() has side-effects on
+ // the beam structure which screw up range_used_on_hit(),
+ // so call it now and store.
+ int rangeUsed = range_used_on_hit(beam);
+
+ // now do enchantment affect
+ int ench_result = affect_monster_enchantment(beam, mon);
+ switch(ench_result)
+ {
+ case MON_RESIST:
+ if (simple_monster_message(mon, " resists."))
+ beam.msgGenerated = true;
+ break;
+ case MON_UNAFFECTED:
+ if (simple_monster_message(mon, " is unaffected."))
+ beam.msgGenerated = true;
+ break;
+ default:
+ break;
+ }
+ return (rangeUsed);
+
+ // END non-tracer enchantment
+ }
+
+
+ // BEGIN non-enchantment (could still be tracer)
+ if (mons_has_ench( mon, ENCH_SUBMERGED ) && !beam.aimedAtFeet)
+ return (0); // missed me!
+
+ // we need to know how much the monster _would_ be hurt by this, before
+ // we decide if it actually hits.
+
+ // Roll the damage:
+ hurt = roll_dice( beam.damage );
+
+ hurt_final = hurt;
+
+ if (beam.isTracer)
+ hurt_final -= mon->armour_class / 2;
+ else
+ hurt_final -= random2(1 + mon->armour_class);
+
+ if (beam.flavour == BEAM_FRAG)
+ {
+ hurt_final -= random2(1 + mon->armour_class);
+ hurt_final -= random2(1 + mon->armour_class);
+ }
+
+ if (hurt_final < 1)
+ {
+ hurt_final = 0;
+ }
+
+#if DEBUG_DIAGNOSTICS
+ const int old_hurt = hurt_final;
+#endif
+
+ // check monster resists, _without_ side effects (since the
+ // beam/missile might yet miss!)
+ hurt_final = mons_adjust_flavoured( mon, beam, hurt_final, false );
+
+#if DEBUG_DIAGNOSTICS
+ if (!beam.isTracer)
+ {
+ snprintf( info, INFO_SIZE,
+ "Monster: %s; Damage: pre-AC: %d; post-AC: %d; post-resist: %d",
+ ptr_monam( mon, DESC_PLAIN ), hurt, old_hurt, hurt_final );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+ }
+#endif
+
+ // now, we know how much this monster would (probably) be
+ // hurt by this beam.
+ if (beam.isTracer)
+ {
+ if (hurt_final != 0)
+ {
+ // monster could be hurt somewhat, but only apply the
+ // monster's power based on how badly it is affected.
+ // For example, if a fire giant (power 16) threw a
+ // fireball at another fire giant, and it only took
+ // 1/3 damage, then power of 5 would be applied to
+ // foe_power or fr_power.
+ if (beam.isFriendly ^ mons_friendly(mon))
+ {
+ beam.foe_count += 1;
+ beam.foe_power += hurt_final * mons_power(tid) / hurt;
+ }
+ else
+ {
+ beam.fr_count += 1;
+ beam.fr_power += hurt_final * mons_power(tid) / hurt;
+ }
+ }
+ // either way, we could hit this monster, so return range used
+ return (range_used_on_hit(beam));
+ }
+ // END non-enchantment (could still be tracer)
+
+ // BEGIN real non-enchantment beam
+
+ // player beams which hit friendly MIGHT annoy them and be considered
+ // naughty if they do much damage (this is so as not to penalize
+ // players that fling fireballs into a melee with fire elementals
+ // on their side - the elementals won't give a sh*t, after all)
+
+ if (nasty_beam(mon, beam))
+ {
+ // could be naughty if it's your beam & the montster is friendly
+ if (mons_friendly(mon) && YOU_KILL(beam.thrower))
+ {
+ // but did you do enough damage to piss them off?
+ if (hurt_final > mon->hit_dice / 3)
+ {
+ naughty(NAUGHTY_ATTACK_FRIEND, 5);
+ behaviour_event( mon, ME_ANNOY, MHITYOU );
+ }
+ }
+ else
+ {
+ behaviour_event(mon, ME_ANNOY,
+ MON_KILL(beam.thrower) ? beam.beam_source : MHITYOU );
+ }
+ }
+
+ // explosions always 'hit'
+ if (!beam.isExplosion && beam.hit < random2(mon->evasion))
+ {
+ // if the PLAYER cannot see the monster, don't tell them anything!
+ if (player_monster_visible( &menv[tid] ) && mons_near(mon))
+ {
+ strcpy(info, "The ");
+ strcat(info, beam.beam_name);
+ strcat(info, " misses ");
+ strcat(info, ptr_monam(mon, DESC_NOCAP_THE));
+ strcat(info, ".");
+ mpr(info);
+ }
+ return (0);
+ }
+
+ // the beam hit.
+ if (mons_near(mon))
+ {
+ strcpy(info, "The ");
+ strcat(info, beam.beam_name);
+ strcat(info, beam.isExplosion?" engulfs ":" hits ");
+
+ if (player_monster_visible( &menv[tid] ))
+ strcat(info, ptr_monam(mon, DESC_NOCAP_THE));
+ else
+ strcat(info, "something");
+
+ strcat(info, ".");
+ mpr(info);
+ }
+ else
+ {
+ // the player might hear something,
+ // if _they_ fired a missile (not beam)
+ if (!silenced(you.x_pos, you.y_pos) && beam.flavour == BEAM_MISSILE
+ && YOU_KILL(beam.thrower))
+ {
+ strcpy(info, "The ");
+ strcat(info, beam.beam_name);
+ strcat(info, " hits something.");
+ mpr(info);
+ }
+ }
+
+ // note that hurt_final was calculated above, so we don't need it again.
+ // just need to apply flavoured specials (since we called with
+ // doFlavouredEffects = false above)
+ hurt_final = mons_adjust_flavoured(mon, beam, hurt_final);
+
+ // now hurt monster
+ hurt_monster( mon, hurt_final );
+
+ int thrower = YOU_KILL(beam.thrower) ? KILL_YOU_MISSILE : KILL_MON_MISSILE;
+
+ if (mon->hit_points < 1)
+ {
+ monster_die(mon, thrower, beam.beam_source);
+ }
+ else
+ {
+ if (thrower == KILL_YOU_MISSILE && mons_near(mon))
+ print_wounds(mon);
+
+ // sticky flame
+ if (strcmp(beam.beam_name, "sticky flame") == 0)
+ {
+ int levels = 1 + random2( hurt_final ) / 2;
+ if (levels > 4)
+ levels = 4;
+
+ sticky_flame_monster( tid, YOU_KILL(beam.thrower), levels );
+ }
+
+
+ /* looks for missiles which aren't poison but
+ are poison*ed* */
+ if (strstr(beam.beam_name, "poison") != NULL
+ && beam.flavour != BEAM_POISON
+ && beam.flavour != BEAM_POISON_ARROW)
+ {
+ if (strstr(beam.beam_name, "needle") != NULL
+ && random2(100) < 90 - (3 * mon->armour_class))
+ {
+ poison_monster( mon, YOU_KILL(beam.thrower), 2 );
+ }
+ else if (random2(hurt_final) - random2(mon->armour_class) > 0)
+ {
+ poison_monster( mon, YOU_KILL(beam.thrower) );
+ }
+ }
+
+ if (mons_is_mimic( mon->type ))
+ mimic_alert(mon);
+ }
+
+ return (range_used_on_hit(beam));
+}
+
+static int affect_monster_enchantment(struct bolt &beam, struct monsters *mon)
+{
+ if (beam.flavour == BEAM_TELEPORT) // teleportation
+ {
+ if (check_mons_resist_magic( mon, beam.ench_power )
+ && !beam.aimedAtFeet)
+ {
+ return (MON_RESIST);
+ }
+
+ if (simple_monster_message(mon, " looks slightly unstable."))
+ beam.obviousEffect = true;
+
+ monster_teleport(mon, false);
+
+ return (MON_AFFECTED);
+ }
+
+ if (beam.flavour == BEAM_POLYMORPH)
+ {
+ if (mons_holiness( mon->type ) != MH_NATURAL)
+ return (MON_UNAFFECTED);
+
+ if (check_mons_resist_magic( mon, beam.ench_power ))
+ return (MON_RESIST);
+
+ if (monster_polymorph(mon, RANDOM_MONSTER, 100))
+ beam.obviousEffect = true;
+
+ return (MON_AFFECTED);
+ }
+
+ if (beam.flavour == BEAM_BANISH)
+ {
+ if (check_mons_resist_magic( mon, beam.ench_power ))
+ return (MON_RESIST);
+
+ if (you.level_type == LEVEL_ABYSS)
+ {
+ simple_monster_message(mon, " wobbles for a moment.");
+ }
+ else
+ monster_die(mon, KILL_RESET, beam.beam_source);
+
+ beam.obviousEffect = true;
+ return (MON_AFFECTED);
+ }
+
+ if (beam.flavour == BEAM_DEGENERATE)
+ {
+ if (mons_holiness(mon->type) != MH_NATURAL
+ || mon->type == MONS_PULSATING_LUMP)
+ {
+ return (MON_UNAFFECTED);
+ }
+
+ if (check_mons_resist_magic( mon, beam.ench_power ))
+ return (MON_RESIST);
+
+ if (monster_polymorph(mon, MONS_PULSATING_LUMP, 100))
+ beam.obviousEffect = true;
+
+ return (MON_AFFECTED);
+ }
+
+ if (beam.flavour == BEAM_DISPEL_UNDEAD)
+ {
+ if (mons_holiness(mon->type) != MH_UNDEAD)
+ return (MON_UNAFFECTED);
+
+ if (simple_monster_message(mon, " convulses!"))
+ beam.obviousEffect = true;
+
+ hurt_monster( mon, roll_dice( beam.damage ) );
+
+ goto deathCheck;
+ }
+
+ if (beam.flavour == BEAM_ENSLAVE_UNDEAD
+ && mons_holiness(mon->type) == MH_UNDEAD)
+ {
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "HD: %d; pow: %d",
+ mon->hit_dice, beam.ench_power );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ if (check_mons_resist_magic( mon, beam.ench_power ))
+ return (MON_RESIST);
+
+ simple_monster_message(mon, " is enslaved.");
+ beam.obviousEffect = true;
+
+ // wow, permanent enslaving
+ mon->attitude = ATT_FRIENDLY;
+ return (MON_AFFECTED);
+ }
+
+ if (beam.flavour == BEAM_ENSLAVE_DEMON
+ && mons_holiness(mon->type) == MH_DEMONIC)
+ {
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "HD: %d; pow: %d",
+ mon->hit_dice, beam.ench_power );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ if (mon->hit_dice * 4 >= random2(beam.ench_power))
+ return (MON_RESIST);
+
+ simple_monster_message(mon, " is enslaved.");
+ beam.obviousEffect = true;
+
+ // wow, permanent enslaving
+ mon->attitude = ATT_FRIENDLY;
+ return (MON_AFFECTED);
+ }
+
+ //
+ // Everything past this point must pass this magic resistance test.
+ //
+ // Using check_mons_resist_magic here since things like disintegrate
+ // are beyond this point. -- bwr
+ if (check_mons_resist_magic( mon, beam.ench_power )
+ && beam.flavour != BEAM_HASTE
+ && beam.flavour != BEAM_HEALING
+ && beam.flavour != BEAM_INVISIBILITY)
+ {
+ return (MON_RESIST);
+ }
+
+ if (beam.flavour == BEAM_PAIN) /* pain/agony */
+ {
+ if (mons_res_negative_energy( mon ))
+ return (MON_UNAFFECTED);
+
+ if (simple_monster_message(mon, " convulses in agony!"))
+ beam.obviousEffect = true;
+
+ if (strstr( beam.beam_name, "agony" ) != NULL)
+ {
+ // AGONY
+ mon->hit_points = mon->hit_points / 2;
+
+ if (mon->hit_points < 1)
+ mon->hit_points = 1;
+ }
+ else
+ {
+ // PAIN
+ hurt_monster( mon, roll_dice( beam.damage ) );
+ }
+
+ goto deathCheck;
+ }
+
+ if (beam.flavour == BEAM_DISINTEGRATION) /* disrupt/disintegrate */
+ {
+ if (simple_monster_message(mon, " is blasted."))
+ beam.obviousEffect = true;
+
+ hurt_monster( mon, roll_dice( beam.damage ) );
+
+ goto deathCheck;
+ }
+
+
+ if (beam.flavour == BEAM_SLEEP)
+ {
+ if (mons_has_ench( mon, ENCH_SLEEP_WARY )) // slept recently
+ return (MON_RESIST);
+
+ if (mons_holiness(mon->type) != MH_NATURAL) // no unnatural
+ return (MON_UNAFFECTED);
+
+ if (simple_monster_message(mon, " looks drowsy..."))
+ beam.obviousEffect = true;
+
+ mon->behaviour = BEH_SLEEP;
+ mons_add_ench( mon, ENCH_SLEEP_WARY );
+
+ return (MON_AFFECTED);
+ }
+
+ if (beam.flavour == BEAM_BACKLIGHT)
+ {
+ if (backlight_monsters(mon->x, mon->y, beam.hit, 0))
+ {
+ beam.obviousEffect = true;
+ return (MON_AFFECTED);
+ }
+ return (MON_UNAFFECTED);
+ }
+
+ // everything else?
+ return (mons_ench_f2(mon, beam));
+
+deathCheck:
+
+ int thrower = KILL_YOU_MISSILE;
+ if (MON_KILL(beam.thrower))
+ thrower = KILL_MON_MISSILE;
+
+ if (mon->hit_points < 1)
+ monster_die(mon, thrower, beam.beam_source);
+ else
+ {
+ print_wounds(mon);
+
+ if (mons_is_mimic( mon->type ))
+ mimic_alert(mon);
+ }
+
+ return (MON_AFFECTED);
+}
+
+
+// extra range used on hit
+static int range_used_on_hit(struct bolt &beam)
+{
+ // non-beams can only affect one thing (player/monster)
+ if (!beam.isBeam)
+ return (BEAM_STOP);
+
+ // CHECK ENCHANTMENTS
+ if (beam.beam_name[0] == '0')
+ {
+ switch(beam.flavour)
+ {
+ case BEAM_SLOW:
+ case BEAM_HASTE:
+ case BEAM_HEALING:
+ case BEAM_PARALYSIS:
+ case BEAM_CONFUSION:
+ case BEAM_INVISIBILITY:
+ case BEAM_TELEPORT:
+ case BEAM_POLYMORPH:
+ case BEAM_CHARM:
+ case BEAM_BANISH:
+ case BEAM_PAIN:
+ case BEAM_DISINTEGRATION:
+ case BEAM_DEGENERATE:
+ case BEAM_DISPEL_UNDEAD:
+ case BEAM_ENSLAVE_UNDEAD:
+ case BEAM_ENSLAVE_DEMON:
+ case BEAM_SLEEP:
+ case BEAM_BACKLIGHT:
+ return (BEAM_STOP);
+ default:
+ break;
+ }
+
+ return (0);
+ }
+
+ // hellfire stops for nobody!
+ if (strcmp( beam.beam_name, "hellfire" ) == 0)
+ return (0);
+
+ // generic explosion
+ if (beam.flavour == BEAM_EXPLOSION)
+ return (BEAM_STOP);
+
+ // plant spit
+ if (beam.flavour == BEAM_ACID)
+ return (BEAM_STOP);
+
+ // lava doesn't go far, but it goes through most stuff
+ if (beam.flavour == BEAM_LAVA)
+ return (1);
+
+ // If it isn't lightning, reduce range by a lot
+ if (beam.flavour != BEAM_ELECTRICITY)
+ return (random2(4) + 2);
+
+ return (0);
+}
+
+/*
+ Takes a bolt struct and refines it for use in the explosion function. Called
+ from missile() and beam() in beam.cc. Explosions which do not follow from
+ beams (eg scrolls of immolation) bypass this function.
+ */
+static void explosion1(struct bolt &pbolt)
+{
+ int ex_size = 1;
+ // convenience
+ int x = pbolt.target_x;
+ int y = pbolt.target_y;
+ const char *seeMsg = NULL;
+ const char *hearMsg = NULL;
+
+ // assume that the player can see/hear the explosion, or
+ // gets burned by it anyway. :)
+ pbolt.msgGenerated = true;
+
+ if (stricmp(pbolt.beam_name, "hellfire") == 0)
+ {
+ seeMsg = "The hellfire explodes!";
+ hearMsg = "You hear a strangely unpleasant explosion.";
+
+ pbolt.type = SYM_BURST;
+ pbolt.flavour = BEAM_HELLFIRE;
+ }
+
+ if (stricmp(pbolt.beam_name, "golden flame") == 0)
+ {
+ seeMsg = "The flame explodes!";
+ hearMsg = "You hear a strange explosion.";
+
+ pbolt.type = SYM_BURST;
+ pbolt.flavour = BEAM_HOLY; // same as golden flame? [dlb]
+ }
+
+ if (stricmp(pbolt.beam_name, "fireball") == 0)
+ {
+ seeMsg = "The fireball explodes!";
+ hearMsg = "You hear an explosion.";
+
+ pbolt.type = SYM_BURST;
+ pbolt.flavour = BEAM_FIRE;
+ ex_size = 1;
+ }
+
+ if (stricmp(pbolt.beam_name, "orb of electricity") == 0)
+ {
+ seeMsg = "The orb of electricity explodes!";
+ hearMsg = "You hear a clap of thunder!";
+
+ pbolt.type = SYM_BURST;
+ pbolt.flavour = BEAM_ELECTRICITY;
+ pbolt.colour = LIGHTCYAN;
+ pbolt.damage.num = 1;
+ ex_size = 2;
+ }
+
+ if (stricmp(pbolt.beam_name, "orb of energy") == 0)
+ {
+ seeMsg = "The orb of energy explodes.";
+ hearMsg = "You hear an explosion.";
+ }
+
+ if (stricmp(pbolt.beam_name, "metal orb") == 0)
+ {
+ seeMsg = "The orb explodes into a blast of deadly shrapnel!";
+ hearMsg = "You hear an explosion!";
+
+ strcpy(pbolt.beam_name, "blast of shrapnel");
+ pbolt.type = SYM_ZAP;
+ pbolt.flavour = BEAM_FRAG; // sets it from pure damage to shrapnel (which is absorbed extra by armour)
+ }
+
+ if (stricmp(pbolt.beam_name, "great blast of cold") == 0)
+ {
+ seeMsg = "The blast explodes into a great storm of ice!";
+ hearMsg = "You hear a raging storm!";
+
+ strcpy(pbolt.beam_name, "ice storm");
+ pbolt.damage.num = 6;
+ pbolt.type = SYM_ZAP;
+ pbolt.colour = WHITE;
+ ex_size = 2 + (random2( pbolt.ench_power ) > 75);
+ }
+
+ if (stricmp(pbolt.beam_name, "ball of vapour") == 0)
+ {
+ seeMsg = "The ball expands into a vile cloud!";
+ hearMsg = "You hear a gentle \'poof\'.";
+ strcpy(pbolt.beam_name, "stinking cloud");
+ }
+
+ if (stricmp(pbolt.beam_name, "potion") == 0)
+ {
+ seeMsg = "The potion explodes!";
+ hearMsg = "You hear an explosion!";
+ strcpy(pbolt.beam_name, "cloud");
+ }
+
+ if (seeMsg == NULL)
+ {
+ seeMsg = "The beam explodes into a cloud of software bugs!";
+ hearMsg = "You hear the sound of one hand clapping!";
+ }
+
+
+ if (!pbolt.isTracer)
+ {
+ // check for see/hear/no msg
+ if (see_grid(x,y) || (x == you.x_pos && y == you.y_pos))
+ mpr(seeMsg);
+ else
+ {
+ if (!(silenced(x,y) || silenced(you.x_pos, you.y_pos)))
+ mpr(hearMsg);
+ else
+ pbolt.msgGenerated = false;
+ }
+ }
+
+ pbolt.ex_size = ex_size;
+ explosion( pbolt );
+} // end explosion1()
+
+
+#define MAX_EXPLOSION_RADIUS 9
+
+// explosion is considered to emanate from beam->target_x, target_y
+// and has a radius equal to ex_size. The explosion will respect
+// boundaries like walls, but go through/around statues/idols/etc.
+
+// for each cell affected by the explosion, affect() is called.
+
+void explosion( struct bolt &beam, bool hole_in_the_middle )
+{
+ int r = beam.ex_size;
+
+ // beam is now an explosion; set isExplosion.
+ beam.isExplosion = true;
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE,
+ "explosion at (%d, %d) : t=%d c=%d f=%d hit=%d dam=%dd%d",
+ beam.target_x, beam.target_y,
+ beam.type, beam.colour, beam.flavour,
+ beam.hit, beam.damage.num, beam.damage.size );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ // for now, we don't support explosions greater than 9 radius
+ if (r > MAX_EXPLOSION_RADIUS)
+ r = MAX_EXPLOSION_RADIUS;
+
+ // make a noise
+ noisy( 10 + 5*r, beam.target_x, beam.target_y );
+
+ // set map to false
+ for (int i=0; i<19; i++)
+ {
+ for (int j=0; j<19; j++)
+ explode_map[i][j] = false;
+ }
+
+ // discover affected cells - recursion is your friend!
+ // this is done to model an explosion's behaviour around
+ // corners where a simple 'line of sight' isn't quite
+ // enough. This might be slow for really big explosions,
+ // as the recursion runs approximately as R^2
+ explosion_map(beam, 0, 0, 0, 0, r);
+
+ // go through affected cells, drawing effect and
+ // calling affect() and affect_items() for each.
+ // now, we get a bit fancy, drawing all radius 0
+ // effects, then radius 1, radius 2, etc. It looks
+ // a bit better that way.
+
+ // turn buffering off
+#ifdef WIN32CONSOLE
+ bool oldValue;
+ if (!beam.isTracer)
+ oldValue = setBuffering(false);
+#endif
+
+ // --------------------- begin boom ---------------
+
+ bool drawing = true;
+ for (int i = 0; i < 2; i++)
+ {
+ // do center -- but only if its affected
+ if (!hole_in_the_middle)
+ explosion_cell(beam, 0, 0, drawing);
+
+ // do the rest of it
+ for(int rad = 1; rad <= r; rad ++)
+ {
+ // do sides
+ for (int ay = 1 - rad; ay <= rad - 1; ay += 1)
+ {
+ if (explode_map[-rad+9][ay+9])
+ explosion_cell(beam, -rad, ay, drawing);
+
+ if (explode_map[rad+9][ay+9])
+ explosion_cell(beam, rad, ay, drawing);
+ }
+
+ // do top & bottom
+ for (int ax = -rad; ax <= rad; ax += 1)
+ {
+ if (explode_map[ax+9][-rad+9])
+ explosion_cell(beam, ax, -rad, drawing);
+
+ if (explode_map[ax+9][rad+9])
+ explosion_cell(beam, ax, rad, drawing);
+ }
+
+ // new-- delay after every 'ring' {gdl}
+#ifdef LINUX
+ // If we don't refresh curses we won't
+ // guarantee that the explosion is visible
+ if (drawing)
+ update_screen();
+#endif
+ // only delay on real explosion
+ if (!beam.isTracer && drawing)
+ delay(50);
+ }
+
+ drawing = false;
+ }
+
+ // ---------------- end boom --------------------------
+
+#ifdef WIN32CONSOLE
+ if (!beam.isTracer)
+ setBuffering(oldValue);
+#endif
+
+ // duplicate old behaviour - pause after entire explosion
+ // has been drawn.
+ if (!beam.isTracer)
+ more();
+}
+
+static void explosion_cell(struct bolt &beam, int x, int y, bool drawOnly)
+{
+ bool random_beam = false;
+ int realx = beam.target_x + x;
+ int realy = beam.target_y + y;
+
+ if (!drawOnly)
+ {
+ // random beams: randomize before affect
+ if (beam.flavour == BEAM_RANDOM)
+ {
+ random_beam = true;
+ beam.flavour = BEAM_FIRE + random2(7);
+ }
+
+ affect(beam, realx, realy);
+
+ if (random_beam)
+ beam.flavour = BEAM_RANDOM;
+ }
+
+ // early out for tracer
+ if (beam.isTracer)
+ return;
+
+ // now affect items
+ if (!drawOnly)
+ affect_items(beam, realx, realy);
+
+ if (drawOnly)
+ {
+ int drawx = realx - you.x_pos + 18;
+ int drawy = realy - you.y_pos + 9;
+
+ if (see_grid(realx, realy) || (realx == you.x_pos && realy == you.y_pos))
+ {
+ // bounds check
+ if (drawx > 8 && drawx < 26 && drawy > 0 && drawy < 18)
+ {
+ if (beam.colour == BLACK)
+ textcolor(random_colour());
+ else
+ textcolor(beam.colour);
+
+ gotoxy(drawx, drawy);
+ putch('#');
+ }
+ }
+ }
+}
+
+static void explosion_map( struct bolt &beam, int x, int y,
+ int count, int dir, int r )
+{
+ // 1. check to see out of range
+ if (x * x + y * y > r * r + r)
+ return;
+
+ // 2. check count
+ if (count > 10*r)
+ return;
+
+ // 3. check to see if we're blocked by something
+ // specifically, we're blocked by WALLS. Not
+ // statues, idols, etc.
+ int dngn_feat = grd[beam.target_x + x][beam.target_y + y];
+
+ // special case: explosion originates from rock/statue
+ // (e.g. Lee's rapid deconstruction) - in this case, ignore
+ // solid cells at the center of the explosion.
+ if (dngn_feat < DNGN_GREEN_CRYSTAL_WALL || dngn_feat == DNGN_WAX_WALL)
+ {
+ if (!(x==0 && y==0))
+ return;
+ }
+
+ // hmm, I think we're ok
+ explode_map[x+9][y+9] = true;
+
+ // now recurse in every direction except the one we
+ // came from
+ for(int i=0; i<4; i++)
+ {
+ if (i+1 != dir)
+ {
+ int cadd = 5;
+ if (x * spreadx[i] < 0 || y * spready[i] < 0)
+ cadd = 17;
+
+ explosion_map( beam, x + spreadx[i], y + spready[i],
+ count + cadd, opdir[i], r );
+ }
+ }
+}
+
+// returns true if the beam is harmful (ignoring monster
+// resists) -- mon is given for 'special' cases where,
+// for example, "Heal" might actually hurt undead, or
+// "Holy Word" being ignored by holy monsters, etc.
+//
+// only enchantments should need the actual monster type
+// to determine this; non-enchantments are pretty
+// straightforward.
+bool nasty_beam(struct monsters *mon, struct bolt &beam)
+{
+ // take care of non-enchantments
+ if (beam.beam_name[0] != '0')
+ return (true);
+
+ // now for some non-hurtful enchantments
+
+ // degeneration / sleep
+ if (beam.flavour == BEAM_DEGENERATE || beam.flavour == BEAM_SLEEP)
+ return (mons_holiness(mon->type) == MH_NATURAL);
+
+ // dispel undead / control undead
+ if (beam.flavour == BEAM_DISPEL_UNDEAD || beam.flavour == BEAM_ENSLAVE_UNDEAD)
+ return (mons_holiness(mon->type) == MH_UNDEAD);
+
+ // pain/agony
+ if (beam.flavour == BEAM_PAIN)
+ return (!mons_res_negative_energy( mon ));
+
+ // control demon
+ if (beam.flavour == BEAM_ENSLAVE_DEMON)
+ return (mons_holiness(mon->type) == MH_DEMONIC);
+
+ // haste
+ if (beam.flavour == BEAM_HASTE)
+ return (false);
+
+ // healing
+ if (beam.flavour == BEAM_HEALING || beam.flavour == BEAM_INVISIBILITY)
+ return (false);
+
+ // everything else is considered nasty by everyone
+ return (true);
+}
diff --git a/trunk/source/beam.h b/trunk/source/beam.h
new file mode 100644
index 0000000000..d2935843ec
--- /dev/null
+++ b/trunk/source/beam.h
@@ -0,0 +1,94 @@
+/*
+ * File: beam.cc
+ * Summary: Functions related to ranged attacks.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef BEAM_H
+#define BEAM_H
+
+
+#include "externs.h"
+
+dice_def calc_dice( int num_dice, int max_damage );
+
+
+/* ***********************************************************************
+ * called from: bang - it_use2 - monstuff - mstuff2
+ * *********************************************************************** */
+void fire_beam( struct bolt &pbolt, item_def *item = NULL );
+
+// last updated 19apr2001 {gdl}
+/* ***********************************************************************
+ * called from: beam
+ * *********************************************************************** */
+bool nasty_beam( struct monsters *mon, struct bolt &beam );
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - it_use3 - item_use - mstuff2 - religion -
+ * spells - spells4
+ * *********************************************************************** */
+void explosion( struct bolt &pbolt, bool hole_in_the_middle = false );
+
+
+// last updated 22jan2001 {gdl}
+/* ***********************************************************************
+ * called from: effects - spells2 - spells4
+ * *********************************************************************** */
+int mons_adjust_flavoured( struct monsters *monster, struct bolt &pbolt,
+ int hurted, bool doFlavouredEffects = true );
+
+
+/* ***********************************************************************
+ * called from: ability - item_use - spell
+ * returns true if messages were generated during the enchantment
+ * *********************************************************************** */
+bool mass_enchantment( int wh_enchant, int pow, int who );
+
+
+/* ***********************************************************************
+ * called from: fight - monstuff - mstuff2
+ * *********************************************************************** */
+int mons_ench_f2( struct monsters *monster, struct bolt &pbolt );
+
+
+/* ***********************************************************************
+ * called from: fight - monstuff - spells2
+ * *********************************************************************** */
+void poison_monster( struct monsters *monster, bool fromPlayer, int levels = 1,
+ bool force = false );
+
+
+/* ***********************************************************************
+ * called from: fight - monstuff - spells - spells1 - spells2
+ * *********************************************************************** */
+#if 0
+void delete_cloud( int cloud );
+void new_cloud( int cloud, int type, int x, int y, int decay );
+
+void place_cloud(unsigned char cl_type, unsigned char ctarget_x, unsigned char ctarget_y, unsigned char cl_range);
+#endif
+
+
+/* ***********************************************************************
+ * called from: monstuff
+ * *********************************************************************** */
+void fire_tracer( struct monsters *monster, struct bolt &pbolt );
+
+
+/* ***********************************************************************
+ * called from: monstuff
+ * *********************************************************************** */
+void mimic_alert( struct monsters *mimic );
+
+
+void zapping( char ztype, int power, struct bolt &pbolt );
+
+#endif
diff --git a/trunk/source/chardump.cc b/trunk/source/chardump.cc
new file mode 100644
index 0000000000..7131da279a
--- /dev/null
+++ b/trunk/source/chardump.cc
@@ -0,0 +1,893 @@
+/*
+ * File: chardump.cc
+ * Summary: Dumps character info out to the morgue file.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ *
+ * <4> 19 June 2000 GDL Changed handles to FILE *
+ * <3> 6/13/99 BWR Improved spell listing
+ * <2> 5/30/99 JDJ dump_spells dumps failure rates (from Brent).
+ * <1> 4/20/99 JDJ Reformatted, uses string objects, split out 7
+ * functions from dump_char, dumps artifact info.
+ */
+
+#include "AppHdr.h"
+#include "chardump.h"
+
+#include <string>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#if !(defined(__IBMCPP__) || defined(__BCPLUSPLUS__))
+#include <unistd.h>
+#endif
+#include <ctype.h>
+
+#ifdef USE_EMX
+#include <sys/types.h>
+#endif
+
+#ifdef OS9
+#include <stat.h>
+#else
+#include <sys/stat.h>
+#endif
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#include "externs.h"
+
+#include "debug.h"
+#include "describe.h"
+#include "itemname.h"
+#include "items.h"
+#include "macro.h"
+#include "mutation.h"
+#include "player.h"
+#include "religion.h"
+#include "shopping.h"
+#include "skills2.h"
+#include "spl-book.h"
+#include "spl-cast.h"
+#include "spl-util.h"
+#include "stuff.h"
+#include "version.h"
+
+
+ // ========================================================================
+ // Internal Functions
+ // ========================================================================
+
+ // fillstring() is a hack to get around a missing constructor in
+ // Borland C++ implementation of the STD basic_string. Argh!!!
+static std::string fillstring(size_t strlen, char filler)
+{
+ std::string s;
+
+ for (size_t i=0; i<strlen; i++)
+ s += filler;
+
+ return s;
+}
+
+ //---------------------------------------------------------------
+ //
+ // munge_description
+ //
+ // Convert dollar signs to EOL and word wrap to 80 characters.
+ // (for some obscure reason get_item_description uses dollar
+ // signs instead of EOL).
+ // - It uses $ signs because they're easier to manipulate than the EOL
+ // macro, which is of uncertain length (well, that and I didn't know how
+ // to do it any better at the time) (LH)
+ //---------------------------------------------------------------
+static std::string munge_description(const std::string & inStr)
+{
+ std::string outStr;
+
+ outStr.reserve(inStr.length() + 32);
+
+ const long kIndent = 3;
+ long lineLen = kIndent;
+
+ long i = 0;
+
+ outStr += fillstring(kIndent, ' ');
+
+ while (i < (long) inStr.length())
+ {
+ char ch = inStr[i];
+
+ if (ch == '$')
+ {
+ outStr += EOL;
+
+ outStr += fillstring(kIndent, ' ');
+ lineLen = kIndent;
+
+ while (inStr[++i] == '$')
+ ;
+ }
+ else if (isspace(ch))
+ {
+ if (lineLen >= 79)
+ {
+ outStr += EOL;
+ outStr += fillstring(kIndent, ' ');
+ lineLen = kIndent;
+
+ }
+ else if (lineLen > 0)
+ {
+ outStr += ch;
+ ++lineLen;
+ }
+ ++i;
+ }
+ else
+ {
+ std::string word;
+
+ while (i < (long) inStr.length()
+ && lineLen + (long) word.length() < 79
+ && !isspace(inStr[i]) && inStr[i] != '$')
+ {
+ word += inStr[i++];
+ }
+
+ if (lineLen + word.length() >= 79)
+ {
+ outStr += EOL;
+ outStr += fillstring(kIndent, ' ');
+ lineLen = kIndent;
+ }
+
+ outStr += word;
+ lineLen += word.length();
+ }
+ }
+
+ outStr += EOL;
+
+ return (outStr);
+} // end munge_description()
+
+ //---------------------------------------------------------------
+ //
+ // dump_stats
+ //
+ //---------------------------------------------------------------
+static void dump_stats( std::string & text )
+{
+ char st_prn[20];
+
+ text += you.your_name;
+ text += " the ";
+
+ text += player_title();
+ text += " (";
+ text += species_name(you.species, you.experience_level);
+ text += ")";
+ text += EOL;
+
+ text += "(Level ";
+ itoa(you.experience_level, st_prn, 10);
+ text += st_prn;
+ text += " ";
+ text += you.class_name;
+ text += ")";
+ text += EOL EOL;
+
+ if (you.real_time != -1)
+ {
+ const time_t curr = you.real_time + (time(NULL) - you.start_time);
+ char buff[200];
+
+ make_time_string( curr, buff, sizeof(buff) );
+
+ text += "Play time: ";
+ text += buff;
+
+ text += " Number of turns: ";
+ itoa( you.num_turns, st_prn, 10 );
+ text += st_prn;
+ text += EOL EOL;
+ }
+
+ text += "Experience : ";
+ itoa(you.experience_level, st_prn, 10);
+ text += st_prn;
+ text += "/";
+ itoa(you.experience, st_prn, 10);
+ text += st_prn;
+ text += EOL;
+
+ text += "Strength ";
+ itoa(you.strength, st_prn, 10);
+ text += st_prn;
+ if (you.strength < you.max_strength)
+ {
+ text += "/";
+ itoa(you.max_strength, st_prn, 10);
+ text += st_prn;
+ }
+
+ text += " Dexterity ";
+ itoa(you.dex, st_prn, 10);
+ text += st_prn;
+ if (you.dex < you.max_dex)
+ {
+ text += "/";
+ itoa(you.max_dex, st_prn, 10);
+ text += st_prn;
+ }
+
+ text += " Intelligence ";
+ itoa(you.intel, st_prn, 10);
+ text += st_prn;
+ if (you.intel < you.max_intel)
+ {
+ text += "/";
+ itoa(you.max_intel, st_prn, 10);
+ text += st_prn;
+ }
+ text += EOL;
+
+ text += "Hit Points : ";
+ itoa(you.hp, st_prn, 10);
+ text += st_prn;
+
+ int max_max_hp = you.hp_max + player_rotted();
+
+ if (you.hp < you.hp_max || max_max_hp != you.hp_max)
+ {
+ text += "/";
+ itoa(you.hp_max, st_prn, 10);
+ text += st_prn;
+
+ if (max_max_hp != you.hp_max)
+ {
+ text += " (";
+ itoa(max_max_hp, st_prn, 10);
+ text += st_prn;
+ text += ")";
+ }
+
+ if (you.hp < 1)
+ {
+ text += " ";
+ text += ((!you.deaths_door) ? "(dead)" : "(almost dead)");
+ }
+ }
+
+ text += " Magic Points : ";
+ itoa(you.magic_points, st_prn, 10);
+ text += st_prn;
+ if (you.magic_points < you.max_magic_points)
+ {
+ text += "/";
+ itoa(you.max_magic_points, st_prn, 10);
+ text += st_prn;
+ }
+ text += EOL;
+
+ text += "AC : ";
+ itoa(player_AC(), st_prn, 10);
+ text += st_prn;
+
+ text += " Evasion : ";
+ itoa(player_evasion(), st_prn, 10);
+ text += st_prn;
+
+ text += " Shield : ";
+ itoa(player_shield_class(), st_prn, 10);
+ text += st_prn;
+ text += EOL;
+
+ text += "GP : ";
+ itoa( you.gold, st_prn, 10 );
+ text += st_prn;
+ text += EOL;
+ text += EOL;
+} // end dump_stats()
+
+ //---------------------------------------------------------------
+ //
+ // dump_location
+ //
+ //---------------------------------------------------------------
+static void dump_location( std::string & text )
+{
+ if (you.level_type != LEVEL_DUNGEON || you.your_level != -1)
+ text += "You are ";
+
+ if (you.level_type == LEVEL_PANDEMONIUM)
+ text += "in Pandemonium";
+ else if (you.level_type == LEVEL_ABYSS)
+ text += "in the Abyss";
+ else if (you.level_type == LEVEL_LABYRINTH)
+ text += "in a labyrinth";
+ else if (you.where_are_you == BRANCH_DIS)
+ text += "in Dis";
+ else if (you.where_are_you == BRANCH_GEHENNA)
+ text += "in Gehenna";
+ else if (you.where_are_you == BRANCH_VESTIBULE_OF_HELL)
+ text += "in the Vestibule of Hell";
+ else if (you.where_are_you == BRANCH_COCYTUS)
+ text += "in Cocytus";
+ else if (you.where_are_you == BRANCH_TARTARUS)
+ text += "in Tartarus";
+ else if (you.where_are_you == BRANCH_INFERNO)
+ text += "in the Inferno";
+ else if (you.where_are_you == BRANCH_THE_PIT)
+ text += "in the Pit";
+ else if (you.where_are_you == BRANCH_ORCISH_MINES)
+ text += "in the Mines";
+ else if (you.where_are_you == BRANCH_HIVE)
+ text += "in the Hive";
+ else if (you.where_are_you == BRANCH_LAIR)
+ text += "in the Lair";
+ else if (you.where_are_you == BRANCH_SLIME_PITS)
+ text += "in the Slime Pits";
+ else if (you.where_are_you == BRANCH_VAULTS)
+ text += "in the Vaults";
+ else if (you.where_are_you == BRANCH_CRYPT)
+ text += "in the Crypt";
+ else if (you.where_are_you == BRANCH_HALL_OF_BLADES)
+ text += "in the Hall of Blades";
+ else if (you.where_are_you == BRANCH_HALL_OF_ZOT)
+ text += "in the Hall of Zot";
+ else if (you.where_are_you == BRANCH_ECUMENICAL_TEMPLE)
+ text += "in the Ecumenical Temple";
+ else if (you.where_are_you == BRANCH_SNAKE_PIT)
+ text += "in the Snake Pit";
+ else if (you.where_are_you == BRANCH_ELVEN_HALLS)
+ text += "in the Elven Halls";
+ else if (you.where_are_you == BRANCH_TOMB)
+ text += "in the Tomb";
+ else if (you.where_are_you == BRANCH_SWAMP)
+ text += "in the Swamp";
+ else
+ {
+ if (you.your_level == -1)
+ text += "You escaped";
+ else
+ {
+ text += "on level ";
+
+ char st_prn[20];
+ itoa(you.your_level + 1, st_prn, 10);
+ text += st_prn;
+ }
+ }
+
+ text += ".";
+ text += EOL;
+} // end dump_location()
+
+ //---------------------------------------------------------------
+ //
+ // dump_religion
+ //
+ //---------------------------------------------------------------
+static void dump_religion( std::string & text )
+{
+ if (you.religion != GOD_NO_GOD)
+ {
+ text += "You worship ";
+ text += god_name(you.religion);
+ text += ".";
+ text += EOL;
+
+ if (!player_under_penance())
+ {
+ if (you.religion != GOD_XOM)
+ { // Xom doesn't care
+ text += god_name(you.religion);
+ text += " is ";
+ text += ((you.piety <= 5) ? "displeased" :
+ (you.piety <= 20) ? "noncommittal" :
+ (you.piety <= 40) ? "pleased with you" :
+ (you.piety <= 70) ? "most pleased with you" :
+ (you.piety <= 100) ? "greatly pleased with you" :
+ (you.piety <= 130) ? "extremely pleased with you"
+ : "exalted by your worship");
+ text += ".";
+ text += EOL;
+ }
+ }
+ else
+ {
+ text += god_name(you.religion);
+ text += " is demanding penance.";
+ text += EOL;
+ }
+ }
+} // end dump_religion()
+
+ //---------------------------------------------------------------
+ //
+ // dump_inventory
+ //
+ //---------------------------------------------------------------
+static void dump_inventory( std::string & text, bool show_prices )
+{
+ int i, j;
+ char temp_id[4][50];
+
+ std::string text2;
+
+ for (i = 0; i < 4; i++)
+ {
+ for (j = 0; j < 50; j++)
+ {
+ temp_id[i][j] = 1;
+ }
+ }
+
+ char st_pass[ ITEMNAME_SIZE ] = "";
+ int inv_class2[OBJ_GOLD];
+ int inv_count = 0;
+ char tmp_quant[20];
+
+ for (i = 0; i < OBJ_GOLD; i++)
+ {
+ inv_class2[i] = 0;
+ }
+
+ for (i = 0; i < ENDOFPACK; i++)
+ {
+ if (is_valid_item( you.inv[i] ))
+ {
+ // adds up number of each class in invent.
+ inv_class2[you.inv[i].base_type]++;
+ inv_count++;
+ }
+ }
+
+ if (!inv_count)
+ {
+ text += "You aren't carrying anything.";
+ text += EOL;
+ }
+ else
+ {
+ text += " Inventory:";
+ text += EOL;
+
+ for (i = 0; i < OBJ_GOLD; i++)
+ {
+ if (inv_class2[i] != 0)
+ {
+ switch (i)
+ {
+ case OBJ_WEAPONS: text += "Hand weapons"; break;
+ case OBJ_MISSILES: text += "Missiles"; break;
+ case OBJ_ARMOUR: text += "Armour"; break;
+ case OBJ_WANDS: text += "Magical devices"; break;
+ case OBJ_FOOD: text += "Comestibles"; break;
+ case OBJ_SCROLLS: text += "Scrolls"; break;
+ case OBJ_JEWELLERY: text += "Jewellery"; break;
+ case OBJ_POTIONS: text += "Potions"; break;
+ case OBJ_BOOKS: text += "Books"; break;
+ case OBJ_STAVES: text += "Magical staves"; break;
+ case OBJ_ORBS: text += "Orbs of Power"; break;
+ case OBJ_MISCELLANY: text += "Miscellaneous"; break;
+ case OBJ_CORPSES: text += "Carrion"; break;
+
+ default:
+ DEBUGSTR("Bad item class");
+ }
+ text += EOL;
+
+ for (j = 0; j < ENDOFPACK; j++)
+ {
+ if (is_valid_item(you.inv[j]) && you.inv[j].base_type == i)
+ {
+ text += " ";
+
+ in_name( j, DESC_INVENTORY_EQUIP, st_pass );
+ text += st_pass;
+
+ inv_count--;
+
+ if (show_prices)
+ {
+ text += " (";
+
+ itoa( item_value( you.inv[j], temp_id, true ),
+ tmp_quant, 10 );
+
+ text += tmp_quant;
+ text += " gold)";
+ }
+
+ if (is_dumpable_artifact( you.inv[j],
+ Options.verbose_dump ))
+ {
+ text2 = get_item_description( you.inv[j],
+ Options.verbose_dump,
+ true );
+
+ text += munge_description(text2);
+ }
+ else
+ {
+ text += EOL;
+ }
+ }
+ }
+ }
+ }
+ }
+} // end dump_inventory()
+
+//---------------------------------------------------------------
+//
+// dump_skills
+//
+//---------------------------------------------------------------
+static void dump_skills( std::string & text )
+{
+ char tmp_quant[20];
+
+ text += EOL;
+ text += EOL;
+ text += " Skills:";
+ text += EOL;
+
+ for (unsigned char i = 0; i < 50; i++)
+ {
+ if (you.skills[i] > 0)
+ {
+ text += ( (you.skills[i] == 27) ? " * " :
+ (you.practise_skill[i]) ? " + "
+ : " - " );
+
+ text += "Level ";
+ itoa( you.skills[i], tmp_quant, 10 );
+ text += tmp_quant;
+ text += " ";
+ text += skill_name(i);
+ text += EOL;
+ }
+ }
+
+ text += EOL;
+ text += EOL;
+} // end dump_skills()
+
+//---------------------------------------------------------------
+//
+// Return string of the i-th spell type, with slash if required
+//
+//---------------------------------------------------------------
+static std::string spell_type_name(int spell_class, bool slash)
+{
+ std::string ret;
+
+ if (slash)
+ ret = "/";
+
+ ret += spelltype_name(spell_class);
+
+ return (ret);
+} // end spell_type_name()
+
+//---------------------------------------------------------------
+//
+// dump_spells
+//
+//---------------------------------------------------------------
+static void dump_spells( std::string & text )
+{
+ char tmp_quant[20];
+
+// This array helps output the spell types in the traditional order.
+// this can be tossed as soon as I reorder the enum to the traditional order {dlb}
+ const int spell_type_index[] = {
+ SPTYP_HOLY,
+ SPTYP_POISON,
+ SPTYP_FIRE,
+ SPTYP_ICE,
+ SPTYP_EARTH,
+ SPTYP_AIR,
+ SPTYP_CONJURATION,
+ SPTYP_ENCHANTMENT,
+ SPTYP_DIVINATION,
+ SPTYP_TRANSLOCATION,
+ SPTYP_SUMMONING,
+ SPTYP_TRANSMIGRATION,
+ SPTYP_NECROMANCY,
+ 0
+ };
+
+ int spell_levels = player_spell_levels();
+
+ if (spell_levels == 1)
+ text += "You have one spell level left.";
+ else if (spell_levels == 0)
+ text += "You cannot memorise any spells.";
+ else
+ {
+ text += "You have ";
+ itoa( spell_levels, tmp_quant, 10 );
+ text += tmp_quant;
+ text += " spell levels left.";
+ }
+
+ text += EOL;
+
+ if (!you.spell_no)
+ {
+ text += "You don't know any spells.";
+ text += EOL;
+
+ }
+ else
+ {
+ text += "You know the following spells:" EOL;
+ text += EOL;
+
+ text += " Your Spells Type Success Level" EOL;
+
+ for (int j = 0; j < 52; j++)
+ {
+ const char letter = index_to_letter( j );
+ const int spell = get_spell_by_letter( letter );
+
+ if (spell != SPELL_NO_SPELL)
+ {
+ std::string spell_line = " ";
+
+ char strng[2];
+ strng[0] = letter;
+ strng[1] = '\0';
+
+ spell_line += strng;
+ spell_line += " - ";
+ spell_line += spell_title( spell );
+
+ for (int i = spell_line.length(); i < 34; i++)
+ {
+ spell_line += ' ';
+ }
+
+ bool already = false;
+
+ for (int i = 0; spell_type_index[i] != 0; i++)
+ {
+ if (spell_typematch( spell, spell_type_index[i] ))
+ {
+ spell_line +=
+ spell_type_name(spell_type_index[i], already);
+ already = true;
+ }
+ }
+
+ for (int i = spell_line.length(); i < 58; i++)
+ {
+ spell_line += ' ';
+ }
+
+ int fail_rate = spell_fail( spell );
+
+ spell_line += (fail_rate == 100) ? "Useless" :
+ (fail_rate > 90) ? "Terrible" :
+ (fail_rate > 80) ? "Cruddy" :
+ (fail_rate > 70) ? "Bad" :
+ (fail_rate > 60) ? "Very Poor" :
+ (fail_rate > 50) ? "Poor" :
+ (fail_rate > 40) ? "Fair" :
+ (fail_rate > 30) ? "Good" :
+ (fail_rate > 20) ? "Very Good" :
+ (fail_rate > 10) ? "Great" :
+ (fail_rate > 0) ? "Excellent"
+ : "Perfect";
+
+ for (int i = spell_line.length(); i < 70; i++)
+ spell_line += ' ';
+
+ itoa((int) spell_difficulty( spell ), tmp_quant, 10 );
+ spell_line += tmp_quant;
+ spell_line += EOL;
+
+ text += spell_line;
+ }
+ }
+ }
+} // end dump_spells()
+
+//---------------------------------------------------------------
+//
+// dump_mutations
+//
+//---------------------------------------------------------------
+static void dump_mutations( std::string & text )
+{
+ // Can't use how_mutated() here, as it doesn't count demonic powers
+ int xz = 0;
+
+ for (int xy = 0; xy < 100; xy++)
+ {
+ if (you.mutation[xy] > 0)
+ xz++;
+ }
+
+ if (xz > 0)
+ {
+ text += "";
+ text += EOL;
+ text += " Mutations & Other Weirdness";
+ text += EOL;
+
+ for (int j = 0; j < 100; j++)
+ {
+ if (you.mutation[j])
+ {
+ if (you.demon_pow[j] > 0)
+ text += "* ";
+
+ text += mutation_name(j);
+ text += EOL;
+ }
+ }
+ }
+} // end dump_mutations()
+
+#if MAC
+#pragma mark -
+#endif
+
+// ========================================================================
+// Public Functions
+// ========================================================================
+
+//---------------------------------------------------------------
+//
+// dump_char
+//
+// Creates a disk record of a character. Returns true if the
+// character was successfully saved.
+//
+//---------------------------------------------------------------
+bool dump_char( const char fname[30], bool show_prices ) // $$$ a try block?
+{
+ bool succeeded = false;
+
+ std::string text;
+
+ // start with enough room for 100 80 character lines
+ text.reserve(100 * 80);
+
+ text += " Dungeon Crawl version " VERSION " character file.";
+ text += EOL;
+ text += EOL;
+
+ dump_stats(text);
+ dump_location(text);
+ dump_religion(text);
+
+ switch (you.burden_state)
+ {
+ case BS_OVERLOADED:
+ text += "You are overloaded with stuff.";
+ text += EOL;
+ break;
+ case BS_ENCUMBERED:
+ text += "You are encumbered.";
+ text += EOL;
+ break;
+ }
+
+ text += "You are ";
+
+ text += ((you.hunger <= 1000) ? "starving" :
+ (you.hunger <= 2600) ? "hungry" :
+ (you.hunger < 7000) ? "not hungry" :
+ (you.hunger < 11000) ? "full" : "completely stuffed");
+
+ text += ".";
+ text += EOL;
+ text += EOL;
+
+ if (you.attribute[ATTR_TRANSFORMATION])
+ {
+ switch (you.attribute[ATTR_TRANSFORMATION])
+ {
+ case TRAN_SPIDER:
+ text += "You are in spider-form.";
+ break;
+ case TRAN_BLADE_HANDS:
+ text += "Your hands are blades.";
+ break;
+ case TRAN_STATUE:
+ text += "You are a stone statue.";
+ break;
+ case TRAN_ICE_BEAST:
+ text += "You are a creature of crystalline ice.";
+ break;
+ case TRAN_DRAGON:
+ text += "You are a fearsome dragon!";
+ break;
+ case TRAN_LICH:
+ text += "You are in lich-form.";
+ break;
+ case TRAN_SERPENT_OF_HELL:
+ text += "You are a huge, demonic serpent!";
+ break;
+ case TRAN_AIR:
+ text += "You are a cloud of diffuse gas.";
+ break;
+ }
+
+ text += EOL;
+ text += EOL;
+ }
+
+ dump_inventory(text, show_prices);
+
+ char tmp_quant[20];
+
+ text += EOL;
+ text += EOL;
+ text += " You have ";
+ itoa( you.exp_available, tmp_quant, 10 );
+ text += tmp_quant;
+ text += " experience left.";
+
+ dump_skills(text);
+ dump_spells(text);
+ dump_mutations(text);
+
+ char file_name[kPathLen] = "\0";
+
+ if (SysEnv.crawl_dir)
+ strncpy(file_name, SysEnv.crawl_dir, kPathLen);
+
+ strncat(file_name, fname, kPathLen);
+
+ if (strcmp(fname, "morgue.txt") != 0)
+ strncat(file_name, ".txt", kPathLen);
+
+ FILE *handle = fopen(file_name, "wb");
+
+#if DEBUG_DIAGNOSTICS
+ strcpy( info, "File name: " );
+ strcat( info, file_name );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ if (handle != NULL)
+ {
+ size_t begin = 0;
+ size_t end = text.find(EOL);
+
+ while (end != std::string::npos)
+ {
+ end += strlen(EOL);
+
+ size_t len = end - begin;
+
+ if (len > 80)
+ len = 80;
+
+ fwrite(text.c_str() + begin, len, 1, handle);
+
+ begin = end;
+ end = text.find(EOL, end);
+ }
+
+ fclose(handle);
+ succeeded = true;
+ }
+ else
+ mpr("Error opening file.");
+
+ return (succeeded);
+} // end dump_char()
diff --git a/trunk/source/chardump.h b/trunk/source/chardump.h
new file mode 100644
index 0000000000..2609d61615
--- /dev/null
+++ b/trunk/source/chardump.h
@@ -0,0 +1,24 @@
+/*
+ * File: chardump.cc
+ * Summary: Dumps character info out to the morgue file.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> 4/20/99 JDJ Reformatted, uses string objects, split out
+ * 7 functions from dump_char, dumps artifact info.
+ */
+
+
+#ifndef CHARDUMP_H
+#define CHARDUMP_H
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - ouch
+ * *********************************************************************** */
+bool dump_char( const char fname[30], bool show_prices );
+
+
+#endif
diff --git a/trunk/source/cloud.cc b/trunk/source/cloud.cc
new file mode 100644
index 0000000000..808c4cce02
--- /dev/null
+++ b/trunk/source/cloud.cc
@@ -0,0 +1,130 @@
+/*
+ * File: cloud.cc
+ * Summary: Functions related to clouds.
+ * Written by: Brent Ross
+ *
+ * Creating a cloud module so all the cloud stuff can be isolated.
+ *
+ * Change History (most recent first):
+ *
+ * <1> Oct 1/2001 BWR Created
+ */
+
+#include "AppHdr.h"
+#include "externs.h"
+
+#include "cloud.h"
+#include "stuff.h"
+
+void delete_cloud( int cloud )
+{
+ if (env.cloud[ cloud ].type != CLOUD_NONE)
+ {
+ const int cloud_x = env.cloud[ cloud ].x;
+ const int cloud_y = env.cloud[ cloud ].y;
+
+ env.cloud[ cloud ].type = CLOUD_NONE;
+ env.cloud[ cloud ].decay = 0;
+ env.cloud[ cloud ].x = 0;
+ env.cloud[ cloud ].y = 0;
+ env.cgrid[ cloud_x ][ cloud_y ] = EMPTY_CLOUD;
+ env.cloud_no--;
+ }
+}
+
+static void new_cloud( int cloud, int type, int x, int y, int decay )
+{
+ ASSERT( env.cloud[ cloud ].type == CLOUD_NONE );
+
+ env.cloud[ cloud ].type = type;
+ env.cloud[ cloud ].decay = decay;
+ env.cloud[ cloud ].x = x;
+ env.cloud[ cloud ].y = y;
+ env.cgrid[ x ][ y ] = cloud;
+ env.cloud_no++;
+}
+
+// The current use of this function is for shifting in the abyss, so
+// that clouds get moved along with the rest of the map.
+void move_cloud( int cloud, int new_x, int new_y )
+{
+ if (cloud != EMPTY_CLOUD)
+ {
+ const int old_x = env.cloud[ cloud ].x;
+ const int old_y = env.cloud[ cloud ].y;
+
+ env.cgrid[ new_x ][ new_y ] = cloud;
+ env.cloud[ cloud ].x = new_x;
+ env.cloud[ cloud ].y = new_y;
+ env.cgrid[ old_x ][ old_y ] = EMPTY_CLOUD;
+ }
+}
+
+// Places a cloud with the given stats. May delete old clouds to make way
+// if there are too many (MAX_CLOUDS == 30) on level. Will overwrite an old
+// cloud under some circumstances.
+void place_cloud(unsigned char cl_type, unsigned char ctarget_x,
+ unsigned char ctarget_y, unsigned char cl_range)
+{
+ int cl_new = -1;
+
+ // more compact {dlb}
+ const unsigned char target_cgrid = env.cgrid[ctarget_x][ctarget_y];
+
+ // that is, another cloud already there {dlb}
+ if (target_cgrid != EMPTY_CLOUD)
+ {
+ if ((env.cloud[ target_cgrid ].type >= CLOUD_GREY_SMOKE
+ && env.cloud[ target_cgrid ].type <= CLOUD_STEAM)
+ || env.cloud[ target_cgrid ].type == CLOUD_STINK
+ || env.cloud[ target_cgrid ].type == CLOUD_BLACK_SMOKE
+ || env.cloud[ target_cgrid ].decay <= 20) //soon gone
+ {
+ cl_new = env.cgrid[ ctarget_x ][ ctarget_y ];
+ delete_cloud( env.cgrid[ ctarget_x ][ ctarget_y ] );
+ }
+ else
+ {
+ return;
+ }
+ }
+
+ // too many clouds
+ if (env.cloud_no >= MAX_CLOUDS)
+ {
+ // default to random in case there's no low quality clouds
+ int cl_del = random2( MAX_CLOUDS );
+
+ for (int ci = 0; ci < MAX_CLOUDS; ci++)
+ {
+ if ((env.cloud[ ci ].type >= CLOUD_GREY_SMOKE
+ && env.cloud[ ci ].type <= CLOUD_STEAM)
+ || env.cloud[ ci ].type == CLOUD_STINK
+ || env.cloud[ ci ].type == CLOUD_BLACK_SMOKE
+ || env.cloud[ ci ].decay <= 20) //soon gone
+ {
+ cl_del = ci;
+ break;
+ }
+ }
+
+ delete_cloud( cl_del );
+ cl_new = cl_del;
+ }
+
+ // create new cloud
+ if (cl_new != -1)
+ new_cloud( cl_new, cl_type, ctarget_x, ctarget_y, cl_range * 10 );
+ else
+ {
+ // find slot for cloud
+ for (int ci = 0; ci < MAX_CLOUDS; ci++)
+ {
+ if (env.cloud[ci].type == CLOUD_NONE) // ie is empty
+ {
+ new_cloud( ci, cl_type, ctarget_x, ctarget_y, cl_range * 10 );
+ break;
+ }
+ }
+ }
+} // end place_cloud();
diff --git a/trunk/source/cloud.h b/trunk/source/cloud.h
new file mode 100644
index 0000000000..e11535ca8c
--- /dev/null
+++ b/trunk/source/cloud.h
@@ -0,0 +1,22 @@
+/*
+ * File: cloud.h
+ * Summary: Functions related to clouds.
+ * Written by: Brent Ross
+ *
+ * Change History (most recent first):
+ *
+ * <1> Oct 1/2001 BWR Created
+ */
+
+
+#ifndef CLOUD_H
+#define CLOUD_H
+
+#include "externs.h"
+
+void delete_cloud( int cloud );
+void move_cloud( int cloud, int new_x, int new_y );
+
+void place_cloud(unsigned char cl_type, unsigned char ctarget_x, unsigned char ctarget_y, unsigned char cl_range);
+
+#endif
diff --git a/trunk/source/command.cc b/trunk/source/command.cc
new file mode 100644
index 0000000000..977dbaf035
--- /dev/null
+++ b/trunk/source/command.cc
@@ -0,0 +1,515 @@
+/*
+ * File: command.cc
+ * Summary: Misc commands.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <4> 10/12/99 BCR BUILD_DATE is now used in version()
+ * <3> 6/13/99 BWR New equipment listing commands
+ * <2> 5/20/99 BWR Swapping inventory letters.
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "command.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "externs.h"
+
+#include "abl-show.h"
+#include "invent.h"
+#include "itemname.h"
+#include "item_use.h"
+#include "items.h"
+#include "ouch.h"
+#include "spl-cast.h"
+#include "spl-util.h"
+#include "stuff.h"
+#include "version.h"
+#include "wpn-misc.h"
+
+static void adjust_item(void);
+static void adjust_spells(void);
+static void adjust_ability(void);
+
+void quit_game(void)
+{
+ if (yesno("Really quit?", false))
+ ouch(-9999, 0, KILLED_BY_QUITTING);
+} // end quit_game()
+
+void version(void)
+{
+ mpr( "This is Dungeon Crawl " VERSION " (Last build " BUILD_DATE ")." );
+} // end version()
+
+void adjust(void)
+{
+ mpr( "Adjust (i)tems, (s)pells, or (a)bilities?", MSGCH_PROMPT );
+
+ unsigned char keyin = tolower( get_ch() );
+
+ if (keyin == 'i')
+ adjust_item();
+ else if (keyin == 's')
+ adjust_spells();
+ else if (keyin == 'a')
+ adjust_ability();
+ else if (keyin == ESCAPE)
+ canned_msg( MSG_OK );
+ else
+ canned_msg( MSG_HUH );
+} // end adjust()
+
+static void adjust_item(void)
+{
+ int from_slot, to_slot;
+ char str_pass[ ITEMNAME_SIZE ];
+
+ if (inv_count() < 1)
+ {
+ canned_msg(MSG_NOTHING_CARRIED);
+ return;
+ }
+
+ from_slot = prompt_invent_item( "Adjust which item?", -1 );
+ if (from_slot == PROMPT_ABORT)
+ {
+ canned_msg( MSG_OK );
+ return;
+ }
+
+ in_name( from_slot, DESC_INVENTORY_EQUIP, str_pass );
+ mpr( str_pass );
+
+ to_slot = prompt_invent_item( "Adjust to which letter?", -1, false, false );
+ if (to_slot == PROMPT_ABORT)
+ {
+ canned_msg( MSG_OK );
+ return;
+ }
+
+ // swap items
+ item_def tmp = you.inv[to_slot];
+ you.inv[to_slot] = you.inv[from_slot];
+ you.inv[from_slot] = tmp;
+
+ you.inv[from_slot].link = from_slot;
+ you.inv[to_slot].link = to_slot;
+
+ for (int i = 0; i < NUM_EQUIP; i++)
+ {
+ if (you.equip[i] == from_slot)
+ you.equip[i] = to_slot;
+ else if (you.equip[i] == to_slot)
+ you.equip[i] = from_slot;
+ }
+
+ in_name( to_slot, DESC_INVENTORY_EQUIP, str_pass );
+ mpr( str_pass );
+
+ if (is_valid_item( you.inv[from_slot] ))
+ {
+ in_name( from_slot, DESC_INVENTORY_EQUIP, str_pass );
+ mpr( str_pass );
+ }
+
+ if (to_slot == you.equip[EQ_WEAPON] || from_slot == you.equip[EQ_WEAPON])
+ you.wield_change = true;
+} // end adjust_item()
+
+static void adjust_spells_cleanup(bool needs_redraw)
+{
+ if (needs_redraw)
+ redraw_screen();
+}
+
+static void adjust_spells(void)
+{
+ unsigned char index_1, index_2;
+ unsigned char nthing = 0;
+
+ bool needs_redraw = false;
+
+ if (!you.spell_no)
+ {
+ mpr("You don't know any spells.");
+ return;
+ }
+
+ query:
+ mpr("Adjust which spell?", MSGCH_PROMPT);
+
+ unsigned char keyin = get_ch();
+
+ if (keyin == '?' || keyin == '*')
+ {
+ if (keyin == '*' || keyin == '?')
+ {
+ nthing = list_spells();
+ needs_redraw = true;
+ }
+
+ if (isalpha( nthing ) || nthing == ESCAPE)
+ keyin = nthing;
+ else
+ {
+ mesclr( true );
+ goto query;
+ }
+ }
+
+ if (keyin == ESCAPE)
+ {
+ adjust_spells_cleanup(needs_redraw);
+ canned_msg( MSG_OK );
+ return;
+ }
+
+ int input_1 = (int) keyin;
+
+ if (!isalpha( input_1 ))
+ {
+ adjust_spells_cleanup(needs_redraw);
+ mpr("You don't know that spell.");
+ return;
+ }
+
+ index_1 = letter_to_index( input_1 );
+ int spell = get_spell_by_letter( input_1 );
+
+ if (spell == SPELL_NO_SPELL)
+ {
+ adjust_spells_cleanup(needs_redraw);
+ mpr("You don't know that spell.");
+ return;
+ }
+
+ // print out targeted spell:
+ snprintf( info, INFO_SIZE, "%c - %s", input_1, spell_title( spell ) );
+ mpr(info);
+
+ mpr( "Adjust to which letter?", MSGCH_PROMPT );
+
+ keyin = get_ch();
+
+ if (keyin == '?' || keyin == '*')
+ {
+ if (keyin == '*' || keyin == '?')
+ {
+ nthing = list_spells();
+ needs_redraw = true;
+ }
+
+ if (isalpha( nthing ) || nthing == ESCAPE)
+ keyin = nthing;
+ else
+ {
+ mesclr( true );
+ goto query;
+ }
+ }
+
+ if (keyin == ESCAPE)
+ {
+ adjust_spells_cleanup(needs_redraw);
+ canned_msg( MSG_OK );
+ return;
+ }
+
+ int input_2 = (int) keyin;
+
+ if (!isalpha( input_2 ))
+ {
+ adjust_spells_cleanup(needs_redraw);
+ mpr("What?");
+ return;
+ }
+
+ adjust_spells_cleanup(needs_redraw);
+
+ index_2 = letter_to_index( input_2 );
+
+ // swap references in the letter table:
+ int tmp = you.spell_letter_table[index_2];
+ you.spell_letter_table[index_2] = you.spell_letter_table[index_1];
+ you.spell_letter_table[index_1] = tmp;
+
+ // print out spell in new slot (now at input_2)
+ snprintf( info, INFO_SIZE, "%c - %s", input_2,
+ spell_title( get_spell_by_letter(input_2) ) );
+
+ mpr(info);
+
+ // print out other spell if one was involved (now at input_1)
+ spell = get_spell_by_letter( input_1 );
+ if (spell != SPELL_NO_SPELL)
+ {
+ snprintf( info, INFO_SIZE, "%c - %s", input_1, spell_title(spell) );
+ mpr(info);
+ }
+} // end adjust_spells()
+
+static void adjust_ability(void)
+{
+ unsigned char index_1, index_2;
+ unsigned char nthing = 0;
+
+ bool needs_redraw = false;
+
+ if (!generate_abilities())
+ {
+ mpr( "You don't currently have any abilities." );
+ return;
+ }
+
+ query:
+ mpr( "Adjust which ability?", MSGCH_PROMPT );
+
+ unsigned char keyin = get_ch();
+
+ if (keyin == '?' || keyin == '*')
+ {
+ if (keyin == '*' || keyin == '?')
+ {
+ nthing = show_abilities();
+ needs_redraw = true;
+ }
+
+ if (isalpha( nthing ) || nthing == ESCAPE)
+ keyin = nthing;
+ else
+ {
+ mesclr( true );
+ goto query;
+ }
+ }
+
+ if (keyin == ESCAPE)
+ {
+ adjust_spells_cleanup(needs_redraw);
+ canned_msg( MSG_OK );
+ return;
+ }
+
+ int input_1 = (int) keyin;
+
+ if (!isalpha( input_1 ))
+ {
+ adjust_spells_cleanup(needs_redraw);
+ mpr("You don't have that ability.");
+ return;
+ }
+
+ index_1 = letter_to_index( input_1 );
+
+ if (you.ability_letter_table[index_1] == ABIL_NON_ABILITY)
+ {
+ adjust_spells_cleanup(needs_redraw);
+ mpr("You don't have that ability.");
+ return;
+ }
+
+ // print out targeted spell:
+ snprintf( info, INFO_SIZE, "%c - %s", input_1,
+ get_ability_name_by_index( index_1 ) );
+
+ mpr(info);
+
+ mpr( "Adjust to which letter?", MSGCH_PROMPT );
+
+ keyin = get_ch();
+
+ if (keyin == '?' || keyin == '*')
+ {
+ if (keyin == '*' || keyin == '?')
+ {
+ nthing = show_abilities();
+ needs_redraw = true;
+ }
+
+ if (isalpha( nthing ) || nthing == ESCAPE)
+ keyin = nthing;
+ else
+ {
+ mesclr( true );
+ goto query;
+ }
+ }
+
+ if (keyin == ESCAPE)
+ {
+ adjust_spells_cleanup(needs_redraw);
+ canned_msg( MSG_OK );
+ return;
+ }
+
+ int input_2 = (int) keyin;
+
+ if (!isalpha( input_2 ))
+ {
+ adjust_spells_cleanup(needs_redraw);
+ mpr("What?");
+ return;
+ }
+
+ adjust_spells_cleanup(needs_redraw);
+
+ index_2 = letter_to_index( input_2 );
+
+ // swap references in the letter table:
+ int tmp = you.ability_letter_table[index_2];
+ you.ability_letter_table[index_2] = you.ability_letter_table[index_1];
+ you.ability_letter_table[index_1] = tmp;
+
+ // Note: the input_2/index_1 and input_1/index_2 here is intentional.
+ // This is because nothing actually moves until generate_abilities is
+ // called again... fortunately that has to be done everytime because
+ // that's the silly way this system currently works. -- bwr
+ snprintf( info, INFO_SIZE, "%c - %s", input_2,
+ get_ability_name_by_index( index_1 ) );
+
+ mpr(info);
+
+ if (you.ability_letter_table[index_1] != ABIL_NON_ABILITY)
+ {
+ snprintf( info, INFO_SIZE, "%c - %s", input_1,
+ get_ability_name_by_index( index_2 ) );
+ mpr(info);
+ }
+} // end adjust_ability()
+
+void list_armour(void)
+{
+ for (int i = EQ_CLOAK; i <= EQ_BODY_ARMOUR; i++)
+ {
+ int armour_id = you.equip[i];
+
+ strcpy( info,
+ (i == EQ_CLOAK) ? "Cloak " :
+ (i == EQ_HELMET) ? "Helmet " :
+ (i == EQ_GLOVES) ? "Gloves " :
+ (i == EQ_SHIELD) ? "Shield " :
+ (i == EQ_BODY_ARMOUR) ? "Armour " :
+
+ (i == EQ_BOOTS
+ && !(you.species == SP_CENTAUR || you.species == SP_NAGA))
+ ? "Boots " :
+ (i == EQ_BOOTS
+ && (you.species == SP_CENTAUR || you.species == SP_NAGA))
+ ? "Barding"
+ : "unknown" );
+
+ strcat(info, " : ");
+
+ if (armour_id != -1)
+ {
+ char str_pass[ ITEMNAME_SIZE ];
+ in_name(armour_id, DESC_INVENTORY, str_pass);
+ strcat(info, str_pass);
+ }
+ else
+ {
+ strcat(info, " none");
+ }
+
+ mpr( info, MSGCH_EQUIPMENT );
+ }
+} // end list_armour()
+
+void list_jewellery(void)
+{
+ for (int i = EQ_LEFT_RING; i <= EQ_AMULET; i++)
+ {
+ int jewellery_id = you.equip[i];
+
+ strcpy( info, (i == EQ_LEFT_RING) ? "Left ring " :
+ (i == EQ_RIGHT_RING) ? "Right ring" :
+ (i == EQ_AMULET) ? "Amulet "
+ : "unknown " );
+
+ strcat(info, " : ");
+
+ if (jewellery_id != -1)
+ {
+ char str_pass[ ITEMNAME_SIZE ];
+ in_name(jewellery_id, DESC_INVENTORY, str_pass);
+ strcat(info, str_pass);
+ }
+ else
+ {
+ strcat(info, " none");
+ }
+
+ mpr( info, MSGCH_EQUIPMENT );
+ }
+} // end list_jewellery()
+
+void list_weapons(void)
+{
+ const int weapon_id = you.equip[EQ_WEAPON];
+
+ // Output the current weapon
+ //
+ // Yes, this is already on the screen... I'm outputing it
+ // for completeness and to avoid confusion.
+ strcpy(info, "Current : ");
+
+ if (weapon_id != -1)
+ {
+ char str_pass[ ITEMNAME_SIZE ];
+ in_name( weapon_id, DESC_INVENTORY_EQUIP, str_pass );
+ strcat(info, str_pass);
+ }
+ else
+ {
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_BLADE_HANDS)
+ strcat(info, " blade hands");
+ else
+ strcat(info, " empty hands");
+ }
+
+ mpr(info);
+
+ // Print out the swap slots
+ for (int i = 0; i <= 1; i++)
+ {
+ // We'll avoid repeating the current weapon for these slots,
+ // in order to keep things clean.
+ if (weapon_id == i)
+ continue;
+
+ strcpy(info, (i == 0) ? "Primary : " : "Secondary : ");
+
+ if (is_valid_item( you.inv[i] ))
+ {
+ char str_pass[ ITEMNAME_SIZE ];
+ in_name(i, DESC_INVENTORY_EQUIP, str_pass);
+ strcat(info, str_pass);
+ }
+ else
+ strcat(info, " none");
+
+ mpr(info); // Output slot
+ }
+
+ // Now we print out the current default fire weapon
+ strcpy(info, "Firing : ");
+
+ const int item = get_fire_item_index();
+
+ if (item == ENDOFPACK)
+ strcat(info, " nothing");
+ else
+ {
+ char str_pass[ ITEMNAME_SIZE ];
+ in_name( item, DESC_INVENTORY_EQUIP, str_pass );
+ strcat( info, str_pass );
+ }
+
+ mpr( info, MSGCH_EQUIPMENT );
+} // end list_weapons()
diff --git a/trunk/source/command.h b/trunk/source/command.h
new file mode 100644
index 0000000000..01fc719290
--- /dev/null
+++ b/trunk/source/command.h
@@ -0,0 +1,58 @@
+/*
+ * File: command.cc
+ * Summary: Misc commands.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef COMMAND_H
+#define COMMAND_H
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void quit_game(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void version(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void adjust(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void list_weapons(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void list_armour(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void list_jewellery(void);
+
+
+#endif
diff --git a/trunk/source/crawl.gdt b/trunk/source/crawl.gdt
new file mode 100644
index 0000000000..11ea870110
--- /dev/null
+++ b/trunk/source/crawl.gdt
Binary files differ
diff --git a/trunk/source/crawl.gpr b/trunk/source/crawl.gpr
new file mode 100644
index 0000000000..9ff1dd051f
--- /dev/null
+++ b/trunk/source/crawl.gpr
Binary files differ
diff --git a/trunk/source/debug.cc b/trunk/source/debug.cc
new file mode 100644
index 0000000000..265db7e1e1
--- /dev/null
+++ b/trunk/source/debug.cc
@@ -0,0 +1,1701 @@
+/*
+ * File: debug.cc
+ * Summary: Debug and wizard related functions.
+ * Written by: Linley Henzell and Jesse Jones
+ *
+ * Change History (most recent first):
+ *
+ * <4> 14/12/99 LRH Added cast_spec_spell_name()
+ * <3> 5/06/99 JDJ Added TRACE.
+ * <2> -/--/-- JDJ Added a bunch od debugging macros.
+ * Old code is now #if WIZARD.
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "debug.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#include "externs.h"
+
+#include "direct.h"
+#include "dungeon.h"
+#include "invent.h"
+#include "itemname.h"
+#include "items.h"
+#include "misc.h"
+#include "monplace.h"
+#include "monstuff.h"
+#include "mon-util.h"
+#include "mutation.h"
+#include "player.h"
+#include "randart.h"
+#include "religion.h"
+#include "skills.h"
+#include "skills2.h"
+#include "spl-cast.h"
+#include "spl-util.h"
+#include "stuff.h"
+
+#ifndef WIZARD
+#define WIZARD
+#endif
+
+#if DEBUG && WIN
+#define MyDebugBreak() _asm {int 3}
+#endif
+
+//-----------------------------------
+// Internal Variables
+//
+#if WIN
+static HANDLE sConsole = NULL;
+#endif
+
+// ========================================================================
+// Internal Functions
+// ========================================================================
+
+//---------------------------------------------------------------
+//
+// BreakStrToDebugger
+//
+//---------------------------------------------------------------
+#if DEBUG
+static void BreakStrToDebugger(const char *mesg)
+{
+
+#if OSX
+ fprintf(stderr, mesg);
+// raise(SIGINT); // this is what DebugStr() does on OS X according to Tech Note 2030
+ int* p = NULL; // but this gives us a stack crawl...
+ *p = 0;
+#elif MAC
+ unsigned char s[50];
+
+ int len = strlen(mesg);
+
+ if (len > 255)
+ len = 255;
+
+ s[0] = (Byte) len;
+ BlockMoveData(mesg, s + 1, len);
+
+ DebugStr(s);
+
+#elif WIN
+ MSG msg; // remove pending quit messages so the message box displays
+
+ bool quitting = (bool)::PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE);
+
+ char text[2500];
+
+ int flags = MB_YESNO + // want abort and ignore buttons
+ // (too bad we can't ditch the retry button...)
+ MB_ICONERROR + // display the icon for errors
+ MB_TASKMODAL + // don't let the user do anything else in the app
+ MB_SETFOREGROUND; // bring the app to the front
+
+ strcpy(text, mesg);
+ strcat(text, "\nDo you want to drop into the debugger?");
+
+ int result = MessageBoxA(NULL, text, "Debug Break", flags);
+
+ if (result == IDYES)
+ MyDebugBreak();
+
+ if (quitting)
+ PostQuitMessage(msg.wParam);
+
+#else
+ fprintf(stderr, "%s\n", mesg);
+ abort();
+#endif
+}
+#endif
+
+
+//---------------------------------------------------------------
+//
+// IsDebuggerPresent95
+//
+// From March 1999 Windows Developer's Journal. This should only
+// be called if we're running on Win 95 (normally I'd add an
+// ASSERT, but that's a bit dicy since this is called by ASSERT...)
+//
+//---------------------------------------------------------------
+#if WIN
+static bool IsDebuggerPresent95()
+{
+ bool present = false;
+
+ const DWORD kDebuggerPresentFlag = 0x000000001;
+ const DWORD kProcessDatabaseBytes = 190;
+ const DWORD kOffsetFlags = 8;
+
+ DWORD threadID = GetCurrentThreadId();
+ DWORD processID = GetCurrentProcessId();
+ DWORD obfuscator = 0;
+
+#if __MWERKS__
+ asm
+ {
+ mov ax, fs
+ mov es, ax
+ mov eax, 0x18
+ mov eax, es:[eax]
+ sub eax, 0x10 xor eax,[threadID] mov[obfuscator], eax
+ }
+
+#else
+ _asm
+ {
+ mov ax, fs
+ mov es, ax
+ mov eax, 18 h
+ mov eax, es:[eax]
+ sub eax, 10 h xor eax,[threadID] mov[obfuscator], eax
+ }
+#endif
+
+ const DWORD *processDatabase =
+ reinterpret_cast< const DWORD * >(processID ^ obfuscator);
+
+ if (!IsBadReadPtr(processDatabase, kProcessDatabaseBytes))
+ {
+ DWORD flags = processDatabase[kOffsetFlags];
+
+ present = (flags & kDebuggerPresentFlag) != 0;
+ }
+
+ return present;
+}
+#endif
+
+
+//---------------------------------------------------------------
+//
+// IsDebuggerPresent
+//
+//---------------------------------------------------------------
+#if WIN
+bool IsDebuggerPresent()
+{
+ bool present = false;
+
+ typedef BOOL(WINAPI * IsDebuggerPresentProc) ();
+
+ HINSTANCE kernelH = LoadLibrary("KERNEL32.DLL");
+
+ if (kernelH != NULL)
+ { // should never fail
+
+ IsDebuggerPresentProc proc =
+ (IsDebuggerPresentProc)::GetProcAddress( kernelH,
+ "IsDebuggerPresent" );
+
+ if (proc != NULL) // only present in NT and Win 98
+ present = proc() != 0;
+ else
+ present = IsDebuggerPresent95();
+ }
+
+ return present;
+}
+#endif
+
+
+//---------------------------------------------------------------
+//
+// CreateConsoleWindow
+//
+//---------------------------------------------------------------
+#if WIN
+static void CreateConsoleWindow()
+{
+ ASSERT(sConsole == NULL);
+
+ // Create the console window
+ if (::AllocConsole())
+ {
+ // Get the console window's handle
+ sConsole =::GetStdHandle(STD_ERROR_HANDLE);
+ if (sConsole == INVALID_HANDLE_VALUE)
+ sConsole = NULL;
+
+ // Set some options
+ if (sConsole != NULL)
+ {
+ VERIFY(::SetConsoleTextAttribute(sConsole, FOREGROUND_GREEN));
+ // green text on a black background (there doesn't appear to
+ // be a way to get black text)
+
+ VERIFY(::SetConsoleTitle("Debug Log"));
+
+ COORD size = { 80, 120 };
+
+ VERIFY(::SetConsoleScreenBufferSize(sConsole, size));
+ }
+ else
+ DEBUGSTR(L "Couldn't get the console window's handle!");
+ }
+ else
+ DEBUGSTR(L "Couldn't allocate the console window!");
+}
+#endif
+
+
+#if DEBUG
+//---------------------------------------------------------------
+//
+// TraceString
+//
+//---------------------------------------------------------------
+static void TraceString(const char *mesg)
+{
+ // Write the string to the debug window
+#if WIN
+ if (IsDebuggerPresent())
+ {
+ OutputDebugStringA(mesg); // if you're using CodeWarrior you'll need to enable the "Log System Messages" checkbox to get this working
+ }
+ else
+ {
+ if (sConsole == NULL) // otherwise we'll use a console window
+ CreateConsoleWindow();
+
+ if (sConsole != NULL)
+ {
+ unsigned long written;
+
+ VERIFY(WriteConsoleA(sConsole, mesg, strlen(mesg), &written, NULL));
+ }
+ }
+#else
+ fprintf(stderr, "%s", mesg);
+#endif
+
+ // Write the string to the debug log
+ static bool inited = false;
+ static FILE *file = NULL;
+
+ if (!inited)
+ {
+ ASSERT(file == NULL);
+
+ const char *fileName = "DebugLog.txt";
+
+ file = fopen(fileName, "w");
+ ASSERT(file != NULL);
+
+ inited = true;
+ }
+
+ if (file != NULL)
+ {
+ fputs(mesg, file);
+ fflush(file); // make sure all the output makes it to the file
+
+ }
+}
+#endif
+
+#if MAC
+#pragma mark -
+#endif
+
+// ========================================================================
+// Global Functions
+// ========================================================================
+
+//---------------------------------------------------------------
+//
+// AssertFailed
+//
+//---------------------------------------------------------------
+#if DEBUG
+void AssertFailed(const char *expr, const char *file, int line)
+{
+ char mesg[512];
+
+#if MAC
+ sprintf(mesg, "ASSERT(%s) in %s at line %d failed.", expr, file, line);
+
+#else
+ const char *fileName = file + strlen(file); // strip off path
+
+ while (fileName > file && fileName[-1] != '\\')
+ --fileName;
+
+ sprintf(mesg, "ASSERT(%s) in '%s' at line %d failed.", expr, fileName,
+ line);
+#endif
+
+ BreakStrToDebugger(mesg);
+}
+#endif
+
+
+//---------------------------------------------------------------
+//
+// DEBUGSTR
+//
+//---------------------------------------------------------------
+#if DEBUG
+void DEBUGSTR(const char *format, ...)
+{
+ char mesg[2048];
+
+ va_list args;
+
+ va_start(args, format);
+ vsprintf(mesg, format, args);
+ va_end(args);
+
+ BreakStrToDebugger(mesg);
+}
+#endif
+
+
+//---------------------------------------------------------------
+//
+// TRACE
+//
+//---------------------------------------------------------------
+#if DEBUG
+void TRACE(const char *format, ...)
+{
+ char mesg[2048];
+
+ va_list args;
+
+ va_start(args, format);
+ vsprintf(mesg, format, args);
+ va_end(args);
+
+ TraceString(mesg);
+}
+#endif // DEBUG
+
+//---------------------------------------------------------------
+//
+// debug_prompt_for_monster
+//
+//---------------------------------------------------------------
+#ifdef WIZARD
+static int debug_prompt_for_monster( void )
+{
+ char specs[80];
+ char obj_name[ ITEMNAME_SIZE ];
+ char *ptr;
+
+ mpr( "(Hint: 'generated' names, eg 'orc zombie', won't work)", MSGCH_PROMPT );
+ mpr( "Which monster by name? ", MSGCH_PROMPT );
+ get_input_line( specs, sizeof( specs ) );
+
+ if (specs[0] == '\0')
+ return (-1);
+
+ int mon = -1;
+
+ for (int i = 0; i < NUM_MONSTERS; i++)
+ {
+ moname( i, true, DESC_PLAIN, obj_name );
+
+ ptr = strstr( strlwr(obj_name), strlwr(specs) );
+ if (ptr != NULL)
+ {
+ mpr( obj_name );
+ if (ptr == obj_name)
+ {
+ // we prefer prefixes over partial matches
+ mon = i;
+ break;
+ }
+ else
+ mon = i;
+ }
+ }
+
+ return (mon);
+}
+#endif
+
+//---------------------------------------------------------------
+//
+// debug_prompt_for_skill
+//
+//---------------------------------------------------------------
+#ifdef WIZARD
+static int debug_prompt_for_skill( const char *prompt )
+{
+ char specs[80];
+
+ mpr( prompt, MSGCH_PROMPT );
+ get_input_line( specs, sizeof( specs ) );
+
+ if (specs[0] == '\0')
+ return (-1);
+
+ int skill = -1;
+
+ for (int i = 0; i < NUM_SKILLS; i++)
+ {
+ // avoid the bad values:
+ if (i == SK_UNUSED_1 || (i > SK_UNARMED_COMBAT && i < SK_SPELLCASTING))
+ continue;
+
+ char sk_name[80];
+ strncpy( sk_name, skill_name(i), sizeof( sk_name ) );
+
+ char *ptr = strstr( strlwr(sk_name), strlwr(specs) );
+ if (ptr != NULL)
+ {
+ if (ptr == sk_name && strlen(specs) > 0)
+ {
+ // we prefer prefixes over partial matches
+ skill = i;
+ break;
+ }
+ else
+ skill = i;
+ }
+ }
+
+ return (skill);
+}
+#endif
+
+//---------------------------------------------------------------
+//
+// debug_change_species
+//
+//---------------------------------------------------------------
+#ifdef WIZARD
+void debug_change_species( void )
+{
+ char specs[80];
+ int i;
+
+ mpr( "What species would you like to be now? " , MSGCH_PROMPT );
+ get_input_line( specs, sizeof( specs ) );
+
+ if (specs[0] == '\0')
+ return;
+
+ int sp = -1;
+
+ for (int i = SP_HUMAN; i < NUM_SPECIES; i++)
+ {
+ char sp_name[80];
+ strncpy( sp_name, species_name(i, you.experience_level), sizeof( sp_name ) );
+
+ char *ptr = strstr( strlwr(sp_name), strlwr(specs) );
+ if (ptr != NULL)
+ {
+ if (ptr == sp_name && strlen(specs) > 0)
+ {
+ // we prefer prefixes over partial matches
+ sp = i;
+ break;
+ }
+ else
+ sp = i;
+ }
+ }
+
+ if (sp == -1)
+ mpr( "That species isn't available." );
+ else
+ {
+ for (i = 0; i < NUM_SKILLS; i++)
+ {
+ you.skill_points[i] *= species_skills( i, sp );
+ you.skill_points[i] /= species_skills( i, you.species );
+ }
+
+ you.species = sp;
+
+ redraw_screen();
+ }
+}
+#endif
+//---------------------------------------------------------------
+//
+// debug_prompt_for_int
+//
+// If nonneg, then it returns a non-negative number or -1 on fail
+// If !nonneg, then it returns an integer, and 0 on fail
+//
+//---------------------------------------------------------------
+#ifdef WIZARD
+static int debug_prompt_for_int( const char *prompt, bool nonneg )
+{
+ char specs[80];
+
+ mpr( prompt, MSGCH_PROMPT );
+ get_input_line( specs, sizeof( specs ) );
+
+ if (specs[0] == '\0')
+ return (nonneg ? -1 : 0);
+
+ char *end;
+ int ret = strtol( specs, &end, 10 );
+
+ if ((ret < 0 && nonneg) || (ret == 0 && end == specs))
+ ret = (nonneg ? -1 : 0);
+
+ return (ret);
+}
+#endif
+
+/*
+ Some debugging functions, accessable through keys like %, $, &, ) etc when
+ a section of code in input() in acr.cc is uncommented.
+ */
+
+//---------------------------------------------------------------
+//
+// cast_spec_spell
+//
+//---------------------------------------------------------------
+#ifdef WIZARD
+void cast_spec_spell(void)
+{
+ int spell = debug_prompt_for_int( "Cast which spell by number? ", true );
+
+ if (spell == -1)
+ canned_msg( MSG_OK );
+ else
+ your_spells( spell, 0, false );
+}
+#endif
+
+
+//---------------------------------------------------------------
+//
+// cast_spec_spell_name
+//
+//---------------------------------------------------------------
+#ifdef WIZARD
+void cast_spec_spell_name(void)
+{
+ int i = 0;
+ char specs[80];
+ char spname[80];
+
+ mpr( "Cast which spell by name? ", MSGCH_PROMPT );
+ get_input_line( specs, sizeof( specs ) );
+
+ for (i = 0; i < NUM_SPELLS; i++)
+ {
+ strncpy( spname, spell_title(i), sizeof( spname ) );
+
+ if (strstr( strlwr(spname), strlwr(specs) ) != NULL)
+ {
+ your_spells(i, 0, false);
+ return;
+ }
+ }
+
+ mpr((one_chance_in(20)) ? "Maybe you should go back to WIZARD school."
+ : "I couldn't find that spell.");
+}
+#endif
+
+
+//---------------------------------------------------------------
+//
+// create_spec_monster
+//
+//---------------------------------------------------------------
+#ifdef WIZARD
+void create_spec_monster(void)
+{
+ int mon = debug_prompt_for_int( "Create which monster by number? ", true );
+
+ if (mon == -1)
+ canned_msg( MSG_OK );
+ else
+ create_monster( mon, 0, BEH_SLEEP, you.x_pos, you.y_pos, MHITNOT, 250 );
+} // end create_spec_monster()
+#endif
+
+
+//---------------------------------------------------------------
+//
+// create_spec_monster_name
+//
+//---------------------------------------------------------------
+#ifdef WIZARD
+void create_spec_monster_name(void)
+{
+ int mon = debug_prompt_for_monster();
+
+ if (mon == -1)
+ {
+ mpr("I couldn't find that monster.");
+
+ if (one_chance_in(20))
+ mpr("Maybe it's hiding.");
+ }
+ else
+ {
+ create_monster(mon, 0, BEH_SLEEP, you.x_pos, you.y_pos, MHITNOT, 250);
+ }
+} // end create_spec_monster_name()
+#endif
+
+
+//---------------------------------------------------------------
+//
+// level_travel
+//
+//---------------------------------------------------------------
+#ifdef WIZARD
+void level_travel( int delta )
+{
+ int old_level = you.your_level;
+ int new_level = you.your_level + delta;
+
+ if (delta == 0)
+ {
+ new_level = debug_prompt_for_int( "Travel to which level? ", true ) - 1;
+ }
+
+ if (new_level < 0 || new_level >= 50)
+ {
+ mpr( "That level is out of bounds." );
+ return;
+ }
+
+ you.your_level = new_level - 1;
+ grd[you.x_pos][you.y_pos] = DNGN_STONE_STAIRS_DOWN_I;
+ down_stairs(true, old_level);
+ untag_followers();
+} // end level_travel()
+#endif
+
+
+//---------------------------------------------------------------
+//
+// create_spec_object
+//
+//---------------------------------------------------------------
+#ifdef WIZARD
+void create_spec_object(void)
+{
+ static int max_subtype[] =
+ {
+ NUM_WEAPONS,
+ NUM_MISSILES,
+ NUM_ARMOURS,
+ NUM_WANDS,
+ NUM_FOODS,
+ 0, // unknown I
+ NUM_SCROLLS,
+ NUM_JEWELLERY,
+ NUM_POTIONS,
+ 0, // unknown II
+ NUM_BOOKS,
+ NUM_STAVES,
+ 0, // Orbs -- only one, handled specially
+ NUM_MISCELLANY,
+ 0, // corpses -- handled specially
+ 0, // gold -- handled specially
+ 0, // "gemstones" -- no items of type
+ };
+
+ char specs[80];
+ char obj_name[ ITEMNAME_SIZE ];
+ char keyin;
+
+ char * ptr;
+ int best_index;
+ int mon;
+ int i;
+
+ int class_wanted = OBJ_UNASSIGNED;
+ int type_wanted = -1;
+ int special_wanted = 0;
+
+ int thing_created;
+
+ for (;;)
+ {
+ mpr(") - weapons ( - missiles [ - armour / - wands ? - scrolls",
+ MSGCH_PROMPT);
+ mpr("= - jewellery ! - potions : - books | - staves 0 - The Orb",
+ MSGCH_PROMPT);
+ mpr("} - miscellany X - corpses %% - food $ - gold ESC - exit",
+ MSGCH_PROMPT);
+
+ mpr("What class of item? ", MSGCH_PROMPT);
+
+ keyin = toupper( get_ch() );
+
+ if (keyin == ')')
+ class_wanted = OBJ_WEAPONS;
+ else if (keyin == '(')
+ class_wanted = OBJ_MISSILES;
+ else if (keyin == '[' || keyin == ']')
+ class_wanted = OBJ_ARMOUR;
+ else if (keyin == '/' || keyin == '\\')
+ class_wanted = OBJ_WANDS;
+ else if (keyin == '?')
+ class_wanted = OBJ_SCROLLS;
+ else if (keyin == '=' || keyin == '"')
+ class_wanted = OBJ_JEWELLERY;
+ else if (keyin == '!')
+ class_wanted = OBJ_POTIONS;
+ else if (keyin == ':')
+ class_wanted = OBJ_BOOKS;
+ else if (keyin == '|')
+ class_wanted = OBJ_STAVES;
+ else if (keyin == '0' || keyin == 'O')
+ class_wanted = OBJ_ORBS;
+ else if (keyin == '}' || keyin == '{')
+ class_wanted = OBJ_MISCELLANY;
+ else if (keyin == 'X')
+ class_wanted = OBJ_CORPSES;
+ else if (keyin == '%')
+ class_wanted = OBJ_FOOD;
+ else if (keyin == '$')
+ class_wanted = OBJ_GOLD;
+ else if (keyin == ESCAPE || keyin == ' '
+ || keyin == '\r' || keyin == '\n')
+ {
+ canned_msg( MSG_OK );
+ return;
+ }
+
+ if (class_wanted != OBJ_UNASSIGNED)
+ break;
+ }
+
+ // allocate an item to play with:
+ thing_created = get_item_slot();
+ if (thing_created == NON_ITEM)
+ {
+ mpr( "Could not allocate item." );
+ return;
+ }
+
+ // turn item into appropriate kind:
+ if (class_wanted == OBJ_ORBS)
+ {
+ mitm[thing_created].base_type = OBJ_ORBS;
+ mitm[thing_created].sub_type = ORB_ZOT;
+ mitm[thing_created].quantity = 1;
+ }
+ else if (class_wanted == OBJ_GOLD)
+ {
+ int amount = debug_prompt_for_int( "How much gold? ", true );
+ if (amount <= 0)
+ {
+ canned_msg( MSG_OK );
+ return;
+ }
+
+ mitm[thing_created].base_type = OBJ_GOLD;
+ mitm[thing_created].sub_type = 0;
+ mitm[thing_created].quantity = amount;
+ }
+ else if (class_wanted == OBJ_CORPSES)
+ {
+ mon = debug_prompt_for_monster();
+
+ if (mon == -1)
+ {
+ mpr( "No such monster." );
+ return;
+ }
+
+ mitm[thing_created].base_type = OBJ_CORPSES;
+ mitm[thing_created].sub_type = CORPSE_BODY;
+ mitm[thing_created].plus = mon;
+ mitm[thing_created].plus2 = 0;
+ mitm[thing_created].special = 210;
+ mitm[thing_created].colour = mons_colour(mon);;
+ mitm[thing_created].quantity = 1;
+ mitm[thing_created].flags = 0;
+ }
+ else
+ {
+ mpr( "What type of item? ", MSGCH_PROMPT );
+ get_input_line( specs, sizeof( specs ) );
+
+ if (specs[0] == '\0')
+ {
+ canned_msg( MSG_OK );
+ return;
+ }
+
+ // In order to get the sub-type, we'll fill out the base type...
+ // then we're going to iterate over all possible subtype values
+ // and see if we get a winner. -- bwr
+ mitm[thing_created].base_type = class_wanted;
+ mitm[thing_created].sub_type = 0;
+ mitm[thing_created].plus = 0;
+ mitm[thing_created].plus2 = 0;
+ mitm[thing_created].special = 0;
+ mitm[thing_created].flags = 0;
+ mitm[thing_created].quantity = 1;
+ set_ident_flags( mitm[thing_created], ISFLAG_IDENT_MASK );
+
+ if (class_wanted == OBJ_ARMOUR)
+ {
+ if (strstr( "naga barding", specs ))
+ {
+ mitm[thing_created].sub_type = ARM_BOOTS;
+ mitm[thing_created].plus2 = TBOOT_NAGA_BARDING;
+ }
+ else if (strstr( "centaur barding", specs ))
+ {
+ mitm[thing_created].sub_type = ARM_BOOTS;
+ mitm[thing_created].plus2 = TBOOT_CENTAUR_BARDING;
+ }
+ else if (strstr( "wizard's hat", specs ))
+ {
+ mitm[thing_created].sub_type = ARM_HELMET;
+ mitm[thing_created].plus2 = THELM_WIZARD_HAT;
+ }
+ else if (strstr( "cap", specs ))
+ {
+ mitm[thing_created].sub_type = ARM_HELMET;
+ mitm[thing_created].plus2 = THELM_CAP;
+ }
+ else if (strstr( "helm", specs ))
+ {
+ mitm[thing_created].sub_type = ARM_HELMET;
+ mitm[thing_created].plus2 = THELM_HELM;
+ }
+ }
+
+ if (!mitm[thing_created].sub_type)
+ {
+ type_wanted = -1;
+ best_index = 10000;
+
+ for (i = 0; i < max_subtype[ mitm[thing_created].base_type ]; i++)
+ {
+ mitm[thing_created].sub_type = i;
+ item_name( mitm[thing_created], DESC_PLAIN, obj_name );
+
+ ptr = strstr( strlwr(obj_name), strlwr(specs) );
+ if (ptr != NULL)
+ {
+ // earliest match is the winner
+ if (ptr - obj_name < best_index)
+ {
+ mpr( obj_name );
+ type_wanted = i;
+ best_index = ptr - obj_name;
+ }
+ }
+ }
+
+ if (type_wanted == -1)
+ {
+ mpr( "No such item." );
+ return;
+ }
+
+ mitm[thing_created].sub_type = type_wanted;
+ }
+
+ switch (mitm[thing_created].base_type)
+ {
+ case OBJ_MISSILES:
+ mitm[thing_created].quantity = 30;
+ // intentional fall-through
+ case OBJ_WEAPONS:
+ case OBJ_ARMOUR:
+ mpr( "What ego type? ", MSGCH_PROMPT );
+ get_input_line( specs, sizeof( specs ) );
+
+ if (specs[0] != '\0')
+ {
+ special_wanted = 0;
+ best_index = 10000;
+
+ for (i = 1; i < 25; i++)
+ {
+ mitm[thing_created].special = i;
+ item_name( mitm[thing_created], DESC_PLAIN, obj_name );
+
+ ptr = strstr( strlwr(obj_name), strlwr(specs) );
+ if (ptr != NULL)
+ {
+ // earliest match is the winner
+ if (ptr - obj_name < best_index)
+ {
+ mpr( obj_name );
+ special_wanted = i;
+ best_index = ptr - obj_name;
+ }
+ }
+ }
+
+ mitm[thing_created].special = special_wanted;
+ }
+ break;
+
+ case OBJ_BOOKS:
+ if (mitm[thing_created].sub_type == BOOK_MANUAL)
+ {
+ special_wanted = debug_prompt_for_skill( "A manual for which skill? " );
+ if (special_wanted != -1)
+ mitm[thing_created].plus = special_wanted;
+ else
+ mpr( "Sorry, no books on that skill today." );
+ }
+ break;
+
+ case OBJ_WANDS:
+ mitm[thing_created].plus = 24;
+ break;
+
+ case OBJ_MISCELLANY:
+ // Runes to "demonic", decks have 50 cards, ignored elsewhere?
+ mitm[thing_created].plus = 50;
+ break;
+
+ case OBJ_FOOD:
+ case OBJ_SCROLLS:
+ case OBJ_POTIONS:
+ mitm[thing_created].quantity = 12;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ item_colour( mitm[thing_created] );
+
+ move_item_to_grid( &thing_created, you.x_pos, you.y_pos );
+
+ if (thing_created != NON_ITEM)
+ canned_msg( MSG_SOMETHING_APPEARS );
+
+}
+#endif
+
+
+//---------------------------------------------------------------
+//
+// create_spec_object
+//
+//---------------------------------------------------------------
+#ifdef WIZARD
+void tweak_object(void)
+{
+ char specs[50];
+ char keyin;
+
+ int item = prompt_invent_item( "Tweak which item? ", -1 );
+ if (item == PROMPT_ABORT)
+ {
+ canned_msg( MSG_OK );
+ return;
+ }
+
+ if (item == you.equip[EQ_WEAPON])
+ you.wield_change = true;
+
+ for (;;)
+ {
+ void *field_ptr = NULL;
+
+ for (;;)
+ {
+ item_name( you.inv[item], DESC_INVENTORY_EQUIP, info );
+ mpr( info );
+
+ mpr( "a - plus b - plus2 c - special d - quantity ESC - exit",
+ MSGCH_PROMPT );
+ mpr( "Which field? ", MSGCH_PROMPT );
+
+ keyin = tolower( get_ch() );
+
+ if (keyin == 'a')
+ field_ptr = &(you.inv[item].plus);
+ else if (keyin == 'b')
+ field_ptr = &(you.inv[item].plus2);
+ else if (keyin == 'c')
+ field_ptr = &(you.inv[item].special);
+ else if (keyin == 'd')
+ field_ptr = &(you.inv[item].quantity);
+ else if (keyin == ESCAPE || keyin == ' '
+ || keyin == '\r' || keyin == '\n')
+ {
+ canned_msg( MSG_OK );
+ return;
+ }
+
+ if (keyin >= 'a' && keyin <= 'd')
+ break;
+ }
+
+ if (keyin != 'c')
+ {
+ const short *const ptr = static_cast< short * >( field_ptr );
+ snprintf( info, INFO_SIZE, "Old value: %d (0x%04x)", *ptr, *ptr );
+ }
+ else
+ {
+ const long *const ptr = static_cast< long * >( field_ptr );
+ snprintf( info, INFO_SIZE, "Old value: %ld (0x%08lx)", *ptr, *ptr );
+ }
+
+ mpr( info );
+
+ mpr( "New value? ", MSGCH_PROMPT );
+ get_input_line( specs, sizeof( specs ) );
+
+ if (specs[0] == '\0')
+ return;
+
+ char *end;
+ int new_value = strtol( specs, &end, 10 );
+
+ if (new_value == 0 && end == specs)
+ return;
+
+ if (keyin != 'c')
+ {
+ short *ptr = static_cast< short * >( field_ptr );
+ *ptr = new_value;
+ }
+ else
+ {
+ long *ptr = static_cast< long * >( field_ptr );
+ *ptr = new_value;
+ }
+ }
+}
+#endif
+
+
+//---------------------------------------------------------------
+//
+// stethoscope
+//
+//---------------------------------------------------------------
+#if DEBUG_DIAGNOSTICS
+
+static const char *enchant_names[] =
+{
+ "None",
+ "Slow", "Haste", "*BUG-3*", "Fear", "Conf", "Invis",
+ "YPois-1", "YPois-2", "YPois-3", "YPois-4",
+ "YShug-1", "YShug-2", "YShug-3", "YShug-4",
+ "YRot-1", "YRot-2", "YRot-3", "YRot-4",
+ "Summon", "Abj-1", "Abj-2", "Abj-3", "Abj-4", "Abj-5", "Abj-6",
+ "Corona-1", "Corona-2", "Corona-3", "Corona-4",
+ "Charm", "YSticky-1", "YSticky-2", "YSticky-3", "YSticky-4",
+ "*BUG-35*", "*BUG-36*", "*BUG-37*",
+ "GlowShapeshifter", "Shapeshifter",
+ "Tele-1", "Tele-2", "Tele-3", "Tele-4",
+ "*BUG-44*", "*BUG-45*", "*BUG-46*", "*BUG-47*", "*BUG-48*", "*BUG-49*",
+ "*BUG-50*", "*BUG-51*", "*BUG-52*", "*BUG-53*", "*BUG-54*", "*BUG-55*",
+ "*BUG-56*",
+ "Pois-1", "Pois-2", "Pois-3", "Pois-4",
+ "Sticky-1", "Sticky-2", "Sticky-3", "Sticky-4",
+ "OldAbj-1", "OldAbj-2", "OldAbj-3", "OldAbj-4", "OldAbj-5", "OldAbj-6",
+ "OldCreatedFriendly", "SleepWary", "Submerged", "Short Lived",
+ "*BUG-too big*"
+};
+
+void stethoscope(int mwh)
+{
+ struct dist stth;
+ int steth_x, steth_y;
+ int i, j;
+
+ if (mwh != RANDOM_MONSTER)
+ i = mwh;
+ else
+ {
+ mpr( "Which monster?", MSGCH_PROMPT );
+
+ direction( stth );
+
+ if (!stth.isValid)
+ return;
+
+ if (stth.isTarget)
+ {
+ steth_x = stth.tx;
+ steth_y = stth.ty;
+ }
+ else
+ {
+ steth_x = you.x_pos + stth.dx;
+ steth_y = you.x_pos + stth.dy;
+ }
+
+ if (env.cgrid[steth_x][steth_y] != EMPTY_CLOUD)
+ {
+ snprintf( info, INFO_SIZE, "cloud type: %d delay: %d",
+ env.cloud[ env.cgrid[steth_x][steth_y] ].type,
+ env.cloud[ env.cgrid[steth_x][steth_y] ].decay );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+ }
+
+ if (mgrd[steth_x][steth_y] == NON_MONSTER)
+ {
+ snprintf( info, INFO_SIZE, "item grid = %d", igrd[steth_x][steth_y] );
+ mpr( info, MSGCH_DIAGNOSTICS );
+ return;
+ }
+
+ i = mgrd[steth_x][steth_y];
+ }
+
+ // print type of monster
+ snprintf( info, INFO_SIZE, "%s (id #%d; type=%d loc=(%d,%d) align=%s)",
+ monam( menv[i].number, menv[i].type, true, DESC_CAP_THE ),
+ i, menv[i].type,
+ menv[i].x, menv[i].y,
+ ((menv[i].attitude == ATT_FRIENDLY) ? "friendly" :
+ (menv[i].attitude == ATT_HOSTILE) ? "hostile" :
+ (menv[i].attitude == ATT_NEUTRAL) ? "neutral"
+ : "unknown alignment") );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+
+ // print stats and other info
+ snprintf( info, INFO_SIZE,"HD=%d HP=%d/%d AC=%d EV=%d MR=%d SP=%d energy=%d num=%d flags=%02x",
+ menv[i].hit_dice,
+ menv[i].hit_points, menv[i].max_hit_points,
+ menv[i].armour_class, menv[i].evasion,
+ mons_resist_magic( &menv[i] ),
+ menv[i].speed, menv[i].speed_increment,
+ menv[i].number, menv[i].flags );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+
+ // print behaviour information
+
+ const int hab = monster_habitat( menv[i].type );
+
+ snprintf( info, INFO_SIZE, "hab=%s beh=%s(%d) foe=%s(%d) mem=%d target=(%d,%d)",
+ ((hab == DNGN_DEEP_WATER) ? "water" :
+ (hab == DNGN_LAVA) ? "lava"
+ : "floor"),
+
+ ((menv[i].behaviour == BEH_SLEEP) ? "sleep" :
+ (menv[i].behaviour == BEH_WANDER) ? "wander" :
+ (menv[i].behaviour == BEH_SEEK) ? "seek" :
+ (menv[i].behaviour == BEH_FLEE) ? "flee" :
+ (menv[i].behaviour == BEH_CORNERED) ? "cornered"
+ : "unknown"),
+ menv[i].behaviour,
+
+ ((menv[i].foe == MHITYOU) ? "you" :
+ (menv[i].foe == MHITNOT) ? "none" :
+ (menv[menv[i].foe].type == -1) ? "unassigned monster"
+ : monam( menv[menv[i].foe].number, menv[menv[i].foe].type,
+ true, DESC_PLAIN )),
+ menv[i].foe,
+ menv[i].foe_memory,
+
+ menv[i].target_x, menv[i].target_y );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+
+ // print resistances
+ snprintf( info, INFO_SIZE, "resist: fire=%d cold=%d elec=%d pois=%d neg=%d",
+ mons_res_fire( &menv[i] ),
+ mons_res_cold( &menv[i] ),
+ mons_res_elec( &menv[i] ),
+ mons_res_poison( &menv[i] ),
+ mons_res_negative_energy( &menv[i] ) );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+
+
+ // print enchantments
+ strncpy( info, "ench: ", INFO_SIZE );
+ for (j = 0; j < 6; j++)
+ {
+ if (menv[i].enchantment[j] >= NUM_ENCHANTMENTS)
+ strncat( info, enchant_names[ NUM_ENCHANTMENTS ], INFO_SIZE );
+ else
+ strncat( info, enchant_names[ menv[i].enchantment[j] ], INFO_SIZE );
+
+ if (strlen( info ) <= 70)
+ strncat( info, " ", INFO_SIZE );
+ else if (j < 5)
+ {
+ mpr( info, MSGCH_DIAGNOSTICS );
+ strncpy( info, "ench: ", INFO_SIZE );
+ }
+ }
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+
+ if (menv[i].type == MONS_PLAYER_GHOST
+ || menv[i].type == MONS_PANDEMONIUM_DEMON)
+ {
+ snprintf( info, INFO_SIZE, "Ghost damage: %d; brand: %d",
+ ghost.values[ GVAL_DAMAGE ], ghost.values[ GVAL_BRAND ] );
+ mpr( info, MSGCH_DIAGNOSTICS );
+ }
+} // end stethoscope()
+#endif
+
+#if DEBUG_ITEM_SCAN
+//---------------------------------------------------------------
+//
+// dump_item
+//
+//---------------------------------------------------------------
+static void dump_item( const char *name, int num, const item_def &item )
+{
+ mpr( name, MSGCH_WARN );
+
+ snprintf( info, INFO_SIZE, " item #%d: base: %d; sub: %d; plus: %d; plus2: %d; special: %ld",
+ num, item.base_type, item.sub_type,
+ item.plus, item.plus2, item.special );
+
+ mpr( info );
+
+ snprintf( info, INFO_SIZE, " quant: %d; colour: %d; ident: 0x%08lx; ident_type: %d",
+ item.quantity, item.colour, item.flags,
+ get_ident_type( item.base_type, item.sub_type ) );
+
+ mpr( info );
+
+ snprintf( info, INFO_SIZE, " x: %d; y: %d; link: %d",
+ item.x, item.y, item.link );
+
+ mpr( info );
+}
+
+//---------------------------------------------------------------
+//
+// debug_item_scan
+//
+//---------------------------------------------------------------
+void debug_item_scan( void )
+{
+ int i;
+ char name[256];
+
+ // unset marks
+ for (i = 0; i < MAX_ITEMS; i++)
+ mitm[i].flags &= (~ISFLAG_DEBUG_MARK);
+
+ // First we're going to check all the stacks on the level:
+ for (int x = 0; x < GXM; x++)
+ {
+ for (int y = 0; y < GYM; y++)
+ {
+ // These are unlinked monster inventory items -- skip them:
+ if (x == 0 && y == 0)
+ continue;
+
+ // Looking for infinite stacks (ie more links than tems allowed)
+ // and for items which have bad coordinates (can't find their stack)
+ for (int obj = igrd[x][y]; obj != NON_ITEM; obj = mitm[obj].link)
+ {
+ // Check for invalid (zero quantity) items that are linked in
+ if (!is_valid_item( mitm[obj] ))
+ {
+ snprintf( info, INFO_SIZE, "Linked invalid item at (%d,%d)!", x, y);
+ mpr( info, MSGCH_WARN );
+ item_name( mitm[obj], DESC_PLAIN, name );
+ dump_item( name, obj, mitm[obj] );
+ }
+
+ // Check that item knows what stack it's in
+ if (mitm[obj].x != x || mitm[obj].y != y)
+ {
+ snprintf( info, INFO_SIZE, "Item position incorrect at (%d,%d)!", x, y);
+ mpr( info, MSGCH_WARN );
+ item_name( mitm[obj], DESC_PLAIN, name );
+ dump_item( name, obj, mitm[obj] );
+ }
+
+ // If we run into a premarked item we're in real trouble,
+ // this will also keep this from being an infinite loop.
+ if (mitm[obj].flags & ISFLAG_DEBUG_MARK)
+ {
+ snprintf( info, INFO_SIZE, "Potential INFINITE STACK at (%d, %d)", x, y);
+ mpr( info, MSGCH_WARN );
+ break;
+ }
+
+ mitm[obj].flags |= ISFLAG_DEBUG_MARK;
+ }
+ }
+ }
+
+ // Now scan all the items on the level:
+ for (i = 0; i < MAX_ITEMS; i++)
+ {
+ if (!is_valid_item( mitm[i] ))
+ continue;
+
+ item_name( mitm[i], DESC_PLAIN, name );
+
+ // Don't check (-1,-1) player items or (0,0) monster items
+ if ((mitm[i].x > 0 || mitm[i].y > 0)
+ && !(mitm[i].flags & ISFLAG_DEBUG_MARK))
+ {
+ mpr( "Unlinked item:", MSGCH_WARN );
+ dump_item( name, i, mitm[i] );
+
+ snprintf( info, INFO_SIZE, "igrd(%d,%d) = %d", mitm[i].x, mitm[i].y,
+ igrd[ mitm[i].x ][ mitm[i].y ] );
+ mpr( info );
+
+ // Let's check to see if it's an errant monster object:
+ for (int j = 0; j < MAX_MONSTERS; j++)
+ {
+ for (int k = 0; k < NUM_MONSTER_SLOTS; k++)
+ {
+ if (menv[j].inv[k] == i)
+ {
+ snprintf( info, INFO_SIZE, "Held by monster #%d: %s at (%d,%d)",
+ j, ptr_monam( &menv[j], DESC_CAP_A ),
+ menv[j].x, menv[j].y );
+
+ mpr( info );
+ }
+ }
+ }
+ }
+
+ // Current bad items of interest:
+ // -- armour and weapons with large enchantments/illegal special vals
+ //
+ // -- items described as questionable (the class 100 bug)
+ //
+ // -- eggplant is an illegal throwing weapon
+ //
+ // -- bola is an illegal fixed artefact
+ //
+ // -- items described as buggy (typically adjectives out of range)
+ // (note: covers buggy, bugginess, buggily, whatever else)
+ //
+ if (strstr( name, "questionable" ) != NULL
+ || strstr( name, "eggplant" ) != NULL
+ || strstr( name, "bola" ) != NULL
+ || strstr( name, "bugg" ) != NULL)
+ {
+ mpr( "Bad item:", MSGCH_WARN );
+ dump_item( name, i, mitm[i] );
+ }
+ else if ((mitm[i].base_type == OBJ_WEAPONS
+ && (abs(mitm[i].plus) > 30
+ || abs(mitm[i].plus2) > 30
+ || (!is_random_artefact( mitm[i] )
+ && (mitm[i].special >= 30
+ && mitm[i].special < 181))))
+
+ || (mitm[i].base_type == OBJ_MISSILES
+ && (abs(mitm[i].plus) > 25
+ || (!is_random_artefact( mitm[i] )
+ && mitm[i].special >= 30)))
+
+ || (mitm[i].base_type == OBJ_ARMOUR
+ && (abs(mitm[i].plus) > 25
+ || (!is_random_artefact( mitm[i] )
+ && mitm[i].sub_type != ARM_HELMET
+ && mitm[i].special >= 30))))
+ {
+ mpr( "Bad plus or special value:", MSGCH_WARN );
+ dump_item( name, i, mitm[i] );
+ }
+ }
+
+ // Don't want debugging marks interfering with anything else.
+ for (i = 0; i < MAX_ITEMS; i++)
+ mitm[i].flags &= (~ISFLAG_DEBUG_MARK);
+
+ // Quickly scan monsters for "program bug"s.
+ for (i = 0; i < MAX_MONSTERS; i++)
+ {
+ const struct monsters *const monster = &menv[i];
+
+ if (monster->type == -1)
+ continue;
+
+ moname( monster->type, true, DESC_PLAIN, name );
+
+ if (strcmp( name, "program bug" ) == 0)
+ {
+ mpr( "Program bug detected!", MSGCH_WARN );
+
+ snprintf( info, INFO_SIZE,
+ "Buggy monster detected: monster #%d; position (%d,%d)",
+ i, monster->x, monster->y );
+
+ mpr( info, MSGCH_WARN );
+ }
+ }
+}
+#endif
+
+//---------------------------------------------------------------
+//
+// debug_add_skills
+//
+//---------------------------------------------------------------
+#ifdef WIZARD
+void debug_add_skills(void)
+{
+ int skill = debug_prompt_for_skill( "Which skill (by name)? " );
+
+ if (skill == -1)
+ mpr("That skill doesn't seem to exist.");
+ else
+ {
+ mpr("Exercising...");
+ exercise(skill, 100);
+ }
+} // end debug_add_skills()
+#endif
+
+//---------------------------------------------------------------
+//
+// debug_set_skills
+//
+//---------------------------------------------------------------
+#ifdef WIZARD
+void debug_set_skills(void)
+{
+ int skill = debug_prompt_for_skill( "Which skill (by name)? " );
+
+ if (skill == -1)
+ mpr("That skill doesn't seem to exist.");
+ else
+ {
+ mpr( skill_name(skill) );
+ int amount = debug_prompt_for_int( "To what level? ", true );
+
+ if (amount == -1)
+ canned_msg( MSG_OK );
+ else
+ {
+ const int points = (skill_exp_needed( amount + 1 )
+ * species_skills( skill, you.species )) / 100;
+
+ you.skill_points[skill] = points + 1;
+ you.skills[skill] = amount;
+
+ calc_total_skill_points();
+
+ redraw_skill( you.your_name, player_title() );
+
+ switch (skill)
+ {
+ case SK_FIGHTING:
+ calc_hp();
+ break;
+
+ case SK_SPELLCASTING:
+ case SK_INVOCATIONS:
+ case SK_EVOCATIONS:
+ calc_mp();
+ break;
+
+ case SK_DODGING:
+ you.redraw_evasion = 1;
+ break;
+
+ case SK_ARMOUR:
+ you.redraw_armour_class = 1;
+ you.redraw_evasion = 1;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+} // end debug_add_skills()
+#endif
+
+
+//---------------------------------------------------------------
+//
+// debug_set_all_skills
+//
+//---------------------------------------------------------------
+#ifdef WIZARD
+void debug_set_all_skills(void)
+{
+ int i;
+ int amount = debug_prompt_for_int( "Set all skills to what level? ", true );
+
+ if (amount < 0) // cancel returns -1 -- bwr
+ canned_msg( MSG_OK );
+ else
+ {
+ if (amount > 27)
+ amount = 27;
+
+ for (i = SK_FIGHTING; i < NUM_SKILLS; i++)
+ {
+ if (i == SK_UNUSED_1
+ || (i > SK_UNARMED_COMBAT && i < SK_SPELLCASTING))
+ {
+ continue;
+ }
+
+ const int points = (skill_exp_needed( amount + 1 )
+ * species_skills( i, you.species )) / 100;
+
+ you.skill_points[i] = points + 1;
+ you.skills[i] = amount;
+ }
+
+ redraw_skill( you.your_name, player_title() );
+
+ calc_total_skill_points();
+
+ calc_hp();
+ calc_mp();
+
+ you.redraw_armour_class = 1;
+ you.redraw_evasion = 1;
+ }
+} // end debug_add_skills()
+#endif
+
+
+//---------------------------------------------------------------
+//
+// debug_add_mutation
+//
+//---------------------------------------------------------------
+#ifdef WIZARD
+bool debug_add_mutation(void)
+{
+ bool success = false;
+ char specs[80];
+
+ // Yeah, the gaining message isn't too good for this... but
+ // there isn't an array of simple mutation names. -- bwr
+ mpr( "Which mutation (by message when getting mutation)? ", MSGCH_PROMPT );
+ get_input_line( specs, sizeof( specs ) );
+
+ if (specs[0] == '\0')
+ return (false);
+
+ int mutation = -1;
+
+ for (int i = 0; i < NUM_MUTATIONS; i++)
+ {
+ char mut_name[80];
+ strncpy( mut_name, mutation_name( i, 1 ), sizeof( mut_name ) );
+
+ char *ptr = strstr( strlwr(mut_name), strlwr(specs) );
+ if (ptr != NULL)
+ {
+ // we take the first mutation that matches
+ mutation = i;
+ break;
+ }
+ }
+
+ if (mutation == -1)
+ mpr("I can't warp you that way!");
+ else
+ {
+ snprintf( info, INFO_SIZE, "Found: %s", mutation_name( mutation, 1 ) );
+ mpr( info );
+
+ int levels = debug_prompt_for_int( "How many levels? ", false );
+
+ if (levels == 0)
+ {
+ canned_msg( MSG_OK );
+ success = false;
+ }
+ else if (levels > 0)
+ {
+ for (int i = 0; i < levels; i++)
+ {
+ if (mutate( mutation ))
+ success = true;
+ }
+ }
+ else
+ {
+ for (int i = 0; i < -levels; i++)
+ {
+ if (delete_mutation( mutation ))
+ success = true;
+ }
+ }
+ }
+
+ return (success);
+} // end debug_add_mutation()
+#endif
+
+
+//---------------------------------------------------------------
+//
+// debug_get_religion
+//
+//---------------------------------------------------------------
+#ifdef WIZARD
+void debug_get_religion(void)
+{
+ char specs[80];
+
+ mpr( "Which god (by name)? ", MSGCH_PROMPT );
+ get_input_line( specs, sizeof( specs ) );
+
+ if (specs[0] == '\0')
+ return;
+
+ int god = -1;
+
+ for (int i = 1; i < NUM_GODS; i++)
+ {
+ char name[80];
+ strncpy( name, god_name(i), sizeof( name ) );
+
+ char *ptr = strstr( strlwr(name), strlwr(specs) );
+ if (ptr != NULL)
+ {
+ god = i;
+ break;
+ }
+ }
+
+ if (god == -1)
+ mpr( "That god doesn't seem to be taking followers today." );
+ else
+ {
+ grd[you.x_pos][you.y_pos] = 179 + god;
+ god_pitch(god);
+ }
+} // end debug_add_skills()
+#endif
+
+
+void error_message_to_player(void)
+{
+ mpr("Oh dear. There appears to be a bug in the program.");
+ mpr("I suggest you leave this level then save as soon as possible.");
+
+} // end error_message_to_player()
diff --git a/trunk/source/debug.h b/trunk/source/debug.h
new file mode 100644
index 0000000000..cbc8161d3b
--- /dev/null
+++ b/trunk/source/debug.h
@@ -0,0 +1,147 @@
+/*
+ * File: debug.h
+ * Summary: Debug and wizard related functions.
+ * Written by: Linley Henzell and Jesse Jones
+ *
+ * Change History (most recent first):
+ *
+ * <4> 5/30/99 JDJ Added synch checks.
+ * <3> 5/06/99 JDJ Added TRACE.
+ * <2> -/--/-- JDJ Added a bunch of debugging macros. Old code is now #if WIZARD.
+ * <1> -/--/-- LRH Created
+ */
+#ifndef DEBUG_H
+#define DEBUG_H
+
+// Synch with ANSI definitions.
+#if DEBUG && defined(NDEBUG)
+#error DEBUG and NDEBUG are out of sync!
+#endif
+
+#if !DEBUG && !defined(NDEBUG)
+#error DEBUG and NDEBUG are out of sync!
+#endif
+
+// Synch with MSL definitions.
+#if __MSL__ && DEBUG != defined(MSIPL_DEBUG_MODE)
+#error DEBUG and MSIPL_DEBUG_MODE are out of sync!
+#endif
+
+// Synch with MSVC.
+#if _MSC_VER >= 1100 && DEBUG != defined(_DEBUG)
+#error DEBUG and _DEBUG are out of sync!
+#endif
+
+
+#ifndef _lint
+#define COMPILE_CHECK(p) {struct _CC {char a[(p) ? 1 : -1];};} 0
+#else
+#define COMPILE_CHECK(p)
+#endif
+
+#if DEBUG
+
+void AssertFailed(const char *expr, const char *file, int line);
+
+#define ASSERT(p) do {if (!(p)) AssertFailed(#p, __FILE__, __LINE__);} while (false)
+#define VERIFY(p) ASSERT(p)
+
+void DEBUGSTR(const char *format,...);
+void TRACE(const char *format,...);
+
+#else
+
+#define ASSERT(p) ((void) 0)
+#define VERIFY(p) do {if (p) ;} while (false)
+
+inline void __DUMMY_TRACE__(...)
+{
+}
+
+#define DEBUGSTR 1 ? ((void) 0) : __DUMMY_TRACE__
+#define TRACE 1 ? ((void) 0) : __DUMMY_TRACE__
+
+#endif
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void cast_spec_spell(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void cast_spec_spell_name(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void create_spec_monster(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void create_spec_monster_name(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: ( this does not seem to be used at all ... {dlb} )
+ * *********************************************************************** */
+void create_spec_object(void);
+void tweak_object(void);
+
+// last updated 12say2001 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void debug_add_skills(void);
+void debug_set_skills(void);
+void debug_set_all_skills(void);
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void debug_add_skills(void);
+
+// last updated 17sep2001 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+bool debug_add_mutation(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: direct - food - items
+ * *********************************************************************** */
+void error_message_to_player(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void level_travel( int delta );
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - direct
+ * *********************************************************************** */
+void stethoscope(int mwh);
+
+void debug_item_scan( void );
+void debug_get_religion( void );
+void debug_change_species( void );
+
+#endif
diff --git a/trunk/source/decks.cc b/trunk/source/decks.cc
new file mode 100644
index 0000000000..cac48d2cbb
--- /dev/null
+++ b/trunk/source/decks.cc
@@ -0,0 +1,906 @@
+/*
+ * File: decks.cc
+ * Summary: Functions with decks of cards.
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "decks.h"
+
+#include <string.h>
+
+#include "externs.h"
+
+#include "effects.h"
+#include "food.h"
+#include "it_use2.h"
+#include "items.h"
+#include "misc.h"
+#include "monplace.h"
+#include "mutation.h"
+#include "ouch.h"
+#include "player.h"
+#include "religion.h"
+#include "spells1.h"
+#include "spells3.h"
+#include "spl-cast.h"
+#include "stuff.h"
+
+// array sizes -- see notes below {dlb}
+#define DECK_WONDERS_SIZE 27
+#define DECK_SUMMONING_SIZE 11
+#define DECK_TRICKS_SIZE 11
+#define DECK_POWER_SIZE 17
+#define DECK_PUNISHMENT_SIZE 23
+
+enum CARDS // (unsigned char) deck_of_foo[]
+{
+ CARD_BLANK = 0, // 0
+ CARD_BUTTERFLY,
+ CARD_WRAITH,
+ CARD_EXPERIENCE,
+ CARD_WEALTH,
+ CARD_INTELLIGENCE, // 5
+ CARD_STRENGTH,
+ CARD_QUICKSILVER,
+ CARD_STUPIDITY,
+ CARD_WEAKNESS,
+ CARD_SLOTH, // 10
+ CARD_SHUFFLE,
+ CARD_FREAK,
+ CARD_DEATH,
+ CARD_NORMALITY,
+ CARD_SHADOW, // 15
+ CARD_GATE,
+ CARD_STATUE,
+ CARD_ACQUISITION,
+ CARD_HASTEN,
+ CARD_DEMON_LESSER, // 20
+ CARD_DEMON_COMMON,
+ CARD_DEMON_GREATER,
+ CARD_DEMON_SWARM,
+ CARD_YAK,
+ CARD_FIEND, // 25
+ CARD_DRAGON,
+ CARD_GOLEM,
+ CARD_THING_FUGLY,
+ CARD_LICH,
+ CARD_HORROR_UNSEEN, // 30
+ CARD_BLINK,
+ CARD_TELEPORT,
+ CARD_TELEPORT_NOW,
+ CARD_RAGE,
+ CARD_LEVITY, // 35
+ CARD_VENOM,
+ CARD_XOM,
+ CARD_SLOW,
+ CARD_DECAY,
+ CARD_HEALING, // 40
+ CARD_HEAL_WOUNDS,
+ CARD_TORMENT,
+ CARD_FOUNTAIN,
+ CARD_ALTAR,
+ CARD_FAMINE, // 45
+ CARD_FEAST,
+ CARD_WILD_MAGIC,
+ CARD_VIOLENCE,
+ CARD_PROTECTION,
+ CARD_KNOWLEDGE, // 50
+ CARD_MAZE,
+ CARD_PANDEMONIUM,
+ CARD_IMPRISONMENT,
+ CARD_RULES_FOR_BRIDGE, // 54
+ NUM_CARDS, // must remain last regular member {dlb}
+ CARD_RANDOM = 255 // must remain final member {dlb}
+};
+
+static unsigned char deck_of_wonders[] =
+{
+ CARD_BLANK,
+ CARD_BUTTERFLY,
+ CARD_WRAITH,
+ CARD_EXPERIENCE,
+ CARD_WEALTH,
+ CARD_INTELLIGENCE,
+ CARD_STRENGTH,
+ CARD_QUICKSILVER,
+ CARD_STUPIDITY,
+ CARD_WEAKNESS,
+ CARD_SLOTH,
+ CARD_SHUFFLE,
+ CARD_FREAK,
+ CARD_DEATH,
+ CARD_NORMALITY,
+ CARD_SHADOW,
+ CARD_GATE,
+ CARD_STATUE,
+ CARD_ACQUISITION,
+ CARD_HASTEN,
+ CARD_LICH,
+ CARD_XOM,
+ CARD_DECAY,
+ CARD_ALTAR,
+ CARD_FOUNTAIN,
+ CARD_MAZE,
+ CARD_PANDEMONIUM
+};
+
+static unsigned char deck_of_summoning[] =
+{
+ CARD_STATUE,
+ CARD_DEMON_LESSER,
+ CARD_DEMON_COMMON,
+ CARD_DEMON_GREATER,
+ CARD_DEMON_SWARM,
+ CARD_YAK,
+ CARD_FIEND,
+ CARD_DRAGON,
+ CARD_GOLEM,
+ CARD_THING_FUGLY,
+ CARD_HORROR_UNSEEN
+};
+
+static unsigned char deck_of_tricks[] =
+{
+ CARD_BLANK,
+ CARD_BUTTERFLY,
+ CARD_BLINK,
+ CARD_TELEPORT,
+ CARD_TELEPORT_NOW,
+ CARD_RAGE,
+ CARD_LEVITY,
+ CARD_HEALING,
+ CARD_WILD_MAGIC,
+ CARD_DEMON_LESSER,
+ CARD_HASTEN
+};
+
+static unsigned char deck_of_power[] =
+{
+ CARD_BLANK,
+ CARD_DEMON_COMMON,
+ CARD_DEMON_GREATER,
+ CARD_TELEPORT_NOW,
+ CARD_VENOM,
+ CARD_XOM,
+ CARD_HEAL_WOUNDS,
+ CARD_FAMINE,
+ CARD_FEAST,
+ CARD_WILD_MAGIC,
+ CARD_VIOLENCE,
+ CARD_PROTECTION,
+ CARD_KNOWLEDGE,
+ CARD_HASTEN,
+ CARD_TORMENT,
+ CARD_DEMON_SWARM,
+ CARD_SLOW
+};
+
+// Supposed to be bad, small chance of OK... Nemelex wouldn't like a game
+// that didn't have some chance of "losing".
+static unsigned char deck_of_punishment[] =
+{
+ CARD_BLANK,
+ CARD_BUTTERFLY,
+ CARD_WRAITH,
+ CARD_WEALTH,
+ CARD_STUPIDITY,
+ CARD_WEAKNESS,
+ CARD_SLOTH,
+ CARD_SHUFFLE,
+ CARD_FREAK,
+ CARD_DEATH,
+ CARD_NORMALITY,
+ CARD_SHADOW,
+ CARD_GATE,
+ CARD_DEMON_SWARM,
+ CARD_RAGE,
+ CARD_VENOM,
+ CARD_SLOW,
+ CARD_DECAY,
+ CARD_TORMENT,
+ CARD_FAMINE,
+ CARD_WILD_MAGIC,
+ CARD_MAZE,
+ CARD_PANDEMONIUM
+};
+
+static void cards(unsigned char which_card);
+
+void deck_of_cards(unsigned char which_deck)
+{
+
+ // I really am not fond of how all of this works, the
+ // decks ought to be stored (possibly) in an array of
+ // pointers to int or as discrete arrays of int using
+ // the sizeof operator to determine upper bounds, and
+ // not defines, which is a bit clumsy given that you
+ // have to update two things presently (the array and
+ // the corresponding define) in order to add things to
+ // decks ... someone fix this, or I will {dlb}
+ unsigned char *card = deck_of_wonders;
+ unsigned char max_card = 0;
+ int i = 0;
+ int brownie_points = 0; // for passing to done_good() {dlb}
+
+ mpr("You draw a card...");
+
+ switch (which_deck)
+ {
+ case DECK_OF_WONDERS:
+ card = deck_of_wonders;
+ max_card = DECK_WONDERS_SIZE;
+ break;
+ case DECK_OF_SUMMONING:
+ card = deck_of_summoning;
+ max_card = DECK_SUMMONING_SIZE;
+ break;
+ case DECK_OF_TRICKS:
+ card = deck_of_tricks;
+ max_card = DECK_TRICKS_SIZE;
+ break;
+ case DECK_OF_POWER:
+ card = deck_of_power;
+ max_card = DECK_POWER_SIZE;
+ break;
+ case DECK_OF_PUNISHMENT:
+ card = deck_of_punishment;
+ max_card = DECK_PUNISHMENT_SIZE;
+ break;
+ }
+
+ i = (int) card[random2(max_card)];
+
+ if (one_chance_in(250))
+ {
+ mpr("This card doesn't seem to belong here.");
+ i = random2(NUM_CARDS);
+ }
+
+ if (i == CARD_BLANK && you.skills[SK_EVOCATIONS] > random2(30))
+ i = (int) card[random2(max_card)];
+
+ cards(i);
+
+ // Decks of punishment aren't objects in the game,
+ // its just Nemelex's form of punishment -- bwr
+ if (which_deck != DECK_OF_PUNISHMENT)
+ {
+ you.inv[you.equip[EQ_WEAPON]].plus--;
+
+ if (you.inv[you.equip[EQ_WEAPON]].plus == 0)
+ {
+ mpr("The deck of cards disappears in a puff of smoke.");
+
+ unwield_item(you.equip[EQ_WEAPON]);
+
+ dec_inv_item_quantity( you.equip[EQ_WEAPON], 1 );
+
+ // these bonuses happen only when the deck expires {dlb}:
+ brownie_points = (coinflip()? 2 : 1);
+
+ if (which_deck == DECK_OF_WONDERS)
+ brownie_points += 2;
+ else if (which_deck == DECK_OF_POWER)
+ brownie_points++;
+ }
+
+ // this bonus happens with every use {dlb}:
+ if (which_deck == DECK_OF_WONDERS || one_chance_in(3))
+ brownie_points++;
+
+ done_good(GOOD_CARDS, brownie_points);
+ }
+
+ return;
+} // end deck_of_cards()
+
+static void cards(unsigned char which_card)
+{
+ FixedVector < int, 5 > dvar;
+ FixedVector < int, 5 > mvar;
+ int dvar1 = 0;
+ int loopy = 0; // general purpose loop variable {dlb}
+ bool success = false; // for summoning messages {dlb}
+ bool failMsg = true;
+ int summ_dur, summ_beh, summ_num;
+
+ if (which_card == CARD_BLANK && one_chance_in(10))
+ which_card = CARD_RULES_FOR_BRIDGE;
+
+ switch (which_card)
+ {
+ default:
+ case CARD_BLANK:
+ mpr("It is blank.");
+ break;
+
+ case CARD_BUTTERFLY:
+ mpr("You have drawn the Butterfly.");
+
+ summ_dur = ENCH_ABJ_I + random2(3) + you.skills[SK_EVOCATIONS] / 2;
+ if (summ_dur > ENCH_ABJ_VI)
+ summ_dur = ENCH_ABJ_VI;
+
+ if (create_monster( MONS_BUTTERFLY, summ_dur, BEH_FRIENDLY,
+ you.x_pos, you.y_pos, MHITYOU, 250 ) != -1)
+ {
+ mpr("A brightly coloured insect flies from the card!");
+ }
+ break;
+
+ case CARD_WRAITH:
+ mpr("You have drawn the Wraith.");
+
+ lose_level();
+ drain_exp();
+ break;
+
+ case CARD_EXPERIENCE:
+ mpr( "You have drawn Experience." );
+ potion_effect( POT_EXPERIENCE, 0 );
+ break;
+
+ case CARD_WEALTH:
+ mpr("You have drawn Wealth.");
+
+ you.gold += roll_dice( 2, 20 * you.skills[SK_EVOCATIONS] );
+ you.redraw_gold = 1;
+ break;
+
+ case CARD_INTELLIGENCE:
+ mpr("You have drawn the Brain!");
+
+ you.intel += 1 + random2( you.skills[SK_EVOCATIONS] ) / 7;
+
+ if (you.max_intel < you.intel)
+ you.max_intel = you.intel;
+
+ you.redraw_intelligence = 1;
+ break;
+
+ case CARD_STRENGTH:
+ mpr("You have drawn Strength!");
+
+ you.strength += 1 + random2( you.skills[SK_EVOCATIONS] ) / 7;
+
+ if (you.max_strength < you.strength)
+ you.max_strength = you.strength;
+
+ you.redraw_strength = 1;
+ break;
+
+ case CARD_QUICKSILVER:
+ mpr("You have drawn the Quicksilver card.");
+
+ you.dex += 1 + random2( you.skills[SK_EVOCATIONS] ) / 7;
+
+ if (you.max_dex < you.dex)
+ you.max_dex = you.dex;
+
+ you.redraw_dexterity = 1;
+ break;
+
+ case CARD_STUPIDITY:
+ mpr("You have drawn Stupidity!");
+
+ you.intel -= (2 + random2avg(3, 2));
+ if (you.intel < 4)
+ you.intel = 0;
+
+ if (you.skills[SK_EVOCATIONS] < random2(30))
+ you.max_intel--;
+
+ you.redraw_intelligence = 1;
+ break;
+
+ case CARD_WEAKNESS:
+ mpr("You have drawn Weakness.");
+
+ you.strength -= (2 + random2avg(3, 2));
+ if (you.strength < 4)
+ you.strength = 0;
+
+ if (you.skills[SK_EVOCATIONS] < random2(30))
+ you.max_strength--;
+
+ you.redraw_strength = 1;
+ break;
+
+ case CARD_SLOTH:
+ mpr("You have drawn the Slug.");
+
+ you.dex -= (2 + random2avg(3, 2));
+ if (you.dex < 4)
+ you.dex = 0;
+
+ if (you.skills[SK_EVOCATIONS] < random2(30))
+ you.max_dex--;
+
+ you.redraw_dexterity = 1;
+ break;
+
+ case CARD_SHUFFLE: // shuffle stats
+ mpr("You have drawn the Shuffle card!");
+
+ dvar[STAT_STRENGTH] = you.strength;
+ dvar[STAT_DEXTERITY] = you.dex;
+ dvar[STAT_INTELLIGENCE] = you.intel;
+
+ mvar[STAT_STRENGTH] = you.max_strength;
+ mvar[STAT_DEXTERITY] = you.max_dex;
+ mvar[STAT_INTELLIGENCE] = you.max_intel;
+
+ you.strength = 101;
+ you.intel = 101;
+ you.dex = 101;
+
+ do
+ {
+ dvar1 = random2(NUM_STATS);
+
+ if (dvar[dvar1] == 101)
+ continue;
+
+ if (you.strength == 101)
+ {
+ you.strength = dvar[dvar1];
+ you.max_strength = mvar[dvar1];
+ }
+ else if (you.intel == 101)
+ {
+ you.intel = dvar[dvar1];
+ you.max_intel = mvar[dvar1];
+ }
+ else if (you.dex == 101)
+ {
+ you.dex = dvar[dvar1];
+ you.max_dex = mvar[dvar1];
+ }
+
+ dvar[dvar1] = 101;
+ }
+ while (dvar[STAT_STRENGTH] != 101 || dvar[STAT_DEXTERITY] != 101
+ || dvar[STAT_INTELLIGENCE] != 101);
+
+ you.redraw_strength = 1;
+ you.redraw_intelligence = 1;
+ you.redraw_dexterity = 1;
+ burden_change();
+ break;
+
+ case CARD_FREAK:
+ mpr("You have drawn the Freak!");
+ for (loopy = 0; loopy < 6; loopy++)
+ {
+ if (!mutate(100, failMsg))
+ failMsg = false;
+ }
+ break;
+
+ case CARD_DEATH:
+ mpr("Oh no! You have drawn the Death card!");
+
+ if (you.duration[DUR_TELEPORT])
+ you_teleport();
+
+ for (loopy = 0; loopy < 5; loopy++)
+ {
+ create_monster( MONS_REAPER, 0, BEH_HOSTILE, you.x_pos, you.y_pos,
+ MHITYOU, 250 );
+ }
+ break;
+
+ case CARD_NORMALITY:
+ mpr("You have drawn Normalisation.");
+ for (loopy = 0; loopy < 6; loopy++)
+ {
+ delete_mutation(100);
+ }
+ break;
+
+ case CARD_SHADOW:
+ mpr("You have drawn the Shadow.");
+ create_monster( MONS_SOUL_EATER, 0, BEH_HOSTILE, you.x_pos, you.y_pos,
+ MHITYOU, 250 );
+ break;
+
+ case CARD_GATE:
+ mpr("You have drawn the Gate!");
+ more();
+
+ if (you.level_type == LEVEL_ABYSS)
+ banished(DNGN_EXIT_ABYSS);
+ else if (you.level_type == LEVEL_LABYRINTH)
+ canned_msg(MSG_NOTHING_HAPPENS);
+ else
+ banished(DNGN_ENTER_ABYSS);
+ break;
+
+ case CARD_STATUE:
+ mpr("You have drawn the Crystal Statue.");
+ create_monster( MONS_CRYSTAL_GOLEM, 0, BEH_FRIENDLY,
+ you.x_pos, you.y_pos, you.pet_target, 250 );
+ break;
+
+ case CARD_ACQUISITION:
+ mpr( "You have drawn Acquisition!" );
+ mpr( "The card unfolds to form a scroll of paper." );
+ acquirement( OBJ_RANDOM );
+ break;
+
+ case CARD_HASTEN:
+ mpr("You have drawn Haste.");
+ potion_effect( POT_SPEED, 5 * you.skills[SK_EVOCATIONS] );
+ break;
+
+ case CARD_DEMON_LESSER:
+ mpr("On the card is a picture of a little demon.");
+
+ summ_dur = ENCH_ABJ_I + random2(3) + you.skills[SK_EVOCATIONS] / 3;
+ if (summ_dur > ENCH_ABJ_VI)
+ summ_dur = ENCH_ABJ_VI;
+
+ if (create_monster( summon_any_demon( DEMON_LESSER ), summ_dur,
+ BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target,
+ 250 ) != -1)
+ {
+ mpr("The picture comes to life!");
+ }
+ break;
+
+ case CARD_DEMON_COMMON:
+ mpr("On the card is a picture of a demon.");
+
+ summ_dur = ENCH_ABJ_I + random2(3) + you.skills[SK_EVOCATIONS] / 4;
+ if (summ_dur > ENCH_ABJ_VI)
+ summ_dur = ENCH_ABJ_VI;
+
+ if (create_monster( summon_any_demon( DEMON_COMMON ), summ_dur,
+ BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target,
+ 250 ) != -1)
+ {
+ mpr("The picture comes to life!");
+ }
+ break;
+
+ case CARD_DEMON_GREATER:
+ mpr("On the card is a picture of a huge demon.");
+
+ summ_beh = (you.skills[SK_EVOCATIONS] > random2(30)) ? BEH_FRIENDLY
+ : BEH_CHARMED;
+
+ if (summ_beh == BEH_CHARMED)
+ mpr( "You don't feel so good about this..." );
+
+ if (create_monster( summon_any_demon( DEMON_GREATER ), ENCH_ABJ_V,
+ summ_beh, you.x_pos, you.y_pos,
+ you.pet_target, 250 ) != -1)
+ {
+ mpr("The picture comes to life!");
+ }
+ break;
+
+ case CARD_DEMON_SWARM:
+ mpr("On the card is a picture of a swarm of little demons.");
+
+ success = false;
+
+ summ_num = 7 + random2(6);
+
+ for (loopy = 0; loopy < summ_num; loopy++)
+ {
+ if (create_monster( summon_any_demon( DEMON_LESSER ), ENCH_ABJ_VI,
+ BEH_HOSTILE, you.x_pos, you.y_pos,
+ MHITYOU, 250 ) != -1)
+ {
+ success = true;
+ }
+ }
+
+ if (success)
+ mpr("The picture comes to life!");
+ break;
+
+ case CARD_YAK:
+ mpr("On the card is a picture of a huge shaggy yak.");
+
+ summ_dur = ENCH_ABJ_II + you.skills[SK_EVOCATIONS] / 2;
+ if (summ_dur > ENCH_ABJ_VI)
+ summ_dur = ENCH_ABJ_VI;
+
+ if (create_monster( MONS_DEATH_YAK, summ_dur, BEH_FRIENDLY,
+ you.x_pos, you.y_pos, you.pet_target, 250 ) != -1)
+ {
+ mpr("The picture comes to life!");
+ }
+ break;
+
+ case CARD_FIEND:
+ mpr("On the card is a picture of a huge scaly devil.");
+
+ summ_dur = ENCH_ABJ_II + you.skills[SK_EVOCATIONS] / 6;
+ if (summ_dur > ENCH_ABJ_VI)
+ summ_dur = ENCH_ABJ_VI;
+
+ if (create_monster( MONS_FIEND, summ_dur, BEH_FRIENDLY,
+ you.x_pos, you.y_pos, you.pet_target, 250 ) != -1)
+ {
+ mpr("The picture comes to life!");
+ }
+ break;
+
+ case CARD_DRAGON:
+ mpr("On the card is a picture of a huge scaly dragon.");
+
+ summ_dur = ENCH_ABJ_III + you.skills[SK_EVOCATIONS] / 6;
+ if (summ_dur > ENCH_ABJ_VI)
+ summ_dur = ENCH_ABJ_VI;
+
+ if (create_monster( (coinflip() ? MONS_DRAGON : MONS_ICE_DRAGON),
+ summ_dur, BEH_FRIENDLY, you.x_pos, you.y_pos,
+ you.pet_target, 250 ) != -1)
+ {
+ mpr("The picture comes to life!");
+ }
+ break;
+
+ case CARD_GOLEM:
+ mpr("On the card is a picture of a statue.");
+
+ summ_dur = ENCH_ABJ_II + you.skills[SK_EVOCATIONS] / 4;
+ if (summ_dur > ENCH_ABJ_VI)
+ summ_dur = ENCH_ABJ_VI;
+
+ if (create_monster( MONS_CLAY_GOLEM + random2(6), summ_dur,
+ BEH_FRIENDLY, you.x_pos, you.y_pos,
+ you.pet_target, 250 ) != -1)
+ {
+ mpr("The picture comes to life!");
+ }
+ break;
+
+ case CARD_THING_FUGLY:
+ mpr("On the card is a picture of a very ugly thing.");
+
+ summ_dur = ENCH_ABJ_II + you.skills[SK_EVOCATIONS] / 4;
+ if (summ_dur > ENCH_ABJ_VI)
+ summ_dur = ENCH_ABJ_VI;
+
+ if (create_monster( MONS_VERY_UGLY_THING, summ_dur, BEH_FRIENDLY,
+ you.x_pos, you.y_pos, you.pet_target, 250 ) != -1)
+ {
+ mpr("The picture comes to life!");
+ }
+ break;
+
+ case CARD_LICH:
+ mpr( "On the card is a picture of a very irritated-looking "
+ "skeletal thing." );
+
+ if (create_monster( MONS_LICH, 0, BEH_HOSTILE, you.x_pos, you.y_pos,
+ MHITYOU, 250) != -1)
+ {
+ mpr("The picture comes to life!");
+ }
+ break;
+
+ case CARD_HORROR_UNSEEN:
+ if (!player_see_invis())
+ mpr("It is blank!");
+ else
+ mpr("On the card is a picture of a hideous abomination.");
+
+ summ_dur = ENCH_ABJ_II + you.skills[SK_EVOCATIONS] / 4;
+ if (summ_dur > ENCH_ABJ_VI)
+ summ_dur = ENCH_ABJ_VI;
+
+ if (create_monster( MONS_UNSEEN_HORROR, summ_dur, BEH_FRIENDLY,
+ you.x_pos, you.y_pos, you.pet_target, 250 ) != -1)
+ {
+ if (player_see_invis())
+ {
+ mpr("The picture comes to life!");
+ }
+ }
+ break;
+
+ case CARD_BLINK:
+ mpr("You have drawn Blink.");
+ blink();
+ // random_blink(true);
+ break;
+
+ case CARD_TELEPORT:
+ mpr("You have drawn the Portal of Delayed Transposition.");
+ you_teleport();
+ break;
+
+ case CARD_TELEPORT_NOW:
+ mpr( "You have drawn the Portal of Instantaneous Transposition." );
+ you_teleport2( true, true ); // in abyss, always to new area
+ break;
+
+ case CARD_RAGE:
+ mpr("You have drawn Rage.");
+
+ if (!go_berserk(false))
+ canned_msg(MSG_NOTHING_HAPPENS);
+ else
+ you.berserk_penalty = NO_BERSERK_PENALTY;
+ break;
+
+ case CARD_LEVITY:
+ mpr("You have drawn Levity.");
+ potion_effect( POT_LEVITATION, 5 * you.skills[SK_EVOCATIONS] );
+ break;
+
+ case CARD_VENOM:
+ mpr("You have drawn Venom.");
+ poison_player( 2 + random2( 7 - you.skills[SK_EVOCATIONS] / 5 ) );
+ break;
+
+ case CARD_XOM:
+ mpr("You have drawn the card of Xom!");
+ Xom_acts( true, 5 + random2( you.skills[SK_EVOCATIONS] ), true );
+ break;
+
+ case CARD_SLOW:
+ mpr("You have drawn Slowness.");
+ potion_effect( POT_SLOWING, 100 - 2 * you.skills[SK_EVOCATIONS] );
+ break;
+
+ case CARD_DECAY:
+ mpr("You have drawn Decay.");
+
+ if (you.is_undead)
+ mpr("You feel terrible.");
+ else
+ rot_player( 2 + random2( 7 - you.skills[SK_EVOCATIONS] / 4 ) );
+ break;
+
+ case CARD_HEALING:
+ mpr("You have drawn the Elixir of Health.");
+ potion_effect( POT_HEALING, 5 * you.skills[SK_EVOCATIONS] );
+ break;
+
+ case CARD_HEAL_WOUNDS:
+ mpr("You have drawn the Symbol of Immediate Regeneration.");
+ potion_effect( POT_HEAL_WOUNDS, 5 * you.skills[SK_EVOCATIONS] );
+ break;
+
+ case CARD_TORMENT:
+ mpr("You have drawn the Symbol of Torment.");
+ torment( you.x_pos, you.y_pos );
+ break;
+
+// what about checking whether there are items there, too? {dlb}
+ case CARD_FOUNTAIN:
+ mpr("You have drawn the Fountain.");
+
+ if (grd[you.x_pos][you.y_pos] == DNGN_FLOOR)
+ {
+ strcpy( info, "A beautiful fountain of clear blue water grows "
+ "from the floor " );
+
+ strcat( info, (you.species == SP_NAGA || you.species == SP_CENTAUR)
+ ? "before you!" : "at your feet!" );
+ mpr(info);
+ grd[you.x_pos][you.y_pos] = DNGN_BLUE_FOUNTAIN;
+ }
+ else
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ }
+ break;
+
+ case CARD_ALTAR:
+ mpr("You have drawn the Altar.");
+
+ if (you.religion == GOD_NO_GOD)
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ }
+ else
+ {
+ dvar1 = 179 + you.religion;
+
+ if (grd[you.x_pos][you.y_pos] == DNGN_FLOOR)
+ {
+ strcpy(info, "An altar grows from the floor ");
+ strcat(info,
+ (you.species == SP_NAGA || you.species == SP_CENTAUR)
+ ? "before you!" : "at your feet!");
+ mpr(info);
+ grd[you.x_pos][you.y_pos] = dvar1;
+ }
+ else
+ {
+ do
+ {
+ dvar[0] = 10 + random2(GXM - 20);
+ dvar[1] = 10 + random2(GYM - 20);
+ }
+ while (grd[dvar[0]][dvar[1]] != DNGN_FLOOR);
+
+ grd[dvar[0]][dvar[1]] = dvar1;
+
+ mpr( "You sense divine power!" );
+ }
+ }
+ break;
+
+ case CARD_FAMINE:
+ mpr("You have drawn Famine.");
+
+ if (you.is_undead == US_UNDEAD)
+ mpr("You feel rather smug.");
+ else
+ set_hunger(500, true);
+ break;
+
+ case CARD_FEAST:
+ mpr("You have drawn the Feast.");
+
+ if (you.is_undead == US_UNDEAD)
+ mpr("You feel a horrible emptiness.");
+ else
+ set_hunger(12000, true);
+ break;
+
+ case CARD_WILD_MAGIC:
+ mpr( "You have drawn Wild Magic." );
+ miscast_effect( SPTYP_RANDOM, random2(15) + 5, random2(250), 0 );
+ break;
+
+ case CARD_VIOLENCE:
+ mpr("You have drawn Violence.");
+ acquirement( OBJ_WEAPONS );
+ break;
+
+ case CARD_PROTECTION:
+ mpr("You have drawn Protection.");
+ acquirement( OBJ_ARMOUR );
+ break;
+
+ case CARD_KNOWLEDGE:
+ mpr("You have drawn Knowledge.");
+ acquirement( OBJ_BOOKS );
+ break;
+
+ case CARD_MAZE:
+ mpr("You have drawn the Maze!");
+ more();
+
+ if (you.level_type == LEVEL_DUNGEON)
+ banished( DNGN_ENTER_LABYRINTH );
+ break;
+
+ case CARD_PANDEMONIUM:
+ mpr("You have drawn the Pandemonium card!");
+ more();
+
+ if (you.level_type == LEVEL_PANDEMONIUM)
+ banished(DNGN_EXIT_PANDEMONIUM);
+ else if (you.level_type == LEVEL_LABYRINTH)
+ canned_msg(MSG_NOTHING_HAPPENS);
+ else
+ banished(DNGN_ENTER_PANDEMONIUM);
+ break;
+
+ case CARD_RULES_FOR_BRIDGE:
+ mpr("You have drawn the rules for contract bridge.");
+ mpr("How intriguing!");
+ break;
+
+ case CARD_IMPRISONMENT:
+ mpr("You have drawn the Prison!");
+ entomb();
+ break;
+ }
+
+ return;
+} // end cards()
diff --git a/trunk/source/decks.h b/trunk/source/decks.h
new file mode 100644
index 0000000000..1227ee19f1
--- /dev/null
+++ b/trunk/source/decks.h
@@ -0,0 +1,22 @@
+/*
+ * File: decks.cc
+ * Summary: Functions with decks of cards.
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef DECKS_H
+#define DECKS_H
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: it_use_3 - religion
+ * *********************************************************************** */
+void deck_of_cards(unsigned char which_deck);
+
+
+#endif
diff --git a/trunk/source/defines.h b/trunk/source/defines.h
new file mode 100644
index 0000000000..d99b68eff6
--- /dev/null
+++ b/trunk/source/defines.h
@@ -0,0 +1,160 @@
+/*
+ * File: defines.h
+ * Summary: Various definess used by Crawl.
+ * Written by: Linley Henzel
+ *
+ * Abstract: A variety of miscellaneous constant values are found here.
+ * I think we should move the colors into an enum or something
+ * because there are in numerical order. But I'm too lazy to
+ * do it myself.
+ *
+ * Copyright © 1999 Brian Robinson. // Me? How come?
+ *
+ * Change History (most recent first):
+ *
+ * <4> 7/29/00 JDJ Renamed MNG NON_MONSTER, MNST MAX_MONSTERS, ITEMS MAX_ITEMS,
+ * ING NON_ITEM, CLOUDS MAX_CLOUDS, CNG EMPTY_CLOUD, NTRAPS MAX_TRAPS.
+ * <3> 9/25/99 CDL linuxlib -> liblinux
+ * <2> 6/17/99 BCR indented and added header
+ * <1> --/--/-- LRH Created
+ */
+
+#ifndef DEFINES_H
+#define DEFINES_H
+
+#define ESCAPE '\x1b' // most ansi-friendly way I can think of defining this.
+
+// there's got to be a better way...
+#ifdef _LIBLINUX_IMPLEMENTATION
+#elif macintosh
+#else
+ #ifndef TRUE
+ #define TRUE 1
+ #endif
+
+ #ifndef FALSE
+ #define FALSE 0
+ #endif
+#endif
+
+
+// max size of inventory array {dlb}:
+#define ENDOFPACK 52
+
+// max size of monter array {dlb}:
+#define MAX_MONSTERS 200
+// number of monster enchantments
+#define NUM_MON_ENCHANTS 6
+// non-monster for mgrd[][] -- (MNST + 1) {dlb}:
+#define NON_MONSTER 201
+
+// max size of item list {dlb}:
+#define MAX_ITEMS 500
+// non-item -- (ITEMS + 1) {dlb}
+#define NON_ITEM 501
+
+// max size of cloud array {dlb}:
+#define MAX_CLOUDS 100
+
+// empty cloud -- (CLOUDS + 1) {dlb}:
+#define EMPTY_CLOUD 101
+
+// max x-bound for level generation {dlb}
+#define GXM 80
+// max y-bound for level generation {dlb}
+#define GYM 70
+
+// max traps per level
+#define MAX_TRAPS 30
+
+// max shops per level
+#define MAX_SHOPS 5
+
+// lowest grid value which can be passed by walking etc.
+#define MINMOVE 31
+
+// lowest grid value which can be seen through
+#define MINSEE 11
+
+
+// some shortcuts:
+#define menv env.mons
+#define mitm env.item
+#define grd env.grid
+#define mgrd env.mgrid
+#define igrd env.igrid
+
+
+// (MNG) -- for a reason! see usage {dlb}:
+#define MHITNOT 201
+// (MNG + 1) -- for a reason! see usage {dlb}:
+#define MHITYOU 202
+
+// colors, such pretty colors ...
+#ifndef DOS
+ #define BLACK 0
+ #define BLUE 1
+ #define GREEN 2
+ #define CYAN 3
+ #define RED 4
+ #define MAGENTA 5
+ #define BROWN 6
+ #define LIGHTGREY 7
+ #define DARKGREY 8
+ #define LIGHTBLUE 9
+ #define LIGHTGREEN 10
+ #define LIGHTCYAN 11
+ #define LIGHTRED 12
+ #define LIGHTMAGENTA 13
+ #define YELLOW 14
+ #define WHITE 15
+
+ #define LIGHTGRAY LIGHTGREY
+ #define DARKGRAY DARKGREY
+#else
+ #include <conio.h>
+ #define LIGHTGREY LIGHTGRAY
+ #define DARKGREY DARKGRAY
+#endif
+
+// Colour options... these are used as bit flags along with the colour
+// value in the low byte.
+
+// This is used to signal curses (which has seven base colours) to
+// try to get a brighter version using recommisioned attribute flags.
+#define COLFLAG_CURSES_BRIGHTEN 0x0080
+
+#ifdef USE_COLOUR_OPTS
+
+ #define COLFLAG_FRIENDLY_MONSTER 0x0100
+
+ enum CHAR_ATTRIBUTES
+ {
+ CHATTR_NORMAL,
+ CHATTR_STANDOUT,
+ CHATTR_BOLD,
+ CHATTR_BLINK,
+ CHATTR_UNDERLINE,
+ CHATTR_REVERSE,
+ CHATTR_DIM
+ };
+
+#endif
+
+// required for stuff::coinflip()
+#define IB1 1
+#define IB2 2
+#define IB5 16
+#define IB18 131072
+#define MASK (IB1 + IB2 + IB5)
+// required for stuff::coinflip()
+
+#define MINIMUM( xxx, yyy ) (((xxx) < (yyy)) ? (xxx) : (yyy))
+#define MAXIMUM( xxx, yyy ) (((xxx) > (yyy)) ? (xxx) : (yyy))
+
+// Convert capital letters into mystic numbers representing
+// CTRL sequences. This is a macro because a lot of the type
+// it wants to be used in case labels.
+#define CONTROL( xxx ) (xxx - 'A' + 1)
+
+#endif
diff --git a/trunk/source/delay.cc b/trunk/source/delay.cc
new file mode 100644
index 0000000000..0894207395
--- /dev/null
+++ b/trunk/source/delay.cc
@@ -0,0 +1,549 @@
+/*
+ * File: delay.cc
+ * Summary: Functions for handling multi-turn actions.
+ *
+ * Change History (most recent first):
+ *
+ * <1> Sept 09, 2001 BWR Created
+ */
+
+#include "AppHdr.h"
+#include "externs.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "delay.h"
+#include "enum.h"
+#include "food.h"
+#include "items.h"
+#include "itemname.h"
+#include "item_use.h"
+#include "it_use2.h"
+#include "message.h"
+#include "misc.h"
+#include "monstuff.h"
+#include "ouch.h"
+#include "output.h"
+#include "player.h"
+#include "randart.h"
+#include "spl-util.h"
+#include "stuff.h"
+
+void start_delay( int type, int turns, int parm1, int parm2 )
+/***********************************************************/
+{
+ delay_queue_item delay;
+
+ delay.type = type;
+ delay.duration = turns;
+ delay.parm1 = parm1;
+ delay.parm2 = parm2;
+
+ you.delay_queue.push( delay );
+}
+
+void stop_delay( void )
+/*********************/
+{
+ delay_queue_item delay = you.delay_queue.front();
+
+ // At the very least we can remove any queued delays, right
+ // now there is no problem with doing this... note that
+ // any queuing here can only happen from a single command,
+ // as the effect of a delay doesn't normally allow interaction
+ // until it is done... it merely chains up individual actions
+ // into a single action. -- bwr
+ if (you.delay_queue.size() > 1)
+ {
+ while (you.delay_queue.size())
+ you.delay_queue.pop();
+
+ you.delay_queue.push( delay );
+ }
+
+ switch (delay.type)
+ {
+ case DELAY_BUTCHER:
+ // Corpse keeps track of work in plus2 field, see handle_delay() -- bwr
+ mpr( "You stop butchering the corpse." );
+ you.delay_queue.pop();
+ break;
+
+ case DELAY_MEMORIZE:
+ // Losing work here is okay... having to start from
+ // scratch is a reasonable behaviour. -- bwr
+ mpr( "Your memorization is interrupted." );
+ you.delay_queue.pop();
+ break;
+
+ case DELAY_PASSWALL:
+ // The lost work here is okay since this spell requires
+ // the player to "attune to the rock". If changed, the
+ // the delay should be increased to reduce the power of
+ // this spell. -- bwr
+ mpr( "Your meditation is interrupted." );
+ you.delay_queue.pop();
+ break;
+
+ case DELAY_INTERUPTABLE:
+ // always stopable by definition...
+ // try using a more specific type anyways. -- bwr
+ you.delay_queue.pop();
+ break;
+
+ case DELAY_EAT:
+ // XXX: Large problems with object destruction here... food can
+ // be from in the inventory or on the ground and these are
+ // still handled quite differently. Eventually we would like
+ // this to be stoppable, with partial food items implimented. -- bwr
+ break;
+
+ case DELAY_ARMOUR_ON:
+ case DELAY_ARMOUR_OFF:
+ // These two have the default action of not being interuptable,
+ // although they will often be chained (remove cloak, remove
+ // armour, wear new armour, replace cloak), all of which can
+ // be stopped when complete. This is a fairly reasonable
+ // behaviour, although perhaps the character should have
+ // option of reversing the current action if it would take
+ // less time to get out of the plate mail that's half on
+ // than it would take to continue. Probably too much trouble,
+ // and would have to have a prompt... this works just fine. -- bwr
+ break;
+
+ case DELAY_AUTOPICKUP: // one turn... too much trouble
+ case DELAY_WEAPON_SWAP: // one turn... too much trouble
+ case DELAY_DROP_ITEM: // one turn... only used for easy armour drops
+ case DELAY_ASCENDING_STAIRS: // short... and probably what people want
+ case DELAY_DESCENDING_STAIRS: // short... and probably what people want
+ case DELAY_UNINTERUPTABLE: // never stopable
+ default:
+ break;
+ }
+}
+
+bool you_are_delayed( void )
+/**************************/
+{
+ return (!you.delay_queue.empty());
+}
+
+int current_delay_action( void )
+/******************************/
+{
+ return (you_are_delayed() ? you.delay_queue.front().type
+ : DELAY_NOT_DELAYED);
+}
+
+void handle_delay( void )
+/***********************/
+{
+ int ego;
+ char str_pass[ ITEMNAME_SIZE ];
+
+ if (you_are_delayed())
+ {
+ delay_queue_item &delay = you.delay_queue.front();
+
+ // First check cases where delay may no longer be valid:
+ // XXX: need to handle passwall when monster digs -- bwr
+ if (delay.type == DELAY_BUTCHER)
+ {
+ // A monster may have raised the corpse you're chopping up! -- bwr
+ // Note that a monster could have raised the corpse and another
+ // monster could die and create a corpse with the same ID number...
+ // However, it would not be at the player's square like the
+ // original and that's why we do it this way. Note that
+ // we ignore the conversion to skeleton possiblity just to
+ // be nice. -- bwr
+ if (is_valid_item( mitm[ delay.parm1 ] )
+ && mitm[ delay.parm1 ].base_type == OBJ_CORPSES
+ && mitm[ delay.parm1 ].x == you.x_pos
+ && mitm[ delay.parm1 ].y == you.y_pos)
+ {
+ // mark work done on the corpse in case we stop -- bwr
+ mitm[ delay.parm1 ].plus2++;
+ }
+ else
+ {
+ // corpse is no longer valid!
+ stop_delay();
+ return;
+ }
+ }
+
+ // Handle delay:
+ if (delay.duration > 0)
+ {
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "Delay type: %d duration: %d",
+ delay.type, delay.duration );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+ delay.duration--;
+ }
+ else
+ {
+ switch (delay.type)
+ {
+ case DELAY_AUTOPICKUP:
+ break;
+
+ case DELAY_WEAPON_SWAP:
+ weapon_switch( delay.parm1 );
+ break;
+
+ case DELAY_ARMOUR_ON:
+ set_ident_flags( you.inv[ delay.parm1 ], ISFLAG_EQ_ARMOUR_MASK );
+
+ in_name( delay.parm1, DESC_NOCAP_YOUR, str_pass );
+ snprintf( info, INFO_SIZE, "You finish putting on %s.", str_pass );
+ mpr(info);
+
+ if (you.inv[ delay.parm1 ].sub_type < ARM_SHIELD
+ || you.inv[ delay.parm1 ].sub_type > ARM_LARGE_SHIELD)
+ {
+ you.equip[EQ_BODY_ARMOUR] = delay.parm1;
+
+ if (you.duration[DUR_ICY_ARMOUR] != 0)
+ {
+ mpr( "Your icy armour melts away.", MSGCH_DURATION );
+ you.redraw_armour_class = 1;
+ you.duration[DUR_ICY_ARMOUR] = 0;
+ }
+ }
+ else
+ {
+ switch (you.inv[ delay.parm1 ].sub_type)
+ {
+ case ARM_BUCKLER:
+ case ARM_LARGE_SHIELD:
+ case ARM_SHIELD:
+ if (you.duration[DUR_CONDENSATION_SHIELD])
+ {
+ mpr( "Your icy shield evaporates.", MSGCH_DURATION );
+ you.duration[DUR_CONDENSATION_SHIELD] = 0;
+ }
+ you.equip[EQ_SHIELD] = delay.parm1;
+ break;
+ case ARM_CLOAK:
+ you.equip[EQ_CLOAK] = delay.parm1;
+ break;
+ case ARM_HELMET:
+ you.equip[EQ_HELMET] = delay.parm1;
+ break;
+ case ARM_GLOVES:
+ you.equip[EQ_GLOVES] = delay.parm1;
+ break;
+ case ARM_BOOTS:
+ you.equip[EQ_BOOTS] = delay.parm1;
+ break;
+ }
+ }
+
+ ego = get_armour_ego_type( you.inv[ delay.parm1 ] );
+ if (ego != SPARM_NORMAL)
+ {
+ switch (ego)
+ {
+ case SPARM_RUNNING:
+ strcpy(info, "You feel quick");
+ strcat(info, (you.species == SP_NAGA
+ || you.species == SP_CENTAUR) ? "." : " on your feet.");
+ mpr(info);
+ break;
+
+ case SPARM_FIRE_RESISTANCE:
+ mpr("You feel resistant to fire.");
+ break;
+
+ case SPARM_COLD_RESISTANCE:
+ mpr("You feel resistant to cold.");
+ break;
+
+ case SPARM_POISON_RESISTANCE:
+ mpr("You feel healthy.");
+ break;
+
+ case SPARM_SEE_INVISIBLE:
+ mpr("You feel perceptive.");
+ break;
+
+ case SPARM_DARKNESS:
+ if (!you.invis)
+ mpr("You become transparent for a moment.");
+ break;
+
+ case SPARM_STRENGTH:
+ modify_stat(STAT_STRENGTH, 3, false);
+ break;
+
+ case SPARM_DEXTERITY:
+ modify_stat(STAT_DEXTERITY, 3, false);
+ break;
+
+ case SPARM_INTELLIGENCE:
+ modify_stat(STAT_INTELLIGENCE, 3, false);
+ break;
+
+ case SPARM_PONDEROUSNESS:
+ mpr("You feel rather ponderous.");
+ // you.speed += 2;
+ you.redraw_evasion = 1;
+ break;
+
+ case SPARM_LEVITATION:
+ mpr("You feel rather light.");
+ break;
+
+ case SPARM_MAGIC_RESISTANCE:
+ mpr("You feel resistant to magic.");
+ break;
+
+ case SPARM_PROTECTION:
+ mpr("You feel protected.");
+ break;
+
+ case SPARM_STEALTH:
+ mpr("You feel stealthy.");
+ break;
+
+ case SPARM_RESISTANCE:
+ mpr("You feel resistant to extremes of temperature.");
+ break;
+
+ case SPARM_POSITIVE_ENERGY:
+ mpr("Your life-force is being protected.");
+ break;
+
+ case SPARM_ARCHMAGI:
+ if (!you.skills[SK_SPELLCASTING])
+ mpr("You feel strangely numb.");
+ else
+ mpr("You feel extremely powerful.");
+ break;
+ }
+ }
+
+ if (is_random_artefact( you.inv[ delay.parm1 ] ))
+ use_randart( delay.parm1 );
+
+ if (item_cursed( you.inv[ delay.parm1 ] ))
+ mpr( "Oops, that feels deathly cold." );
+
+ you.redraw_armour_class = 1;
+ you.redraw_evasion = 1;
+ break;
+
+ case DELAY_ARMOUR_OFF:
+ in_name( delay.parm1, DESC_NOCAP_YOUR, str_pass );
+ snprintf( info, INFO_SIZE, "You finish taking off %s.", str_pass );
+ mpr(info);
+
+ if (you.inv[ delay.parm1 ].sub_type < ARM_SHIELD
+ || you.inv[ delay.parm1 ].sub_type > ARM_LARGE_SHIELD)
+ {
+ you.equip[EQ_BODY_ARMOUR] = -1;
+ }
+ else
+ {
+ switch (you.inv[ delay.parm1 ].sub_type)
+ {
+ case ARM_BUCKLER:
+ case ARM_LARGE_SHIELD:
+ case ARM_SHIELD:
+ if (delay.parm1 == you.equip[EQ_SHIELD])
+ you.equip[EQ_SHIELD] = -1;
+ break;
+
+ case ARM_CLOAK:
+ if (delay.parm1 == you.equip[EQ_CLOAK])
+ you.equip[EQ_CLOAK] = -1;
+ break;
+
+ case ARM_HELMET:
+ if (delay.parm1 == you.equip[EQ_HELMET])
+ you.equip[EQ_HELMET] = -1;
+ break;
+
+
+ case ARM_GLOVES:
+ if (delay.parm1 == you.equip[EQ_GLOVES])
+ you.equip[EQ_GLOVES] = -1;
+ break;
+
+ case ARM_BOOTS:
+ if (delay.parm1 == you.equip[EQ_BOOTS])
+ you.equip[EQ_BOOTS] = -1;
+ break;
+ }
+ }
+
+ unwear_armour( delay.parm1 );
+
+ you.redraw_armour_class = 1;
+ you.redraw_evasion = 1;
+ break;
+
+ case DELAY_EAT:
+ mpr( "You finish eating." );
+ break;
+
+ case DELAY_MEMORIZE:
+ mpr( "You finish memorising." );
+ add_spell_to_memory( delay.parm1 );
+ break;
+
+ case DELAY_PASSWALL:
+ {
+ mpr( "You finish merging with the rock." );
+ more(); // or the above message won't be seen
+
+ const int pass_x = delay.parm1;
+ const int pass_y = delay.parm2;
+
+ if (pass_x != 0 && pass_y != 0)
+ {
+
+ switch (grd[ pass_x ][ pass_y ])
+ {
+ case DNGN_ROCK_WALL:
+ case DNGN_STONE_WALL:
+ case DNGN_METAL_WALL:
+ case DNGN_GREEN_CRYSTAL_WALL:
+ case DNGN_WAX_WALL:
+ case DNGN_SILVER_STATUE:
+ case DNGN_ORANGE_CRYSTAL_STATUE:
+ ouch(1 + you.hp, 0, KILLED_BY_PETRIFICATION);
+ break;
+
+ case DNGN_SECRET_DOOR: // oughtn't happen
+ case DNGN_CLOSED_DOOR: // open the door
+ grd[ pass_x ][ pass_y ] = DNGN_OPEN_DOOR;
+ break;
+
+ default:
+ break;
+ }
+
+ //jmf: hmm, what to do. kill the monster? (seems too powerful)
+ // displace the monster? randomly teleport the monster?
+ // This seems fair: try to move the monster, but if not
+ // able to, then kill it.
+ int mon = mgrd[ pass_x ][ pass_y ];
+ if (mon != NON_MONSTER)
+ {
+ monster_blink( &menv[ mon ] );
+
+ // recheck square for monster
+ mon = mgrd[ pass_x ][ pass_y ];
+ if (mon != NON_MONSTER)
+ monster_die( &menv[ mon ], KILL_YOU, 0 );
+ }
+
+ you.x_pos = pass_x;
+ you.y_pos = pass_y;
+ redraw_screen();
+
+ const unsigned char grid = grd[ you.x_pos ][ you.y_pos ];
+ if ((grid == DNGN_LAVA || grid == DNGN_DEEP_WATER)
+ && !player_is_levitating())
+ {
+ if (you.species == SP_MERFOLK && grid == DNGN_DEEP_WATER)
+ {
+ mpr("You fall into the water and return "
+ "to your normal form.");
+ merfolk_start_swimming();
+ }
+ else
+ {
+ fall_into_a_pool( true, grid );
+ redraw_screen();
+ }
+ }
+ }
+ }
+ break;
+
+ case DELAY_BUTCHER:
+ strcpy( info, "You finish " );
+ strcat( info, (you.species == SP_TROLL
+ || you.species == SP_GHOUL) ? "ripping"
+ : "chopping" );
+
+ strcat( info, " the corpse into pieces." );
+ mpr( info );
+
+ turn_corpse_into_chunks( mitm[ delay.parm1 ] );
+
+ if (you.berserker && you.berserk_penalty != NO_BERSERK_PENALTY)
+ {
+ mpr("You enjoyed that.");
+ you.berserk_penalty = 0;
+ }
+ break;
+
+ case DELAY_DROP_ITEM:
+ // Note: checking if item is dropable is assumed to
+ // be done before setting up this delay... this includes
+ // quantity (delay.parm2). -- bwr
+
+ // Make sure item still exists.
+ if (!is_valid_item( you.inv[ delay.parm1 ] ))
+ break;
+
+ // Must handle unwield_item before we attempt to copy
+ // so that temporary brands and such are cleared. -- bwr
+ if (delay.parm1 == you.equip[EQ_WEAPON])
+ {
+ unwield_item( delay.parm1 );
+ you.equip[EQ_WEAPON] = -1;
+ canned_msg( MSG_EMPTY_HANDED );
+ }
+
+ if (!copy_item_to_grid( you.inv[ delay.parm1 ],
+ you.x_pos, you.y_pos, delay.parm2 ))
+ {
+ mpr("Too many items on this level, not dropping the item.");
+ }
+ else
+ {
+ quant_name( you.inv[ delay.parm1 ], delay.parm2,
+ DESC_NOCAP_A, str_pass );
+
+ snprintf( info, INFO_SIZE, "You drop %s.", str_pass );
+ mpr(info);
+
+ dec_inv_item_quantity( delay.parm1, delay.parm2 );
+ }
+ break;
+
+ case DELAY_ASCENDING_STAIRS:
+ up_stairs();
+ untag_followers();
+ break;
+
+ case DELAY_DESCENDING_STAIRS:
+ down_stairs( false, delay.parm1 );
+ untag_followers();
+ break;
+
+ case DELAY_INTERUPTABLE:
+ case DELAY_UNINTERUPTABLE:
+ // these are simple delays that have no effect when complete
+ break;
+
+ default:
+ mpr( "You finish doing something." );
+ break;
+ }
+
+ you.wield_change = true;
+ print_stats(); // force redraw of the stats
+ you.turn_is_over = 1;
+ you.delay_queue.pop();
+ }
+ }
+}
diff --git a/trunk/source/delay.h b/trunk/source/delay.h
new file mode 100644
index 0000000000..e171e355c8
--- /dev/null
+++ b/trunk/source/delay.h
@@ -0,0 +1,19 @@
+/*
+ * File: delay.h
+ * Summary: Functions for handling multi-turn actions.
+ *
+ * Change History (most recent first):
+ *
+ * <1> 09/09/01 BWR Created
+ */
+
+#ifndef DELAY_H
+#define DELAY_H
+
+void start_delay( int type, int turns, int parm1 = 0, int parm2 = 0 );
+void stop_delay( void );
+bool you_are_delayed( void );
+int current_delay_action( void );
+void handle_delay( void );
+
+#endif
diff --git a/trunk/source/describe.cc b/trunk/source/describe.cc
new file mode 100644
index 0000000000..a02e33b95d
--- /dev/null
+++ b/trunk/source/describe.cc
@@ -0,0 +1,6689 @@
+/*
+ * File: describe.cc
+ * Summary: Functions used to print information about various game objects.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <4> 10/14/99 BCR enummed describe_god()
+ * <3> 10/13/99 BCR Added GOD_NO_GOD case in describe_god()
+ * <2> 5/20/99 BWR Replaced is_artifact with
+ * is_dumpable_artifact
+ * <1> 4/20/99 JDJ Reformatted, uses string objects,
+ * split out 10 new functions from
+ * describe_item(), added
+ * get_item_description and
+ * is_artifact.
+ */
+
+#include "AppHdr.h"
+#include "describe.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string>
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#include "externs.h"
+
+#include "abl-show.h"
+#include "debug.h"
+#include "fight.h"
+#include "itemname.h"
+#include "macro.h"
+#include "mon-util.h"
+#include "player.h"
+#include "randart.h"
+#include "religion.h"
+#include "skills2.h"
+#include "stuff.h"
+#include "wpn-misc.h"
+#include "spl-util.h"
+
+
+// ========================================================================
+// Internal Functions
+// ========================================================================
+
+//---------------------------------------------------------------
+//
+// append_value
+//
+// Appends a value to the string. If plussed == 1, will add a + to
+// positive values (itoa always adds - to -ve ones).
+//
+//---------------------------------------------------------------
+static void append_value( std::string & description, int valu, bool plussed )
+{
+ if (valu >= 0 && plussed == 1)
+ description += "+";
+
+ char value_str[80];
+
+ itoa( valu, value_str, 10 );
+
+ description += value_str;
+} // end append_value()
+
+//---------------------------------------------------------------
+//
+// print_description
+//
+// Takes a descpr string filled up with stuff from other functions,
+// and displays it with minor formatting to avoid cut-offs in mid
+// word and such. The character $ is interpreted as a CR.
+//
+//---------------------------------------------------------------
+static void print_description( const std::string &d )
+{
+ unsigned int nextLine = std::string::npos;
+ unsigned int currentPos = 0;
+
+#ifdef DOS
+ const unsigned int lineWidth = 52;
+#else
+ const unsigned int lineWidth = 70;
+#endif
+
+ bool nlSearch = true; // efficiency
+
+ textcolor(LIGHTGREY);
+
+ while(currentPos < d.length())
+ {
+ if (currentPos != 0)
+ {
+#ifdef PLAIN_TERM
+ gotoxy(1, wherey() + 1);
+#endif
+#ifdef DOS_TERM
+ cprintf(EOL);
+#endif
+ }
+
+ // see if $ sign is within one lineWidth
+ if (nlSearch)
+ {
+ nextLine = d.find('$', currentPos);
+
+ if (nextLine >= currentPos && nextLine < currentPos + lineWidth)
+ {
+ cprintf((d.substr(currentPos, nextLine - currentPos)).c_str());
+ currentPos = nextLine + 1;
+ continue;
+ }
+
+ if (nextLine == std::string::npos)
+ nlSearch = false; // there are no newlines, don't search again.
+ }
+
+ // no newline -- see if rest of string will fit.
+ if (currentPos + lineWidth >= d.length())
+ {
+ cprintf((d.substr(currentPos)).c_str());
+ return;
+ }
+
+
+ // ok.. try to truncate at space.
+ nextLine = d.rfind(' ', currentPos + lineWidth);
+
+ if (nextLine > 0)
+ {
+ cprintf((d.substr(currentPos, nextLine - currentPos)).c_str());
+ currentPos = nextLine + 1;
+ continue;
+ }
+
+ // oops. just truncate.
+ nextLine = currentPos + lineWidth;
+
+ if (nextLine > d.length())
+ nextLine = d.length();
+
+ cprintf((d.substr(currentPos, nextLine - currentPos)).c_str());
+ currentPos = nextLine;
+ }
+}
+
+//---------------------------------------------------------------
+//
+// randart_descpr
+//
+// Appends the various powers of a random artefact to the description
+// string.
+//
+//---------------------------------------------------------------
+static void randart_descpr( std::string &description, const item_def &item )
+{
+ unsigned int old_length = description.length();
+
+ FixedVector< char, RA_PROPERTIES > proprt;
+ randart_wpn_properties( item, proprt );
+
+ if (proprt[ RAP_AC ])
+ {
+ description += "$It affects your AC (";
+ append_value(description, proprt[ RAP_AC ], true);
+ description += ").";
+ }
+
+ if (proprt[ RAP_EVASION ])
+ {
+ description += "$It affects your evasion (";
+ append_value(description, proprt[ RAP_EVASION ], true);
+ description += ").";
+ }
+
+ if (proprt[ RAP_STRENGTH ])
+ {
+ description += "$It affects your strength (";
+ append_value(description, proprt[ RAP_STRENGTH ], true);
+ description += ").";
+ }
+
+ if (proprt[ RAP_INTELLIGENCE ])
+ {
+ description += "$It affects your intelligence (";
+ append_value(description, proprt[ RAP_INTELLIGENCE ], true);
+ description += ").";
+ }
+
+ if (proprt[ RAP_DEXTERITY ])
+ {
+ description += "$It affects your dexterity (";
+ append_value(description, proprt[ RAP_DEXTERITY ], true);
+ description += ").";
+ }
+
+ if (proprt[ RAP_ACCURACY ])
+ {
+ description += "$It affects your accuracy (";
+ append_value(description, proprt[ RAP_ACCURACY ], true);
+ description += ").";
+ }
+
+ if (proprt[ RAP_DAMAGE ])
+ {
+ description += "$It affects your damage-dealing abilities (";
+ append_value(description, proprt[ RAP_DAMAGE ], true);
+ description += ").";
+ }
+
+ if (proprt[ RAP_FIRE ] < -2)
+ description += "$It makes you highly vulnerable to fire. ";
+ else if (proprt[ RAP_FIRE ] == -2)
+ description += "$It makes you greatly susceptible to fire. ";
+ else if (proprt[ RAP_FIRE ] == -1)
+ description += "$It makes you susceptible to fire. ";
+ else if (proprt[ RAP_FIRE ] == 1)
+ description += "$It protects you from fire. ";
+ else if (proprt[ RAP_FIRE ] == 2)
+ description += "$It greatly protects you from fire. ";
+ else if (proprt[ RAP_FIRE ] > 2)
+ description += "$It renders you almost immune to fire. ";
+
+ if (proprt[ RAP_COLD ] < -2)
+ description += "$It makes you highly susceptible to cold. ";
+ else if (proprt[ RAP_COLD ] == -2)
+ description += "$It makes you greatly susceptible to cold. ";
+ else if (proprt[ RAP_COLD ] == -1)
+ description += "$It makes you susceptible to cold. ";
+ else if (proprt[ RAP_COLD ] == 1)
+ description += "$It protects you from cold. ";
+ else if (proprt[ RAP_COLD ] == 2)
+ description += "$It greatly protects you from cold. ";
+ else if (proprt[ RAP_COLD ] > 2)
+ description += "$It renders you almost immune to cold. ";
+
+ if (proprt[ RAP_ELECTRICITY ])
+ description += "$It insulates you from electricity. ";
+
+ if (proprt[ RAP_POISON ])
+ description += "$It protects you from poison. ";
+
+ if (proprt[ RAP_NEGATIVE_ENERGY ] == 1)
+ description += "$It partially protects you from negative energy. ";
+ else if (proprt[ RAP_NEGATIVE_ENERGY ] == 2)
+ description += "$It protects you from negative energy. ";
+ else if (proprt[ RAP_NEGATIVE_ENERGY ] > 2)
+ description += "$It renders you almost immune negative energy. ";
+
+ if (proprt[ RAP_MAGIC ])
+ description += "$It protects you from magic. ";
+
+ if (proprt[ RAP_STEALTH ] < 0)
+ {
+ if (proprt[ RAP_STEALTH ] < -20)
+ description += "$It makes you much less stealthy. ";
+ else
+ description += "$It makes you less stealthy. ";
+ }
+ else if (proprt[ RAP_STEALTH ] > 0)
+ {
+ if (proprt[ RAP_STEALTH ] > 20)
+ description += "$It makes you much more stealthy. ";
+ else
+ description += "$It makes you more stealthy. ";
+ }
+
+ if (proprt[ RAP_EYESIGHT ])
+ description += "$It enhances your eyesight. ";
+
+ if (proprt[ RAP_INVISIBLE ])
+ description += "$It lets you turn invisible. ";
+
+ if (proprt[ RAP_LEVITATE ])
+ description += "$It lets you levitate. ";
+
+ if (proprt[ RAP_BLINK ])
+ description += "$It lets you blink. ";
+
+ if (proprt[ RAP_CAN_TELEPORT ])
+ description += "$It lets you teleport. ";
+
+ if (proprt[ RAP_BERSERK ])
+ description += "$It lets you go berserk. ";
+
+ if (proprt[ RAP_MAPPING ])
+ description += "$It lets you sense your surroundings. ";
+
+ if (proprt[ RAP_NOISES ])
+ description += "$It makes noises. ";
+
+ if (proprt[ RAP_PREVENT_SPELLCASTING ])
+ description += "$It prevents spellcasting. ";
+
+ if (proprt[ RAP_CAUSE_TELEPORTATION ])
+ description += "$It causes teleportation. ";
+
+ if (proprt[ RAP_PREVENT_TELEPORTATION ])
+ description += "$It prevents most forms of teleportation. ";
+
+ if (proprt[ RAP_ANGRY ])
+ description += "$It makes you angry. ";
+
+ if (proprt[ RAP_METABOLISM ] >= 3)
+ description += "$It greatly speeds your metabolism. ";
+ else if (proprt[ RAP_METABOLISM ])
+ description += "$It speeds your metabolism. ";
+
+ if (proprt[ RAP_MUTAGENIC ] > 3)
+ description += "$It glows with mutagenic radiation.";
+ else if (proprt[ RAP_MUTAGENIC ])
+ description += "$It emits mutagenic radiations.";
+
+ if (old_length != description.length())
+ description += "$";
+
+ if (is_unrandom_artefact( item ))
+ {
+ const char *desc = unrandart_descrip( 0, item );
+ if (strlen( desc ) > 0)
+ {
+ description += desc;
+ description += "$";
+ }
+ }
+}
+
+
+//---------------------------------------------------------------
+//
+// describe_demon
+//
+// Describes the random demons you find in Pandemonium.
+//
+//---------------------------------------------------------------
+static std::string describe_demon(void)
+{
+ long globby = 0;
+
+ for (unsigned int i = 0; i < strlen( ghost.name ); i++)
+ globby += ghost.name[i];
+
+ globby *= strlen( ghost.name );
+
+ srand( globby );
+
+ std::string description = "A powerful demon, ";
+
+ description += ghost.name;
+ description += " has a";
+
+ switch (random2(31))
+ {
+ case 0:
+ description += " huge, barrel-shaped ";
+ break;
+ case 1:
+ description += " wispy, insubstantial ";
+ break;
+ case 2:
+ description += " spindly ";
+ break;
+ case 3:
+ description += " skeletal ";
+ break;
+ case 4:
+ description += " horribly deformed ";
+ break;
+ case 5:
+ description += " spiny ";
+ break;
+ case 6:
+ description += " waif-like ";
+ break;
+ case 7:
+ description += " scaly ";
+ break;
+ case 8:
+ description += " sickeningly deformed ";
+ break;
+ case 9:
+ description += " bruised and bleeding ";
+ break;
+ case 10:
+ description += " sickly ";
+ break;
+ case 11:
+ description += " mass of writhing tentacles for a ";
+ break;
+ case 12:
+ description += " mass of ropey tendrils for a ";
+ break;
+ case 13:
+ description += " tree trunk-like ";
+ break;
+ case 14:
+ description += " hairy ";
+ break;
+ case 15:
+ description += " furry ";
+ break;
+ case 16:
+ description += " fuzzy ";
+ break;
+ case 17:
+ description += "n obese ";
+ break;
+ case 18:
+ description += " fat ";
+ break;
+ case 19:
+ description += " slimy ";
+ break;
+ case 20:
+ description += " wrinkled ";
+ break;
+ case 21:
+ description += " metallic ";
+ break;
+ case 22:
+ description += " glassy ";
+ break;
+ case 23:
+ description += " crystalline ";
+ break;
+ case 24:
+ description += " muscular ";
+ break;
+ case 25:
+ description += "n icky ";
+ break;
+ case 26:
+ description += " swollen ";
+ break;
+ case 27:
+ description += " lumpy ";
+ break;
+ case 28:
+ description += " armoured ";
+ break;
+ case 29:
+ description += " carapaced ";
+ break;
+ case 30:
+ description += " slender ";
+ break;
+ }
+
+ description += "body";
+
+
+ switch (ghost.values[GVAL_DEMONLORD_FLY])
+ {
+ case 1: // proper flight
+ switch (random2(10))
+ {
+ case 0:
+ description += " with small insectoid wings";
+ break;
+ case 1:
+ description += " with large insectoid wings";
+ break;
+ case 2:
+ description += " with moth-like wings";
+ break;
+ case 3:
+ description += " with butterfly wings";
+ break;
+ case 4:
+ description += " with huge, bat-like wings";
+ break;
+ case 5:
+ description += " with fleshy wings";
+ break;
+ case 6:
+ description += " with small, bat-like wings";
+ break;
+ case 7:
+ description += " with hairy wings";
+ break;
+ case 8:
+ description += " with great feathered wings";
+ break;
+ case 9:
+ description += " with shiny metal wings";
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case 2: // levitation
+ if (coinflip())
+ description += " which hovers in mid-air";
+ else
+ description += " with sacs of gas hanging from its back";
+ break;
+
+ default: // does not fly
+ switch (random2(40))
+ {
+ default:
+ break;
+ case 12:
+ description += " covered in tiny crawling spiders";
+ break;
+ case 13:
+ description += " covered in tiny crawling insects";
+ break;
+ case 14:
+ description += " and the head of a crocodile";
+ break;
+ case 15:
+ description += " and the head of a hippopotamus";
+ break;
+ case 16:
+ description += " and a cruel curved beak for a mouth";
+ break;
+ case 17:
+ description += " and a straight sharp beak for a mouth";
+ break;
+ case 18:
+ description += " and no head at all";
+ break;
+ case 19:
+ description += " and a hideous tangle of tentacles for a mouth";
+ break;
+ case 20:
+ description += " and an elephantine trunk";
+ break;
+ case 21:
+ description += " and an evil-looking proboscis";
+ break;
+ case 22:
+ description += " and dozens of eyes";
+ break;
+ case 23:
+ description += " and two ugly heads";
+ break;
+ case 24:
+ description += " and a long serpentine tail";
+ break;
+ case 25:
+ description += " and a pair of huge tusks growing from its jaw";
+ break;
+ case 26:
+ description +=
+ " and a single huge eye, in the centre of its forehead";
+ break;
+ case 27:
+ description += " and spikes of black metal for teeth";
+ break;
+ case 28:
+ description += " and a disc-shaped sucker for a head";
+ break;
+ case 29:
+ description += " and huge, flapping ears";
+ break;
+ case 30:
+ description += " and a huge, toothy maw in the centre of its chest";
+ break;
+ case 31:
+ description += " and a giant snail shell on its back";
+ break;
+ case 32:
+ description += " and a dozen heads";
+ break;
+ case 33:
+ description += " and the head of a jackal";
+ break;
+ case 34:
+ description += " and the head of a baboon";
+ break;
+ case 35:
+ description += " and a huge, slobbery tongue";
+ break;
+ case 36:
+ description += " which is covered in oozing lacerations";
+ break;
+ case 37:
+ description += " and the head of a frog";
+ break;
+ case 38:
+ description += " and the head of a yak";
+ break;
+ case 39:
+ description += " and eyes out on stalks";
+ break;
+ }
+ break;
+ }
+
+ description += ".";
+
+ switch (random2(40) + (you.species == SP_MUMMY ? 3 : 0))
+ {
+ case 0:
+ description += " It stinks of brimstone.";
+ break;
+ case 1:
+ description += " It smells like rotting flesh";
+ if (you.species == SP_GHOUL)
+ description += " - yum!";
+ else
+ description += ".";
+ break;
+ case 2:
+ description += " It is surrounded by a sickening stench.";
+ break;
+ case 3:
+ description += " It seethes with hatred of the living.";
+ break;
+ case 4:
+ description += " Tiny orange flames dance around it.";
+ break;
+ case 5:
+ description += " Tiny purple flames dance around it.";
+ break;
+ case 6:
+ description += " It is surrounded by a weird haze.";
+ break;
+ case 7:
+ description += " It glows with a malevolent light.";
+ break;
+ case 8:
+ description += " It looks incredibly angry.";
+ break;
+ case 9:
+ description += " It oozes with slime.";
+ break;
+ case 10:
+ description += " It dribbles constantly.";
+ break;
+ case 11:
+ description += " Mould grows all over it.";
+ break;
+ case 12:
+ description += " It looks diseased.";
+ break;
+ case 13:
+ description += " It looks as frightened of you as you are of it.";
+ break;
+ case 14:
+ description += " It moves in a series of hideous convulsions.";
+ break;
+ case 15:
+ description += " It moves with an unearthly grace.";
+ break;
+ case 16:
+ description += " It hungers for your soul!";
+ break;
+ case 17:
+ description += " It leaves a glistening oily trail.";
+ break;
+ case 18:
+ description += " It shimmers before your eyes.";
+ break;
+ case 19:
+ description += " It is surrounded by a brilliant glow.";
+ break;
+ case 20:
+ description += " It radiates an aura of extreme power.";
+ break;
+ default:
+ break;
+ }
+
+ return description;
+} // end describe_demon()
+
+
+//---------------------------------------------------------------
+//
+// describe_weapon
+//
+//---------------------------------------------------------------
+static std::string describe_weapon( const item_def &item, char verbose)
+{
+ std::string description;
+
+ description.reserve(200);
+
+ description = "";
+
+ if (is_fixed_artefact( item ))
+ {
+ if (item_ident( item, ISFLAG_KNOW_PROPERTIES ))
+ {
+ description += "$";
+
+ switch (item.special)
+ {
+ case SPWPN_SINGING_SWORD:
+ description += "This blessed weapon loves nothing more "
+ "than to sing to its owner, "
+ "whether they want it to or not. ";
+ break;
+ case SPWPN_WRATH_OF_TROG:
+ description += "This was the favourite weapon of "
+ "the old god Trog, before he lost it one day. "
+ "It induces a bloodthirsty berserker rage in "
+ "anyone who uses it to strike another. ";
+ break;
+ case SPWPN_SCYTHE_OF_CURSES:
+ description += "This weapon carries a "
+ "terrible and highly irritating curse. ";
+ break;
+ case SPWPN_MACE_OF_VARIABILITY:
+ description += "It is rather unreliable. ";
+ break;
+ case SPWPN_GLAIVE_OF_PRUNE:
+ description += "It is the creation of a mad god, and "
+ "carries a curse which transforms anyone "
+ "possessing it into a prune. Fortunately, "
+ "the curse works very slowly, and one can "
+ "use it briefly with no consequences "
+ "worse than slightly purple skin and a few wrinkles. ";
+ break;
+ case SPWPN_SCEPTRE_OF_TORMENT:
+ description += "This truly accursed weapon is "
+ "an instrument of Hell. ";
+ break;
+ case SPWPN_SWORD_OF_ZONGULDROK:
+ description += "This dreadful weapon is used "
+ "at the user's peril. ";
+ break;
+ case SPWPN_SWORD_OF_CEREBOV:
+ description += "Eerie flames cover its twisted blade. ";
+ break;
+ case SPWPN_STAFF_OF_DISPATER:
+ description += "This legendary item can unleash "
+ "the fury of Hell. ";
+ break;
+ case SPWPN_SCEPTRE_OF_ASMODEUS:
+ description += "It carries some of the powers of "
+ "the arch-fiend Asmodeus. ";
+ break;
+ case SPWPN_SWORD_OF_POWER:
+ description += "It rewards the powerful with power "
+ "and the meek with weakness. ";
+ break;
+ case SPWPN_KNIFE_OF_ACCURACY:
+ description += "It is almost unerringly accurate. ";
+ break;
+ case SPWPN_STAFF_OF_OLGREB:
+ description += "It was the magical weapon wielded by the "
+ "mighty wizard Olgreb before he met his "
+ "fate somewhere within these dungeons. It "
+ "grants its wielder resistance to the "
+ "effects of poison and increases their "
+ "ability to use venomous magic, and "
+ "carries magical powers which can be evoked. ";
+ break;
+ case SPWPN_VAMPIRES_TOOTH:
+ description += "It is lethally vampiric. ";
+ break;
+ case SPWPN_STAFF_OF_WUCAD_MU:
+ description += "Its power varies in proportion to "
+ "its wielder's intelligence. "
+ "Using it can be a bit risky. ";
+ break;
+ }
+
+ description += "$";
+ }
+ else if (item_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ // We know it's an artefact type weapon, but not what it does.
+ description += "$This weapon may have some hidden properties.$";
+ }
+ }
+ else if (is_unrandom_artefact( item )
+ && strlen(unrandart_descrip(1, item)) != 0)
+ {
+ description += unrandart_descrip(1, item);
+ description += "$";
+ }
+ else
+ {
+ if (verbose == 1)
+ {
+ switch (item.sub_type)
+ {
+ case WPN_CLUB:
+ description += "A heavy piece of wood. ";
+ break;
+
+ case WPN_MACE:
+ description += "A long handle "
+ "with a heavy lump on one end. ";
+ break;
+
+ case WPN_FLAIL:
+ description += "Like a mace, but with a length of chain "
+ "between the handle and the lump of metal. ";
+ break;
+
+ case WPN_DAGGER:
+ description += "A long knife or a very short sword, "
+ "which can be held or thrown. ";
+ break;
+
+ case WPN_KNIFE:
+ description += "A simple survival knife. "
+ "Designed more for utility than combat, "
+ "it looks quite capable of butchering a corpse. ";
+ break;
+
+ case WPN_MORNINGSTAR:
+ description += "A mace covered in spikes. ";
+ break;
+
+ case WPN_SHORT_SWORD:
+ description += "A sword with a short, slashing blade. ";
+ break;
+
+ case WPN_LONG_SWORD:
+ description += "A sword with a long, slashing blade. ";
+ break;
+
+ case WPN_GREAT_SWORD:
+ description += "A sword with a very long, heavy blade "
+ "and a long handle. ";
+ break;
+
+ case WPN_SCIMITAR:
+ description += "A long sword with a curved blade. ";
+ break;
+
+ case WPN_HAND_AXE:
+ description += "An small axe designed for either hand combat "
+ "or throwing. ";
+ // "It might also make a good tool.";
+ break;
+
+ case WPN_BATTLEAXE:
+ description += "A large axe with a double-headed blade. ";
+ break;
+
+ case WPN_SPEAR:
+ description += "A long stick with a pointy blade on one end, "
+ "to be held or thrown. ";
+ break;
+
+ case WPN_TRIDENT:
+ description +=
+ "A hafted weapon with three points at one end. ";
+ break;
+
+ case WPN_HALBERD:
+ description +=
+ "A long pole with a spiked axe head on one end. ";
+ break;
+
+ case WPN_SLING:
+ description +=
+ "A piece of cloth and leather for launching stones, "
+ "which do a small amount of damage on impact. ";
+ break;
+
+ case WPN_BOW:
+ description += "A curved piece of wood and string, "
+ "for shooting arrows. It does good damage in combat, "
+ "and a skilled user can use it to great effect. ";
+ break;
+
+ case WPN_BLOWGUN:
+ description += "A long, light tube, open at both ends. Doing "
+ "very little damage, its main use is to fire poisoned "
+ "needles from afar. It makes very little noise. ";
+ break;
+
+ case WPN_CROSSBOW:
+ description += "A piece of machinery used for firing bolts, "
+ "which takes some time to load and fire. "
+ "It does very good damage in combat. ";
+ break;
+
+ case WPN_HAND_CROSSBOW:
+ description += "A small crossbow, for firing darts. ";
+ break;
+
+ case WPN_GLAIVE:
+ description +=
+ "A pole with a large, heavy blade on one end. ";
+ break;
+
+ case WPN_QUARTERSTAFF:
+ description += "A sturdy wooden pole. ";
+ break;
+
+ case WPN_SCYTHE:
+ description +=
+ "A farm implement, usually unsuited to combat. ";
+ break;
+
+ case WPN_GIANT_CLUB:
+ description += "A giant lump of wood, "
+ "shaped for an ogre's hands. ";
+ break;
+
+ case WPN_GIANT_SPIKED_CLUB:
+ description +=
+ "A giant lump of wood with sharp spikes at one end. ";
+ break;
+
+ case WPN_EVENINGSTAR:
+ description += "The opposite of a morningstar. ";
+ break;
+
+ case WPN_QUICK_BLADE:
+ description += "A small and magically quick sword. ";
+ break;
+
+ case WPN_KATANA:
+ description += "A very rare and extremely effective "
+ "imported weapon, featuring a long "
+ "single-edged blade. ";
+ break;
+
+ case WPN_EXECUTIONERS_AXE:
+ description += "A huge axe. ";
+ break;
+
+ case WPN_DOUBLE_SWORD:
+ description +=
+ "A magical weapon with two razor-sharp blades. ";
+ break;
+
+ case WPN_TRIPLE_SWORD:
+ description += "A magical weapon with three "
+ "great razor-sharp blades. ";
+ break;
+
+ case WPN_HAMMER:
+ description += "The kind of thing you hit nails with, "
+ "adapted for battle. ";
+ break;
+
+ case WPN_ANCUS:
+ description += "A large and vicious toothed club. ";
+ break;
+
+ case WPN_WHIP:
+ description += "A whip. ";
+ break;
+
+ case WPN_SABRE:
+ description += "A sword with a medium length slashing blade. ";
+ break;
+
+ case WPN_DEMON_BLADE:
+ description +=
+ "A terrible weapon, forged in the fires of Hell. ";
+ break;
+
+ case WPN_DEMON_WHIP:
+ description += "A terrible weapon, woven "
+ "in the depths of the inferno. ";
+ break;
+
+ case WPN_DEMON_TRIDENT:
+ description +=
+ "A terrible weapon, molded by fire and brimstone. ";
+ break;
+
+ case WPN_BROAD_AXE:
+ description += "An axe with a large blade. ";
+ break;
+
+ case WPN_WAR_AXE:
+ description += "An axe intended for hand to hand combat. ";
+ break;
+
+ case WPN_SPIKED_FLAIL:
+ description +=
+ "A flail with large spikes on the metal lump. ";
+ break;
+
+ case WPN_GREAT_MACE:
+ description += "A large and heavy mace. ";
+ break;
+
+ case WPN_GREAT_FLAIL:
+ description += "A large and heavy flail. ";
+ break;
+
+ case WPN_FALCHION:
+ description += "A sword with a broad slashing blade. ";
+ break;
+
+ default:
+ DEBUGSTR("Unknown weapon");
+ }
+
+ description += "$";
+ }
+ }
+
+ if (verbose == 1 && !launches_things( item.sub_type ))
+ {
+ description += "$Damage rating: ";
+ append_value(description, property( item, PWPN_DAMAGE ), false);
+
+ description += "$Accuracy rating: ";
+ append_value(description, property( item, PWPN_HIT ), true);
+
+ description += "$Base attack delay: ";
+ append_value(description, property( item, PWPN_SPEED ) * 10, false);
+ description += "%%";
+ }
+ description += "$";
+
+ if (!is_fixed_artefact( item ))
+ {
+ int spec_ench = get_weapon_brand( item );
+
+ if (!is_random_artefact( item ) && verbose == 0)
+ spec_ench = SPWPN_NORMAL;
+
+ // special weapon descrip
+ if (spec_ench != SPWPN_NORMAL && item_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ description += "$";
+
+ switch (spec_ench)
+ {
+ case SPWPN_FLAMING:
+ description += "It emits flame when wielded, "
+ "causing extra injury to most foes "
+ "and up to double damage against "
+ "particularly susceptible opponents. ";
+ break;
+ case SPWPN_FREEZING:
+ description += "It has been specially enchanted to "
+ "freeze those struck by it, causing "
+ "extra injury to most foes and "
+ "up to double damage against "
+ "particularly susceptible opponents. ";
+ break;
+ case SPWPN_HOLY_WRATH:
+ description += "It has been blessed by the Shining One "
+ "to harm undead and cause great damage to "
+ "the unholy creatures of Hell or Pandemonium. ";
+ break;
+ case SPWPN_ELECTROCUTION:
+ description += "Occasionally upon striking a foe "
+ "it will discharge some electrical energy "
+ "and cause terrible harm. ";
+ break;
+ case SPWPN_ORC_SLAYING:
+ description += "It is especially effective against "
+ "all of orcish descent. ";
+ break;
+ case SPWPN_VENOM:
+ if (launches_things( item.sub_type ))
+ description += "It poisons the unbranded ammo it fires. ";
+ else
+ description += "It poisons the flesh of those it strikes. ";
+ break;
+ case SPWPN_PROTECTION:
+ description += "It protects the one who wields it against "
+ "injury (+5 to AC). ";
+ break;
+ case SPWPN_DRAINING:
+ description += "A truly terrible weapon, "
+ "it drains the life of those it strikes. ";
+ break;
+ case SPWPN_SPEED:
+ if (launches_things( item.sub_type ))
+ {
+ description += "It allows its wielder to fire twice when "
+ "they would otherwise have fired only once. ";
+ }
+ else
+ {
+ description += "It allows its wielder to attack twice when "
+ "they would otherwise have struck only once. ";
+ }
+ break;
+ case SPWPN_VORPAL:
+ description += "It inflicts extra damage upon your enemies. ";
+ break;
+ case SPWPN_FLAME:
+ description += "It turns projectiles fired from it into "
+ "bolts of fire. ";
+ break;
+ case SPWPN_FROST:
+ description += "It turns projectiles fired from it into "
+ "bolts of frost. ";
+ break;
+ case SPWPN_VAMPIRICISM:
+ description += "It inflicts no extra harm, "
+ "but heals its wielder somewhat when "
+ "he or she strikes a living foe. ";
+ break;
+ case SPWPN_DISRUPTION:
+ description += "It is a weapon blessed by Zin, "
+ "and can inflict up to fourfold damage "
+ "when used against the undead. ";
+ break;
+ case SPWPN_PAIN:
+ description += "In the hands of one skilled in "
+ "necromantic magic it inflicts "
+ "extra damage on living creatures. ";
+ break;
+ case SPWPN_DISTORTION:
+ description += "It warps and distorts space around it. ";
+ break;
+ case SPWPN_REACHING:
+ description += "It can be evoked to extend its reach. ";
+ break;
+ }
+ }
+
+ if (is_random_artefact( item ))
+ {
+ if (item_ident( item, ISFLAG_KNOW_PROPERTIES ))
+ {
+ unsigned int old_length = description.length();
+ randart_descpr( description, item );
+
+ if (description.length() == old_length)
+ description += "$";
+ }
+ else if (item_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ description += "$This weapon may have some hidden properties.$";
+ }
+ }
+ else if (spec_ench != SPWPN_NORMAL && item_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ description += "$";
+ }
+ }
+
+ if (item_known_cursed( item ))
+ {
+ description += "$It has a curse placed upon it.";
+ }
+
+ if (verbose == 1 && !launches_things( item.sub_type ))
+ {
+#ifdef USE_NEW_COMBAT_STATS
+ const int str_weight = weapon_str_weight( item.base_type, item.sub_type );
+
+ if (str_weight >= 8)
+ description += "$This weapon is best used by the strong.";
+ else if (str_weight > 5)
+ description += "$This weapon is better for the strong.";
+ else if (str_weight <= 2)
+ description += "$This weapon is best used by the dexterous.";
+ else if (str_weight < 5)
+ description += "$This weapon is better for the dexterous.";
+#endif
+
+ switch (hands_reqd_for_weapon(item.base_type, item.sub_type))
+ {
+ case HANDS_ONE_HANDED:
+ description += "$It is a one handed weapon.";
+ break;
+ case HANDS_ONE_OR_TWO_HANDED:
+ description += "$It can be used with one hand, or more "
+ "effectively with two (i.e. when not using a shield).";
+ break;
+ case HANDS_TWO_HANDED:
+ description += "$It is a two handed weapon.";
+ break;
+ }
+ }
+
+ if (!is_random_artefact( item ))
+ {
+ switch (get_equip_race( item ))
+ {
+ case ISFLAG_DWARVEN:
+ description += "$It is well-crafted and very durable.";
+ break;
+ }
+
+ if (launches_things( item.sub_type ))
+ {
+ switch (get_equip_race( item ))
+ {
+ case ISFLAG_DWARVEN:
+ description += "$It is most deadly when used with "
+ "dwarven ammunition.";
+ break;
+ case ISFLAG_ELVEN:
+ description += "$It is most deadly when used with "
+ "elven ammunition.";
+ break;
+ case ISFLAG_ORCISH:
+ description += "$It is most deadly when used with "
+ "orcish ammunition.";
+ break;
+ }
+ }
+ }
+
+ if (verbose == 1)
+ {
+ description += "$It falls into the";
+
+ switch (item.sub_type)
+ {
+ case WPN_SLING:
+ description += " 'slings' category. ";
+ break;
+ case WPN_BOW:
+ description += " 'bows' category. ";
+ break;
+ case WPN_HAND_CROSSBOW:
+ case WPN_CROSSBOW:
+ description += " 'crossbows' category. ";
+ break;
+ case WPN_BLOWGUN:
+ description += " 'darts' category. ";
+ break;
+ default:
+ // Melee weapons
+ switch (weapon_skill(item.base_type, item.sub_type))
+ {
+ case SK_SHORT_BLADES:
+ description += " 'short blades' category. ";
+ break;
+ case SK_LONG_SWORDS:
+ description += " 'long swords' category. ";
+ break;
+ case SK_AXES:
+ description += " 'axes' category. ";
+ break;
+ case SK_MACES_FLAILS:
+ description += " 'maces and flails' category. ";
+ break;
+ case SK_POLEARMS:
+ description += " 'pole-arms' category. ";
+ break;
+ case SK_STAVES:
+ description += " 'staves' category. ";
+ break;
+ default:
+ description += " 'bug' category. ";
+ DEBUGSTR("Unknown weapon type");
+ break;
+ }
+ }
+ }
+
+ return (description);
+}
+
+
+//---------------------------------------------------------------
+//
+// describe_ammo
+//
+//---------------------------------------------------------------
+static std::string describe_ammo( const item_def &item )
+{
+ std::string description;
+
+ description.reserve(64);
+
+ switch (item.sub_type)
+ {
+ case MI_STONE:
+ description += "A stone. ";
+ break;
+ case MI_ARROW:
+ description += "An arrow. ";
+ break;
+ case MI_NEEDLE:
+ description += "A needle. ";
+ break;
+ case MI_BOLT:
+ description += "A crossbow bolt. ";
+ break;
+ case MI_DART:
+ description += "A small throwing weapon. ";
+ break;
+ case MI_LARGE_ROCK:
+ description += "A rock, used by giants as a missile. ";
+ break;
+ case MI_EGGPLANT:
+ description += "A purple vegetable. "
+ "The presence of this object in the game "
+ "indicates a bug (or some kind of cheating on your part). ";
+ break;
+ default:
+ DEBUGSTR("Unknown ammo type");
+ break;
+ }
+
+ if (item.special != 0 && item_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ switch (item.special)
+ {
+ case 1:
+ description += "$When fired from an appropriate launcher, "
+ "it turns into a bolt of flame. ";
+ break;
+ case 2:
+ description += "$When fired from an appropriate launcher, "
+ "it turns into a bolt of ice. ";
+ break;
+ case 3:
+ case 4:
+ description += "$It is coated with poison. ";
+ break;
+ }
+ }
+
+ description += "$";
+
+ return (description);
+}
+
+
+//---------------------------------------------------------------
+//
+// describe_armour
+//
+//---------------------------------------------------------------
+static std::string describe_armour( const item_def &item, char verbose )
+{
+ std::string description;
+
+ description.reserve(200);
+
+ if (is_unrandom_artefact( item )
+ && strlen(unrandart_descrip(1, item)) != 0)
+ {
+ description += "$";
+ description += unrandart_descrip(1, item);
+ description += "$$";
+ }
+ else
+ {
+ if (verbose == 1)
+ {
+ switch (item.sub_type)
+ {
+ case ARM_ROBE:
+ description += "A cloth robe. ";
+ break;
+ case ARM_LEATHER_ARMOUR:
+ description += "A suit made of hardened leather. ";
+ break;
+ case ARM_RING_MAIL:
+ description += "A leather suit covered in little rings. ";
+ break;
+ case ARM_SCALE_MAIL:
+ description +=
+ "A leather suit covered in little metal plates. ";
+ break;
+ case ARM_CHAIN_MAIL:
+ description += "A suit made of interlocking metal rings. ";
+ break;
+ case ARM_SPLINT_MAIL:
+ description += "A suit made of splints of metal. ";
+ break;
+ case ARM_BANDED_MAIL:
+ description += "A suit made of bands of metal. ";
+ break;
+ case ARM_PLATE_MAIL:
+ description += "A suit of mail and large plates of metal. ";
+ break;
+ case ARM_SHIELD:
+ description +=
+ "A piece of metal, to be strapped on one's arm. "
+ "It is cumbersome to wear, and slightly slows "
+ "the rate at which you may attack. ";
+ break;
+ case ARM_CLOAK:
+ description += "A cloth cloak. ";
+ break;
+
+ case ARM_HELMET:
+ switch (get_helmet_type( item ))
+ {
+ case THELM_HELMET:
+ case THELM_HELM:
+ description += "A piece of metal headgear. ";
+ break;
+ case THELM_CAP:
+ description += "A cloth or leather cap. ";
+ break;
+ case THELM_WIZARD_HAT:
+ description += "A conical cloth hat. ";
+ break;
+ }
+ break;
+
+ case ARM_GLOVES:
+ description += "A pair of gloves. ";
+ break;
+ case ARM_BOOTS:
+ if (item.plus2 == TBOOT_NAGA_BARDING)
+ description += "A special armour made for Nagas, "
+ "to wear over their tails. ";
+ else if (item.plus2 == TBOOT_CENTAUR_BARDING)
+ description += "An armour made for centaurs, "
+ "to wear over their equine half. ";
+ else
+ description += "A pair of sturdy boots. ";
+ break;
+ case ARM_BUCKLER:
+ description += "A small shield. ";
+ break;
+ case ARM_LARGE_SHIELD:
+ description += "Like a normal shield, only larger. ";
+ if (you.species == SP_TROLL || you.species == SP_OGRE
+ || you.species == SP_OGRE_MAGE
+ || player_genus(GENPC_DRACONIAN))
+ {
+ description += "It looks like it would fit you well. ";
+ }
+ else
+ {
+ description += "It is very cumbersome to wear, and "
+ "slows the rate at which you may attack. ";
+ }
+ break;
+ case ARM_DRAGON_HIDE:
+ description += "The scaly skin of a dragon. I suppose "
+ "you could wear it if you really wanted to. ";
+ break;
+ case ARM_TROLL_HIDE:
+ description += "The stiff and knobbly hide of a troll. "
+ "I suppose you could wear it "
+ "if you really wanted to. ";
+ break;
+ case ARM_CRYSTAL_PLATE_MAIL:
+ description += "An incredibly heavy but extremely effective "
+ "suit of crystalline armour. "
+ "It is somewhat resistant to corrosion. ";
+ break;
+ case ARM_DRAGON_ARMOUR:
+ description += "A magical armour, made from the scales of "
+ "a fire-breathing dragon. It provides "
+ "great protection from the effects of fire, "
+ "but renders its wearer more susceptible to "
+ "the effects of cold. ";
+ break;
+ case ARM_TROLL_LEATHER_ARMOUR:
+ description += "A magical armour, made from the stiff and "
+ "knobbly skin of a common troll. It magically regenerates "
+ "its wearer's flesh at a fairly slow rate "
+ "(unless already a troll). ";
+ break;
+ case ARM_ICE_DRAGON_HIDE:
+ description += "The scaly skin of a dragon. I suppose "
+ "you could wear it if you really wanted to. ";
+ break;
+ case ARM_ICE_DRAGON_ARMOUR:
+ description += "A magical armour, made from the scales of "
+ "a cold-breathing dragon. It provides "
+ "great protection from the effects of cold, "
+ "but renders its wearer more susceptible to "
+ "the effects of fire and heat. ";
+ break;
+ case ARM_STEAM_DRAGON_HIDE:
+ description += "The soft and supple scaley skin of "
+ "a steam dragon. I suppose you could "
+ "wear it if you really wanted to. ";
+ break;
+ case ARM_STEAM_DRAGON_ARMOUR:
+ description += "A magical armour, made from the scales of "
+ "a steam-breathing dragon. Although unlike "
+ "the armour made from the scales of some "
+ "larger dragons it does not provide its wearer "
+ "with much in the way of special magical "
+ "protection, it is extremely light and "
+ "as supple as cloth. ";
+ break; /* Protects from steam */
+ case ARM_MOTTLED_DRAGON_HIDE:
+ description += "The weirdly-patterned scaley skin of "
+ "a mottled dragon. I suppose you could "
+ "wear it if you really wanted to. ";
+ break;
+ case ARM_MOTTLED_DRAGON_ARMOUR:
+ description += "A magical armour made from the scales of a "
+ "mottled dragon. Although unlike the armour "
+ "made from the scales of some larger dragons "
+ "it does not provide its wearer with much in "
+ "the way of special magical protection, it is "
+ "as light and relatively uncumbersome as "
+ "leather armour. ";
+ break; /* Protects from napalm */
+ case ARM_STORM_DRAGON_HIDE:
+ description += "The hide of a storm dragon, covered in "
+ "extremely hard blue scales. I suppose "
+ "you could wear it if you really wanted to. ";
+ break;
+ case ARM_STORM_DRAGON_ARMOUR:
+ description += "A magical armour made from the scales of "
+ "a lightning-breathing dragon. It is heavier "
+ "than most dragon scale armours, but gives "
+ "its wearer great resistance to "
+ "electrical discharges. ";
+ break;
+ case ARM_GOLD_DRAGON_HIDE:
+ description += "The extremely tough and heavy skin of a "
+ "golden dragon, covered in shimmering golden "
+ "scales. I suppose you could wear it if "
+ "you really wanted to. ";
+ break;
+ case ARM_GOLD_DRAGON_ARMOUR:
+ description += "A magical armour made from the golden scales "
+ "of a golden dragon. It is extremely heavy and "
+ "cumbersome, but confers resistances to fire, "
+ "cold, and poison on its wearer. ";
+ break;
+ case ARM_ANIMAL_SKIN:
+ description += "The skins of several animals. ";
+ break;
+ case ARM_SWAMP_DRAGON_HIDE:
+ description += "The slimy";
+ if (you.species != SP_MUMMY)
+ description += ", smelly";
+ description += " skin of a swamp-dwelling dragon. I suppose "
+ "you could wear it if you really wanted to. ";
+ break;
+ case ARM_SWAMP_DRAGON_ARMOUR:
+ description += "A magical armour made from the scales of "
+ "a swamp dragon. It confers resistance to "
+ "poison on its wearer. ";
+ break;
+ default:
+ DEBUGSTR("Unknown armour");
+ }
+
+ description += "$";
+ }
+ }
+
+ if (verbose == 1
+ && item.sub_type != ARM_SHIELD
+ && item.sub_type != ARM_BUCKLER
+ && item.sub_type != ARM_LARGE_SHIELD)
+ {
+ description += "$Armour rating: ";
+
+ if (item.sub_type == ARM_HELMET
+ && (get_helmet_type( item ) == THELM_CAP
+ || get_helmet_type( item ) == THELM_WIZARD_HAT))
+ {
+ // caps and wizard hats don't have a base AC
+ append_value(description, 0, false);
+ }
+ else if (item.sub_type == ARM_BOOTS && item.plus2 != TBOOT_BOOTS)
+ {
+ // Barding has AC value 4.
+ append_value(description, 4, false);
+ }
+ else
+ {
+ append_value(description, property( item, PARM_AC ), false);
+ }
+
+ description += "$Evasion modifier: ";
+ append_value(description, property( item, PARM_EVASION ), true);
+ description += "$";
+ }
+
+ int ego = get_armour_ego_type( item );
+ if (ego != SPARM_NORMAL
+ && item_ident( item, ISFLAG_KNOW_TYPE )
+ && verbose == 1)
+ {
+ description += "$";
+
+ switch (ego)
+ {
+ case SPARM_RUNNING:
+ description += "It allows its wearer to run at a great speed. ";
+ break;
+ case SPARM_FIRE_RESISTANCE:
+ description += "It protects its wearer from heat and fire. ";
+ break;
+ case SPARM_COLD_RESISTANCE:
+ description += "It protects its wearer from cold. ";
+ break;
+ case SPARM_POISON_RESISTANCE:
+ description += "It protects its wearer from poison. ";
+ break;
+ case SPARM_SEE_INVISIBLE:
+ description += "It allows its wearer to see invisible things. ";
+ break;
+ case SPARM_DARKNESS:
+ description += "When activated it hides its wearer from "
+ "the sight of others, but also increases "
+ "their metabolic rate by a large amount. ";
+ break;
+ case SPARM_STRENGTH:
+ description += "It increases the physical power of its wearer (+3 to strength). ";
+ break;
+ case SPARM_DEXTERITY:
+ description += "It increases the dexterity of its wearer (+3 to dexterity). ";
+ break;
+ case SPARM_INTELLIGENCE:
+ description += "It makes you more clever (+3 to intelligence). ";
+ break;
+ case SPARM_PONDEROUSNESS:
+ description += "It is very cumbersome (-2 to EV, slows movement). ";
+ break;
+ case SPARM_LEVITATION:
+ description += "It can be activated to allow its wearer to "
+ "float above the ground and remain so indefinitely. ";
+ break;
+ case SPARM_MAGIC_RESISTANCE:
+ description += "It increases its wearer's resistance "
+ "to enchantments. ";
+ break;
+ case SPARM_PROTECTION:
+ description += "It protects its wearer from harm (+3 to AC). ";
+ break;
+ case SPARM_STEALTH:
+ description += "It enhances the stealth of its wearer. ";
+ break;
+ case SPARM_RESISTANCE:
+ description += "It protects its wearer from the effects "
+ "of both cold and heat. ";
+ break;
+
+ // these two are robes only:
+ case SPARM_POSITIVE_ENERGY:
+ description += "It partially protects its wearer from "
+ "the effects of negative energy. ";
+ break;
+ case SPARM_ARCHMAGI:
+ description += "It greatly increases the power of its "
+ "wearer's magical spells, but is only "
+ "intended for those who have " "very little left to learn. ";
+ break;
+
+ case SPARM_PRESERVATION:
+ description += "It protects its wearer's possessions "
+ "from damage and destruction. ";
+ break;
+ }
+
+ description += "$";
+ }
+
+ if (is_random_artefact( item ))
+ {
+ if (item_ident( item, ISFLAG_KNOW_PROPERTIES ))
+ randart_descpr( description, item );
+ else if (item_ident( item, ISFLAG_KNOW_TYPE ))
+ description += "$This armour may have some hidden properties.$";
+ }
+ else
+ {
+ switch (get_equip_race( item ))
+ {
+ case ISFLAG_ELVEN:
+ //jmf: not light
+ description += "$It is well-crafted and unobstructive";
+
+ if (item.sub_type == ARM_CLOAK || item.sub_type == ARM_BOOTS)
+ description += ", and helps its wearer avoid being noticed";
+
+ description += ".";
+ break;
+
+ case ISFLAG_DWARVEN:
+ description += "$It is well-crafted and very durable.";
+ break;
+
+ case ISFLAG_ORCISH:
+ default:
+ break;
+ }
+ }
+
+ if (item_known_cursed( item ))
+ {
+ description += "$It has a curse placed upon it.";
+ }
+
+ return description;
+}
+
+//---------------------------------------------------------------
+//
+// describe_stick
+//
+//---------------------------------------------------------------
+static std::string describe_stick( const item_def &item )
+{
+ std::string description;
+
+ description.reserve(64);
+
+ if (get_ident_type( OBJ_WANDS, item.sub_type ) != ID_KNOWN_TYPE)
+ description += "A stick. Maybe it's magical. ";
+ else
+ {
+ description += "A magical device which ";
+ switch (item.sub_type)
+ {
+ case WAND_FLAME:
+ description += "throws little bits of flame. ";
+ break;
+
+ case WAND_FROST:
+ description += "throws little bits of frost. ";
+ break;
+
+ case WAND_SLOWING:
+ description += "casts enchantments to slow down the actions of "
+ "a creature at which it is directed. ";
+ break;
+
+ case WAND_HASTING:
+ description += "casts enchantments to speed up the actions of "
+ "a creature at which it is directed. ";
+ break;
+
+ case WAND_MAGIC_DARTS:
+ description += "throws small bolts of destructive energy. ";
+ break;
+
+ case WAND_HEALING:
+ description += "can heal a creature's wounds. ";
+ break;
+
+ case WAND_PARALYSIS:
+ description += "can render a creature immobile. ";
+ break;
+
+ case WAND_FIRE:
+ description += "throws great bolts of fire. ";
+ break;
+
+ case WAND_COLD:
+ description += "throws great bolts of cold. ";
+ break;
+
+ case WAND_CONFUSION:
+ description += "induces confusion and bewilderment in "
+ "a target creature. ";
+ break;
+
+ case WAND_INVISIBILITY:
+ description += "hides a creature from the view of others. ";
+ break;
+
+ case WAND_DIGGING:
+ description += "drills tunnels through unworked rock. ";
+ break;
+
+ case WAND_FIREBALL:
+ description += "throws exploding blasts of flame. ";
+ break;
+
+ case WAND_TELEPORTATION:
+ description += "causes a creature to be randomly translocated. ";
+ break;
+
+ case WAND_LIGHTNING:
+ description += "throws great bolts of lightning. ";
+ break;
+
+ case WAND_POLYMORPH_OTHER:
+ description += "causes a creature to be transmogrified into "
+ "another form. "
+ "It doesn't work on you, so don't even try. ";
+ break;
+
+ case WAND_ENSLAVEMENT:
+ description += "causes slavish obedience in a creature. ";
+ break;
+
+ case WAND_DRAINING:
+ description += "throws a bolt of negative energy which "
+ "drains the life essences of living creatures, "
+ "but is useless against the undead. ";
+ break;
+
+ case WAND_RANDOM_EFFECTS:
+ description += "can produce a variety of effects. ";
+ break;
+
+ case WAND_DISINTEGRATION:
+ description += "disrupts the physical structure of "
+ "an object, especially a creature's body. ";
+ break;
+
+ default:
+ DEBUGSTR("Unknown stick");
+ }
+
+ if (item_ident( item, ISFLAG_KNOW_PLUSES ) && item.plus == 0)
+ description += "Unfortunately, it has no charges left. ";
+ }
+
+ return description;
+}
+
+
+//---------------------------------------------------------------
+//
+// describe_food
+//
+//---------------------------------------------------------------
+static std::string describe_food( const item_def &item )
+{
+ std::string description;
+
+ description.reserve(100);
+
+ switch (item.sub_type)
+ {
+ // rations
+ case FOOD_MEAT_RATION:
+ case FOOD_BREAD_RATION:
+ description += "A filling ration of ";
+ switch (item.sub_type)
+ {
+ case FOOD_MEAT_RATION:
+ description += "dried and preserved meats";
+ break;
+ case FOOD_BREAD_RATION:
+ description += "breads";
+ break;
+ }
+ description += ". ";
+ break;
+
+ // fruits
+ case FOOD_PEAR:
+ case FOOD_APPLE:
+ case FOOD_APRICOT:
+ case FOOD_ORANGE:
+ case FOOD_BANANA:
+ case FOOD_STRAWBERRY:
+ case FOOD_RAMBUTAN:
+ case FOOD_LEMON:
+ case FOOD_GRAPE:
+ case FOOD_LYCHEE:
+ case FOOD_SULTANA:
+ description += "A";
+ switch (item.sub_type)
+ {
+ case FOOD_PEAR:
+ description += " delicious juicy";
+ break;
+ case FOOD_APPLE:
+ description += " delicious red or green";
+ break;
+ case FOOD_APRICOT:
+ description += " delicious orange";
+ break;
+ case FOOD_ORANGE:
+ description += " delicious juicy orange";
+ break;
+ case FOOD_BANANA:
+ description += " delicious yellow";
+ break;
+ case FOOD_STRAWBERRY:
+ description += " small but delicious red";
+ break;
+ case FOOD_RAMBUTAN:
+ description += " small but delicious tropical";
+ break;
+ case FOOD_LEMON:
+ description += " yellow";
+ break;
+ case FOOD_GRAPE:
+ description += " small";
+ break;
+ case FOOD_LYCHEE:
+ description += " tropical";
+ break;
+ case FOOD_SULTANA:
+ description += " dried";
+ break;
+ }
+
+ description += " fruit";
+
+ switch (item.sub_type)
+ {
+ case FOOD_BANANA:
+ description += ", probably grown and imported by "
+ "some amoral multinational as the "
+ "result of a corrupt trade deal";
+ break;
+ case FOOD_RAMBUTAN:
+ description += ". How it got into this dungeon "
+ "is anyone's guess";
+ break;
+ case FOOD_SULTANA:
+ description += " of some sort, possibly a grape";
+ break;
+ }
+ description += ". ";
+ break;
+
+ // vegetables
+ case FOOD_CHOKO:
+ case FOOD_SNOZZCUMBER:
+ description += "A";
+ switch (item.sub_type)
+ {
+ case FOOD_CHOKO:
+ description += "n almost tasteless green";
+ break;
+ case FOOD_SNOZZCUMBER:
+ description += " repulsive cucumber-shaped";
+ break;
+ }
+ description += " vegetable";
+ switch (item.sub_type)
+ {
+ case FOOD_CHOKO:
+ description += ", which grows on a vine";
+ break;
+ }
+ description += ". ";
+ break;
+
+ // lumps, slices, chunks, and strips
+ case FOOD_HONEYCOMB:
+ case FOOD_ROYAL_JELLY:
+ case FOOD_PIZZA:
+ case FOOD_CHEESE:
+ case FOOD_BEEF_JERKY:
+ case FOOD_SAUSAGE:
+ case FOOD_CHUNK:
+ description += "A";
+ switch (item.sub_type)
+ {
+ case FOOD_SAUSAGE:
+ description += "n elongated";
+ break;
+ }
+ switch (item.sub_type)
+ {
+ case FOOD_HONEYCOMB:
+ case FOOD_ROYAL_JELLY:
+ case FOOD_CHEESE:
+ case FOOD_SAUSAGE:
+ description += " lump";
+ break;
+ case FOOD_PIZZA:
+ description += " slice";
+ break;
+ case FOOD_BEEF_JERKY:
+ description += " strip";
+ break;
+ case FOOD_CHUNK:
+ description += " piece";
+ }
+ description += " of ";
+ switch (item.sub_type)
+ {
+ case FOOD_SAUSAGE:
+ description += "low-grade gristle, entrails and "
+ "cereal products encased in an intestine";
+ break;
+ case FOOD_HONEYCOMB:
+ description += "the delicious honeycomb made by giant bees";
+ break;
+ case FOOD_ROYAL_JELLY:
+ description += "the magical substance produced by giant bees "
+ "to be fed to their queens";
+ break;
+ case FOOD_PIZZA:
+ description += "pizza";
+ break;
+ case FOOD_CHEESE:
+ description += "cheese";
+ break;
+ case FOOD_BEEF_JERKY:
+ description += "preserved dead cow or bull";
+ break;
+ case FOOD_CHUNK:
+ description += "dungeon meat";
+ break;
+ }
+ description += ". ";
+ switch (item.sub_type)
+ {
+ case FOOD_SAUSAGE:
+ description += "Yum! ";
+ break;
+ case FOOD_PIZZA:
+ description += "Don't tell me you don't know what that is! ";
+ break;
+ case FOOD_CHUNK:
+ if (you.species != SP_GHOUL)
+ description += "It looks rather unpleasant. ";
+
+ if (item.special < 100)
+ {
+ if (you.species == SP_GHOUL)
+ description += "It looks nice and ripe. ";
+ else if (you.species != SP_MUMMY)
+ {
+ description += "In fact, it is "
+ "rotting away before your eyes. "
+ "Eating it would probably be unwise. ";
+ }
+ }
+ break;
+ }
+ break;
+
+ default:
+ DEBUGSTR("Unknown food");
+ }
+
+ description += "$";
+
+ return (description);
+}
+
+//---------------------------------------------------------------
+//
+// describe_potion
+//
+//---------------------------------------------------------------
+static std::string describe_potion( const item_def &item )
+{
+ std::string description;
+
+ description.reserve(64);
+
+ if (get_ident_type( OBJ_POTIONS, item.sub_type ) != ID_KNOWN_TYPE)
+ description += "A small bottle of liquid.";
+ else
+ {
+ description += "A";
+
+ switch (item.sub_type)
+ {
+ case POT_HEALING:
+ description += " blessed";
+ break;
+ case POT_HEAL_WOUNDS:
+ description += " magical healing";
+ break;
+ case POT_SPEED:
+ description += "n enchanted";
+ break;
+ case POT_MIGHT:
+ description += " magic";
+ break;
+ case POT_POISON:
+ description += " nasty poisonous";
+ break;
+ case POT_PORRIDGE:
+ description += " filling";
+ break;
+ case POT_DEGENERATION:
+ description += " noxious";
+ break;
+ case POT_DECAY:
+ description += " vile and putrid cursed";
+ break;
+ case POT_WATER:
+ description += " unique";
+ break;
+ case POT_EXPERIENCE:
+ description += " truly wonderful and very rare";
+ break;
+ case POT_MAGIC:
+ description += " valuable";
+ break;
+ case POT_STRONG_POISON:
+ description += " terribly venomous";
+ break;
+ }
+
+ description += " ";
+
+ switch (item.sub_type)
+ {
+ case POT_MIGHT:
+ case POT_GAIN_STRENGTH:
+ case POT_GAIN_DEXTERITY:
+ case POT_GAIN_INTELLIGENCE:
+ case POT_LEVITATION:
+ case POT_SLOWING:
+ case POT_PARALYSIS:
+ case POT_CONFUSION:
+ case POT_INVISIBILITY:
+ case POT_PORRIDGE:
+ case POT_MAGIC:
+ case POT_RESTORE_ABILITIES:
+ case POT_STRONG_POISON:
+ case POT_BERSERK_RAGE:
+ case POT_CURE_MUTATION:
+ case POT_MUTATION:
+ description += "potion";
+ break;
+ case POT_HEALING:
+ description += "fluid";
+ break;
+ case POT_HEAL_WOUNDS:
+ description += "elixir";
+ break;
+ case POT_SPEED:
+ description += "beverage";
+ break;
+ case POT_POISON:
+ case POT_DECAY:
+ description += "liquid";
+ break;
+ case POT_DEGENERATION:
+ description += "concoction";
+ break;
+ case POT_WATER:
+ description += "substance";
+ break;
+ case POT_EXPERIENCE:
+ description += "drink";
+ break;
+ }
+
+ switch (item.sub_type)
+ {
+ case POT_HEALING:
+ case POT_HEAL_WOUNDS:
+ case POT_SPEED:
+ case POT_MIGHT:
+ case POT_LEVITATION:
+ case POT_SLOWING:
+ case POT_PARALYSIS:
+ case POT_CONFUSION:
+ case POT_INVISIBILITY:
+ case POT_DEGENERATION:
+ case POT_DECAY:
+ case POT_MAGIC:
+ case POT_RESTORE_ABILITIES:
+ case POT_BERSERK_RAGE:
+ case POT_CURE_MUTATION:
+ case POT_MUTATION:
+ description += " which ";
+ break;
+ case POT_GAIN_STRENGTH:
+ case POT_GAIN_DEXTERITY:
+ case POT_GAIN_INTELLIGENCE:
+ case POT_PORRIDGE:
+ description += " of ";
+ break;
+ }
+
+ switch (item.sub_type)
+ {
+ case POT_HEALING:
+ description += "heals some wounds, clears the mind, "
+ "and cures diseases";
+ break;
+ case POT_HEAL_WOUNDS:
+ description += "causes wounds to close and heal "
+ "almost instantly";
+ break;
+ case POT_SPEED:
+ description += "speeds the actions of anyone who drinks it";
+ break;
+ case POT_MIGHT:
+ description += "greatly increases the strength and "
+ "physical power of one who drinks it";
+ break;
+ case POT_GAIN_STRENGTH:
+ case POT_GAIN_DEXTERITY:
+ case POT_GAIN_INTELLIGENCE:
+ description += "beneficial mutation";
+ break;
+ case POT_LEVITATION:
+ description += "confers great buoyancy on one who consumes it";
+ break;
+ case POT_SLOWING:
+ description += "slows your actions";
+ break;
+ case POT_PARALYSIS:
+ description += "eliminates your control over your own body";
+ break;
+ case POT_CONFUSION:
+ description += "confuses your perceptions and reduces "
+ "your control over your own actions";
+ break;
+ case POT_INVISIBILITY:
+ description += "hides you from the sight of others";
+ break;
+ case POT_PORRIDGE:
+ description += "sludge, high in cereal fibre";
+ break;
+ case POT_DEGENERATION:
+ description += "can do terrible things to your "
+ "body, brain and reflexes";
+ break;
+ case POT_DECAY:
+ description += "causes your flesh to decay "
+ "before your very eyes";
+ break;
+ case POT_WATER:
+ description += ", vital for the existence of most life";
+ break;
+ case POT_MAGIC:
+ description += "grants a person with an "
+ "infusion of magical energy";
+ break;
+ case POT_RESTORE_ABILITIES:
+ description += "restores the abilities of one who drinks it";
+ break;
+ case POT_BERSERK_RAGE:
+ description += "can send one into an incoherent rage";
+ break;
+ case POT_CURE_MUTATION:
+ description += "removes some or all of any mutations "
+ "which may be afflicting you";
+ break;
+ case POT_MUTATION:
+ description += "does very strange things to you";
+ break;
+ }
+
+ description += ". ";
+
+ switch (item.sub_type)
+ {
+ case POT_HEALING:
+ case POT_HEAL_WOUNDS:
+ description += "If one uses it when they are "
+ "at or near full health, it can also ";
+
+ if (item.sub_type == POT_HEALING)
+ description += "slightly ";
+ description += "repair permanent injuries. ";
+ break;
+ }
+
+ //default:
+ // DEBUGSTR("Unknown potion"); // I had no idea where to put this back 16jan2000 {dlb}
+ }
+
+ description += "$";
+
+ return (description);
+}
+
+
+//---------------------------------------------------------------
+//
+// describe_scroll
+//
+//---------------------------------------------------------------
+static std::string describe_scroll( const item_def &item )
+{
+ std::string description;
+
+ description.reserve(64);
+
+ if (get_ident_type( OBJ_SCROLLS, item.sub_type ) != ID_KNOWN_TYPE)
+ description += "A scroll of paper covered in magical writing.";
+ else
+ {
+ switch (item.sub_type)
+ {
+ case SCR_IDENTIFY:
+ description += "This useful magic scroll allows you to "
+ "determine the properties of any object. ";
+ break;
+
+ case SCR_TELEPORTATION:
+ description += "Reading the words on this scroll "
+ "translocates you to a random position. ";
+ break;
+
+ case SCR_FEAR:
+ description += "This scroll causes great fear in those "
+ "who see the one who reads it. ";
+ break;
+
+ case SCR_NOISE:
+ description += "This prank scroll, often slipped into a wizard's "
+ "backpack by a devious apprentice, causes a loud noise. "
+ "It is not otherwise noted for its usefulness. ";
+ break;
+
+ case SCR_REMOVE_CURSE:
+ description += "Reading this scroll removes curses from "
+ "the items you are using. ";
+ break;
+
+ case SCR_DETECT_CURSE:
+ description += "This scroll allows you to detect the presence "
+ "of cursed items among your possessions. ";
+ break;
+
+ case SCR_SUMMONING:
+ description += "This scroll opens a conduit to the Abyss "
+ "and draws a terrible beast to this world "
+ "for a limited time. ";
+ break;
+
+ case SCR_ENCHANT_WEAPON_I:
+ description += "This scroll places an enchantment on a weapon, "
+ "making it more accurate in combat. It may fail "
+ "to affect weapons already heavily enchanted. ";
+ break;
+
+ case SCR_ENCHANT_ARMOUR:
+ description += "This scroll places an enchantment "
+ "on a piece of armour. ";
+ break;
+
+ case SCR_TORMENT:
+ description += "This scroll calls on the powers of Hell to "
+ "inflict great pain on any nearby creature - "
+ "including you! ";
+ break;
+
+ case SCR_RANDOM_USELESSNESS:
+ description += "It is easy to be blinded to the essential "
+ "uselessness of this scroll by the sense of achievement "
+ "you get from getting it to work at all.";
+ // -- The Hitchhiker's Guide to the Galaxy (paraphrase)
+ break;
+
+ case SCR_CURSE_WEAPON:
+ description += "This scroll places a curse on a weapon. ";
+ break;
+
+ case SCR_CURSE_ARMOUR:
+ description += "This scroll places a curse "
+ "on a piece of armour. ";
+ break;
+
+ case SCR_IMMOLATION:
+ description += "Small writing on the back of the scroll reads: "
+ "\"Warning: contents under pressure. Do not use near"
+ " flammable objects.\"";
+ break;
+
+ case SCR_BLINKING:
+ description += "This scroll allows its reader to teleport "
+ "a short distance, with precise control. Be wary that "
+ "controlled teleports will cause the subject to "
+ "become contaminated with magical energy. ";
+ break;
+
+ case SCR_PAPER:
+ description += "Apart from a label, this scroll is blank. ";
+ break;
+
+ case SCR_MAGIC_MAPPING:
+ description += "This scroll reveals the nearby surroundings "
+ "of one who reads it. ";
+ break;
+
+ case SCR_FORGETFULNESS:
+ description += "This scroll induces "
+ "an irritating disorientation. ";
+ break;
+
+ case SCR_ACQUIREMENT:
+ description += "This wonderful scroll causes the "
+ "creation of a valuable item to "
+ "appear before the reader. "
+ "It is especially treasured by specialist "
+ "magicians, as they can use it to obtain "
+ "the powerful spells of their specialty. ";
+ break;
+
+ case SCR_ENCHANT_WEAPON_II:
+ description += "This scroll places an enchantment on a weapon, "
+ "making it inflict greater damage in combat. "
+ "It may fail to affect weapons already "
+ "heavily enchanted. ";
+ break;
+
+ case SCR_VORPALISE_WEAPON:
+ description += "This scroll enchants a weapon so as to make "
+ "it far more effective at inflicting harm on "
+ "its wielder's enemies. Using it on a weapon "
+ "already affected by some kind of special "
+ "enchantment (other than that produced by a "
+ "normal scroll of enchant weapon) is not advised. ";
+ break;
+
+ case SCR_RECHARGING:
+ description += "This scroll restores the charges of "
+ "any magical wand wielded by its reader. ";
+ break;
+
+ case SCR_ENCHANT_WEAPON_III:
+ description += "This scroll enchants a weapon to be "
+ "far more effective in combat. Although "
+ "it can be used in the creation of especially "
+ "enchanted weapons, it may fail to affect those "
+ "already heavily enchanted. ";
+ break;
+
+ default:
+ DEBUGSTR("Unknown scroll");
+ }
+ }
+
+ description += "$";
+
+ return (description);
+}
+
+
+//---------------------------------------------------------------
+//
+// describe_jewellery
+//
+//---------------------------------------------------------------
+static std::string describe_jewellery( const item_def &item, char verbose)
+{
+ std::string description;
+
+ description.reserve(200);
+
+ if (is_unrandom_artefact( item ) && strlen(unrandart_descrip(1, item)) != 0)
+ {
+ description += "$";
+ description += unrandart_descrip(1, item);
+ description += "$$";
+ }
+ else if ((!is_random_artefact( item )
+ && get_ident_type( OBJ_JEWELLERY, item.sub_type ) != ID_KNOWN_TYPE)
+ || (is_random_artefact( item )
+ && item_not_ident( item, ISFLAG_KNOW_TYPE )))
+ {
+ description += "A piece of jewellery.";
+ }
+ else if (verbose == 1 || is_random_artefact( item ))
+ {
+ switch (item.sub_type)
+ {
+ case RING_REGENERATION:
+ description += "This wonderful ring greatly increases the "
+ "recuperative powers of its wearer, but also "
+ "considerably speeds his or her metabolism. ";
+ break;
+
+ case RING_PROTECTION:
+ description +=
+ "This ring either protects its wearer from harm or makes "
+ "them more vulnerable to injury, to a degree dependent "
+ "on its power. ";
+ break;
+
+ case RING_PROTECTION_FROM_FIRE:
+ description +=
+ "This ring provides protection from heat and fire. ";
+ break;
+
+ case RING_POISON_RESISTANCE:
+ description +=
+ "This ring provides protection from the effects of poisons and venom. ";
+ break;
+
+ case RING_PROTECTION_FROM_COLD:
+ description += "This ring provides protection from cold. ";
+ break;
+
+ case RING_STRENGTH:
+ description +=
+ "This ring increases or decreases the physical strength "
+ "of its wearer, to a degree dependent on its power. ";
+ break;
+
+ case RING_SLAYING:
+ description +=
+ "This ring increases the hand-to-hand and missile combat "
+ "skills of its wearer.";
+ break;
+
+ case RING_SEE_INVISIBLE:
+ description +=
+ "This ring allows its wearer to see those things hidden "
+ "from view by magic. ";
+ break;
+
+ case RING_INVISIBILITY:
+ description +=
+ "This powerful ring can be activated to hide its wearer "
+ "from the view of others, but increases the speed of his "
+ "or her metabolism greatly while doing so. ";
+ break;
+
+ case RING_HUNGER:
+ description +=
+ "This accursed ring causes its wearer to hunger "
+ "considerably more quickly. ";
+ break;
+
+ case RING_TELEPORTATION:
+ description +=
+ "This ring occasionally exerts its power to randomly "
+ "translocate its wearer to another place, and can be "
+ "deliberately activated for the same effect. ";
+ break;
+
+ case RING_EVASION:
+ description +=
+ "This ring makes its wearer either more or less capable "
+ "of avoiding attacks, depending on its degree "
+ "of enchantment. ";
+ break;
+
+ case RING_SUSTAIN_ABILITIES:
+ description +=
+ "This ring protects its wearer from the loss of their "
+ "strength, dexterity and intelligence. ";
+ break;
+
+ case RING_SUSTENANCE:
+ description +=
+ "This ring provides energy to its wearer, so that they "
+ "need eat less often. ";
+ break;
+
+ case RING_DEXTERITY:
+ description +=
+ "This ring increases or decreases the dexterity of its "
+ "wearer, depending on the degree to which it has been "
+ "enchanted. ";
+ break;
+
+ case RING_INTELLIGENCE:
+ description +=
+ "This ring increases or decreases the mental ability of "
+ "its wearer, depending on the degree to which it has "
+ "been enchanted. ";
+ break;
+
+ case RING_WIZARDRY:
+ description +=
+ "This ring increases the ability of its wearer to use "
+ "magical spells. ";
+ break;
+
+ case RING_MAGICAL_POWER:
+ description +=
+ "This ring increases its wearer's reserves of magical "
+ "power. ";
+ break;
+
+ case RING_LEVITATION:
+ description +=
+ "This ring allows its wearer to hover above the floor. ";
+ break;
+
+ case RING_LIFE_PROTECTION:
+ description +=
+ "This blessed ring protects the life-force of its wearer "
+ "from negative energy, making them partially immune to "
+ "the draining effects of undead and necromantic magic. ";
+ break;
+
+ case RING_PROTECTION_FROM_MAGIC:
+ description +=
+ "This ring increases its wearer's resistance to "
+ "hostile enchantments. ";
+ break;
+
+ case RING_FIRE:
+ description +=
+ "This ring brings its wearer more in contact with "
+ "the powers of fire. He or she gains resistance to "
+ "heat and can use fire magic more effectively, but "
+ "becomes more vulnerable to the effects of cold. ";
+ break;
+
+ case RING_ICE:
+ description +=
+ "This ring brings its wearer more in contact with "
+ "the powers of cold and ice. He or she gains resistance "
+ "to cold and can use ice magic more effectively, but "
+ "becomes more vulnerable to the effects of fire. ";
+ break;
+
+ case RING_TELEPORT_CONTROL:
+ description += "This ring allows its wearer to control the "
+ "destination of any teleportation, although without "
+ "perfect accuracy. Trying to teleport into a solid "
+ "object will result in a random teleportation, at "
+ "least in the case of a normal teleportation. Also "
+ "be wary that controlled teleports will contaminate "
+ "the subject with residual magical energy.";
+ break;
+
+ case AMU_RAGE:
+ description +=
+ "This amulet enables its wearer to attempt to enter "
+ "a state of berserk rage, and increases their chance "
+ "of successfully doing so. It also partially protects "
+ "the user from passing out when coming out of that rage. ";
+ break;
+
+ case AMU_RESIST_SLOW:
+ description +=
+ "This amulet protects its wearer from some magically "
+ "induced forms of slowness, and increases the duration "
+ "of enchantments which speed his or her actions. ";
+ break;
+
+ case AMU_CLARITY:
+ description +=
+ "This amulet protects its wearer from some forms of "
+ "mental confusion. ";
+ break;
+
+ case AMU_WARDING:
+ description +=
+ "This amulet repels some of the attacks of creatures "
+ "which have been magically summoned. ";
+ break;
+
+ case AMU_RESIST_CORROSION:
+ description +=
+ "This amulet protects the armour and weaponry of its "
+ "wearer from corrosion caused by acids, although not "
+ "infallibly so. ";
+ break;
+
+ case AMU_THE_GOURMAND:
+ description +=
+ "This amulet allows its wearer to consume meat in "
+ "various states of decay without suffering unduly as "
+ "a result. Poisonous or cursed flesh is still not "
+ "recommended. ";
+ break;
+
+ case AMU_CONSERVATION:
+ description +=
+ "This amulet protects some of the possessions of "
+ "its wearer from outright destruction, but not "
+ "infallibly so. ";
+ break;
+
+ case AMU_CONTROLLED_FLIGHT:
+ description +=
+ "Should the wearer of this amulet be levitated "
+ "by magical means, he or she will be able to exercise "
+ "some control over the resulting motion. This allows "
+ "the descent of staircases and the retrieval of items "
+ "lying on the ground, for example, but does not "
+ "deprive the wearer of the benefits of levitation. ";
+ break;
+
+ case AMU_INACCURACY:
+ description +=
+ "This amulet makes its wearer less accurate in hand combat. ";
+ break;
+
+ case AMU_RESIST_MUTATION:
+ description +=
+ "This amulet protects its wearer from mutations, "
+ "although not infallibly so. ";
+ break;
+
+ default:
+ DEBUGSTR("Unknown jewellery");
+ }
+
+ description += "$";
+ }
+
+ if ((verbose == 1 || is_random_artefact( item ))
+ && item_ident( item, ISFLAG_KNOW_PLUSES ))
+ {
+ // Explicit description of ring power (useful for randarts)
+ // Note that for randarts we'll print out the pluses even
+ // in the case that its zero, just to avoid confusion. -- bwr
+ if (item.plus != 0
+ || (item.sub_type == RING_SLAYING && item.plus2 != 0)
+ || is_random_artefact( item ))
+ {
+ switch (item.sub_type)
+ {
+ case RING_PROTECTION:
+ description += "$It affects your AC (";
+ append_value( description, item.plus, true );
+ description += ").";
+ break;
+
+ case RING_EVASION:
+ description += "$It affects your evasion (";
+ append_value( description, item.plus, true );
+ description += ").";
+ break;
+
+ case RING_STRENGTH:
+ description += "$It affects your strength (";
+ append_value( description, item.plus, true );
+ description += ").";
+ break;
+
+ case RING_INTELLIGENCE:
+ description += "$It affects your intelligence (";
+ append_value( description, item.plus, true );
+ description += ").";
+ break;
+
+ case RING_DEXTERITY:
+ description += "$It affects your dexterity (";
+ append_value( description, item.plus, true );
+ description += ").";
+ break;
+
+ case RING_SLAYING:
+ if (item.plus != 0 || is_random_artefact( item ))
+ {
+ description += "$It affects your accuracy (";
+ append_value( description, item.plus, true );
+ description += ").";
+ }
+
+ if (item.plus2 != 0 || is_random_artefact( item ))
+ {
+ description += "$It affects your damage-dealing abilities (";
+ append_value( description, item.plus2, true );
+ description += ").";
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ // randart properties
+ if (is_random_artefact( item ))
+ {
+ if (item_ident( item, ISFLAG_KNOW_PROPERTIES ))
+ randart_descpr( description, item );
+ else if (item_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ if (item.sub_type >= AMU_RAGE)
+ description += "$This amulet may have hidden properties.$";
+ else
+ description += "$This ring may have hidden properties.$";
+ }
+ }
+
+ if (item_known_cursed( item ))
+ {
+ description += "$It has a curse placed upon it.";
+ }
+
+ return (description);
+} // end describe_jewellery()
+
+//---------------------------------------------------------------
+//
+// describe_staff
+//
+//---------------------------------------------------------------
+static std::string describe_staff( const item_def &item )
+{
+ std::string description;
+
+ description.reserve(200);
+
+ if (item_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ // NB: the leading space is here {dlb}
+ description += "This " + std::string( item_is_staff( item ) ? "staff "
+ : "rod " );
+
+ switch (item.sub_type)
+ {
+ case STAFF_WIZARDRY:
+ description +=
+ "increases the magical proficiency of its wielder by "
+ "a considerable degree, increasing the power of their spells. ";
+ break;
+
+ case STAFF_POWER:
+ description +=
+ "provides a reservoir of magical power to its wielder. ";
+ break;
+
+ case STAFF_FIRE:
+ description +=
+ "increases the power of fire spells cast by its wielder, "
+ "and protects him or her from the effects of heat and fire. "
+ "It can burn those struck by it. ";
+ break;
+
+ case STAFF_COLD:
+ description +=
+ "increases the power of ice spells cast by its wielder, "
+ "and protects him or her from the effects of cold. It can "
+ "freeze those struck by it. ";
+ break;
+
+ case STAFF_POISON:
+ description +=
+ "increases the power of poisoning spells cast by its "
+ "wielder, and protects him or her from the effects of "
+ "poison. It can poison those struck by it. ";
+ break;
+
+ case STAFF_ENERGY:
+ description +=
+ "allows its wielder to cast magical spells without "
+ "hungering as a result. ";
+ break;
+
+ case STAFF_DEATH:
+ description +=
+ "increases the power of necromantic spells cast by its "
+ "wielder. It can cause great pain in those living souls "
+ "its wielder strikes. ";
+ break;
+
+ case STAFF_CONJURATION:
+ description +=
+ "increases the power of conjurations cast by its wielder. ";
+ break;
+
+ case STAFF_ENCHANTMENT:
+ description +=
+ "increases the power of enchantments cast by its wielder. ";
+ break;
+
+ case STAFF_SUMMONING:
+ description +=
+ "increases the power of summonings cast by its wielder. ";
+ break;
+
+ case STAFF_SMITING:
+ description +=
+ "allows its wielder to smite foes from afar. The wielder "
+ "must be at least level four to safely use this ability, "
+ "which costs 4 magic points. ";
+ break;
+
+ case STAFF_STRIKING:
+ description += "allows its wielder to strike foes from afar. ";
+ break;
+
+ case STAFF_SPELL_SUMMONING:
+ description += "contains spells of summoning. ";
+ break;
+
+ case STAFF_WARDING:
+ description +=
+ "contains spells designed to repel one's enemies. ";
+ break;
+
+ case STAFF_DISCOVERY:
+ description +=
+ "contains spells which reveal various aspects of "
+ "an explorer's surroundings to them. ";
+ break;
+
+ case STAFF_AIR:
+ description +=
+ "increases the power of air spells cast by its wielder. "
+ "It can shock those struck by it. ";
+ break;
+
+ case STAFF_EARTH:
+ description +=
+ "increases the power of earth spells cast by its wielder. "
+ "It can crush those struck by it. ";
+ break;
+
+ case STAFF_CHANNELING:
+ description +=
+ "allows its caster to channel ambient magical energy for "
+ "his or her own purposes. ";
+ break;
+
+ default:
+ description +=
+ "contains spells of mayhem and destruction. ";
+ break;
+ }
+
+ if (item_is_rod( item ))
+ {
+ description +=
+ "Casting a spell from it consumes no food, and will not fail.$";
+ }
+ else
+ {
+ description +=
+ "$$Damage rating: 7 $Accuracy rating: +6 $Attack delay: 120%%";
+
+ description += "$$It falls into the 'staves' category. ";
+ }
+ }
+ else
+ {
+ description += "A stick imbued with magical properties.$";
+ }
+
+ return (description);
+}
+
+
+//---------------------------------------------------------------
+//
+// describe_misc_item
+//
+//---------------------------------------------------------------
+static std::string describe_misc_item( const item_def &item )
+{
+ std::string description;
+
+ description.reserve(100);
+
+ if (item_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ switch (item.sub_type)
+ {
+ case MISC_BOTTLED_EFREET:
+ description +=
+ "A mighty efreet, captured by some wizard and bound into "
+ "a bronze flask. Breaking the flask's seal will release it "
+ "to wreak havoc - possibly on you. ";
+ break;
+ case MISC_CRYSTAL_BALL_OF_SEEING:
+ description +=
+ "A magical device which allows one to see the layout of "
+ "their surroundings. It requires a degree of magical "
+ "ability to be used reliably, otherwise it can produce "
+ "unpredictable and possibly harmful results. ";
+ break;
+ case MISC_AIR_ELEMENTAL_FAN:
+ description += "A magical device for summoning air "
+ "elementals. It is rather unreliable, and usually requires "
+ "several attempts to function correctly. Using it carries "
+ "an element of risk, which is reduced if one is skilled in "
+ "the appropriate elemental magic. ";
+ break;
+ case MISC_LAMP_OF_FIRE:
+ description += "A magical device for summoning fire "
+ "elementals. It is rather unreliable, and usually "
+ "requires several attempts to function correctly. Using "
+ "it carries an element of risk, which is reduced if one "
+ "is skilled in the appropriate elemental magic.";
+ break;
+ case MISC_STONE_OF_EARTH_ELEMENTALS:
+ description += "A magical device for summoning earth "
+ "elementals. It is rather unreliable, and usually "
+ "requires several attempts to function correctly. "
+ "Using it carries an element of risk, which is reduced "
+ "if one is skilled in the appropriate elemental magic.";
+ break;
+ case MISC_LANTERN_OF_SHADOWS:
+ description +=
+ "An unholy device which calls on the powers of darkness "
+ "to assist its user, with a small cost attached. ";
+ break;
+ case MISC_HORN_OF_GERYON:
+ description +=
+ "The horn belonging to Geryon, guardian of the Vestibule "
+ "of Hell. Legends say that a mortal who desires access "
+ "into one of the Hells must use it in order to gain entry. ";
+ break;
+ case MISC_BOX_OF_BEASTS:
+ description +=
+ "A magical box containing many wild beasts. One may "
+ "allow them to escape by opening the box's lid. ";
+ break;
+ case MISC_DECK_OF_WONDERS:
+ description +=
+ "A deck of highly mysterious and magical cards. One may "
+ "draw a random card from it, but should be prepared to "
+ "suffer the possible consequences! ";
+ break;
+ case MISC_DECK_OF_SUMMONINGS:
+ description +=
+ "A deck of magical cards, depicting a range of weird and "
+ "wondrous creatures. ";
+ break;
+ case MISC_CRYSTAL_BALL_OF_ENERGY:
+ description +=
+ "A magical device which can be used to restore one's "
+ "reserves of magical energy, but the use of which carries "
+ "the risk of draining all of those energies completely. "
+ "This risk varies inversely with the proportion of their "
+ "maximum energy which the user possesses; a user near his "
+ "or her full potential will find this item most beneficial. ";
+ break;
+ case MISC_EMPTY_EBONY_CASKET:
+ description += "A magical box after its power is spent. ";
+ break;
+ case MISC_CRYSTAL_BALL_OF_FIXATION:
+ description +=
+ "A dangerous item which hypnotises anyone so unwise as "
+ "to gaze into it, leaving them helpless for a significant "
+ "length of time. ";
+ break;
+ case MISC_DISC_OF_STORMS:
+ description +=
+ "This extremely powerful item can unleash a destructive "
+ "storm of electricity. It is especially effective in the "
+ "hands of one skilled in air elemental magic, but cannot "
+ "be used by one who is not a conductor. ";
+ break;
+ case MISC_RUNE_OF_ZOT:
+ description +=
+ "A talisman which allows entry into Zot's domain. ";
+ break;
+ case MISC_DECK_OF_TRICKS:
+ description +=
+ "A deck of magical cards, full of amusing tricks. ";
+ break;
+ case MISC_DECK_OF_POWER:
+ description += "A deck of powerful magical cards. ";
+ break;
+ case MISC_PORTABLE_ALTAR_OF_NEMELEX:
+ description +=
+ "An altar to Nemelex Xobeh, built for easy assembly and "
+ "disassembly. Evoke it to place it on a clear patch of floor, "
+ "then pick it up again when you've finished. ";
+ break;
+ default:
+ DEBUGSTR("Unknown misc item (2)");
+ }
+ }
+ else
+ {
+ switch (item.sub_type)
+ {
+ case MISC_BOTTLED_EFREET:
+ description += "A heavy bronze flask, warm to the touch. ";
+ break;
+ case MISC_CRYSTAL_BALL_OF_ENERGY:
+ case MISC_CRYSTAL_BALL_OF_FIXATION:
+ case MISC_CRYSTAL_BALL_OF_SEEING:
+ description += "A sphere of clear crystal. ";
+ break;
+ case MISC_AIR_ELEMENTAL_FAN:
+ description += "A fan. ";
+ break;
+ case MISC_LAMP_OF_FIRE:
+ description += "A lamp. ";
+ break;
+ case MISC_STONE_OF_EARTH_ELEMENTALS:
+ description += "A lump of rock. ";
+ break;
+ case MISC_LANTERN_OF_SHADOWS:
+ description += "A strange lantern made out of ancient bones. ";
+ break;
+ case MISC_HORN_OF_GERYON:
+ description += "A great silver horn, radiating unholy energies. ";
+ break;
+ case MISC_BOX_OF_BEASTS:
+ case MISC_EMPTY_EBONY_CASKET:
+ description += "A small black box. I wonder what's inside? ";
+ break;
+ case MISC_DECK_OF_WONDERS:
+ case MISC_DECK_OF_TRICKS:
+ case MISC_DECK_OF_POWER:
+ case MISC_DECK_OF_SUMMONINGS:
+ description += "A deck of cards. ";
+ break;
+ case MISC_RUNE_OF_ZOT:
+ description += "A talisman of some sort. ";
+ break;
+ case MISC_DISC_OF_STORMS:
+ description += "A grey disc. ";
+ break;
+ case MISC_PORTABLE_ALTAR_OF_NEMELEX:
+ description +=
+ "An altar to Nemelex Xobeh, built for easy assembly and "
+ "disassembly. Evoke it to place on a clear patch of floor, "
+ "then pick it up again when you've finished. ";
+ break;
+ default:
+ DEBUGSTR("Unknown misc item");
+ }
+ }
+
+ description += "$";
+
+ return (description);
+}
+
+#if MAC
+#pragma mark -
+#endif
+
+// ========================================================================
+// Public Functions
+// ========================================================================
+
+bool is_dumpable_artifact( const item_def &item, char verbose)
+{
+ bool ret = false;
+
+ if (is_random_artefact( item ) || is_fixed_artefact( item ))
+ {
+ ret = item_ident( item, ISFLAG_KNOW_PROPERTIES );
+ }
+ else if (item.base_type == OBJ_ARMOUR
+ && (verbose == 1 && item_ident( item, ISFLAG_KNOW_TYPE )))
+ {
+ const int spec_ench = get_armour_ego_type( item );
+ ret = (spec_ench >= SPARM_RUNNING && spec_ench <= SPARM_PRESERVATION);
+ }
+ else if (item.base_type == OBJ_JEWELLERY
+ && (verbose == 1
+ && get_ident_type(OBJ_JEWELLERY, item.sub_type) == ID_KNOWN_TYPE))
+ {
+ ret = true;
+ }
+
+ return (ret);
+} // end is_dumpable_artifact()
+
+
+//---------------------------------------------------------------
+//
+// get_item_description
+//
+// Note that the string will include dollar signs which should
+// be interpreted as carriage returns.
+//
+//---------------------------------------------------------------
+std::string get_item_description( const item_def &item, char verbose, bool dump )
+{
+ std::string description;
+ description.reserve(500);
+
+ if (!dump)
+ {
+ char str_pass[ ITEMNAME_SIZE ];
+ item_name( item, DESC_INVENTORY_EQUIP, str_pass );
+ description += std::string(str_pass);
+ }
+
+ description += "$$";
+
+#if DEBUG_DIAGNOSTICS
+ if (!dump)
+ {
+ snprintf( info, INFO_SIZE,
+ "base: %d; sub: %d; plus: %d; plus2: %d; special: %ld$"
+ "quant: %d; colour: %d; flags: 0x%08lx$"
+ "x: %d; y: %d; link: %d$ident_type: %d$$",
+ item.base_type, item.sub_type, item.plus, item.plus2,
+ item.special, item.quantity, item.colour, item.flags,
+ item.x, item.y, item.link,
+ get_ident_type( item.base_type, item.sub_type ) );
+
+ description += info;
+ }
+#endif
+
+ switch (item.base_type)
+ {
+ case OBJ_WEAPONS:
+ description += describe_weapon( item, verbose );
+ break;
+ case OBJ_MISSILES:
+ description += describe_ammo( item );
+ break;
+ case OBJ_ARMOUR:
+ description += describe_armour( item, verbose );
+ break;
+ case OBJ_WANDS:
+ description += describe_stick( item );
+ break;
+ case OBJ_FOOD:
+ description += describe_food( item );
+ break;
+ case OBJ_SCROLLS:
+ description += describe_scroll( item );
+ break;
+ case OBJ_JEWELLERY:
+ description += describe_jewellery( item, verbose );
+ break;
+ case OBJ_POTIONS:
+ description += describe_potion( item );
+ break;
+ case OBJ_STAVES:
+ description += describe_staff( item );
+ break;
+
+ case OBJ_BOOKS:
+ switch (item.sub_type)
+ {
+ case BOOK_DESTRUCTION:
+ description += "An extremely powerful but unpredictable book "
+ "of magic. ";
+ break;
+
+ case BOOK_MANUAL:
+ description += "A valuable book of magic which allows one to "
+ "practise a certain skill greatly. As it is used, it gradually "
+ "disintegrates and will eventually fall apart. ";
+ break;
+
+ default:
+ description += "A book of magic spells. Beware, for some of the "
+ "more powerful grimoires are not to be toyed with. ";
+ break;
+ }
+ break;
+
+ case OBJ_ORBS:
+ description += "Once you have escaped to the surface with "
+ "this invaluable artefact, your quest is complete. ";
+ break;
+
+ case OBJ_MISCELLANY:
+ description += describe_misc_item( item );
+ break;
+
+ case OBJ_CORPSES:
+ description +=
+ ((item.sub_type == CORPSE_BODY) ? "A corpse. "
+ : "A decaying skeleton. ");
+ break;
+
+ default:
+ DEBUGSTR("Bad item class");
+ description += "This item should not exist. Mayday! Mayday! ";
+ }
+
+ if (verbose == 1)
+ {
+ description += "$It weighs around ";
+
+ const int mass = mass_item( item );
+
+ char item_mass[16];
+ itoa( mass / 10, item_mass, 10 );
+
+ for (int i = 0; i < 14; i++)
+ {
+ if (item_mass[i] == '\0')
+ {
+ item_mass[i] = '.';
+ item_mass[i+1] = (mass % 10) + '0';
+ item_mass[i+2] = '\0';
+ break;
+ }
+ }
+
+ description += item_mass;
+ description += " aum. "; // arbitrary unit of mass
+ }
+
+ return (description);
+} // end get_item_description()
+
+
+//---------------------------------------------------------------
+//
+// describe_item
+//
+// Describes all items in the game.
+//
+//---------------------------------------------------------------
+void describe_item( const item_def &item )
+{
+#ifdef DOS_TERM
+ char buffer[3400];
+
+ gettext(25, 1, 80, 25, buffer);
+
+ window(25, 1, 80, 25);
+#endif
+
+ clrscr();
+
+ std::string description = get_item_description( item, 1 );
+
+ print_description(description);
+
+ if (getch() == 0)
+ getch();
+
+#ifdef DOS_TERM
+ puttext(25, 1, 80, 25, buffer);
+ window(1, 1, 80, 25);
+#endif
+} // end describe_item()
+
+
+//---------------------------------------------------------------
+//
+// describe_spell
+//
+// Describes (most) every spell in the game.
+//
+//---------------------------------------------------------------
+void describe_spell(int spelled)
+{
+ std::string description;
+
+ description.reserve(500);
+
+#ifdef DOS_TERM
+ char buffer[3400];
+
+ gettext(25, 1, 80, 25, buffer);
+ window(25, 1, 80, 25);
+#endif
+
+ clrscr();
+ description += spell_title( spelled );
+ description += "$$This spell "; // NB: the leading space is here {dlb}
+
+ switch (spelled)
+ {
+ case SPELL_IDENTIFY:
+ description += "allows the caster to determine the properties of "
+ "an otherwise inscrutable magic item. ";
+ break;
+
+ case SPELL_TELEPORT_SELF:
+ description += "teleports the caster to a random location. ";
+ break;
+
+ case SPELL_CAUSE_FEAR:
+ description += "causes fear in those near to the caster. ";
+ break;
+
+ case SPELL_CREATE_NOISE:
+ description += "causes a loud noise to be heard. ";
+ break;
+
+ case SPELL_REMOVE_CURSE:
+ description += "removes curses from any items which are "
+ "being used by the caster. ";
+ break;
+
+ case SPELL_MAGIC_DART:
+ description += "hurls a small bolt of magical energy. ";
+ break;
+
+ case SPELL_FIREBALL:
+ description += "hurls an exploding bolt of fire. This spell "
+ "does not cost additional spell levels if the learner already "
+ "knows Delayed Fireball. ";
+ break;
+
+ case SPELL_DELAYED_FIREBALL:
+ description = "$$Successfully casting this spell gives the caster "
+ "the ability to instantaneously release a fireball at a later "
+ "time. Knowing this spell allows the learner to memorise "
+ "Fireball for no additional spell levels. ";
+ break;
+
+ case SPELL_BOLT_OF_MAGMA:
+ description += "hurls a sizzling bolt of molten rock. ";
+ break;
+
+// spells 7 through 12 ??? {dlb}
+
+ case SPELL_CONJURE_FLAME:
+ description += "creates a column of roaring flame. ";
+ break;
+
+ case SPELL_DIG:
+ description += "digs a tunnel through unworked rock. ";
+ break;
+
+ case SPELL_BOLT_OF_FIRE:
+ description += "hurls a great bolt of flames. ";
+ break;
+
+ case SPELL_BOLT_OF_COLD:
+ description += "hurls a great bolt of ice and frost. ";
+ break;
+
+ case SPELL_LIGHTNING_BOLT:
+ description += "hurls a mighty bolt of lightning. "
+ "Although this spell inflicts less damage than "
+ "similar fire and ice spells, it can at once "
+ "rip through whole rows of creatures. ";
+ break;
+
+// spells 18 and 19 ??? {dlb}
+
+ case SPELL_POLYMORPH_OTHER:
+ description += "randomly alters the form of another creature. ";
+ break;
+
+ case SPELL_SLOW:
+ description += "slows the actions of a creature. ";
+ break;
+
+ case SPELL_HASTE:
+ description += "speeds the actions of a creature. ";
+ break;
+
+ case SPELL_PARALYZE:
+ description += "prevents a creature from moving. ";
+ break;
+
+ case SPELL_CONFUSING_TOUCH:
+ description += "enchants the casters hands with magical energy. "
+ "This energy is released when the caster touches "
+ "a monster with their bare hands, and may induce "
+ "a state of confusing in the monster. ";
+ break;
+
+ case SPELL_CONFUSE:
+ description += "induces a state of bewilderment and confusion "
+ "in a creature's mind. ";
+ break;
+
+ case SPELL_SURE_BLADE:
+ description += "forms a mystical bond between the caster and "
+ "a wielded short blade, making the blade much " "easier to use. ";
+ break;
+
+ case SPELL_INVISIBILITY:
+ description += "hides a creature from the sight of others. ";
+ break;
+
+ case SPELL_THROW_FLAME:
+ description += "throws a small bolt of flame. ";
+ break;
+
+ case SPELL_THROW_FROST:
+ description += "throws a small bolt of frost. ";
+ break;
+
+ case SPELL_CONTROLLED_BLINK:
+ description +=
+ "allows short-range translocation, with precise control. "
+ "Be wary that controlled teleports will cause the subject to "
+ "become contaminated with magical energy. ";
+ break;
+
+ case SPELL_FREEZING_CLOUD:
+ description += "conjures up a large cloud of lethally cold vapour. ";
+ break;
+
+ case SPELL_MEPHITIC_CLOUD:
+ description +=
+ "conjures up a large but short-lived cloud of vile fumes. ";
+ break;
+
+ case SPELL_RING_OF_FLAMES:
+ description += "surrounds the caster with a mobile ring of searing "
+ "flame, and keeps other fire clouds away from the caster. "
+ "This spell attunes the caster to the forces of fire, "
+ "increasing their fire magic and giving protection from fire. "
+ "However, it also makes them much more susceptible to the forces "
+ "of ice. "; // well, if it survives the fire wall it's a risk -- bwr
+ break;
+
+ case SPELL_RESTORE_STRENGTH:
+ description += "restores the physical strength of the caster. ";
+ break;
+
+ case SPELL_RESTORE_INTELLIGENCE:
+ description += "restores the intelligence of the caster. ";
+ break;
+
+ case SPELL_RESTORE_DEXTERITY:
+ description += "restores the dexterity of the caster. ";
+ break;
+
+ case SPELL_VENOM_BOLT:
+ description += "throws a bolt of poison. ";
+ break;
+
+ case SPELL_POISON_ARROW:
+ description +=
+ "hurls a magical arrow of the most vile and noxious toxin. "
+ "No living thing is completely immune to it's effects. ";
+ break;
+
+ case SPELL_OLGREBS_TOXIC_RADIANCE:
+ description +=
+ "bathes the caster's surroundings in poisonous green light. ";
+ break;
+
+ case SPELL_TELEPORT_OTHER:
+ description += "randomly translocates another creature. ";
+ break;
+
+ case SPELL_LESSER_HEALING:
+ description +=
+ "heals a small amount of damage to the caster's body. ";
+ break;
+
+ case SPELL_GREATER_HEALING:
+ description +=
+ "heals a large amount of damage to the caster's body. ";
+ break;
+
+ case SPELL_CURE_POISON_I:
+ description += "removes poison from the caster's system. ";
+ break;
+
+ case SPELL_PURIFICATION:
+ description += "purifies the caster's body, removing "
+ "poison, disease, and certain malign enchantments. ";
+ break;
+
+ case SPELL_DEATHS_DOOR:
+ description += "is extremely powerful, but carries a degree of risk. "
+ "It renders living casters nigh invulnerable to harm "
+ "for a brief period, but can bring them dangerously "
+ "close to death (how close depends on one's necromantic "
+ "abilities). The spell can be cancelled at any time by "
+ "any healing effect, and the caster will receive one "
+ "warning shortly before the spell expires. "
+ "Undead cannot use this spell. ";
+ break;
+
+ case SPELL_SELECTIVE_AMNESIA:
+ description += "allows the caster to selectively erase one spell "
+ "from memory to recapture the magical energy bound "
+ "up with it. Casters will be able to memorise this "
+ "spell should even their minds be otherwise full of "
+ "magic (i.e., already possessing the maximum number "
+ "of spells). ";
+ break;
+
+ case SPELL_MASS_CONFUSION:
+ description += "causes confusion in all who gaze upon the caster. ";
+ break;
+
+ case SPELL_STRIKING:
+ description += "hurls a small bolt of force. ";
+ break;
+
+ case SPELL_SMITING:
+ description += "smites one creature of the caster's choice. ";
+ break;
+
+ case SPELL_REPEL_UNDEAD:
+ description += "calls on a divine power to repel the unholy. ";
+ break;
+
+ case SPELL_HOLY_WORD:
+ description += "involves the intonation of a word of power "
+ "which repels and can destroy unholy creatures. ";
+ break;
+
+ case SPELL_DETECT_CURSE:
+ description += "alerts the caster to the presence of curses "
+ "on his or her possessions. ";
+ break;
+
+ case SPELL_SUMMON_SMALL_MAMMAL:
+ description += "summons one or more "
+ "small creatures to the caster's aid. ";
+ break;
+
+ case SPELL_ABJURATION_I:
+ description += "attempts to send hostile summoned creatures to "
+ "the place from whence they came, or at least "
+ "shorten their stay in the caster's locality. ";
+ break;
+
+ case SPELL_SUMMON_SCORPIONS:
+ description += "summons one or more "
+ "giant scorpions to the caster's assistance. ";
+ break;
+
+ case SPELL_LEVITATION:
+ description += "allows the caster to float in the air. ";
+ break;
+
+ case SPELL_BOLT_OF_DRAINING:
+ description += "hurls a deadly bolt of negative energy, "
+ "which drains the life from any living creature " "it strikes. ";
+ break;
+
+ case SPELL_LEHUDIBS_CRYSTAL_SPEAR:
+ description += "hurls a lethally sharp bolt of crystal. ";
+ break;
+
+ case SPELL_BOLT_OF_INACCURACY:
+ description += "inflicts enormous damage upon any creature struck "
+ "by the bolt of incandescent energy conjured into "
+ "existence. Unfortunately, it is very difficult to "
+ "aim and very rarely hits anything. Pity, that. ";
+ break;
+
+ case SPELL_POISONOUS_CLOUD:
+ description += "conjures forth a great cloud of lethal gasses. ";
+ break;
+
+ case SPELL_FIRE_STORM:
+ description += "creates a mighty storm of roaring flame. ";
+ break;
+
+ case SPELL_DETECT_TRAPS:
+ description += "reveals traps in the caster's vicinity. ";
+ break;
+
+ case SPELL_BLINK:
+ description += "randomly translocates the caster a short distance. ";
+ break;
+
+ case SPELL_ISKENDERUNS_MYSTIC_BLAST:
+ description += "throws a crackling sphere of destructive energy. ";
+ break;
+
+ case SPELL_SWARM:
+ description += "summons forth a pestilential swarm. ";
+ break;
+
+ case SPELL_SUMMON_HORRIBLE_THINGS:
+ description += "opens a gate to the Abyss and calls through "
+ "one or more hideous abominations from that dreadful place."
+ " The powers who answer this invocation require of casters "
+ "a portion of their intellect in exchange for this service.";
+ break;
+
+ case SPELL_ENSLAVEMENT:
+ description += "causes an otherwise hostile creature "
+ "to fight on your side for a while. ";
+ break;
+
+ case SPELL_MAGIC_MAPPING:
+ description += "reveals details about the caster's surroundings. ";
+ break;
+
+ case SPELL_HEAL_OTHER:
+ description += "heals another creature from a distance. ";
+ break;
+
+ case SPELL_ANIMATE_DEAD:
+ description += "causes the dead to rise up and serve the caster; "
+ "every corpse within a certain distance of the caster "
+ "is affected. By means of this spell, powerful casters "
+ "could press into service an army of the mindless undead. ";
+ break;
+
+ case SPELL_PAIN:
+ description += "inflicts an extremely painful injury "
+ "upon one living creature. ";
+ break;
+
+ case SPELL_EXTENSION:
+ description +=
+ "extends the duration of most beneficial enchantments "
+ "affecting the caster. ";
+ break;
+
+ case SPELL_CONTROL_UNDEAD:
+ description +=
+ "attempts to enslave any undead in the vicinity of the caster. ";
+ break;
+
+ case SPELL_ANIMATE_SKELETON:
+ description += "raises an inert skeleton to a state of unlife. ";
+ break;
+
+ case SPELL_VAMPIRIC_DRAINING:
+ description += "steals the life of a living creature and grants it "
+ "to the caster. Life will not be drained in excess of "
+ "what the caster can capably absorb. ";
+ break;
+
+ case SPELL_SUMMON_WRAITHS:
+ description +=
+ "calls on the powers of the undead to aid the caster. ";
+ break;
+
+ case SPELL_DETECT_ITEMS:
+ description +=
+ "detects any items lying about the caster's general vicinity. ";
+ break;
+
+ case SPELL_BORGNJORS_REVIVIFICATION:
+ description += "instantly heals any and all wounds suffered by the "
+ "caster with an attendant, but also permanently lessens his or her "
+ "resilience to injury -- the severity of which is dependent on "
+ "(and inverse to) magical skill. ";
+ break;
+
+ case SPELL_BURN:
+ description += "burns a creature. ";
+ break;
+
+ case SPELL_FREEZE:
+ description += "freezes a creature. This may temporarily slow the "
+ "metabolism of a cold-blooded creature. ";
+ break;
+
+ case SPELL_SUMMON_ELEMENTAL:
+ description += "calls forth "
+ "a spirit from the elemental planes to aid the caster. "
+ "A large quantity of the desired element must be "
+ "available; this is rarely a problem for earth and air, "
+ "but may be for fire or water. The elemental will usually "
+ "be friendly to casters -- especially those skilled in "
+ "the appropriate form of elemental magic.";
+ break;
+
+ case SPELL_OZOCUBUS_REFRIGERATION:
+ description += "drains the heat from the caster and her "
+ "surroundings, causing harm to all creatures not resistant to "
+ "cold. ";
+ break;
+
+ case SPELL_STICKY_FLAME:
+ description += "conjures a sticky glob of liquid fire, which will "
+ "adhere to and burn any creature it strikes. ";
+ break;
+
+ case SPELL_SUMMON_ICE_BEAST:
+ description += "calls forth " "a beast of ice to serve the caster. ";
+ break;
+
+ case SPELL_OZOCUBUS_ARMOUR:
+ description += "encases the caster's body in a protective layer "
+ "of ice, the power of which depends on his or her "
+ "skill with Ice magic. The caster and the caster's "
+ "equipment are protected from the cold, but the "
+ "spell will not function for casters already wearing "
+ "heavy armour. The effects of this spell are boosted "
+ "if the caster is in Ice Form. ";
+ break;
+
+ case SPELL_CALL_IMP:
+ description += "calls forth " "a minor demon from the pits of Hell. ";
+ break;
+
+ case SPELL_REPEL_MISSILES:
+ description += "reduces the chance of projectile attacks striking "
+ "the caster. Even powerful attacks such as "
+ "lightning bolts or dragon breath are affected, "
+ "although smaller missiles are repelled to a "
+ "much greater extent. ";
+ break;
+
+ case SPELL_BERSERKER_RAGE:
+ description += "sends the caster into a temporary psychotic rage. ";
+ break;
+
+ case SPELL_DISPEL_UNDEAD:
+ description +=
+ "inflicts a great deal of damage on an undead creature. ";
+ break;
+
+ // spell 86 - Guardian
+ // spell 87 - Pestilence
+ // spell 99 - Thunderbolt
+ // spell 100 - Flame of Cleansing
+ // spell 101 - Shining Light
+ // spell 102 - Summon Daeva
+ // spell 103 - Abjuration II
+
+ case SPELL_TWISTED_RESURRECTION:
+ description += "allows its caster to imbue a mass of deceased flesh "
+ "with a magical life force. Casting this spell involves "
+ "the assembling several corpses together; the greater "
+ "the combined mass of flesh available, the greater the "
+ "chances of success. ";
+ break;
+
+ case SPELL_REGENERATION:
+ description += "dramatically but temporarily increases the caster's "
+ "recuperative abilities, while also increasing the rate "
+ "of food consumption. ";
+ break;
+
+ case SPELL_BONE_SHARDS:
+ description += "uses the bones of a skeleton (or similar materials: "
+ "the rigid exoskeleton of an insect, for example) to "
+ "dispense a lethal spray of slicing fragments, allowing "
+ "its caster to dispense with conjurations in favour of "
+ "necromancy alone to provide a low-level yet very "
+ "powerful offensive spell. The use of a large and "
+ "heavy skeleton (by wielding it) amplifies this spell's "
+ "effect. ";
+ break;
+
+ case SPELL_BANISHMENT:
+ description += "banishes one creature to the Abyss. Those wishing "
+ "to visit that unpleasant place in person may always "
+ "banish themselves. ";
+ break;
+
+ case SPELL_CIGOTUVIS_DEGENERATION:
+ description +=
+ "mutates one creature into a pulsating mass of flesh. ";
+ break;
+
+ case SPELL_STING:
+ description += "throws a magical dart of poison. ";
+ break;
+
+ case SPELL_SUBLIMATION_OF_BLOOD:
+ description += "converts flesh, blood, and other bodily fluids "
+ "into magical energy. Casters may focus this spell "
+ "on their own bodies (which can be dangerous but "
+ "never directly lethal) or can wield freshly butchered "
+ "flesh in order to draw power into themselves. ";
+ break;
+
+ case SPELL_TUKIMAS_DANCE:
+ description += "causes a weapon held in the caster's hand to dance "
+ "into the air and strike the caster's enemies. It will "
+ "not function on magical staves and certain "
+ "willful artefacts. ";
+ break;
+
+ case SPELL_HELLFIRE: // basically, a debug message {dlb}
+ description += "should only be available from Dispater's staff. "
+ "So how are you reading this? (describe.cc)";
+ break;
+
+ case SPELL_SUMMON_DEMON:
+ description += "opens a gate to the realm of Pandemonium "
+ "and draws forth one of its inhabitants "
+ "to serve the caster for a time. ";
+ break;
+
+ case SPELL_DEMONIC_HORDE:
+ description += "calls forth "
+ "a small swarm of small demons "
+ "to do battle with the caster's foes. ";
+ break;
+
+ case SPELL_SUMMON_GREATER_DEMON:
+ description += "calls forth one of the greater demons of Pandemonium "
+ "to serve the caster. Beware, for the spell binding it "
+ "to service may not outlast "
+ "that which binds it to this world! ";
+ break;
+
+ case SPELL_CORPSE_ROT:
+ description += "rapidly accelerates the decomposition of any "
+ "corpses lying around the caster, emitting in"
+ "process a foul miasmic vapour, which eats away "
+ "at the life force of any creature it envelops. ";
+ break;
+
+ case SPELL_TUKIMAS_VORPAL_BLADE:
+ description += "bestows a lethal but temporary sharpness "
+ "on a sword held by the caster. It will not affect "
+ "weapons otherwise subject to special enchantments. ";
+ break;
+
+ case SPELL_FIRE_BRAND:
+ description += "sets a weapon held by the caster ablaze. It will not "
+ "affect weapons otherwise subject to special enchantments. ";
+ break;
+
+ case SPELL_FREEZING_AURA:
+ description +=
+ "surrounds a weapon held by the caster with an aura of "
+ "freezing cold. It will not affect weapons which are "
+ "otherwise subject to special enchantments. ";
+ break;
+
+ case SPELL_LETHAL_INFUSION:
+ description += "infuses a weapon held by the caster with unholy "
+ "energies. It will not affect weapons which are "
+ "otherwise subject to special enchantments. ";
+ break;
+
+ case SPELL_CRUSH: // a theory of gravity in Crawl? {dlb}
+ description += "crushes a nearby creature with waves of "
+ "gravitational force. ";
+ break;
+
+ case SPELL_BOLT_OF_IRON:
+ description += "hurls "
+ "a large and heavy metal bolt " "at the caster's foes. ";
+ break;
+
+ case SPELL_STONE_ARROW:
+ description += "hurls "
+ "a sharp spine of rock outward from the caster. ";
+ break;
+
+ case SPELL_TOMB_OF_DOROKLOHE:
+ description += "entombs the caster within four walls of rock. These "
+ "walls will destroy most objects in their way, but "
+ "their growth is obstructed by the presence of any "
+ "creature. Beware - only the unwise cast this spell "
+ "without reliable means of escape. ";
+ break;
+
+ case SPELL_STONEMAIL:
+ description += "covers the caster with chunky scales of stone, "
+ "the durability of which depends on his or her "
+ "skill with Earth magic. These scales can coexist "
+ "with other forms of armour, but are in and of "
+ "themselves extremely heavy and cumbersome. The effects "
+ "of this spell are increased if the caster is in Statue Form. ";
+ break;
+
+ case SPELL_SHOCK:
+ description += "throws a bolt of electricity. ";
+ break;
+
+ case SPELL_SWIFTNESS:
+ description += "imbues its caster with the ability to achieve "
+ "great movement speeds. Flying spellcasters can move even "
+ "faster.";
+ break;
+
+ case SPELL_FLY:
+ description +=
+ "grants to the caster the ability to fly through the air. ";
+ break;
+
+ case SPELL_INSULATION:
+ description += "protects the caster from electric shocks. ";
+ break;
+
+ case SPELL_ORB_OF_ELECTROCUTION:
+ description += "hurls "
+ "a crackling orb of electrical energy "
+ "which explodes with immense force on impact. ";
+ break;
+
+ case SPELL_DETECT_CREATURES:
+ description += "allows the caster to detect any creatures "
+ "within a certain radius. ";
+ break;
+
+ case SPELL_CURE_POISON_II:
+ description +=
+ "removes some or all toxins from the caster's system. ";
+ break;
+
+ case SPELL_CONTROL_TELEPORT:
+ description += "allows the caster to control translocations. Be "
+ "wary that controlled teleports will cause the subject to "
+ "become contaminated with magical energy. ";
+ break;
+
+ case SPELL_POISON_AMMUNITION:
+ description += "envenoms missile ammunition held by the caster. ";
+ break;
+
+ case SPELL_POISON_WEAPON:
+ description +=
+ "temporarily coats any sharp bladed weapon with poison. Will only "
+ "work on weapons without an existing enchantment.";
+ break;
+
+ case SPELL_RESIST_POISON:
+ description += "protects the caster from exposure to all poisons "
+ "for a period of time. ";
+ break;
+
+ case SPELL_PROJECTED_NOISE:
+ description += "produces a noise emanating "
+ "from a place of the caster's own choosing. ";
+ break;
+
+ case SPELL_ALTER_SELF:
+ description += "causes aberrations to form in the caster's body, "
+ "leaving the caster in a weakened state "
+ "(though it is not fatal in and of itself). "
+ "It may fail to affect those who are already "
+ "heavily mutated. ";
+ break;
+
+// spell 145 - debugging ray
+
+ case SPELL_RECALL:
+ description += "is greatly prized by summoners and necromancers, "
+ "as it allows the caster to recall any friendly "
+ "creatures nearby to a position adjacent to the caster. ";
+ break;
+
+ case SPELL_PORTAL:
+ description += "creates a gate allowing long-distance travel "
+ "in relatively ordinary environments "
+ "(i.e., the Dungeon only). The portal lasts "
+ "long enough for the caster and nearby creatures "
+ "to enter. Casters are never taken past the level "
+ "limits of the current area. ";
+ break;
+
+ case SPELL_AGONY:
+ description += "cuts the resilience of a target creature in half, "
+ "although it will never cause death directly. ";
+ break;
+
+ case SPELL_SPIDER_FORM:
+ description += "temporarily transforms the caster into a venomous, "
+ "spider-like creature. Spellcasting is slightly more difficult "
+ "in this form. This spell is not powerful enough to allow "
+ "the caster to slip out of cursed equipment. ";
+ break;
+
+ case SPELL_DISRUPT:
+ description += "disrupts space around another creature, "
+ "causing injury.";
+ break;
+
+ case SPELL_DISINTEGRATE:
+ description += "violently rends apart anything in a small volume of "
+ "space. Can be used to cause severe damage.";
+ break;
+
+ case SPELL_BLADE_HANDS:
+ description += "causes long, scythe-shaped blades to grow "
+ "from the caster's hands. It makes spellcasting somewhat "
+ "difficult. This spell is not powerful enough to force "
+ "a cursed weapon from the caster's hands.";
+ break;
+
+ case SPELL_STATUE_FORM:
+ description += "temporarily transforms the caster into a "
+ "slow-moving (but extremely robust) stone statue. ";
+ break;
+
+ case SPELL_ICE_FORM:
+ description += "temporarily transforms the caster's body into a "
+ "frozen ice-creature. ";
+ break;
+
+ case SPELL_DRAGON_FORM:
+ description += "temporarily transforms the caster into a "
+ "great, fire-breathing dragon. ";
+ break;
+
+ case SPELL_NECROMUTATION:
+ description += "first transforms the caster into a "
+ "semi-corporeal apparition receptive to negative energy, "
+ "then infuses that form with the powers of Death. "
+ "The caster becomes resistant to "
+ "cold, poison, magic and hostile negative energies. ";
+ break;
+
+ case SPELL_DEATH_CHANNEL:
+ description += "raises living creatures slain by the caster "
+ "into a state of unliving slavery as spectral horrors. ";
+ break;
+
+ case SPELL_SYMBOL_OF_TORMENT:
+ description += "calls on the powers of Hell to cause agonising "
+ "injury to any living thing in the caster's vicinity. "
+ "It carries within itself a degree of danger, "
+ "for any brave enough to invoke it, for the Symbol "
+ "also affects its caller and indeed will not function "
+ "if he or she is immune to its terrible effects. "
+ "Despite its ominous power, this spell is never lethal. ";
+ break;
+
+ case SPELL_DEFLECT_MISSILES:
+ description += "protects the caster from "
+ "any kind of projectile attack, "
+ "although particularly powerful attacks "
+ "(lightning bolts, etc.) are deflected "
+ "to a lesser extent than lighter missiles. ";
+ break;
+
+ case SPELL_ORB_OF_FRAGMENTATION:
+ description += "throws a heavy sphere of metal "
+ "which explodes on impact into a rain of "
+ "deadly, jagged fragments. "
+ "It can rip a creature to shreds, "
+ "but proves ineffective against heavily-armoured targets. ";
+ break;
+
+ case SPELL_ICE_BOLT:
+ description += "throws forth a chunk of ice. "
+ "It is particularly effective against "
+ "those creatures not immune to the effects of freezing, "
+ "but the half of its destructive potential that comes from "
+ "its weight and cutting edges "
+ "cannot be ignored by even cold-resistant creatures. ";
+ break;
+
+ case SPELL_ICE_STORM:
+ description += "conjures forth "
+ "a raging blizzard of ice, sleet and freezing gasses. ";
+ break;
+
+ case SPELL_ARC:
+ description += "zaps at random a nearby creature with a powerful "
+ "electrical current.";
+ break;
+
+ case SPELL_AIRSTRIKE: // jet planes in Crawl ??? {dlb}
+ description +=
+ "causes the air around a creature to twist itself into "
+ "a whirling vortex of meteorological fury. ";
+ break;
+
+ case SPELL_SHADOW_CREATURES:
+ description += "weaves a creature from shadows and threads of "
+ "Abyssal matter. The creature thus brought into "
+ "existence will recreate some type of creature "
+ "found in the caster's immediate vicinity. "
+ "The spell even creates appropriate equipment for "
+ "the creature, which are given a lasting substance "
+ //jmf: if also conjuration:
+ //"by the spell's conjuration component. ";
+ //jmf: else:
+ "by their firm contact with reality. ";
+ break;
+
+ //jmf: new spells
+ case SPELL_FLAME_TONGUE:
+ description += "creates a short burst of flame.";
+ break;
+
+ case SPELL_PASSWALL:
+ description += "tunes the caster's body such that it can instantly "
+ "pass through solid rock. This can be dangerous, "
+ "since it is possible for the spell to expire while "
+ "the caster is en route, and it also takes time for the "
+ "caster to attune to the rock, during which time they will "
+ "be helpless. ";
+ break;
+
+ case SPELL_IGNITE_POISON:
+ description += "attempts to convert all poison within the caster's "
+ "view into liquid flame. It is very effective against "
+ "poisonous creatures or those carrying poison potions. "
+ "It is also an amazingly painful way to eliminate "
+ "poison from one's own system. ";
+ break;
+
+ case SPELL_STICKS_TO_SNAKES: // FIXME: description sucks
+ description += "uses wooden items in the caster's grasp as raw "
+ "material for a powerful summoning. Note that highly "
+ "enchanted items, such as wizard's staves, will not be "
+ "affected. ";
+ // "Good examples of sticks include arrows, quarterstaves and clubs.";
+ break;
+
+ case SPELL_SUMMON_LARGE_MAMMAL:
+ description += "summons a canine to the caster's aid.";
+ break;
+
+ case SPELL_SUMMON_DRAGON: //jmf: reworking, currently unavailable
+ description += "summons and binds a powerful dragon to perform the "
+ "caster's bidding. Beware, for the summons may succeed "
+ "even as the binding fails. ";
+ break;
+
+ case SPELL_TAME_BEASTS:
+ description += "attempts to tame animals in the caster's vicinity. "
+ "It works best on animals amenable to domestication. ";
+ break;
+
+ case SPELL_SLEEP:
+ description += "tries to lower its target's metabolic rate, "
+ "inducing hypothermic hibernation. It may have side effects "
+ "on cold-blooded creatures. ";
+ break;
+
+ case SPELL_MASS_SLEEP:
+ description += "tries to lower the metabolic rate of every creature "
+ "within the caster's view enough to induce hypothermic hibernation. "
+ "It may have side effects on cold-blooded creatures. ";
+ break;
+
+/* ******************************************************************
+// not implemented {dlb}:
+ case SPELL_DETECT_MAGIC:
+ description += "probes one or more items lying nearby for enchantment. "
+ "An experienced diviner may glean additional information. ";
+ break;
+****************************************************************** */
+
+ case SPELL_DETECT_SECRET_DOORS:
+ description += "is beloved by lazy dungeoneers everywhere, for it can "
+ "greatly reduce time-consuming searches. ";
+ break;
+
+ case SPELL_SEE_INVISIBLE:
+ description += "enables the caster to perceive things that are "
+ "shielded from ordinary sight. ";
+ break;
+
+ case SPELL_FORESCRY:
+ description += "makes the caster aware of the immediate future; "
+ "while not far enough to predict the result of a "
+ "fight, it does give the caster ample time to get "
+ "out of the way of a punch (reflexes allowing). ";
+ break;
+
+ case SPELL_SUMMON_BUTTERFLIES:
+ description +=
+ "creates a shower of colourful butterflies. How pretty!";
+ break;
+
+ case SPELL_WARP_BRAND:
+ description += "temporarily binds a localized warp field to the "
+ "invoker's weapon. This spell is very dangerous to cast, "
+ "as the field is likely to effect the caster as well. ";
+ break;
+
+ case SPELL_SILENCE:
+ description += "eliminates all sound near the caster. This makes "
+ "reading scrolls, casting spells, praying or yelling "
+ "in the caster's vicinity impossible. (Applies to "
+ "caster too, of course.) This spell will not hide your "
+ "presence, since its oppressive, unnatural effect "
+ "will almost certainly alert any living creature that something "
+ "is very wrong. ";
+ break;
+
+ case SPELL_SHATTER:
+ description +=
+ "causes a burst of concussive force around the caster, "
+ "which will damage most creatures, although those "
+ "composed of stone, metal or crystal, or otherwise "
+ "brittle, will particularly suffer. The magic has been "
+ "known to adversely affect walls. ";
+ break;
+
+ case SPELL_DISPERSAL:
+ description += "tries to teleport away any monsters directly beside "
+ "the caster. ";
+ break;
+
+ case SPELL_DISCHARGE:
+ description += "releases electric charges against those "
+ "next to the caster. These may arc to "
+ "adjacent monsters (or even the caster) before "
+ "they eventually ground out. ";
+ break;
+
+ case SPELL_BEND:
+ description +=
+ "applies a localized spatial distortion to the detriment"
+ " of some nearby creature. ";
+ break;
+
+ case SPELL_BACKLIGHT:
+ description += "causes a halo of glowing light to surround and "
+ "effectively outline a creature. This glow offsets "
+ "the dark, musty atmosphere of the dungeon, and "
+ "thereby makes the affected creature appreciably easier to hit.";
+ break;
+
+ case SPELL_INTOXICATE:
+ description += "works by converting a small portion of brain matter "
+ "into alcohol. It affects all intelligent humanoids within "
+ "the caster's view (presumably including the caster). It "
+ "is frequently used as an icebreaker at wizard parties. ";
+ break;
+
+ case SPELL_GLAMOUR: // intended only as Grey Elf ability
+ description += "is an Elvish magic, which draws upon the viewing "
+ "creature's credulity and the caster's comeliness "
+ "to charm, confuse or render comatose. ";
+ break;
+
+ case SPELL_EVAPORATE:
+ description += "heats a potion causing it to explode into a large "
+ "cloud when thrown. The potion must be thrown immediately, "
+ "as part of the spell, for this to work. ";
+ break;
+
+ case SPELL_FULSOME_DISTILLATION:
+ description += "extracts the vile and poisonous essences from a "
+ "corpse. A rotten corpse may produce a stronger potion."
+ "$$You probably don't want to drink the results. ";
+ break;
+
+/* ******************************************************************
+// not implemented {dlb}:
+ case SPELL_ERINGYAS_SURPRISING_BOUQUET:
+ description += "transmutes any wooden items in the caster's grasp "
+ "into a bouquet of beautiful flowers. ";
+ break;
+****************************************************************** */
+
+ case SPELL_FRAGMENTATION:
+ description +=
+ "creates a concussive explosion within a large body of "
+ "rock (or other hard material), to the detriment of "
+ "any who happen to be standing nearby. ";
+ break;
+
+ case SPELL_AIR_WALK:
+ description += "transforms the caster's body into an insubstantial "
+ "cloud. The caster becomes immaterial and nearly immune "
+ "to physical harm, but is vulnerable to magical fire "
+ "and ice. While insubstantial the caster is, of course, "
+ "unable to interact with physical objects (but may still "
+ "cast spells). ";
+ break;
+
+ case SPELL_SANDBLAST:
+ description += "creates a short blast of high-velocity particles. "
+ "It works best when the caster provides some source "
+ "(by wielding a stone), but will do what it can with "
+ "whatever ambient grit is available. ";
+ break;
+
+ case SPELL_ROTTING:
+ description += "causes the flesh of all those near the caster to "
+ "rot. It will affect the living and many of the "
+ "corporeal undead. ";
+ break;
+
+ case SPELL_SHUGGOTH_SEED:
+ description += "implants a shuggoth seed, the larval parasitic form "
+ "of the fearsome shuggoth, in a living host. The "
+ "shuggoth seed will draw life from its host and then "
+ "hatch, whereupon a fully grown shuggoth will burst "
+ "from the unfortunate host's chest. ";
+ break;
+
+ case SPELL_MAXWELLS_SILVER_HAMMER:
+ description += "bestows a lethal but temporary gravitic field "
+ "to a crushing implement held by the caster. "
+ "It will not affect weapons otherwise subject to "
+ "special enchantments. ";
+ break;
+
+ case SPELL_CONDENSATION_SHIELD:
+ description += "causes a disc of dense vapour to condense out of the "
+ "air surrounding the caster. It acts like a normal "
+ "shield, but its density (and therefore stopping power) "
+ "depends upon the caster's skill with Ice Magic. The "
+ "disc is controlled by the caster's mind and thus will "
+ "not conflict with the wielding of a two-handed weapon. ";
+ break;
+
+ case SPELL_STONESKIN:
+ description += "hardens the one's skin to a degree determined "
+ "by one's skill in Earth Magic. This only works on relatively "
+ "normal flesh; it will aid neither the undead nor the bodily "
+ "transformed. The effects of this spell are boosted if the "
+ "caster is in Statue Form. ";
+ break;
+
+ case SPELL_SIMULACRUM:
+ description += "uses a piece of a flesh in hand to create a replica "
+ "of the original being out of ice. This magic is "
+ "unstable so eventually the replica will sublimate "
+ "into a freezing cloud, if it isn't hacked or melted "
+ "into a small puddle of water first. ";
+ break;
+
+ case SPELL_CONJURE_BALL_LIGHTNING:
+ description += "allows the conjurer to create ball lightning. "
+ "Using the spell is not without risk - ball lighting "
+ "can be difficult to control. ";
+ break;
+
+ case SPELL_TWIST:
+ description += "causes a slight spatial distortion around a monster "
+ "in line of sight of the caster, causing injury. ";
+ break;
+
+ case SPELL_FAR_STRIKE:
+ description += "allows the caster to transfer the force of a "
+ "weapon strike to any target the caster can see. "
+ "This spell will only deliver the impact of the blow; "
+ "magical side-effects and enchantments cannot be "
+ "transferred in this way. The force transferred by "
+ "this spell has little to do with one's skill with "
+ "weapons, and more to do with personal strength, "
+ "translocation skill, and magic ability. ";
+ break;
+
+ case SPELL_SWAP:
+ description += "allows the caster to swap positions with an adjacent "
+ "being. ";
+ break;
+
+ case SPELL_APPORTATION:
+ description += "allows the caster to pull the top item or group of "
+ "similar items from a distant pile to the floor "
+ "near the caster. The mass of the target item(s) will "
+ "make the task more difficult, with some items too "
+ "massive to ever be moved by this spell. Using this "
+ "spell on a group of items can be risky; insufficient "
+ "power will cause some of the items to be lost in the "
+ "infinite void.";
+ break;
+
+ default:
+ DEBUGSTR("Bad spell");
+ description += "apparently does not exist. "
+ "Casting it may therefore be unwise. "
+#if DEBUG
+ "Instead, go fix it. ";
+#else
+ "Please contact Dungeon Tech Support "
+ "at /dev/null for details. ";
+#endif // DEBUG
+ }
+
+ print_description(description);
+
+ if (getch() == 0)
+ getch();
+
+#ifdef DOS_TERM
+ puttext(25, 1, 80, 25, buffer);
+ window(1, 1, 80, 25);
+#endif
+} // end describe_spell()
+
+
+//---------------------------------------------------------------
+//
+// describe_monsters
+//
+// Contains sketchy descriptions of every monster in the game.
+//
+//---------------------------------------------------------------
+void describe_monsters(int class_described, unsigned char which_mons)
+{
+ std::string description;
+
+ description.reserve(200);
+
+#ifdef DOS_TERM
+ char buffer[3400];
+
+ gettext(25, 1, 80, 25, buffer);
+ window(25, 1, 80, 25);
+#endif
+
+ clrscr();
+ description = std::string( ptr_monam( &(menv[ which_mons ]), DESC_CAP_A ) );
+ description += "$$";
+
+ switch (class_described)
+ {
+ // (missing) case 423 - MONS_ANOTHER_LAVA_THING ??? 15jan2000 {dlb}
+ // no entry in m_list.h 17jan200 {dlb}
+ // monster has no stats!
+ // mv: changed ANOTHER_LAVA_THING to SALAMANDER, added stats and
+ // description
+ // (missing) case 250 - MONS_PROGRAM_BUG ??? 16jan2000 {dlb}
+ case MONS_KILLER_BEE_LARVA:
+ description += "A small, powerless larva of killer bee.";
+ break;
+
+ case MONS_QUASIT:
+ description += "A small twisted demon with long sharply pointed tail.";
+ break;
+
+ case MONS_ANGEL:
+ description += "A winged holy being of unnatural beauty. "
+ "It's surrounded by aura of brilliant golden light. ";
+ break;
+
+ case MONS_HUMAN:
+ // These should only be possible from polymorphing or shapeshifting.
+ description += "A remarkably nondescript person. How odd!";
+ break;
+
+ case MONS_GIANT_ANT:
+ description += "A black ant with poisonous pincers,"
+ " about the size of a large dog.";
+ break;
+
+ case MONS_SOLDIER_ANT:
+ description += "A giant ant with large mandibles and a vicious sting.";
+ break;
+
+ case MONS_QUEEN_ANT:
+ description += "A bloated insect, covered in thick chitinous armour."
+ "Now you know where all those ants keep coming from!";
+ break;
+
+ case MONS_ANT_LARVA:
+ description += "A baby ant. Isn't it cute?";
+ break;
+
+ case MONS_GIANT_BAT:
+ description += "A huge black bat.";
+ break;
+
+ case MONS_CENTAUR:
+ case MONS_CENTAUR_WARRIOR:
+ description += "A hybrid with the torso of a "
+ "human atop the body of a large horse. ";
+ if (class_described == MONS_CENTAUR_WARRIOR)
+ description += "It looks strong and aggressive. ";
+ break;
+
+ case MONS_YAKTAUR:
+ case MONS_YAKTAUR_CAPTAIN:
+ description += "Like a centaur, but half yak. ";
+ if (class_described == MONS_YAKTAUR_CAPTAIN)
+ description += "It looks very strong and aggressive. ";
+ break;
+
+ case MONS_RED_DEVIL:
+ description += "The Red Devil is slightly shorter than a human, "
+ "but muscular and covered in spikes and horns. Two "
+ "short wings sprout from its shoulders.";
+ break;
+
+ case MONS_ROTTING_DEVIL:
+ description += "A hideous decaying form.";
+ if (you.species == SP_GHOUL)
+ description += "$It smells great!";
+ else if (you.species != SP_MUMMY)
+ description += "$It stinks.";
+ break;
+
+ case MONS_HAIRY_DEVIL:
+ description += "A small humanoid demon covered in brown hair. "
+ "Watch out - it may have fleas!";
+ break;
+
+ case MONS_ICE_DEVIL:
+ description += "A man-sized demon covered in glittering ice.";
+ break;
+
+ case MONS_BLUE_DEVIL:
+ description += "A strange and nasty blue thing. It looks cold.";
+ break;
+
+ case MONS_IRON_DEVIL:
+ description += "A hideous humanoid figure with metal skin.";
+ break;
+
+ case MONS_ETTIN:
+ description += "A large, two headed humanoid. Most often seen "
+ "wielding two weapons, so that the heads will have one less "
+ "thing to bicker about.";
+ break;
+
+ case MONS_FUNGUS:
+ description += "A lumpy grey fungus, "
+ "growing well in the dank underground dungeon.";
+ break;
+
+ case MONS_GOBLIN:
+ description += "A race of short, ugly and unfriendly humanoids.";
+ break;
+
+ case MONS_HOUND:
+ description += "A fearsome hunting dog.";
+ break;
+
+ case MONS_HELL_HOUND:
+ description += "A huge black dog, with glowing red eyes and "
+ "smoke pouring from its fanged mouth.";
+ break;
+
+ case MONS_WAR_DOG:
+ description += "A vicious dog, trained to kill."
+ "Its neck is protected by massive spiked collar.";
+ break;
+
+ case MONS_IMP:
+ description += "A small, ugly minor demon.";
+ break;
+
+ case MONS_JACKAL:
+ description += "A small, dog-like scavenger. Packs of these creatures "
+ "roam the underworld, searching for carrion to devour.";
+ break;
+
+ case MONS_KILLER_BEE:
+ description += "A giant bee, bearing a deadly barb which can sting "
+ "repeatedly.";
+ break;
+
+ case MONS_QUEEN_BEE:
+ description += "Even larger and more dangerous-looking than its "
+ "offspring, this creature wants you out of its hive. Now!";
+ break;
+
+ case MONS_BUMBLEBEE:
+ description += "A very large and fat hairy bee.";
+ break;
+
+ case MONS_MANTICORE:
+ description += "A hideous cross-breed, bearing the features of a "
+ "human and a lion, with great bat-like wings. Its tail "
+ "bristles with spikes, which can be loosed at potential prey.";
+ break;
+
+ case MONS_NECROPHAGE:
+ description += "A vile undead creation of the most unholy necromancy,"
+ " these creatures are made from the decaying corpses "
+ "of humanoid creatures. They exist to spread disease "
+ "and decay, and gain power from the decaying corpses "
+ "of other beings.";
+ break;
+
+ case MONS_GHOUL:
+ description += "An undead humanoid creature created from the decaying "
+ "corpse by some unholy means of necromancy. It "
+ "exists to spread disease and decay, and gains power"
+ "from the decaying corpses same way as necrophage does.";
+ break;
+
+ case MONS_ORC:
+ description += "An ugly subterranean race, orcs combine the"
+ " worst features of humans, pigs, and several"
+ " other unpleasant creatures.";
+ break;
+
+ case MONS_ORC_KNIGHT:
+ description += "A heavily armoured orc, covered in scars from many "
+ "past battles.";
+ break;
+
+ case MONS_ORC_PRIEST:
+ description += "A servant of the ancient and cruel gods of the orcs,"
+ " dressed in long robe. he's mumbling some strange prayers. "
+ "Hope that they will remain unheard.";
+ break;
+
+ case MONS_ORC_HIGH_PRIEST:
+ description += "An exalted servant of the orc god.";
+ break;
+
+ case MONS_ORC_SORCERER:
+ description += "An orc who draws magical power from Hell.";
+ break;
+
+ case MONS_ORC_WARLORD:
+ description += "A very large and strong looking orc.";
+ break;
+
+ case MONS_ORC_WARRIOR:
+ description += "An armoured orc, obviously experienced in the ways of "
+ "hacking other creatures apart.";
+ break;
+
+ case MONS_ORC_WIZARD:
+ description += "While orcs are generally quite stupid, occasionally"
+ " one develops an aptitude for magic.";
+ break;
+
+ case MONS_PHANTOM:
+ description += "A transparent man-like undead spirit.";
+ break;
+
+ case MONS_RAT:
+ description += "Rats which have grown large and aggressive in "
+ "the pestilential dungeon environment.";
+ break;
+
+ case MONS_GREY_RAT:
+ description += "A very large grey rat.";
+ break;
+
+ case MONS_GREEN_RAT:
+ description += "A very large rat, with hair and skin of a "
+ "most peculiar green colour.";
+ break;
+
+ case MONS_ORANGE_RAT:
+ description += "A huge rat, with weird knobbly orange skin."
+ "It glows with unholy energies. ";
+ break;
+
+ case MONS_SCORPION:
+ description += "A giant black scorpion, its body covered in thick"
+ " armour plating, and its tail tipped by a nasty "
+ "venomous sting.";
+ break;
+
+/* ******************************************************************
+// the tunneling worm is no more ...
+// not until it can be re-implemented safely {dlb}
+ case MONS_TUNNELING_WORM:
+ case MONS_WORM_TAIL:
+ description += "A gargantuan worm, its huge maw capable of crushing rock into dust with little trouble.";
+ break;
+****************************************************************** */
+
+ case MONS_BRAIN_WORM:
+ description += "A slimy mauve worm with a greatly distended head.";
+ break;
+
+ case MONS_LAVA_WORM:
+ description += "A vicious red worm which swims through molten rock.";
+ break;
+
+ case MONS_SPINY_WORM:
+ description += "A great black worm, its many-segmented body covered "
+ "in spiky plates of chitinous armour. Acidic venom drips "
+ "from its toothy maw.";
+ break;
+
+ case MONS_SWAMP_WORM:
+ description += "A large slimy worm, adept at swimming through the "
+ "muck of this foul swamp.";
+ break;
+
+ case MONS_WORM:
+ description += "A giant worm, with unusually large teeth.";
+ break;
+
+ case MONS_UGLY_THING:
+ description += "An ugly thing. Yuck.";
+ break;
+
+ case MONS_VERY_UGLY_THING:
+ description += "A very ugly thing. Double yuck.";
+ break;
+
+ case MONS_FIRE_VORTEX:
+ description += "A swirling cloud of flame.";
+ break;
+
+ case MONS_SPATIAL_VORTEX:
+ description += "A crazily shifting twist in the fabric of reality.";
+ break;
+
+ case MONS_ABOMINATION_SMALL:
+ description +=
+ "A hideous form, created or summoned by some arcane process.";
+ break;
+
+ case MONS_ABOMINATION_LARGE:
+ description += "A huge and hideous form, created or summoned "
+ "by some arcane process.";
+ break;
+
+ case MONS_YELLOW_WASP:
+ description += "A giant wasp covered with thick plates of yellow "
+ "chitinous armour.";
+ break;
+
+ case MONS_RED_WASP:
+ description += "A huge red wasp with a viciously barbed stinger.";
+ break;
+
+ case MONS_ZOMBIE_SMALL:
+ description += "A corpse raised to undeath by necromancy. ";
+ break;
+ case MONS_ZOMBIE_LARGE:
+ description += "A large corpse raised to undeath by necromancy. ";
+ break;
+
+ case MONS_SIMULACRUM_LARGE:
+ case MONS_SIMULACRUM_SMALL:
+ description += "An ice replica of a monster, that's animated by "
+ "the powers of necromancy. ";
+ break;
+
+ case MONS_CYCLOPS:
+ description += "A giant with one eye in the centre of its forehead."
+ " Despite their lack of binocular vision, cyclopes "
+ "throw boulders with fearsomely accuracy.";
+ break;
+
+ case MONS_DRAGON:
+ description += "A great reptilian beast, covered in thick green "
+ "scales and with two huge bat-like wings. Little trails "
+ "of smoke spill from its toothy maw.";
+ break;
+
+ case MONS_GOLDEN_DRAGON:
+ description += "A great dragon covered in shining golden scales. ";
+ break;
+
+ case MONS_ICE_DRAGON:
+ description +=
+ "Like a normal dragon, only white and covered in frost.";
+ break;
+
+ case MONS_IRON_DRAGON:
+ description += "A very heavy and apparently flightless dragon.";
+ break;
+
+ case MONS_MOTTLED_DRAGON:
+ description += "A small dragon with strangely mottled scales.";
+ break;
+
+ case MONS_QUICKSILVER_DRAGON:
+ description += "A long and sinuous dragon, seemingly more neck and "
+ "tail than anything else. Its skin shines like molten mercury, "
+ "and magical energies arc from its pointed snout.";
+ break;
+
+ case MONS_SHADOW_DRAGON:
+ description += "A great shadowy shape, radiating evil and death.";
+ break;
+
+ case MONS_SKELETAL_DRAGON:
+ description += "A huge undead abomination, pieced together from "
+ "the broken bones of many dragons.";
+ break;
+
+ case MONS_STEAM_DRAGON:
+ description += "A relatively small grey dragon, with steam pouring "
+ "from its mouth.";
+ break;
+
+ case MONS_STORM_DRAGON:
+ description += "A huge and very powerful dragon. "
+ "Sparks crackle along its enormous scaly wings.";
+ break;
+
+ case MONS_SWAMP_DRAGON:
+ description += "A slimy dragon, covered in swamp muck. "
+ "Poisonous gasses dribble from its snout.";
+ break;
+
+ case MONS_SERPENT_OF_HELL:
+ description += "A huge red glowing dragon, burning with hellfire. ";
+ break;
+
+ case MONS_SWAMP_DRAKE:
+ description += "A small and slimy dragon, covered in swamp muck. ";
+ if (you.species != SP_MUMMY)
+ description += "It smells horrible.";
+ break;
+
+ case MONS_FIREDRAKE:
+ description += "A small dragon, puffing clouds of smoke.";
+ break;
+
+ case MONS_TWO_HEADED_OGRE:
+ description += "A huge ogre with two heads on top of a "
+ "bloated ogre body. It is capable of holding a weapon "
+ "in each giant hand.";
+ break;
+
+ case MONS_FIEND:
+ description += "One of the most fearsome denizens of any Hell. "
+ "A huge and powerful demon wreathed in hellfire,"
+ " with great scaly wings.";
+ break;
+
+ case MONS_ICE_FIEND:
+ description += "One of the most terrible denizens of the "
+ "many Hells, the Ice Fiend is a huge icy figure, "
+ "covered in frost and wreathed in freezing air.";
+ break;
+
+ case MONS_SHADOW_FIEND:
+ description += "One of the most terrible denizens of the many Hells, "
+ "this horrible being appears as a great mass of "
+ "writhing shadows which occasionally reveal a huge, "
+ "horned skeleton.";
+ break;
+
+ case MONS_GIANT_SPORE:
+ description += "A volatile floating ball of spores, "
+ "covered in knobbly rhizome growths.";
+ break;
+
+ case MONS_HOBGOBLIN:
+ description += "A larger and stronger relatives of goblins.";
+ break;
+
+ case MONS_ICE_BEAST:
+ description +=
+ "A terrible creature, formed of snow and crystalline ice. "
+ "Its feet leave puddles of icy water on the floor.";
+ break;
+
+ case MONS_KOBOLD:
+ description += "Reputedly the creation of an ancient demon-god, "
+ "kobolds are small goblin-like creatures with canine heads.";
+ break;
+
+ case MONS_BIG_KOBOLD:
+ description += "An unusually large kobold.";
+ break;
+
+ case MONS_KOBOLD_DEMONOLOGIST:
+ description += "A kobold who has learned to summon and direct demons.";
+ break;
+
+ case MONS_LICH:
+ description +=
+ "A wizard who didn't want to die, a Lich is a skeletal,"
+ " desiccated corpse kept alive by a mighty exercise of "
+ "necromancy. These undead creatures can wield great "
+ "magic and are best avoided by all but the most confident.";
+ break;
+
+ case MONS_ANCIENT_LICH:
+ description += "A lich who has grown mighty over countless years. ";
+ break;
+
+ case MONS_MUMMY:
+ description += "An undead figure covered in "
+ "bandages and embalming fluids, "
+ "compelled to walk by an ancient curse. "
+ "It radiates a malign aura to those who intrude on its domain. ";
+ break;
+
+ case MONS_GUARDIAN_MUMMY:
+ description += "An ancient warrior, embalmed "
+ "and cursed to walk in undeath for eternity.";
+ break;
+
+ case MONS_GREATER_MUMMY:
+ case MONS_MUMMY_PRIEST:
+ description += "The embalmed and undead corpse of an ancient ";
+ if (class_described == MONS_GREATER_MUMMY)
+ description += "ruler";
+ else
+ description += "servant of darkness";
+ description += ".";
+ break;
+
+ case MONS_NAGA:
+ case MONS_NAGA_MAGE:
+ case MONS_NAGA_WARRIOR:
+ case MONS_GUARDIAN_NAGA:
+ case MONS_GREATER_NAGA:
+ if (you.species == SP_NAGA)
+ description = "An attractive";
+ else
+ description = "A strange";
+
+ description += " hybrid; human from the chest up,"
+ " with a scaly, muscular torso trailing off like "
+ " that of a snake. ";
+
+ switch (class_described)
+ {
+ case MONS_GUARDIAN_NAGA:
+ description += "These nagas are "
+ "often used as guardians by powerful creatures.";
+ break;
+ case MONS_GREATER_NAGA:
+ description += "It looks strong and aggressive.";
+ break;
+ case MONS_NAGA_MAGE:
+ description += "An eldritch nimbus trails its motions. ";
+ break;
+ case MONS_NAGA_WARRIOR:
+ description += "It bears scars of many past battles. ";
+ break;
+ }
+ break;
+
+ case MONS_OGRE:
+ description += "A larger, uglier and fatter relative "
+ "of orcs and goblins.";
+ break;
+
+ case MONS_OGRE_MAGE:
+ description += "A rare breed of ogre, skilled in the use of magic.";
+ break;
+
+ case MONS_PLANT:
+ description += "Few plants can grow in the unpleasant dungeon "
+ "environment, but some have managed to adapt and even thrive "
+ "underground in the absence of the sun.";
+ break;
+
+ case MONS_OKLOB_PLANT:
+ description += "A vicious plant, dripping with vitriol.";
+ break;
+
+ case MONS_RAKSHASA:
+ case MONS_RAKSHASA_FAKE:
+ description += "A type of demon who comes to the material world in "
+ "search of power and knowledge. Rakshasas are experts"
+ " in the art of illusion, among other things.";
+ break;
+
+ case MONS_SNAKE:
+ description += "The common dungeon snake. ";
+ break;
+
+ case MONS_BLACK_SNAKE:
+ description += "A large black snake. ";
+ break;
+
+ case MONS_BROWN_SNAKE:
+ description += "A large brown snake.";
+ break;
+
+ case MONS_GREY_SNAKE:
+ description += "A very large grey python.";
+ break;
+
+ case MONS_LAVA_SNAKE:
+ description += "A burning red snake which rears up from pools "
+ "of lava and tries to bite you.";
+ break;
+
+ case MONS_SMALL_SNAKE:
+ description += "The lesser dungeon snake.";
+ break;
+
+ case MONS_YELLOW_SNAKE:
+ description += "A large yellow tubular reptile.";
+ break;
+
+ case MONS_GIANT_NEWT:
+ description += "Several times the size of a normal newt, but still "
+ "not really impressive.";
+ break;
+
+ case MONS_GIANT_GECKO:
+ description += "A lizard with pads on its toes allowing it to cling "
+ "to walls and ceilings. It's much larger than a normal gecko... "
+ "perhaps it's something in the water?";
+ break;
+
+ case MONS_GIANT_IGUANA:
+ case MONS_GIANT_LIZARD:
+ description += "A huge lizard with great crunching jaws.";
+ break;
+
+ case MONS_GILA_MONSTER:
+ description += "A large lizard with brightly coloured stripes and "
+ "splotches.";
+ break;
+
+ case MONS_KOMODO_DRAGON:
+ description += "An enormous monitor lizard. It's more than capable "
+ "of preying on large animals. Bits of fetid and rotting flesh "
+ "from its last few meals are stuck in its teeth.";
+ break;
+
+ case MONS_LINDWURM:
+ description += "A small serpentine dragon with a pair of strong "
+ "forelimbs. Its thick scales give off an eerie green glow.";
+ break;
+
+ case MONS_TROLL:
+ description +=
+ "A huge, nasty-looking creature. Its thick and knobbly hide "
+ "seems to heal almost instantly from most wounds.";
+ break;
+
+ case MONS_DEEP_TROLL:
+ description += "A stooped troll.";
+ break;
+
+ case MONS_IRON_TROLL:
+ description +=
+ "A great troll, plated with thick scales of rusty iron.";
+ // you can't see its hide, but think it's thick and kobbly, too :P {dlb}
+ //jmf: I thought its skin *was* the rusty iron. If so, ought to change
+ // shatter_monsters in spells4.cc.
+ break;
+
+ case MONS_ROCK_TROLL:
+ description +=
+ "An enormous and very nasty-looking humanoid creature. Its "
+ "rocky hide seems to heal almost instantaneously from most wounds.";
+ break;
+
+ case MONS_UNSEEN_HORROR:
+ description +=
+ "These creatures are usually unseen by the eyes of most,"
+ " and those few who have seen them would rather not have.";
+ break;
+
+ case MONS_VAMPIRE:
+ description += "A powerful undead.";
+ if (you.is_undead == US_ALIVE)
+ description += " It wants to drink your blood! ";
+ break;
+
+ case MONS_VAMPIRE_KNIGHT:
+ description +=
+ "A powerful warrior, with skills undiminished by undeath.";
+ if (you.is_undead == US_ALIVE)
+ description += " It wants to drink your blood! ";
+ break;
+
+ case MONS_VAMPIRE_MAGE:
+ description += "Undeath has not lessened this powerful mage.";
+ if (you.is_undead == US_ALIVE)
+ description += " It wants to drink your blood! ";
+ break;
+
+ case MONS_WRAITH:
+ description += "This undead spirit appears as a cloud of black mist "
+ "surrounding an insubstantial skeletal form. Its eyes "
+ "burn bright with unholy malevolence.";
+ break;
+
+ case MONS_FREEZING_WRAITH:
+ description += "A cloud of freezing air surrounding an incorporeal "
+ "skeletal form.";
+ break;
+
+ case MONS_SHADOW_WRAITH:
+ description += "A mist-wreathed skeletal shadow hanging in mid-air, "
+ "this creature is almost invisible even to your enhanced sight. ";
+ // assumes: to read this message, has see invis
+ break;
+
+ case MONS_YAK:
+ description += "The common dungeon yak, covered in shaggy yak hair "
+ "and bearing a nasty pair of yak horns.";
+ break;
+
+ case MONS_DEATH_YAK:
+ description += "A larger and beefier relative of the common dungeon "
+ "yak. Its little red eyes gleam with hunger for living flesh.";
+ break;
+
+ case MONS_WYVERN:
+ description += "A dragon-like creature with long sharply pointed tail."
+ " Although smaller and less formidable than true dragons, "
+ "wyverns are nonetheless a foe to be reckoned with.";
+ break;
+
+ case MONS_GIANT_EYEBALL:
+ description += "A giant eyeball, with a captivating stare.";
+ break;
+
+ case MONS_GREAT_ORB_OF_EYES:
+ description += "A levitating ball, covered in malignant eyes.";
+ break;
+
+ case MONS_EYE_OF_DEVASTATION:
+ description += "A huge eyeball, encased in a levitating globe of "
+ "incandescent energy. ";
+ break;
+
+ case MONS_SHINING_EYE:
+ description += "A huge and strangely deformed eyeball, "
+ "pulsating with light. "
+ "Beauty is certainly nowhere to be found " "in this beholder. ";
+ break;
+
+ case MONS_EYE_OF_DRAINING:
+ description +=
+ "These hovering horrors are especially loathed by wizards.";
+ break;
+
+ case MONS_WIGHT:
+ description += "An ancient warrior, kept in a state of undeath "
+ "by its will to live.";
+ break;
+
+ case MONS_WOLF_SPIDER:
+ description += "A large hairy spider with vicious mandibles, "
+ "roaming the dungeon in search of food.";
+ break;
+
+ case MONS_REDBACK:
+ description += "A vicious black spider with a splash of red on its "
+ "swollen abdomen. Its mandibles drip with lethal poison.";
+ break;
+
+ case MONS_SHADOW:
+ description +=
+ "An wisp of unliving shadow, drifting on the edge of vision.";
+ break;
+
+ case MONS_HUNGRY_GHOST:
+ description += "The undead form of someone who died of starvation,"
+ " this creature wants the same thing to happen to you!";
+ break;
+
+ case MONS_BUTTERFLY:
+ description += "A large multicoloured butterfly with beautifully "
+ "patterned wings.";
+ break;
+
+ case MONS_WANDERING_MUSHROOM:
+ description += "A large, fat mushroom.";
+ break;
+
+ case MONS_EFREET:
+ description +=
+ "A huge and muscular figure engulfed in a cloud of searing flame.";
+ break;
+
+ case MONS_GIANT_ORANGE_BRAIN:
+ description += "A huge wrinkled brain, floating just off the floor."
+ " Every now and then it seems to pulsate.";
+ break;
+
+ case MONS_GIANT_BEETLE:
+ description += "A huge black beetle with great crunching mandibles "
+ "and very hard chitinous armour.";
+ break;
+
+ case MONS_BORING_BEETLE:
+ description +=
+ "A large brown beetle with huge, rock-crushing mandibles.";
+ break;
+
+ case MONS_BOULDER_BEETLE:
+ description +=
+ "A huge grey beetle with an almost impenetrable rocky carapace.";
+ break;
+
+ case MONS_FLYING_SKULL:
+ description +=
+ "Unholy magic keeps a disembodied undead skull hovering "
+ "above the floor. It has a nasty set of teeth.";
+ break;
+
+ case MONS_MINOTAUR:
+ description += "A large muscular human with the head of a bull. "
+ "It makes its home in secluded labyrinths.";
+ break;
+
+ case MONS_SLIME_CREATURE:
+ description +=
+ "An icky glob of slime, which slithers along the ground.";
+ break;
+
+ case MONS_HELLION:
+ description += "A frightful demon, covered in roaring hellfire.";
+ break;
+
+ case MONS_TORMENTOR:
+ description += "This malign devil is covered in all manner "
+ "of claws, spines and cruel hooks.";
+ break;
+
+ case MONS_REAPER:
+ description += "A skeletal form wielding a giant scythe. ";
+ if (you.is_undead == US_ALIVE)
+ description += "It has come for your soul!";
+ break;
+
+ case MONS_SOUL_EATER:
+ description +=
+ "This greater demon looks like a shadow gliding through "
+ "the air towards you. It radiates an intense aura of negative power.";
+ break;
+
+ case MONS_BEAST:
+ description += "A weird and hideous cross between beast and human.";
+ break;
+
+ case MONS_GLOWING_SHAPESHIFTER:
+ description += "A shapeshifter who has lost control over its "
+ "transformations, and is constantly changing form.";
+ break;
+
+ case MONS_SHAPESHIFTER:
+ description += "A weird creature with the power to change its form. "
+ "It is very rarely observed alive in its natural state.";
+ break;
+
+ case MONS_GIANT_MITE:
+ description += "A large arachnid with vicious poisoned mouth-parts.";
+ break;
+
+ case MONS_GRIFFON:
+ case MONS_HIPPOGRIFF:
+ description += "A large creature with the hindquarters of a ";
+ if (class_described == MONS_HIPPOGRIFF)
+ description += "horse";
+ else
+ description += "lion";
+ description += " and the wings, head, and talons of a great eagle. ";
+ break;
+
+ case MONS_HYDRA:
+ description +=
+ "A great reptilian beast, distantly related to the dragon."
+ " It has many heads, and the potential to grow many more!";
+ break;
+
+ case MONS_SKELETON_SMALL: //MONS_SMALL_SKELETON:
+ case MONS_SKELETON_LARGE: //MONS_LARGE_SKELETON:
+ description +=
+ "A skeleton compelled to unlife by the exercise of necromancy.";
+ break;
+
+ case MONS_SKELETAL_WARRIOR:
+ description += "The vicious and heavily armed skeleton of a humanoid "
+ "creature, animated by unholy power.";
+ break;
+
+ case MONS_HELL_KNIGHT:
+ description += "A heavily armoured warrior, in league with the powers"
+ " of Hell.";
+ break;
+
+ case MONS_WIZARD:
+ description += "An rather eccentric person, dabbling in all sorts of"
+ " arcanities.";
+ break;
+
+ case MONS_NECROMANCER:
+ description +=
+ "A wizard specializing in the practices of necromantic magic.";
+ break;
+
+ case MONS_GNOLL:
+ description +=
+ "A taller and better equipt relative of goblins and orcs.";
+ break;
+
+ case MONS_CLAY_GOLEM:
+ description += "A huge animated clay statue.";
+ break;
+
+ case MONS_WOOD_GOLEM:
+ description += "An animated wooden statue.";
+ break;
+
+ case MONS_STONE_GOLEM:
+ description += "A huge animated stone statue.";
+ break;
+
+ case MONS_IRON_GOLEM:
+ description += "A huge animated metal statue.";
+ break;
+
+ case MONS_CRYSTAL_GOLEM:
+ description += "A huge animated crystal statue.";
+ break;
+
+ case MONS_TOENAIL_GOLEM:
+ description += "A huge animated statue made entirely from toenail "
+ "clippings. Some people just have too much time on their hands.";
+ break;
+
+ case MONS_ELECTRIC_GOLEM:
+ description += "An animated figure made completely of electricity. ";
+ break;
+
+ case MONS_EARTH_ELEMENTAL:
+ description += "A spirit drawn from the elemental plane of earth, "
+ "which exists in this world by inhabiting a lump of earth and rocks.";
+ break;
+
+ case MONS_FIRE_ELEMENTAL:
+ description += "A spirit drawn from the elemental plane of fire, "
+ "which exists in this world as a brilliant column of raging flames.";
+ break;
+
+ case MONS_AIR_ELEMENTAL:
+ description += "A spirit drawn from the elemental plane of air. "
+ "It exists in this world as a swirling vortex of air, "
+ "often dissipating and reforming.";
+ break;
+
+ case MONS_WATER_ELEMENTAL:
+ description += "A spirit drawn from the elemental plane of water. "
+ "It exists on this world as part of a body of water.";
+ break;
+
+ case MONS_SPECTRAL_WARRIOR: // spectre
+ description += "A hideous translucent green undead spirit.";
+ break;
+
+ case MONS_CURSE_TOE:
+ description += "A disembodied toe, hanging in the air and"
+ " radiating an intense field of negative energy.";
+ break;
+
+ case MONS_PULSATING_LUMP:
+ description += "A revolting glob of writhing flesh.";
+ break;
+
+ case MONS_OOZE:
+ description += "A disgusting glob of grey sludge.";
+ break;
+
+ case MONS_BROWN_OOZE:
+ description += "A viscous liquid, flowing along the floor "
+ "in search of organic matter to corrode. ";
+ break;
+
+ case MONS_DEATH_OOZE:
+ description += "A putrid mass of decaying flesh. ";
+ break;
+
+ case MONS_GIANT_AMOEBA:
+ description += "A pulsating lump of protoplasm. ";
+ break;
+
+ case MONS_JELLY:
+ description += "A pulsating mass of acidic protoplasm. It can and "
+ "will eat almost anything, and grows a little each time...";
+ break;
+
+ case MONS_AZURE_JELLY:
+ description += "A frosty blob of bright blue cytoplasm. ";
+ break;
+
+ case MONS_ACID_BLOB:
+ description +=
+ "A lump of sickly green flesh, dripping with lethal acid.";
+ break;
+
+ case MONS_JELLYFISH:
+ description += "A pulsating glob of transparent flesh, waiting just "
+ "below the surface to sting you with its many tentacles.";
+ break;
+
+ case MONS_ROYAL_JELLY:
+ description += "A particularly rich and golden gelatinous thing. ";
+ break;
+
+ case MONS_FIRE_GIANT:
+ description += "A huge ruddy humanoid with bright hair. ";
+ break;
+
+ case MONS_FROST_GIANT:
+ description += "A huge blue humanoid with hoarfrost hair.";
+ break;
+
+ case MONS_HILL_GIANT:
+ description +=
+ "Although one of the smaller giant varieties, this hill giant is still big enough to be dangerous.";
+ break;
+
+ case MONS_STONE_GIANT:
+ description +=
+ "A gigantic humanoid with grey skin almost as hard as rock. "
+ "It carries several boulders - are you up for a game of 'catch'?";
+ break;
+
+ case MONS_TITAN:
+ description += "This lightning-limned humanoid is unusually large "
+ "and powerful, even among giants.";
+ break;
+
+ case MONS_FLAYED_GHOST:
+ description += "A hideous undead creature, with torn skin hanging "
+ "from an emaciated body.";
+ break;
+
+ case MONS_INSUBSTANTIAL_WISP:
+ description += "A thin wisp of floating gas.";
+ break;
+
+ case MONS_VAPOUR:
+ description += "A normally invisible cloud of weird-looking vapour.";
+ break;
+
+ case MONS_DANCING_WEAPON:
+ description += "A weapon dancing in the air. ";
+ break;
+
+ case MONS_ELEPHANT_SLUG:
+ description += "A huge grey slug with folds of wrinkled skin. ";
+ break;
+
+ case MONS_GIANT_SLUG:
+ description += "A huge and disgusting gastropod. ";
+ break;
+
+ case MONS_GIANT_SNAIL:
+ description +=
+ "A huge and disgusting gastropod with light green shell. ";
+ break;
+
+ case MONS_SHEEP:
+ description += "A stupid woolly animal, with murder in its eyes. ";
+ break;
+
+ case MONS_HOG:
+ description += "A large, fat and very ugly pig. ";
+ break;
+
+ case MONS_HELL_HOG:
+ description += "A large, fat and very ugly pig, suckled "
+ "in the pits of Hell. ";
+ break;
+
+ case MONS_GIANT_MOSQUITO:
+ description += "A huge, bloated mosquito. It looks diseased.";
+ break;
+
+ case MONS_GIANT_CENTIPEDE:
+ description += "It has a lot of legs.";
+ break;
+
+ case MONS_GIANT_BLOWFLY:
+ description += "A huge and irritating fly.";
+ break;
+
+ case MONS_GIANT_FROG:
+ description +=
+ "It probably didn't get this big by eating little insects.";
+ break;
+
+ case MONS_GIANT_BROWN_FROG:
+ description += "A very large and vicious-looking carnivorous frog. "
+ "Its knobbly brown skin blends in with the rough rock of your surroundings.";
+ break;
+
+ case MONS_SPINY_FROG:
+ description +=
+ "Although slightly smaller than its cousin, the giant brown"
+ " frog, the spiny frog makes up for lack of size by being"
+ " covered in wickedly barbed spines and spurs.";
+ break;
+
+ case MONS_BLINK_FROG:
+ description +=
+ "A weird-looking frog, constantly blinking in and out of reality.";
+ break;
+
+ case MONS_GIANT_COCKROACH:
+ description += "A large brown cockroach.";
+ break;
+
+ case MONS_PIT_FIEND:
+ description += "A huge winged fiend with incredibly tough skin.";
+ break;
+
+ case MONS_GARGOYLE:
+ description += "A hideous stone statue come to life.";
+ break;
+
+ case MONS_METAL_GARGOYLE:
+ description += "A hideous metal statue come to life.";
+ break;
+
+ case MONS_MOLTEN_GARGOYLE:
+ description += "A hideous melting stone statue come to life.";
+ break;
+
+ case MONS_ELF:
+ case MONS_DEEP_ELF_SOLDIER:
+ case MONS_DEEP_ELF_FIGHTER:
+ case MONS_DEEP_ELF_KNIGHT:
+ case MONS_DEEP_ELF_MAGE:
+ case MONS_DEEP_ELF_SUMMONER:
+ case MONS_DEEP_ELF_CONJURER:
+ case MONS_DEEP_ELF_PRIEST:
+ case MONS_DEEP_ELF_HIGH_PRIEST:
+ case MONS_DEEP_ELF_DEMONOLOGIST:
+ case MONS_DEEP_ELF_ANNIHILATOR:
+ case MONS_DEEP_ELF_SORCERER:
+ case MONS_DEEP_ELF_DEATH_MAGE:
+ description +=
+ "One of the race of elves which inhabits this dreary cave.$";
+ switch (class_described)
+ {
+
+ case MONS_DEEP_ELF_SOLDIER:
+ description += "This one is just common soldier.";
+ break;
+
+ case MONS_DEEP_ELF_FIGHTER:
+ description += "This soldier has learned some magic.";
+ break;
+
+ case MONS_DEEP_ELF_KNIGHT:
+ description += "This one bears the scars of battles past.";
+ break;
+
+ case MONS_DEEP_ELF_MAGE:
+ description += "Mana crackles between this one's long fingers.";
+ break;
+
+ case MONS_DEEP_ELF_SUMMONER:
+ case MONS_DEEP_ELF_CONJURER:
+ description += "This one is a mage specialized in the ancient art ";
+ if (class_described == MONS_DEEP_ELF_SUMMONER)
+ description += "of summoning servants";
+ else
+ description += "of hurling energies";
+ description += " of destruction.";
+ break;
+
+ case MONS_DEEP_ELF_PRIEST:
+ description += "This one is a servant of the deep elves' god.";
+ break;
+
+ case MONS_DEEP_ELF_HIGH_PRIEST:
+ description +=
+ "This one is an exalted servant of the deep elves' god.";
+ break;
+
+ case MONS_DEEP_ELF_DEMONOLOGIST:
+ description +=
+ "This mage specialized in demonology, and is marked heavily "
+ "from long years in contact with unnatural demonic forces.";
+ break;
+
+ case MONS_DEEP_ELF_ANNIHILATOR:
+ description += "This one likes destructive magics more than most, "
+ "and is better at them.";
+ break;
+
+ case MONS_DEEP_ELF_SORCERER:
+ description += "This mighty spellcaster draws power from Hell.";
+ break;
+
+ case MONS_DEEP_ELF_DEATH_MAGE:
+ description += "A strong negative aura surrounds this one.";
+ break;
+
+ case MONS_ELF:
+ // These are only possible from polymorphing or shapeshifting.
+ description += "This one is remarkably plain looking.";
+ break;
+ }
+ break;
+
+ case MONS_WHITE_IMP:
+ description += "A small and mischievous minor demon. ";
+ break;
+
+ case MONS_LEMURE:
+ description += "A vaguely humanoid blob of putrid white flesh. ";
+ break;
+
+ case MONS_UFETUBUS:
+ description += "A chattering and shrieking minor demon. ";
+ break;
+
+ case MONS_MANES:
+ description += "An ugly, twisted little minor demon. ";
+ break;
+
+ case MONS_MIDGE:
+ description += "A small flying demon. ";
+ break;
+
+ case MONS_NEQOXEC:
+ description += "A weirdly shaped demon. ";
+ break;
+
+ case MONS_ORANGE_DEMON:
+ description += "A bright orange demon with a venomous stinger. ";
+ break;
+
+ case MONS_HELLWING:
+ description +=
+ "A hideous skeletal demon, with wings of ancient withered skin. ";
+ break;
+
+ case MONS_SMOKE_DEMON:
+ description += "A writhing cloud of smoke hanging in the air. ";
+ break;
+
+ case MONS_YNOXINUL:
+ description += "A demon with shiny metallic scales. ";
+ break;
+
+ case MONS_EXECUTIONER:
+ description += "A horribly powerful demon. ";
+ break;
+
+ case MONS_GREEN_DEATH:
+ description +=
+ "A bloated form covered in oozing sores and exhaling clouds of lethal poison. ";
+ break;
+
+ case MONS_BLUE_DEATH:
+ description += "A blue greater demon. ";
+ break;
+
+ case MONS_BALRUG:
+ description +=
+ "A huge and very powerful demon, wreathed in fire and shadows. ";
+ break;
+
+ case MONS_CACODEMON:
+ description += "A hideously ugly demon of rage and legendary power. ";
+ break;
+
+ case MONS_DEMONIC_CRAWLER:
+ description += "A long and bloated body, supported by "
+ "dozens of short legs and topped with an evil-looking head. ";
+ break;
+
+ case MONS_SUN_DEMON:
+ description +=
+ "A demonic figure shining with the light and fury of a fallen star.";
+ break;
+
+ case MONS_SHADOW_IMP:
+ description += "A small and shadowy minor demon.";
+ break;
+
+ case MONS_SHADOW_DEMON:
+ description += "A mysterious demonic figure,"
+ " constantly blurring into multiple shadows of itself.";
+ break;
+
+ case MONS_LOROCYPROCA:
+ description += "A tall and gaunt figure, "
+ "draped in long robes which flow as if alive.";
+ break;
+
+ case MONS_GERYON:
+ description +=
+ "A huge and slithery arch-demon, guarding the gates of Hell. ";
+ break;
+
+ case MONS_DISPATER:
+ description += "The lord of the Iron City of Dis. ";
+ break;
+
+ case MONS_ASMODEUS:
+ description +=
+ "One of the arch-demons who dwell in the depths of Hell. ";
+ break;
+
+ case MONS_ANTAEUS:
+ description += "A great titan who lives in the depths of Cocytus. ";
+ break;
+
+ case MONS_ERESHKIGAL:
+ description +=
+ "A fearsome arch-fiend who rules the deathly netherworld of Tartarus. ";
+ break;
+
+ case MONS_VAULT_GUARD:
+ description += "A heavily armed and armoured guardian of the Vaults. ";
+ break;
+
+ case MONS_CURSE_SKULL:
+ description +=
+ "A charred skull floating in the air and rotating slowly. "
+ "Mystic symbols carved into its blackened surface indicate "
+ "its resistance to almost any form of attack. ";
+ break;
+
+ case MONS_ORB_GUARDIAN:
+ description +=
+ "A huge and glowing purple creature, created by the Orb to "
+ "defend itself. ";
+ break;
+
+ case MONS_DAEVA:
+ description +=
+ "A divine agent of the Shining One. It manifests as a winged "
+ "figure obscured by an aura of brilliant golden light. ";
+ break;
+
+ case MONS_SPECTRAL_THING:
+ description += "A hideous glowing apparition.";
+ break;
+
+ case MONS_TENTACLED_MONSTROSITY:
+ description +=
+ "A writhing mass of tentacles, all covered in putrid mucous.";
+ break;
+
+ case MONS_SPHINX:
+ description +=
+ "A large creature with a human head, the body of a lion, and "
+ "the wings of a huge bird.";
+ break;
+
+ case MONS_ROTTING_HULK:
+ description += "A shambling undead, related to the ghoul.";
+ break;
+
+ case MONS_KILLER_KLOWN:
+ description += "A comical figure full of life and laughter. It"
+ " looks very happy to see you... but is there a slightly malicious"
+ " cast to its features? Is that red facepaint or something"
+ " altogether less pleasant? Join in the fun, and maybe you'll"
+ " find out!";
+ break;
+
+ case MONS_MOTH_OF_WRATH:
+ description += "A huge moth, as violent as it is hairy.";
+ break;
+
+ case MONS_DEATH_COB:
+ description += "A dreadful undead cob of corn.";
+ break;
+
+ case MONS_BOGGART:
+ description +=
+ "A twisted little sprite-goblin. Beware of its magical tricks!";
+ break;
+
+ case MONS_LAVA_FISH:
+ description += "A fish which lives in lava.";
+ break;
+
+ case MONS_BIG_FISH:
+ description += "A fish of unusual size.";
+ break;
+
+ case MONS_GIANT_GOLDFISH:
+ description +=
+ "This is what happens when you give your pet goldfish too much food!";
+ break;
+
+ case MONS_ELECTRICAL_EEL:
+ description +=
+ "A small and slimy eel, crackling with electrical discharge.";
+ break;
+
+ case MONS_PLAYER_GHOST:
+ {
+ char tmp_buff[ INFO_SIZE ];
+
+ // We're fudgins stats so that unarmed combat gets based off
+ // of the ghost's species, not the player's stats... exact
+ // stats are required anyways, all that matters is whether
+ // dex >= str. -- bwr
+ const int dex = 10;
+ int str;
+ switch (ghost.values[GVAL_SPECIES])
+ {
+ case SP_HILL_DWARF:
+ case SP_MOUNTAIN_DWARF:
+ case SP_TROLL:
+ case SP_OGRE:
+ case SP_OGRE_MAGE:
+ case SP_MINOTAUR:
+ case SP_HILL_ORC:
+ case SP_CENTAUR:
+ case SP_NAGA:
+ case SP_MUMMY:
+ case SP_GHOUL:
+ str = 15;
+ break;
+
+ case SP_HUMAN:
+ case SP_DEMIGOD:
+ case SP_DEMONSPAWN:
+ str = 10;
+ break;
+
+ default:
+ str = 5;
+ break;
+ }
+
+ snprintf( tmp_buff, sizeof(tmp_buff),
+ "The apparition of %s the %s, a%s %s %s.$",
+ ghost.name,
+
+ skill_title( ghost.values[GVAL_BEST_SKILL],
+ ghost.values[GVAL_SKILL_LEVEL],
+ ghost.values[GVAL_SPECIES],
+ str, dex, GOD_NO_GOD ),
+
+ (ghost.values[GVAL_EXP_LEVEL] < 4) ? " weakling" :
+ (ghost.values[GVAL_EXP_LEVEL] < 7) ? "n average" :
+ (ghost.values[GVAL_EXP_LEVEL] < 11) ? "n experienced" :
+ (ghost.values[GVAL_EXP_LEVEL] < 16) ? " powerful" :
+ (ghost.values[GVAL_EXP_LEVEL] < 22) ? " mighty" :
+ (ghost.values[GVAL_EXP_LEVEL] < 26) ? " great" :
+ (ghost.values[GVAL_EXP_LEVEL] < 27) ? "n awesomely powerful"
+ : " legendary",
+
+ species_name( ghost.values[GVAL_SPECIES],
+ ghost.values[GVAL_EXP_LEVEL] ),
+
+ get_class_name( ghost.values[GVAL_CLASS] ) );
+
+ description += tmp_buff;
+ }
+ break;
+
+ case MONS_PANDEMONIUM_DEMON:
+ description += describe_demon();
+ break;
+
+ // mimics -- I'm not considering these descriptions a bug. -- bwr
+ case MONS_GOLD_MIMIC:
+ description +=
+ "An apparently harmless pile of gold coins hides a nasty "
+ "venomous shapechanging predator.";
+ break;
+
+ case MONS_WEAPON_MIMIC:
+ description +=
+ "An apparently abandoned weapon, actually a vicious little "
+ "beast in disguise.";
+ break;
+
+ case MONS_ARMOUR_MIMIC:
+ description +=
+ "An apparently abandoned suit of finely-made armour, actually "
+ "a vicious little beast in disguise.";
+ break;
+
+ case MONS_SCROLL_MIMIC:
+ description +=
+ "An ancient parchment covered in arcane runes. Did it just twitch?";
+ break;
+
+ case MONS_POTION_MIMIC:
+ description += "A delicious looking magical drink. Go on, pick it up!";
+ break;
+
+ case MONS_BALL_LIGHTNING:
+ description += "An oddity of nature, ball lightning bounces around "
+ "behaving almost, but not quite, entirely unlike "
+ "regular lightning. ";
+ break;
+
+ case MONS_ORB_OF_FIRE:
+ description += "A globe of raw primordial fire, capable of "
+ "impressive pyrotechnics.";
+ break;
+
+ // the quokka is no more ... {dlb}
+ // the quokka is back, without cyberware -- bwr
+ case MONS_QUOKKA:
+ description += "A small marsupial. Don't call it a rat.";
+ break;
+
+ // uniques
+ case MONS_MNOLEG: // was: Nemelex Xobeh - and wrong! {dlb}
+ description += "A weirdly glowing figure, "
+ "dancing through the twisted air of Pandemonium. ";
+ break;
+
+ case MONS_LOM_LOBON: // was: Sif Muna - and wrong! {dlb}
+ description += "An ancient and strangely serene demon. "
+ "It regards you coldly from "
+ "the huge glowing eye in the centre of its forehead. ";
+ break;
+
+ case MONS_CEREBOV: // was: Okawaru - and wrong! {dlb}
+ description += "A violent and wrathful demon, "
+ "Cerebov appears as a giant human "
+ "covered in shining golden armour "
+ "and wielding a huge twisted sword. ";
+ break;
+
+ case MONS_GLOORX_VLOQ: // was: Kikubaaqudgha - and wrong! {dlb}
+ description += "A shadowy figure clothed in profound darkness. ";
+ break;
+
+ case MONS_TERENCE:
+ description += "An evil human fighter.";
+ break;
+
+ case MONS_JESSICA:
+ description += "An evil apprentice sorceress.";
+ break;
+
+ case MONS_SIGMUND:
+ description += "An evil and spry old human, whose eyes "
+ "twinkle with madness. Sigmund wields a nasty looking scythe.";
+ break;
+
+ case MONS_EDMUND:
+ description += "A lightly armoured warrior.";
+ break;
+
+ case MONS_PSYCHE:
+ description += "A fair-haired magess.";
+ break;
+
+ case MONS_DONALD:
+ description += "An adventurer like you, trying to find the Orb.";
+ break;
+
+ case MONS_MICHAEL:
+ description += "A powerful spellcaster, dressed in a long robe.";
+ break;
+
+ case MONS_JOSEPH:
+ description += "Looks like a mercenary.";
+ break;
+
+ case MONS_ERICA:
+ description += "A comely spellweaver.";
+ break;
+
+ case MONS_JOSEPHINE:
+ description += "An ugly elderly figure, dressed in Druidic clothes.";
+ break;
+
+ case MONS_HAROLD:
+ description += "An evil human bounty hunter.";
+ break;
+
+ case MONS_NORBERT:
+ description += "A skilled warrior.";
+ break;
+
+ case MONS_JOZEF:
+ description += "A tall bounty hunter.";
+ break;
+
+ case MONS_AGNES:
+ description += "A lanky warrior.";
+ break;
+
+ case MONS_MAUD:
+ description += "An evil warrior who looks inexplicably like a rodent.";
+ break;
+
+ case MONS_LOUISE:
+ description += "An unusually heavily armoured spellcaster.";
+ break;
+
+ case MONS_FRANCIS:
+ description += "A wizened spellcaster.";
+ break;
+
+ case MONS_FRANCES:
+ description += "A stout warrior, bearing a deep facial scar.";
+ break;
+
+ case MONS_RUPERT:
+ description += "An evil berserker.";
+ break;
+
+ case MONS_WAYNE:
+ description += "A fat, evil dwarf in a stupid looking hat.";
+ break;
+
+ case MONS_DUANE:
+ description += "An evil mercenary with unusually large ears.";
+ break;
+
+ case MONS_NORRIS:
+ description += "A tan, fit and thoroughly evil surfer.";
+ break;
+
+ case MONS_ADOLF:
+ description += "A svelte fighter-mage with unfortunate facial hair.";
+ break;
+
+ case MONS_MARGERY:
+ description += "A lithe spellcaster.";
+ break;
+
+ case MONS_IJYB:
+ description += "A small and twisted goblin, wearing some ugly blue rags.";
+ break;
+
+ case MONS_BLORK_THE_ORC:
+ description += "A particularly fat and ugly orc.";
+ break;
+
+ case MONS_EROLCHA:
+ description += "An especially cunning ogre magess.";
+ break;
+
+ case MONS_URUG:
+ description += "A rude";
+ if (you.species != SP_MUMMY)
+ description += ", smelly";
+ description += " orc.";
+ break;
+
+ case MONS_SNORG:
+ description += "A hairy troll.";
+ break;
+
+ case MONS_XTAHUA:
+ description += "An ancient and mighty dragon.";
+ break;
+
+ case MONS_BORIS:
+ description +=
+ "An ancient lich. The air around his shrouded form crackles with evil energy. ";
+ break;
+
+ case MONS_SHUGGOTH:
+ description += "A vile creature with an elongated head, spiked tail "
+ "and wicked six-fingered claws. Its awesome strength is matched by "
+ "its umbrage at being transported to this backwater dimension. ";
+ break;
+
+ case MONS_WOLF:
+ description += "A large and strong grey canine.";
+ break;
+
+ case MONS_WARG:
+ description += "A particularly large and evil looking wolf, usually "
+ "found in the company of orcs.";
+ break;
+
+ case MONS_BEAR:
+ description += "The common dungeon bear.";
+ break;
+
+ case MONS_GRIZZLY_BEAR:
+ description += "A large, nasty bear with grey fur.";
+ break;
+
+ case MONS_POLAR_BEAR:
+ description += "A large and very strong bear covered in glistening "
+ "white fur. ";
+ break;
+
+ case MONS_BLACK_BEAR:
+ description += "A small black bear.";
+ break;
+
+ case MONS_SALAMANDER: // mv: was ANOTHER_LAVA_THING
+ description += "A strange half-human half-snake creature "
+ "covered in thick red scales and thorns.";
+ break;
+
+ case MONS_PROGRAM_BUG:
+ default:
+ description += "If this monster is a \"program bug\", then it's "
+ "recommended that you save your game and reload. Please report "
+ "monsters who masquerade as program bugs or run around the "
+ "dungeon without a proper description to the authorities.";
+ break;
+ // onocentaur - donkey
+ }
+
+#if DEBUG_DIAGNOSTICS
+
+ if (mons_flag( menv[ which_mons ].type, M_SPELLCASTER ))
+ {
+ int hspell_pass[6] = { MS_NO_SPELL, MS_NO_SPELL, MS_NO_SPELL,
+ MS_NO_SPELL, MS_NO_SPELL, MS_NO_SPELL };
+
+ int msecc = ((class_described == MONS_HELLION) ? MST_BURNING_DEVIL :
+ (class_described == MONS_PANDEMONIUM_DEMON) ? MST_GHOST
+ : menv[ which_mons ].number);
+
+ mons_spell_list(msecc, hspell_pass);
+
+ bool found_spell = false;
+
+ for (int i = 0; i < 6; i++)
+ {
+ if (hspell_pass[i] != MS_NO_SPELL)
+ {
+ if (!found_spell)
+ {
+ description += "$Monster Spells:$";
+ found_spell = true;
+ }
+
+ snprintf( info, INFO_SIZE, " %d: %s$", i,
+ mons_spell_name( hspell_pass[i] ) );
+
+ description += info;
+ }
+ }
+ }
+
+ bool has_item = false;
+ for (int i = 0; i < NUM_MONSTER_SLOTS; i++)
+ {
+ if (menv[ which_mons ].inv[i] != NON_ITEM)
+ {
+ if (!has_item)
+ {
+ description += "$Monster Inventory:$";
+ has_item = true;
+ }
+
+ char buff[ ITEMNAME_SIZE ];
+
+ item_def item = mitm[ menv[which_mons].inv[i] ];
+ set_ident_flags( item, ISFLAG_IDENT_MASK );
+
+ item_name( item, DESC_NOCAP_A, buff );
+ snprintf( info, INFO_SIZE, " %d: %s$", i, buff );
+ description += info;
+ }
+ }
+
+#endif
+
+ print_description(description);
+
+ if (getch() == 0)
+ getch();
+
+#ifdef DOS_TERM
+ puttext(25, 1, 80, 25, buffer);
+ window(1, 1, 80, 25);
+#endif
+} // end describe_monsters
+
+
+static void print_god_abil_desc( int abil )
+{
+ const ability_def &abil_info = get_ability_def( abil );
+
+ const std::string cost = "(" + make_cost_description( abil_info ) + ")";
+
+ // Produce a 79 character string with cost right justified:
+ std::string str( abil_info.name );
+ str += std::string( 79 - str.length() - cost.length(), ' ' ) + cost + EOL;
+
+ cprintf( str.c_str() );
+}
+
+
+//---------------------------------------------------------------
+//
+// describe_god
+//
+// Describes all gods. Accessible through altars (by praying), or
+// by the ^ key if player is a worshipper.
+//
+//---------------------------------------------------------------
+
+void describe_god( int which_god, bool give_title )
+{
+
+ const char *description; // mv: tmp string used for printing description
+ int colour; // mv: colour used for some messages
+
+#ifdef DOS_TERM
+ char buffer[4000];
+ gettext( 1, 1, 80, 25, buffer );
+ window( 1, 1, 80, 25 );
+#endif
+
+ clrscr();
+
+ if (give_title)
+ {
+ textcolor( WHITE );
+ cprintf( " Religion" EOL );
+ textcolor( LIGHTGREY );
+ }
+
+ if (which_god == GOD_NO_GOD) //mv:no god -> say it and go away
+ {
+ cprintf( EOL "You are not religious." );
+ goto end_god_info;
+ }
+
+ colour = god_colour(which_god);
+
+ //mv: print god's name and title - if you can think up better titles
+ //I have nothing against
+ textcolor(colour);
+ cprintf (god_name(which_god,true)); //print long god's name
+ cprintf (EOL EOL);
+
+ //mv: print god's description
+ textcolor (LIGHTGRAY);
+
+ switch (which_god)
+ {
+ case GOD_ZIN:
+ description = "Zin is an ancient and revered God, dedicated to the establishment of order" EOL
+ "and the destruction of the forces of chaos and night. Valued worshippers " EOL
+ "can gain a variety of powers useful in the fight against the evil, but must" EOL
+ "abstain from the use of necromancy and other forms of unholy magic." EOL
+ "Zin appreciates long-standing faith as well as sacrifices of valued objects." EOL;
+ break;
+
+ case GOD_SHINING_ONE:
+ description = "The Shining One is a powerful crusading deity, allied with Zin in the fight" EOL
+ "against evil. Followers may be granted with the ability to summarily dispense" EOL
+ "the wrath of heaven, but must never use any form of evil magic and should" EOL
+ "fight honourably. The Shining One appreciates long-standing persistence in " EOL
+ "the endless crusade, as well as the dedicated destruction of unholy creatures.";
+ break;
+
+ case GOD_KIKUBAAQUDGHA:
+ description = "Kikubaaqudgha is a terrible Demon-God, served by those who seek knowledge of" EOL
+ "the powers of death. Followers gain special powers over the undead, and " EOL
+ "especially favoured servants can call on mighty demons to slay their foes." EOL
+ "Kikubaaqudgha requires the deaths of living creatures as often as possible," EOL
+ "but is not interested in the offering of corpses except at an appropriate" EOL
+ "altar.";
+ break;
+
+ case GOD_YREDELEMNUL:
+ description = "Yredelemnul is worshipped by those who seek powers over death and the undead" EOL
+ "without having to learn to use necromancy. Followers can raise legions of " EOL
+ "servile undead and gain a number of other useful (if unpleasant) powers." EOL
+ "Yredelemnul appreciates killing, but prefers corpses to be put to use rather" EOL
+ "than sacrificed.";
+ break;
+
+ case GOD_XOM:
+ description = "Xom is a wild and unpredictable God of chaos, who seeks not worshippers but" EOL
+ "playthings to toy with. Many choose to follow Xom in the hope of receiving" EOL
+ "fabulous rewards and mighty powers, but Xom is nothing if not capricious. ";
+ break;
+
+ case GOD_VEHUMET:
+ description = "Vehumet is a God of the destructive powers of magic. Followers gain various" EOL
+ "useful powers to enhance their command of the hermetic arts, and the most" EOL
+ "favoured stand to gain access to some of the fearsome spells in Vehumet's" EOL
+ "library. One's devotion to Vehumet can be proved by the causing of as much" EOL
+ "carnage and destruction as possible.";
+ break;
+
+ case GOD_OKAWARU:
+ description = "Okawaru is a dangerous and powerful God of battle. Followers can gain a " EOL
+ "number of powers useful in combat as well as various rewards, but must " EOL
+ "constantly prove themselves through battle and the sacrifice of corpses" EOL
+ "and valuable items.";
+ break;
+
+ case GOD_MAKHLEB:
+ description = "Makhleb the Destroyer is a fearsome God of chaos and violent death. Followers," EOL
+ "who must constantly appease Makhleb with blood, stand to gain various powers " EOL
+ "of death and destruction. The Destroyer appreciates sacrifices of corpses and" EOL
+ "valuable items.";
+ break;
+
+ case GOD_SIF_MUNA:
+ description = "Sif Muna is a contemplative but powerful deity, served by those who seek" EOL
+ "magical knowledge. Sif Muna appreciates sacrifices of valuable items, and" EOL
+ "the casting of spells as often as possible.";
+ break;
+
+ case GOD_TROG:
+ description = "Trog is an ancient God of anger and violence. Followers are expected to kill" EOL
+ "in Trog's name and sacrifice the dead, and in return gain power in battle and" EOL
+ "occasional rewards. Trog hates wizards, and followers are forbidden the use" EOL
+ "of spell magic. ";
+ break;
+
+ case GOD_NEMELEX_XOBEH:
+ description = "Nemelex is a strange and unpredictable trickster God, whose powers can be" EOL
+ "invoked through the magical packs of cards which Nemelex paints in the ichor" EOL
+ "of demons. Followers receive occasional gifts, and should use these gifts as" EOL
+ "as much as possible. Offerings of any type of item are also appreciated.";
+ break;
+
+ case GOD_ELYVILON:
+ description = "Elyvilon the Healer is worshipped by the healers (among others), who gain" EOL
+ "their healing powers by long worship and devotion. Although Elyvilon prefers" EOL
+ "a creed of pacifism, those who crusade against evil are not excluded. Elyvilon" EOL
+ "appreciates the offering of weapons. ";
+ break;
+
+ default:
+ description = "God of Program Bugs is a weird and dangerous God and his presence should" EOL
+ "be reported to dev-team.";
+ }
+
+ cprintf(description);
+ //end of printing description
+
+ // title only shown for our own god
+ if (you.religion == which_god)
+ {
+ //mv: print title based on piety
+ cprintf( EOL EOL "Title - " );
+ textcolor(colour);
+
+ // mv: if your piety is high enough you get title
+ // based on your god
+ if (you.piety > 160)
+ {
+ cprintf((which_god == GOD_SHINING_ONE) ? "Champion of Law" :
+ (which_god == GOD_ZIN) ? "Divine Warrior" :
+ (which_god == GOD_ELYVILON) ? "Champion of Light" :
+ (which_god == GOD_OKAWARU) ? "Master of Thousand Battles" :
+ (which_god == GOD_YREDELEMNUL) ? "Master of Eternal Death" :
+ (which_god == GOD_KIKUBAAQUDGHA) ? "Lord of Darkness" :
+ (which_god == GOD_MAKHLEB) ? "Champion of Chaos" :
+ (which_god == GOD_VEHUMET) ? "Lord of Destruction" :
+ (which_god == GOD_TROG) ? "Great Slayer" :
+ (which_god == GOD_NEMELEX_XOBEH) ? "Great Trickster" :
+ (which_god == GOD_SIF_MUNA) ? "Master of Arcane" :
+ (which_god == GOD_XOM) ? "Teddy Bear" :
+ "Bogy the Lord of the Bugs"); // Xom and no god is handled before
+ }
+ else
+ {
+ //mv: most titles are still universal - if any one wants to
+ //he might write specific titles for all gods or rewrite current
+ //ones (I know they are not perfect)
+ //btw. titles are divided according to piety levels on which you get
+ //new abilities.In the main it means - new ability = new title
+ switch (which_god)
+ {
+ case GOD_ZIN:
+ case GOD_SHINING_ONE:
+ case GOD_KIKUBAAQUDGHA:
+ case GOD_YREDELEMNUL:
+ case GOD_VEHUMET:
+ case GOD_OKAWARU:
+ case GOD_MAKHLEB:
+ case GOD_SIF_MUNA:
+ //mv: what about
+ //sinner, believer, apprentice, disciple, adept, scholar, oracle
+ case GOD_TROG:
+ case GOD_NEMELEX_XOBEH:
+ case GOD_ELYVILON:
+ cprintf ( (you.piety >= 120) ? "High Priest" :
+ (you.piety >= 100) ? "Elder" :
+ (you.piety >= 75) ? "Priest" :
+ (you.piety >= 50) ? "Deacon" :
+ (you.piety >= 30) ? "Novice" :
+ (you.piety > 5) ? "Believer"
+ : "Sinner" );
+ break;
+
+ case GOD_XOM:
+ cprintf( (you.experience_level >= 20) ? "Xom's favourite toy"
+ : "Toy" );
+ break;
+
+ default:
+ cprintf ("Bug");
+ }
+ }
+ }
+ // end of print title
+
+ // mv: now let's print favor as Brent suggested
+ // I know these messages aren't perfect so if you can
+ // think up something better, do it
+
+ textcolor(LIGHTGRAY);
+ cprintf(EOL EOL "Favour - ");
+ textcolor(colour);
+
+ //mv: player is praying at altar without appropriate religion
+ //it means player isn't checking his own religion and so we only
+ //display favour and will go out
+ if (you.religion != which_god)
+ {
+ textcolor (colour);
+ snprintf( info, INFO_SIZE,
+ (you.penance[which_god] >= 50) ? "%s's wrath is upon you!" :
+ (you.penance[which_god] >= 20) ? "%s is annoyed with you." :
+ (you.penance[which_god] >= 5) ? "%s well remembers your sins." :
+ (you.penance[which_god] > 0) ? "%s is ready to forgive your sins." :
+ (you.worshipped[which_god]) ? "%s is ambivalent towards you."
+ : "%s is neutral towards you.",
+ god_name(which_god) );
+
+ cprintf(info);
+ }
+ else
+ {
+ if (player_under_penance()) //mv: penance check
+ {
+ cprintf( (you.penance[which_god] >= 50) ? "Godly wrath is upon you!" :
+ (you.penance[which_god] >= 20) ? "You've transgressed heavily! Be penitent!" :
+ (you.penance[which_god] >= 5 ) ? "You are under penance."
+ : "You should show more discipline." );
+
+ }
+ else
+ {
+ if (which_god == GOD_XOM)
+ cprintf("You are ignored.");
+ else
+ {
+ snprintf( info, INFO_SIZE,
+
+ (you.piety > 130) ? "A prized avatar of %s.":
+ (you.piety > 100) ? "A shining star in the eyes of %s." :
+ (you.piety > 70) ? "A rising star in the eyes of %s." :
+ (you.piety > 40) ? "%s is most pleased with you." :
+ (you.piety > 20) ? "%s has noted your presence." :
+ (you.piety > 5) ? "%s is noncommittal."
+ : "You are beneath notice.",
+
+ god_name(which_god)
+ );
+
+ cprintf(info);
+ }
+ }
+ //end of favour
+
+ //mv: following code shows abilities given from god (if any)
+
+
+ textcolor(LIGHTGRAY);
+ cprintf(EOL EOL "Granted powers : (Cost)" EOL);
+ textcolor(colour);
+
+
+ // mv: these gods protects you during your prayer (not mentioning XOM)
+ // chance for doing so is (random2(you.piety) >= 30)
+ // Note that it's not depending on penance.
+ // Btw. I'm not sure how to explain such divine protection
+ // because god isn't really protecting player - he only sometimes
+ // saves his life (probably it shouldn't be displayed at all).
+ // What about this ?
+ if ((which_god == GOD_ZIN
+ || which_god == GOD_SHINING_ONE
+ || which_god == GOD_ELYVILON
+ || which_god == GOD_OKAWARU
+ || which_god == GOD_YREDELEMNUL)
+ && you.piety >= 30)
+ {
+ snprintf( info, INFO_SIZE,
+ "%s %s watches over you during prayer." EOL,
+ god_name(which_god),
+ (you.piety >= 150) ? "carefully": // > 4/5
+ (you.piety >= 90) ? "often" : // > 2/3
+ "sometimes" // less than 2:3
+ );
+
+ cprintf(info);
+ }
+
+ // mv: No abilities (except divine protection)
+ // under penance (fix me if I'm wrong)
+ if (player_under_penance())
+ {
+ cprintf( "None." EOL );
+ }
+ else
+ {
+ switch (which_god) //mv: finaly let's print abilities
+ {
+ case GOD_ZIN:
+ if (you.piety >= 30)
+ print_god_abil_desc( ABIL_ZIN_REPEL_UNDEAD );
+ else
+ cprintf( "None." EOL );
+
+ if (you.piety >= 50)
+ print_god_abil_desc( ABIL_ZIN_HEALING );
+
+ if (you.piety >= 75)
+ print_god_abil_desc( ABIL_ZIN_PESTILENCE );
+
+ if (you.piety >= 100)
+ print_god_abil_desc( ABIL_ZIN_HOLY_WORD );
+
+ if (you.piety >= 120)
+ print_god_abil_desc( ABIL_ZIN_SUMMON_GUARDIAN );
+ break;
+
+ case GOD_SHINING_ONE:
+ if (you.piety >= 30)
+ print_god_abil_desc( ABIL_TSO_REPEL_UNDEAD );
+ else
+ cprintf( "None." EOL );
+
+ if (you.piety >= 50)
+ print_god_abil_desc( ABIL_TSO_SMITING );
+
+ if (you.piety >= 75)
+ print_god_abil_desc( ABIL_TSO_ANNIHILATE_UNDEAD );
+
+ if (you.piety >= 100)
+ print_god_abil_desc( ABIL_TSO_THUNDERBOLT );
+
+ if (you.piety >= 120)
+ print_god_abil_desc( ABIL_TSO_SUMMON_DAEVA );
+ break;
+
+ case GOD_KIKUBAAQUDGHA:
+ if (you.piety >= 30)
+ print_god_abil_desc( ABIL_KIKU_RECALL_UNDEAD_SLAVES );
+ else
+ cprintf( "None." EOL );
+
+ if (you.piety >= 50)
+ cprintf("You are protected from some of the side-effects of death magic." EOL);
+
+ if (you.piety >= 75)
+ print_god_abil_desc( ABIL_KIKU_ENSLAVE_UNDEAD );
+
+ if (you.piety >= 120)
+ print_god_abil_desc( ABIL_KIKU_INVOKE_DEATH );
+ break;
+
+ case GOD_YREDELEMNUL:
+ if (you.piety >= 30)
+ print_god_abil_desc( ABIL_YRED_ANIMATE_CORPSE );
+ else
+ cprintf( "None." EOL );
+
+ if (you.piety >= 50)
+ print_god_abil_desc( ABIL_YRED_RECALL_UNDEAD );
+
+ if (you.piety >= 75)
+ print_god_abil_desc( ABIL_YRED_ANIMATE_DEAD );
+
+ if (you.piety >= 100)
+ print_god_abil_desc( ABIL_YRED_DRAIN_LIFE );
+
+ if (you.piety >= 120)
+ print_god_abil_desc( ABIL_YRED_CONTROL_UNDEAD );
+ break;
+
+
+ case GOD_VEHUMET:
+ if (you.piety >= 30)
+ {
+ cprintf( "You can gain power from the those you kill " EOL
+ " in Vehumet's name, or those slain by your servants." EOL );
+ }
+ else
+ cprintf( "None." EOL );
+
+ if (you.piety >= 50)
+ cprintf( "Vehumet assists with destructive magics during prayer." EOL );
+
+ if (you.piety >= 75)
+ cprintf( "During prayer you have some protection from summoned creatures." EOL );
+
+ if (you.piety >= 100)
+ print_god_abil_desc( ABIL_VEHUMET_CHANNEL_ENERGY );
+ break;
+
+
+ case GOD_OKAWARU:
+ if (you.piety >= 30)
+ print_god_abil_desc( ABIL_OKAWARU_MIGHT );
+ else
+ cprintf( "None." EOL );
+
+ if (you.piety >= 50)
+ print_god_abil_desc( ABIL_OKAWARU_HEALING );
+
+ if (you.piety >= 120)
+ print_god_abil_desc( ABIL_OKAWARU_HASTE );
+ break;
+
+ case GOD_MAKHLEB:
+ if (you.piety >= 30)
+ {
+ cprintf( "You can gain power from the deaths " EOL
+ " of those you kill in Makhleb's name." EOL );
+ }
+ else
+ cprintf( "None." EOL );
+
+ if (you.piety >= 50)
+ print_god_abil_desc( ABIL_MAKHLEB_MINOR_DESTRUCTION );
+
+ if (you.piety >= 75)
+ print_god_abil_desc( ABIL_MAKHLEB_LESSER_SERVANT_OF_MAKHLEB );
+
+ if (you.piety >= 100)
+ print_god_abil_desc( ABIL_MAKHLEB_MAJOR_DESTRUCTION );
+
+ if (you.piety >= 120)
+ print_god_abil_desc( ABIL_MAKHLEB_GREATER_SERVANT_OF_MAKHLEB );
+ break;
+
+ case GOD_SIF_MUNA:
+ if (you.piety >= 50)
+ print_god_abil_desc( ABIL_SIF_MUNA_FORGET_SPELL );
+ else
+ cprintf( "None." EOL );
+
+ if (you.piety >= 100)
+ cprintf( "You are protected from some side-effects of spellcasting." EOL );
+ break;
+
+ case GOD_TROG:
+ if (you.piety >= 30)
+ print_god_abil_desc( ABIL_TROG_BERSERK );
+ else
+ cprintf( "None." EOL );
+
+ if (you.piety >= 50)
+ print_god_abil_desc( ABIL_TROG_MIGHT );
+
+ if (you.piety >= 100)
+ print_god_abil_desc( ABIL_TROG_HASTE_SELF );
+ break;
+
+ case GOD_ELYVILON:
+ if (you.piety >= 30)
+ print_god_abil_desc( ABIL_ELYVILON_LESSER_HEALING );
+ else
+ cprintf( "None." EOL );
+
+ if (you.piety >= 50)
+ print_god_abil_desc( ABIL_ELYVILON_PURIFICATION );
+
+ if (you.piety >= 75)
+ print_god_abil_desc( ABIL_ELYVILON_HEALING );
+
+ if (you.piety >= 100)
+ print_god_abil_desc( ABIL_ELYVILON_RESTORATION );
+
+ if (you.piety >= 120)
+ print_god_abil_desc( ABIL_ELYVILON_GREATER_HEALING );
+ break;
+
+ default: //mv: default is Xom, Nemelex and all bugs.
+ cprintf( "None." EOL );
+ } //end of printing abilities
+ }
+ }
+
+
+end_god_info: //end of everything (life, world, universe etc.)
+
+ getch(); // wait until keypressed
+
+#ifdef DOS_TERM //mv: if DOS_TERM is defined than buffer is returned to screen
+ //if not redraw_screen() is called everytime when this function is
+ //called
+ puttext(1, 1, 80, 25, buffer);
+ window(1, 1, 80, 25);
+#endif
+} //mv: That's all folks.
diff --git a/trunk/source/describe.h b/trunk/source/describe.h
new file mode 100644
index 0000000000..73037a7001
--- /dev/null
+++ b/trunk/source/describe.h
@@ -0,0 +1,58 @@
+
+/*
+ * File: describe.h
+ * Summary: Functions used to print information about various game objects.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <2> 5/21/99 BWR Changed from is_artifact to is_dumpable_artifact
+ * <1> 4/20/99 JDJ Added get_item_description and is_artifact.
+ */
+
+#ifndef DESCRIBE_H
+#define DESCRIBE_H
+
+#include <string>
+#include "externs.h"
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: chardump - spells4
+ * *********************************************************************** */
+bool is_dumpable_artifact( const item_def &item, char verbose );
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: chardump - describe
+ * *********************************************************************** */
+std::string get_item_description( const item_def &item, char verbose,
+ bool dump = false );
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - religion
+ * *********************************************************************** */
+void describe_god( int which_god, bool give_title );
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: item_use - shopping
+ * *********************************************************************** */
+void describe_item( const item_def &item );
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: direct
+ * *********************************************************************** */
+void describe_monsters(int class_described, unsigned char which_mons);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: item_use
+ * *********************************************************************** */
+void describe_spell(int spelled);
+
+#endif
diff --git a/trunk/source/direct.cc b/trunk/source/direct.cc
new file mode 100644
index 0000000000..3284ce7413
--- /dev/null
+++ b/trunk/source/direct.cc
@@ -0,0 +1,1195 @@
+/*
+ * File: direct.cc
+ * Summary: Functions used when picking squares.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <5> 01/08/01 GDL complete rewrite of direction()
+ * <4> 11/23/99 LRH Looking at monsters now
+ * displays more info
+ * <3> 5/12/99 BWR changes to allow for space selection of target.
+ * CR, ESC, and 't' in targeting.
+ * <2> 5/09/99 JDJ look_around no longer prints a prompt.
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "direct.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#include "externs.h"
+
+#include "debug.h"
+#include "describe.h"
+#include "itemname.h"
+#include "monstuff.h"
+#include "mon-util.h"
+#include "player.h"
+#include "shopping.h"
+#include "stuff.h"
+#include "spells4.h"
+#include "view.h"
+
+#ifdef USE_MACROS
+#include "macro.h"
+#endif
+
+// x and y offsets in the following order:
+// SW, S, SE, W, E, NW, N, NE
+static const char xcomp[9] = { -1, 0, 1, -1, 0, 1, -1, 0, 1 };
+static const char ycomp[9] = { 1, 1, 1, 0, 0, 0, -1, -1, -1 };
+static const char dirchars[19] = { "b1j2n3h4.5l6y7k8u9" };
+static const char DOSidiocy[10] = { "OPQKSMGHI" };
+static const char *aim_prompt = "Aim (move cursor or -/+/=, change mode with CTRL-F, select with . or >)";
+
+static void describe_cell(int mx, int my);
+static char mons_find( unsigned char xps, unsigned char yps,
+ FixedVector<char, 2> &mfp, char direction,
+ int mode = TARG_ANY );
+
+//---------------------------------------------------------------
+//
+// direction
+//
+// input: restricts : DIR_NONE accepts keypad dir or targetting
+// DIR_TARGET must use targetting.
+// DIR_DIR must use keypad direction
+//
+//
+// outputs: dist structure:
+//
+// isValid a valid target or direction was chosen
+// isCancel player hit 'escape'
+// isTarget targetting was used
+// tx,ty target x,y or logical beam extension to
+// edge of map if keypad direction used.
+// dx,dy direction delta if keypad used {-1,0,1}
+//
+// SYNOPSIS:
+//
+// gets a direction, or any of the follwing:
+//
+// * go to targetting mode
+// +,= go to targetting mode, next monster
+// - " , prev monster
+// t,p auto-select previous target
+//
+//
+// targetting mode is handled by look_around()
+//---------------------------------------------------------------
+void direction( struct dist &moves, int restrict, int mode )
+{
+ bool dirChosen = false;
+ bool targChosen = false;
+ int dir = 0;
+
+ // init
+ moves.isValid = false;
+ moves.isTarget = false;
+ moves.isMe = false;
+ moves.isCancel = false;
+ moves.dx = moves.dy = 0;
+ moves.tx = moves.ty = 0;
+
+ // XXX. this is ALWAYS in relation to the player. But a bit of a hack
+ // nonetheless! --GDL
+ gotoxy( 18, 9 );
+
+ int keyin = getch();
+
+ if (keyin == 0) // DOS idiocy (emulated by win32 console)
+ {
+ keyin = getch(); // grrr.
+ if (keyin == '*')
+ {
+ targChosen = true;
+ dir = 0;
+ }
+ else
+ {
+ if (strchr(DOSidiocy, keyin) == NULL)
+ return;
+ dirChosen = true;
+ dir = (int)(strchr(DOSidiocy, keyin) - DOSidiocy);
+ }
+ }
+ else
+ {
+ if (strchr( dirchars, keyin ) != NULL)
+ {
+ dirChosen = true;
+ dir = (int)(strchr(dirchars, keyin) - dirchars) / 2;
+ }
+ else
+ {
+ switch (keyin)
+ {
+ case CONTROL('F'):
+ mode = (mode + 1) % TARG_NUM_MODES;
+
+ snprintf( info, INFO_SIZE, "Targeting mode is now: %s",
+ (mode == TARG_ANY) ? "any" :
+ (mode == TARG_ENEMY) ? "enemies"
+ : "friends" );
+
+ mpr( info );
+
+ targChosen = true;
+ dir = 0;
+ break;
+
+ case '-':
+ targChosen = true;
+ dir = -1;
+ break;
+
+ case '*':
+ targChosen = true;
+ dir = 0;
+ break;
+
+ case '+':
+ case '=':
+ targChosen = true;
+ dir = 1;
+ break;
+
+ case 't':
+ case 'p':
+ targChosen = true;
+ dir = 2;
+ break;
+
+ case ESCAPE:
+ moves.isCancel = true;
+ return;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ // at this point, we know exactly the input - validate
+ if (!(targChosen || dirChosen) || (targChosen && restrict == DIR_DIR))
+ {
+ mpr("What an unusual direction.");
+ return;
+ }
+
+ // special case: they typed a dir key, but they're in target-only mode
+ if (dirChosen && restrict == DIR_TARGET)
+ {
+ mpr(aim_prompt);
+ look_around( moves, false, dir, mode );
+ return;
+ }
+
+ if (targChosen)
+ {
+ if (dir < 2)
+ {
+ mpr(aim_prompt);
+ moves.prev_target = dir;
+ look_around( moves, false, -1, mode );
+ if (moves.prev_target != -1) // -1 means they pressed 'p'
+ return;
+ }
+
+ // chose to aim at previous target. do we have one?
+ if (you.prev_targ == MHITNOT || you.prev_targ == MHITYOU)
+ {
+ mpr("You haven't got a target.");
+ return;
+ }
+
+ // we have a valid previous target (maybe)
+ struct monsters *montarget = &menv[you.prev_targ];
+
+ if (!mons_near(montarget) || !player_monster_visible( montarget ))
+ {
+ mpr("You can't see that creature any more.");
+ return;
+ }
+ else
+ {
+ moves.isValid = true;
+ moves.isTarget = true;
+ moves.tx = montarget->x;
+ moves.ty = montarget->y;
+ }
+ return;
+ }
+
+ // at this point, we have a direction, and direction is allowed.
+ moves.isValid = true;
+ moves.isTarget = false;
+ moves.dx = xcomp[dir];
+ moves.dy = ycomp[dir];
+ if (xcomp[dir] == 0 && ycomp[dir] == 0)
+ moves.isMe = true;
+
+ // now the tricky bit - extend the target x,y out to map edge.
+ int mx, my;
+ mx = my = 0;
+
+ if (moves.dx > 0)
+ mx = (GXM - 1) - you.x_pos;
+ if (moves.dx < 0)
+ mx = you.x_pos;
+
+ if (moves.dy > 0)
+ my = (GYM - 1) - you.y_pos;
+ if (moves.dy < 0)
+ my = you.y_pos;
+
+ if (!(mx == 0 || my == 0))
+ {
+ if (mx < my)
+ my = mx;
+ else
+ mx = my;
+ }
+ moves.tx = you.x_pos + moves.dx * mx;
+ moves.ty = you.y_pos + moves.dy * my;
+}
+
+//---------------------------------------------------------------
+//
+// look_around
+//
+// Accessible by the x key and when using cursor aiming. Lets you
+// find out what symbols mean, and is the way to access monster
+// descriptions.
+//
+// input: dist.prev_target : -1 is last monster
+// 0 is no monster selected
+// 1 is next monster
+//
+// input: first_move is -1 if no initial cursor move, otherwise
+// make 1 move in that direction.
+//
+//
+// output: if dist.prev_target is -1 on OUTPUT, it means that
+// player selected 'p' ot 't' for last targetted monster.
+//
+// otherwise, usual dist fields are filled in (dx and dy are
+// always zero coming back from this function)
+//
+//---------------------------------------------------------------
+
+void look_around(struct dist &moves, bool justLooking, int first_move, int mode)
+{
+ int keyin = 0;
+ bool dirChosen = false;
+ bool targChosen = false;
+ int dir = 0;
+ int cx = 17;
+ int cy = 9;
+ int newcx, newcy;
+ int mx, my; // actual map x,y (scratch)
+ int mid; // monster id (scratch)
+ FixedVector < char, 2 > monsfind_pos;
+
+ monsfind_pos[0] = you.x_pos;
+ monsfind_pos[1] = you.y_pos;
+
+ message_current_target();
+
+ // setup initial keystroke
+ if (first_move >= 0)
+ keyin = (int)'1' + first_move;
+ if (moves.prev_target == -1)
+ keyin = '-';
+ if (moves.prev_target == 1)
+ keyin = '+';
+ // reset
+ moves.prev_target = 0;
+
+ // loop until some exit criteria reached
+ while(true)
+ {
+ dirChosen = false;
+ targChosen = false;
+ newcx = cx;
+ newcy = cy;
+
+ // move cursor to current position
+ gotoxy(cx+1, cy);
+
+ if (keyin == 0)
+ keyin = getch();
+
+ // DOS idiocy
+ if (keyin == 0)
+ {
+ // get the extended key
+ keyin = getch();
+
+ // look for CR - change to '5' to indicate selection
+ if (keyin == 13)
+ keyin = 'S';
+
+ if (strchr(DOSidiocy, keyin) == NULL)
+ break;
+ dirChosen = true;
+ dir = (int)(strchr(DOSidiocy, keyin) - DOSidiocy);
+ }
+ else
+ {
+ if (strchr(dirchars, keyin) != NULL)
+ {
+ dirChosen = true;
+ dir = (int)(strchr(dirchars, keyin) - dirchars) / 2;
+ }
+ else
+ {
+ // handle non-directional keys
+ switch (keyin)
+ {
+ case CONTROL('F'):
+ mode = (mode + 1) % TARG_NUM_MODES;
+
+ snprintf( info, INFO_SIZE, "Targeting mode is now: %s",
+ (mode == TARG_ANY) ? "any" :
+ (mode == TARG_ENEMY) ? "enemies"
+ : "friends" );
+
+ mpr( info );
+ targChosen = true;
+ break;
+
+ case '-':
+ if (mons_find( cx, cy, monsfind_pos, -1, mode ) == 0)
+ flush_input_buffer( FLUSH_ON_FAILURE );
+ else
+ {
+ newcx = monsfind_pos[0];
+ newcy = monsfind_pos[1];
+ }
+ targChosen = true;
+ break;
+
+ case '+':
+ case '=':
+ if (mons_find( cx, cy, monsfind_pos, 1, mode ) == 0)
+ flush_input_buffer( FLUSH_ON_FAILURE );
+ else
+ {
+ newcx = monsfind_pos[0];
+ newcy = monsfind_pos[1];
+ }
+ targChosen = true;
+ break;
+
+ case 't':
+ case 'p':
+ moves.prev_target = -1;
+ break;
+
+ case '?':
+ targChosen = true;
+ mx = you.x_pos + cx - 17;
+ my = you.y_pos + cy - 9;
+ mid = mgrd[mx][my];
+
+ if (mid == NON_MONSTER)
+ break;
+
+#if (!DEBUG_DIAGNOSTICS)
+ if (!player_monster_visible( &menv[mid] ))
+ break;
+#endif
+
+ describe_monsters( menv[ mid ].type, mid );
+ redraw_screen();
+ mesclr( true );
+ // describe the cell again.
+ describe_cell(you.x_pos + cx - 17, you.y_pos + cy - 9);
+ break;
+
+ case '\r':
+ case '\n':
+ case '>':
+ case ' ':
+ case '.':
+ dirChosen = true;
+ dir = 4;
+ break;
+
+ case ESCAPE:
+ moves.isCancel = true;
+ mesclr( true );
+ return;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ // now we have parsed the input character completely. Reset & Evaluate:
+ keyin = 0;
+ if (!targChosen && !dirChosen)
+ break;
+
+ // check for SELECTION
+ if (dirChosen && dir == 4)
+ {
+ // RULE: cannot target what you cannot see
+ if (env.show[cx - 8][cy] == 0 && !(cx == 17 && cy == 9))
+ {
+ if (!justLooking)
+ mpr("Sorry, you can't target what you can't see.");
+ return;
+ }
+
+ moves.isValid = true;
+ moves.isTarget = true;
+ moves.tx = you.x_pos + cx - 17;
+ moves.ty = you.y_pos + cy - 9;
+
+ if (moves.tx == you.x_pos && moves.ty == you.y_pos)
+ moves.isMe = true;
+ else
+ {
+ // try to set you.previous target
+ mx = you.x_pos + cx - 17;
+ my = you.y_pos + cy - 9;
+ mid = mgrd[mx][my];
+
+ if (mid == NON_MONSTER)
+ break;
+
+ if (!player_monster_visible( &(menv[mid]) ))
+ break;
+
+ you.prev_targ = mid;
+ }
+ break;
+ }
+
+ // check for MOVE
+ if (dirChosen)
+ {
+ newcx = cx + xcomp[dir];
+ newcy = cy + ycomp[dir];
+ }
+
+ // bounds check for newcx, newcy
+ if (newcx < 9) newcx = 9;
+ if (newcx > 25) newcx = 25;
+ if (newcy < 1) newcy = 1;
+ if (newcy > 17) newcy = 17;
+
+ // no-op if the cursor doesn't move.
+ if (newcx == cx && newcy == cy)
+ continue;
+
+ // CURSOR MOVED - describe new cell.
+ cx = newcx;
+ cy = newcy;
+ mesclr( true );
+ if (env.show[cx - 8][cy] == 0 && !(cx == 17 && cy == 9))
+ {
+ mpr("You can't see that place.");
+ continue;
+ }
+ describe_cell(you.x_pos + cx - 17, you.y_pos + cy - 9);
+ } // end WHILE
+
+ mesclr( true );
+} // end look_around()
+
+//---------------------------------------------------------------
+//
+// mons_find
+//
+// Finds the next monster (moving in a spiral outwards from the
+// player, so closer monsters are chosen first; starts to player's
+// left) and puts its coordinates in mfp. Returns 1 if it found
+// a monster, zero otherwise. If direction is -1, goes backwards.
+//
+//---------------------------------------------------------------
+static char mons_find( unsigned char xps, unsigned char yps,
+ FixedVector<char, 2> &mfp, char direction, int mode )
+{
+ unsigned char temp_xps = xps;
+ unsigned char temp_yps = yps;
+ char x_change = 0;
+ char y_change = 0;
+
+ int i, j;
+
+ if (direction == 1 && temp_xps == 9 && temp_yps == 17)
+ return (0); // end of spiral
+
+ while (temp_xps >= 8 && temp_xps <= 25 && temp_yps <= 17) // yps always >= 0
+ {
+ if (direction == -1 && temp_xps == 17 && temp_yps == 9)
+ return (0); // can't go backwards from you
+
+ if (direction == 1)
+ {
+ if (temp_xps == 8)
+ {
+ x_change = 0;
+ y_change = -1;
+ }
+ else if (temp_xps - 17 == 0 && temp_yps - 9 == 0)
+ {
+ x_change = -1;
+ y_change = 0;
+ }
+ else if (abs(temp_xps - 17) <= abs(temp_yps - 9))
+ {
+ if (temp_xps - 17 >= 0 && temp_yps - 9 <= 0)
+ {
+ if (abs(temp_xps - 17) > abs(temp_yps - 9 + 1))
+ {
+ x_change = 0;
+ y_change = -1;
+ if (temp_xps - 17 > 0)
+ y_change = 1;
+ goto finished_spiralling;
+ }
+ }
+ x_change = -1;
+ if (temp_yps - 9 < 0)
+ x_change = 1;
+ y_change = 0;
+ }
+ else
+ {
+ x_change = 0;
+ y_change = -1;
+ if (temp_xps - 17 > 0)
+ y_change = 1;
+ }
+ } // end if (direction == 1)
+ else
+ {
+ /*
+ This part checks all eight surrounding squares to find the
+ one that leads on to the present square.
+ */
+ for (i = -1; i < 2; i++)
+ {
+ for (j = -1; j < 2; j++)
+ {
+ if (i == 0 && j == 0)
+ continue;
+
+ if (temp_xps + i == 8)
+ {
+ x_change = 0;
+ y_change = -1;
+ }
+ else if (temp_xps + i - 17 == 0 && temp_yps + j - 9 == 0)
+ {
+ x_change = -1;
+ y_change = 0;
+ }
+ else if (abs(temp_xps + i - 17) <= abs(temp_yps + j - 9))
+ {
+ const int xi = temp_xps + i - 17;
+ const int yj = temp_yps + j - 9;
+
+ if (xi >= 0 && yj <= 0)
+ {
+ if (abs(xi) > abs(yj + 1))
+ {
+ x_change = 0;
+ y_change = -1;
+ if (xi > 0)
+ y_change = 1;
+ goto finished_spiralling;
+ }
+ }
+
+ x_change = -1;
+ if (yj < 0)
+ x_change = 1;
+ y_change = 0;
+ }
+ else
+ {
+ x_change = 0;
+ y_change = -1;
+ if (temp_xps + i - 17 > 0)
+ y_change = 1;
+ }
+
+ if (temp_xps + i + x_change == temp_xps
+ && temp_yps + j + y_change == temp_yps)
+ {
+ goto finished_spiralling;
+ }
+ }
+ }
+ } // end else
+
+
+ finished_spiralling:
+ x_change *= direction;
+ y_change *= direction;
+
+ temp_xps += x_change;
+ if (temp_yps + y_change <= 17) // it can wrap, unfortunately
+ temp_yps += y_change;
+
+ const int targ_x = you.x_pos + temp_xps - 17;
+ const int targ_y = you.y_pos + temp_yps - 9;
+
+ // We don't want to be looking outside the bounds of the arrays:
+ if (temp_xps > 25 || temp_xps < 8 || temp_yps > 17 || temp_yps < 1)
+ continue;
+
+ if (targ_x < 0 || targ_x >= GXM || targ_y < 0 || targ_y >= GYM)
+ continue;
+
+ const int targ_mon = mgrd[ targ_x ][ targ_y ];
+
+ if (targ_mon != NON_MONSTER
+ && env.show[temp_xps - 8][temp_yps] != 0
+ && player_monster_visible( &(menv[targ_mon]) )
+ && !mons_is_mimic( menv[targ_mon].type )
+ && (mode == TARG_ANY
+ || (mode == TARG_FRIEND && mons_friendly( &menv[targ_mon] ))
+ || (mode == TARG_ENEMY && !mons_friendly( &menv[targ_mon] ))))
+ {
+ //mpr("Found something!");
+ //more();
+ mfp[0] = temp_xps;
+ mfp[1] = temp_yps;
+ return (1);
+ }
+ }
+
+ return (0);
+}
+
+static void describe_cell(int mx, int my)
+{
+ int trf; // used for trap type??
+ char str_pass[ ITEMNAME_SIZE ];
+ bool mimic_item = false;
+
+ if (mgrd[mx][my] != NON_MONSTER)
+ {
+ int i = mgrd[mx][my];
+
+ if (grd[mx][my] == DNGN_SHALLOW_WATER)
+ {
+ if (!player_monster_visible(&menv[i]) && !mons_flies(&menv[i]))
+ {
+ mpr("There is a strange disturbance in the water here.");
+ }
+ }
+
+#if DEBUG_DIAGNOSTICS
+ if (!player_monster_visible( &menv[i] ))
+ mpr( "There is a non-visible monster here.", MSGCH_DIAGNOSTICS );
+#else
+ if (!player_monster_visible( &menv[i] ))
+ goto look_clouds;
+#endif
+
+ const int mon_wep = menv[i].inv[MSLOT_WEAPON];
+ const int mon_arm = menv[i].inv[MSLOT_ARMOUR];
+
+ strcpy(info, ptr_monam( &(menv[i]), DESC_CAP_A ));
+ strcat(info, ".");
+ mpr(info);
+
+ if (menv[i].type != MONS_DANCING_WEAPON && mon_wep != NON_ITEM)
+ {
+ snprintf( info, INFO_SIZE, "%s is wielding ", mons_pronoun( menv[i].type,
+ PRONOUN_CAP ));
+ it_name(mon_wep, DESC_NOCAP_A, str_pass);
+ strcat(info, str_pass);
+
+ // 2-headed ogres can wield 2 weapons
+ if ((menv[i].type == MONS_TWO_HEADED_OGRE
+ || menv[i].type == MONS_ETTIN)
+ && menv[i].inv[MSLOT_MISSILE] != NON_ITEM)
+ {
+ strcat( info, " and " );
+ it_name(menv[i].inv[MSLOT_MISSILE], DESC_NOCAP_A, str_pass);
+ strcat(info, str_pass);
+ strcat(info, ".");
+
+ mpr(info);
+ }
+ else
+ {
+ strcat(info, ".");
+ mpr(info);
+ }
+ }
+
+ if (mon_arm != NON_ITEM)
+ {
+ it_name( mon_arm, DESC_PLAIN, str_pass );
+ snprintf( info, INFO_SIZE, "%s is wearing %s.",
+ mons_pronoun( menv[i].type, PRONOUN_CAP ),
+ str_pass );
+
+ mpr( info );
+ }
+
+
+ if (menv[i].type == MONS_HYDRA)
+ {
+ snprintf( info, INFO_SIZE, "It has %d heads.", menv[i].number );
+ mpr( info );
+ }
+
+ print_wounds(&menv[i]);
+
+
+ if (mons_is_mimic( menv[i].type ))
+ mimic_item = true;
+ else if (!mons_flag(menv[i].type, M_NO_EXP_GAIN))
+ {
+ if (menv[i].behaviour == BEH_SLEEP)
+ {
+ strcpy(info, mons_pronoun(menv[i].type, PRONOUN_CAP));
+ strcat(info, " doesn't appear to have noticed you.");
+ mpr(info);
+ }
+ // wandering hostile with no target in LOS
+ else if (menv[i].behaviour == BEH_WANDER && !mons_friendly(&menv[i])
+ && menv[i].foe == MHITNOT)
+ {
+ // special case: batty monsters get set to BEH_WANDER as
+ // part of their special behaviour.
+ if (!testbits(menv[i].flags, MF_BATTY))
+ {
+ strcpy(info, mons_pronoun(menv[i].type, PRONOUN_CAP));
+ strcat(info, " doesn't appear to be interested in you.");
+ mpr(info);
+ }
+ }
+ }
+
+ if (menv[i].attitude == ATT_FRIENDLY)
+ {
+ strcpy(info, mons_pronoun(menv[i].type, PRONOUN_CAP));
+ strcat(info, " is friendly.");
+ mpr(info);
+ }
+
+ for (int p = 0; p < NUM_MON_ENCHANTS; p++)
+ {
+ strcpy(info, mons_pronoun(menv[i].type, PRONOUN_CAP));
+ switch (menv[i].enchantment[p])
+ {
+ case ENCH_YOUR_ROT_I:
+ case ENCH_YOUR_ROT_II:
+ case ENCH_YOUR_ROT_III:
+ case ENCH_YOUR_ROT_IV:
+ strcat(info, " is rotting away."); //jmf: "covered in sores"?
+ break;
+ case ENCH_BACKLIGHT_I:
+ case ENCH_BACKLIGHT_II:
+ case ENCH_BACKLIGHT_III:
+ case ENCH_BACKLIGHT_IV:
+ strcat(info, " is softly glowing.");
+ break;
+ case ENCH_SLOW:
+ strcat(info, " is moving slowly.");
+ break;
+ case ENCH_HASTE:
+ strcat(info, " is moving very quickly.");
+ break;
+ case ENCH_CONFUSION:
+ strcat(info, " appears to be bewildered and confused.");
+ break;
+ case ENCH_INVIS:
+ strcat(info, " is slightly transparent.");
+ break;
+ case ENCH_CHARM:
+ strcat(info, " is in your thrall.");
+ break;
+ case ENCH_YOUR_STICKY_FLAME_I:
+ case ENCH_YOUR_STICKY_FLAME_II:
+ case ENCH_YOUR_STICKY_FLAME_III:
+ case ENCH_YOUR_STICKY_FLAME_IV:
+ case ENCH_STICKY_FLAME_I:
+ case ENCH_STICKY_FLAME_II:
+ case ENCH_STICKY_FLAME_III:
+ case ENCH_STICKY_FLAME_IV:
+ strcat(info, " is covered in liquid flames.");
+ break;
+ default:
+ info[0] = '\0';
+ break;
+ } // end switch
+ if (info[0])
+ mpr(info);
+ }
+
+#if DEBUG_DIAGNOSTICS
+ stethoscope(i);
+#endif
+ }
+
+#if (!DEBUG_DIAGNOSTICS)
+ // removing warning
+ look_clouds:
+#endif
+ if (env.cgrid[mx][my] != EMPTY_CLOUD)
+ {
+ const char cloud_inspected = env.cgrid[mx][my];
+
+ const char cloud_type = env.cloud[ cloud_inspected ].type;
+
+ strcpy(info, "There is a cloud of ");
+ strcat(info,
+ (cloud_type == CLOUD_FIRE
+ || cloud_type == CLOUD_FIRE_MON) ? "flame" :
+ (cloud_type == CLOUD_STINK
+ || cloud_type == CLOUD_STINK_MON) ? "noxious fumes" :
+ (cloud_type == CLOUD_COLD
+ || cloud_type == CLOUD_COLD_MON) ? "freezing vapour" :
+ (cloud_type == CLOUD_POISON
+ || cloud_type == CLOUD_POISON_MON) ? "poison gases" :
+ (cloud_type == CLOUD_GREY_SMOKE
+ || cloud_type == CLOUD_GREY_SMOKE_MON) ? "grey smoke" :
+ (cloud_type == CLOUD_BLUE_SMOKE
+ || cloud_type == CLOUD_BLUE_SMOKE_MON) ? "blue smoke" :
+ (cloud_type == CLOUD_PURP_SMOKE
+ || cloud_type == CLOUD_PURP_SMOKE_MON) ? "purple smoke" :
+ (cloud_type == CLOUD_STEAM
+ || cloud_type == CLOUD_STEAM_MON) ? "steam" :
+ (cloud_type == CLOUD_MIASMA
+ || cloud_type == CLOUD_MIASMA_MON) ? "foul pestilence" :
+ (cloud_type == CLOUD_BLACK_SMOKE
+ || cloud_type == CLOUD_BLACK_SMOKE_MON) ? "black smoke"
+ : "buggy goodness");
+ strcat(info, " here.");
+ mpr(info);
+ }
+
+ int targ_item = igrd[ mx ][ my ];
+
+ if (targ_item != NON_ITEM)
+ {
+ // If a mimic is on this square, we pretend its the first item -- bwr
+ if (mimic_item)
+ mpr("There is something else lying underneath.");
+ else
+ {
+ if (mitm[ targ_item ].base_type == OBJ_GOLD)
+ {
+ mpr( "A pile of gold coins." );
+ }
+ else
+ {
+ strcpy(info, "You see ");
+ it_name( targ_item, DESC_NOCAP_A, str_pass);
+ strcat(info, str_pass);
+ strcat(info, " here.");
+ mpr(info);
+ }
+
+ if (mitm[ targ_item ].link != NON_ITEM)
+ mpr("There is something else lying underneath.");
+ }
+ }
+
+ switch (grd[mx][my])
+ {
+ case DNGN_STONE_WALL:
+ mpr("A stone wall.");
+ break;
+ case DNGN_ROCK_WALL:
+ case DNGN_SECRET_DOOR:
+ if (you.level_type == LEVEL_PANDEMONIUM)
+ mpr("A wall of the weird stuff which makes up Pandemonium.");
+ else
+ mpr("A rock wall.");
+ break;
+ case DNGN_PERMAROCK_WALL:
+ mpr("An unnaturally hard rock wall.");
+ break;
+ case DNGN_CLOSED_DOOR:
+ mpr("A closed door.");
+ break;
+ case DNGN_METAL_WALL:
+ mpr("A metal wall.");
+ break;
+ case DNGN_GREEN_CRYSTAL_WALL:
+ mpr("A wall of green crystal.");
+ break;
+ case DNGN_ORCISH_IDOL:
+ mpr("An orcish idol.");
+ break;
+ case DNGN_WAX_WALL:
+ mpr("A wall of solid wax.");
+ break;
+ case DNGN_SILVER_STATUE:
+ mpr("A silver statue.");
+ break;
+ case DNGN_GRANITE_STATUE:
+ mpr("A granite statue.");
+ break;
+ case DNGN_ORANGE_CRYSTAL_STATUE:
+ mpr("An orange crystal statue.");
+ break;
+ case DNGN_LAVA:
+ mpr("Some lava.");
+ break;
+ case DNGN_DEEP_WATER:
+ mpr("Some deep water.");
+ break;
+ case DNGN_SHALLOW_WATER:
+ mpr("Some shallow water.");
+ break;
+ case DNGN_UNDISCOVERED_TRAP:
+ case DNGN_FLOOR:
+ mpr("Floor.");
+ break;
+ case DNGN_OPEN_DOOR:
+ mpr("An open door.");
+ break;
+ case DNGN_ROCK_STAIRS_DOWN:
+ mpr("A rock staircase leading down.");
+ break;
+ case DNGN_STONE_STAIRS_DOWN_I:
+ case DNGN_STONE_STAIRS_DOWN_II:
+ case DNGN_STONE_STAIRS_DOWN_III:
+ mpr("A stone staircase leading down.");
+ break;
+ case DNGN_ROCK_STAIRS_UP:
+ mpr("A rock staircase leading upwards.");
+ break;
+ case DNGN_STONE_STAIRS_UP_I:
+ case DNGN_STONE_STAIRS_UP_II:
+ case DNGN_STONE_STAIRS_UP_III:
+ mpr("A stone staircase leading up.");
+ break;
+ case DNGN_ENTER_HELL:
+ mpr("A gateway to hell.");
+ break;
+ case DNGN_BRANCH_STAIRS:
+ mpr("A staircase to a branch level.");
+ break;
+ case DNGN_TRAP_MECHANICAL:
+ case DNGN_TRAP_MAGICAL:
+ case DNGN_TRAP_III:
+ for (trf = 0; trf < MAX_TRAPS; trf++)
+ {
+ if (env.trap[trf].x == mx
+ && env.trap[trf].y == my)
+ {
+ break;
+ }
+
+ if (trf == MAX_TRAPS - 1)
+ {
+ mpr("Error - couldn't find that trap.");
+ error_message_to_player();
+ break;
+ }
+ }
+
+ switch (env.trap[trf].type)
+ {
+ case TRAP_DART:
+ mpr("A dart trap.");
+ break;
+ case TRAP_ARROW:
+ mpr("An arrow trap.");
+ break;
+ case TRAP_SPEAR:
+ mpr("A spear trap.");
+ break;
+ case TRAP_AXE:
+ mpr("An axe trap.");
+ break;
+ case TRAP_TELEPORT:
+ mpr("A teleportation trap.");
+ break;
+ case TRAP_AMNESIA:
+ mpr("An amnesia trap.");
+ break;
+ case TRAP_BLADE:
+ mpr("A blade trap.");
+ break;
+ case TRAP_BOLT:
+ mpr("A bolt trap.");
+ break;
+ case TRAP_ZOT:
+ mpr("A Zot trap.");
+ break;
+ case TRAP_NEEDLE:
+ mpr("A needle trap.");
+ break;
+ default:
+ mpr("An undefined trap. Huh?");
+ error_message_to_player();
+ break;
+ }
+ break;
+ case DNGN_ENTER_SHOP:
+ mpr(shop_name(mx, my));
+ break;
+ case DNGN_ENTER_LABYRINTH:
+ mpr("A labyrinth entrance.");
+ break;
+ case DNGN_ENTER_DIS:
+ mpr("A gateway to the Iron City of Dis.");
+ break;
+ case DNGN_ENTER_GEHENNA:
+ mpr("A gateway to Gehenna.");
+ break;
+ case DNGN_ENTER_COCYTUS:
+ mpr("A gateway to the freezing wastes of Cocytus.");
+ break;
+ case DNGN_ENTER_TARTARUS:
+ mpr("A gateway to the decaying netherworld of Tartarus.");
+ break;
+ case DNGN_ENTER_ABYSS:
+ mpr("A gateway to the infinite Abyss.");
+ break;
+ case DNGN_EXIT_ABYSS:
+ mpr("A gateway leading out of the Abyss.");
+ break;
+ case DNGN_STONE_ARCH:
+ mpr("An empty arch of ancient stone.");
+ break;
+ case DNGN_ENTER_PANDEMONIUM:
+ mpr("A gate leading to the halls of Pandemonium.");
+ break;
+ case DNGN_EXIT_PANDEMONIUM:
+ mpr("A gate leading out of Pandemonium.");
+ break;
+ case DNGN_TRANSIT_PANDEMONIUM:
+ mpr("A gate leading to another region of Pandemonium.");
+ break;
+ case DNGN_ENTER_ORCISH_MINES:
+ mpr("A staircase to the Orcish Mines.");
+ break;
+ case DNGN_ENTER_HIVE:
+ mpr("A staircase to the Hive.");
+ break;
+ case DNGN_ENTER_LAIR:
+ mpr("A staircase to the Lair.");
+ break;
+ case DNGN_ENTER_SLIME_PITS:
+ mpr("A staircase to the Slime Pits.");
+ break;
+ case DNGN_ENTER_VAULTS:
+ mpr("A staircase to the Vaults.");
+ break;
+ case DNGN_ENTER_CRYPT:
+ mpr("A staircase to the Crypt.");
+ break;
+ case DNGN_ENTER_HALL_OF_BLADES:
+ mpr("A staircase to the Hall of Blades.");
+ break;
+ case DNGN_ENTER_ZOT:
+ mpr("A gate to the Realm of Zot.");
+ break;
+ case DNGN_ENTER_TEMPLE:
+ mpr("A staircase to the Ecumenical Temple.");
+ break;
+ case DNGN_ENTER_SNAKE_PIT:
+ mpr("A staircase to the Snake Pit.");
+ break;
+ case DNGN_ENTER_ELVEN_HALLS:
+ mpr("A staircase to the Elven Halls.");
+ break;
+ case DNGN_ENTER_TOMB:
+ mpr("A staircase to the Tomb.");
+ break;
+ case DNGN_ENTER_SWAMP:
+ mpr("A staircase to the Swamp.");
+ break;
+ case DNGN_RETURN_FROM_ORCISH_MINES:
+ case DNGN_RETURN_FROM_HIVE:
+ case DNGN_RETURN_FROM_LAIR:
+ case DNGN_RETURN_FROM_VAULTS:
+ case DNGN_RETURN_FROM_TEMPLE:
+ mpr("A staircase back to the Dungeon.");
+ break;
+ case DNGN_RETURN_FROM_SLIME_PITS:
+ case DNGN_RETURN_FROM_SNAKE_PIT:
+ case DNGN_RETURN_FROM_SWAMP:
+ mpr("A staircase back to the Lair.");
+ break;
+ case DNGN_RETURN_FROM_CRYPT:
+ case DNGN_RETURN_FROM_HALL_OF_BLADES:
+ mpr("A staircase back to the Vaults.");
+ break;
+ case DNGN_RETURN_FROM_ELVEN_HALLS:
+ mpr("A staircase back to the Mines.");
+ break;
+ case DNGN_RETURN_FROM_TOMB:
+ mpr("A staircase back to the Crypt.");
+ break;
+ case DNGN_RETURN_FROM_ZOT:
+ mpr("A gate leading back out of this place.");
+ break;
+ case DNGN_ALTAR_ZIN:
+ mpr("A glowing white marble altar of Zin.");
+ break;
+ case DNGN_ALTAR_SHINING_ONE:
+ mpr("A glowing golden altar of the Shining One.");
+ break;
+ case DNGN_ALTAR_KIKUBAAQUDGHA:
+ mpr("An ancient bone altar of Kikubaaqudgha.");
+ break;
+ case DNGN_ALTAR_YREDELEMNUL:
+ mpr("A basalt altar of Yredelemnul.");
+ break;
+ case DNGN_ALTAR_XOM:
+ mpr("A shimmering altar of Xom.");
+ break;
+ case DNGN_ALTAR_VEHUMET:
+ mpr("A shining altar of Vehumet.");
+ break;
+ case DNGN_ALTAR_OKAWARU:
+ mpr("An iron altar of Okawaru.");
+ break;
+ case DNGN_ALTAR_MAKHLEB:
+ mpr("A burning altar of Makhleb.");
+ break;
+ case DNGN_ALTAR_SIF_MUNA:
+ mpr("A deep blue altar of Sif Muna.");
+ break;
+ case DNGN_ALTAR_TROG:
+ mpr("A bloodstained altar of Trog.");
+ break;
+ case DNGN_ALTAR_NEMELEX_XOBEH:
+ mpr("A sparkling altar of Nemelex Xobeh.");
+ break;
+ case DNGN_ALTAR_ELYVILON:
+ mpr("A silver altar of Elyvilon.");
+ break;
+ case DNGN_BLUE_FOUNTAIN:
+ mpr("A fountain of clear blue water.");
+ break;
+ case DNGN_SPARKLING_FOUNTAIN:
+ mpr("A fountain of sparkling water.");
+ break;
+ case DNGN_DRY_FOUNTAIN_I:
+ case DNGN_DRY_FOUNTAIN_II:
+ case DNGN_DRY_FOUNTAIN_IV:
+ case DNGN_DRY_FOUNTAIN_VI:
+ case DNGN_DRY_FOUNTAIN_VIII:
+ case DNGN_PERMADRY_FOUNTAIN:
+ mpr("A dry fountain.");
+ break;
+ }
+}
diff --git a/trunk/source/direct.h b/trunk/source/direct.h
new file mode 100644
index 0000000000..2bd5a06cdd
--- /dev/null
+++ b/trunk/source/direct.h
@@ -0,0 +1,41 @@
+/*
+ * File: direct.cc
+ * Summary: Functions used when picking squares.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef DIRECT_H
+#define DIRECT_H
+
+#include "externs.h"
+#include "enum.h"
+
+#define STD_DIRECTION_PROMPT "Which direction ([*+-] to target)? "
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - debug - effects - it_use3 - item_use - spells1 -
+ * spells2 - spells3 - spells4
+ * *********************************************************************** */
+
+#define DIR_NONE 0
+#define DIR_TARGET 1
+#define DIR_DIR 2
+
+void direction( struct dist &moves, int restricts = DIR_NONE,
+ int mode = TARG_ANY );
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - direct
+ * *********************************************************************** */
+void look_around( struct dist &moves, bool justLooking, int first_move = -1,
+ int mode = TARG_ANY );
+
+
+#endif
diff --git a/trunk/source/dungeon.cc b/trunk/source/dungeon.cc
new file mode 100644
index 0000000000..c899daa7dc
--- /dev/null
+++ b/trunk/source/dungeon.cc
@@ -0,0 +1,8446 @@
+/*
+ * File: dungeon.cc
+ * Summary: Functions used when building new levels.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ *
+ * <9> 07-Aug-2001 MV clean up of give_item; distribution of
+ * wands, potions and scrolls
+ * underground rivers and lakes
+ * <8> 02-Apr-2001 gdl cleanup; nuked all globals
+ * <7> 06-Mar-2000 bwr reduced vorpal weapon freq,
+ * spellbooks now hold up to eight spells.
+ * <6> 11/06/99 cdl random3 -> random2
+ * <5> 8/08/99 BWR Upped rarity of unique artefacts
+ * <4> 7/13/99 BWR Made pole arms of speed.
+ * <3> 5/22/99 BWR Made named artefact weapons
+ * rarer, Sword of Power esp.
+ * <2> 5/09/99 LRH Replaced some sanity checking code in
+ * spellbook_template with a corrected version
+ * using ASSERTs.
+ * <1> -/--/-- LRH Created
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+#include "AppHdr.h"
+#include "abyss.h"
+#include "defines.h"
+#include "enum.h"
+#include "externs.h"
+#include "dungeon.h"
+#include "itemname.h"
+#include "items.h"
+#include "maps.h"
+#include "mon-util.h"
+#include "mon-pick.h"
+#include "monplace.h"
+#include "player.h"
+#include "randart.h"
+#include "spl-book.h"
+#include "stuff.h"
+#include "wpn-misc.h"
+
+struct spec_t {
+ bool created;
+ bool hooked_up;
+ int x1;
+ int y1;
+ int x2;
+ int y2;
+};
+
+typedef struct spec_t spec_room;
+
+// DUNGEON BUILDERS
+static bool find_in_area(int sx, int sy, int ex, int ey, unsigned char feature);
+static bool make_box(int room_x1, int room_y1, int room_x2, int room_y2,
+ unsigned char floor=0, unsigned char wall=0, unsigned char avoid=0);
+static void replace_area(int sx, int sy, int ex, int ey, unsigned char replace,
+ unsigned char feature);
+static int builder_by_type(int level_number, char level_type);
+static int builder_by_branch(int level_number);
+static int builder_normal(int level_number, char level_type, spec_room &s);
+static int builder_basic(int level_number);
+static void builder_extras(int level_number, int level_type);
+static void builder_items(int level_number, char level_type, int items_wanted);
+static void builder_monsters(int level_number, char level_type, int mon_wanted);
+static void place_specific_stair(unsigned char stair);
+static void place_branch_entrances(int dlevel, char level_type);
+static bool place_specific_trap(unsigned char spec_x, unsigned char spec_y,
+ unsigned char spec_type);
+static void place_traps( int level_number );
+static void prepare_swamp(void);
+static void prepare_water( int level_number );
+static void check_doors(void);
+static void hide_doors(void);
+static void make_trail(int xs, int xr, int ys, int yr,int corrlength, int intersect_chance,
+ int no_corr, unsigned char begin, unsigned char end=0);
+static bool make_room(int sx,int sy,int ex,int ey,int max_doors, int doorlevel);
+static void join_the_dots(unsigned char dotx1, unsigned char doty1,
+ unsigned char dotx2, unsigned char doty2, char forbid_x1, char forbid_y1,
+ char forbid_x2, char forbid_y2);
+static void place_pool(unsigned char pool_type, unsigned char pool_x1,
+ unsigned char pool_y1, unsigned char pool_x2,
+ unsigned char pool_y2);
+static void many_pools(unsigned char pool_type);
+
+#ifdef USE_RIVERS
+static void build_river(unsigned char river_type); //mv
+static void build_lake(unsigned char lake_type); //mv
+#endif // USE_RIVERS
+
+static void spotty_level(bool seeded, int iterations, bool boxy);
+static void bigger_room(void);
+static void plan_main(int level_number, char force_plan);
+static char plan_1(void);
+static char plan_2(void);
+static char plan_3(void);
+static char plan_4(char forbid_x1, char forbid_y1, char forbid_x2,
+ char forbid_y2, unsigned char force_wall);
+static char plan_5(void);
+static char plan_6(int level_number);
+static bool octa_room(spec_room &sr, int oblique_max, unsigned char type_floor);
+static void labyrinth_level(int level_number);
+static void box_room(int bx1, int bx2, int by1, int by2, int wall_type);
+static int box_room_doors( int bx1, int bx2, int by1, int by2, int new_doors);
+static void city_level(int level_number);
+static void diamond_rooms(int level_number);
+
+// ITEM & SHOP FUNCTIONS
+static void place_shops(int level_number);
+static void place_spec_shop(int level_number, unsigned char shop_x,
+ unsigned char shop_y, unsigned char force_s_type);
+static unsigned char item_in_shop(unsigned char shop_type);
+static bool treasure_area(int level_number, unsigned char ta1_x,
+ unsigned char ta2_x, unsigned char ta1_y,
+ unsigned char ta2_y);
+static char rare_weapon(unsigned char w_type);
+static bool is_weapon_special(int the_weapon);
+static void set_weapon_special(int the_weapon, int spwpn);
+static void big_room(int level_number);
+static void chequerboard(spec_room &sr, unsigned char
+ target, unsigned char floor1, unsigned char floor2);
+static void roguey_level(int level_number, spec_room &sr);
+static void morgue(spec_room &sr);
+
+// SPECIAL ROOM BUILDERS
+static void special_room(int level_number, spec_room &sr);
+static void specr_2(spec_room &sr);
+static void beehive(spec_room &sr);
+
+// VAULT FUNCTIONS
+static void build_vaults(int level_number, int force_vault);
+static void build_minivaults(int level_number, int force_vault);
+static int vault_grid( int level_number, int vx, int vy, int altar_count,
+ FixedVector < char, 7 > &acq_item_class,
+ FixedVector < int, 7 > &mons_array,
+ char vgrid, int &initial_x, int &initial_y,
+ int force_vault, int &num_runes );
+
+// ALTAR FUNCTIONS
+static int pick_an_altar(void);
+static void place_altar(void);
+
+
+/*
+ **************************************************
+ * *
+ * BEGIN PUBLIC FUNCTIONS *
+ * *
+ **************************************************
+*/
+
+void builder(int level_number, char level_type)
+{
+ int i; // generic loop variable
+ int x,y; // generic map loop variables
+
+ srandom(time(NULL));
+
+ // blank level with DNGN_ROCK_WALL
+ make_box(0,0,GXM-1,GYM-1,DNGN_ROCK_WALL,DNGN_ROCK_WALL);
+
+ // delete all traps
+ for (i = 0; i < MAX_TRAPS; i++)
+ env.trap[i].type = TRAP_UNASSIGNED;
+
+ // initialize all items
+ for (i = 0; i < MAX_ITEMS; i++)
+ init_item( i );
+
+ // reset all monsters
+ for (i = 0; i < MAX_MONSTERS; i++)
+ menv[i].type = -1;
+
+ // unlink all monsters and items from the grid
+ for(x=0; x<GXM; x++)
+ {
+ for(y=0; y<GYM; y++)
+ {
+ mgrd[x][y] = NON_MONSTER;
+ igrd[x][y] = NON_ITEM;
+ }
+ }
+
+ // reset all shops
+ for (unsigned char shcount = 0; shcount < 5; shcount++)
+ {
+ env.shop[shcount].type = SHOP_UNASSIGNED;
+ }
+
+ int skip_build;
+
+ skip_build = builder_by_type(level_number, level_type);
+ if (skip_build < 0)
+ return;
+
+ if (skip_build == 0)
+ {
+ skip_build = builder_by_branch(level_number);
+
+ if (skip_build < 0)
+ return;
+ }
+
+ spec_room sr = { false, false, 0, 0, 0, 0 };
+
+ if (skip_build == 0)
+ {
+ // do 'normal' building. Well, except for the swamp.
+ if (!player_in_branch( BRANCH_SWAMP ))
+ skip_build = builder_normal(level_number, level_type, sr);
+
+ if (skip_build == 0)
+ {
+ skip_build = builder_basic(level_number);
+ if (skip_build == 0)
+ builder_extras(level_number, level_type);
+ }
+ }
+
+ // hook up the special room (if there is one, and it hasn't
+ // been hooked up already in roguey_level()
+ if (sr.created && !sr.hooked_up)
+ specr_2(sr);
+
+ // now place items, monster, gates, etc.
+ // stairs must exist by this point. Some items and monsters
+ // already exist.
+
+ // time to make the swamp {dlb}:
+ if (player_in_branch( BRANCH_SWAMP ))
+ prepare_swamp();
+
+ // figure out how many 'normal' monsters we should place
+ int mon_wanted = 0;
+ if (level_type == LEVEL_ABYSS
+ || player_in_branch( BRANCH_ECUMENICAL_TEMPLE ))
+ {
+ mon_wanted = 0;
+ }
+ else
+ {
+ mon_wanted = roll_dice( 3, 10 );
+
+ if (player_in_hell())
+ mon_wanted += roll_dice( 3, 8 );
+ else if (player_in_branch( BRANCH_HALL_OF_BLADES ))
+ mon_wanted += roll_dice( 6, 8 );
+
+ // unlikely - now only possible in HoB {dlb} 10mar2000
+ if (mon_wanted > 60)
+ mon_wanted = 60;
+ }
+
+ place_branch_entrances( level_number, level_type );
+
+ check_doors();
+
+ if (!player_in_branch( BRANCH_DIS ) && !player_in_branch( BRANCH_VAULTS ))
+ hide_doors();
+
+ if (!player_in_branch( BRANCH_ECUMENICAL_TEMPLE ))
+ place_traps(level_number);
+
+ int items_wanted = 3 + roll_dice( 3, 11 );
+
+ if (level_number > 5 && one_chance_in(500 - 5 * level_number))
+ items_wanted = 10 + random2avg( 90, 2 ); // rich level!
+
+ // change pre-rock (105) to rock, and pre-floor (106) to floor
+ replace_area( 0,0,GXM-1,GYM-1, DNGN_BUILDER_SPECIAL_WALL, DNGN_ROCK_WALL );
+ replace_area( 0,0,GXM-1,GYM-1, DNGN_BUILDER_SPECIAL_FLOOR, DNGN_FLOOR );
+
+ // place items
+ builder_items(level_number, level_type, items_wanted);
+
+ // place monsters
+ builder_monsters(level_number, level_type, mon_wanted);
+
+ // place shops, if appropriate
+ if (player_in_branch( BRANCH_MAIN_DUNGEON )
+ || player_in_branch( BRANCH_ORCISH_MINES )
+ || player_in_branch( BRANCH_ELVEN_HALLS )
+ || player_in_branch( BRANCH_LAIR )
+ || player_in_branch( BRANCH_VAULTS )
+ || player_in_branch( BRANCH_SNAKE_PIT )
+ || player_in_branch( BRANCH_SWAMP ))
+ {
+ place_shops(level_number);
+ }
+
+ // If level part of Dis -> all walls metal;
+ // If part of vaults -> walls depend on level;
+ // If part of crypt -> all walls stone:
+ if (player_in_branch( BRANCH_DIS )
+ || player_in_branch( BRANCH_VAULTS )
+ || player_in_branch( BRANCH_CRYPT ))
+ {
+ // always the case with Dis {dlb}
+ unsigned char vault_wall = DNGN_METAL_WALL;
+
+ if (player_in_branch( BRANCH_VAULTS ))
+ {
+ vault_wall = DNGN_ROCK_WALL;
+
+ if (level_number > you.branch_stairs[STAIRS_VAULTS] + 2)
+ vault_wall = DNGN_STONE_WALL;
+
+ if (level_number > you.branch_stairs[STAIRS_VAULTS] + 4)
+ vault_wall = DNGN_METAL_WALL;
+
+ if (level_number > you.branch_stairs[STAIRS_VAULTS] + 6
+ && one_chance_in(10))
+ {
+ vault_wall = DNGN_GREEN_CRYSTAL_WALL;
+ }
+ }
+ else if (player_in_branch( BRANCH_CRYPT ))
+ {
+ vault_wall = DNGN_STONE_WALL;
+ }
+
+ replace_area(0,0,GXM-1,GYM-1,DNGN_ROCK_WALL,vault_wall);
+ }
+
+ // Top level of branch levels - replaces up stairs
+ // with stairs back to dungeon or wherever:
+ for (i = 0; i< 30; i++)
+ {
+ if (you.branch_stairs[i] == 0)
+ break;
+
+ if (level_number == you.branch_stairs[i] + 1
+ && level_type == LEVEL_DUNGEON
+ && you.where_are_you == BRANCH_ORCISH_MINES + i)
+ {
+ for (x = 1; x < GXM; x++)
+ {
+ for (y = 1; y < GYM; y++)
+ {
+ if (grd[x][y] >= DNGN_STONE_STAIRS_UP_I
+ && grd[x][y] <= DNGN_ROCK_STAIRS_UP)
+ {
+ grd[x][y] = DNGN_RETURN_FROM_ORCISH_MINES + i;
+ }
+ }
+ }
+ }
+ }
+
+ // bottom level of branch - replaces down stairs with up ladders:
+ for (i = 0; i < 30; i++)
+ {
+ if (level_number == you.branch_stairs[i] + branch_depth(i)
+ && level_type == LEVEL_DUNGEON
+ && you.where_are_you == BRANCH_ORCISH_MINES + i)
+ {
+ for (x = 1; x < GXM; x++)
+ {
+ for (y = 1; y < GYM; y++)
+ {
+ if (grd[x][y] >= DNGN_STONE_STAIRS_DOWN_I
+ && grd[x][y] <= DNGN_ROCK_STAIRS_DOWN)
+ {
+ grd[x][y] = DNGN_ROCK_STAIRS_UP;
+ }
+ }
+ }
+ }
+ }
+
+ if (player_in_branch( BRANCH_CRYPT ))
+ {
+ if (one_chance_in(3))
+ mons_place( MONS_CURSE_SKULL, BEH_SLEEP, MHITNOT, false, 0, 0 );
+
+ if (one_chance_in(7))
+ mons_place( MONS_CURSE_SKULL, BEH_SLEEP, MHITNOT, false, 0, 0 );
+ }
+
+ if (player_in_branch( BRANCH_ORCISH_MINES ) && one_chance_in(5))
+ place_altar();
+
+ // hall of blades (1 level deal) - no down staircases, thanks!
+ if (player_in_branch( BRANCH_HALL_OF_BLADES ))
+ {
+ for (x = 1; x < GXM; x++)
+ {
+ for (y = 1; y < GYM; y++)
+ {
+ if (grd[x][y] >= DNGN_STONE_STAIRS_DOWN_I
+ && grd[x][y] <= DNGN_ROCK_STAIRS_UP)
+ {
+ grd[x][y] = DNGN_FLOOR;
+ }
+ }
+ }
+ }
+
+ link_items();
+
+ if (!player_in_branch(BRANCH_COCYTUS) && !player_in_branch(BRANCH_SWAMP))
+ prepare_water( level_number );
+} // end builder()
+
+// Returns item slot or NON_ITEM if it fails
+int items( int allow_uniques, // not just true-false,
+ // because of BCR acquirement hack
+ int force_class, // desired OBJECTS class {dlb}
+ int force_type, // desired SUBTYPE - enum varies by OBJ
+ bool dont_place, // don't randomly place item on level
+ int item_level, // level of the item, can differ from global
+ int item_race ) // weapon / armour racial categories
+ // item_race also gives type of rune!
+{
+ int temp_rand = 0; // probability determination {dlb}
+ int range_charges = 0; // for OBJ_WANDS charge count {dlb}
+ int temp_value = 0; // temporary value storage {dlb}
+ int loopy = 0; // just another loop variable {dlb}
+ int count = 0; // just another loop variable {dlb}
+
+ int race_plus = 0;
+ int race_plus2 = 0;
+ int x_pos, y_pos;
+
+ int quant = 0;
+
+ FixedVector < int, SPELLBOOK_SIZE > fpass;
+ int icky = 0;
+ int p = 0;
+
+ // find an emtpy slot for the item (with culling if required)
+ p = get_item_slot(10);
+ if (p == NON_ITEM)
+ return (NON_ITEM);
+
+ // clear all properties except mitm.base_type <used in switch below> {dlb}:
+ mitm[p].sub_type = 0;
+ mitm[p].flags = 0;
+ mitm[p].special = 0;
+ mitm[p].plus = 0;
+ mitm[p].plus2 = 0;
+ mitm[p].x = 0;
+ mitm[p].y = 0;
+ mitm[p].link = NON_ITEM;
+
+ // cap item_level unless an acquirement-level item {dlb}:
+ if (item_level > 50 && item_level != MAKE_GOOD_ITEM)
+ item_level = 50;
+
+ // determine base_type for item generated {dlb}:
+ if (force_class != OBJ_RANDOM)
+ mitm[p].base_type = force_class;
+ else
+ {
+ // nice and large for subtle differences {dlb}
+ temp_rand = random2(10000);
+
+ mitm[p].base_type = ((temp_rand < 50) ? OBJ_STAVES : // 0.50%
+ (temp_rand < 200) ? OBJ_BOOKS : // 1.50%
+ (temp_rand < 450) ? OBJ_JEWELLERY :// 2.50%
+ (temp_rand < 800) ? OBJ_WANDS : // 3.50%
+ (temp_rand < 1500) ? OBJ_FOOD : // 7.00%
+ (temp_rand < 2500) ? OBJ_ARMOUR : // 10.00%
+ (temp_rand < 3500) ? OBJ_WEAPONS : // 10.00%
+ (temp_rand < 4500) ? OBJ_POTIONS : // 10.00%
+ (temp_rand < 6000) ? OBJ_MISSILES : // 15.00%
+ (temp_rand < 8000) ? OBJ_SCROLLS // 20.00%
+ : OBJ_GOLD); // 20.00%
+
+ // misc items placement wholly dependent upon current depth {dlb}:
+ if (item_level > 7 && (20 + item_level) >= random2(3500))
+ mitm[p].base_type = OBJ_MISCELLANY;
+
+ if (item_level < 7
+ && (mitm[p].base_type == OBJ_BOOKS
+ || mitm[p].base_type == OBJ_STAVES
+ || mitm[p].base_type == OBJ_WANDS)
+ && random2(7) >= item_level)
+ {
+ mitm[p].base_type = coinflip() ? OBJ_POTIONS : OBJ_SCROLLS;
+ }
+ }
+
+ // determine sub_type accordingly {dlb}:
+ switch (mitm[p].base_type)
+ {
+ case OBJ_WEAPONS:
+ // generate initial weapon subtype using weighted function --
+ // indefinite loop now more evident and fewer array lookups {dlb}:
+ if (force_type != OBJ_RANDOM)
+ mitm[p].sub_type = force_type;
+ else
+ {
+ if (random2(20) < 20 - item_level)
+ {
+ // these are the common/low level weapon types
+ temp_rand = random2(12);
+
+ mitm[p].sub_type = ((temp_rand == 0) ? WPN_KNIFE :
+ (temp_rand == 1) ? WPN_QUARTERSTAFF :
+ (temp_rand == 2) ? WPN_SLING :
+ (temp_rand == 3) ? WPN_SPEAR :
+ (temp_rand == 4) ? WPN_HAND_AXE :
+ (temp_rand == 5) ? WPN_DAGGER :
+ (temp_rand == 6) ? WPN_MACE :
+ (temp_rand == 7) ? WPN_DAGGER :
+ (temp_rand == 8) ? WPN_CLUB :
+ (temp_rand == 9) ? WPN_HAMMER :
+ (temp_rand == 10) ? WPN_WHIP
+ : WPN_SABRE);
+ }
+ else if (item_level > 6 && random2(100) < (10 + item_level)
+ && one_chance_in(30))
+ {
+ // place the rare_weapon() == 0 weapons
+ //
+ // this replaced the infinite loop (wasteful) -- may need
+ // to make into its own function to allow ease of tweaking
+ // distribution {dlb}:
+ temp_rand = random2(9);
+
+ mitm[p].sub_type = ((temp_rand == 8) ? WPN_DEMON_BLADE :
+ (temp_rand == 7) ? WPN_DEMON_TRIDENT :
+ (temp_rand == 6) ? WPN_DEMON_WHIP :
+ (temp_rand == 5) ? WPN_DOUBLE_SWORD :
+ (temp_rand == 4) ? WPN_EVENINGSTAR :
+ (temp_rand == 3) ? WPN_EXECUTIONERS_AXE :
+ (temp_rand == 2) ? WPN_KATANA :
+ (temp_rand == 1) ? WPN_QUICK_BLADE
+ /*(temp_rand == 0)*/: WPN_TRIPLE_SWORD);
+ }
+ else
+ {
+ // pick a weapon based on rarity
+ for (;;)
+ {
+ temp_value = (unsigned char) random2(NUM_WEAPONS);
+
+ if (rare_weapon(temp_value) >= random2(10) + 1)
+ {
+ mitm[p].sub_type = temp_value;
+ break;
+ }
+ }
+ }
+ }
+
+ if (allow_uniques)
+ {
+ // Note there is nothing to stop randarts being reproduced,
+ // except vast improbability.
+ if (mitm[p].sub_type != WPN_CLUB && item_level > 2
+ && random2(2000) <= 100 + (item_level * 3) && coinflip())
+ {
+ if (you.level_type != LEVEL_ABYSS
+ && you.level_type != LEVEL_PANDEMONIUM
+ && one_chance_in(50))
+ {
+ icky = find_okay_unrandart( OBJ_WEAPONS, force_type );
+
+ if (icky != -1)
+ {
+ quant = 1;
+ make_item_unrandart( mitm[p], icky );
+ break;
+ }
+ }
+
+ make_item_randart( mitm[p] );
+ mitm[p].plus = 0;
+ mitm[p].plus2 = 0;
+ mitm[p].plus += random2(7);
+ mitm[p].plus2 += random2(7);
+
+ if (one_chance_in(3))
+ mitm[p].plus += random2(7);
+
+ if (one_chance_in(3))
+ mitm[p].plus2 += random2(7);
+
+ if (one_chance_in(9))
+ mitm[p].plus -= random2(7);
+
+ if (one_chance_in(9))
+ mitm[p].plus2 -= random2(7);
+
+ quant = 1;
+
+ if (one_chance_in(4))
+ {
+ do_curse_item( mitm[p] );
+ mitm[p].plus = -random2(6);
+ mitm[p].plus2 = -random2(6);
+ }
+ else if ((mitm[p].plus < 0 || mitm[p].plus2 < 0)
+ && !one_chance_in(3))
+ {
+ do_curse_item( mitm[p] );
+ }
+ break;
+ }
+
+ if (item_level > 6
+ && random2(3000) <= 30 + (item_level * 3) && one_chance_in(12))
+ {
+ if (make_item_fixed_artefact( mitm[p], (item_level == 51) ))
+ break;
+ }
+ }
+
+ ASSERT(!is_fixed_artefact(mitm[p]) && !is_random_artefact(mitm[p]));
+
+ if (item_level == MAKE_GOOD_ITEM
+ && force_type != OBJ_RANDOM
+ && (mitm[p].sub_type == WPN_CLUB || mitm[p].sub_type == WPN_SLING))
+ {
+ mitm[p].sub_type = WPN_LONG_SWORD;
+ }
+
+ quant = 1;
+
+ mitm[p].plus = 0;
+ mitm[p].plus2 = 0;
+ mitm[p].special = SPWPN_NORMAL;
+
+ if (item_race == MAKE_ITEM_RANDOM_RACE && coinflip())
+ {
+ switch (mitm[p].sub_type)
+ {
+ case WPN_CLUB:
+ if (coinflip())
+ set_equip_race( mitm[p], ISFLAG_ORCISH );
+ break;
+
+ case WPN_MACE:
+ case WPN_FLAIL:
+ case WPN_SPIKED_FLAIL:
+ case WPN_GREAT_MACE:
+ case WPN_GREAT_FLAIL:
+ if (one_chance_in(6))
+ set_equip_race( mitm[p], ISFLAG_ELVEN );
+ if (one_chance_in(4))
+ set_equip_race( mitm[p], ISFLAG_DWARVEN );
+ if (one_chance_in(3))
+ set_equip_race( mitm[p], ISFLAG_ORCISH );
+ break;
+
+ case WPN_MORNINGSTAR:
+ case WPN_HAMMER:
+ if (one_chance_in(3))
+ set_equip_race( mitm[p], ISFLAG_ORCISH );
+ if (one_chance_in(3))
+ set_equip_race( mitm[p], ISFLAG_DWARVEN );
+ break;
+
+ case WPN_DAGGER:
+ if (one_chance_in(3))
+ set_equip_race( mitm[p], ISFLAG_ORCISH );
+ if (one_chance_in(4))
+ set_equip_race( mitm[p], ISFLAG_DWARVEN );
+ if (one_chance_in(4))
+ set_equip_race( mitm[p], ISFLAG_ELVEN );
+ break;
+
+ case WPN_SHORT_SWORD:
+ if (one_chance_in(3))
+ set_equip_race( mitm[p], ISFLAG_ORCISH );
+ if (one_chance_in(3))
+ set_equip_race( mitm[p], ISFLAG_DWARVEN );
+ if (one_chance_in(3))
+ set_equip_race( mitm[p], ISFLAG_ELVEN );
+ break;
+
+ case WPN_FALCHION:
+ if (one_chance_in(5))
+ set_equip_race( mitm[p], ISFLAG_DWARVEN );
+ if (one_chance_in(3))
+ set_equip_race( mitm[p], ISFLAG_ORCISH );
+ if (one_chance_in(3))
+ set_equip_race( mitm[p], ISFLAG_ELVEN );
+ break;
+
+ case WPN_LONG_SWORD:
+ if (one_chance_in(4))
+ set_equip_race( mitm[p], ISFLAG_ORCISH );
+ if (coinflip())
+ set_equip_race( mitm[p], ISFLAG_ELVEN );
+ break;
+
+ case WPN_GREAT_SWORD:
+ if (one_chance_in(3))
+ set_equip_race( mitm[p], ISFLAG_ORCISH );
+ break;
+
+ case WPN_SCIMITAR:
+ if (coinflip())
+ set_equip_race( mitm[p], ISFLAG_ORCISH );
+ break;
+
+ case WPN_WAR_AXE:
+ case WPN_HAND_AXE:
+ case WPN_BROAD_AXE:
+ case WPN_BATTLEAXE:
+ if (one_chance_in(3))
+ set_equip_race( mitm[p], ISFLAG_ORCISH );
+ if (coinflip())
+ set_equip_race( mitm[p], ISFLAG_DWARVEN );
+ break;
+
+ case WPN_SPEAR:
+ case WPN_TRIDENT:
+ if (one_chance_in(4))
+ set_equip_race( mitm[p], ISFLAG_ORCISH );
+ if (one_chance_in(4))
+ set_equip_race( mitm[p], ISFLAG_ELVEN );
+ break;
+
+ case WPN_HALBERD:
+ case WPN_GLAIVE:
+ case WPN_EXECUTIONERS_AXE:
+ if (one_chance_in(5))
+ set_equip_race( mitm[p], ISFLAG_ORCISH );
+ break;
+
+ case WPN_QUICK_BLADE:
+ if (one_chance_in(4))
+ set_equip_race( mitm[p], ISFLAG_ELVEN );
+ break;
+
+ case WPN_KATANA:
+ case WPN_KNIFE:
+ case WPN_SLING:
+ set_equip_race( mitm[p], ISFLAG_NO_RACE );
+ set_item_ego_type( mitm[p], OBJ_WEAPONS, SPWPN_NORMAL );
+ break;
+
+ case WPN_BOW:
+ if (one_chance_in(6))
+ set_equip_race( mitm[p], ISFLAG_ORCISH );
+ if (coinflip())
+ set_equip_race( mitm[p], ISFLAG_ELVEN );
+ break;
+
+ case WPN_CROSSBOW:
+ if (one_chance_in(4))
+ set_equip_race( mitm[p], ISFLAG_ORCISH );
+ if (one_chance_in(4))
+ set_equip_race( mitm[p], ISFLAG_DWARVEN );
+ break;
+
+ case WPN_HAND_CROSSBOW:
+ if (one_chance_in(3))
+ set_equip_race( mitm[p], ISFLAG_ELVEN );
+ break;
+
+ case WPN_BLOWGUN:
+ if (one_chance_in(10))
+ set_equip_race( mitm[p], ISFLAG_ELVEN );
+ if (one_chance_in(4))
+ set_equip_race( mitm[p], ISFLAG_ORCISH );
+ break;
+ }
+ }
+
+ // fine, but out-of-order relative to mitm[].special ordering {dlb}
+ switch (item_race)
+ {
+ case MAKE_ITEM_ELVEN:
+ set_equip_race( mitm[p], ISFLAG_ELVEN );
+ break;
+
+ case MAKE_ITEM_DWARVEN:
+ set_equip_race( mitm[p], ISFLAG_DWARVEN );
+ break;
+
+ case MAKE_ITEM_ORCISH:
+ set_equip_race( mitm[p], ISFLAG_ORCISH );
+ break;
+ }
+
+ // if we allow acquirement-type items to be orcish, then
+ // there's a good chance that we'll just strip them of
+ // their ego type at the bottom of this function. -- bwr
+ if (item_level == MAKE_GOOD_ITEM
+ && cmp_equip_race( mitm[p], ISFLAG_ORCISH ))
+ {
+ set_equip_race( mitm[p], ISFLAG_NO_RACE );
+ }
+
+ switch (get_equip_race( mitm[p] ))
+ {
+ case ISFLAG_ORCISH:
+ if (coinflip())
+ race_plus--;
+ if (coinflip())
+ race_plus2++;
+ break;
+
+ case ISFLAG_ELVEN:
+ race_plus += random2(3);
+ break;
+
+ case ISFLAG_DWARVEN:
+ if (coinflip())
+ race_plus++;
+ if (coinflip())
+ race_plus2++;
+ break;
+ }
+
+ mitm[p].plus += race_plus;
+ mitm[p].plus2 += race_plus2;
+
+ if ((random2(200) <= 50 + item_level
+ || item_level == MAKE_GOOD_ITEM
+ || is_demonic(mitm[p].sub_type))
+ // nobody would bother enchanting a club
+ && mitm[p].sub_type != WPN_CLUB
+ && mitm[p].sub_type != WPN_GIANT_CLUB
+ && mitm[p].sub_type != WPN_GIANT_SPIKED_CLUB)
+ {
+ count = 0;
+
+ do
+ {
+ if (random2(300) <= 100 + item_level
+ || item_level == MAKE_GOOD_ITEM
+ || is_demonic( mitm[p].sub_type ))
+ {
+ // note: this doesn't guarantee special enchantment
+ switch (mitm[p].sub_type)
+ {
+ case WPN_EVENINGSTAR:
+ if (coinflip())
+ set_weapon_special(p, SPWPN_DRAINING);
+ // **** intentional fall through here ****
+ case WPN_MORNINGSTAR:
+ if (one_chance_in(4))
+ set_weapon_special(p, SPWPN_VENOM);
+
+ if (one_chance_in(4))
+ {
+ set_weapon_special(p, (coinflip() ? SPWPN_FLAMING
+ : SPWPN_FREEZING));
+ }
+
+ if (one_chance_in(20))
+ set_weapon_special(p, SPWPN_VAMPIRICISM);
+ // **** intentional fall through here ****
+ case WPN_MACE:
+ case WPN_GREAT_MACE:
+ if ((mitm[p].sub_type == WPN_MACE
+ || mitm[p].sub_type == WPN_GREAT_MACE)
+ && one_chance_in(4))
+ {
+ set_weapon_special(p, SPWPN_DISRUPTION);
+ }
+ // **** intentional fall through here ****
+ case WPN_FLAIL:
+ case WPN_SPIKED_FLAIL:
+ case WPN_GREAT_FLAIL:
+ case WPN_HAMMER:
+ if (one_chance_in(25))
+ set_weapon_special(p, SPWPN_PAIN);
+
+ if (one_chance_in(25))
+ set_weapon_special(p, SPWPN_DISTORTION);
+
+ if (one_chance_in(3) &&
+ (!is_weapon_special(p) || one_chance_in(5)))
+ set_weapon_special(p, SPWPN_VORPAL);
+
+ if (one_chance_in(4))
+ set_weapon_special(p, SPWPN_HOLY_WRATH);
+
+ if (one_chance_in(3))
+ set_weapon_special(p, SPWPN_PROTECTION);
+
+ if (one_chance_in(10))
+ set_weapon_special(p, SPWPN_DRAINING);
+ break;
+
+
+ case WPN_DAGGER:
+ if (one_chance_in(10))
+ set_weapon_special(p, SPWPN_PAIN);
+
+ if (one_chance_in(3))
+ set_weapon_special(p, SPWPN_VENOM);
+ // **** intentional fall through here ****
+
+ case WPN_SHORT_SWORD:
+ case WPN_SABRE:
+ if (one_chance_in(25))
+ set_weapon_special(p, SPWPN_DISTORTION);
+
+ if (one_chance_in(10))
+ set_weapon_special(p, SPWPN_VAMPIRICISM);
+
+ if (one_chance_in(8))
+ set_weapon_special(p, SPWPN_ELECTROCUTION);
+
+ if (one_chance_in(8))
+ set_weapon_special(p, SPWPN_PROTECTION);
+
+ if (one_chance_in(10))
+ set_weapon_special(p, SPWPN_ORC_SLAYING);
+
+ if (one_chance_in(8))
+ {
+ set_weapon_special(p,(coinflip() ? SPWPN_FLAMING
+ : SPWPN_FREEZING));
+ }
+
+ if (one_chance_in(12))
+ set_weapon_special(p, SPWPN_HOLY_WRATH);
+
+ if (one_chance_in(8))
+ set_weapon_special(p, SPWPN_DRAINING);
+
+ if (one_chance_in(8))
+ set_weapon_special(p, SPWPN_SPEED);
+
+ if (one_chance_in(6))
+ set_weapon_special(p, SPWPN_VENOM);
+ break;
+
+ case WPN_FALCHION:
+ case WPN_LONG_SWORD:
+ if (one_chance_in(12))
+ set_weapon_special(p, SPWPN_VENOM);
+ // **** intentional fall through here ****
+ case WPN_SCIMITAR:
+ if (one_chance_in(25))
+ set_weapon_special(p, SPWPN_PAIN);
+
+ if (one_chance_in(7))
+ set_weapon_special(p, SPWPN_SPEED);
+ // **** intentional fall through here ****
+ case WPN_GREAT_SWORD:
+ case WPN_DOUBLE_SWORD:
+ case WPN_TRIPLE_SWORD:
+ if (one_chance_in(10))
+ set_weapon_special(p, SPWPN_VAMPIRICISM);
+
+ if (one_chance_in(25))
+ set_weapon_special(p, SPWPN_DISTORTION);
+
+ if (one_chance_in(5))
+ {
+ set_weapon_special(p,(coinflip() ? SPWPN_FLAMING
+ : SPWPN_FREEZING));
+ }
+
+ if (one_chance_in(7))
+ set_weapon_special(p, SPWPN_PROTECTION);
+
+ if (one_chance_in(8))
+ set_weapon_special(p, SPWPN_ORC_SLAYING);
+
+ if (one_chance_in(12))
+ set_weapon_special(p, SPWPN_DRAINING);
+
+ if (one_chance_in(7))
+ set_weapon_special(p, SPWPN_ELECTROCUTION);
+
+ if (one_chance_in(4))
+ set_weapon_special(p, SPWPN_HOLY_WRATH);
+
+ if (one_chance_in(4)
+ && (!is_weapon_special(p) || one_chance_in(3)))
+ {
+ set_weapon_special(p, SPWPN_VORPAL);
+ }
+ break;
+
+
+ case WPN_WAR_AXE:
+ case WPN_BROAD_AXE:
+ case WPN_BATTLEAXE:
+ case WPN_EXECUTIONERS_AXE:
+ if (one_chance_in(25))
+ set_weapon_special(p, SPWPN_HOLY_WRATH);
+
+ if (one_chance_in(14))
+ set_weapon_special(p, SPWPN_DRAINING);
+ // **** intentional fall through here ****
+ case WPN_HAND_AXE:
+ if (one_chance_in(30))
+ set_weapon_special(p, SPWPN_PAIN);
+
+ if (one_chance_in(10))
+ set_weapon_special(p, SPWPN_VAMPIRICISM);
+
+ if (one_chance_in(25))
+ set_weapon_special(p, SPWPN_DISTORTION);
+
+ if (one_chance_in(3)
+ && (!is_weapon_special(p) || one_chance_in(5)))
+ {
+ set_weapon_special(p, SPWPN_VORPAL);
+ }
+
+ if (one_chance_in(6))
+ set_weapon_special(p, SPWPN_ORC_SLAYING);
+
+ if (one_chance_in(4))
+ {
+ set_weapon_special(p, (coinflip() ? SPWPN_FLAMING
+ : SPWPN_FREEZING));
+ }
+
+ if (one_chance_in(8))
+ set_weapon_special(p, SPWPN_ELECTROCUTION);
+
+ if (one_chance_in(12))
+ set_weapon_special(p, SPWPN_VENOM);
+
+ break;
+
+ case WPN_WHIP:
+ if (one_chance_in(20))
+ set_weapon_special(p, SPWPN_DISTORTION);
+
+ if (one_chance_in(6))
+ {
+ set_weapon_special(p, (coinflip() ? SPWPN_FLAMING
+ : SPWPN_FREEZING));
+ }
+
+ if (one_chance_in(6))
+ set_weapon_special(p, SPWPN_VENOM);
+
+ if (coinflip())
+ set_weapon_special(p, SPWPN_REACHING);
+
+ if (one_chance_in(5))
+ set_weapon_special(p, SPWPN_SPEED);
+
+ if (one_chance_in(5))
+ set_weapon_special(p, SPWPN_ELECTROCUTION);
+ break;
+
+ case WPN_HALBERD:
+ case WPN_GLAIVE:
+ if (one_chance_in(30))
+ set_weapon_special(p, SPWPN_HOLY_WRATH);
+
+ if (one_chance_in(4))
+ set_weapon_special(p, SPWPN_PROTECTION);
+ // **** intentional fall through here ****
+ case WPN_SCYTHE:
+ case WPN_TRIDENT:
+ if (one_chance_in(5))
+ set_weapon_special(p, SPWPN_SPEED);
+ // **** intentional fall through here ****
+ case WPN_SPEAR:
+ if (one_chance_in(25))
+ set_weapon_special(p, SPWPN_PAIN);
+
+ if (one_chance_in(10))
+ set_weapon_special(p, SPWPN_VAMPIRICISM);
+
+ if (one_chance_in(20))
+ set_weapon_special(p, SPWPN_DISTORTION);
+
+ if (one_chance_in(5) &&
+ (!is_weapon_special(p) || one_chance_in(6)))
+ set_weapon_special(p, SPWPN_VORPAL);
+
+ if (one_chance_in(6))
+ set_weapon_special(p, SPWPN_ORC_SLAYING);
+
+ if (one_chance_in(6))
+ {
+ set_weapon_special(p, (coinflip() ? SPWPN_FLAMING
+ : SPWPN_FREEZING));
+ }
+
+ if (one_chance_in(6))
+ set_weapon_special(p, SPWPN_VENOM);
+
+ if (one_chance_in(3))
+ set_weapon_special(p, SPWPN_REACHING);
+ break;
+
+
+ case WPN_SLING:
+ case WPN_HAND_CROSSBOW:
+ if (coinflip())
+ break;
+ // **** possible intentional fall through here ****
+ case WPN_BOW:
+ case WPN_CROSSBOW:
+ if (one_chance_in(30))
+ set_weapon_special( p, SPWPN_SPEED );
+
+ if (one_chance_in(5))
+ set_weapon_special( p, SPWPN_PROTECTION );
+
+ if (coinflip())
+ set_weapon_special(p, (coinflip() ? SPWPN_FLAME
+ : SPWPN_FROST));
+ break;
+
+ case WPN_BLOWGUN:
+ if (one_chance_in(7))
+ set_weapon_special(p, SPWPN_VENOM);
+ break;
+
+ // quarterstaff - not powerful, as this would make
+ // the 'staves' skill just too good
+ case WPN_QUARTERSTAFF:
+ if (one_chance_in(30))
+ set_weapon_special(p, SPWPN_PAIN);
+
+ if (one_chance_in(20))
+ set_weapon_special(p, SPWPN_DISTORTION);
+
+ if (one_chance_in(5))
+ set_weapon_special(p, SPWPN_SPEED);
+
+ if (one_chance_in(10))
+ set_weapon_special(p, SPWPN_VORPAL);
+
+ if (one_chance_in(5))
+ set_weapon_special(p, SPWPN_PROTECTION);
+ break;
+
+
+ case WPN_DEMON_TRIDENT:
+ case WPN_DEMON_WHIP:
+ case WPN_DEMON_BLADE:
+ set_equip_race( mitm[p], ISFLAG_NO_RACE );
+
+ if (one_chance_in(10))
+ set_weapon_special(p, SPWPN_PAIN);
+
+ if (one_chance_in(3)
+ && (mitm[p].sub_type == WPN_DEMON_WHIP
+ || mitm[p].sub_type == WPN_DEMON_TRIDENT))
+ {
+ set_weapon_special(p, SPWPN_REACHING);
+ }
+
+ if (one_chance_in(5))
+ set_weapon_special(p, SPWPN_DRAINING);
+
+ if (one_chance_in(5))
+ {
+ set_weapon_special(p, (coinflip() ? SPWPN_FLAMING
+ : SPWPN_FREEZING));
+ }
+
+ if (one_chance_in(5))
+ set_weapon_special(p, SPWPN_ELECTROCUTION);
+
+ if (one_chance_in(5))
+ set_weapon_special(p, SPWPN_VAMPIRICISM);
+
+ if (one_chance_in(5))
+ set_weapon_special(p, SPWPN_VENOM);
+ break;
+
+ // unlisted weapons have no associated, standard ego-types {dlb}
+ default:
+ break;
+ }
+ } // end if specially enchanted
+
+ count++;
+ }
+ while (item_level == MAKE_GOOD_ITEM
+ && mitm[p].special == SPWPN_NORMAL
+ && count < 5);
+
+ // if acquired item still not ego... enchant it up a bit.
+ if (item_level == MAKE_GOOD_ITEM && mitm[p].special == SPWPN_NORMAL)
+ {
+ mitm[p].plus += 2 + random2(3);
+ mitm[p].plus2 += 2 + random2(3);
+ }
+
+ const int chance = (item_level == MAKE_GOOD_ITEM) ? 200
+ : item_level;
+
+ // odd-looking, but this is how the algorithm compacts {dlb}:
+ for (loopy = 0; loopy < 4; loopy++)
+ {
+ mitm[p].plus += random2(3);
+
+ if (random2(350) > 20 + chance)
+ break;
+ }
+
+ // odd-looking, but this is how the algorithm compacts {dlb}:
+ for (loopy = 0; loopy < 4; loopy++)
+ {
+ mitm[p].plus2 += random2(3);
+
+ if (random2(500) > 50 + chance)
+ break;
+ }
+ }
+ else
+ {
+ if (one_chance_in(12))
+ {
+ do_curse_item( mitm[p] );
+ mitm[p].plus -= random2(4);
+ mitm[p].plus2 -= random2(4);
+
+ // clear specials {dlb}
+ set_item_ego_type( mitm[p], OBJ_WEAPONS, SPWPN_NORMAL );
+ }
+ }
+
+ // value was "0" comment said "orc" so I went with comment {dlb}
+ if (cmp_equip_race( mitm[p], ISFLAG_ORCISH ))
+ {
+ // no holy wrath or slay orc and 1/2 the time no-ego
+ const int brand = get_weapon_brand( mitm[p] );
+ if (brand == SPWPN_HOLY_WRATH
+ || brand == SPWPN_ORC_SLAYING
+ || (brand != SPWPN_NORMAL && coinflip()))
+ {
+ // this makes no sense {dlb}
+ // Probably a remnant of the old code which used
+ // to decrement this when the electric attack happened -- bwr
+ // if (brand == SPWPN_ELECTROCUTION)
+ // mitm[p].plus = 0;
+
+ set_item_ego_type( mitm[p], OBJ_WEAPONS, SPWPN_NORMAL );
+ }
+ }
+
+ if ((((is_random_artefact( mitm[p] )
+ || get_weapon_brand( mitm[p] ) != SPWPN_NORMAL)
+ && !one_chance_in(10))
+ || ((mitm[p].plus != 0 || mitm[p].plus2 != 0)
+ && one_chance_in(3)))
+ && mitm[p].sub_type != WPN_CLUB
+ && mitm[p].sub_type != WPN_GIANT_CLUB
+ && mitm[p].sub_type != WPN_GIANT_SPIKED_CLUB
+ && cmp_equip_desc( mitm[p], 0 )
+ && cmp_equip_race( mitm[p], 0 ))
+ {
+ set_equip_desc( mitm[p], (coinflip() ? ISFLAG_GLOWING
+ : ISFLAG_RUNED) );
+ }
+ break;
+
+ case OBJ_MISSILES:
+ quant = 0;
+ mitm[p].plus = 0;
+ mitm[p].special = SPMSL_NORMAL;
+
+ temp_rand = random2(20);
+ mitm[p].sub_type = (temp_rand < 6) ? MI_STONE : // 30 %
+ (temp_rand < 10) ? MI_DART : // 20 %
+ (temp_rand < 14) ? MI_ARROW : // 20 %
+ (temp_rand < 18) ? MI_BOLT // 20 %
+ : MI_NEEDLE; // 10 %
+
+ if (force_type != OBJ_RANDOM)
+ mitm[p].sub_type = force_type;
+
+ // no fancy rocks -- break out before we get to racial/special stuff
+ if (mitm[p].sub_type == MI_LARGE_ROCK)
+ {
+ quant = 2 + random2avg(5,2);
+ break;
+ }
+ else if (mitm[p].sub_type == MI_STONE)
+ {
+ quant = 1 + random2(9) + random2(12) + random2(15) + random2(12);
+ break;
+ }
+
+ // set racial type:
+ switch (item_race)
+ {
+ case MAKE_ITEM_ELVEN:
+ set_equip_race( mitm[p], ISFLAG_ELVEN );
+ break;
+
+ case MAKE_ITEM_DWARVEN:
+ set_equip_race( mitm[p], ISFLAG_DWARVEN );
+ break;
+
+ case MAKE_ITEM_ORCISH:
+ set_equip_race( mitm[p], ISFLAG_ORCISH );
+ break;
+
+ case MAKE_ITEM_RANDOM_RACE:
+ if ((mitm[p].sub_type == MI_ARROW
+ || mitm[p].sub_type == MI_DART)
+ && one_chance_in(4))
+ {
+ // elven - not for bolts, though
+ set_equip_race( mitm[p], ISFLAG_ELVEN );
+ }
+
+ if ((mitm[p].sub_type == MI_ARROW
+ || mitm[p].sub_type == MI_BOLT
+ || mitm[p].sub_type == MI_DART)
+ && one_chance_in(4))
+ {
+ set_equip_race( mitm[p], ISFLAG_ORCISH );
+ }
+
+ if ((mitm[p].sub_type == MI_DART
+ || mitm[p].sub_type == MI_BOLT)
+ && one_chance_in(6))
+ {
+ set_equip_race( mitm[p], ISFLAG_DWARVEN );
+ }
+
+ if (mitm[p].sub_type == MI_NEEDLE)
+ {
+ if (one_chance_in(10))
+ set_equip_race( mitm[p], ISFLAG_ELVEN );
+ if (one_chance_in(6))
+ set_equip_race( mitm[p], ISFLAG_ORCISH );
+ }
+ break;
+ }
+
+ // note that needles can only be poisoned
+ //
+ // Actually, it'd be really nice if there where
+ // some paralysis or slowing poison needles, just
+ // so that blowguns have some added utility over
+ // the other launchers/throwing weapons. -- bwr
+ if (mitm[p].sub_type == MI_NEEDLE
+ && (item_level == MAKE_GOOD_ITEM || !one_chance_in(5)))
+ {
+ set_item_ego_type( mitm[p], OBJ_MISSILES, SPMSL_POISONED_II );
+ }
+ else
+ {
+ // decide specials:
+ if (item_level == MAKE_GOOD_ITEM)
+ temp_rand = random2(150);
+ else
+ temp_rand = random2(2000 - 55 * item_level);
+
+ set_item_ego_type( mitm[p], OBJ_MISSILES,
+ (temp_rand < 60) ? SPMSL_FLAME :
+ (temp_rand < 120) ? SPMSL_ICE :
+ (temp_rand < 150) ? SPMSL_POISONED_II
+ : SPMSL_NORMAL );
+ }
+
+ // orcish ammo gets poisoned a lot more often -- in the original
+ // code it was poisoned every time!?
+ if (cmp_equip_race( mitm[p], ISFLAG_ORCISH ) && one_chance_in(3))
+ set_item_ego_type( mitm[p], OBJ_MISSILES, SPMSL_POISONED_II );
+
+ // reduced quantity if special
+ if (get_ammo_brand( mitm[p] ) != SPMSL_NORMAL )
+ quant = 1 + random2(9) + random2(12) + random2(12);
+ else
+ quant = 1 + random2(9) + random2(12) + random2(15) + random2(12);
+
+ if (10 + item_level >= random2(100))
+ mitm[p].plus += random2(5);
+
+ // elven arrows and dwarven bolts are quality items
+ if ((cmp_equip_race( mitm[p], ISFLAG_ELVEN )
+ && mitm[p].sub_type == MI_ARROW)
+ || (cmp_equip_race( mitm[p], ISFLAG_DWARVEN )
+ && mitm[p].sub_type == MI_BOLT))
+ {
+ mitm[p].plus += random2(3);
+ }
+ break;
+
+ case OBJ_ARMOUR:
+ quant = 1;
+
+ mitm[p].plus = 0;
+ mitm[p].plus2 = 0;
+ mitm[p].special = SPARM_NORMAL;
+
+ if (force_type != OBJ_RANDOM)
+ mitm[p].sub_type = force_type;
+ else
+ {
+ mitm[p].sub_type = random2(3);
+
+ if (random2(35) <= item_level + 10)
+ {
+ mitm[p].sub_type = random2(5);
+ if (one_chance_in(4))
+ mitm[p].sub_type = ARM_ANIMAL_SKIN;
+ }
+
+ if (random2(60) <= item_level + 10)
+ mitm[p].sub_type = random2(8);
+
+ if (10 + item_level >= random2(400) && one_chance_in(20))
+ mitm[p].sub_type = ARM_DRAGON_HIDE + random2(7);
+
+ if (10 + item_level >= random2(500) && one_chance_in(20))
+ {
+ mitm[p].sub_type = ARM_STEAM_DRAGON_HIDE + random2(11);
+
+ if (mitm[p].sub_type == ARM_ANIMAL_SKIN && one_chance_in(20))
+ mitm[p].sub_type = ARM_CRYSTAL_PLATE_MAIL;
+ }
+
+ // secondary armours:
+ if (one_chance_in(5))
+ {
+ mitm[p].sub_type = ARM_SHIELD + random2(5);
+
+ if (mitm[p].sub_type == ARM_SHIELD) // 33.3%
+ {
+ if (coinflip())
+ mitm[p].sub_type = ARM_BUCKLER; // 50.0%
+ else if (one_chance_in(3))
+ mitm[p].sub_type = ARM_LARGE_SHIELD; // 16.7%
+ }
+ }
+ }
+
+ if (mitm[p].sub_type == ARM_HELMET)
+ {
+ set_helmet_type( mitm[p], THELM_HELMET );
+ set_helmet_desc( mitm[p], THELM_DESC_PLAIN );
+
+ if (one_chance_in(3))
+ set_helmet_type( mitm[p], random2( THELM_NUM_TYPES ) );
+
+ if (one_chance_in(3))
+ set_helmet_random_desc( mitm[p] );
+ }
+
+ if (allow_uniques == 1
+ && item_level > 2
+ && random2(2000) <= (100 + item_level * 3)
+ && coinflip())
+ {
+ if ((you.level_type != LEVEL_ABYSS
+ && you.level_type != LEVEL_PANDEMONIUM)
+ && one_chance_in(50))
+ {
+ icky = find_okay_unrandart(OBJ_ARMOUR);
+ if (icky != -1)
+ {
+ quant = 1;
+ make_item_unrandart( mitm[p], icky );
+ break;
+ }
+ }
+
+ hide2armour( &(mitm[p].sub_type) );
+
+ // mitm[p].special = SPARM_RANDART_II + random2(4);
+ make_item_randart( mitm[p] );
+ mitm[p].plus = 0;
+
+ if (mitm[p].sub_type == ARM_BOOTS)
+ {
+ mitm[p].plus2 = TBOOT_BOOTS;
+ if (one_chance_in(10))
+ mitm[p].plus2 = random2( NUM_BOOT_TYPES );
+ }
+
+ mitm[p].plus += random2(4);
+
+ if (one_chance_in(5))
+ mitm[p].plus += random2(4);
+
+ if (one_chance_in(6))
+ mitm[p].plus -= random2(8);
+
+ quant = 1;
+
+ if (one_chance_in(5))
+ {
+ do_curse_item( mitm[p] );
+ mitm[p].plus = -random2(6);
+ }
+ else if (mitm[p].plus < 0 && !one_chance_in(3))
+ {
+ do_curse_item( mitm[p] );
+ }
+ break;
+ }
+
+ mitm[p].plus = 0;
+
+ if (item_race == MAKE_ITEM_RANDOM_RACE && coinflip())
+ {
+ switch (mitm[p].sub_type)
+ {
+ case ARM_SHIELD: // shield - must do special things for this!
+ case ARM_BUCKLER:
+ case ARM_LARGE_SHIELD:
+ if (one_chance_in(4))
+ set_equip_race( mitm[p], ISFLAG_ELVEN );
+ if (one_chance_in(3))
+ set_equip_race( mitm[p], ISFLAG_DWARVEN );
+ break;
+
+ case ARM_CLOAK:
+ if (one_chance_in(4))
+ set_equip_race( mitm[p], ISFLAG_ORCISH );
+ if (one_chance_in(4))
+ set_equip_race( mitm[p], ISFLAG_DWARVEN );
+ if (one_chance_in(4))
+ set_equip_race( mitm[p], ISFLAG_ELVEN );
+ break;
+
+ case ARM_GLOVES:
+ if (one_chance_in(4))
+ set_equip_race( mitm[p], ISFLAG_ELVEN );
+ break;
+
+ case ARM_BOOTS:
+ if (one_chance_in(4))
+ {
+ mitm[p].plus2 = TBOOT_NAGA_BARDING;
+ break;
+ }
+
+ if (one_chance_in(4))
+ {
+ mitm[p].plus2 = TBOOT_CENTAUR_BARDING;
+ break;
+ }
+
+ if (one_chance_in(4))
+ set_equip_race( mitm[p], ISFLAG_ORCISH );
+ if (one_chance_in(4))
+ set_equip_race( mitm[p], ISFLAG_ELVEN );
+ if (one_chance_in(6))
+ set_equip_race( mitm[p], ISFLAG_DWARVEN );
+ break;
+
+ case ARM_HELMET:
+ if (cmp_helmet_type( mitm[p], THELM_CAP )
+ || cmp_helmet_type( mitm[p], THELM_WIZARD_HAT ))
+ {
+ if (one_chance_in(6))
+ set_equip_race( mitm[p], ISFLAG_ELVEN );
+ }
+ else
+ {
+ // helms and helmets
+ if (one_chance_in(8))
+ set_equip_race( mitm[p], ISFLAG_ORCISH );
+ if (one_chance_in(6))
+ set_equip_race( mitm[p], ISFLAG_DWARVEN );
+ }
+ break;
+
+ case ARM_ROBE:
+ if (one_chance_in(4))
+ set_equip_race( mitm[p], ISFLAG_ELVEN );
+ break;
+
+ case ARM_RING_MAIL:
+ case ARM_SCALE_MAIL:
+ case ARM_CHAIN_MAIL:
+ case ARM_SPLINT_MAIL:
+ case ARM_BANDED_MAIL:
+ case ARM_PLATE_MAIL:
+ if (mitm[p].sub_type <= ARM_CHAIN_MAIL && one_chance_in(6))
+ set_equip_race( mitm[p], ISFLAG_ELVEN );
+ if (mitm[p].sub_type >= ARM_RING_MAIL && one_chance_in(5))
+ set_equip_race( mitm[p], ISFLAG_DWARVEN );
+ if (one_chance_in(5))
+ set_equip_race( mitm[p], ISFLAG_ORCISH );
+
+ default: // skins, hides, crystal plate are always plain
+ break;
+ }
+ }
+
+ switch (item_race)
+ {
+ case MAKE_ITEM_ELVEN:
+ set_equip_race( mitm[p], ISFLAG_ELVEN );
+ break;
+
+ case MAKE_ITEM_DWARVEN:
+ set_equip_race( mitm[p], ISFLAG_DWARVEN );
+ if (coinflip())
+ mitm[p].plus++;
+ break;
+
+ case MAKE_ITEM_ORCISH:
+ set_equip_race( mitm[p], ISFLAG_ORCISH );
+ break;
+ }
+
+
+ if (50 + item_level >= random2(250)
+ || item_level == MAKE_GOOD_ITEM
+ || (mitm[p].sub_type == ARM_HELMET
+ && cmp_helmet_type( mitm[p], THELM_WIZARD_HAT )))
+ {
+ mitm[p].plus += random2(3);
+
+ if (mitm[p].sub_type <= ARM_PLATE_MAIL && 20 + item_level >= random2(300))
+ mitm[p].plus += random2(3);
+
+ if (30 + item_level >= random2(350)
+ && (item_level == MAKE_GOOD_ITEM
+ || (!cmp_equip_race( mitm[p], ISFLAG_ORCISH )
+ || (mitm[p].sub_type <= ARM_PLATE_MAIL && coinflip()))))
+ {
+ switch (mitm[p].sub_type)
+ {
+ case ARM_SHIELD: // shield - must do special things for this!
+ case ARM_LARGE_SHIELD:
+ case ARM_BUCKLER:
+ set_item_ego_type( mitm[p], OBJ_ARMOUR, SPARM_PROTECTION );
+ break; // prot
+ //break;
+
+ case ARM_CLOAK:
+ if (cmp_equip_race( mitm[p], ISFLAG_DWARVEN ))
+ break;
+
+ switch (random2(4))
+ {
+ case 0:
+ set_item_ego_type( mitm[p],
+ OBJ_ARMOUR, SPARM_POISON_RESISTANCE );
+ break;
+
+ case 1:
+ set_item_ego_type( mitm[p],
+ OBJ_ARMOUR, SPARM_DARKNESS );
+ break;
+ case 2:
+ set_item_ego_type( mitm[p],
+ OBJ_ARMOUR, SPARM_MAGIC_RESISTANCE );
+ break;
+ case 3:
+ set_item_ego_type( mitm[p],
+ OBJ_ARMOUR, SPARM_PRESERVATION );
+ break;
+ }
+ break;
+
+ case ARM_HELMET:
+ if (cmp_helmet_type(mitm[p],THELM_WIZARD_HAT) && coinflip())
+ {
+ if (one_chance_in(3))
+ {
+ set_item_ego_type( mitm[p],
+ OBJ_ARMOUR, SPARM_MAGIC_RESISTANCE );
+ }
+ else
+ {
+ set_item_ego_type( mitm[p],
+ OBJ_ARMOUR, SPARM_INTELLIGENCE );
+ }
+ }
+ else
+ {
+ set_item_ego_type( mitm[p], OBJ_ARMOUR,
+ coinflip() ? SPARM_SEE_INVISIBLE
+ : SPARM_INTELLIGENCE );
+ }
+ break;
+
+ case ARM_GLOVES:
+ set_item_ego_type( mitm[p], OBJ_ARMOUR,
+ coinflip() ? SPARM_DEXTERITY
+ : SPARM_STRENGTH );
+ break;
+
+ case ARM_BOOTS:
+ switch (random2(3))
+ {
+ case 0:
+ if (mitm[p].plus2 == TBOOT_BOOTS)
+ set_item_ego_type(mitm[p], OBJ_ARMOUR, SPARM_RUNNING);
+ break;
+ case 1:
+ set_item_ego_type(mitm[p], OBJ_ARMOUR, SPARM_LEVITATION);
+ break;
+ case 2:
+ set_item_ego_type(mitm[p], OBJ_ARMOUR, SPARM_STEALTH);
+ break;
+ }
+ break;
+
+ case ARM_ROBE:
+ switch (random2(4))
+ {
+ case 0:
+ set_item_ego_type( mitm[p], OBJ_ARMOUR,
+ coinflip() ? SPARM_COLD_RESISTANCE
+ : SPARM_FIRE_RESISTANCE );
+ break;
+
+ case 1:
+ set_item_ego_type( mitm[p],
+ OBJ_ARMOUR, SPARM_MAGIC_RESISTANCE );
+ break;
+
+ case 2:
+ set_item_ego_type( mitm[p], OBJ_ARMOUR,
+ coinflip() ? SPARM_POSITIVE_ENERGY
+ : SPARM_RESISTANCE );
+ break;
+ case 3:
+ if (force_type != OBJ_RANDOM
+ || is_random_artefact( mitm[p] )
+ || get_armour_ego_type( mitm[p] ) != SPARM_NORMAL
+ || random2(50) > 10 + item_level)
+ {
+ break;
+ }
+
+ set_item_ego_type( mitm[p], OBJ_ARMOUR, SPARM_ARCHMAGI );
+ break;
+ }
+ break;
+
+ default: // other body armours:
+ set_item_ego_type( mitm[p], OBJ_ARMOUR,
+ coinflip() ? SPARM_COLD_RESISTANCE
+ : SPARM_FIRE_RESISTANCE );
+
+ if (one_chance_in(9))
+ {
+ set_item_ego_type( mitm[p],
+ OBJ_ARMOUR, SPARM_POSITIVE_ENERGY );
+ }
+
+ if (one_chance_in(5))
+ {
+ set_item_ego_type( mitm[p],
+ OBJ_ARMOUR, SPARM_MAGIC_RESISTANCE );
+ }
+
+ if (one_chance_in(5))
+ {
+ set_item_ego_type( mitm[p],
+ OBJ_ARMOUR, SPARM_POISON_RESISTANCE );
+ }
+
+ if (mitm[p].sub_type == ARM_PLATE_MAIL
+ && one_chance_in(15))
+ {
+ set_item_ego_type( mitm[p],
+ OBJ_ARMOUR, SPARM_PONDEROUSNESS );
+ mitm[p].plus += 3 + random2(4);
+ }
+ break;
+ }
+ }
+ }
+ else if (one_chance_in(12))
+ {
+ // mitm[p].plus = (coinflip() ? 99 : 98); // 98? 99?
+ do_curse_item( mitm[p] );
+
+ if (one_chance_in(5))
+ mitm[p].plus -= random2(3);
+
+ set_item_ego_type( mitm[p], OBJ_ARMOUR, SPARM_NORMAL );
+ }
+
+ // if not given a racial type, and special, give shiny/runed/etc desc.
+ if (cmp_equip_race( mitm[p], 0 )
+ && cmp_equip_desc( mitm[p], 0 )
+ && (((is_random_artefact(mitm[p])
+ || get_armour_ego_type( mitm[p] ) != SPARM_NORMAL)
+ && !one_chance_in(10))
+ || (mitm[p].plus != 0 && one_chance_in(3))))
+ {
+ switch (random2(3))
+ {
+ case 0:
+ set_equip_desc( mitm[p], ISFLAG_GLOWING );
+ break;
+
+ case 1:
+ set_equip_desc( mitm[p], ISFLAG_RUNED );
+ break;
+
+ case 2:
+ default:
+ set_equip_desc( mitm[p], ISFLAG_EMBROIDERED_SHINY );
+ break;
+ }
+ }
+
+ // Make sure you don't get a hide from acquirement (since that
+ // would be an enchanted item which somehow didn't get converted
+ // into armour).
+ if (item_level == MAKE_GOOD_ITEM)
+ hide2armour( &(mitm[p].sub_type) ); // what of animal hides? {dlb}
+
+ // skin armours + Crystal PM don't get special enchantments
+ // or species, but can be randarts
+ if (mitm[p].sub_type >= ARM_DRAGON_HIDE
+ && mitm[p].sub_type <= ARM_SWAMP_DRAGON_ARMOUR)
+ {
+ set_equip_race( mitm[p], ISFLAG_NO_RACE );
+ set_item_ego_type( mitm[p], OBJ_ARMOUR, SPARM_NORMAL );
+ }
+ break;
+
+ case OBJ_WANDS:
+ // determine sub_type:
+ if (force_type != OBJ_RANDOM)
+ mitm[p].sub_type = force_type;
+ else
+ {
+ mitm[p].sub_type = random2( NUM_WANDS );
+
+ // Adjusted distribution here -- bwr
+ // Wands used to be uniform (5.26% each)
+ //
+ // Now:
+ // invis, hasting, healing (1.11% each)
+ // fireball, teleportaion (3.74% each)
+ // others (6.37% each)
+ if ((mitm[p].sub_type == WAND_INVISIBILITY
+ || mitm[p].sub_type == WAND_HASTING
+ || mitm[p].sub_type == WAND_HEALING)
+ || ((mitm[p].sub_type == WAND_FIREBALL
+ || mitm[p].sub_type == WAND_TELEPORTATION)
+ && coinflip()))
+ {
+ mitm[p].sub_type = random2( NUM_WANDS );
+ }
+ }
+
+ // determine upper bound on charges:
+ range_charges = ((mitm[p].sub_type == WAND_HEALING
+ || mitm[p].sub_type == WAND_HASTING
+ || mitm[p].sub_type == WAND_INVISIBILITY) ? 8 :
+ (mitm[p].sub_type == WAND_FLAME
+ || mitm[p].sub_type == WAND_FROST
+ || mitm[p].sub_type == WAND_MAGIC_DARTS
+ || mitm[p].sub_type == WAND_RANDOM_EFFECTS) ? 28
+ : 16);
+
+ // generate charges randomly:
+ mitm[p].plus = random2avg(range_charges, 3);
+ //
+ // set quantity to one:
+ quant = 1;
+ break;
+
+ case OBJ_FOOD: // this can be parsed out {dlb}
+ // determine sub_type:
+ if (force_type == OBJ_RANDOM)
+ {
+ temp_rand = random2(1000);
+
+ mitm[p].sub_type =
+ ((temp_rand >= 750) ? FOOD_MEAT_RATION : // 25.00% chance
+ (temp_rand >= 450) ? FOOD_BREAD_RATION :// 30.00% chance
+ (temp_rand >= 350) ? FOOD_PEAR : // 10.00% chance
+ (temp_rand >= 250) ? FOOD_APPLE : // 10.00% chance
+ (temp_rand >= 150) ? FOOD_CHOKO : // 10.00% chance
+ (temp_rand >= 140) ? FOOD_CHEESE : // 1.00% chance
+ (temp_rand >= 130) ? FOOD_PIZZA : // 1.00% chance
+ (temp_rand >= 120) ? FOOD_SNOZZCUMBER : // 1.00% chance
+ (temp_rand >= 110) ? FOOD_APRICOT : // 1.00% chance
+ (temp_rand >= 100) ? FOOD_ORANGE : // 1.00% chance
+ (temp_rand >= 90) ? FOOD_BANANA : // 1.00% chance
+ (temp_rand >= 80) ? FOOD_STRAWBERRY : // 1.00% chance
+ (temp_rand >= 70) ? FOOD_RAMBUTAN : // 1.00% chance
+ (temp_rand >= 60) ? FOOD_LEMON : // 1.00% chance
+ (temp_rand >= 50) ? FOOD_GRAPE : // 1.00% chance
+ (temp_rand >= 40) ? FOOD_SULTANA : // 1.00% chance
+ (temp_rand >= 30) ? FOOD_LYCHEE : // 1.00% chance
+ (temp_rand >= 20) ? FOOD_BEEF_JERKY : // 1.00% chance
+ (temp_rand >= 10) ? FOOD_SAUSAGE : // 1.00% chance
+ (temp_rand >= 5) ? FOOD_HONEYCOMB // 0.50% chance
+ : FOOD_ROYAL_JELLY );// 0.50% chance
+ }
+ else
+ mitm[p].sub_type = force_type;
+
+ // Happens with ghoul food acquirement -- use place_chunks() outherwise
+ if (mitm[p].sub_type == FOOD_CHUNK)
+ {
+ for (count = 0; count < 1000; count++)
+ {
+ temp_rand = random2( NUM_MONSTERS ); // random monster
+ temp_rand = mons_charclass( temp_rand ); // corpse base type
+
+ if (mons_weight( temp_rand ) > 0) // drops a corpse
+ break;
+ }
+
+ // set chunk flavour (default to common dungeon rat steaks):
+ mitm[p].plus = (count == 1000) ? MONS_RAT : temp_rand;
+
+ // set duration
+ mitm[p].special = (10 + random2(11)) * 10;
+ }
+
+ // determine quantity:
+ if (allow_uniques > 1)
+ quant = allow_uniques;
+ else
+ {
+ quant = 1;
+
+ if (mitm[p].sub_type != FOOD_MEAT_RATION
+ && mitm[p].sub_type != FOOD_BREAD_RATION)
+ {
+ if (one_chance_in(80))
+ quant += random2(3);
+
+ if (mitm[p].sub_type == FOOD_STRAWBERRY
+ || mitm[p].sub_type == FOOD_GRAPE
+ || mitm[p].sub_type == FOOD_SULTANA)
+ {
+ quant += 3 + random2avg(15,2);
+ }
+ }
+ }
+ break;
+
+ case OBJ_POTIONS:
+ quant = 1;
+
+ if (one_chance_in(18))
+ quant++;
+
+ if (one_chance_in(25))
+ quant++;
+
+ if (force_type != OBJ_RANDOM)
+ mitm[p].sub_type = force_type;
+ else
+ {
+ temp_rand = random2(9); // general type of potion;
+
+ switch (temp_rand)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 8:
+ // healing potions
+ if (one_chance_in(3))
+ mitm[p].sub_type = POT_HEAL_WOUNDS; // 14.074%
+ else
+ mitm[p].sub_type = POT_HEALING; // 28.148%
+
+ if (one_chance_in(20))
+ mitm[p].sub_type = POT_CURE_MUTATION; // 2.222%
+ break;
+
+ case 3:
+ case 4:
+ // enhancements
+ if (coinflip())
+ mitm[p].sub_type = POT_SPEED; // 6.444%
+ else
+ mitm[p].sub_type = POT_MIGHT; // 6.444%
+
+ if (one_chance_in(10))
+ mitm[p].sub_type = POT_BERSERK_RAGE; // 1.432%
+
+ if (one_chance_in(5))
+ mitm[p].sub_type = POT_INVISIBILITY; // 3.580%
+
+ if (one_chance_in(6))
+ mitm[p].sub_type = POT_LEVITATION; // 3.580%
+
+ if (one_chance_in(30))
+ mitm[p].sub_type = POT_PORRIDGE; // 0.741%
+ break;
+
+ case 5:
+ // gain ability
+ mitm[p].sub_type = POT_GAIN_STRENGTH + random2(3); // 1.125%
+ // or 0.375% each
+
+ if (one_chance_in(10))
+ mitm[p].sub_type = POT_EXPERIENCE; // 0.125%
+
+ if (one_chance_in(10))
+ mitm[p].sub_type = POT_MAGIC; // 0.139%
+
+ if (!one_chance_in(8))
+ mitm[p].sub_type = POT_RESTORE_ABILITIES; // 9.722%
+
+ quant = 1;
+ break;
+
+ case 6:
+ case 7:
+ // bad things
+ switch (random2(6))
+ {
+ case 0:
+ case 4:
+ // is this not always the case? - no, level one is 0 {dlb}
+ if (item_level > 0)
+ {
+ mitm[p].sub_type = POT_POISON; // 6.475%
+
+ if (item_level > 10 && one_chance_in(4))
+ mitm[p].sub_type = POT_STRONG_POISON;
+
+ break;
+ }
+
+ /* **** intentional fall through **** */ // ignored for %
+ case 5:
+ if (item_level > 6)
+ {
+ mitm[p].sub_type = POT_MUTATION; // 3.237%
+ break;
+ }
+
+ /* **** intentional fall through **** */ // ignored for %
+ case 1:
+ mitm[p].sub_type = POT_SLOWING; // 3.237%
+ break;
+
+ case 2:
+ mitm[p].sub_type = POT_PARALYSIS; // 3.237%
+ break;
+
+ case 3:
+ mitm[p].sub_type = POT_CONFUSION; // 3.237%
+ break;
+
+ }
+
+ if (one_chance_in(8))
+ mitm[p].sub_type = POT_DEGENERATION; // 2.775%
+
+ if (one_chance_in(1000)) // 0.022%
+ mitm[p].sub_type = POT_DECAY;
+
+ break;
+ }
+ }
+
+ mitm[p].plus = 0;
+ break;
+
+ case OBJ_SCROLLS:
+ // determine sub_type:
+ if (force_type == OBJ_RANDOM)
+ {
+ // only used in certain cases {dlb}
+ int depth_mod = random2(1 + item_level);
+
+ temp_rand = random2(920);
+
+ mitm[p].sub_type =
+ ((temp_rand > 751) ? SCR_IDENTIFY : // 18.26%
+ (temp_rand > 629) ? SCR_REMOVE_CURSE : // 13.26%
+ (temp_rand > 554) ? SCR_TELEPORTATION : // 8.15%
+ (temp_rand > 494) ? SCR_DETECT_CURSE : // 6.52%
+ (temp_rand > 464) ? SCR_FEAR : // 3.26%
+ (temp_rand > 434) ? SCR_NOISE : // 3.26%
+ (temp_rand > 404) ? SCR_MAGIC_MAPPING : // 3.26%
+ (temp_rand > 374) ? SCR_FORGETFULNESS : // 3.26%
+ (temp_rand > 344) ? SCR_RANDOM_USELESSNESS :// 3.26%
+ (temp_rand > 314) ? SCR_CURSE_WEAPON : // 3.26%
+ (temp_rand > 284) ? SCR_CURSE_ARMOUR : // 3.26%
+ (temp_rand > 254) ? SCR_RECHARGING : // 3.26%
+ (temp_rand > 224) ? SCR_BLINKING : // 3.26%
+ (temp_rand > 194) ? SCR_PAPER : // 3.26%
+ (temp_rand > 164) ? SCR_ENCHANT_ARMOUR : // 3.26%
+ (temp_rand > 134) ? SCR_ENCHANT_WEAPON_I : // 3.26%
+ (temp_rand > 104) ? SCR_ENCHANT_WEAPON_II : // 3.26%
+
+ // Crawl is kind to newbie adventurers {dlb}:
+ // yes -- these five are messy {dlb}:
+ // yes they are a hellish mess of tri-ops and long lines,
+ // this formating is somewhat better -- bwr
+ (temp_rand > 74) ?
+ ((item_level < 4) ? SCR_TELEPORTATION
+ : SCR_IMMOLATION) : // 3.26%
+ (temp_rand > 59) ?
+ ((depth_mod < 4) ? SCR_TELEPORTATION
+ : SCR_ACQUIREMENT) : // 1.63%
+ (temp_rand > 44) ?
+ ((depth_mod < 4) ? SCR_DETECT_CURSE
+ : SCR_SUMMONING) : // 1.63%
+ (temp_rand > 29) ?
+ ((depth_mod < 4) ? SCR_TELEPORTATION // 1.63%
+ : SCR_ENCHANT_WEAPON_III) :
+ (temp_rand > 14) ?
+ ((depth_mod < 7) ? SCR_DETECT_CURSE
+ : SCR_TORMENT) // 1.63%
+ // default:
+ : ((depth_mod < 7) ? SCR_TELEPORTATION // 1.63%
+ : SCR_VORPALISE_WEAPON));
+ }
+ else
+ mitm[p].sub_type = force_type;
+
+ // determine quantity:
+ temp_rand = random2(48);
+
+ quant = ((temp_rand > 1
+ || mitm[p].sub_type == SCR_VORPALISE_WEAPON
+ || mitm[p].sub_type == SCR_ENCHANT_WEAPON_III
+ || mitm[p].sub_type == SCR_ACQUIREMENT
+ || mitm[p].sub_type == SCR_TORMENT) ? 1 : // 95.83%
+ (temp_rand == 0) ? 2 // 2.08%
+ : 3); // 2.08%
+ mitm[p].plus = 0;
+ break;
+
+ case OBJ_JEWELLERY:
+ // determine whether an unrandart will be generated {dlb}:
+ if (item_level > 2
+ && you.level_type != LEVEL_ABYSS
+ && you.level_type != LEVEL_PANDEMONIUM
+ && random2(2000) <= 100 + (item_level * 3)
+ && one_chance_in(20))
+ {
+ icky = find_okay_unrandart(OBJ_JEWELLERY);
+
+ if (icky != -1)
+ {
+ quant = 1;
+ make_item_unrandart( mitm[p], icky );
+ break;
+ }
+ }
+
+ // otherwise, determine jewellery type {dlb}:
+ if (force_type == OBJ_RANDOM)
+ {
+ mitm[p].sub_type = (!one_chance_in(4) ? random2(24) // rings
+ : AMU_RAGE + random2(10));
+
+ // Adjusted distribution here -- bwr
+ if ((mitm[p].sub_type == RING_INVISIBILITY
+ || mitm[p].sub_type == RING_REGENERATION
+ || mitm[p].sub_type == RING_TELEPORT_CONTROL
+ || mitm[p].sub_type == RING_SLAYING)
+ && !one_chance_in(3))
+ {
+ mitm[p].sub_type = random2(24);
+ }
+ }
+ else
+ mitm[p].sub_type = force_type;
+
+ // quantity is always one {dlb}:
+ quant = 1;
+
+ // everything begins as uncursed, unenchanted jewellery {dlb}:
+ mitm[p].plus = 0;
+ mitm[p].plus2 = 0;
+
+ // set pluses for rings that require them {dlb}:
+ switch (mitm[p].sub_type)
+ {
+ case RING_PROTECTION:
+ case RING_STRENGTH:
+ case RING_SLAYING:
+ case RING_EVASION:
+ case RING_DEXTERITY:
+ case RING_INTELLIGENCE:
+ if (one_chance_in(5)) // 20% of such rings are cursed {dlb}
+ {
+ do_curse_item( mitm[p] );
+ mitm[p].plus = (coinflip() ? -2 : -3);
+
+ if (one_chance_in(3))
+ mitm[p].plus -= random2(4);
+ }
+ else
+ {
+ mitm[p].plus += 1 + (one_chance_in(3) ? random2(3)
+ : random2avg(6, 2));
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // rings of slaying also require that pluses2 be set {dlb}:
+ if (mitm[p].sub_type == RING_SLAYING)
+ {
+ if (item_cursed( mitm[p] ) && !one_chance_in(20))
+ mitm[p].plus2 = -1 - random2avg(6, 2);
+ else
+ {
+ mitm[p].plus2 += 1 + (one_chance_in(3) ? random2(3)
+ : random2avg(6, 2));
+
+ if (random2(25) < 9) // 36% of such rings {dlb}
+ {
+ // make "ring of damage"
+ do_uncurse_item( mitm[p] );
+ mitm[p].plus = 0;
+ mitm[p].plus2 += 2;
+ }
+ }
+ }
+
+ // All jewellery base types should now work. -- bwr
+ if (allow_uniques == 1 && item_level > 2
+ && random2(2000) <= 100 + (item_level * 3) && coinflip())
+ {
+ make_item_randart( mitm[p] );
+ break;
+ }
+
+ // rings of hunger and teleportation are always cursed {dlb}:
+ if (mitm[p].sub_type == RING_HUNGER
+ || mitm[p].sub_type == RING_TELEPORTATION
+ || one_chance_in(50))
+ {
+ do_curse_item( mitm[p] );
+ }
+ break;
+
+ case OBJ_BOOKS:
+ create_book:
+ do
+ {
+ mitm[p].sub_type = random2(NUM_BOOKS);
+
+ if (book_rarity(mitm[p].sub_type) == 100)
+ continue;
+
+ if (mitm[p].sub_type != BOOK_DESTRUCTION
+ && mitm[p].sub_type != BOOK_MANUAL)
+ {
+ if (one_chance_in(10))
+ {
+ if (coinflip())
+ mitm[p].sub_type = BOOK_WIZARDRY;
+ else
+ mitm[p].sub_type = BOOK_POWER;
+ }
+
+ if (random2(item_level + 1) + 1 >= book_rarity(mitm[p].sub_type)
+ || one_chance_in(100))
+ {
+ break;
+ }
+ else
+ {
+ mitm[p].sub_type = BOOK_DESTRUCTION;
+ continue;
+ }
+ }
+ }
+ while (mitm[p].sub_type == BOOK_DESTRUCTION
+ || mitm[p].sub_type == BOOK_MANUAL);
+
+ if (book_rarity(mitm[p].sub_type) == 100)
+ goto create_book;
+
+ mitm[p].special = random2(5);
+
+ if (one_chance_in(10))
+ mitm[p].special += random2(8) * 10;
+
+ if (force_type != OBJ_RANDOM)
+ mitm[p].sub_type = force_type;
+
+ quant = 1;
+
+ // tome of destruction : rare!
+ if (force_type == BOOK_DESTRUCTION
+ || (random2(7000) <= item_level + 20 && item_level > 10
+ && force_type == OBJ_RANDOM))
+ {
+ mitm[p].sub_type = BOOK_DESTRUCTION;
+ }
+
+ // skill manuals - also rare
+ // fixed to generate manuals for *all* extant skills - 14mar2000 {dlb}
+ if (force_type == BOOK_MANUAL
+ || (random2(4000) <= item_level + 20 && item_level > 6
+ && force_type == OBJ_RANDOM))
+ {
+ mitm[p].sub_type = BOOK_MANUAL;
+
+ if (one_chance_in(4))
+ {
+ mitm[p].plus = SK_SPELLCASTING
+ + random2(NUM_SKILLS - SK_SPELLCASTING);
+ }
+ else
+ {
+ mitm[p].plus = random2(SK_UNARMED_COMBAT);
+
+ if (mitm[p].plus == SK_UNUSED_1)
+ mitm[p].plus = SK_UNARMED_COMBAT;
+ }
+ }
+ break;
+
+ case OBJ_STAVES: // this can be parsed, too {dlb}
+ if (force_type != OBJ_RANDOM)
+ mitm[p].sub_type = force_type;
+ else
+ {
+ mitm[p].sub_type = random2(13);
+
+ // top three non-spell staves are in separate block -- bwr
+ if (mitm[p].sub_type >= 10)
+ mitm[p].sub_type = STAFF_AIR + mitm[p].sub_type - 10;
+
+ // spell staves
+ if (one_chance_in(20))
+ mitm[p].sub_type = STAFF_SMITING + random2(10);
+
+ if ((mitm[p].sub_type == STAFF_ENERGY
+ || mitm[p].sub_type == STAFF_CHANNELING) && one_chance_in(4))
+ {
+ mitm[p].sub_type = coinflip() ? STAFF_WIZARDRY : STAFF_POWER;
+ }
+ }
+
+ mitm[p].special = random2(9);
+
+ quant = 1;
+ break;
+
+ case OBJ_ORBS: // always forced in current setup {dlb}
+ quant = 1;
+
+ if (force_type != OBJ_RANDOM)
+ mitm[p].sub_type = force_type;
+
+ // I think we only have one type of orb now, so ... {dlb}
+ set_unique_item_status( OBJ_ORBS, mitm[p].sub_type, UNIQ_EXISTS );
+ break;
+
+ // I think these must always be forced, too ... {dlb}
+
+ case OBJ_MISCELLANY: //mv: rewrote with use of NUM_MISCELLANY (9 Aug 01)
+ if (force_type == OBJ_RANDOM)
+ {
+ do
+ mitm[p].sub_type = random2(NUM_MISCELLANY);
+ while //mv: never generated
+ ((mitm[p].sub_type == MISC_RUNE_OF_ZOT)
+ || (mitm[p].sub_type == MISC_HORN_OF_GERYON)
+ || (mitm[p].sub_type == MISC_PORTABLE_ALTAR_OF_NEMELEX)
+ // mv: others are possible but less often
+ // btw. chances of generating decks are almost the same as
+ // before, other chances are now distributed more steadily
+ || (mitm[p].sub_type == MISC_DECK_OF_POWER && !one_chance_in(12))
+ || (mitm[p].sub_type == MISC_DECK_OF_SUMMONINGS && !one_chance_in(3))
+ || (mitm[p].sub_type == MISC_DECK_OF_TRICKS && !one_chance_in(3))
+ || (mitm[p].sub_type == MISC_DECK_OF_WONDERS && !one_chance_in(3))
+ );
+
+ // filling those silly empty boxes -- bwr
+ if (mitm[p].sub_type == MISC_EMPTY_EBONY_CASKET
+ && !one_chance_in(20))
+ {
+ mitm[p].sub_type = MISC_BOX_OF_BEASTS;
+ }
+ }
+ else
+ {
+ mitm[p].sub_type = force_type;
+ }
+
+ if (mitm[p].sub_type == MISC_DECK_OF_WONDERS
+ || mitm[p].sub_type == MISC_DECK_OF_SUMMONINGS
+ || mitm[p].sub_type == MISC_DECK_OF_POWER)
+ {
+ mitm[p].plus = 4 + random2(10);
+ }
+
+ if (mitm[p].sub_type == MISC_DECK_OF_TRICKS)
+ mitm[p].plus = 6 + random2avg(15, 2);
+
+ if (mitm[p].sub_type == MISC_RUNE_OF_ZOT)
+ mitm[p].plus = item_race;
+
+ quant = 1;
+ break; // mv: end of rewrote;
+
+ // that is, everything turns to gold if not enumerated above, so ... {dlb}
+ default:
+ mitm[p].base_type = OBJ_GOLD;
+
+ // Note that acquirement level gold gives much less than the
+ // price of a scroll of acquirement (520 gold). -- bwr
+ if (item_level == MAKE_GOOD_ITEM)
+ quant = 50 + random2avg(100, 2) + random2avg(100, 2);
+ else
+ quant = 1 + random2avg(19, 2) + random2(item_level);
+ break;
+ }
+
+ mitm[p].quantity = quant;
+
+ // should really only be used for monster inventories.
+ if (dont_place)
+ {
+ mitm[p].x = 0;
+ mitm[p].y = 0;
+ mitm[p].link = NON_ITEM;
+ }
+ else
+ {
+ do
+ {
+ x_pos = random2(GXM);
+ y_pos = random2(GYM);
+ }
+ while (grd[x_pos][y_pos] != DNGN_FLOOR);
+
+ move_item_to_grid( &p, x_pos, y_pos );
+ }
+
+ item_colour( mitm[p] );
+
+ // Okay, this check should be redundant since the purpose of
+ // this function is to create valid items. Still, we're adding
+ // this safety for fear that a report of Trog giving a non-existant
+ // item might symbolize something more serious. -- bwr
+ return (is_valid_item( mitm[p] ) ? p : NON_ITEM);
+} // end items()
+
+
+void give_item(int mid, int level_number) //mv: cleanup+minor changes
+{
+ int temp_rand = 0; // probability determination {dlb}
+
+ int bp = 0;
+ int thing_created = 0;
+ int hand_used = 0; // for Ettins etc.
+ int xitc = 0;
+ int xitt = 0;
+
+ int iquan = 0;
+ // forces colour and quantity, too for intial weapons {dlb}
+ int force_item = 0;
+
+ int item_race = MAKE_ITEM_RANDOM_RACE;
+ int give_level = level_number;
+
+ //mv: THIS CODE DISTRIBUTES WANDS/SCROLLS/POTIONS
+ //(now only to uniques but it's easy to modify that)
+ //7 Aug 01
+
+ //mv - give scroll
+
+ if (mons_is_unique( menv[mid].type ) && one_chance_in(3))
+ {
+ thing_created = items(0, OBJ_SCROLLS, OBJ_RANDOM, true, give_level, 0);
+ if (thing_created == NON_ITEM)
+ return;
+
+ mitm[thing_created].flags = 0;
+ menv[mid].inv[MSLOT_SCROLL] = thing_created;
+ }
+
+ //mv - give wand
+ if (mons_is_unique( menv[mid].type ) && one_chance_in(5))
+ {
+ thing_created = items(0, OBJ_WANDS, OBJ_RANDOM, true, give_level, 0);
+ if (thing_created == NON_ITEM)
+ return;
+
+ mitm[thing_created].flags = 0;
+ menv[mid].inv[MSLOT_WAND] = thing_created;
+ }
+
+ //mv - give potion
+ if (mons_is_unique( menv[mid].type ) && one_chance_in(3))
+ {
+ thing_created = items(0, OBJ_POTIONS, OBJ_RANDOM, true, give_level, 0);
+ if (thing_created == NON_ITEM)
+ return;
+
+ mitm[thing_created].flags = 0;
+ menv[mid].inv[MSLOT_POTION] = thing_created;
+ }
+
+
+ //end of DISTRIBUTE WANDS/POTIONS/SCROLLS CODE
+
+ bp = get_item_slot();
+ if (bp == NON_ITEM)
+ return;
+
+ mitm[bp].quantity = 0; // set below if force_item, else we toss this item!
+ mitm[bp].plus = 0;
+ mitm[bp].plus2 = 0;
+ mitm[bp].special = 0;
+
+ // this flags things to "goto give_armour" below ... {dlb}
+ mitm[bp].base_type = 101;
+
+ if (menv[mid].type == MONS_DANCING_WEAPON
+ && player_in_branch( BRANCH_HALL_OF_BLADES ))
+ {
+ give_level = MAKE_GOOD_ITEM;
+ }
+
+ // moved setting of quantity here to keep it in mind {dlb}
+ iquan = 1;
+ // I wonder if this is even used, given calls to item() {dlb}
+
+
+ switch (menv[mid].type)
+ {
+ case MONS_KOBOLD:
+ // a few of the smarter kobolds have blowguns.
+ if (one_chance_in(15) && level_number > 1)
+ {
+ mitm[bp].base_type = OBJ_WEAPONS;
+ mitm[bp].sub_type = WPN_BLOWGUN;
+ break;
+ }
+ // intentional fallthrough
+ case MONS_BIG_KOBOLD:
+ if (random2(5) < 3) // give hand weapon
+ {
+ mitm[bp].base_type = OBJ_WEAPONS;
+
+ temp_rand = random2(5);
+ mitm[bp].sub_type = ((temp_rand > 2) ? WPN_DAGGER : // 40%
+ (temp_rand > 0) ? WPN_SHORT_SWORD // 40%
+ : WPN_CLUB); // 20%
+ }
+ else if (random2(5) < 2) // give darts
+ {
+ item_race = MAKE_ITEM_NO_RACE;
+ mitm[bp].base_type = OBJ_MISSILES;
+ mitm[bp].sub_type = MI_DART;
+ iquan = 1 + random2(5);
+ }
+ else
+ goto give_ammo;
+ break;
+
+ case MONS_HOBGOBLIN:
+ if (one_chance_in(3))
+ item_race = MAKE_ITEM_ORCISH;
+
+ if (random2(5) < 3) // give hand weapon
+ {
+ mitm[bp].base_type = OBJ_WEAPONS;
+ mitm[bp].sub_type = WPN_CLUB;
+ }
+ else
+ goto give_ammo;
+ break;
+
+ case MONS_GOBLIN:
+ if (one_chance_in(3))
+ item_race = MAKE_ITEM_ORCISH;
+
+ if (one_chance_in(12) && level_number > 1)
+ {
+ mitm[bp].base_type = OBJ_WEAPONS;
+ mitm[bp].base_type = WPN_BLOWGUN;
+ break;
+ }
+ // deliberate fall through {dlb}
+ case MONS_JESSICA:
+ case MONS_IJYB:
+ if (random2(5) < 3) // < 1 // give hand weapon
+ {
+ mitm[bp].base_type = OBJ_WEAPONS;
+ mitm[bp].sub_type = (coinflip() ? WPN_DAGGER : WPN_CLUB);
+ }
+ else
+ goto give_ammo;
+ break;
+
+ case MONS_WIGHT:
+ case MONS_NORRIS:
+ mitm[bp].base_type = OBJ_WEAPONS;
+ mitm[bp].sub_type = (one_chance_in(6) ? WPN_WAR_AXE + random2(4)
+ : WPN_MACE + random2(12));
+
+ if (coinflip())
+ {
+ force_item = 1;
+ item_race = MAKE_ITEM_NO_RACE;
+ mitm[bp].plus += 1 + random2(3);
+ mitm[bp].plus2 += 1 + random2(3);
+
+ if (one_chance_in(5))
+ set_item_ego_type( mitm[bp], OBJ_WEAPONS, SPWPN_FREEZING );
+ }
+
+ if (one_chance_in(3))
+ do_curse_item( mitm[bp] );
+ break;
+
+ case MONS_GNOLL:
+ case MONS_OGRE_MAGE:
+ case MONS_NAGA_WARRIOR:
+ case MONS_GREATER_NAGA:
+ case MONS_EDMUND:
+ case MONS_DUANE:
+ item_race = MAKE_ITEM_NO_RACE;
+
+ if (!one_chance_in(5))
+ {
+ mitm[bp].base_type = OBJ_WEAPONS;
+
+ temp_rand = random2(5);
+ mitm[bp].sub_type = ((temp_rand > 2) ? WPN_SPEAR : // 40%
+ (temp_rand == 2) ? WPN_FLAIL : // 20%
+ (temp_rand == 1) ? WPN_HALBERD // 20%
+ : WPN_CLUB); // 20%
+ }
+ break;
+
+ case MONS_ORC:
+ if (one_chance_in(15) && level_number > 1)
+ {
+ mitm[bp].base_type = OBJ_WEAPONS;
+ mitm[bp].base_type = WPN_BLOWGUN;
+ break;
+ }
+ // deliberate fall through {gdl}
+ case MONS_ORC_PRIEST:
+ item_race = MAKE_ITEM_ORCISH;
+ // deliberate fall through {dlb}
+ case MONS_TERENCE:
+ if (!one_chance_in(5))
+ {
+ mitm[bp].base_type = OBJ_WEAPONS;
+
+ temp_rand = random2(240);
+ mitm[bp].sub_type = ((temp_rand > 209) ? WPN_DAGGER : //12.50%
+ (temp_rand > 179) ? WPN_CLUB : //12.50%
+ (temp_rand > 152) ? WPN_FLAIL : //11.25%
+ (temp_rand > 128) ? WPN_HAND_AXE : //10.00%
+ (temp_rand > 108) ? WPN_HAMMER : // 8.33%
+ (temp_rand > 88) ? WPN_HALBERD : // 8.33%
+ (temp_rand > 68) ? WPN_SHORT_SWORD : // 8.33%
+ (temp_rand > 48) ? WPN_MACE : // 8.33%
+ (temp_rand > 38) ? WPN_WHIP : // 4.17%
+ (temp_rand > 28) ? WPN_TRIDENT : // 4.17%
+ (temp_rand > 18) ? WPN_FALCHION : // 4.17%
+ (temp_rand > 8) ? WPN_MORNINGSTAR : // 4.17%
+ (temp_rand > 2) ? WPN_WAR_AXE // 2.50%
+ : WPN_SPIKED_FLAIL);// 1.25%
+ }
+ else
+ goto give_ammo;
+ break;
+
+ case MONS_DEEP_ELF_FIGHTER:
+ case MONS_DEEP_ELF_HIGH_PRIEST:
+ case MONS_DEEP_ELF_KNIGHT:
+ case MONS_DEEP_ELF_PRIEST:
+ case MONS_DEEP_ELF_SOLDIER:
+ item_race = MAKE_ITEM_ELVEN;
+ mitm[bp].base_type = OBJ_WEAPONS;
+
+ temp_rand = random2(8);
+ mitm[bp].sub_type = ((temp_rand > 5) ? WPN_LONG_SWORD : // 2 in 8
+ (temp_rand > 3) ? WPN_SHORT_SWORD : // 2 in 8
+ (temp_rand > 2) ? WPN_SCIMITAR : // 1 in 8
+ (temp_rand > 1) ? WPN_MACE : // 1 in 8
+ (temp_rand > 0) ? WPN_BOW // 1 in 8
+ : WPN_HAND_CROSSBOW); // 1 in 8
+ break;
+
+ case MONS_DEEP_ELF_ANNIHILATOR:
+ case MONS_DEEP_ELF_CONJURER:
+ case MONS_DEEP_ELF_DEATH_MAGE:
+ case MONS_DEEP_ELF_DEMONOLOGIST:
+ case MONS_DEEP_ELF_MAGE:
+ case MONS_DEEP_ELF_SORCERER:
+ case MONS_DEEP_ELF_SUMMONER:
+ item_race = MAKE_ITEM_ELVEN;
+ mitm[bp].base_type = OBJ_WEAPONS;
+
+ temp_rand = random2(6);
+ mitm[bp].sub_type = ((temp_rand > 3) ? WPN_LONG_SWORD : // 2 in 6
+ (temp_rand > 2) ? WPN_SHORT_SWORD :// 1 in 6
+ (temp_rand > 1) ? WPN_SABRE : // 1 in 6
+ (temp_rand > 0) ? WPN_DAGGER // 1 in 6
+ : WPN_WHIP); // 1 in 6
+ break;
+
+ case MONS_ORC_WARRIOR:
+ case MONS_ORC_HIGH_PRIEST:
+ case MONS_BLORK_THE_ORC:
+ item_race = MAKE_ITEM_ORCISH;
+ // deliberate fall-through {dlb}
+ case MONS_DANCING_WEAPON: // give_level may have been adjusted above
+ case MONS_FRANCES:
+ case MONS_FRANCIS:
+ case MONS_HAROLD:
+ case MONS_JOSEPH:
+ case MONS_LOUISE:
+ case MONS_MICHAEL:
+ case MONS_NAGA:
+ case MONS_NAGA_MAGE:
+ case MONS_RUPERT:
+ case MONS_SKELETAL_WARRIOR:
+ case MONS_WAYNE:
+ mitm[bp].base_type = OBJ_WEAPONS;
+
+ temp_rand = random2(120);
+ mitm[bp].sub_type = ((temp_rand > 109) ? WPN_LONG_SWORD : // 8.33%
+ (temp_rand > 99) ? WPN_SHORT_SWORD : // 8.33%
+ (temp_rand > 89) ? WPN_SCIMITAR : // 8.33%
+ (temp_rand > 79) ? WPN_BATTLEAXE : // 8.33%
+ (temp_rand > 69) ? WPN_HAND_AXE : // 8.33%
+ (temp_rand > 59) ? WPN_HALBERD : // 8.33%
+ (temp_rand > 49) ? WPN_GLAIVE : // 8.33%
+ (temp_rand > 39) ? WPN_MORNINGSTAR : // 8.33%
+ (temp_rand > 29) ? WPN_GREAT_MACE : // 8.33%
+ (temp_rand > 19) ? WPN_TRIDENT : // 8.33%
+ (temp_rand > 10) ? WPN_WAR_AXE : // 7.50%
+ (temp_rand > 1) ? WPN_FLAIL : // 7.50%
+ (temp_rand > 0) ? WPN_BROAD_AXE // 0.83%
+ : WPN_SPIKED_FLAIL); // 0.83%
+ break;
+
+ case MONS_ORC_WARLORD:
+ // being at the top has it's priviledges
+ if (one_chance_in(3))
+ give_level = MAKE_GOOD_ITEM;
+ // deliberate fall-through
+ case MONS_ORC_KNIGHT:
+ item_race = MAKE_ITEM_ORCISH;
+ // deliberate fall-through, I guess {dlb}
+ case MONS_NORBERT:
+ case MONS_JOZEF:
+ case MONS_URUG:
+ case MONS_VAULT_GUARD:
+ case MONS_VAMPIRE_KNIGHT:
+ mitm[bp].base_type = OBJ_WEAPONS;
+
+ temp_rand = random2(24);
+ mitm[bp].sub_type = ((temp_rand > 19) ? WPN_GREAT_SWORD :// 16.67%
+ (temp_rand > 15) ? WPN_LONG_SWORD : // 16.67%
+ (temp_rand > 11) ? WPN_BATTLEAXE : // 16.67%
+ (temp_rand > 7) ? WPN_WAR_AXE : // 16.67%
+ (temp_rand > 5) ? WPN_GREAT_MACE : // 8.33%
+ (temp_rand > 3) ? WPN_GREAT_FLAIL :// 8.33%
+ (temp_rand > 1) ? WPN_GLAIVE : // 8.33%
+ (temp_rand > 0) ? WPN_BROAD_AXE // 4.17%
+ : WPN_HALBERD); // 4.17%
+
+ if (one_chance_in(4))
+ mitm[bp].plus += 1 + random2(3);
+ break;
+
+ case MONS_CYCLOPS:
+ case MONS_STONE_GIANT:
+ item_race = MAKE_ITEM_NO_RACE;
+ mitm[bp].base_type = OBJ_MISSILES;
+ mitm[bp].sub_type = MI_LARGE_ROCK;
+ break;
+
+ case MONS_TWO_HEADED_OGRE:
+ case MONS_ETTIN:
+ item_race = MAKE_ITEM_NO_RACE;
+ hand_used = 0;
+
+ if (menv[mid].inv[MSLOT_WEAPON] != NON_ITEM)
+ hand_used = 1;
+
+ mitm[bp].base_type = OBJ_WEAPONS;
+ mitm[bp].sub_type = (one_chance_in(3) ? WPN_GIANT_SPIKED_CLUB
+ : WPN_GIANT_CLUB);
+
+ if (one_chance_in(10) || menv[mid].type == MONS_ETTIN)
+ {
+ mitm[bp].sub_type = ((one_chance_in(10)) ? WPN_GREAT_FLAIL
+ : WPN_GREAT_MACE);
+ }
+ break;
+
+ case MONS_REAPER:
+ give_level = MAKE_GOOD_ITEM;
+ // intentional fall-through...
+
+ case MONS_SIGMUND:
+ item_race = MAKE_ITEM_NO_RACE;
+ mitm[bp].base_type = OBJ_WEAPONS;
+ mitm[bp].sub_type = WPN_SCYTHE;
+ break;
+
+ case MONS_BALRUG:
+ item_race = MAKE_ITEM_NO_RACE;
+ mitm[bp].base_type = OBJ_WEAPONS;
+ mitm[bp].sub_type = WPN_DEMON_WHIP;
+ break;
+
+ case MONS_RED_DEVIL:
+ if (!one_chance_in(3))
+ {
+ item_race = MAKE_ITEM_NO_RACE;
+ mitm[bp].base_type = OBJ_WEAPONS;
+ mitm[bp].sub_type = (one_chance_in(3) ? WPN_DEMON_TRIDENT
+ : WPN_TRIDENT);
+ }
+ break;
+
+ case MONS_OGRE:
+ case MONS_HILL_GIANT:
+ case MONS_EROLCHA:
+ item_race = MAKE_ITEM_NO_RACE;
+ mitm[bp].base_type = OBJ_WEAPONS;
+
+ mitm[bp].sub_type = (one_chance_in(3) ? WPN_GIANT_SPIKED_CLUB
+ : WPN_GIANT_CLUB);
+
+ if (one_chance_in(10))
+ {
+ mitm[bp].sub_type = (one_chance_in(10) ? WPN_GREAT_FLAIL
+ : WPN_GREAT_MACE);
+ }
+ break;
+
+ case MONS_CENTAUR:
+ case MONS_CENTAUR_WARRIOR:
+ item_race = MAKE_ITEM_NO_RACE;
+ mitm[bp].base_type = OBJ_WEAPONS;
+ mitm[bp].sub_type = WPN_BOW;
+ break;
+
+ case MONS_YAKTAUR:
+ case MONS_YAKTAUR_CAPTAIN:
+ item_race = MAKE_ITEM_NO_RACE;
+ mitm[bp].base_type = OBJ_WEAPONS;
+ mitm[bp].sub_type = WPN_CROSSBOW;
+ break;
+
+ case MONS_EFREET:
+ case MONS_ERICA:
+ force_item = 1;
+ item_race = MAKE_ITEM_NO_RACE;
+ mitm[bp].base_type = OBJ_WEAPONS;
+ mitm[bp].sub_type = WPN_SCIMITAR;
+ mitm[bp].plus = random2(5);
+ mitm[bp].plus2 = random2(5);
+ mitm[bp].colour = RED; // forced by force_item above {dlb}
+ set_item_ego_type( mitm[bp], OBJ_WEAPONS, SPWPN_FLAMING );
+ break;
+
+ case MONS_ANGEL:
+ force_item = 1;
+ mitm[bp].base_type = OBJ_WEAPONS;
+ mitm[bp].colour = WHITE; // forced by force_item above {dlb}
+
+ set_equip_desc( mitm[bp], ISFLAG_GLOWING );
+ if (one_chance_in(3))
+ {
+ mitm[bp].sub_type = (one_chance_in(3) ? WPN_GREAT_MACE : WPN_MACE);
+ set_item_ego_type( mitm[bp], OBJ_WEAPONS, SPWPN_HOLY_WRATH );
+ }
+ else
+ {
+ mitm[bp].sub_type = WPN_LONG_SWORD;
+ }
+
+ mitm[bp].plus = 1 + random2(3);
+ mitm[bp].plus2 = 1 + random2(3);
+ break;
+
+ case MONS_DAEVA:
+ force_item = 1;
+ mitm[bp].base_type = OBJ_WEAPONS;
+ mitm[bp].colour = WHITE; // forced by force_item above {dlb}
+
+ mitm[bp].sub_type = (one_chance_in(4) ? WPN_GREAT_SWORD
+ : WPN_LONG_SWORD);
+
+ set_equip_desc( mitm[bp], ISFLAG_GLOWING );
+ set_item_ego_type( mitm[bp], OBJ_WEAPONS, SPWPN_HOLY_WRATH );
+ mitm[bp].plus = 1 + random2(3);
+ mitm[bp].plus2 = 1 + random2(3);
+ break;
+
+ case MONS_HELL_KNIGHT:
+ case MONS_MAUD:
+ case MONS_ADOLF:
+ case MONS_MARGERY:
+ force_item = 1;
+ mitm[bp].base_type = OBJ_WEAPONS;
+ mitm[bp].sub_type = WPN_LONG_SWORD + random2(3);
+
+ if (one_chance_in(7))
+ mitm[bp].sub_type = WPN_HALBERD;
+ if (one_chance_in(7))
+ mitm[bp].sub_type = WPN_GLAIVE;
+ if (one_chance_in(7))
+ mitm[bp].sub_type = WPN_GREAT_MACE;
+ if (one_chance_in(7))
+ mitm[bp].sub_type = WPN_BATTLEAXE;
+ if (one_chance_in(7))
+ mitm[bp].sub_type = WPN_WAR_AXE;
+ if (one_chance_in(7))
+ mitm[bp].sub_type = WPN_BROAD_AXE;
+ if (one_chance_in(7))
+ mitm[bp].sub_type = WPN_DEMON_TRIDENT;
+ if (one_chance_in(7))
+ mitm[bp].sub_type = WPN_DEMON_BLADE;
+ if (one_chance_in(7))
+ mitm[bp].sub_type = WPN_DEMON_WHIP;
+
+ temp_rand = random2(3);
+ set_equip_desc( mitm[bp], (temp_rand == 1) ? ISFLAG_GLOWING :
+ (temp_rand == 2) ? ISFLAG_RUNED
+ : ISFLAG_NO_DESC );
+
+ if (one_chance_in(3))
+ set_item_ego_type( mitm[bp], OBJ_WEAPONS, SPWPN_FLAMING );
+ else if (one_chance_in(3))
+ {
+ temp_rand = random2(5);
+
+ set_item_ego_type( mitm[bp], OBJ_WEAPONS,
+ ((temp_rand == 0) ? SPWPN_DRAINING :
+ (temp_rand == 1) ? SPWPN_VORPAL :
+ (temp_rand == 2) ? SPWPN_PAIN :
+ (temp_rand == 3) ? SPWPN_DISTORTION
+ : SPWPN_SPEED) );
+ }
+
+ mitm[bp].plus += random2(6);
+ mitm[bp].plus2 += random2(6);
+
+ mitm[bp].colour = RED; // forced by force_item above {dlb}
+
+ if (one_chance_in(3))
+ mitm[bp].colour = DARKGREY;
+ if (one_chance_in(5))
+ mitm[bp].colour = CYAN;
+ break;
+
+ case MONS_FIRE_GIANT:
+ force_item = 1;
+ mitm[bp].base_type = OBJ_WEAPONS;
+ mitm[bp].sub_type = WPN_GREAT_SWORD;
+ mitm[bp].plus = 0;
+ mitm[bp].plus2 = 0;
+ set_item_ego_type( mitm[bp], OBJ_WEAPONS, SPWPN_FLAMING );
+
+ mitm[bp].colour = RED; // forced by force_item above {dlb}
+ if (one_chance_in(3))
+ mitm[bp].colour = DARKGREY;
+ if (one_chance_in(5))
+ mitm[bp].colour = CYAN;
+ break;
+
+ case MONS_FROST_GIANT:
+ force_item = 1;
+ mitm[bp].base_type = OBJ_WEAPONS;
+ mitm[bp].sub_type = WPN_BATTLEAXE;
+ mitm[bp].plus = 0;
+ mitm[bp].plus2 = 0;
+ set_item_ego_type( mitm[bp], OBJ_WEAPONS, SPWPN_FREEZING );
+
+ // forced by force_item above {dlb}
+ mitm[bp].colour = (one_chance_in(3) ? WHITE : CYAN);
+ break;
+
+ case MONS_KOBOLD_DEMONOLOGIST:
+ case MONS_ORC_WIZARD:
+ case MONS_ORC_SORCERER:
+ item_race = MAKE_ITEM_ORCISH;
+ // deliberate fall-through, I guess {dlb}
+ case MONS_NECROMANCER:
+ case MONS_WIZARD:
+ case MONS_PSYCHE:
+ case MONS_DONALD:
+ case MONS_JOSEPHINE:
+ case MONS_AGNES:
+ mitm[bp].base_type = OBJ_WEAPONS;
+ mitm[bp].sub_type = WPN_DAGGER;
+ break;
+
+ case MONS_CEREBOV:
+ force_item = 1;
+ make_item_fixed_artefact( mitm[bp], false, SPWPN_SWORD_OF_CEREBOV );
+ break;
+
+ case MONS_DISPATER:
+ force_item = 1;
+ make_item_fixed_artefact( mitm[bp], false, SPWPN_STAFF_OF_DISPATER );
+ break;
+
+ case MONS_ASMODEUS:
+ force_item = 1;
+ make_item_fixed_artefact( mitm[bp], false, SPWPN_SCEPTRE_OF_ASMODEUS );
+ break;
+
+ case MONS_GERYON:
+ //mv: probably should be moved out of this switch,
+ //but it's not worth of it, unless we have more
+ //monsters with misc. items
+ mitm[bp].base_type = OBJ_MISCELLANY;
+ mitm[bp].sub_type = MISC_HORN_OF_GERYON;
+ break;
+
+ case MONS_SALAMANDER: //mv: new 8 Aug 2001
+ //Yes, they've got really nice items, but
+ //it's almost impossible to get them
+ force_item = 1;
+ item_race = MAKE_ITEM_NO_RACE;
+ mitm[bp].base_type = OBJ_WEAPONS;
+ temp_rand = random2(6);
+
+ mitm[bp].sub_type = ((temp_rand == 5) ? WPN_GREAT_SWORD :
+ (temp_rand == 4) ? WPN_TRIDENT :
+ (temp_rand == 3) ? WPN_SPEAR :
+ (temp_rand == 2) ? WPN_GLAIVE :
+ (temp_rand == 1) ? WPN_BOW
+ : WPN_HALBERD);
+
+ if (mitm[bp].sub_type == WPN_BOW)
+ set_item_ego_type( mitm[bp], OBJ_WEAPONS, SPWPN_FLAME );
+ else
+ set_item_ego_type( mitm[bp], OBJ_WEAPONS, SPWPN_FLAMING );
+
+ mitm[bp].plus = random2(5);
+ mitm[bp].plus2 = random2(5);
+ mitm[bp].colour = RED; // forced by force_item above {dlb}
+ break;
+ } // end "switch(menv[mid].type)"
+
+ // only happens if something in above switch doesn't set it {dlb}
+ if (mitm[bp].base_type == 101)
+ {
+ mitm[bp].base_type = OBJ_UNASSIGNED;
+ goto give_ammo;
+ }
+
+ mitm[bp].x = 0;
+ mitm[bp].y = 0;
+ mitm[bp].link = NON_ITEM;
+
+ if (force_item)
+ mitm[bp].quantity = iquan;
+ else if (mons_is_unique( menv[mid].type ))
+ {
+ if (random2(100) <= 9 + menv[mid].hit_dice)
+ give_level = MAKE_GOOD_ITEM;
+ else
+ give_level = level_number + 5;
+ }
+
+ xitc = mitm[bp].base_type;
+ xitt = mitm[bp].sub_type;
+
+ // Note this mess, all the work above doesn't mean much unless
+ // force_item is set... otherwise we're just going to take the
+ // base and subtypes and create a new item. -- bwr
+ thing_created = ((force_item) ? bp : items( 0, xitc, xitt, true,
+ give_level, item_race) );
+
+ if (thing_created == NON_ITEM)
+ return;
+
+ mitm[thing_created].x = 0;
+ mitm[thing_created].y = 0;
+ mitm[thing_created].link = NON_ITEM;
+ unset_ident_flags( mitm[thing_created], ISFLAG_IDENT_MASK );
+
+ //mv: now every item gets in appropriate slot
+ //no more miscellany in potion slot etc. (19 May 2001)
+ // hand_used = 0 unless Ettin's 2nd hand etc.
+ if ( mitm[thing_created].base_type == OBJ_WEAPONS )
+ menv[mid].inv[hand_used] = thing_created;
+ else if ( mitm[thing_created].base_type == OBJ_MISSILES )
+ menv[mid].inv[MSLOT_MISSILE] = thing_created;
+ else if ( mitm[thing_created].base_type == OBJ_SCROLLS )
+ menv[mid].inv[MSLOT_SCROLL] = thing_created;
+ else if ( mitm[thing_created].base_type == OBJ_GOLD )
+ menv[mid].inv[MSLOT_GOLD] = thing_created;
+ else if ( mitm[thing_created].base_type == OBJ_POTIONS )
+ menv[mid].inv[MSLOT_POTION] = thing_created;
+ else if ( mitm[thing_created].base_type == OBJ_MISCELLANY )
+ menv[mid].inv[MSLOT_MISCELLANY] = thing_created;
+
+
+ if (get_weapon_brand( mitm[thing_created] ) == SPWPN_PROTECTION )
+ menv[mid].armour_class += 5;
+
+ if (!force_item || mitm[thing_created].colour == BLACK)
+ item_colour( mitm[thing_created] );
+
+ give_ammo:
+ // mv: gives ammunition
+ // note that item_race is not reset for this section
+ if (menv[mid].inv[MSLOT_WEAPON] != NON_ITEM
+ && launches_things( mitm[menv[mid].inv[MSLOT_WEAPON]].sub_type ))
+ {
+ xitc = OBJ_MISSILES;
+ xitt = launched_by(mitm[menv[mid].inv[MSLOT_WEAPON]].sub_type);
+
+ thing_created = items( 0, xitc, xitt, true, give_level, item_race );
+ if (thing_created == NON_ITEM)
+ return;
+
+ // monsters will always have poisoned needles -- otherwise
+ // they are just going to behave badly --GDL
+ if (xitt == MI_NEEDLE)
+ set_item_ego_type(mitm[thing_created], OBJ_MISSILES, SPMSL_POISONED);
+
+ mitm[thing_created].x = 0;
+ mitm[thing_created].y = 0;
+ mitm[thing_created].flags = 0;
+ menv[mid].inv[MSLOT_MISSILE] = thing_created;
+
+ item_colour( mitm[thing_created] );
+ } // end if needs ammo
+
+ bp = get_item_slot();
+ if (bp == NON_ITEM)
+ return;
+
+ mitm[bp].x = 0;
+ mitm[bp].y = 0;
+ mitm[bp].link = NON_ITEM;
+
+ item_race = MAKE_ITEM_RANDOM_RACE;
+ give_level = 1 + (level_number / 2);
+
+ int force_colour = 0; //mv: important !!! Items with force_colour = 0
+ //are colored defaultly after following
+ //switch. Others will get force_colour.
+
+ switch (menv[mid].type)
+ {
+ case MONS_DEEP_ELF_ANNIHILATOR:
+ case MONS_DEEP_ELF_CONJURER:
+ case MONS_DEEP_ELF_DEATH_MAGE:
+ case MONS_DEEP_ELF_DEMONOLOGIST:
+ case MONS_DEEP_ELF_FIGHTER:
+ case MONS_DEEP_ELF_HIGH_PRIEST:
+ case MONS_DEEP_ELF_KNIGHT:
+ case MONS_DEEP_ELF_MAGE:
+ case MONS_DEEP_ELF_PRIEST:
+ case MONS_DEEP_ELF_SOLDIER:
+ case MONS_DEEP_ELF_SORCERER:
+ case MONS_DEEP_ELF_SUMMONER:
+ if (item_race == MAKE_ITEM_RANDOM_RACE)
+ item_race = MAKE_ITEM_ELVEN;
+ // deliberate fall through {dlb}
+ case MONS_IJYB:
+ case MONS_ORC:
+ case MONS_ORC_HIGH_PRIEST:
+ case MONS_ORC_PRIEST:
+ case MONS_ORC_SORCERER:
+ if (item_race == MAKE_ITEM_RANDOM_RACE)
+ item_race = MAKE_ITEM_ORCISH;
+ // deliberate fall through {dlb}
+ case MONS_ERICA:
+ case MONS_HAROLD:
+ case MONS_JOSEPH:
+ case MONS_JOSEPHINE:
+ case MONS_JOZEF:
+ case MONS_NORBERT:
+ case MONS_PSYCHE:
+ case MONS_TERENCE:
+ if (random2(5) < 2)
+ {
+ mitm[bp].base_type = OBJ_ARMOUR;
+
+ switch (random2(8))
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ mitm[bp].sub_type = ARM_LEATHER_ARMOUR;
+ break;
+ case 4:
+ case 5:
+ mitm[bp].sub_type = ARM_RING_MAIL;
+ break;
+ case 6:
+ mitm[bp].sub_type = ARM_SCALE_MAIL;
+ break;
+ case 7:
+ mitm[bp].sub_type = ARM_CHAIN_MAIL;
+ break;
+ }
+ }
+ else
+ return;
+ break;
+
+ case MONS_DUANE:
+ case MONS_EDMUND:
+ case MONS_RUPERT:
+ case MONS_URUG:
+ case MONS_WAYNE:
+ mitm[bp].base_type = OBJ_ARMOUR;
+ mitm[bp].sub_type = ARM_LEATHER_ARMOUR + random2(4);
+ break;
+
+ case MONS_ORC_WARLORD:
+ // being at the top has it's priviledges
+ if (one_chance_in(3))
+ give_level = MAKE_GOOD_ITEM;
+ // deliberate fall through
+ case MONS_ORC_KNIGHT:
+ case MONS_ORC_WARRIOR:
+ if (item_race == MAKE_ITEM_RANDOM_RACE)
+ item_race = MAKE_ITEM_ORCISH;
+ // deliberate fall through {dlb}
+ case MONS_ADOLF:
+ case MONS_HELL_KNIGHT:
+ case MONS_LOUISE:
+ case MONS_MARGERY:
+ case MONS_MAUD:
+ case MONS_VAMPIRE_KNIGHT:
+ case MONS_VAULT_GUARD:
+ mitm[bp].base_type = OBJ_ARMOUR;
+ mitm[bp].sub_type = ARM_CHAIN_MAIL + random2(4);
+ break;
+
+ case MONS_ANGEL:
+ case MONS_SIGMUND:
+ case MONS_WIGHT:
+ item_race = MAKE_ITEM_NO_RACE;
+ mitm[bp].base_type = OBJ_ARMOUR;
+ mitm[bp].sub_type = ARM_ROBE;
+ force_colour = WHITE; //mv: always white
+ break;
+
+ case MONS_NAGA:
+ case MONS_NAGA_MAGE:
+ case MONS_NAGA_WARRIOR:
+ if (!one_chance_in(3))
+ return;
+ // deliberate fall through {dlb}
+ case MONS_DONALD:
+ case MONS_GREATER_NAGA:
+ case MONS_JESSICA:
+ case MONS_KOBOLD_DEMONOLOGIST:
+ case MONS_OGRE_MAGE:
+ case MONS_ORC_WIZARD:
+ case MONS_WIZARD:
+ item_race = MAKE_ITEM_NO_RACE;
+ mitm[bp].base_type = OBJ_ARMOUR;
+ mitm[bp].sub_type = ARM_ROBE;
+ break;
+
+ case MONS_BORIS:
+ give_level = MAKE_GOOD_ITEM;
+ // fall-through
+ case MONS_AGNES:
+ case MONS_BLORK_THE_ORC:
+ case MONS_FRANCES:
+ case MONS_FRANCIS:
+ case MONS_NECROMANCER:
+ case MONS_VAMPIRE_MAGE:
+ mitm[bp].base_type = OBJ_ARMOUR;
+ mitm[bp].sub_type = ARM_ROBE;
+ force_colour = DARKGREY; //mv: always darkgrey
+ break;
+
+ default:
+ return;
+ } // end of switch(menv [mid].type)
+
+ iquan = 1; //because it may have been set earlier
+ //by giving ammo or weapons {dlb}
+
+ xitc = mitm[bp].base_type;
+ xitt = mitm[bp].sub_type;
+
+ if (mons_is_unique( menv[mid].type ) && give_level != MAKE_GOOD_ITEM)
+ {
+ if (random2(100) < 9 + menv[mid].hit_dice)
+ give_level = MAKE_GOOD_ITEM;
+ else
+ give_level = level_number + 5;
+ }
+
+ thing_created = items( 0, xitc, xitt, true, give_level, item_race );
+
+ if (thing_created == NON_ITEM)
+ return;
+
+ mitm[thing_created].x = 0;
+ mitm[thing_created].y = 0;
+ mitm[thing_created].link = NON_ITEM;
+ menv[mid].inv[MSLOT_ARMOUR] = thing_created;
+
+ //mv: all items with force_colour = 0 are colored via items().
+ if (force_colour)
+ mitm[thing_created].colour = force_colour;
+
+ menv[mid].armour_class += property( mitm[thing_created], PARM_AC );
+
+ const int armour_plus = mitm[thing_created].plus;
+
+ ASSERT(abs(armour_plus) < 20);
+
+ if (abs(armour_plus) < 20)
+ menv[mid].armour_class += armour_plus;
+
+ menv[mid].evasion += property( mitm[thing_created], PARM_EVASION ) / 2;
+
+ if (menv[mid].evasion < 1)
+ menv[mid].evasion = 1; // This *shouldn't* happen.
+} // end give_item()
+
+//---------------------------------------------------------------------------
+// PRIVATE HELPER FUNCTIONS
+//---------------------------------------------------------------------------
+
+static bool is_weapon_special(int the_weapon)
+{
+ return (mitm[the_weapon].special != SPWPN_NORMAL);
+} // end is_weapon_special()
+
+static void set_weapon_special(int the_weapon, int spwpn)
+{
+ set_item_ego_type( mitm[the_weapon], OBJ_WEAPONS, spwpn );
+} // end set_weapon_special()
+
+static void check_doors(void)
+{
+ unsigned char ig;
+ unsigned char solid_count = 0; // clarifies innermost loop {dlb}
+ int x,y;
+
+ for (x = 1; x < GXM-1; x++)
+ {
+ for (y = 1; y < GYM-1; y++)
+ {
+ ig = grd[x][y];
+
+ if (ig != DNGN_CLOSED_DOOR)
+ continue;
+
+ solid_count = 0;
+
+ // first half of each conditional represents bounds checking {dlb}:
+ if (grd[x - 1][y] < DNGN_LAST_SOLID_TILE)
+ solid_count++;
+
+ if (grd[x + 1][y] < DNGN_LAST_SOLID_TILE)
+ solid_count++;
+
+ if (grd[x][y - 1] < DNGN_LAST_SOLID_TILE)
+ solid_count++;
+
+ if (grd[x][y + 1] < DNGN_LAST_SOLID_TILE)
+ solid_count++;
+
+ grd[x][y] = ((solid_count < 2) ? DNGN_FLOOR : DNGN_CLOSED_DOOR);
+ }
+ }
+} // end check_doors()
+
+static void hide_doors(void)
+{
+ unsigned char dx = 0, dy = 0; // loop variables
+ unsigned char wall_count = 0; // clarifies inner loop {dlb}
+
+ for (dx = 1; dx < GXM-1; dx++)
+ {
+ for (dy = 1; dy < GYM-1; dy++)
+ {
+ // only one out of four doors are candidates for hiding {gdl}:
+ if (grd[dx][dy] == DNGN_CLOSED_DOOR && one_chance_in(4))
+ {
+ wall_count = 0;
+
+ if (grd[dx - 1][dy] == DNGN_ROCK_WALL)
+ wall_count++;
+
+ if (grd[dx + 1][dy] == DNGN_ROCK_WALL)
+ wall_count++;
+
+ if (grd[dx][dy - 1] == DNGN_ROCK_WALL)
+ wall_count++;
+
+ if (grd[dx][dy + 1] == DNGN_ROCK_WALL)
+ wall_count++;
+
+ // if door is attached to more than one wall, hide it {dlb}:
+ if (wall_count > 1)
+ grd[dx][dy] = DNGN_SECRET_DOOR;
+ }
+ }
+ }
+} // end hide_doors()
+
+static void prepare_swamp(void)
+{
+ int i, j; // loop variables
+ int temp_rand; // probability determination {dlb}
+
+ for (i = 10; i < (GXM - 10); i++)
+ {
+ for (j = 10; j < (GYM - 10); j++)
+ {
+ // doors -> floors {dlb}
+ if (grd[i][j] == DNGN_CLOSED_DOOR || grd[i][j] == DNGN_SECRET_DOOR)
+ grd[i][j] = DNGN_FLOOR;
+
+ // floors -> shallow water 1 in 3 times {dlb}
+ if (grd[i][j] == DNGN_FLOOR && one_chance_in(3))
+ grd[i][j] = DNGN_SHALLOW_WATER;
+
+ // walls -> deep/shallow water or remain unchanged {dlb}
+ if (grd[i][j] == DNGN_ROCK_WALL)
+ {
+ temp_rand = random2(6);
+
+ if (temp_rand > 0) // 17% chance unchanged {dlb}
+ {
+ grd[i][j] = ((temp_rand > 2) ? DNGN_SHALLOW_WATER // 50%
+ : DNGN_DEEP_WATER); // 33%
+ }
+ }
+ }
+ }
+} // end prepare_swamp()
+
+// Gives water which is next to ground/shallow water a chance of being
+// shallow. Checks each water space.
+static void prepare_water( int level_number )
+{
+ int i, j, k, l; // loop variables {dlb}
+ unsigned char which_grid; // code compaction {dlb}
+
+ for (i = 10; i < (GXM - 10); i++)
+ {
+ for (j = 10; j < (GYM - 10); j++)
+ {
+ if (grd[i][j] == DNGN_DEEP_WATER)
+ {
+ for (k = -1; k < 2; k++)
+ {
+ for (l = -1; l < 2; l++)
+ {
+ if (k != 0 || l != 0)
+ {
+ which_grid = grd[i + k][j + l];
+
+ // must come first {dlb}
+ if (which_grid == DNGN_SHALLOW_WATER
+ && one_chance_in( 8 + level_number ))
+ {
+ grd[i][j] = DNGN_SHALLOW_WATER;
+ }
+ else if (which_grid >= DNGN_FLOOR
+ && random2(100) < 80 - level_number * 4)
+ {
+ grd[i][j] = DNGN_SHALLOW_WATER;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+} // end prepare_water()
+
+static bool find_in_area(int sx, int sy, int ex, int ey, unsigned char feature)
+{
+ int x,y;
+
+ if (feature != 0)
+ {
+ for(x = sx; x <= ex; x++)
+ {
+ for(y = sy; y <= ey; y++)
+ {
+ if (grd[x][y] == feature)
+ return (true);
+ }
+ }
+ }
+
+ return (false);
+}
+
+// stamp a box. can avoid a possible type, and walls and floors can
+// be different (or not stamped at all)
+// Note that the box boundaries are INclusive.
+static bool make_box(int room_x1, int room_y1, int room_x2, int room_y2,
+ unsigned char floor, unsigned char wall, unsigned char avoid)
+{
+ int bx,by;
+
+ // check for avoidance
+ if (find_in_area(room_x1, room_y1, room_x2, room_y2, avoid))
+ return false;
+
+ // draw walls
+ if (wall != 0)
+ {
+ for(bx=room_x1; bx<=room_x2; bx++)
+ {
+ grd[bx][room_y1] = wall;
+ grd[bx][room_y2] = wall;
+ }
+ for(by=room_y1+1; by<room_y2; by++)
+ {
+ grd[room_x1][by] = wall;
+ grd[room_x2][by] = wall;
+ }
+ }
+
+ // draw floor
+ if (floor != 0)
+ {
+ for(bx=room_x1 + 1; bx < room_x2; bx++)
+ for(by=room_y1 + 1; by < room_y2; by++)
+ grd[bx][by] = floor;
+ }
+
+ return true;
+}
+
+// take care of labyrinth, abyss, pandemonium
+// returns 1 if we should skip further generation,
+// -1 if we should immediately quit, and 0 otherwise.
+static int builder_by_type(int level_number, char level_type)
+{
+ if (level_type == LEVEL_LABYRINTH)
+ {
+ labyrinth_level(level_number);
+ return -1;
+ }
+
+ if (level_type == LEVEL_ABYSS)
+ {
+ generate_abyss();
+ return 1;
+ }
+
+ if (level_type == LEVEL_PANDEMONIUM)
+ {
+ char which_demon = -1;
+ // Could do spotty_level, but that doesn't always put all paired
+ // stairs reachable from each other which isn't a problem in normal
+ // dungeon but could be in Pandemonium
+ if (one_chance_in(15))
+ {
+ do
+ {
+ which_demon = random2(4);
+
+ // makes these things less likely as you find more
+ if (one_chance_in(4))
+ {
+ which_demon = -1;
+ break;
+ }
+ }
+ while (you.unique_creatures[40 + which_demon] == 1);
+ }
+
+ if (which_demon >= 0)
+ {
+ you.unique_creatures[40 + which_demon] = 1;
+ build_vaults(level_number, which_demon + 60);
+ }
+ else
+ {
+ plan_main(level_number, 0);
+ build_minivaults(level_number, 300 + random2(9));
+ }
+
+ return 1;
+ }
+
+ // must be normal dungeon
+ return 0;
+}
+
+// returns 1 if we should skip further generation,
+// -1 if we should immediately quit, and 0 otherwise.
+static int builder_by_branch(int level_number)
+{
+ switch (you.where_are_you)
+ {
+ case BRANCH_HIVE:
+ if (level_number == you.branch_stairs[STAIRS_HIVE]
+ + branch_depth(STAIRS_HIVE))
+ build_vaults(level_number, 80);
+ else
+ spotty_level(false, 100 + random2(500), false);
+ return 1;
+
+ case BRANCH_SLIME_PITS:
+ if (level_number == you.branch_stairs[STAIRS_SLIME_PITS]
+ + branch_depth(STAIRS_SLIME_PITS))
+ {
+ build_vaults(level_number, 81);
+ }
+ else
+ spotty_level(false, 100 + random2(500), false);
+ return 1;
+
+ case BRANCH_VAULTS:
+ if (level_number == you.branch_stairs[STAIRS_VAULTS]
+ + branch_depth(STAIRS_VAULTS))
+ {
+ build_vaults(level_number, 82);
+ return 1;
+ }
+ break;
+
+ case BRANCH_HALL_OF_BLADES:
+ if (level_number == you.branch_stairs[STAIRS_HALL_OF_BLADES]
+ + branch_depth(STAIRS_HALL_OF_BLADES))
+ {
+ build_vaults(level_number, 83);
+ return 1;
+ }
+ break;
+
+ case BRANCH_HALL_OF_ZOT:
+ if (level_number == you.branch_stairs[STAIRS_HALL_OF_ZOT]
+ + branch_depth(STAIRS_HALL_OF_ZOT))
+ {
+ build_vaults(level_number, 84);
+ return 1;
+ }
+ break;
+
+ case BRANCH_ECUMENICAL_TEMPLE:
+ if (level_number == you.branch_stairs[STAIRS_ECUMENICAL_TEMPLE]
+ + branch_depth(STAIRS_ECUMENICAL_TEMPLE))
+ {
+ build_vaults(level_number, 85);
+ return 1;
+ }
+ break;
+
+ case BRANCH_SNAKE_PIT:
+ if (level_number == you.branch_stairs[STAIRS_SNAKE_PIT]
+ + branch_depth(STAIRS_SNAKE_PIT))
+ {
+ build_vaults(level_number, 86);
+ return 1;
+ }
+ break;
+
+ case BRANCH_ELVEN_HALLS:
+ if (level_number == you.branch_stairs[STAIRS_ELVEN_HALLS]
+ + branch_depth(STAIRS_ELVEN_HALLS))
+ {
+ build_vaults(level_number, 87);
+ return 1;
+ }
+ break;
+
+ case BRANCH_TOMB:
+ if (level_number == you.branch_stairs[STAIRS_TOMB] + 1)
+ {
+ build_vaults(level_number, 88);
+ return 1;
+ }
+ else if (level_number == you.branch_stairs[STAIRS_TOMB] + 2)
+ {
+ build_vaults(level_number, 89);
+ return 1;
+ }
+ else if (level_number == you.branch_stairs[STAIRS_TOMB] + 3)
+ {
+ build_vaults(level_number, 90);
+ return 1;
+ }
+ break;
+
+ case BRANCH_SWAMP:
+ if (level_number == you.branch_stairs[STAIRS_SWAMP]
+ + branch_depth(STAIRS_SWAMP))
+ {
+ build_vaults(level_number, 91);
+ return 1;
+ }
+ break;
+
+ case BRANCH_ORCISH_MINES:
+ spotty_level(false, 100 + random2(500), false);
+ return 1;
+
+ case BRANCH_LAIR:
+ if (!one_chance_in(3))
+ {
+ spotty_level(false, 100 + random2(500), false);
+ return 1;
+ }
+ break;
+
+ case BRANCH_VESTIBULE_OF_HELL:
+ build_vaults( level_number, 50 );
+ link_items();
+ return -1;
+
+ case BRANCH_DIS:
+ if (level_number == 33)
+ {
+ build_vaults(level_number, 51);
+ return 1;
+ }
+ break;
+
+ case BRANCH_GEHENNA:
+ if (level_number == 33)
+ {
+ build_vaults(level_number, 52);
+ return 1;
+ }
+ break;
+
+ case BRANCH_COCYTUS:
+ if (level_number == 33)
+ {
+ build_vaults(level_number, 53);
+ return 1;
+ }
+ break;
+
+ case BRANCH_TARTARUS:
+ if (level_number == 33)
+ {
+ build_vaults(level_number, 54);
+ return 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+// returns 1 if we should dispense with city building,
+// 0 otherwise. Also sets special_room if one is generated
+// so that we can link it up later.
+
+static int builder_normal(int level_number, char level_type, spec_room &sr)
+{
+ UNUSED( level_type );
+
+ bool skipped = false;
+ bool done_city = false;
+
+ if (player_in_branch( BRANCH_DIS ))
+ {
+ city_level(level_number);
+ return 1;
+ }
+
+ if (player_in_branch( BRANCH_MAIN_DUNGEON )
+ && level_number > 10 && level_number < 23 && one_chance_in(9))
+ {
+ // Can't have vaults on you.where_are_you != BRANCH_MAIN_DUNGEON levels
+ build_vaults(level_number, 100);
+ return 1;
+ }
+
+ if (player_in_branch( BRANCH_VAULTS ))
+ {
+ if (one_chance_in(3))
+ city_level(level_number);
+ else
+ plan_main(level_number, 4);
+ return 1;
+ }
+
+ if (level_number > 7 && level_number < 23)
+ {
+ if (one_chance_in(16))
+ {
+ spotty_level(false, 0, coinflip());
+ return 1;
+ }
+
+ if (one_chance_in(16))
+ {
+ bigger_room();
+ return 1;
+ }
+ }
+
+ if (level_number > 2 && level_number < 23 && one_chance_in(3))
+ {
+ plan_main(level_number, 0);
+
+ if (one_chance_in(3) && level_number > 6)
+ build_minivaults(level_number, 200);
+
+ return 1;
+ }
+
+ if (one_chance_in(3))
+ skipped = true;
+
+ //V was 3
+ if (!skipped && one_chance_in(7))
+ {
+ // sometimes roguey_levels generate a special room
+ roguey_level(level_number, sr);
+
+ if (level_number > 6
+ && player_in_branch( BRANCH_MAIN_DUNGEON )
+ && one_chance_in(4))
+ {
+ build_minivaults(level_number, 200);
+ return 1;
+ }
+ }
+ else
+ {
+ if (!skipped && level_number > 13 && one_chance_in(8))
+ {
+ if (one_chance_in(3))
+ city_level(level_number);
+ else
+ plan_main(level_number, 4);
+ done_city = true;
+ }
+ }
+
+ // maybe create a special room, if roguey_level hasn't done it
+ // already.
+ if (!sr.created && level_number > 5 && !done_city && one_chance_in(5))
+ special_room(level_number, sr);
+
+ return 0;
+}
+
+// returns 1 if we should skip extras(), otherwise 0
+static int builder_basic(int level_number)
+{
+ int temp_rand;
+ int doorlevel = random2(11);
+ int corrlength = 2 + random2(14);
+ int roomsize = 4 + random2(5) + random2(6);
+ int no_corr = (one_chance_in(100) ? 500 + random2(500) : 30 + random2(200));
+ int intersect_chance = (one_chance_in(20) ? 400 : random2(20));
+
+ make_trail( 35, 30, 35, 20, corrlength, intersect_chance, no_corr,
+ DNGN_STONE_STAIRS_DOWN_I, DNGN_STONE_STAIRS_UP_I );
+
+ make_trail( 10, 15, 10, 15, corrlength, intersect_chance, no_corr,
+ DNGN_STONE_STAIRS_DOWN_II, DNGN_STONE_STAIRS_UP_II );
+
+ make_trail(50,20,10,15,corrlength,intersect_chance,no_corr,
+ DNGN_STONE_STAIRS_DOWN_III, DNGN_STONE_STAIRS_UP_III);
+
+ if (one_chance_in(4))
+ {
+ make_trail( 10, 20, 40, 20, corrlength, intersect_chance, no_corr,
+ DNGN_ROCK_STAIRS_DOWN );
+ }
+
+ if (one_chance_in(4))
+ {
+ make_trail( 50, 20, 40, 20, corrlength, intersect_chance, no_corr,
+ DNGN_ROCK_STAIRS_UP );
+ }
+
+
+ if (level_number > 1 && one_chance_in(16))
+ big_room(level_number);
+
+ if (random2(level_number) > 6 && one_chance_in(3))
+ diamond_rooms(level_number);
+
+ // make some rooms:
+ int i, no_rooms, max_doors;
+ int sx,sy,ex,ey, time_run;
+
+ temp_rand = random2(750);
+ time_run = 0;
+
+ no_rooms = ((temp_rand > 63) ? (5 + random2avg(29, 2)) : // 91.47% {dlb}
+ (temp_rand > 14) ? 100 // 6.53% {dlb}
+ : 1); // 2.00% {dlb}
+
+ max_doors = 2 + random2(8);
+
+ for (i = 0; i < no_rooms; i++)
+ {
+ sx = 8 + random2(50);
+ sy = 8 + random2(40);
+ ex = sx + 2 + random2(roomsize);
+ ey = sy + 2 + random2(roomsize);
+
+ if (!make_room(sx,sy,ex,ey,max_doors, doorlevel))
+ {
+ time_run++;
+ i--;
+ }
+
+ if (time_run > 30)
+ {
+ time_run = 0;
+ i++;
+ }
+ }
+
+ // make some more rooms:
+ no_rooms = 1 + random2(3);
+ max_doors = 1;
+
+ for (i = 0; i < no_rooms; i++)
+ {
+ sx = 8 + random2(55);
+ sy = 8 + random2(45);
+ ex = sx + 5 + random2(6);
+ ey = sy + 5 + random2(6);
+
+ if (!make_room(sx,sy,ex,ey,max_doors, doorlevel))
+ {
+ time_run++;
+ i--;
+ }
+
+ if (time_run > 30)
+ {
+ time_run = 0;
+ i++;
+ }
+ }
+
+ return 0;
+}
+
+static void builder_extras( int level_number, int level_type )
+{
+ UNUSED( level_type );
+
+ if (level_number >= 11 && level_number <= 23 && one_chance_in(15))
+ place_specific_stair(DNGN_ENTER_LABYRINTH);
+
+ if (level_number > 6
+ && player_in_branch( BRANCH_MAIN_DUNGEON )
+ && one_chance_in(3))
+ {
+ build_minivaults(level_number, 200);
+ return;
+ }
+
+ if (level_number > 5 && one_chance_in(10))
+ {
+ many_pools( (coinflip() ? DNGN_DEEP_WATER : DNGN_LAVA) );
+ return;
+ }
+
+#ifdef USE_RIVERS
+ //mv: it's better to be here so other dungeon features
+ // are not overriden by water
+ int river_type = one_chance_in( 5 + level_number ) ? DNGN_SHALLOW_WATER
+ : DNGN_DEEP_WATER;
+
+ if (level_number > 11
+ && (one_chance_in(5) || (level_number > 15 && !one_chance_in(5))))
+ {
+ river_type = DNGN_LAVA;
+ }
+
+ if (player_in_branch( BRANCH_GEHENNA ))
+ {
+ river_type = DNGN_LAVA;
+
+ if (coinflip())
+ build_river( river_type );
+ else
+ build_lake( river_type );
+ }
+ else if (player_in_branch( BRANCH_COCYTUS ))
+ {
+ river_type = DNGN_DEEP_WATER;
+
+ if (coinflip())
+ build_river( river_type );
+ else
+ build_lake( river_type );
+ }
+
+
+ if (level_number > 8 && one_chance_in(16))
+ build_river( river_type );
+ else if (level_number > 8 && one_chance_in(12))
+ {
+ build_lake( (river_type != DNGN_SHALLOW_WATER) ? river_type
+ : DNGN_DEEP_WATER );
+ }
+#endif // USE_RIVERS
+}
+
+static void place_traps(int level_number)
+{
+ int i;
+ int num_traps = random2avg(9, 2);
+
+ for (i = 0; i < num_traps; i++)
+ {
+ // traps can be placed in vaults
+ if (env.trap[i].type != TRAP_UNASSIGNED)
+ continue;
+
+ do
+ {
+ env.trap[i].x = 10 + random2(GXM - 20);
+ env.trap[i].y = 10 + random2(GYM - 20);
+ }
+ while (grd[env.trap[i].x][env.trap[i].y] != DNGN_FLOOR);
+
+ env.trap[i].type = TRAP_DART;
+
+ if ((random2(1 + level_number) > 1) && one_chance_in(4))
+ env.trap[i].type = TRAP_NEEDLE;
+ if (random2(1 + level_number) > 2)
+ env.trap[i].type = TRAP_ARROW;
+ if (random2(1 + level_number) > 3)
+ env.trap[i].type = TRAP_SPEAR;
+ if (random2(1 + level_number) > 5)
+ env.trap[i].type = TRAP_AXE;
+ if (random2(1 + level_number) > 7)
+ env.trap[i].type = TRAP_BOLT;
+ if (random2(1 + level_number) > 11)
+ env.trap[i].type = TRAP_BLADE;
+
+ if ((random2(1 + level_number) > 14 && one_chance_in(3))
+ || (player_in_branch( BRANCH_HALL_OF_ZOT ) && coinflip()))
+ {
+ env.trap[i].type = TRAP_ZOT;
+ }
+
+ if (one_chance_in(20))
+ env.trap[i].type = TRAP_TELEPORT;
+ if (one_chance_in(40))
+ env.trap[i].type = TRAP_AMNESIA;
+
+ grd[env.trap[i].x][env.trap[i].y] = DNGN_UNDISCOVERED_TRAP;
+ } // end "for i"
+} // end place_traps()
+
+static void place_specific_stair(unsigned char stair)
+{
+ int sx, sy;
+
+ do
+ {
+ sx = random2(GXM-10);
+ sy = random2(GYM-10);
+ }
+ while(grd[sx][sy] != DNGN_FLOOR || mgrd[sx][sy] != NON_MONSTER);
+
+ grd[sx][sy] = stair;
+}
+
+
+static void place_branch_entrances(int dlevel, char level_type)
+{
+ unsigned char stair;
+ unsigned char entrance;
+ int sx, sy;
+
+ if (!level_type == LEVEL_DUNGEON)
+ return;
+
+ if (player_in_branch( BRANCH_MAIN_DUNGEON ))
+ {
+ // stair to HELL
+ if (dlevel >= 20 && dlevel <= 27)
+ place_specific_stair(DNGN_ENTER_HELL);
+
+ // stair to PANDEMONIUM
+ if (dlevel >= 20 && dlevel <= 50 && (dlevel == 23 || one_chance_in(4)))
+ place_specific_stair(DNGN_ENTER_PANDEMONIUM);
+
+ // stairs to ABYSS
+ if (dlevel >= 20 && dlevel <= 30 && (dlevel == 24 || one_chance_in(3)))
+ place_specific_stair(DNGN_ENTER_ABYSS);
+
+ // level 26: replaces all down stairs with staircases to Zot:
+ if (dlevel == 26)
+ {
+ for (sx = 1; sx < GXM; sx++)
+ {
+ for (sy = 1; sy < GYM; sy++)
+ {
+ if (grd[sx][sy] >= DNGN_STONE_STAIRS_DOWN_I
+ && grd[sx][sy] <= DNGN_ROCK_STAIRS_DOWN)
+ {
+ grd[sx][sy] = DNGN_ENTER_ZOT;
+ }
+ }
+ }
+ }
+ }
+
+ // place actual branch entrances
+ for (int branch = 0; branch < 30; branch++)
+ {
+ stair = 0;
+ entrance = 100;
+
+ if (you.branch_stairs[branch] == 100) // set in newgame
+ break;
+
+ if (you.branch_stairs[branch] != dlevel)
+ continue;
+
+ // decide if this branch leaves from this level
+ switch(branch)
+ {
+ case STAIRS_ORCISH_MINES:
+ case STAIRS_HIVE:
+ case STAIRS_LAIR:
+ case STAIRS_VAULTS:
+ case STAIRS_ECUMENICAL_TEMPLE:
+ entrance = BRANCH_MAIN_DUNGEON;
+ break;
+
+ case STAIRS_SLIME_PITS:
+ case STAIRS_SWAMP:
+ case STAIRS_SNAKE_PIT:
+ entrance = BRANCH_LAIR;
+ break;
+
+ case STAIRS_ELVEN_HALLS:
+ entrance = BRANCH_ORCISH_MINES;
+ break;
+
+ case STAIRS_CRYPT:
+ case STAIRS_HALL_OF_BLADES:
+ entrance = BRANCH_VAULTS;
+ break;
+
+ case STAIRS_TOMB:
+ entrance = BRANCH_CRYPT;
+ break;
+
+ default:
+ entrance = 100;
+ break;
+ }
+
+ if (you.where_are_you != entrance)
+ continue;
+
+ stair = branch + DNGN_ENTER_ORCISH_MINES;
+ place_specific_stair(stair);
+ } // end loop - possible branch entrances
+}
+
+static void make_trail(int xs, int xr, int ys, int yr, int corrlength,
+ int intersect_chance, int no_corr, unsigned char begin,
+ unsigned char end)
+{
+ int x_start, y_start; // begin point
+ int x_ps, y_ps; // end point
+ int finish = 0;
+ int length = 0;
+ int temp_rand;
+
+ // temp positions
+ int dir_x = 0;
+ int dir_y = 0;
+ int dir_x2, dir_y2;
+
+ do
+ {
+ x_start = xs + random2(xr);
+ y_start = ys + random2(yr);
+ }
+ while (grd[x_start][y_start] != DNGN_ROCK_WALL
+ && grd[x_start][y_start] != DNGN_FLOOR);
+
+ // assign begin feature
+ if (begin != 0)
+ grd[x_start][y_start] = begin;
+ x_ps = x_start;
+ y_ps = y_start;
+
+ // wander
+ do // (while finish < no_corr)
+ {
+ dir_x2 = ((x_ps < 15) ? 1 : 0);
+
+ if (x_ps > 65)
+ dir_x2 = -1;
+
+ dir_y2 = ((y_ps < 15) ? 1 : 0);
+
+ if (y_ps > 55)
+ dir_y2 = -1;
+
+ temp_rand = random2(10);
+
+ // Put something in to make it go to parts of map it isn't in now
+ if (coinflip())
+ {
+ if (dir_x2 != 0 && temp_rand < 6)
+ dir_x = dir_x2;
+
+ if (dir_x2 == 0 || temp_rand >= 6)
+ dir_x = (coinflip()? -1 : 1);
+
+ dir_y = 0;
+ }
+ else
+ {
+ if (dir_y2 != 0 && temp_rand < 6)
+ dir_y = dir_y2;
+
+ if (dir_y2 == 0 || temp_rand >= 6)
+ dir_y = (coinflip()? -1 : 1);
+
+ dir_x = 0;
+ }
+
+ if (dir_x == 0 && dir_y == 0)
+ continue;
+
+ if (x_ps < 8)
+ {
+ dir_x = 1;
+ dir_y = 0;
+ }
+
+ if (y_ps < 8)
+ {
+ dir_y = 1;
+ dir_x = 0;
+ }
+
+ if (x_ps > (GXM - 8))
+ {
+ dir_x = -1;
+ dir_y = 0;
+ }
+
+ if (y_ps > (GYM - 8))
+ {
+ dir_y = -1;
+ dir_x = 0;
+ }
+
+ // corridor length.. change only when going vertical?
+ if (dir_x == 0 || length == 0)
+ length = random2(corrlength) + 2;
+
+ int bi = 0;
+
+ for (bi = 0; bi < length; bi++)
+ {
+ // Below, I've changed the values of the unimportant variable from
+ // 0 to random2(3) - 1 to avoid getting stuck on the "stuck!" bit
+ if (x_ps < 9)
+ {
+ dir_y = 0; //random2(3) - 1;
+ dir_x = 1;
+ }
+
+ if (x_ps > (GXM - 9))
+ {
+ dir_y = 0; //random2(3) - 1;
+ dir_x = -1;
+ }
+
+ if (y_ps < 9)
+ {
+ dir_y = 1;
+ dir_x = 0; //random2(3) - 1;
+ }
+
+ if (y_ps > (GYM - 9))
+ {
+ dir_y = -1;
+ dir_x = 0; //random2(3) - 1;
+ }
+
+ // don't interfere with special rooms
+ if (grd[x_ps + dir_x][y_ps + dir_y] == DNGN_BUILDER_SPECIAL_WALL)
+ break;
+
+ // see if we stop due to intersection with another corridor/room
+ if (grd[x_ps + 2 * dir_x][y_ps + 2 * dir_y] == DNGN_FLOOR
+ && !one_chance_in(intersect_chance))
+ break;
+
+ x_ps += dir_x;
+ y_ps += dir_y;
+
+ if (grd[x_ps][y_ps] == DNGN_ROCK_WALL)
+ grd[x_ps][y_ps] = DNGN_FLOOR;
+ }
+
+ if (finish == no_corr - 1 && grd[x_ps][y_ps] != DNGN_FLOOR)
+ finish -= 2;
+
+ finish++;
+ }
+ while (finish < no_corr);
+
+ // assign end feature
+ if (end != 0)
+ grd[x_ps][y_ps] = end;
+}
+
+static int good_door_spot(int x, int y)
+{
+ if ((grd[x][y] > DNGN_WATER_X && grd[x][y] < DNGN_ENTER_PANDEMONIUM)
+ || grd[x][y] == DNGN_CLOSED_DOOR)
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+// return TRUE if a room was made successfully
+static bool make_room(int sx,int sy,int ex,int ey,int max_doors, int doorlevel)
+{
+ int find_door = 0;
+ int diag_door = 0;
+ int rx,ry;
+
+ // check top & bottom for possible doors
+ for (rx = sx; rx <= ex; rx++)
+ {
+ find_door += good_door_spot(rx,sy);
+ find_door += good_door_spot(rx,ey);
+ }
+
+ // check left and right for possible doors
+ for (ry = sy+1; ry < ey; ry++)
+ {
+ find_door += good_door_spot(sx,ry);
+ find_door += good_door_spot(ex,ry);
+ }
+
+ diag_door += good_door_spot(sx,sy);
+ diag_door += good_door_spot(ex,sy);
+ diag_door += good_door_spot(sx,ey);
+ diag_door += good_door_spot(ex,ey);
+
+ if ((diag_door + find_door) > 1 && max_doors == 1)
+ return false;
+
+ if (find_door == 0 || find_door > max_doors)
+ return false;
+
+ // look for 'special' rock walls - don't interrupt them
+ if (find_in_area(sx,sy,ex,ey,DNGN_BUILDER_SPECIAL_WALL))
+ return false;
+
+ // convert the area to floor
+ for (rx=sx; rx<=ex; rx++)
+ {
+ for(ry=sy; ry<=ey; ry++)
+ {
+ if (grd[rx][ry] <= DNGN_FLOOR)
+ grd[rx][ry] = DNGN_FLOOR;
+ }
+ }
+
+ // put some doors on the sides (but not in corners),
+ // where it makes sense to do so.
+ for(ry=sy+1; ry<ey; ry++)
+ {
+ // left side
+ if (grd[sx-1][ry] == DNGN_FLOOR
+ && grd[sx-1][ry-1] < DNGN_LAST_SOLID_TILE
+ && grd[sx-1][ry+1] < DNGN_LAST_SOLID_TILE)
+ {
+ if (random2(10) < doorlevel)
+ grd[sx-1][ry] = DNGN_CLOSED_DOOR;
+ }
+
+ // right side
+ if (grd[ex+1][ry] == DNGN_FLOOR
+ && grd[ex+1][ry-1] < DNGN_LAST_SOLID_TILE
+ && grd[ex+1][ry+1] < DNGN_LAST_SOLID_TILE)
+ {
+ if (random2(10) < doorlevel)
+ grd[ex+1][ry] = DNGN_CLOSED_DOOR;
+ }
+ }
+
+ // put some doors on the top & bottom
+ for(rx=sx+1; rx<ex; rx++)
+ {
+ // top
+ if (grd[rx][sy-1] == DNGN_FLOOR
+ && grd[rx-1][sy-1] < DNGN_LAST_SOLID_TILE
+ && grd[rx+1][sy-1] < DNGN_LAST_SOLID_TILE)
+ {
+ if (random2(10) < doorlevel)
+ grd[rx][sy-1] = DNGN_CLOSED_DOOR;
+ }
+
+ // bottom
+ if (grd[rx][ey+1] == DNGN_FLOOR
+ && grd[rx-1][ey+1] < DNGN_LAST_SOLID_TILE
+ && grd[rx+1][ey+1] < DNGN_LAST_SOLID_TILE)
+ {
+ if (random2(10) < doorlevel)
+ grd[rx][ey+1] = DNGN_CLOSED_DOOR;
+ }
+ }
+
+ return true;
+} //end make_room()
+
+static void builder_monsters(int level_number, char level_type, int mon_wanted)
+{
+ int i = 0;
+ int totalplaced = 0;
+ int not_used=0;
+ int x,y;
+ int lava_spaces, water_spaces;
+ int aq_creatures;
+ int swimming_things[4];
+
+ if (level_type == LEVEL_PANDEMONIUM)
+ return;
+
+ for (i = 0; i < mon_wanted; i++)
+ {
+ if (place_monster( not_used, RANDOM_MONSTER, level_number, BEH_SLEEP,
+ MHITNOT, false, 1, 1, true ))
+ {
+ totalplaced++;
+ }
+ }
+
+ // Unique beasties:
+ int which_unique;
+
+ if (level_number > 0
+ && you.level_type == LEVEL_DUNGEON // avoid generating on temp levels
+ && !player_in_hell()
+ && !player_in_branch( BRANCH_ORCISH_MINES )
+ && !player_in_branch( BRANCH_HIVE )
+ && !player_in_branch( BRANCH_LAIR )
+ && !player_in_branch( BRANCH_SLIME_PITS )
+ && !player_in_branch( BRANCH_ECUMENICAL_TEMPLE ))
+ {
+ while(one_chance_in(3))
+ {
+ which_unique = -1; // 30 in total
+
+ while(which_unique < 0 || you.unique_creatures[which_unique])
+ {
+ // sometimes, we just quit if a unique is already placed.
+ if (which_unique >= 0 && !one_chance_in(3))
+ {
+ which_unique = -1;
+ break;
+ }
+
+ which_unique = ((level_number > 19) ? 20 + random2(11) :
+ (level_number > 16) ? 13 + random2(10) :
+ (level_number > 13) ? 9 + random2( 9) :
+ (level_number > 9) ? 6 + random2( 5) :
+ (level_number > 7) ? 4 + random2( 4) :
+ (level_number > 3) ? 2 + random2( 4)
+ : random2(4));
+ }
+
+ // usually, we'll have quit after a few tries. Make sure we don't
+ // create unique[-1] by accident.
+ if (which_unique < 0)
+ break;
+
+ // note: unique_creatures 40 + used by unique demons
+ if (place_monster( not_used, 280 + which_unique, level_number,
+ BEH_SLEEP, MHITNOT, false, 1, 1, true ))
+ {
+ totalplaced++;
+ }
+ }
+ }
+
+ // do aquatic and lava monsters:
+
+ // count the number of lava and water tiles {dlb}:
+ lava_spaces = 0;
+ water_spaces = 0;
+
+ for (x = 0; x < GXM; x++)
+ {
+ for (y = 0; y < GYM; y++)
+ {
+ if (grd[x][y] == DNGN_LAVA)
+ {
+ lava_spaces++;
+ }
+ else if (grd[x][y] == DNGN_DEEP_WATER
+ || grd[x][y] == DNGN_SHALLOW_WATER)
+ {
+ water_spaces++;
+ }
+ }
+ }
+
+ if (lava_spaces > 49)
+ {
+ for (i = 0; i < 4; i++)
+ {
+ swimming_things[i] = MONS_LAVA_WORM + random2(3);
+
+ //mv: this is really ugly, but easiest
+ //IMO generation of water/lava beasts should be changed,
+ //because we want data driven code and not things like it
+ if (one_chance_in(30))
+ swimming_things[i] = MONS_SALAMANDER;
+ }
+
+ aq_creatures = random2avg(9, 2) + (random2(lava_spaces) / 10);
+
+ if (aq_creatures > 15)
+ aq_creatures = 15;
+
+ for (i = 0; i < aq_creatures; i++)
+ {
+ if (place_monster( not_used, swimming_things[ random2(4) ],
+ level_number, BEH_SLEEP, MHITNOT,
+ false, 1, 1, true ))
+ {
+ totalplaced++;
+ }
+
+ if (totalplaced > 99)
+ break;
+ }
+ }
+
+ if (water_spaces > 49)
+ {
+ for (i = 0; i < 4; i++)
+ {
+ // mixing enums and math ticks me off !!! 15jan2000 {dlb}
+ swimming_things[i] = MONS_BIG_FISH + random2(4);
+
+ // swamp worms and h2o elementals generated below: {dlb}
+ if (player_in_branch( BRANCH_SWAMP ) && !one_chance_in(3))
+ swimming_things[i] = MONS_SWAMP_WORM;
+ }
+
+ if (level_number >= 25 && one_chance_in(5))
+ swimming_things[0] = MONS_WATER_ELEMENTAL;
+
+ if (player_in_branch( BRANCH_COCYTUS ))
+ swimming_things[3] = MONS_WATER_ELEMENTAL;
+
+ aq_creatures = random2avg(9, 2) + (random2(water_spaces) / 10);
+
+ if (aq_creatures > 15)
+ aq_creatures = 15;
+
+ for (i = 0; i < aq_creatures; i++)
+ {
+ if (place_monster( not_used, swimming_things[ random2(4) ],
+ level_number, BEH_SLEEP, MHITNOT,
+ false, 1, 1, true ))
+ {
+ totalplaced++;
+ }
+
+ if (totalplaced > 99)
+ break;
+ }
+ }
+}
+
+static void builder_items(int level_number, char level_type, int items_wanted)
+{
+ UNUSED( level_type );
+
+ int i = 0;
+ unsigned char specif_type = OBJ_RANDOM;
+ int items_levels = level_number;
+ int item_no;
+
+ if (player_in_branch( BRANCH_VAULTS ))
+ {
+ items_levels *= 15;
+ items_levels /= 10;
+ }
+ else if (player_in_branch( BRANCH_ORCISH_MINES ))
+ {
+ specif_type = OBJ_GOLD; /* lots of gold in the orcish mines */
+ }
+
+ if (player_in_branch( BRANCH_VESTIBULE_OF_HELL )
+ || player_in_hell()
+ || player_in_branch( BRANCH_SLIME_PITS )
+ || player_in_branch( BRANCH_HALL_OF_BLADES )
+ || player_in_branch( BRANCH_ECUMENICAL_TEMPLE ))
+ {
+ /* No items in hell, the slime pits, the Hall */
+ return;
+ }
+ else
+ {
+ for (i = 0; i < items_wanted; i++)
+ items( 1, specif_type, OBJ_RANDOM, false, items_levels, 250 );
+
+ // Make sure there's a very good chance of a knife being placed
+ // in the first five levels, but not a guarantee of one. The
+ // intent of this is to reduce the advantage that "cutting"
+ // starting weapons have. -- bwr
+ if (player_in_branch( BRANCH_MAIN_DUNGEON )
+ && level_number < 5 && coinflip())
+ {
+ item_no = items( 0, OBJ_WEAPONS, WPN_KNIFE, false, 0, 250 );
+
+ // Guarantee that the knife is uncursed and non-special
+ if (item_no != NON_ITEM)
+ {
+ mitm[item_no].plus = 0;
+ mitm[item_no].plus2 = 0;
+ mitm[item_no].flags = 0; // no id, no race/desc, no curse
+ mitm[item_no].special = 0; // no ego type
+ }
+ }
+ }
+}
+
+// the entire intent of this function is to find a
+// hallway from a special room to a floor space somewhere,
+// changing the special room wall (DNGN_BUILDER_SPECIAL_WALL)
+// to a closed door, and normal rock wall to pre-floor.
+// Anything that might otherwise block the hallway is changed
+// to pre-floor.
+static void specr_2(spec_room &sr)
+{
+ int bkout = 0;
+ int cx = 0, cy = 0;
+ int sx = 0, sy = 0;
+ int dx = 0, dy = 0;
+ int i,j;
+
+ // paranoia -- how did we get here if there's no actual special room??
+ if (!sr.created)
+ return;
+
+ grolko:
+
+ if (bkout > 100)
+ return;
+
+ switch (random2(4))
+ {
+ case 0:
+ // go up from north edge
+ cx = sr.x1 + (random2(sr.x2 - sr.x1));
+ cy = sr.y1;
+ dx = 0;
+ dy = -1;
+ break;
+ case 1:
+ // go down from south edge
+ cx = sr.x1 + (random2(sr.x2 - sr.x1));
+ cy = sr.y2;
+ dx = 0;
+ dy = 1;
+ break;
+ case 2:
+ // go left from west edge
+ cy = sr.y1 + (random2(sr.y2 - sr.y1));
+ cx = sr.x1;
+ dx = -1;
+ dy = 0;
+ break;
+ case 3:
+ // go right from east edge
+ cy = sr.y1 + (random2(sr.y2 - sr.y1));
+ cx = sr.x2;
+ dx = 1;
+ dy = 0;
+ break;
+ }
+
+ sx = cx;
+ sy = cy;
+
+ for (i = 0; i < 100; i++)
+ {
+ sx += dx;
+ sy += dy;
+
+ // quit if we run off the map before finding floor
+ if (sx < 6 || sx > (GXM - 7) || sy < 6 || sy > (GYM - 7))
+ {
+ bkout++;
+ goto grolko;
+ }
+
+ // look around for floor
+ if (i > 0)
+ {
+ if (grd[sx + 1][sy] == DNGN_FLOOR)
+ break;
+ if (grd[sx][sy + 1] == DNGN_FLOOR)
+ break;
+ if (grd[sx - 1][sy] == DNGN_FLOOR)
+ break;
+ if (grd[sx][sy - 1] == DNGN_FLOOR)
+ break;
+ }
+ }
+
+ sx = cx;
+ sy = cy;
+
+ for (j = 0; j < i + 2; j++)
+ {
+ if (grd[sx][sy] == DNGN_BUILDER_SPECIAL_WALL)
+ grd[sx][sy] = DNGN_CLOSED_DOOR;
+
+ if (j > 0 && grd[sx + dx][sy + dy] > DNGN_ROCK_WALL
+ && grd[sx + dx][sy + dy] < DNGN_FLOOR)
+ grd[sx][sy] = DNGN_BUILDER_SPECIAL_FLOOR;
+
+ if (grd[sx][sy] == DNGN_ROCK_WALL)
+ grd[sx][sy] = DNGN_BUILDER_SPECIAL_FLOOR;
+
+ sx += dx;
+ sy += dy;
+ }
+
+ sr.hooked_up = true;
+} // end specr_2()
+
+static void special_room(int level_number, spec_room &sr)
+{
+ char spec_room_type = SROOM_LAIR_KOBOLD;
+ int lev_mons;
+ int thing_created = 0;
+ int x, y;
+
+ unsigned char obj_type = OBJ_RANDOM; // used in calling items() {dlb}
+ unsigned char i; // general purpose loop variable {dlb}
+ int temp_rand = 0; // probability determination {dlb}
+
+ FixedVector < int, 10 > mons_alloc; // was [20] {dlb}
+
+ char lordx = 0, lordy = 0;
+
+ // overwrites anything; this function better be called early on during
+ // creation..
+ int room_x1 = 8 + random2(55);
+ int room_y1 = 8 + random2(45);
+ int room_x2 = room_x1 + 4 + random2avg(6,2);
+ int room_y2 = room_y1 + 4 + random2avg(6,2);
+
+ // do special walls & floor
+ make_box( room_x1, room_y1, room_x2, room_y2,
+ DNGN_BUILDER_SPECIAL_FLOOR, DNGN_BUILDER_SPECIAL_WALL );
+
+ // set up passed in spec_room structure
+ sr.created = true;
+ sr.hooked_up = false;
+ sr.x1 = room_x1 + 1;
+ sr.x2 = room_x2 - 1;
+ sr.y1 = room_y1 + 1;
+ sr.y2 = room_y2 - 1;
+
+ if (level_number < 7)
+ spec_room_type = SROOM_LAIR_KOBOLD;
+ else
+ {
+ spec_room_type = random2(NUM_SPECIAL_ROOMS);
+
+ if (level_number < 23 && one_chance_in(4))
+ spec_room_type = SROOM_BEEHIVE;
+
+ if ((level_number > 13 && spec_room_type == SROOM_LAIR_KOBOLD)
+ || (level_number < 16 && spec_room_type == SROOM_MORGUE)
+ || (level_number < 17 && one_chance_in(4)))
+ {
+ spec_room_type = SROOM_LAIR_ORC;
+ }
+
+ if (level_number > 19 && coinflip())
+ spec_room_type = SROOM_MORGUE;
+ }
+
+
+ switch (spec_room_type)
+ {
+ case SROOM_LAIR_ORC:
+ // determine which monster array to generate {dlb}:
+ lev_mons = ((level_number > 24) ? 3 :
+ (level_number > 15) ? 2 :
+ (level_number > 9) ? 1
+ : 0);
+
+ // fill with baseline monster type {dlb}:
+ for (i = 0; i < 10; i++)
+ {
+ mons_alloc[i] = MONS_ORC;
+ }
+
+ // fill in with special monster types {dlb}:
+ switch (lev_mons)
+ {
+ case 0:
+ mons_alloc[9] = MONS_ORC_WARRIOR;
+ break;
+ case 1:
+ mons_alloc[8] = MONS_ORC_WARRIOR;
+ mons_alloc[9] = MONS_ORC_WARRIOR;
+ break;
+ case 2:
+ mons_alloc[6] = MONS_ORC_KNIGHT;
+ mons_alloc[7] = MONS_ORC_WARRIOR;
+ mons_alloc[8] = MONS_ORC_WARRIOR;
+ mons_alloc[9] = MONS_OGRE;
+ break;
+ case 3:
+ mons_alloc[2] = MONS_ORC_WARRIOR;
+ mons_alloc[3] = MONS_ORC_WARRIOR;
+ mons_alloc[4] = MONS_ORC_WARRIOR;
+ mons_alloc[5] = MONS_ORC_KNIGHT;
+ mons_alloc[6] = MONS_ORC_KNIGHT;
+ mons_alloc[7] = MONS_OGRE;
+ mons_alloc[8] = MONS_OGRE;
+ mons_alloc[9] = MONS_TROLL;
+ break;
+ }
+
+ // place monsters and give them items {dlb}:
+ for (x = sr.x1; x <= sr.x2; x++)
+ {
+ for (y = sr.y1; y <= sr.y2; y++)
+ {
+ if (one_chance_in(4))
+ continue;
+
+ mons_place( mons_alloc[random2(10)], BEH_SLEEP, MHITNOT,
+ true, x, y );
+ }
+ }
+ break;
+
+ case SROOM_LAIR_KOBOLD:
+ lordx = sr.x1 + random2(sr.x2 - sr.x1);
+ lordy = sr.y1 + random2(sr.y2 - sr.y1);
+
+ // determine which monster array to generate {dlb}:
+ lev_mons = ((level_number < 4) ? 0 :
+ (level_number < 6) ? 1 : (level_number < 9) ? 2 : 3);
+
+ // fill with baseline monster type {dlb}:
+ for (i = 0; i < 10; i++)
+ {
+ mons_alloc[i] = MONS_KOBOLD;
+ }
+
+ // fill in with special monster types {dlb}:
+ // in this case, they are uniformly the same {dlb}:
+ for (i = (7 - lev_mons); i < 10; i++)
+ {
+ mons_alloc[i] = MONS_BIG_KOBOLD;
+ }
+
+ // place monsters and give them items {dlb}:
+ for (x = sr.x1; x <= sr.x2; x++)
+ {
+ for (y = sr.y1; y <= sr.y2; y++)
+ {
+ if (one_chance_in(4))
+ continue;
+
+ // we'll put the boss down later.
+ if (x == lordx && y == lordy)
+ continue;
+
+ mons_place( mons_alloc[random2(10)], BEH_SLEEP, MHITNOT,
+ true, x, y );
+ }
+ }
+
+ // put the boss monster down
+ mons_place( MONS_BIG_KOBOLD, BEH_SLEEP, MHITNOT, true, lordx, lordy );
+
+ break;
+
+ case SROOM_TREASURY:
+ // should only appear in deep levels, with a guardian
+ // Maybe have several types of treasure room?
+ // place treasure {dlb}:
+ for (x = sr.x1; x <= sr.x2; x++)
+ {
+ for (y = sr.y1; y <= sr.y2; y++)
+ {
+ temp_rand = random2(11);
+
+ obj_type = ((temp_rand > 8) ? OBJ_WEAPONS : // 2 in 11
+ (temp_rand > 6) ? OBJ_ARMOUR : // 2 in 11
+ (temp_rand > 5) ? OBJ_MISSILES : // 1 in 11
+ (temp_rand > 4) ? OBJ_WANDS : // 1 in 11
+ (temp_rand > 3) ? OBJ_SCROLLS : // 1 in 11
+ (temp_rand > 2) ? OBJ_JEWELLERY : // 1 in 11
+ (temp_rand > 1) ? OBJ_BOOKS : // 1 in 11
+ (temp_rand > 0) ? OBJ_STAVES // 1 in 11
+ : OBJ_POTIONS); // 1 in 11
+
+ thing_created = items( 1, obj_type, OBJ_RANDOM, true,
+ level_number * 3, 250 );
+
+ if (thing_created != NON_ITEM)
+ {
+ mitm[thing_created].x = x;
+ mitm[thing_created].y = y;
+ }
+ }
+ }
+
+ // place guardian {dlb}:
+ mons_place( MONS_GUARDIAN_NAGA, BEH_SLEEP, MHITNOT, true,
+ sr.x1 + random2( sr.x2 - sr.x1 ),
+ sr.y1 + random2( sr.y2 - sr.y1 ) );
+
+ break;
+
+ case SROOM_BEEHIVE:
+ beehive(sr);
+ break;
+
+ case SROOM_MORGUE:
+ morgue(sr);
+ break;
+ }
+} // end special_room()
+
+// fills a special room with bees
+static void beehive(spec_room &sr)
+{
+ int i;
+ int x,y;
+
+ for (x = sr.x1; x <= sr.x2; x++)
+ {
+ for (y = sr.y1; y <= sr.y2; y++)
+ {
+ if (coinflip())
+ continue;
+
+ i = get_item_slot();
+ if (i == NON_ITEM)
+ goto finished_food;
+
+ mitm[i].quantity = 1;
+ mitm[i].base_type = OBJ_FOOD;
+ mitm[i].sub_type = (one_chance_in(25) ? FOOD_ROYAL_JELLY
+ : FOOD_HONEYCOMB);
+ mitm[i].x = x;
+ mitm[i].y = y;
+
+ item_colour( mitm[i] );
+ }
+ }
+
+
+ finished_food:
+
+ int queenx = sr.x1 + random2(sr.x2 - sr.x1);
+ int queeny = sr.y1 + random2(sr.y2 - sr.y1);
+
+ for (x = sr.x1; x <= sr.x2; x++)
+ {
+ for (y = sr.y1; y <= sr.y2; y++)
+ {
+ if (x == queenx && y == queeny)
+ continue;
+
+ // the hive is chock full of bees!
+
+ mons_place( one_chance_in(7) ? MONS_KILLER_BEE_LARVA
+ : MONS_KILLER_BEE,
+ BEH_SLEEP, MHITNOT, true, x, y );
+ }
+ }
+
+ mons_place( MONS_QUEEN_BEE, BEH_SLEEP, MHITNOT, true, queenx, queeny );
+} // end beehive()
+
+static void build_minivaults(int level_number, int force_vault)
+{
+ // for some weird reason can't put a vault on level 1, because monster equip
+ // isn't generated.
+ int altar_count = 0;
+
+ FixedVector < char, 7 > acq_item_class;
+ // hack - passing chars through '...' promotes them to ints, which
+ // barfs under gcc in fixvec.h. So don't.
+ acq_item_class[0] = OBJ_WEAPONS;
+ acq_item_class[1] = OBJ_ARMOUR;
+ acq_item_class[2] = OBJ_WEAPONS;
+ acq_item_class[3] = OBJ_JEWELLERY;
+ acq_item_class[4] = OBJ_BOOKS;
+ acq_item_class[5] = OBJ_STAVES;
+ acq_item_class[6] = OBJ_MISCELLANY;
+
+ FixedVector < int, 7 > mons_array(RANDOM_MONSTER,
+ RANDOM_MONSTER,
+ RANDOM_MONSTER,
+ RANDOM_MONSTER,
+ RANDOM_MONSTER,
+ RANDOM_MONSTER,
+ RANDOM_MONSTER);
+
+ char vgrid[81][81];
+
+ if (force_vault == 200)
+ {
+ force_vault = 200 + random2(37);
+ }
+
+ vault_main(vgrid, mons_array, force_vault, level_number);
+
+ int vx, vy;
+ int v1x, v1y;
+
+ /* find a target area which can be safely overwritten: */
+ while(1)
+ {
+ //if ( one_chance_in(1000) ) return;
+ v1x = 12 + random2(45);
+ v1y = 12 + random2(35);
+
+ for (vx = v1x; vx < v1x + 12; vx++)
+ {
+ for (vy = v1y; vy < v1y + 12; vy++)
+ {
+ if (one_chance_in(2000))
+ return;
+
+ if ((grd[vx][vy] != DNGN_FLOOR
+ && grd[vx][vy] != DNGN_ROCK_WALL
+ && grd[vx][vy] != DNGN_CLOSED_DOOR
+ && grd[vx][vy] != DNGN_SECRET_DOOR)
+ || igrd[vx][vy] != NON_ITEM
+ || mgrd[vx][vy] != NON_MONSTER)
+ {
+ goto out_of_check;
+ }
+ }
+ }
+
+ /* must not be completely isolated: */
+ for (vx = v1x; vx < v1x + 12; vx++)
+ {
+ // if (vx != v1x && vx != v1x + 12) continue;
+ for (vy = v1y; vy < v1y + 12; vy++)
+ {
+ // if (vy != v1y && vy != v1y + 12) continue;
+ if (grd[vx][vy] == DNGN_FLOOR
+ || grd[vx][vy] == DNGN_CLOSED_DOOR
+ || grd[vx][vy] == DNGN_SECRET_DOOR)
+ goto break_out;
+ }
+ }
+
+ out_of_check:
+ continue;
+
+ break_out:
+ break;
+ }
+
+ for (vx = v1x; vx < v1x + 12; vx++)
+ {
+ for (vy = v1y; vy < v1y + 12; vy++)
+ {
+ grd[vx][vy] = vgrid[vx - v1x][vy - v1y];
+ }
+ }
+
+ // these two are throwaways:
+ int initial_x, initial_y;
+ int num_runes = 0;
+
+ // paint the minivault onto the grid
+ for (vx = v1x; vx < v1x + 12; vx++)
+ {
+ for (vy = v1y; vy < v1y + 12; vy++)
+ {
+ altar_count = vault_grid( level_number, vx, vy, altar_count,
+ acq_item_class, mons_array,
+ grd[vx][vy], initial_x, initial_y,
+ force_vault, num_runes );
+ }
+ }
+} // end build_minivaults()
+
+static void build_vaults(int level_number, int force_vault)
+{
+ // for some weird reason can't put a vault on level 1, because monster equip
+ // isn't generated.
+ int i,j; // general loop variables
+ int altar_count = 0;
+ FixedVector < char, 10 > stair_exist;
+ char stx, sty;
+ int initial_x=0, initial_y=0;
+
+ FixedVector < char, 7 > acq_item_class;
+ // hack - passing chars through '...' promotes them to ints, which
+ // barfs under gcc in fixvec.h. So don't. -- GDL
+ acq_item_class[0] = OBJ_WEAPONS;
+ acq_item_class[1] = OBJ_ARMOUR;
+ acq_item_class[2] = OBJ_WEAPONS;
+ acq_item_class[3] = OBJ_JEWELLERY;
+ acq_item_class[4] = OBJ_BOOKS;
+ acq_item_class[5] = OBJ_STAVES;
+ acq_item_class[6] = OBJ_MISCELLANY;
+
+ FixedVector < int, 7 > mons_array(RANDOM_MONSTER,
+ RANDOM_MONSTER,
+ RANDOM_MONSTER,
+ RANDOM_MONSTER,
+ RANDOM_MONSTER,
+ RANDOM_MONSTER,
+ RANDOM_MONSTER);
+
+ char roomsss = 10 + random2(90);
+ char which_room = 0;
+
+ bool exclusive = (one_chance_in(10) ? false : true);
+
+ //bool exclusive2 = coinflip(); // usage commented out below {dlb}
+
+ char vgrid[81][81];
+
+ char gluggy = vault_main(vgrid, mons_array, force_vault, level_number);
+
+ int vx, vy;
+ int v1x = 0, v1y = 0, v2x = 0, v2y = 0;
+
+ //int item_made;
+
+ char dig_dir_x = 0;
+ char dig_dir_y = 0;
+ char dig_place_x = 0;
+ char dig_place_y = 0;
+ int num_runes = 0;
+
+ // note: assumes *no* previous item (I think) or monster (definitely)
+ // placement
+ for (vx = 0; vx < GXM; vx++)
+ {
+ for (vy = 0; vy < GYM; vy++)
+ {
+ altar_count = vault_grid( level_number, vx, vy, altar_count,
+ acq_item_class, mons_array,
+ vgrid[vy][vx], initial_x, initial_y,
+ force_vault, num_runes );
+ }
+ }
+
+ switch (gluggy)
+ {
+ case MAP_NORTH:
+ v1x = 1;
+ v2x = GXM;
+ v1y = 1;
+ v2y = 35;
+ initial_y++;
+ dig_dir_x = 0;
+ dig_dir_y = 1;
+ break;
+
+ case MAP_NORTHWEST:
+ v1x = 1;
+ v2x = 40;
+ v1y = 1;
+ v2y = 35;
+ initial_y++;
+ dig_dir_x = 1;
+ dig_dir_y = 0;
+ break;
+
+ case MAP_NORTHEAST:
+ v1x = 40;
+ v2x = GXM;
+ v1y = 1;
+ v2y = 35;
+ initial_y++;
+ dig_dir_x = -1;
+ dig_dir_y = 0;
+ break;
+
+ case MAP_SOUTHWEST:
+ v1x = 1;
+ v2x = 40;
+ v1y = 35;
+ v2y = GYM;
+ initial_y--;
+ dig_dir_x = 0;
+ dig_dir_y = -1;
+ break;
+
+ case MAP_SOUTHEAST:
+ v1x = 40;
+ v2x = GXM;
+ v1y = 35;
+ v2y = GYM;
+ initial_y--;
+ dig_dir_x = 0;
+ dig_dir_y = -1;
+ break;
+
+ case MAP_ENCOMPASS:
+ return;
+
+ case MAP_NORTH_DIS:
+ v1x = 1;
+ v2x = GXM;
+ v1y = 1;
+ v2y = 35;
+ plan_4(1, 1, 80, 35, DNGN_METAL_WALL);
+ goto vstair;
+ }
+
+ char cnx, cny;
+ char romx1[30], romy1[30], romx2[30], romy2[30];
+
+ for (i = 0; i < roomsss; i++)
+ {
+ do
+ {
+ romx1[which_room] = 10 + random2(50);
+ romy1[which_room] = 10 + random2(40);
+ romx2[which_room] = romx1[which_room] + 2 + random2(8);
+ romy2[which_room] = romy1[which_room] + 2 + random2(8);
+ }
+ while ((romx1[which_room] >= v1x && romx1[which_room] <= v2x
+ && romy1[which_room] >= v1y && romy1[which_room] <= v2y)
+ || (romx2[which_room] >= v1x && romx2[which_room] <= v2x
+ && romy2[which_room] >= v1y && romy2[which_room] <= v2y));
+
+ if (i == 0)
+ {
+ join_the_dots(initial_x, initial_y, romx1[which_room], romy1[which_room],
+ v1x, v1y, v2x, v2y);
+ }
+ else if (exclusive)
+ {
+ for (cnx = romx1[which_room] - 1; cnx < romx2[which_room] + 1;
+ cnx++)
+ {
+ for (cny = romy1[which_room] - 1; cny < romy2[which_room] + 1;
+ cny++)
+ {
+ if (grd[cnx][cny] != DNGN_ROCK_WALL)
+ goto continuing;
+ }
+ }
+ }
+
+ replace_area(romx1[which_room], romy1[which_room], romx2[which_room],
+ romy2[which_room], DNGN_ROCK_WALL, DNGN_FLOOR);
+
+ if (which_room > 0) // && !exclusive2
+ {
+ const int rx1 = romx1[which_room];
+ const int rx2 = romx2[which_room];
+ const int prev_rx1 = romx1[which_room - 1];
+ const int prev_rx2 = romx2[which_room - 1];
+
+ const int ry1 = romy1[which_room];
+ const int ry2 = romy2[which_room];
+ const int prev_ry1 = romy1[which_room - 1];
+ const int prev_ry2 = romy2[which_room - 1];
+
+ join_the_dots( rx1 + random2( rx2 - rx1 ),
+ ry1 + random2( ry2 - ry1 ),
+ prev_rx1 + random2( prev_rx2 - prev_rx1 ),
+ prev_ry1 + random2( prev_ry2 - prev_ry1 ),
+ v1x, v1y, v2x, v2y);
+ }
+
+ which_room++;
+
+ if (which_room >= 29)
+ break;
+
+ continuing:
+ continue; // next i loop
+
+ }
+
+ vstair:
+ dig_place_x = initial_x;
+ dig_place_y = initial_y;
+
+ if (gluggy != MAP_NORTH_DIS)
+ {
+ for (i = 0; i < 40; i++)
+ {
+ dig_place_x += dig_dir_x;
+ dig_place_y += dig_dir_y;
+
+ if (dig_place_x < 10 || dig_place_x > (GXM - 10)
+ || dig_place_y < 10 || dig_place_y > (GYM - 10))
+ {
+ break;
+ }
+
+ if (grd[dig_place_x][dig_place_y] == DNGN_ROCK_WALL)
+ grd[dig_place_x][dig_place_y] = DNGN_FLOOR;
+ }
+ }
+
+ unsigned char pos_x, pos_y;
+
+ for (stx = 0; stx < 10; stx++)
+ stair_exist[stx] = 0;
+
+ for (stx = 0; stx < GXM; stx++)
+ {
+ for (sty = 0; sty < GYM; sty++)
+ {
+ if (grd[stx][sty] >= DNGN_STONE_STAIRS_DOWN_I
+ && grd[stx][sty] <= DNGN_ROCK_STAIRS_UP)
+ {
+ stair_exist[grd[stx][sty] - 82] = 1;
+ }
+ }
+ }
+
+ if (player_in_branch( BRANCH_DIS ))
+ {
+ for (sty = 0; sty < 5; sty++)
+ stair_exist[sty] = 1;
+
+ for (sty = 6; sty < 10; sty++)
+ stair_exist[sty] = 0;
+ }
+
+ for (j = 0; j < (coinflip()? 4 : 3); j++)
+ {
+ for (i = 0; i < 2; i++)
+ {
+
+ if (stair_exist[(82 + j + (i * 4)) - 82] == 1) // does this look funny to *you*? {dlb}
+ continue;
+
+ do
+ {
+ pos_x = 10 + random2(GXM - 20);
+ pos_y = 10 + random2(GYM - 20);
+ }
+ while (grd[pos_x][pos_y] != DNGN_FLOOR
+ || (pos_x >= v1x && pos_x <= v2x && pos_y >= v1y
+ && pos_y <= v2y));
+
+ grd[pos_x][pos_y] = j + ((i == 0) ? DNGN_STONE_STAIRS_DOWN_I
+ : DNGN_STONE_STAIRS_UP_I);
+ }
+ }
+} // end build_vaults()
+
+// returns altar_count - seems rather odd to me to force such a return
+// when I believe the value is only used in the case of the ecumenical
+// temple - oh, well... {dlb}
+static int vault_grid( int level_number, int vx, int vy, int altar_count,
+ FixedVector < char, 7 > &acq_item_class,
+ FixedVector < int, 7 > &mons_array,
+ char vgrid, int &initial_x, int &initial_y,
+ int force_vault, int &num_runes)
+{
+ int not_used;
+
+ // first, set base tile for grids {dlb}:
+ grd[vx][vy] = ((vgrid == 'x') ? DNGN_ROCK_WALL :
+ (vgrid == 'X') ? DNGN_PERMAROCK_WALL :
+ (vgrid == 'c') ? DNGN_STONE_WALL :
+ (vgrid == 'v') ? DNGN_METAL_WALL :
+ (vgrid == 'b') ? DNGN_GREEN_CRYSTAL_WALL :
+ (vgrid == 'a') ? DNGN_WAX_WALL :
+ (vgrid == '+') ? DNGN_CLOSED_DOOR :
+ (vgrid == '=') ? DNGN_SECRET_DOOR :
+ (vgrid == 'w') ? DNGN_DEEP_WATER :
+ (vgrid == 'l') ? DNGN_LAVA :
+ (vgrid == '>') ? DNGN_ROCK_STAIRS_DOWN :
+ (vgrid == '<') ? DNGN_ROCK_STAIRS_UP :
+ (vgrid == '}') ? DNGN_STONE_STAIRS_DOWN_I :
+ (vgrid == '{') ? DNGN_STONE_STAIRS_UP_I :
+ (vgrid == ')') ? DNGN_STONE_STAIRS_DOWN_II :
+ (vgrid == '(') ? DNGN_STONE_STAIRS_UP_II :
+ (vgrid == ']') ? DNGN_STONE_STAIRS_DOWN_III :
+ (vgrid == '[') ? DNGN_STONE_STAIRS_UP_III :
+ (vgrid == 'A') ? DNGN_STONE_ARCH :
+ (vgrid == 'B') ? (DNGN_ALTAR_ZIN + altar_count) :// see below
+ (vgrid == 'C') ? pick_an_altar() : // f(x) elsewhere {dlb}
+
+ (vgrid == 'F') ? (one_chance_in(100)
+ ? (coinflip() ? DNGN_SILVER_STATUE
+ : DNGN_ORANGE_CRYSTAL_STATUE)
+ : DNGN_GRANITE_STATUE) :
+
+ (vgrid == 'I') ? DNGN_ORCISH_IDOL :
+ (vgrid == 'S') ? DNGN_SILVER_STATUE :
+ (vgrid == 'G') ? DNGN_GRANITE_STATUE :
+ (vgrid == 'H') ? DNGN_ORANGE_CRYSTAL_STATUE :
+ (vgrid == 'T') ? DNGN_BLUE_FOUNTAIN :
+ (vgrid == 'U') ? DNGN_SPARKLING_FOUNTAIN :
+ (vgrid == 'V') ? DNGN_PERMADRY_FOUNTAIN :
+ (vgrid == '\0')? DNGN_ROCK_WALL :
+ DNGN_FLOOR); // includes everything else
+
+ // then, handle oddball grids {dlb}:
+ switch (vgrid)
+ {
+ case 'B':
+ altar_count++;
+ break;
+ case '@':
+ initial_x = vx;
+ initial_y = vy;
+ break;
+ case '^':
+ place_specific_trap(vx, vy, TRAP_RANDOM);
+ break;
+ }
+
+ // then, handle grids that place "stuff" {dlb}:
+ switch (vgrid) // yes, I know this is a bit ugly ... {dlb}
+ {
+ case 'R':
+ case '$':
+ case '%':
+ case '*':
+ case '|':
+ case 'P': // possible rune
+ case 'O': // definite rune
+ case 'Z': // definite orb
+ {
+ int item_made = NON_ITEM;
+ unsigned char which_class = OBJ_RANDOM;
+ unsigned char which_type = OBJ_RANDOM;
+ int which_depth;
+ bool possible_rune = one_chance_in(3); // lame, I know {dlb}
+ int spec = 250;
+
+ if (vgrid == 'R')
+ {
+ which_class = OBJ_FOOD;
+ which_type = (one_chance_in(3) ? FOOD_ROYAL_JELLY
+ : FOOD_HONEYCOMB);
+ }
+ else if (vgrid == '$')
+ {
+ which_class = OBJ_GOLD;
+ which_type = OBJ_RANDOM;
+ }
+ else if (vgrid == '%' || vgrid == '*')
+ {
+ which_class = OBJ_RANDOM;
+ which_type = OBJ_RANDOM;
+ }
+ else if (vgrid == 'Z')
+ {
+ which_class = OBJ_ORBS;
+ which_type = ORB_ZOT;
+ }
+ else if (vgrid == '|'
+ || (vgrid == 'P' && (!possible_rune || num_runes > 0))
+ || (vgrid == 'O' && num_runes > 0))
+ {
+ which_class = acq_item_class[random2(7)];
+ which_type = OBJ_RANDOM;
+ }
+ else // for 'P' (1 out of 3 times) {dlb}
+ {
+ which_class = OBJ_MISCELLANY;
+ which_type = MISC_RUNE_OF_ZOT;
+ num_runes++;
+
+ if (you.level_type == LEVEL_PANDEMONIUM)
+ {
+ if (force_vault >= 60 && force_vault <= 63)
+ spec = force_vault;
+ else
+ spec = 50;
+ }
+ else if (you.level_type == LEVEL_ABYSS)
+ spec = 51;
+ else
+ spec = you.where_are_you;
+ }
+
+ which_depth = ((vgrid == '|'
+ || vgrid == 'P'
+ || vgrid == 'O'
+ || vgrid == 'Z') ? MAKE_GOOD_ITEM :
+ (vgrid == '*') ? 5 + (level_number * 2)
+ : level_number);
+
+ item_made = items( 1, which_class, which_type, true,
+ which_depth, spec );
+
+ if (item_made != NON_ITEM)
+ {
+ mitm[item_made].x = vx;
+ mitm[item_made].y = vy;
+ }
+ }
+ break;
+ }
+
+ // finally, handle grids that place monsters {dlb}:
+ if (vgrid >= '0' && vgrid <= '9')
+ {
+ int monster_level;
+ int monster_type_thing;
+
+ monster_level = ((vgrid == '8') ? (4 + (level_number * 2)) :
+ (vgrid == '9') ? (5 + level_number) : level_number);
+
+ if (monster_level > 30) // very high level monsters more common here
+ monster_level = 30;
+
+ monster_type_thing = ((vgrid == '8'
+ || vgrid == '9'
+ || vgrid == '0') ? RANDOM_MONSTER
+ : mons_array[(vgrid - '1')]);
+
+ place_monster( not_used, monster_type_thing, monster_level, BEH_SLEEP,
+ MHITNOT, true, vx, vy, false);
+ }
+
+ // again, this seems odd, given that this is just one of many
+ // vault types {dlb}
+ return (altar_count);
+} // end vault_grid()
+
+static void replace_area(int sx, int sy, int ex, int ey, unsigned char replace,
+ unsigned char feature)
+{
+ int x,y;
+ for(x=sx; x<=ex; x++)
+ for(y=sy; y<=ey; y++)
+ if (grd[x][y] == replace)
+ grd[x][y] = feature;
+}
+
+static void join_the_dots(unsigned char dotx1, unsigned char doty1,
+ unsigned char dotx2, unsigned char doty2,
+ char forbid_x1, char forbid_y1, char forbid_x2,
+ char forbid_y2)
+{
+ if (dotx1 == dotx2 && doty1 == doty2)
+ return;
+
+ char atx = dotx1, aty = doty1;
+
+ int join_count = 0;
+
+ grd[atx][aty] = DNGN_FLOOR;
+
+ do
+ {
+ join_count++;
+
+ if (join_count > 10000) // just insurance
+ return;
+
+ if (atx < dotx2
+ && (forbid_x1 == 0
+ || (atx + 1 < forbid_x1 || atx + 1 > forbid_x2
+ || (aty > forbid_y2 || aty < forbid_y1))))
+ {
+ atx++;
+ goto continuing;
+ }
+
+ if (atx > dotx2
+ && (forbid_x2 == 0
+ || (atx - 1 > forbid_x2 || atx - 1 < forbid_x1
+ || (aty > forbid_y2 || aty < forbid_y1))))
+ {
+ atx--;
+ goto continuing;
+ }
+
+ if (aty > doty2
+ && (forbid_y2 == 0
+ || (aty - 1 > forbid_y2 || aty - 1 < forbid_y1
+ || (atx > forbid_x2 || atx < forbid_x1))))
+ {
+ aty--;
+ goto continuing;
+ }
+
+ if (aty < doty2
+ && (forbid_y1 == 0
+ || (aty + 1 < forbid_y1 || aty + 1 > forbid_y2
+ || (atx > forbid_x2 || atx < forbid_x1))))
+ {
+ aty++;
+ goto continuing;
+ }
+
+ continuing:
+ grd[atx][aty] = DNGN_FLOOR;
+
+ }
+ while (atx != dotx2 || aty != doty2);
+} // end join_the_dots()
+
+static void place_pool(unsigned char pool_type, unsigned char pool_x1,
+ unsigned char pool_y1, unsigned char pool_x2,
+ unsigned char pool_y2)
+{
+ int i, j;
+ unsigned char left_edge, right_edge;
+
+ // don't place LAVA pools in crypt.. use shallow water instead.
+ if (pool_type == DNGN_LAVA
+ && (player_in_branch(BRANCH_CRYPT) || player_in_branch(BRANCH_TOMB)))
+ {
+ pool_type = DNGN_SHALLOW_WATER;
+ }
+
+ if (pool_x1 >= pool_x2 - 4 || pool_y1 >= pool_y2 - 4)
+ return;
+
+ left_edge = pool_x1 + 2 + random2(pool_x2 - pool_x1);
+ right_edge = pool_x2 - 2 - random2(pool_x2 - pool_x1);
+
+ for (j = pool_y1 + 1; j < pool_y2 - 1; j++)
+ {
+ for (i = pool_x1 + 1; i < pool_x2 - 1; i++)
+ {
+ if (i >= left_edge && i <= right_edge && grd[i][j] == DNGN_FLOOR)
+ grd[i][j] = pool_type;
+ }
+
+ if (j - pool_y1 < (pool_y2 - pool_y1) / 2 || one_chance_in(4))
+ {
+ if (left_edge > pool_x1 + 1)
+ left_edge -= random2(3);
+
+ if (right_edge < pool_x2 - 1)
+ right_edge += random2(3);
+ }
+
+ if (left_edge < pool_x2 - 1
+ && (j - pool_y1 >= (pool_y2 - pool_y1) / 2
+ || left_edge <= pool_x1 + 2 || one_chance_in(4)))
+ {
+ left_edge += random2(3);
+ }
+
+ if (right_edge > pool_x1 + 1
+ && (j - pool_y1 >= (pool_y2 - pool_y1) / 2
+ || right_edge >= pool_x2 - 2 || one_chance_in(4)))
+ {
+ right_edge -= random2(3);
+ }
+ }
+} // end place_pool()
+
+static void many_pools(unsigned char pool_type)
+{
+ int pools = 0;
+ int i = 0, j = 0, k = 0, l = 0;
+ int m = 0, n = 0;
+ int no_pools = 20 + random2avg(9, 2);
+ int timeout = 0;
+
+ if (player_in_branch( BRANCH_COCYTUS ))
+ pool_type = DNGN_DEEP_WATER;
+ else if (player_in_branch( BRANCH_GEHENNA ))
+ pool_type = DNGN_LAVA;
+
+ do
+ {
+ timeout++;
+
+ if (timeout >= 30000)
+ break;
+
+ i = 6 + random2( GXM - 26 );
+ j = 6 + random2( GYM - 26 );
+ k = i + 2 + roll_dice( 2, 9 );
+ l = j + 2 + roll_dice( 2, 9 );
+
+ for (m = i; m < k; m++)
+ {
+ for (n = j; n < l; n++)
+ {
+ if (grd[m][n] != DNGN_FLOOR)
+ goto continue_pools;
+ }
+ }
+
+ place_pool(pool_type, i, j, k, l);
+ pools++;
+
+ continue_pools:
+ continue;
+ }
+ while (pools < no_pools);
+} // end many_pools()
+
+void item_colour( item_def &item )
+{
+ int switchnum = 0;
+ int temp_value;
+
+ switch (item.base_type)
+ {
+ case OBJ_WEAPONS:
+ if (is_unrandom_artefact( item ))
+ break; // unrandarts already coloured
+
+ if (is_fixed_artefact( item ))
+ {
+ switch (item.special) // was: - 180, but that is *wrong* {dlb}
+ {
+ case SPWPN_SINGING_SWORD:
+ case SPWPN_SCEPTRE_OF_TORMENT:
+ item.colour = YELLOW;
+ break;
+ case SPWPN_WRATH_OF_TROG:
+ case SPWPN_SWORD_OF_POWER:
+ item.colour = RED;
+ break;
+ case SPWPN_SCYTHE_OF_CURSES:
+ item.colour = DARKGREY;
+ break;
+ case SPWPN_MACE_OF_VARIABILITY:
+ item.colour = random_colour();
+ break;
+ case SPWPN_GLAIVE_OF_PRUNE:
+ item.colour = MAGENTA;
+ break;
+ case SPWPN_SWORD_OF_ZONGULDROK:
+ item.colour = LIGHTGREY;
+ break;
+ case SPWPN_KNIFE_OF_ACCURACY:
+ item.colour = LIGHTCYAN;
+ break;
+ case SPWPN_STAFF_OF_OLGREB:
+ item.colour = GREEN;
+ break;
+ case SPWPN_VAMPIRES_TOOTH:
+ item.colour = WHITE;
+ break;
+ case SPWPN_STAFF_OF_WUCAD_MU:
+ item.colour = BROWN;
+ break;
+ }
+ break;
+ }
+
+ if (is_demonic( item.sub_type ))
+ item.colour = random_colour();
+ else if (launches_things( item.sub_type ))
+ item.colour = BROWN;
+ else
+ {
+ switch (item.sub_type)
+ {
+ case WPN_CLUB:
+ case WPN_GIANT_CLUB:
+ case WPN_GIANT_SPIKED_CLUB:
+ case WPN_ANCUS:
+ case WPN_WHIP:
+ case WPN_QUARTERSTAFF:
+ item.colour = BROWN;
+ break;
+ case WPN_QUICK_BLADE:
+ item.colour = LIGHTBLUE;
+ break;
+ case WPN_EXECUTIONERS_AXE:
+ item.colour = RED;
+ break;
+ default:
+ item.colour = LIGHTCYAN;
+ if (cmp_equip_race( item, ISFLAG_DWARVEN ))
+ item.colour = CYAN;
+ break;
+ }
+ }
+
+ // I don't think this is ever done -- see start of case {dlb}:
+ if (is_random_artefact( item ) && one_chance_in(5))
+ item.colour = random_colour();
+ break;
+
+ case OBJ_MISSILES:
+ switch (item.sub_type)
+ {
+ case MI_STONE:
+ case MI_LARGE_ROCK:
+ case MI_ARROW:
+ item.colour = BROWN;
+ break;
+ case MI_NEEDLE:
+ item.colour = WHITE;
+ break;
+ default:
+ item.colour = LIGHTCYAN;
+ if (cmp_equip_race( item, ISFLAG_DWARVEN ))
+ item.colour = CYAN;
+ break;
+ }
+ break;
+
+ case OBJ_ARMOUR:
+ if (is_unrandom_artefact( item ))
+ break; /* unrandarts have already been coloured */
+
+ switch (item.sub_type)
+ {
+ case ARM_CLOAK:
+ case ARM_ROBE:
+ item.colour = random_colour();
+ break;
+
+ case ARM_HELMET:
+ //caps and wizard's hats are random coloured
+ if (cmp_helmet_type( item, THELM_CAP )
+ || cmp_helmet_type( item, THELM_WIZARD_HAT ))
+ {
+ item.colour = random_colour();
+ }
+ else
+ item.colour = LIGHTCYAN;
+ break;
+
+ case ARM_BOOTS: // maybe more interesting boot colours?
+ case ARM_GLOVES:
+ case ARM_LEATHER_ARMOUR:
+ item.colour = BROWN;
+ break;
+ case ARM_DRAGON_HIDE:
+ case ARM_DRAGON_ARMOUR:
+ item.colour = mons_colour( MONS_DRAGON );
+ break;
+ case ARM_TROLL_HIDE:
+ case ARM_TROLL_LEATHER_ARMOUR:
+ item.colour = mons_colour( MONS_TROLL );
+ break;
+ case ARM_CRYSTAL_PLATE_MAIL:
+ item.colour = LIGHTGREY;
+ break;
+ case ARM_ICE_DRAGON_HIDE:
+ case ARM_ICE_DRAGON_ARMOUR:
+ item.colour = mons_colour( MONS_ICE_DRAGON );
+ break;
+ case ARM_STEAM_DRAGON_HIDE:
+ case ARM_STEAM_DRAGON_ARMOUR:
+ item.colour = mons_colour( MONS_STEAM_DRAGON );
+ break;
+ case ARM_MOTTLED_DRAGON_HIDE:
+ case ARM_MOTTLED_DRAGON_ARMOUR:
+ item.colour = mons_colour( MONS_MOTTLED_DRAGON );
+ break;
+ case ARM_STORM_DRAGON_HIDE:
+ case ARM_STORM_DRAGON_ARMOUR:
+ item.colour = mons_colour( MONS_STORM_DRAGON );
+ break;
+ case ARM_GOLD_DRAGON_HIDE:
+ case ARM_GOLD_DRAGON_ARMOUR:
+ item.colour = mons_colour( MONS_GOLDEN_DRAGON );
+ break;
+ case ARM_ANIMAL_SKIN:
+ item.colour = BROWN;
+ break;
+ case ARM_SWAMP_DRAGON_HIDE:
+ case ARM_SWAMP_DRAGON_ARMOUR:
+ item.colour = mons_colour( MONS_SWAMP_DRAGON );
+ break;
+ default:
+ item.colour = LIGHTCYAN;
+ if (cmp_equip_race( item, ISFLAG_DWARVEN ))
+ item.colour = CYAN;
+ break;
+ }
+
+ // I don't think this is ever done -- see start of case {dlb}:
+ if (is_random_artefact( item ) && one_chance_in(5))
+ item.colour = random_colour();
+ break;
+
+ case OBJ_WANDS:
+ item.special = you.item_description[IDESC_WANDS][item.sub_type];
+
+ switch (item.special % 12)
+ {
+ case 0: //"iron wand"
+ item.colour = CYAN;
+ break;
+ case 1: //"brass wand"
+ case 5: //"gold wand"
+ item.colour = YELLOW;
+ break;
+ case 2: //"bone wand"
+ case 8: //"ivory wand"
+ case 9: //"glass wand"
+ case 10: //"lead wand"
+ default:
+ item.colour = LIGHTGREY;
+ break;
+ case 3: //"wooden wand"
+ case 4: //"copper wand"
+ case 7: //"bronze wand"
+ item.colour = BROWN;
+ break;
+ case 6: //"silver wand"
+ item.colour = WHITE;
+ break;
+ case 11: //"plastic wand"
+ item.colour = random_colour();
+ break;
+ }
+
+ if (item.special / 12 == 9)
+ item.colour = DARKGREY;
+
+ // rare wands (eg disintegration - these will be very rare):
+ // maybe only 1 thing, like: crystal, shining, etc.
+ break;
+
+ case OBJ_POTIONS:
+ item.special = you.item_description[IDESC_POTIONS][item.sub_type];
+
+ switch (item.special % 14)
+ {
+ case 0: //"clear potion"
+ default:
+ item.colour = LIGHTGREY;
+ break;
+ case 1: //"blue potion"
+ case 7: //"inky potion"
+ item.colour = BLUE;
+ break;
+ case 2: //"black potion"
+ item.colour = DARKGREY;
+ break;
+ case 3: //"silvery potion"
+ case 13: //"white potion"
+ item.colour = WHITE;
+ break;
+ case 4: //"cyan potion"
+ item.colour = CYAN;
+ break;
+ case 5: //"purple potion"
+ item.colour = MAGENTA;
+ break;
+ case 6: //"orange potion"
+ item.colour = LIGHTRED;
+ break;
+ case 8: //"red potion"
+ item.colour = RED;
+ break;
+ case 9: //"yellow potion"
+ item.colour = YELLOW;
+ break;
+ case 10: //"green potion"
+ item.colour = GREEN;
+ break;
+ case 11: //"brown potion"
+ item.colour = BROWN;
+ break;
+ case 12: //"pink potion"
+ item.colour = LIGHTMAGENTA;
+ break;
+ }
+ break;
+
+ case OBJ_FOOD:
+ switch (item.sub_type)
+ {
+ case FOOD_BEEF_JERKY:
+ case FOOD_BREAD_RATION:
+ case FOOD_LYCHEE:
+ case FOOD_MEAT_RATION:
+ case FOOD_RAMBUTAN:
+ case FOOD_SAUSAGE:
+ case FOOD_SULTANA:
+ item.colour = BROWN;
+ break;
+ case FOOD_BANANA:
+ case FOOD_CHEESE:
+ case FOOD_HONEYCOMB:
+ case FOOD_LEMON:
+ case FOOD_PIZZA:
+ case FOOD_ROYAL_JELLY:
+ item.colour = YELLOW;
+ break;
+ case FOOD_PEAR:
+ item.colour = LIGHTGREEN;
+ break;
+ case FOOD_CHOKO:
+ case FOOD_SNOZZCUMBER:
+ item.colour = GREEN;
+ break;
+ case FOOD_APRICOT:
+ case FOOD_ORANGE:
+ item.colour = LIGHTRED;
+ break;
+ case FOOD_STRAWBERRY:
+ item.colour = RED;
+ break;
+ case FOOD_APPLE:
+ item.colour = (coinflip() ? RED : GREEN);
+ break;
+ case FOOD_GRAPE:
+ item.colour = (coinflip() ? MAGENTA : GREEN);
+ break;
+ case FOOD_CHUNK:
+ // set the appropriate colour of the meat:
+ temp_value = mons_colour( item.plus );
+ item.colour = (temp_value == BLACK) ? LIGHTRED : temp_value;
+ break;
+ default:
+ item.colour = BROWN;
+ }
+ break;
+
+ case OBJ_JEWELLERY:
+ /* unrandarts have already been coloured */
+ if (is_unrandom_artefact( item ))
+ break;
+ else if (is_random_artefact( item ))
+ {
+ item.colour = random_colour();
+ break;
+ }
+
+ item.colour = YELLOW;
+ item.special = you.item_description[IDESC_RINGS][item.sub_type];
+
+ switchnum = item.special % 13;
+
+ switch (switchnum)
+ {
+ case 0:
+ case 5:
+ item.colour = BROWN;
+ break;
+ case 1:
+ case 8:
+ case 11:
+ item.colour = LIGHTGREY;
+ break;
+ case 2:
+ case 6:
+ item.colour = YELLOW;
+ break;
+ case 3:
+ case 4:
+ item.colour = CYAN;
+ break;
+ case 7:
+ item.colour = BROWN;
+ break;
+ case 9:
+ case 10:
+ item.colour = WHITE;
+ break;
+ case 12:
+ item.colour = GREEN;
+ break;
+ case 13:
+ item.colour = LIGHTCYAN;
+ break;
+ }
+
+ if (item.sub_type >= AMU_RAGE)
+ {
+ switch (switchnum)
+ {
+ case 0: //"zirconium amulet"
+ case 9: //"ivory amulet"
+ case 11: //"platinum amulet"
+ item.colour = WHITE;
+ break;
+ case 1: //"sapphire amulet"
+ item.colour = LIGHTBLUE;
+ break;
+ case 2: //"golden amulet"
+ case 6: //"brass amulet"
+ item.colour = YELLOW;
+ break;
+ case 3: //"emerald amulet"
+ item.colour = GREEN;
+ break;
+ case 4: //"garnet amulet"
+ case 8: //"ruby amulet"
+ item.colour = RED;
+ break;
+ case 5: //"bronze amulet"
+ case 7: //"copper amulet"
+ item.colour = BROWN;
+ break;
+ case 10: //"bone amulet"
+ item.colour = LIGHTGREY;
+ break;
+ case 12: //"jade amulet"
+ item.colour = GREEN;
+ break;
+ case 13: //"plastic amulet"
+ item.colour = random_colour();
+ }
+ }
+
+ // blackened - same for both rings and amulets
+ if (item.special / 13 == 5)
+ item.colour = DARKGREY;
+ break;
+
+ case OBJ_SCROLLS:
+ item.colour = LIGHTGREY;
+ item.special = you.item_description[IDESC_SCROLLS][item.sub_type];
+ item.plus = you.item_description[IDESC_SCROLLS_II][item.sub_type];
+ break;
+
+ case OBJ_BOOKS:
+ switch (item.special % 10)
+ {
+ case 0:
+ case 1:
+ default:
+ item.colour = random_colour();
+ break;
+ case 2:
+ item.colour = (one_chance_in(3) ? BROWN : DARKGREY);
+ break;
+ case 3:
+ item.colour = CYAN;
+ break;
+ case 4:
+ item.colour = LIGHTGREY;
+ break;
+ }
+ break;
+
+ case OBJ_STAVES:
+ item.colour = BROWN;
+ break;
+
+ case OBJ_ORBS:
+ item.colour = LIGHTMAGENTA;
+ break;
+
+ case OBJ_MISCELLANY:
+ switch (item.sub_type)
+ {
+ case MISC_BOTTLED_EFREET:
+ case MISC_STONE_OF_EARTH_ELEMENTALS:
+ item.colour = BROWN;
+ break;
+
+ case MISC_AIR_ELEMENTAL_FAN:
+ case MISC_CRYSTAL_BALL_OF_ENERGY:
+ case MISC_CRYSTAL_BALL_OF_FIXATION:
+ case MISC_CRYSTAL_BALL_OF_SEEING:
+ case MISC_DISC_OF_STORMS:
+ case MISC_HORN_OF_GERYON:
+ case MISC_LANTERN_OF_SHADOWS:
+ item.colour = LIGHTGREY;
+ break;
+
+ case MISC_LAMP_OF_FIRE:
+ item.colour = YELLOW;
+ break;
+
+ case MISC_BOX_OF_BEASTS:
+ item.colour = DARKGREY;
+ break;
+
+ case MISC_RUNE_OF_ZOT:
+ switch (item.plus)
+ {
+ case RUNE_DIS: // iron
+ item.colour = CYAN;
+ break;
+
+ case RUNE_COCYTUS: // icy
+ item.colour = LIGHTBLUE;
+ break;
+
+ case RUNE_TARTARUS: // bone
+ item.colour = WHITE;
+ break;
+
+ case RUNE_SLIME_PITS: // slimy
+ item.colour = GREEN;
+ break;
+
+ case RUNE_SNAKE_PIT: // serpentine
+ case RUNE_ELVEN_HALLS: // elven
+ item.colour = LIGHTGREEN;
+ break;
+
+ case RUNE_VAULTS: // silver
+ item.colour = LIGHTGREY;
+ break;
+
+ case RUNE_TOMB: // golden
+ item.colour = YELLOW;
+ break;
+
+ case RUNE_SWAMP: // decaying
+ item.colour = BROWN;
+ break;
+
+ // These two are hardly unique, but since colour isn't used for
+ // stacking, so we don't have to worry to much about this. -- bwr
+ case RUNE_DEMONIC: // random pandemonium demonlords
+ case RUNE_ABYSSAL: // random in abyss
+ item.colour = random_colour();
+ break;
+
+ case RUNE_MNOLEG: // glowing
+ item.colour = coinflip() ? MAGENTA : LIGHTMAGENTA;
+ break;
+
+ case RUNE_LOM_LOBON: // magical
+ item.colour = BLUE;
+ break;
+
+ case RUNE_CEREBOV: // fiery
+ item.colour = coinflip() ? RED : LIGHTRED;
+ break;
+
+ case RUNE_GEHENNA: // obsidian
+ case RUNE_GLOORX_VLOQ: // dark
+ default:
+ item.colour = DARKGREY;
+ break;
+ }
+ break;
+
+ case MISC_EMPTY_EBONY_CASKET:
+ item.colour = DARKGREY;
+ break;
+
+ case MISC_DECK_OF_SUMMONINGS:
+ case MISC_DECK_OF_WONDERS:
+ case MISC_DECK_OF_TRICKS:
+ case MISC_DECK_OF_POWER:
+ default:
+ item.colour = random_colour();
+ break;
+ }
+ break;
+
+ case OBJ_CORPSES:
+ // set the appropriate colour of the body:
+ temp_value = mons_colour( item.plus );
+ item.colour = (temp_value == BLACK) ? LIGHTRED : temp_value;
+ break;
+
+ case OBJ_GOLD:
+ item.colour = YELLOW;
+ break;
+ }
+} // end item_colour()
+
+// Checks how rare a weapon is. Many of these have special routines for
+// placement, especially those with a rarity of zero. Chance is out of 10.
+static char rare_weapon(unsigned char w_type)
+{
+
+ // zero value weapons must be placed specially -- see items() {dlb}
+ if (is_demonic(w_type))
+ return 0;
+
+ switch (w_type)
+ {
+ case WPN_CLUB:
+ case WPN_DAGGER:
+ return 10;
+ case WPN_HAND_AXE:
+ case WPN_FALCHION:
+ case WPN_MACE:
+ case WPN_QUARTERSTAFF:
+ return 9;
+ case WPN_BOW:
+ case WPN_FLAIL:
+ case WPN_HAMMER:
+ case WPN_SABRE:
+ case WPN_SHORT_SWORD:
+ case WPN_SLING:
+ case WPN_SPEAR:
+ return 8;
+ case WPN_LONG_SWORD:
+ case WPN_MORNINGSTAR:
+ case WPN_WAR_AXE:
+ return 7;
+ case WPN_BATTLEAXE:
+ case WPN_CROSSBOW:
+ case WPN_GREAT_SWORD:
+ case WPN_SCIMITAR:
+ case WPN_TRIDENT:
+ return 6;
+ case WPN_GLAIVE:
+ case WPN_HALBERD:
+ case WPN_BLOWGUN:
+ return 5;
+ case WPN_BROAD_AXE:
+ case WPN_HAND_CROSSBOW:
+ case WPN_SPIKED_FLAIL:
+ case WPN_WHIP:
+ return 4;
+ case WPN_GREAT_MACE:
+ return 3;
+ case WPN_ANCUS:
+ case WPN_GREAT_FLAIL:
+ case WPN_SCYTHE:
+ return 2;
+ case WPN_GIANT_CLUB:
+ case WPN_GIANT_SPIKED_CLUB:
+ return 1;
+ // zero value weapons must be placed specially -- see items() {dlb}
+ case WPN_DOUBLE_SWORD:
+ case WPN_EVENINGSTAR:
+ case WPN_EXECUTIONERS_AXE:
+ case WPN_KATANA:
+ case WPN_KNIFE:
+ case WPN_QUICK_BLADE:
+ case WPN_TRIPLE_SWORD:
+ return 0;
+
+ default:
+ // should not happen now that calls are bounded by NUM_WEAPONS {dlb}
+ return -1;
+ }
+} // end rare_weapon()
+
+//jmf: generate altar based on where you are, or possibly randomly
+static int pick_an_altar(void)
+{
+ int altar_type = 0;
+ int temp_rand; // probability determination {dlb}
+
+ if (player_in_branch( BRANCH_SLIME_PITS )
+ || player_in_branch( BRANCH_ECUMENICAL_TEMPLE )
+ || you.level_type == LEVEL_LABYRINTH)
+ {
+ // no extra altars in temple, none at all in slime pits or labyrinth
+ altar_type = DNGN_FLOOR;
+ }
+ else if (you.level_type == LEVEL_DUNGEON && !one_chance_in(5))
+ {
+ switch (you.where_are_you)
+ {
+ case BRANCH_CRYPT:
+ altar_type = (coinflip() ? DNGN_ALTAR_KIKUBAAQUDGHA
+ : DNGN_ALTAR_YREDELEMNUL);
+ break;
+
+ case BRANCH_ORCISH_MINES: // violent gods
+ temp_rand = random2(5);
+
+ altar_type = ((temp_rand == 0) ? DNGN_ALTAR_VEHUMET :
+ (temp_rand == 1) ? DNGN_ALTAR_MAKHLEB :
+ (temp_rand == 2) ? DNGN_ALTAR_OKAWARU :
+ (temp_rand == 3) ? DNGN_ALTAR_TROG
+ : DNGN_ALTAR_XOM);
+ break;
+
+ case BRANCH_VAULTS: // "lawful" gods
+ temp_rand = random2(7);
+
+ altar_type = ((temp_rand == 0) ? DNGN_ALTAR_ELYVILON :
+ (temp_rand == 1) ? DNGN_ALTAR_SIF_MUNA :
+ (temp_rand == 2) ? DNGN_ALTAR_SHINING_ONE :
+ (temp_rand == 3 || temp_rand == 4) ? DNGN_ALTAR_OKAWARU
+ : DNGN_ALTAR_ZIN);
+ break;
+
+ case BRANCH_HALL_OF_BLADES:
+ altar_type = DNGN_ALTAR_OKAWARU;
+ break;
+
+ case BRANCH_ELVEN_HALLS: // "magic" gods
+ temp_rand = random2(4);
+
+ altar_type = ((temp_rand == 0) ? DNGN_ALTAR_VEHUMET :
+ (temp_rand == 1) ? DNGN_ALTAR_SIF_MUNA :
+ (temp_rand == 2) ? DNGN_ALTAR_XOM
+ : DNGN_ALTAR_MAKHLEB);
+ break;
+
+ case BRANCH_TOMB:
+ altar_type = DNGN_ALTAR_KIKUBAAQUDGHA;
+ break;
+
+ default:
+ do
+ {
+ altar_type = DNGN_ALTAR_ZIN + random2(NUM_GODS - 1);
+ }
+ while (altar_type == DNGN_ALTAR_NEMELEX_XOBEH);
+ break;
+ }
+ }
+ else
+ {
+ // Note: this case includes the pandemonium or the abyss.
+ temp_rand = random2(9);
+
+ altar_type = ((temp_rand == 0) ? DNGN_ALTAR_ZIN :
+ (temp_rand == 1) ? DNGN_ALTAR_SHINING_ONE :
+ (temp_rand == 2) ? DNGN_ALTAR_KIKUBAAQUDGHA :
+ (temp_rand == 3) ? DNGN_ALTAR_XOM :
+ (temp_rand == 4) ? DNGN_ALTAR_OKAWARU :
+ (temp_rand == 5) ? DNGN_ALTAR_MAKHLEB :
+ (temp_rand == 6) ? DNGN_ALTAR_SIF_MUNA :
+ (temp_rand == 7) ? DNGN_ALTAR_TROG
+ : DNGN_ALTAR_ELYVILON);
+ }
+
+ return (altar_type);
+} // end pick_an_altar()
+
+static void place_altar(void)
+{
+ int px, py;
+ int i, j;
+ int k = 0, l = 0;
+ int altar_type = pick_an_altar();
+
+ while(true)
+ {
+ rand_px:
+
+ px = 15 + random2(55);
+ py = 15 + random2(45);
+ k++;
+
+ if (k == 5000)
+ return;
+
+ l = 0;
+
+ for (i = px - 2; i < px + 3; i++)
+ {
+ for (j = py - 2; j < py + 3; j++)
+ {
+ if (grd[i][j] == DNGN_FLOOR)
+ l++;
+
+ if ((grd[i][j] != DNGN_ROCK_WALL
+ && grd[i][j] != DNGN_CLOSED_DOOR
+ && grd[i][j] != DNGN_SECRET_DOOR
+ && grd[i][j] != DNGN_FLOOR)
+ || mgrd[i][j] != NON_MONSTER)
+ {
+ goto rand_px;
+ }
+ }
+ }
+
+ if (l == 0)
+ goto rand_px;
+
+ for (i = px - 2; i < px + 3; i++)
+ {
+ for (j = py - 2; j < py + 3; j++)
+ {
+ grd[i][j] = DNGN_FLOOR;
+ }
+ }
+
+ grd[px][py] = altar_type;
+
+ return;
+ }
+} // end place_altar()
+
+static void place_shops(int level_number)
+{
+ int temp_rand = 0; // probability determination {dlb}
+ int timeout = 0;
+
+ unsigned char no_shops = 0;
+ unsigned char shop_place_x = 0;
+ unsigned char shop_place_y = 0;
+
+ temp_rand = random2(125);
+
+#if DEBUG_SHOPS
+ no_shops = MAX_SHOPS;
+#else
+ no_shops = ((temp_rand > 28) ? 0 : // 76.8%
+ (temp_rand > 4) ? 1 // 19.2%
+ : 1 + random2( MAX_SHOPS )); // 4.0%
+
+ if (no_shops == 0 || level_number < 3)
+ return;
+#endif
+
+ for (int i = 0; i < no_shops; i++)
+ {
+ timeout = 0;
+
+ do
+ {
+ shop_place_x = random2(GXM - 20) + 10;
+ shop_place_y = random2(GYM - 20) + 10;
+
+ timeout++;
+
+ if (timeout > 20000)
+ return;
+ }
+ while (grd[shop_place_x][shop_place_y] != DNGN_FLOOR);
+
+ place_spec_shop(level_number, shop_place_x, shop_place_y, SHOP_RANDOM);
+ }
+} // end place_shops()
+
+static void place_spec_shop( int level_number,
+ unsigned char shop_x, unsigned char shop_y,
+ unsigned char force_s_type )
+{
+ int orb = 0;
+ int i = 0;
+ int j = 0; // loop variable
+ int item_level;
+
+ for (i = 0; i < MAX_SHOPS; i++)
+ {
+ if (env.shop[i].type == SHOP_UNASSIGNED)
+ break;
+ }
+
+ if (i == MAX_SHOPS)
+ return;
+
+ for (j = 0; j < 3; j++)
+ {
+ env.shop[i].keeper_name[j] = 1 + random2(200);
+ }
+
+ env.shop[i].level = level_number * 2;
+
+ env.shop[i].type = (force_s_type != SHOP_RANDOM) ? force_s_type
+ : random2(NUM_SHOPS);
+
+ if (env.shop[i].type == SHOP_FOOD)
+ {
+ env.shop[i].greed = 10 + random2(5);
+ }
+ else if (env.shop[i].type != SHOP_WEAPON_ANTIQUE
+ && env.shop[i].type != SHOP_ARMOUR_ANTIQUE
+ && env.shop[i].type != SHOP_GENERAL_ANTIQUE)
+ {
+ env.shop[i].greed = 10 + random2(5) + random2(level_number / 2);
+ }
+ else
+ {
+ env.shop[i].greed = 15 + random2avg(19, 2) + random2(level_number);
+ }
+
+ int plojy = 5 + random2avg(12, 3);
+
+ for (j = 0; j < plojy; j++)
+ {
+ if (env.shop[i].type != SHOP_WEAPON_ANTIQUE
+ && env.shop[i].type != SHOP_ARMOUR_ANTIQUE
+ && env.shop[i].type != SHOP_GENERAL_ANTIQUE)
+ {
+ item_level = level_number + random2((level_number + 1) * 2);
+ }
+ else
+ {
+ item_level = level_number + random2((level_number + 1) * 3);
+ }
+
+ if (one_chance_in(4))
+ item_level = MAKE_GOOD_ITEM;
+
+ // don't generate gold in shops! This used to be possible with
+ // General Stores (see item_in_shop() below) (GDL)
+ while(true)
+ {
+ orb = items( 1, item_in_shop(env.shop[i].type), OBJ_RANDOM, true,
+ item_level, 250 );
+
+ if (orb != NON_ITEM
+ && mitm[orb].base_type != OBJ_GOLD
+ && (env.shop[i].type != SHOP_GENERAL_ANTIQUE
+ || (mitm[orb].base_type != OBJ_MISSILES
+ && mitm[orb].base_type != OBJ_FOOD)))
+ {
+ break;
+ }
+
+ // reset object and try again
+ if (orb != NON_ITEM)
+ {
+ mitm[orb].base_type = OBJ_UNASSIGNED;
+ mitm[orb].quantity = 0;
+ }
+ }
+
+ if (orb == NON_ITEM)
+ break;
+
+ // set object 'position' (gah!) & ID status
+ mitm[orb].x = 0;
+ mitm[orb].y = 5 + i;
+
+ if (env.shop[i].type != SHOP_WEAPON_ANTIQUE
+ && env.shop[i].type != SHOP_ARMOUR_ANTIQUE
+ && env.shop[i].type != SHOP_GENERAL_ANTIQUE)
+ {
+ set_ident_flags( mitm[orb], ISFLAG_IDENT_MASK );
+ }
+ }
+
+ env.shop[i].x = shop_x;
+ env.shop[i].y = shop_y;
+
+ grd[shop_x][shop_y] = DNGN_ENTER_SHOP;
+} // end place_spec_shop()
+
+static unsigned char item_in_shop(unsigned char shop_type)
+{
+ switch (shop_type)
+ {
+ case SHOP_WEAPON:
+ if (one_chance_in(5))
+ return (OBJ_MISSILES);
+ // *** deliberate fall through here {dlb} ***
+ case SHOP_WEAPON_ANTIQUE:
+ return (OBJ_WEAPONS);
+
+ case SHOP_ARMOUR:
+ case SHOP_ARMOUR_ANTIQUE:
+ return (OBJ_ARMOUR);
+
+ case SHOP_GENERAL:
+ case SHOP_GENERAL_ANTIQUE:
+ return (OBJ_RANDOM);
+
+ case SHOP_JEWELLERY:
+ return (OBJ_JEWELLERY);
+
+ case SHOP_WAND:
+ return (OBJ_WANDS);
+
+ case SHOP_BOOK:
+ return (OBJ_BOOKS);
+
+ case SHOP_FOOD:
+ return (OBJ_FOOD);
+
+ case SHOP_DISTILLERY:
+ return (OBJ_POTIONS);
+
+ case SHOP_SCROLL:
+ return (OBJ_SCROLLS);
+ }
+
+ return (OBJ_RANDOM);
+} // end item_in_shop()
+
+static void spotty_level(bool seeded, int iterations, bool boxy)
+{
+ // assumes starting with a level full of rock walls (1)
+ int i, j, k, l;
+
+ if (!seeded)
+ {
+ for (i = DNGN_STONE_STAIRS_DOWN_I; i < DNGN_ROCK_STAIRS_UP; i++)
+ {
+ if (i == DNGN_ROCK_STAIRS_DOWN
+ || (i == DNGN_STONE_STAIRS_UP_I
+ && !player_in_branch( BRANCH_SLIME_PITS )))
+ {
+ continue;
+ }
+
+ do
+ {
+ j = 10 + random2(GXM - 20);
+ k = 10 + random2(GYM - 20);
+ }
+ while (grd[j][k] != DNGN_ROCK_WALL
+ && grd[j + 1][k] != DNGN_ROCK_WALL);
+
+ grd[j][k] = i;
+
+ // creating elevators
+ if (i == DNGN_STONE_STAIRS_DOWN_I
+ && !player_in_branch( BRANCH_SLIME_PITS ))
+ {
+ grd[j + 1][k] = DNGN_STONE_STAIRS_UP_I;
+ }
+
+ if (grd[j][k - 1] == DNGN_ROCK_WALL)
+ grd[j][k - 1] = DNGN_FLOOR;
+ if (grd[j][k + 1] == DNGN_ROCK_WALL)
+ grd[j][k + 1] = DNGN_FLOOR;
+ if (grd[j - 1][k] == DNGN_ROCK_WALL)
+ grd[j - 1][k] = DNGN_FLOOR;
+ if (grd[j + 1][k] == DNGN_ROCK_WALL)
+ grd[j + 1][k] = DNGN_FLOOR;
+ }
+ } // end if !seeded
+
+ l = iterations;
+
+ // boxy levels have more clearing, so they get fewer iterations:
+ if (l == 0)
+ l = 200 + random2( (boxy ? 750 : 1500) );
+
+ for (i = 0; i < l; i++)
+ {
+ do
+ {
+ j = random2(GXM - 20) + 10;
+ k = random2(GYM - 20) + 10;
+ }
+ while (grd[j][k] == DNGN_ROCK_WALL
+ && grd[j - 1][k] == DNGN_ROCK_WALL
+ && grd[j + 1][k] == DNGN_ROCK_WALL
+ && grd[j][k - 1] == DNGN_ROCK_WALL
+ && grd[j][k + 1] == DNGN_ROCK_WALL
+ && grd[j - 2][k] == DNGN_ROCK_WALL
+ && grd[j + 2][k] == DNGN_ROCK_WALL
+ && grd[j][k - 2] == DNGN_ROCK_WALL
+ && grd[j][k + 2] == DNGN_ROCK_WALL);
+
+ if (grd[j][k] == DNGN_ROCK_WALL)
+ grd[j][k] = DNGN_FLOOR;
+ if (grd[j][k - 1] == DNGN_ROCK_WALL)
+ grd[j][k - 1] = DNGN_FLOOR;
+ if (grd[j][k + 1] == DNGN_ROCK_WALL)
+ grd[j][k + 1] = DNGN_FLOOR;
+ if (grd[j - 1][k] == DNGN_ROCK_WALL)
+ grd[j - 1][k] = DNGN_FLOOR;
+ if (grd[j + 1][k] == DNGN_ROCK_WALL)
+ grd[j + 1][k] = DNGN_FLOOR;
+
+ if (boxy)
+ {
+ if (grd[j - 1][k - 1] == DNGN_ROCK_WALL)
+ grd[j - 1][k - 1] = DNGN_FLOOR;
+ if (grd[j + 1][k + 1] == DNGN_ROCK_WALL)
+ grd[j + 1][k + 1] = DNGN_FLOOR;
+ if (grd[j - 1][k + 1] == DNGN_ROCK_WALL)
+ grd[j - 1][k + 1] = DNGN_FLOOR;
+ if (grd[j + 1][k - 1] == DNGN_ROCK_WALL)
+ grd[j + 1][k - 1] = DNGN_FLOOR;
+ }
+ }
+} // end spotty_level()
+
+static void bigger_room(void)
+{
+ unsigned char i, j;
+
+ for (i = 10; i < (GXM - 10); i++)
+ {
+ for (j = 10; j < (GYM - 10); j++)
+ {
+ if (grd[i][j] == DNGN_ROCK_WALL)
+ grd[i][j] = DNGN_FLOOR;
+ }
+ }
+
+ many_pools(DNGN_DEEP_WATER);
+
+ if (one_chance_in(3))
+ {
+ if (coinflip())
+ build_river( DNGN_DEEP_WATER );
+ else
+ build_lake( DNGN_DEEP_WATER );
+ }
+
+ int pair_count = coinflip() ? 4 : 3;
+
+ for (j = 0; j < pair_count; j++)
+ {
+ for (i = 0; i < 2; i++)
+ {
+ place_specific_stair( j + ((i==0) ? DNGN_STONE_STAIRS_DOWN_I
+ : DNGN_STONE_STAIRS_UP_I) );
+ }
+ }
+} // end bigger_room()
+
+// various plan_xxx functions
+static void plan_main(int level_number, char force_plan)
+{
+ // possible values for do_stairs:
+ // 0 - stairs already done
+ // 1 - stairs already done, do spotty
+ // 2 - no stairs
+ // 3 - no stairs, do spotty
+ char do_stairs = 0;
+ unsigned char special_grid = (one_chance_in(3) ? DNGN_METAL_WALL
+ : DNGN_STONE_WALL);
+ int i,j;
+
+ if (!force_plan)
+ force_plan = 1 + random2(12);
+
+ do_stairs = ((force_plan == 1) ? plan_1() :
+ (force_plan == 2) ? plan_2() :
+ (force_plan == 3) ? plan_3() :
+ (force_plan == 4) ? plan_4(0, 0, 0, 0, 99) :
+ (force_plan == 5) ? (one_chance_in(9) ? plan_5()
+ : plan_3()) :
+ (force_plan == 6) ? plan_6(level_number)
+ : plan_3());
+
+ if (do_stairs == 3 || do_stairs == 1)
+ spotty_level(true, 0, coinflip());
+
+ if (do_stairs == 2 || do_stairs == 3)
+ {
+ int pair_count = coinflip()?4:3;
+
+ for (j = 0; j < pair_count; j++)
+ {
+ for (i = 0; i < 2; i++)
+ {
+ place_specific_stair( j + ((i==0) ? DNGN_STONE_STAIRS_DOWN_I
+ : DNGN_STONE_STAIRS_UP_I) );
+ }
+ }
+ }
+
+ if (one_chance_in(20))
+ replace_area(0,0,GXM-1,GYM-1,DNGN_ROCK_WALL,special_grid);
+} // end plan_main()
+
+static char plan_1(void)
+{
+ int temp_rand = 0; // probability determination {dlb}
+
+ unsigned char width = (10 - random2(7)); // value range of [4,10] {dlb}
+
+ replace_area(10, 10, (GXM - 10), (10 + width), DNGN_ROCK_WALL, DNGN_FLOOR);
+ replace_area(10, (60 - width), (GXM - 10), (GYM - 10),
+ DNGN_ROCK_WALL, DNGN_FLOOR);
+ replace_area(10, 10, (10 + width), (GYM - 10), DNGN_ROCK_WALL, DNGN_FLOOR);
+ replace_area((60 - width), 10, (GXM - 10), (GYM - 10),
+ DNGN_ROCK_WALL, DNGN_FLOOR);
+
+ // possible early returns {dlb}:
+ temp_rand = random2(4);
+
+ if (temp_rand > 2) // 25% chance {dlb}
+ return 3;
+ else if (temp_rand > 1) // 25% chance {dlb}
+ return 2;
+ else // 50% chance {dlb}
+ {
+ unsigned char width2 = (coinflip()? (1 + random2(5)) : 5);
+
+ replace_area(10, (35 - width2), (GXM - 10), (35 + width2),
+ DNGN_ROCK_WALL, DNGN_FLOOR);
+ replace_area((40 - width2), 10, (40 + width2), (GYM - 10),
+ DNGN_ROCK_WALL, DNGN_FLOOR);
+ }
+
+ // possible early returns {dlb}:
+ temp_rand = random2(4);
+
+ if (temp_rand > 2) // 25% chance {dlb}
+ return 3;
+ else if (temp_rand > 1) // 25% chance {dlb}
+ return 2;
+ else // 50% chance {dlb}
+ {
+ temp_rand = random2(15);
+
+ if (temp_rand > 7) // 7 in 15 odds {dlb}
+ {
+ spec_room sr = { false, false, 0,0,0,0 };
+ sr.x1 = 25;
+ sr.y1 = 25;
+ sr.x2 = (GXM - 25);
+ sr.y2 = (GYM - 25);
+
+ int oblique_max = 0;
+ if (coinflip())
+ oblique_max = 5 + random2(20);
+
+ temp_rand = random2(7);
+
+ unsigned char floor_type = ((temp_rand > 1) ? DNGN_FLOOR : // 5/7
+ (temp_rand > 0) ? DNGN_DEEP_WATER// 1/7
+ : DNGN_LAVA); // 1/7
+ octa_room(sr, oblique_max, floor_type);
+ }
+ }
+
+ // final return {dlb}:
+ return (one_chance_in(5) ? 3 : 2);
+} // end plan_1()
+
+// just a cross:
+static char plan_2(void)
+{
+ char width2 = (5 - random2(5)); // value range of [1,5] {dlb}
+
+ replace_area(10, (35 - width2), (GXM - 10), (35 + width2),
+ DNGN_ROCK_WALL, DNGN_FLOOR);
+ replace_area((40 - width2), 10, (40 + width2), (GYM - 10),
+ DNGN_ROCK_WALL, DNGN_FLOOR);
+
+ return (one_chance_in(4) ? 2 : 3);
+} // end plan_2()
+
+static char plan_3(void)
+{
+
+ /* Draws a room, then another and links them together, then another and etc
+ Of course, this can easily end up looking just like a make_trail level.
+ */
+ int i;
+ char cnx, cny;
+ char roomsss = 30 + random2(90);
+
+ bool exclusive = (one_chance_in(10) ? false : true);
+ bool exclusive2 = coinflip();
+
+ char romx1[30], romy1[30], romx2[30], romy2[30];
+
+ char which_room = 0;
+
+ for (i = 0; i < roomsss; i++)
+ {
+ romx1[which_room] = 10 + random2(50);
+ romy1[which_room] = 10 + random2(40);
+ romx2[which_room] = romx1[which_room] + 2 + random2(8);
+ romy2[which_room] = romy1[which_room] + 2 + random2(8);
+
+ if (exclusive)
+ {
+ for (cnx = romx1[which_room] - 1; cnx < romx2[which_room] + 1;
+ cnx++)
+ {
+ for (cny = romy1[which_room] - 1; cny < romy2[which_room] + 1;
+ cny++)
+ {
+ if (grd[cnx][cny] != DNGN_ROCK_WALL)
+ goto continuing;
+ }
+ }
+ }
+
+ replace_area(romx1[which_room], romy1[which_room], romx2[which_room],
+ romy2[which_room], DNGN_ROCK_WALL, DNGN_FLOOR);
+
+ if (which_room > 0 && !exclusive2)
+ {
+ const int rx1 = romx1[which_room];
+ const int rx2 = romx2[which_room];
+ const int prev_rx1 = romx1[which_room - 1];
+ const int prev_rx2 = romx2[which_room - 1];
+
+ const int ry1 = romy1[which_room];
+ const int ry2 = romy2[which_room];
+ const int prev_ry1 = romy1[which_room - 1];
+ const int prev_ry2 = romy2[which_room - 1];
+
+ join_the_dots( rx1 + random2( rx2 - rx1 ),
+ ry1 + random2( ry2 - ry1 ),
+ prev_rx1 + random2( prev_rx2 - prev_rx1 ),
+ prev_ry1 + random2( prev_ry2 - prev_ry1 ),
+ 0, 0, 0, 0 );
+ }
+
+ which_room++;
+
+ if (which_room >= 29)
+ break;
+
+ continuing:
+ continue;
+ }
+
+ if (exclusive2)
+ {
+ for (i = 0; i < which_room; i++)
+ {
+ if (i > 0)
+ {
+ const int rx1 = romx1[i];
+ const int rx2 = romx2[i];
+ const int prev_rx1 = romx1[i - 1];
+ const int prev_rx2 = romx2[i - 1];
+
+ const int ry1 = romy1[i];
+ const int ry2 = romy2[i];
+ const int prev_ry1 = romy1[i - 1];
+ const int prev_ry2 = romy2[i - 1];
+
+ join_the_dots( rx1 + random2( rx2 - rx1 ),
+ ry1 + random2( ry2 - ry1 ),
+ prev_rx1 + random2( prev_rx2 - prev_rx1 ),
+ prev_ry1 + random2( prev_ry2 - prev_ry1 ),
+ 0, 0, 0, 0 );
+ }
+ }
+ }
+
+ return 2;
+} // end plan_3()
+
+static char plan_4(char forbid_x1, char forbid_y1, char forbid_x2,
+ char forbid_y2, unsigned char force_wall)
+{
+ // a more chaotic version of city level
+ int temp_rand; // req'd for probability checking
+
+ int number_boxes = 5000;
+ unsigned char drawing = DNGN_ROCK_WALL;
+ char b1x, b1y, b2x, b2y;
+ char cnx, cny;
+ int i;
+
+ temp_rand = random2(81);
+
+ number_boxes = ((temp_rand > 48) ? 4000 : // odds: 32 in 81 {dlb}
+ (temp_rand > 24) ? 3000 : // odds: 24 in 81 {dlb}
+ (temp_rand > 8) ? 5000 : // odds: 16 in 81 {dlb}
+ (temp_rand > 0) ? 2000 // odds: 8 in 81 {dlb}
+ : 1000); // odds: 1 in 81 {dlb}
+
+ if (force_wall != 99)
+ drawing = force_wall;
+ else
+ {
+ temp_rand = random2(18);
+
+ drawing = ((temp_rand > 7) ? DNGN_ROCK_WALL : // odds: 10 in 18 {dlb}
+ (temp_rand > 2) ? DNGN_STONE_WALL // odds: 5 in 18 {dlb}
+ : DNGN_METAL_WALL); // odds: 3 in 18 {dlb}
+ }
+
+ replace_area(10, 10, (GXM - 10), (GYM - 10), DNGN_ROCK_WALL, DNGN_FLOOR);
+
+ // replace_area can also be used to fill in:
+ for (i = 0; i < number_boxes; i++)
+ {
+
+ b1x = 11 + random2(45);
+ b1y = 11 + random2(35);
+
+ b2x = b1x + 3 + random2(7) + random2(5);
+ b2y = b1y + 3 + random2(7) + random2(5);
+
+ if (forbid_x1 != 0 || forbid_x2 != 0)
+ {
+ if (b1x <= forbid_x2 && b1x >= forbid_x1
+ && b1y <= forbid_y2 && b1y >= forbid_y1)
+ {
+ goto continuing;
+ }
+ else if (b2x <= forbid_x2 && b2x >= forbid_x1
+ && b2y <= forbid_y2 && b2y >= forbid_y1)
+ {
+ goto continuing;
+ }
+ }
+
+ for (cnx = b1x - 1; cnx < b2x + 1; cnx++)
+ {
+ for (cny = b1y - 1; cny < b2y + 1; cny++)
+ {
+ if (grd[cnx][cny] != DNGN_FLOOR)
+ goto continuing;
+ }
+ }
+
+ if (force_wall == 99)
+ {
+ // NB: comparison reversal here - combined
+ temp_rand = random2(1200);
+
+ // probabilities *not meant* to sum to one! {dlb}
+ if (temp_rand < 417) // odds: 261 in 1200 {dlb}
+ drawing = DNGN_ROCK_WALL;
+ else if (temp_rand < 156) // odds: 116 in 1200 {dlb}
+ drawing = DNGN_STONE_WALL;
+ else if (temp_rand < 40) // odds: 40 in 1200 {dlb}
+ drawing = DNGN_METAL_WALL;
+ }
+
+ temp_rand = random2(210);
+
+ if (temp_rand > 71) // odds: 138 in 210 {dlb}
+ replace_area(b1x, b1y, b2x, b2y, DNGN_FLOOR, drawing);
+ else // odds: 72 in 210 {dlb}
+ box_room(b1x, b2x - 1, b1y, b2y - 1, drawing);
+
+ continuing:
+ continue;
+ }
+
+ if (forbid_x1 == 0 && one_chance_in(4)) // a market square
+ {
+ spec_room sr = { false, false, 0, 0, 0, 0 };
+ sr.x1 = 25;
+ sr.y1 = 25;
+ sr.x2 = 55;
+ sr.y2 = 45;
+
+ int oblique_max = 0;
+ if (!one_chance_in(4))
+ oblique_max = 5 + random2(20); // used elsewhere {dlb}
+
+ unsigned char feature = DNGN_FLOOR;
+ if (one_chance_in(10))
+ feature = coinflip()? DNGN_DEEP_WATER : DNGN_LAVA;
+
+ octa_room(sr, oblique_max, feature);
+ }
+
+ return 2;
+} // end plan_4()
+
+static char plan_5(void)
+{
+ unsigned char imax = 5 + random2(20); // value range of [5,24] {dlb}
+
+ for (unsigned char i = 0; i < imax; i++)
+ {
+ join_the_dots( random2(GXM - 20) + 10, random2(GYM - 20) + 10,
+ random2(GXM - 20) + 10, random2(GYM - 20) + 10,
+ 0, 0, 0, 0 );
+ }
+
+ if (!one_chance_in(4))
+ spotty_level(true, 100, coinflip());
+
+ return 2;
+} // end plan_5()
+
+static char plan_6(int level_number)
+{
+ spec_room sr = { false, false, 0,0,0,0 };
+
+ // circle of standing stones (well, kind of)
+ sr.x1 = 10;
+ sr.x2 = (GXM - 10);
+ sr.y1 = 10;
+ sr.y2 = (GYM - 10);
+
+ octa_room(sr, 14, DNGN_FLOOR);
+
+ replace_area(23, 23, 26, 26, DNGN_FLOOR, DNGN_STONE_WALL);
+ replace_area(23, 47, 26, 50, DNGN_FLOOR, DNGN_STONE_WALL);
+ replace_area(55, 23, 58, 26, DNGN_FLOOR, DNGN_STONE_WALL);
+ replace_area(55, 47, 58, 50, DNGN_FLOOR, DNGN_STONE_WALL);
+ replace_area(39, 20, 43, 23, DNGN_FLOOR, DNGN_STONE_WALL);
+ replace_area(39, 50, 43, 53, DNGN_FLOOR, DNGN_STONE_WALL);
+ replace_area(20, 30, 23, 33, DNGN_FLOOR, DNGN_STONE_WALL);
+ replace_area(20, 40, 23, 43, DNGN_FLOOR, DNGN_STONE_WALL);
+ replace_area(58, 30, 61, 33, DNGN_FLOOR, DNGN_STONE_WALL);
+ replace_area(58, 40, 61, 43, DNGN_FLOOR, DNGN_STONE_WALL);
+
+ grd[35][32] = DNGN_STONE_WALL;
+ grd[46][32] = DNGN_STONE_WALL;
+ grd[35][40] = DNGN_STONE_WALL;
+ grd[46][40] = DNGN_STONE_WALL;
+
+ grd[69][34] = DNGN_STONE_STAIRS_DOWN_I;
+ grd[69][35] = DNGN_STONE_STAIRS_DOWN_II;
+ grd[69][36] = DNGN_STONE_STAIRS_DOWN_III;
+
+ grd[10][34] = DNGN_STONE_STAIRS_UP_I;
+ grd[10][35] = DNGN_STONE_STAIRS_UP_II;
+ grd[10][36] = DNGN_STONE_STAIRS_UP_III;
+
+ // This "back door" is often one of the easier ways to get out of
+ // pandemonium... the easiest is to use the banish spell.
+ //
+ // Note, that although "level_number > 20" will work for most
+ // trips to pandemonium (through regular portals), it won't work
+ // for demonspawn who gate themselves there. -- bwr
+ if (((player_in_branch( BRANCH_MAIN_DUNGEON ) && level_number > 20)
+ || you.level_type == LEVEL_PANDEMONIUM)
+ && (coinflip() || you.mutation[ MUT_PANDEMONIUM ]))
+ {
+ grd[40][36] = DNGN_ENTER_ABYSS;
+ grd[41][36] = DNGN_ENTER_ABYSS;
+ }
+
+ return 0;
+} // end plan_6()
+
+static bool octa_room(spec_room &sr, int oblique_max, unsigned char type_floor)
+{
+ int x,y;
+
+ // hack - avoid lava in the crypt {gdl}
+ if ((player_in_branch( BRANCH_CRYPT ) || player_in_branch( BRANCH_TOMB ))
+ && type_floor == DNGN_LAVA)
+ {
+ type_floor = DNGN_SHALLOW_WATER;
+ }
+
+ int oblique = oblique_max;
+
+ // check octagonal room for special; avoid if exists
+ for (x = sr.x1; x < sr.x2; x++)
+ {
+ for (y = sr.y1 + oblique; y < sr.y2 - oblique; y++)
+ {
+ if (grd[x][y] == DNGN_BUILDER_SPECIAL_WALL)
+ return false;
+ }
+
+ if (oblique > 0)
+ oblique--;
+
+ if (x > sr.x2 - oblique_max)
+ oblique += 2;
+ }
+
+ oblique = oblique_max;
+
+
+ for (x = sr.x1; x < sr.x2; x++)
+ {
+ for (y = sr.y1 + oblique; y < sr.y2 - oblique; y++)
+ {
+ if (grd[x][y] == DNGN_ROCK_WALL)
+ grd[x][y] = type_floor;
+
+ if (grd[x][y] == DNGN_FLOOR && type_floor == DNGN_SHALLOW_WATER)
+ grd[x][y] = DNGN_SHALLOW_WATER;
+
+ if (type_floor >= DNGN_LAST_SOLID_TILE
+ && grd[x][y] == DNGN_CLOSED_DOOR)
+ {
+ grd[x][y] = DNGN_FLOOR; // ick
+ }
+ }
+
+ if (oblique > 0)
+ oblique--;
+
+ if (x > sr.x2 - oblique_max)
+ oblique += 2;
+ }
+
+ return true;
+} // end octa_room()
+
+static void labyrinth_level(int level_number)
+{
+ int temp_rand; // probability determination {dlb}
+
+ int keep_lx = 0, keep_ly = 0;
+ int keep_lx2 = 0, keep_ly2 = 0;
+ char start_point_x = 10;
+ char start_point_y = 10;
+ char going_x = 1;
+ char going_y = (coinflip() ? 0 : 1);
+ bool do_2 = false;
+ int clear_space = 1;
+ unsigned char traps_put2 = 0;
+
+ if (coinflip())
+ {
+ start_point_x = (GXM - 10);
+ going_x = -1;
+ }
+
+ if (coinflip())
+ {
+ start_point_y = (GYM - 10);
+
+ if (going_y == 1)
+ going_y = -1;
+ }
+
+ int lx = start_point_x;
+ int ly = start_point_y;
+
+ if (going_y)
+ goto do_y;
+
+ do_x:
+ traps_put2 = 0;
+ clear_space = 0; // ( coinflip()? 3 : 2 );
+
+ do
+ {
+ lx += going_x;
+
+ if (grd[lx][ly] == DNGN_ROCK_WALL)
+ grd[lx][ly] = DNGN_FLOOR;
+ }
+ while (lx < (GXM - 8) && lx > 8
+ && grd[lx + going_x * (2 + clear_space)][ly] == DNGN_ROCK_WALL);
+
+ going_x = 0;
+
+ if (ly < 32)
+ going_y = 1;
+ else if (ly > 37)
+ going_y = -1;
+ else
+ goto finishing;
+
+ do_y: // if (going_y != 0)
+ if (do_2)
+ {
+ lx = keep_lx2;
+ ly = keep_ly2;
+ }
+
+ // do_2 = false is the problem
+ if (coinflip())
+ {
+ clear_space = 0;
+ do_2 = false;
+ }
+ else
+ {
+ clear_space = 2;
+ do_2 = true;
+ }
+
+ do
+ {
+ ly += going_y;
+
+ if (grd[lx][ly] == DNGN_ROCK_WALL)
+ grd[lx][ly] = DNGN_FLOOR;
+ }
+ while (ly < (GYM - 8) && ly > 8
+ && grd[lx][ly + going_y * (2 + clear_space)] == DNGN_ROCK_WALL);
+
+ keep_lx = lx;
+ keep_ly = ly;
+
+ if (lx < 37)
+ going_x = 1;
+ else if (lx > 42)
+ going_x = -1;
+
+ if (ly < 33)
+ ly += 2;
+ else if (ly > 37)
+ ly -= 2;
+
+ clear_space = ((!do_2) ? 6 : 2);
+
+ do
+ {
+ lx += going_x;
+
+ if (grd[lx][ly] == DNGN_ROCK_WALL)
+ grd[lx][ly] = DNGN_FLOOR;
+ }
+ while (lx < (GXM - 8) && lx > 8
+ && grd[lx + going_x * (2 + clear_space)][ly] == DNGN_ROCK_WALL);
+
+ if (do_2)
+ {
+ keep_lx2 = lx;
+ keep_ly2 = ly;
+ }
+
+ lx = keep_lx;
+ ly = keep_ly;
+
+ going_y = 0;
+
+ if (lx < 37)
+ going_x = 1;
+ else if (lx > 42)
+ going_x = -1;
+ else
+ goto finishing;
+
+ goto do_x;
+
+ finishing:
+ start_point_x = 10 + random2(GXM - 20);
+
+ int treasure_item = 0;
+
+ unsigned char glopop = OBJ_RANDOM; // used in calling items() {dlb}
+
+ int num_items = 8 + random2avg(9, 2);
+ for (int i = 0; i < num_items; i++)
+ {
+ temp_rand = random2(11);
+
+ glopop = ((temp_rand == 0 || temp_rand == 9) ? OBJ_WEAPONS :
+ (temp_rand == 1 || temp_rand == 10) ? OBJ_ARMOUR :
+ (temp_rand == 2) ? OBJ_MISSILES :
+ (temp_rand == 3) ? OBJ_WANDS :
+ (temp_rand == 4) ? OBJ_MISCELLANY :
+ (temp_rand == 5) ? OBJ_SCROLLS :
+ (temp_rand == 6) ? OBJ_JEWELLERY :
+ (temp_rand == 7) ? OBJ_BOOKS
+ /* (temp_rand == 8) */ : OBJ_STAVES);
+
+ treasure_item = items( 1, glopop, OBJ_RANDOM, true,
+ level_number * 3, 250 );
+
+ if (treasure_item != NON_ITEM)
+ {
+ mitm[treasure_item].x = lx;
+ mitm[treasure_item].y = ly;
+ }
+ }
+
+ mons_place( MONS_MINOTAUR, BEH_SLEEP, MHITNOT, true, lx, ly );
+
+ grd[lx][ly] = DNGN_ROCK_STAIRS_UP;
+
+ link_items();
+
+ // turn rock walls into undiggable stone or metal:
+ temp_rand = random2(50);
+
+ unsigned char wall_xform = ((temp_rand > 10) ? DNGN_STONE_WALL // 78.0%
+ : DNGN_METAL_WALL); // 22.0%
+
+ replace_area(0,0,GXM-1,GYM-1,DNGN_ROCK_WALL,wall_xform);
+
+} // end labyrinth_level()
+
+static bool is_wall(int x, int y)
+{
+ unsigned char feat = grd[x][y];
+
+ switch (feat)
+ {
+ case DNGN_ROCK_WALL:
+ case DNGN_STONE_WALL:
+ case DNGN_METAL_WALL:
+ case DNGN_GREEN_CRYSTAL_WALL:
+ case DNGN_WAX_WALL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+
+static int box_room_door_spot(int x, int y)
+{
+ // if there is a door near us embedded in rock, we have to be a door too.
+ if ((grd[x-1][y] == DNGN_CLOSED_DOOR && is_wall(x-1,y-1) && is_wall(x-1,y+1))
+ || (grd[x+1][y] == DNGN_CLOSED_DOOR && is_wall(x+1,y-1) && is_wall(x+1,y+1))
+ || (grd[x][y-1] == DNGN_CLOSED_DOOR && is_wall(x-1,y-1) && is_wall(x+1,y-1))
+ || (grd[x][y+1] == DNGN_CLOSED_DOOR && is_wall(x-1,y+1) && is_wall(x+1,y+1)))
+ {
+ grd[x][y] = DNGN_CLOSED_DOOR;
+ return 2;
+ }
+
+ // to be a good spot for a door, we need non-wall on two sides and
+ // wall on two sides.
+ bool nor = is_wall(x, y-1);
+ bool sou = is_wall(x, y+1);
+ bool eas = is_wall(x-1, y);
+ bool wes = is_wall(x+1, y);
+
+ if (nor == sou && eas == wes && nor != eas)
+ return 1;
+
+ return 0;
+}
+
+static int box_room_doors( int bx1, int bx2, int by1, int by2, int new_doors)
+{
+ int good_doors[200]; // 1 == good spot, 2 == door placed!
+ int spot;
+ int i,j;
+ int doors_placed = new_doors;
+
+ // sanity
+ if ( 2 * ( (bx2 - bx1) + (by2-by1) ) > 200)
+ return 0;
+
+ // go through, building list of good door spots, and replacing wall
+ // with door if we're about to block off another door.
+ int spot_count = 0;
+
+ // top & bottom
+ for(i=bx1+1; i<bx2; i++)
+ {
+ good_doors[spot_count ++] = box_room_door_spot(i, by1);
+ good_doors[spot_count ++] = box_room_door_spot(i, by2);
+ }
+ // left & right
+ for(i=by1+1; i<by2; i++)
+ {
+ good_doors[spot_count ++] = box_room_door_spot(bx1, i);
+ good_doors[spot_count ++] = box_room_door_spot(bx2, i);
+ }
+
+ if (new_doors == 0)
+ {
+ // count # of doors we HAD to place
+ for(i=0; i<spot_count; i++)
+ if (good_doors[i] == 2)
+ doors_placed++;
+
+ return doors_placed;
+ }
+
+ while(new_doors > 0 && spot_count > 0)
+ {
+ spot = random2(spot_count);
+ if (good_doors[spot] != 1)
+ continue;
+
+ j = 0;
+ for(i=bx1+1; i<bx2; i++)
+ {
+ if (spot == j++)
+ {
+ grd[i][by1] = DNGN_CLOSED_DOOR;
+ break;
+ }
+ if (spot == j++)
+ {
+ grd[i][by2] = DNGN_CLOSED_DOOR;
+ break;
+ }
+ }
+
+ for(i=by1+1; i<by2; i++)
+ {
+ if (spot == j++)
+ {
+ grd[bx1][i] = DNGN_CLOSED_DOOR;
+ break;
+ }
+ if (spot == j++)
+ {
+ grd[bx2][i] = DNGN_CLOSED_DOOR;
+ break;
+ }
+ }
+
+ // try not to put a door in the same place twice
+ good_doors[spot] = 2;
+ new_doors --;
+ }
+
+ return doors_placed;
+}
+
+
+static void box_room(int bx1, int bx2, int by1, int by2, int wall_type)
+{
+ // hack -- avoid lava in the crypt. {gdl}
+ if ((player_in_branch( BRANCH_CRYPT ) || player_in_branch( BRANCH_TOMB ))
+ && wall_type == DNGN_LAVA)
+ {
+ wall_type = DNGN_SHALLOW_WATER;
+ }
+
+ int temp_rand, new_doors, doors_placed;
+
+ // do top & bottom walls
+ replace_area(bx1,by1,bx2,by1,DNGN_FLOOR,wall_type);
+ replace_area(bx1,by2,bx2,by2,DNGN_FLOOR,wall_type);
+
+ // do left & right walls
+ replace_area(bx1,by1+1,bx1,by2-1,DNGN_FLOOR,wall_type);
+ replace_area(bx2,by1+1,bx2,by2-1,DNGN_FLOOR,wall_type);
+
+ // sometimes we have to place doors, or else we shut in other buildings' doors
+ doors_placed = box_room_doors(bx1, bx2, by1, by2, 0);
+
+ temp_rand = random2(100);
+ new_doors = (temp_rand > 45) ? 2 :
+ ((temp_rand > 22) ? 1 : 3);
+
+ // small rooms don't have as many doors
+ if ((bx2-bx1)*(by2-by1) < 36)
+ new_doors--;
+
+ new_doors -= doors_placed;
+ if (new_doors > 0)
+ box_room_doors(bx1, bx2, by1, by2, new_doors);
+}
+
+static void city_level(int level_number)
+{
+ int temp_rand; // probability determination {dlb}
+ int wall_type; // remember, can have many wall types in one level
+ int wall_type_room; // simplifies logic of innermost loop {dlb}
+
+ int xs = 0, ys = 0;
+ int x1 = 0, x2 = 0;
+ int y1 = 0, y2 = 0;
+ int i,j;
+
+ temp_rand = random2(8);
+
+ wall_type = ((temp_rand > 4) ? DNGN_ROCK_WALL : // 37.5% {dlb}
+ (temp_rand > 1) ? DNGN_STONE_WALL // 37.5% {dlb}
+ : DNGN_METAL_WALL); // 25.0% {dlb}
+
+ if (one_chance_in(100))
+ wall_type = DNGN_GREEN_CRYSTAL_WALL;
+
+ make_box( 7, 7, GXM-7, GYM-7, DNGN_FLOOR );
+
+ for (i = 0; i < 5; i++)
+ {
+ for (j = 0; j < 4; j++)
+ {
+ xs = 8 + (i * 13);
+ ys = 8 + (j * 14);
+ x1 = xs + random2avg(5, 2);
+ y1 = ys + random2avg(5, 2);
+ x2 = xs + 11 - random2avg(5, 2);
+ y2 = ys + 11 - random2avg(5, 2);
+
+ temp_rand = random2(280);
+
+ if (temp_rand > 39) // 85.7% draw room(s) {dlb}
+ {
+ wall_type_room = ((temp_rand > 63) ? wall_type : // 77.1%
+ (temp_rand > 54) ? DNGN_STONE_WALL : // 3.2%
+ (temp_rand > 45) ? DNGN_ROCK_WALL // 3.2%
+ : DNGN_METAL_WALL); // 2.1%
+
+ if (one_chance_in(250))
+ wall_type_room = DNGN_GREEN_CRYSTAL_WALL;
+
+ box_room(x1, x2, y1, y2, wall_type_room);
+
+ // inner room - neat.
+ if (x2 - x1 > 5 && y2 - y1 > 5 && one_chance_in(8))
+ {
+ box_room(x1 + 2, x2 - 2, y1 + 2, y2 - 2, wall_type);
+
+ // treasure area.. neat.
+ if (one_chance_in(3))
+ treasure_area(level_number, x1 + 3, x2 - 3, y1 + 3, y2 - 3);
+ }
+ }
+ }
+ }
+
+ int stair_count = coinflip() ? 2 : 1;
+
+ for (j = 0; j < stair_count; j++)
+ {
+ for (i = 0; i < 2; i++)
+ {
+ place_specific_stair( j + ((i==0) ? DNGN_STONE_STAIRS_DOWN_I
+ : DNGN_STONE_STAIRS_UP_I) );
+ }
+ }
+
+} // end city_level()
+
+static bool treasure_area(int level_number, unsigned char ta1_x,
+ unsigned char ta2_x, unsigned char ta1_y,
+ unsigned char ta2_y)
+{
+ int x_count = 0;
+ int y_count = 0;
+ int item_made = 0;
+
+ ta2_x++;
+ ta2_y++;
+
+ if (ta2_x <= ta1_x || ta2_y <= ta1_y)
+ return false;
+
+ if ((ta2_x - ta1_x) * (ta2_y - ta1_y) >= 40)
+ return false;
+
+ for (x_count = ta1_x; x_count < ta2_x; x_count++)
+ {
+ for (y_count = ta1_y; y_count < ta2_y; y_count++)
+ {
+ if (grd[x_count][y_count] != DNGN_FLOOR || coinflip())
+ continue;
+
+ item_made = items( 1, OBJ_RANDOM, OBJ_RANDOM, true,
+ random2( level_number * 2 ), 250 );
+
+ if (item_made != NON_ITEM)
+ {
+ mitm[item_made].x = x_count;
+ mitm[item_made].y = y_count;
+ }
+ }
+ }
+
+ return true;
+} // end treasure_area()
+
+static void diamond_rooms(int level_number)
+{
+ char numb_diam = 1 + random2(10);
+ char type_floor = DNGN_DEEP_WATER;
+ int runthru = 0;
+ int i, oblique_max;
+
+ // I guess no diamond rooms in either of these places {dlb}:
+ if (player_in_branch( BRANCH_DIS ) || player_in_branch( BRANCH_TARTARUS ))
+ return;
+
+ if (level_number > 5 + random2(5) && coinflip())
+ type_floor = DNGN_SHALLOW_WATER;
+
+ if (level_number > 10 + random2(5) && coinflip())
+ type_floor = DNGN_DEEP_WATER;
+
+ if (level_number > 17 && coinflip())
+ type_floor = DNGN_LAVA;
+
+ if (level_number > 10 && one_chance_in(15))
+ type_floor = (coinflip()? DNGN_STONE_WALL : DNGN_ROCK_WALL);
+
+ if (level_number > 12 && one_chance_in(20))
+ type_floor = DNGN_METAL_WALL;
+
+ if (player_in_branch( BRANCH_GEHENNA ))
+ type_floor = DNGN_LAVA;
+ else if (player_in_branch( BRANCH_COCYTUS ))
+ type_floor = DNGN_DEEP_WATER;
+
+ for (i = 0; i < numb_diam; i++)
+ {
+ spec_room sr = { false, false, 0, 0, 0, 0 };
+
+ sr.x1 = 8 + random2(43);
+ sr.y1 = 8 + random2(35);
+ sr.x2 = sr.x1 + 5 + random2(15);
+ sr.y2 = sr.y1 + 5 + random2(10);
+
+ oblique_max = (sr.x2 - sr.x1) / 2; //random2(20) + 5;
+
+ if (!octa_room(sr, oblique_max, type_floor))
+ {
+ runthru++;
+ if (runthru > 9)
+ {
+ runthru = 0;
+ }
+ else
+ {
+ i--;
+ continue;
+ }
+ }
+ } // end "for(bk...)"
+} // end diamond_rooms()
+
+static void big_room(int level_number)
+{
+ unsigned char type_floor = DNGN_FLOOR;
+ unsigned char type_2 = DNGN_FLOOR;
+ int i, j, k, l;
+
+ spec_room sr = { false, false, 0, 0, 0, 0 };
+ int oblique;
+
+ if (one_chance_in(4))
+ {
+ oblique = 5 + random2(20);
+
+ sr.x1 = 8 + random2(30);
+ sr.y1 = 8 + random2(22);
+ sr.x2 = sr.x1 + 20 + random2(10);
+ sr.y2 = sr.y1 + 20 + random2(8);
+
+ // usually floor, except at higher levels
+ if (!one_chance_in(5) || level_number < 8 + random2(8))
+ {
+ octa_room(sr, oblique, DNGN_FLOOR);
+ return;
+ }
+
+ // default is lava.
+ type_floor = DNGN_LAVA;
+
+ if (level_number > 7)
+ {
+ type_floor = ((random2(level_number) < 14) ? DNGN_DEEP_WATER
+ : DNGN_LAVA);
+ }
+
+ octa_room(sr, oblique, type_floor);
+ }
+
+ // what now?
+ sr.x1 = 8 + random2(30);
+ sr.y1 = 8 + random2(22);
+ sr.x2 = sr.x1 + 20 + random2(10);
+ sr.y2 = sr.y1 + 20 + random2(8);
+
+ // check for previous special
+ if (find_in_area(sr.x1, sr.y1, sr.x2, sr.y2, DNGN_BUILDER_SPECIAL_WALL))
+ return;
+
+ if (level_number > 7 && one_chance_in(4))
+ {
+ type_floor = ((random2(level_number) < 14) ? DNGN_DEEP_WATER
+ : DNGN_LAVA);
+ }
+
+ // make the big room.
+ replace_area(sr.x1, sr.y1, sr.x2, sr.y2, DNGN_ROCK_WALL, type_floor);
+ replace_area(sr.x1, sr.y1, sr.x2, sr.y2, DNGN_CLOSED_DOOR, type_floor);
+
+ if (type_floor == DNGN_FLOOR)
+ type_2 = DNGN_ROCK_WALL + random2(4);
+
+ // no lava in the Crypt or Tomb, thanks!
+ if (player_in_branch( BRANCH_CRYPT ) || player_in_branch( BRANCH_TOMB ))
+ {
+ if (type_floor == DNGN_LAVA)
+ type_floor = DNGN_SHALLOW_WATER;
+
+ if (type_2 == DNGN_LAVA)
+ type_2 = DNGN_SHALLOW_WATER;
+ }
+
+ // sometimes make it a chequerboard
+ if (one_chance_in(4))
+ {
+ chequerboard( sr, type_floor, type_floor, type_2 );
+ }
+ // sometimes make an inside room w/ stone wall.
+ else if (one_chance_in(6))
+ {
+ i = sr.x1;
+ j = sr.y1;
+ k = sr.x2;
+ l = sr.y2;
+
+ do
+ {
+ i += 2 + random2(3);
+ j += 2 + random2(3);
+ k -= 2 + random2(3);
+ l -= 2 + random2(3);
+ // check for too small
+ if (i >= k - 3)
+ break;
+ if (j >= l - 3)
+ break;
+
+ box_room(i, k, j, l, DNGN_STONE_WALL);
+
+ }
+ while (level_number < 1500); // ie forever
+ }
+} // end big_room()
+
+// helper function for chequerboard rooms
+// note that box boundaries are INclusive
+static void chequerboard( spec_room &sr, unsigned char target,
+ unsigned char floor1, unsigned char floor2 )
+{
+ int i, j;
+
+ if (sr.x2 < sr.x1 || sr.y2 < sr.y1)
+ return;
+
+ for (i = sr.x1; i <= sr.x2; i++)
+ {
+ for (j = sr.y1; j <= sr.y2; j++)
+ {
+ if (grd[i][j] == target)
+ grd[i][j] = (((i + j) % 2) ? floor2 : floor1);
+ }
+ }
+} // end chequerboard()
+
+static void roguey_level(int level_number, spec_room &sr)
+{
+ int bcount_x, bcount_y;
+ int cn = 0;
+ int i;
+
+ FixedVector < unsigned char, 30 > rox1;
+ FixedVector < unsigned char, 30 > rox2;
+ FixedVector < unsigned char, 30 > roy1;
+ FixedVector < unsigned char, 30 > roy2;
+
+ for (bcount_y = 0; bcount_y < 5; bcount_y++)
+ {
+ for (bcount_x = 0; bcount_x < 5; bcount_x++)
+ {
+ // rooms:
+ rox1[cn] = bcount_x * 13 + 8 + random2(4);
+ roy1[cn] = bcount_y * 11 + 8 + random2(4);
+
+ rox2[cn] = rox1[cn] + 3 + random2(8);
+ roy2[cn] = roy1[cn] + 3 + random2(6);
+
+ // bounds
+ if (rox2[cn] > GXM-8)
+ rox2[cn] = GXM-8;
+
+ cn++;
+ }
+ }
+
+ cn = 0;
+
+ for (i = 0; i < 25; i++)
+ {
+ replace_area( rox1[i], roy1[i], rox2[i], roy2[i],
+ DNGN_ROCK_WALL, DNGN_FLOOR );
+
+ // inner room?
+ if (rox2[i] - rox1[i] > 5 && roy2[i] - roy1[i] > 5)
+ {
+ if (random2(100 - level_number) < 3)
+ {
+ if (!one_chance_in(4))
+ {
+ box_room( rox1[i] + 2, rox2[i] - 2, roy1[i] + 2,
+ roy2[i] - 2, (coinflip() ? DNGN_STONE_WALL
+ : DNGN_ROCK_WALL) );
+ }
+ else
+ {
+ box_room( rox1[i] + 2, rox2[i] - 2, roy1[i] + 2,
+ roy2[i] - 2, DNGN_METAL_WALL );
+ }
+
+ if (coinflip())
+ {
+ treasure_area( level_number, rox1[i] + 3, rox2[i] - 3,
+ roy1[i] + 3, roy2[i] - 3 );
+ }
+ }
+ }
+ } // end "for i"
+
+ // Now, join them together:
+ FixedVector < char, 2 > pos;
+ FixedVector < char, 2 > jpos;
+
+ char doing = 0;
+
+ char last_room = 0;
+ int bp;
+
+ for (bp = 0; bp < 2; bp++)
+ {
+ for (i = 0; i < 25; i++)
+ {
+ if (bp == 0 && (!(i % 5) || i == 0))
+ continue;
+
+ if (bp == 1 && i < 5)
+ continue;
+
+ switch (bp)
+ {
+ case 0:
+ last_room = i - 1;
+ pos[0] = rox1[i]; // - 1;
+ pos[1] = roy1[i] + random2(roy2[i] - roy1[i]);
+ jpos[0] = rox2[last_room]; // + 1;
+ jpos[1] = roy1[last_room]
+ + random2(roy2[last_room] - roy1[last_room]);
+ break;
+
+ case 1:
+ last_room = i - 5;
+ pos[1] = roy1[i]; // - 1;
+ pos[0] = rox1[i] + random2(rox2[i] - rox1[i]);
+ jpos[1] = roy2[last_room]; // + 1;
+ jpos[0] = rox1[last_room]
+ + random2(rox2[last_room] - rox1[last_room]);
+ break;
+ }
+
+ while (pos[0] != jpos[0] || pos[1] != jpos[1])
+ {
+ doing = (coinflip()? 1 : 0);
+
+ if (pos[doing] < jpos[doing])
+ pos[doing]++;
+ else if (pos[doing] > jpos[doing])
+ pos[doing]--;
+
+ if (grd[pos[0]][pos[1]] == DNGN_ROCK_WALL)
+ grd[pos[0]][pos[1]] = DNGN_FLOOR;
+ }
+
+ if (grd[pos[0]][pos[1]] == DNGN_FLOOR)
+ {
+ if ((grd[pos[0] + 1][pos[1]] == DNGN_ROCK_WALL
+ && grd[pos[0] - 1][pos[1]] == DNGN_ROCK_WALL)
+ || (grd[pos[0]][pos[1] + 1] == DNGN_ROCK_WALL
+ && grd[pos[0]][pos[1] - 1] == DNGN_ROCK_WALL))
+ {
+ grd[pos[0]][pos[1]] = 103;
+ }
+ }
+ } // end "for bp, for i"
+ }
+
+ // is one of them a special room?
+ if (level_number > 8 && one_chance_in(10))
+ {
+ int spec_room_done = random2(25);
+
+ sr.created = true;
+ sr.hooked_up = true;
+ sr.x1 = rox1[spec_room_done];
+ sr.x2 = rox2[spec_room_done];
+ sr.y1 = roy1[spec_room_done];
+ sr.y2 = roy2[spec_room_done];
+ special_room( level_number, sr );
+
+ // make the room 'special' so it doesn't get overwritten
+ // by something else (or put monsters in walls, etc..).
+
+ // top
+ replace_area(sr.x1-1, sr.y1-1, sr.x2+1,sr.y1-1, DNGN_ROCK_WALL, DNGN_BUILDER_SPECIAL_WALL);
+ replace_area(sr.x1-1, sr.y1-1, sr.x2+1,sr.y1-1, DNGN_FLOOR, DNGN_BUILDER_SPECIAL_FLOOR);
+ replace_area(sr.x1-1, sr.y1-1, sr.x2+1,sr.y1-1, DNGN_CLOSED_DOOR, DNGN_BUILDER_SPECIAL_FLOOR);
+
+ // bottom
+ replace_area(sr.x1-1, sr.y2+1, sr.x2+1,sr.y2+1, DNGN_ROCK_WALL, DNGN_BUILDER_SPECIAL_WALL);
+ replace_area(sr.x1-1, sr.y2+1, sr.x2+1,sr.y2+1, DNGN_FLOOR, DNGN_BUILDER_SPECIAL_FLOOR);
+ replace_area(sr.x1-1, sr.y2+1, sr.x2+1,sr.y2+1, DNGN_CLOSED_DOOR, DNGN_BUILDER_SPECIAL_FLOOR);
+
+ // left
+ replace_area(sr.x1-1, sr.y1-1, sr.x1-1, sr.y2+1, DNGN_ROCK_WALL, DNGN_BUILDER_SPECIAL_WALL);
+ replace_area(sr.x1-1, sr.y1-1, sr.x1-1, sr.y2+1, DNGN_FLOOR, DNGN_BUILDER_SPECIAL_FLOOR);
+ replace_area(sr.x1-1, sr.y1-1, sr.x1-1, sr.y2+1, DNGN_CLOSED_DOOR, DNGN_BUILDER_SPECIAL_FLOOR);
+
+ // right
+ replace_area(sr.x2+1, sr.y1-1, sr.x2+1, sr.y2+1, DNGN_ROCK_WALL, DNGN_BUILDER_SPECIAL_WALL);
+ replace_area(sr.x2+1, sr.y1-1, sr.x2+1, sr.y2+1, DNGN_FLOOR, DNGN_BUILDER_SPECIAL_FLOOR);
+ replace_area(sr.x2+1, sr.y1-1, sr.x2+1, sr.y2+1, DNGN_CLOSED_DOOR, DNGN_BUILDER_SPECIAL_FLOOR);
+ }
+
+ int stair_count = coinflip() ? 2 : 1;
+
+ for (int j = 0; j < stair_count; j++)
+ {
+ for (i = 0; i < 2; i++)
+ {
+ place_specific_stair(j + ((i==0) ? DNGN_STONE_STAIRS_DOWN_I
+ : DNGN_STONE_STAIRS_UP_I));
+ }
+ }
+} // end roguey_level()
+
+static void morgue(spec_room &sr)
+{
+ int temp_rand = 0; // probability determination {dlb}
+ int x,y;
+
+ for (x = sr.x1; x <= sr.x2; x++)
+ {
+ for (y = sr.y1; y <= sr.y2; y++)
+ {
+ if (grd[x][y] == DNGN_FLOOR || grd[x][y] == DNGN_BUILDER_SPECIAL_FLOOR)
+ {
+ int mon_type;
+ temp_rand = random2(24);
+
+ mon_type = ((temp_rand > 11) ? MONS_ZOMBIE_SMALL : // 50.0%
+ (temp_rand > 7) ? MONS_WIGHT : // 16.7%
+ (temp_rand > 3) ? MONS_NECROPHAGE : // 16.7%
+ (temp_rand > 0) ? MONS_WRAITH // 12.5%
+ : MONS_VAMPIRE); // 4.2%
+
+ mons_place( mon_type, BEH_SLEEP, MHITNOT, true, x, y );
+ }
+ }
+ }
+} // end morgue()
+
+static bool place_specific_trap(unsigned char spec_x, unsigned char spec_y,
+ unsigned char spec_type)
+{
+ if (spec_type == TRAP_RANDOM)
+ spec_type = random2(NUM_TRAPS);
+
+ for (int tcount = 0; tcount < MAX_TRAPS; tcount++)
+ {
+ if (env.trap[tcount].type == TRAP_UNASSIGNED)
+ {
+ env.trap[tcount].type = spec_type;
+ env.trap[tcount].x = spec_x;
+ env.trap[tcount].y = spec_y;
+ grd[spec_x][spec_y] = DNGN_UNDISCOVERED_TRAP;
+ return true;
+ }
+
+ if (tcount >= MAX_TRAPS - 1)
+ return false;
+ }
+
+ return false;
+} // end place_specific_trap()
+
+void define_zombie( int mid, int ztype, int cs, int power )
+{
+ int mons_sec2 = 0;
+ int zombie_size = 0;
+ bool ignore_rarity = false;
+ int test, cls;
+
+ if (power > 27)
+ power = 27;
+
+ // set size based on zombie class (cs)
+ switch(cs)
+ {
+ case MONS_ZOMBIE_SMALL:
+ case MONS_SIMULACRUM_SMALL:
+ case MONS_SKELETON_SMALL:
+ zombie_size = 1;
+ break;
+
+ case MONS_ZOMBIE_LARGE:
+ case MONS_SIMULACRUM_LARGE:
+ case MONS_SKELETON_LARGE:
+ zombie_size = 2;
+ break;
+
+ case MONS_SPECTRAL_THING:
+ zombie_size = -1;
+ break;
+
+ default:
+ // this should NEVER happen.
+ perror("\ncreate_zombie() got passed incorrect zombie type!\n");
+ end(0);
+ break;
+ }
+
+ // that is, random creature from which to fashion undead
+ if (ztype == 250)
+ {
+ // how OOD this zombie can be.
+ int relax = 5;
+
+ // pick an appropriate creature to make a zombie out of,
+ // levelwise. The old code was generating absolutely
+ // incredible OOD zombies.
+ while(true)
+ {
+ // this limit can be updated if mons->number goes >8 bits..
+ test = random2(182); // not guaranteed to be valid, so..
+ cls = mons_charclass(test);
+ if (cls == MONS_PROGRAM_BUG)
+ continue;
+
+ // on certain branches, zombie creation will fail if we use
+ // the mons_rarity() functions, because (for example) there
+ // are NO zombifiable "native" abyss creatures. Other branches
+ // where this is a problem are hell levels and the crypt.
+ // we have to watch for summoned zombies on other levels, too,
+ // such as the Temple, HoB, and Slime Pits.
+ if (you.level_type != LEVEL_DUNGEON
+ || player_in_hell()
+ || player_in_branch( BRANCH_HALL_OF_ZOT )
+ || player_in_branch( BRANCH_VESTIBULE_OF_HELL )
+ || player_in_branch( BRANCH_ECUMENICAL_TEMPLE )
+ || player_in_branch( BRANCH_CRYPT )
+ || player_in_branch( BRANCH_TOMB )
+ || player_in_branch( BRANCH_HALL_OF_BLADES )
+ || player_in_branch( BRANCH_SNAKE_PIT )
+ || player_in_branch( BRANCH_SLIME_PITS )
+ || one_chance_in(1000))
+ {
+ ignore_rarity = true;
+ }
+
+ // don't make out-of-rarity zombies when we don't have to
+ if (!ignore_rarity && mons_rarity(cls) == 0)
+ continue;
+
+ // monster class must be zombifiable
+ if (!mons_zombie_size(cls))
+ continue;
+
+ // if skeleton, monster must have a skeleton
+ if ((cs == MONS_SKELETON_SMALL || cs == MONS_SKELETON_LARGE)
+ && !mons_skeleton(cls))
+ {
+ continue;
+ }
+
+ // size must match, but you can make a spectral thing out of anything.
+ if (mons_zombie_size(cls) != zombie_size && zombie_size >= 0)
+ continue;
+
+ // hack -- non-dungeon zombies are always made out of nastier
+ // monsters
+ if (you.level_type != LEVEL_DUNGEON && mons_power(cls) > 8)
+ break;
+
+ // check for rarity.. and OOD - identical to mons_place()
+ int level, diff, chance;
+
+ level = mons_level( cls ) - 4;
+ diff = level - power;
+
+ chance = (ignore_rarity) ? 100
+ : mons_rarity(cls) - (diff * diff) / 2;
+
+ if (power > level - relax && power < level + relax
+ && random2avg(100, 2) <= chance)
+ {
+ break;
+ }
+
+ // every so often, we'll relax the OOD restrictions. Avoids
+ // infinite loops (if we don't do this, things like creating
+ // a large skeleton on level 1 may hang the game!
+ if (one_chance_in(5))
+ relax++;
+ }
+
+ // set type and secondary appropriately
+ menv[mid].number = cls;
+ mons_sec2 = cls;
+ }
+ else
+ {
+ menv[mid].number = mons_charclass(ztype);
+ mons_sec2 = menv[mid].number;
+ }
+
+ menv[mid].type = menv[mid].number;
+
+ define_monster(mid);
+
+ menv[mid].hit_points = hit_points( menv[mid].hit_dice, 6, 5 );
+ menv[mid].max_hit_points = menv[mid].hit_points;
+
+ menv[mid].armour_class -= 2;
+
+ if (menv[mid].armour_class < 0)
+ menv[mid].armour_class = 0;
+
+ menv[mid].evasion -= 5;
+
+ if (menv[mid].evasion < 0)
+ menv[mid].evasion = 0;
+
+ menv[mid].speed -= 2;
+
+ if (menv[mid].speed < 3)
+ menv[mid].speed = 3;
+
+ menv[mid].speed_increment = 70;
+ menv[mid].number = mons_sec2;
+
+ if (cs == MONS_ZOMBIE_SMALL || cs == MONS_ZOMBIE_LARGE)
+ {
+ menv[mid].type = ((mons_zombie_size(menv[mid].number) == 2)
+ ? MONS_ZOMBIE_LARGE : MONS_ZOMBIE_SMALL);
+ }
+ else if (cs == MONS_SKELETON_SMALL || cs == MONS_SKELETON_LARGE)
+ {
+ menv[mid].hit_points = hit_points( menv[mid].hit_dice, 5, 4 );
+ menv[mid].max_hit_points = menv[mid].hit_points;
+
+ menv[mid].armour_class -= 4;
+
+ if (menv[mid].armour_class < 0)
+ menv[mid].armour_class = 0;
+
+ menv[mid].evasion -= 2;
+
+ if (menv[mid].evasion < 0)
+ menv[mid].evasion = 0;
+
+ menv[mid].type = ((mons_zombie_size( menv[mid].number ) == 2)
+ ? MONS_SKELETON_LARGE : MONS_SKELETON_SMALL);
+ }
+ else if (cs == MONS_SIMULACRUM_SMALL || cs == MONS_SIMULACRUM_LARGE)
+ {
+ // Simulacrum aren't tough, but you can create piles of them. -- bwr
+ menv[mid].hit_points = hit_points( menv[mid].hit_dice, 1, 4 );
+ menv[mid].max_hit_points = menv[mid].hit_points;
+ menv[mid].type = ((mons_zombie_size( menv[mid].number ) == 2)
+ ? MONS_SIMULACRUM_LARGE : MONS_SIMULACRUM_SMALL);
+ }
+ else if (cs == MONS_SPECTRAL_THING)
+ {
+ menv[mid].hit_points = hit_points( menv[mid].hit_dice, 4, 4 );
+ menv[mid].max_hit_points = menv[mid].hit_points;
+ menv[mid].armour_class += 4;
+ menv[mid].type = MONS_SPECTRAL_THING;
+ }
+
+ menv[mid].number = mons_sec2;
+} // end define_zombie()
+
+#ifdef USE_RIVERS
+
+static void build_river( unsigned char river_type ) //mv
+{
+ int i,j;
+ int y, width;
+
+ if (player_in_branch( BRANCH_CRYPT ) || player_in_branch( BRANCH_TOMB ))
+ return;
+
+ // if (one_chance_in(10))
+ // build_river(river_type);
+
+ // Made rivers less wide... min width five rivers were too annoying. -- bwr
+ width = 3 + random2(4);
+ y = 10 - width + random2avg( GYM-10, 3 );
+
+ for (i = 5; i < (GXM - 5); i++)
+ {
+ if (one_chance_in(3)) y++;
+ if (one_chance_in(3)) y--;
+ if (coinflip()) width++;
+ if (coinflip()) width--;
+
+ if (width < 2) width = 2;
+ if (width > 6) width = 6;
+
+ for (j = y; j < y+width ; j++)
+ {
+ if (j >= 5 && j <= GYM - 5)
+ {
+ // Note that vaults might have been created in this area!
+ // So we'll avoid the silliness of orcs/royal jelly on
+ // lava and deep water grids. -- bwr
+ if (!one_chance_in(200)
+ // && grd[i][j] == DNGN_FLOOR
+ && mgrd[i][j] == NON_MONSTER
+ && igrd[i][j] == NON_ITEM)
+ {
+ if (width == 2 && river_type == DNGN_DEEP_WATER
+ && coinflip())
+ {
+ grd[i][j] = DNGN_SHALLOW_WATER;
+ }
+ else
+ grd[i][j] = river_type;
+ }
+ }
+ }
+ }
+} // end build_river()
+
+static void build_lake(unsigned char lake_type) //mv
+{
+ int i, j;
+ int x1, y1, x2, y2;
+
+ if (player_in_branch( BRANCH_CRYPT ) || player_in_branch( BRANCH_TOMB ))
+ return;
+
+ // if (one_chance_in (10))
+ // build_lake(lake_type);
+
+ x1 = 5 + random2(GXM - 30);
+ y1 = 5 + random2(GYM - 30);
+ x2 = x1 + 4 + random2(16);
+ y2 = y1 + 8 + random2(12);
+ // mpr("lake");
+
+ for (j = y1; j < y2; j++)
+ {
+ if (coinflip()) x1 += random2(3);
+ if (coinflip()) x1 -= random2(3);
+ if (coinflip()) x2 += random2(3);
+ if (coinflip()) x2 -= random2(3);
+
+ // mv: this does much more worse effects
+ // if (coinflip()) x1 = x1 -2 + random2(5);
+ // if (coinflip()) x2 = x2 -2 + random2(5);
+
+ if ((j-y1) < ((y2-y1) / 2))
+ {
+ x2 += random2(3);
+ x1 -= random2(3);
+ }
+ else
+ {
+ x2 -= random2(3);
+ x1 += random2(3);
+ }
+
+ for (i = x1; i < x2 ; i++)
+ {
+ if ((j >= 5 && j <= GYM - 5) && (i >= 5 && i <= GXM - 5))
+ {
+ // Note that vaults might have been created in this area!
+ // So we'll avoid the silliness of monsters and items
+ // on lava and deep water grids. -- bwr
+ if (!one_chance_in(200)
+ // && grd[i][j] == DNGN_FLOOR
+ && mgrd[i][j] == NON_MONSTER
+ && igrd[i][j] == NON_ITEM)
+ {
+ grd[i][j] = lake_type;
+ }
+ }
+ }
+ }
+} // end lake()
+
+#endif // USE_RIVERS
diff --git a/trunk/source/dungeon.h b/trunk/source/dungeon.h
new file mode 100644
index 0000000000..dedd41ae68
--- /dev/null
+++ b/trunk/source/dungeon.h
@@ -0,0 +1,49 @@
+/*
+ * File: dungeon.cc
+ * Summary: Functions used when building new levels.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef DUNGEON_H
+#define DUNGEON_H
+
+#include "FixVec.h"
+#include "externs.h"
+
+#define MAKE_GOOD_ITEM 351
+
+void item_colour( item_def &item );
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: files
+ * *********************************************************************** */
+void builder(int level_number, char level_type);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: abyss - debug - dungeon - effects - religion - spells4
+ * *********************************************************************** */
+int items( int allow_uniques, int force_class, int force_type,
+ bool dont_place, int item_level, int item_race );
+
+// last updated 13mar2001 {gdl}
+/* ***********************************************************************
+ * called from: dungeon monplace
+ * *********************************************************************** */
+void give_item(int mid, int level_number);
+
+
+// last updated 13mar2001 {gdl}
+/* ***********************************************************************
+ * called from: dungeon monplace
+ * *********************************************************************** */
+void define_zombie(int mid, int ztype, int cs, int power);
+
+#endif
diff --git a/trunk/source/effects.cc b/trunk/source/effects.cc
new file mode 100644
index 0000000000..c2645e1b73
--- /dev/null
+++ b/trunk/source/effects.cc
@@ -0,0 +1,1374 @@
+/*
+ * File: effects.cc
+ * Summary: Misc stuff.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "effects.h"
+
+#include <string.h>
+#include <stdio.h>
+
+#include "externs.h"
+
+#include "beam.h"
+#include "direct.h"
+#include "dungeon.h"
+#include "itemname.h"
+#include "items.h"
+#include "misc.h"
+#include "monplace.h"
+#include "monstuff.h"
+#include "mon-util.h"
+#include "mutation.h"
+#include "newgame.h"
+#include "ouch.h"
+#include "player.h"
+#include "randart.h"
+#include "skills2.h"
+#include "spells3.h"
+#include "spells4.h"
+#include "spl-book.h"
+#include "spl-util.h"
+#include "stuff.h"
+#include "view.h"
+#include "wpn-misc.h"
+
+// torment_monsters is called with power 0 because torment is
+// UNRESISTABLE except for being undead or having torment
+// resistance! Even if we used maximum power of 1000, high
+// level monsters and characters would save too often. (GDL)
+
+static int torment_monsters(int x, int y, int pow, int garbage)
+{
+ UNUSED( pow );
+ UNUSED( garbage );
+
+ // is player?
+ if (x == you.x_pos && y == you.y_pos)
+ {
+ if (you.is_undead || you.mutation[MUT_TORMENT_RESISTANCE])
+ mpr("You feel a surge of unholy energy.");
+ else
+ {
+ mpr("Your body is wracked with pain!");
+ dec_hp((you.hp / 2) - 1, false);
+ }
+
+ return 1;
+ }
+
+ // check for monster in cell
+ int mon = mgrd[x][y];
+
+ if (mon == NON_MONSTER)
+ return 0;
+
+ struct monsters *monster = &menv[mon];
+
+ if (monster->type == -1)
+ return 0;
+
+ if (mons_res_negative_energy( monster ) >= 3)
+ return 0;
+
+ monster->hit_points = 1 + (monster->hit_points / 2);
+ simple_monster_message(monster, " convulses!");
+
+ return 1;
+}
+
+void torment(int tx, int ty)
+{
+ apply_area_within_radius(torment_monsters, tx, ty, 0, 8, 0);
+} // end torment()
+
+void banished(unsigned char gate_type)
+{
+ you_teleport2( false );
+
+ // this is to ensure that you're standing on a suitable space (67)
+ grd[you.x_pos][you.y_pos] = gate_type;
+
+ down_stairs(true, you.your_level); // heh heh
+ untag_followers(); // safety
+} // end banished()
+
+bool forget_spell(void)
+{
+ if (!you.spell_no)
+ return (false);
+
+ // find a random spell to forget:
+ int slot = -1;
+ int num = 0;
+
+ for (int i = 0; i < 25; i++)
+ {
+ if (you.spells[i] != SPELL_NO_SPELL)
+ {
+ num++;
+ if (one_chance_in( num ))
+ slot = i;
+ }
+ }
+
+ if (slot == -1) // should never happen though
+ return (false);
+
+ del_spell_from_memory_by_slot( slot );
+
+ return (true);
+} // end forget_spell()
+
+// use player::decrease_stats() instead iff:
+// (a) player_sust_abil() should not factor in; and
+// (b) there is no floor to the final stat values {dlb}
+bool lose_stat(unsigned char which_stat, unsigned char stat_loss, bool force)
+{
+ bool statLowered = false; // must initialize to false {dlb}
+ char *ptr_stat = 0; // NULL {dlb}
+ char *ptr_redraw = 0; // NULL {dlb}
+ char newValue = 0; // holds new value, for comparison to old {dlb}
+
+ // begin outputing message: {dlb}
+ strcpy(info, "You feel ");
+
+ // set pointers to appropriate variables: {dlb}
+ if (which_stat == STAT_RANDOM)
+ which_stat = random2(NUM_STATS);
+
+ switch (which_stat)
+ {
+ case STAT_STRENGTH:
+ strcat(info, "weakened");
+ ptr_stat = &you.strength;
+ ptr_redraw = &you.redraw_strength;
+ break;
+
+ case STAT_DEXTERITY:
+ strcat(info, "clumsy");
+ ptr_stat = &you.dex;
+ ptr_redraw = &you.redraw_dexterity;
+ break;
+
+ case STAT_INTELLIGENCE:
+ strcat(info, "dopey");
+ ptr_stat = &you.intel;
+ ptr_redraw = &you.redraw_intelligence;
+ break;
+ }
+
+ // scale modifier by player_sust_abil() - right-shift
+ // permissible because stat_loss is unsigned: {dlb}
+ if (!force)
+ stat_loss >>= player_sust_abil();
+
+ // newValue is current value less modifier: {dlb}
+ newValue = *ptr_stat - stat_loss;
+
+ // XXX: Death by stat loss is currently handled in the redraw code. -- bwr
+ if (newValue < 0)
+ newValue = 0;
+
+ // conceivable that stat was already *at* three
+ // or stat_loss zeroed by player_sust_abil(): {dlb}
+ //
+ // Actually, that code was somewhat flawed. Several race-class combos
+ // can start with a stat lower than three, and this block (which
+ // used to say '!=' would actually cause stat gain with the '< 3'
+ // check that used to be above. Crawl has stat-death code and I
+ // don't see why we shouldn't be using it here. -- bwr
+ if (newValue < *ptr_stat)
+ {
+ *ptr_stat = newValue;
+ *ptr_redraw = 1;
+
+ // handle burden change, where appropriate: {dlb}
+ if (ptr_stat == &you.strength)
+ burden_change();
+
+ statLowered = true; // that is, stat was lowered (not just changed)
+ }
+
+ // a warning to player that s/he cut it close: {dlb}
+ if (!statLowered)
+ strcat(info, " for a moment");
+
+ // finish outputting message: {dlb}
+ strcat(info, ".");
+ mpr(info);
+
+ return (statLowered);
+} // end lose_stat()
+
+void direct_effect(struct bolt &pbolt)
+{
+ int damage_taken = 0;
+
+ switch (pbolt.type)
+ {
+ case DMNBM_HELLFIRE:
+ mpr( "You are engulfed in a burst of hellfire!" );
+ strcpy( pbolt.beam_name, "hellfire" );
+ pbolt.ex_size = 1;
+ pbolt.flavour = BEAM_EXPLOSION;
+ pbolt.type = SYM_ZAP;
+ pbolt.colour = RED;
+ pbolt.thrower = KILL_MON_MISSILE;
+ pbolt.aux_source = NULL;
+ pbolt.isBeam = false;
+ pbolt.isTracer = false;
+ pbolt.hit = 20;
+ pbolt.damage = dice_def( 3, 20 );
+ pbolt.aux_source = "burst of hellfire";
+ explosion( pbolt );
+ break;
+
+ case DMNBM_SMITING:
+ mpr( "Something smites you!" );
+ strcpy( pbolt.beam_name, "smiting" ); // for ouch
+ pbolt.aux_source = "by divine providence";
+ damage_taken = 7 + random2avg(11, 2);
+ break;
+
+ case DMNBM_BRAIN_FEED:
+ // lose_stat() must come last {dlb}
+ if (one_chance_in(3) && lose_stat(STAT_INTELLIGENCE, 1))
+ mpr("Something feeds on your intellect!");
+ else
+ mpr("Something tries to feed on your intellect!");
+ break;
+
+ case DMNBM_MUTATION:
+ mpr("Strange energies course through your body.");
+ if (one_chance_in(5))
+ mutate(100);
+ else
+ give_bad_mutation();
+ break;
+ }
+
+ // apply damage and handle death, where appropriate {dlb}
+ if (damage_taken > 0)
+ ouch(damage_taken, pbolt.beam_source, KILLED_BY_BEAM, pbolt.aux_source);
+
+ return;
+} // end direct_effect()
+
+// monster-to-monster
+void mons_direct_effect(struct bolt &pbolt, int i)
+{
+ // note the translation here - important {dlb}
+ int o = menv[i].foe;
+ struct monsters *monster = &menv[o];
+ int damage_taken = 0;
+
+ // annoy the target
+ behaviour_event(monster, ME_ANNOY, i);
+
+ switch (pbolt.type)
+ {
+ case DMNBM_HELLFIRE:
+ simple_monster_message(monster, " is engulfed in hellfire.");
+ strcpy(pbolt.beam_name, "hellfire");
+ pbolt.flavour = BEAM_LAVA;
+
+ damage_taken = 5 + random2(10) + random2(5);
+ damage_taken = mons_adjust_flavoured(monster, pbolt, damage_taken);
+ break;
+
+ case DMNBM_SMITING:
+ simple_monster_message(monster, " is smitten.");
+ strcpy(pbolt.beam_name, "smiting");
+ pbolt.flavour = BEAM_MISSILE;
+
+ damage_taken += 7 + random2avg(11, 2);
+ break;
+
+ case DMNBM_BRAIN_FEED: // not implemented here (nor, probably, can be)
+ break;
+
+ case DMNBM_MUTATION:
+ if (mons_holiness( monster->type ) != MH_NATURAL)
+ simple_monster_message(monster, " is unaffected.");
+ else if (check_mons_resist_magic( monster, pbolt.ench_power ))
+ simple_monster_message(monster, " resists.");
+ else
+ monster_polymorph(monster, RANDOM_MONSTER, 100);
+ break;
+ }
+
+ // apply damage and handle death, where appropriate {dlb}
+ if (damage_taken > 0)
+ {
+ hurt_monster(monster, damage_taken);
+
+ if (monster->hit_points < 1)
+ monster_die(monster, KILL_MON_MISSILE, i);
+ }
+
+ return;
+} // end mons_direct_effect()
+
+void random_uselessness(unsigned char ru, unsigned char sc_read_2)
+{
+ char wc[30];
+ int temp_rand = 0; // probability determination {dlb}
+
+ switch (ru)
+ {
+ case 0:
+ strcpy(info, "The dust glows a ");
+ weird_colours(random2(256), wc);
+ strcat(info, wc);
+ strcat(info, " colour!");
+ mpr(info);
+ break;
+
+ case 1:
+ mpr("The scroll reassembles itself in your hand!");
+ inc_inv_item_quantity( sc_read_2, 1 );
+ break;
+
+ case 2:
+ if (you.equip[EQ_WEAPON] != -1)
+ {
+ char str_pass[ ITEMNAME_SIZE ];
+ in_name(you.equip[EQ_WEAPON], DESC_CAP_YOUR, str_pass);
+ strcpy(info, str_pass);
+ strcat(info, " glows ");
+ weird_colours(random2(256), wc);
+ strcat(info, wc);
+ strcat(info, " for a moment.");
+ mpr(info);
+ }
+ else
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ }
+ break;
+
+ case 3:
+ strcpy(info, "You hear the distant roaring of an enraged ");
+
+ temp_rand = random2(8);
+
+ strcat(info, (temp_rand == 0) ? "frog" :
+ (temp_rand == 1) ? "pill bug" :
+ (temp_rand == 2) ? "millipede" :
+ (temp_rand == 3) ? "eggplant" :
+ (temp_rand == 4) ? "albino dragon" :
+ (temp_rand == 5) ? "dragon" :
+ (temp_rand == 6) ? "human"
+ : "slug");
+
+ strcat(info, "!");
+ mpr(info);
+ break;
+
+ case 4:
+ // josh declares mummies can't smell {dlb}
+ if (you.species != SP_MUMMY)
+ {
+ strcpy(info, "You smell ");
+
+ temp_rand = random2(8);
+
+ strcat(info, (temp_rand == 0) ? "coffee." :
+ (temp_rand == 1) ? "salt." :
+ (temp_rand == 2) ? "burning hair!" :
+ (temp_rand == 3) ? "baking bread." :
+ (temp_rand == 4) ? "something weird." :
+ (temp_rand == 5) ? "wet wool." :
+ (temp_rand == 6) ? "sulphur."
+ : "fire and brimstone!");
+ mpr(info);
+ }
+ break;
+
+ case 5:
+ mpr("You experience a momentary feeling of inescapable doom!");
+ break;
+
+ case 6:
+ strcpy(info, "Your ");
+
+ temp_rand = random2(3);
+
+ strcat(info, (temp_rand == 0) ? "ears itch." :
+ (temp_rand == 1) ? "brain hurts!"
+ : "nose twitches suddenly!");
+ mpr(info);
+ break;
+
+ case 7:
+ mpr("You hear the tinkle of a tiny bell.");
+ cast_summon_butterflies( 100 );
+ break;
+
+ case 8:
+ strcpy(info, "You hear ");
+
+ temp_rand = random2(9);
+
+ strcat(info, (temp_rand == 0) ? "snatches of song" :
+ (temp_rand == 1) ? "a voice call someone else's name" :
+ (temp_rand == 2) ? "a very strange noise" :
+ (temp_rand == 3) ? "roaring flame" :
+ (temp_rand == 4) ? "a very strange noise indeed" :
+ (temp_rand == 5) ? "the chiming of a distant gong" :
+ (temp_rand == 6) ? "the bellowing of a yak" :
+ (temp_rand == 7) ? "a crunching sound"
+ : "the tinkle of an enormous bell");
+ strcat(info, ".");
+ mpr(info);
+ break;
+ }
+
+ return;
+} // end random_uselessness()
+
+bool acquirement(unsigned char force_class)
+{
+ int thing_created = 0;
+ int iteration = 0;
+
+ // Remember lava!
+ unsigned char class_wanted = OBJ_RANDOM;
+ unsigned char type_wanted = OBJ_RANDOM;
+
+ unsigned char unique = 1;
+ unsigned char acqc = 0;
+
+ const int max_has_value = 100;
+ FixedVector< int, max_has_value > already_has;
+
+ char best_spell = 99;
+ char best_any = 99;
+ unsigned char keyin;
+
+ for (acqc = 0; acqc < max_has_value; acqc++)
+ already_has[acqc] = 0;
+
+ int spell_skills = 0;
+ for (int i = SK_SPELLCASTING; i <= SK_POISON_MAGIC; i++)
+ spell_skills += you.skills[i];
+
+ if (force_class == OBJ_RANDOM)
+ {
+ mpr("This is a scroll of acquirement!");
+
+ query:
+ mpr( "[a|A] Weapon [b|B] Armour [c|C] Jewellery [d|D] Book" );
+ mpr( "[e|E] Staff [f|F] Food [g|G] Miscellaneous [h|H] Gold" );
+
+ //mpr("[r|R] - Just give me something good.");
+ mpr("What kind of item would you like to acquire? ", MSGCH_PROMPT);
+
+ keyin = get_ch();
+
+ if (keyin == 'a' || keyin == 'A')
+ class_wanted = OBJ_WEAPONS;
+ else if (keyin == 'b' || keyin == 'B')
+ class_wanted = OBJ_ARMOUR;
+ else if (keyin == 'c' || keyin == 'C')
+ class_wanted = OBJ_JEWELLERY;
+ else if (keyin == 'd' || keyin == 'D')
+ class_wanted = OBJ_BOOKS;
+ else if (keyin == 'e' || keyin == 'E')
+ class_wanted = OBJ_STAVES;
+ else if (keyin == 'f' || keyin == 'F')
+ class_wanted = OBJ_FOOD;
+ else if (keyin == 'g' || keyin == 'G')
+ class_wanted = OBJ_MISCELLANY;
+ else if (keyin == 'h' || keyin == 'H')
+ class_wanted = OBJ_GOLD;
+ }
+ else
+ class_wanted = force_class;
+
+ for (acqc = 0; acqc < ENDOFPACK; acqc++)
+ {
+ if (is_valid_item( you.inv[acqc] )
+ && you.inv[acqc].base_type == class_wanted)
+ {
+ ASSERT( you.inv[acqc].sub_type < max_has_value );
+ already_has[you.inv[acqc].sub_type] += you.inv[acqc].quantity;
+ }
+ }
+
+ if (class_wanted == OBJ_FOOD)
+ {
+ // food is a little less predicatable now -- bwr
+
+ if (you.species == SP_GHOUL)
+ {
+ type_wanted = one_chance_in(10) ? FOOD_ROYAL_JELLY
+ : FOOD_CHUNK;
+ }
+ else
+ {
+ // Meat is better than bread (except for herbivors), and
+ // by choosing it as the default we don't have to worry
+ // about special cases for carnivorous races (ie kobold)
+ type_wanted = FOOD_MEAT_RATION;
+
+ if (you.mutation[MUT_HERBIVOROUS])
+ type_wanted = FOOD_BREAD_RATION;
+
+ // If we have some regular rations, then we're probably be more
+ // interested in faster foods (escpecially royal jelly)...
+ // otherwise the regular rations should be a good enough offer.
+ if (already_has[FOOD_MEAT_RATION]
+ + already_has[FOOD_BREAD_RATION] >= 2 || coinflip())
+ {
+ type_wanted = one_chance_in(5) ? FOOD_HONEYCOMB
+ : FOOD_ROYAL_JELLY;
+ }
+ }
+
+ // quantity is handled by unique for food
+ unique = 3 + random2(5);
+
+ // giving more of the lower food value items
+ if (type_wanted == FOOD_HONEYCOMB || type_wanted == FOOD_CHUNK)
+ {
+ unique += random2avg(10, 2);
+ }
+ }
+ else if (class_wanted == OBJ_WEAPONS)
+ {
+ // Now asking for a weapon is biased towards your skills,
+ // although launchers are right out for now. -- bwr
+ int count = 0;
+ int skill = SK_FIGHTING;
+
+ // Can't do much with launchers, so we'll avoid them for now -- bwr
+ for (int i = SK_SHORT_BLADES; i <= SK_STAVES; i++)
+ {
+ if (i == SK_UNUSED_1)
+ continue;
+
+ // Adding a small constant allows for the occasional
+ // weapon in an untrained skill.
+ count += (you.skills[i] + 1);
+
+ if (random2(count) < you.skills[i] + 1)
+ skill = i;
+ }
+
+ if (skill == SK_STAVES)
+ type_wanted = WPN_QUARTERSTAFF; // only one in this class
+ else
+ {
+ count = 0;
+
+ // skipping clubs, knives, blowguns
+ for (int i = WPN_MACE; i < NUM_WEAPONS; i++)
+ {
+ // skipping launchers
+ if (i == WPN_SLING)
+ i = WPN_GLAIVE;
+
+ // skipping giant clubs
+ if (i == WPN_GIANT_CLUB)
+ i = WPN_EVENINGSTAR;
+
+ // skipping knife and blowgun
+ if (i == WPN_KNIFE)
+ i = WPN_FALCHION;
+
+ // "rare" weapons are only considered some of the time...
+ // still, the chance is higher than actual random creation
+ if (weapon_skill( OBJ_WEAPONS, i ) == skill
+ && (i < WPN_EVENINGSTAR || i > WPN_BROAD_AXE
+ || (i >= WPN_HAMMER && i <= WPN_SABRE)
+ || one_chance_in(4)))
+ {
+ count++;
+ if (one_chance_in( count ))
+ type_wanted = i;
+ }
+ }
+ }
+ }
+ else if (class_wanted == OBJ_ARMOUR)
+ {
+ // Increasing the representation of the non-body armour
+ // slots here to make up for the fact that there's one
+ // one type of item for most of them. -- bwr
+ //
+ // OBJ_RANDOM is body armour and handled below
+ type_wanted = (coinflip()) ? OBJ_RANDOM : ARM_SHIELD + random2(5);
+
+ // mutation specific problems (horns allow caps)
+ if ((you.mutation[MUT_HOOVES] && type_wanted == ARM_BOOTS)
+ || (you.mutation[MUT_CLAWS] >= 3 && type_wanted == ARM_GLOVES))
+ {
+ type_wanted = OBJ_RANDOM;
+ }
+
+ // some species specific fitting problems
+ switch (you.species)
+ {
+ case SP_OGRE:
+ case SP_OGRE_MAGE:
+ case SP_TROLL:
+ case SP_SPRIGGAN:
+ if (type_wanted == ARM_GLOVES || type_wanted == ARM_BOOTS)
+ {
+ type_wanted = OBJ_RANDOM;
+ }
+ else if (type_wanted == ARM_SHIELD)
+ {
+ if (you.species == SP_SPRIGGAN)
+ type_wanted = ARM_BUCKLER;
+ else if (coinflip()) // giant races: 50/50 shield/large shield
+ type_wanted = ARM_LARGE_SHIELD;
+ }
+ else if (type_wanted == OBJ_RANDOM)
+ {
+ type_wanted = ARM_ROBE; // no heavy armour, see below
+ }
+ break;
+
+ case SP_KENKU:
+ if (type_wanted == ARM_BOOTS)
+ type_wanted = OBJ_RANDOM;
+ break;
+
+ default:
+ break;
+ }
+
+ // Now we'll randomly pick a body armour (light only in the
+ // case of ARM_ROBE). Unlike before, now we're only giving
+ // out the finished products here, never the hides. -- bwr
+ if (type_wanted == OBJ_RANDOM || type_wanted == ARM_ROBE)
+ {
+ // start with normal base armour
+ if (type_wanted == ARM_ROBE)
+ type_wanted = coinflip() ? ARM_ROBE : ARM_ANIMAL_SKIN;
+ else
+ {
+ type_wanted = ARM_ROBE + random2(8);
+
+ if (one_chance_in(10) && you.skills[SK_ARMOUR] >= 10)
+ type_wanted = ARM_CRYSTAL_PLATE_MAIL;
+
+ if (one_chance_in(10))
+ type_wanted = ARM_ANIMAL_SKIN;
+ }
+
+ // everyone can wear things made from hides
+ if (one_chance_in(20))
+ {
+ int rnd = random2(20);
+
+ type_wanted = (rnd < 4) ? ARM_TROLL_LEATHER_ARMOUR : // 20%
+ (rnd < 8) ? ARM_STEAM_DRAGON_ARMOUR : // 20%
+ (rnd < 11) ? ARM_MOTTLED_DRAGON_ARMOUR : // 15%
+ (rnd < 14) ? ARM_SWAMP_DRAGON_ARMOUR : // 15%
+ (rnd < 16) ? ARM_DRAGON_ARMOUR : // 10%
+ (rnd < 18) ? ARM_ICE_DRAGON_ARMOUR : // 10%
+ (rnd < 19) ? ARM_STORM_DRAGON_ARMOUR // 5%
+ : ARM_GOLD_DRAGON_ARMOUR; // 5%
+ }
+ }
+ }
+ else if (class_wanted != OBJ_GOLD)
+ {
+
+ do
+ {
+ unsigned char i;
+
+ switch (class_wanted)
+ {
+ case OBJ_JEWELLERY:
+ // Try for a base type the player hasn't identified
+ for (i = 0; i < 10; i++)
+ {
+ type_wanted = random2(24);
+
+ if (one_chance_in(3))
+ type_wanted = AMU_RAGE + random2(10);
+
+ if (get_ident_type(OBJ_JEWELLERY, type_wanted) == ID_UNKNOWN_TYPE)
+ {
+ break;
+ }
+ }
+ break;
+
+ case OBJ_BOOKS:
+ // remember, put rarer books higher in the list
+ iteration = 1;
+ type_wanted = NUM_BOOKS;
+
+ best_spell = best_skill( SK_SPELLCASTING, (NUM_SKILLS - 1),
+ best_spell );
+
+ which_book:
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE,
+ "acquirement: iteration = %d, best_spell = %d",
+ iteration, best_spell );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif //jmf: debugging
+
+ switch (best_spell)
+ {
+ default:
+ case SK_SPELLCASTING:
+ if (you.skills[SK_SPELLCASTING] <= 3
+ && !you.had_book[BOOK_CANTRIPS])
+ {
+ // Handful of level one spells, very useful for the
+ // new spellcaster who's asking for a book -- bwr
+ type_wanted = BOOK_CANTRIPS;
+ }
+ else if (!you.had_book[BOOK_MINOR_MAGIC_I])
+ type_wanted = BOOK_MINOR_MAGIC_I + random2(3);
+ else if (!you.had_book[BOOK_WIZARDRY])
+ type_wanted = BOOK_WIZARDRY;
+ else if (!you.had_book[BOOK_CONTROL])
+ type_wanted = BOOK_CONTROL;
+ else if (!you.had_book[BOOK_POWER])
+ type_wanted = BOOK_POWER;
+ break;
+
+ case SK_POISON_MAGIC:
+ if (!you.had_book[BOOK_YOUNG_POISONERS])
+ type_wanted = BOOK_YOUNG_POISONERS;
+ else if (!you.had_book[BOOK_ENVENOMATIONS])
+ type_wanted = BOOK_ENVENOMATIONS;
+ break;
+
+ case SK_EARTH_MAGIC:
+ if (!you.had_book[BOOK_GEOMANCY])
+ type_wanted = BOOK_GEOMANCY;
+ else if (!you.had_book[BOOK_EARTH])
+ type_wanted = BOOK_EARTH;
+ break;
+
+ case SK_AIR_MAGIC:
+ // removed the book of clouds... all the other elements
+ // (and most other spell skills) only get two.
+ if (!you.had_book[BOOK_AIR])
+ type_wanted = BOOK_AIR;
+ else if (!you.had_book[BOOK_SKY])
+ type_wanted = BOOK_SKY;
+ break;
+
+ case SK_ICE_MAGIC:
+ if (!you.had_book[BOOK_FROST])
+ type_wanted = BOOK_FROST;
+ else if (!you.had_book[BOOK_ICE])
+ type_wanted = BOOK_ICE;
+ break;
+
+ case SK_FIRE_MAGIC:
+ if (!you.had_book[BOOK_FLAMES])
+ type_wanted = BOOK_FLAMES;
+ else if (!you.had_book[BOOK_FIRE])
+ type_wanted = BOOK_FIRE;
+ break;
+
+ case SK_SUMMONINGS:
+ if (!you.had_book[BOOK_CALLINGS])
+ type_wanted = BOOK_CALLINGS;
+ else if (!you.had_book[BOOK_SUMMONINGS])
+ type_wanted = BOOK_SUMMONINGS;
+
+ // now a Vehumet special -- bwr
+ // else if (!you.had_book[BOOK_DEMONOLOGY])
+ // type_wanted = BOOK_DEMONOLOGY;
+ break;
+
+ case SK_ENCHANTMENTS:
+ best_any = best_skill(SK_FIGHTING, (NUM_SKILLS - 1), 99);
+
+ // So many enchantment books! I really can't feel
+ // guilty at all for dividing out the fighting
+ // books and forcing the player to raise a fighting
+ // skill (or enchantments in the case of Crusaders)
+ // to get the remaining books... enchantments are
+ // much too good (most spells, lots of books here,
+ // id wand charges, gives magic resistance),
+ // something will eventually have to be done. -- bwr
+ if (best_any >= SK_FIGHTING
+ && best_any <= SK_STAVES)
+ {
+ // Fighter mage's get the fighting enchantment books
+ if (!you.had_book[BOOK_WAR_CHANTS])
+ type_wanted = BOOK_WAR_CHANTS;
+ else if (!you.had_book[BOOK_TUKIMA])
+ type_wanted = BOOK_TUKIMA;
+ }
+ else if (!you.had_book[BOOK_CHARMS])
+ type_wanted = BOOK_CHARMS;
+ else if (!you.had_book[BOOK_HINDERANCE])
+ type_wanted = BOOK_HINDERANCE;
+ else if (!you.had_book[BOOK_ENCHANTMENTS])
+ type_wanted = BOOK_ENCHANTMENTS;
+ break;
+
+ case SK_CONJURATIONS:
+ if (!you.had_book[BOOK_CONJURATIONS_I])
+ type_wanted = give_first_conjuration_book();
+ else if (!you.had_book[BOOK_TEMPESTS])
+ type_wanted = BOOK_TEMPESTS;
+
+ // now a Vehumet special -- bwr
+ // else if (!you.had_book[BOOK_ANNIHILATIONS])
+ // type_wanted = BOOK_ANNIHILATIONS;
+ break;
+
+ case SK_NECROMANCY:
+ if (!you.had_book[BOOK_NECROMANCY])
+ type_wanted = BOOK_NECROMANCY;
+ else if (!you.had_book[BOOK_DEATH])
+ type_wanted = BOOK_DEATH;
+ else if (!you.had_book[BOOK_UNLIFE])
+ type_wanted = BOOK_UNLIFE;
+
+ // now a Kikubaaqudgha special -- bwr
+ // else if (!you.had_book[BOOK_NECRONOMICON])
+ // type_wanted = BOOK_NECRONOMICON;
+ break;
+
+ case SK_TRANSLOCATIONS:
+ if (!you.had_book[BOOK_SPATIAL_TRANSLOCATIONS])
+ type_wanted = BOOK_SPATIAL_TRANSLOCATIONS;
+ else if (!you.had_book[BOOK_WARP])
+ type_wanted = BOOK_WARP;
+ break;
+
+ case SK_TRANSMIGRATION:
+ if (!you.had_book[BOOK_CHANGES])
+ type_wanted = BOOK_CHANGES;
+ else if (!you.had_book[BOOK_TRANSFIGURATIONS])
+ type_wanted = BOOK_TRANSFIGURATIONS;
+ else if (!you.had_book[BOOK_MUTATIONS])
+ type_wanted = BOOK_MUTATIONS;
+ break;
+
+ case SK_DIVINATIONS: //jmf: added 24mar2000
+ if (!you.had_book[BOOK_SURVEYANCES])
+ type_wanted = BOOK_SURVEYANCES;
+ else if (!you.had_book[BOOK_DIVINATIONS])
+ type_wanted = BOOK_DIVINATIONS;
+ break;
+ }
+/*
+ if (type_wanted == 99 && glof == best_skill(SK_SPELLCASTING, (NUM_SKILLS - 1), 99))
+*/
+ if (type_wanted == NUM_BOOKS && iteration == 1)
+ {
+ best_spell = best_skill( SK_SPELLCASTING, (NUM_SKILLS - 1),
+ best_skill(SK_SPELLCASTING,
+ (NUM_SKILLS - 1), 99) );
+ iteration++;
+ goto which_book;
+ }
+
+ // if we don't have a book, try and get a new one.
+ if (type_wanted == NUM_BOOKS)
+ {
+ do
+ {
+ type_wanted = random2(NUM_BOOKS);
+ if (one_chance_in(500))
+ break;
+ }
+ while (you.had_book[type_wanted]);
+ }
+
+ // if the book is invalid find any valid one.
+ while (book_rarity(type_wanted) == 100
+ || type_wanted == BOOK_DESTRUCTION
+ || type_wanted == BOOK_MANUAL)
+ {
+ type_wanted = random2(NUM_BOOKS);
+ }
+ break;
+
+ case OBJ_STAVES:
+ type_wanted = random2(13);
+
+ if (type_wanted >= 10)
+ type_wanted = STAFF_AIR + type_wanted - 10;
+
+ // Elemental preferences -- bwr
+ if (type_wanted == STAFF_FIRE || type_wanted == STAFF_COLD)
+ {
+ if (you.skills[SK_FIRE_MAGIC] > you.skills[SK_ICE_MAGIC])
+ type_wanted = STAFF_FIRE;
+ else if (you.skills[SK_FIRE_MAGIC] != you.skills[SK_ICE_MAGIC])
+ type_wanted = STAFF_COLD;
+ }
+ else if (type_wanted == STAFF_AIR || type_wanted == STAFF_EARTH)
+ {
+ if (you.skills[SK_AIR_MAGIC] > you.skills[SK_EARTH_MAGIC])
+ type_wanted = STAFF_AIR;
+ else if (you.skills[SK_AIR_MAGIC] != you.skills[SK_EARTH_MAGIC])
+ type_wanted = STAFF_EARTH;
+ }
+
+ best_spell = best_skill( SK_SPELLCASTING, (NUM_SKILLS-1), 99 );
+
+ // If we're going to give out an enhancer stave,
+ // we should at least bias things towards the
+ // best spell skill. -- bwr
+ switch (best_spell)
+ {
+ case SK_FIRE_MAGIC:
+ if (!already_has[STAFF_FIRE])
+ type_wanted = STAFF_FIRE;
+ break;
+
+ case SK_ICE_MAGIC:
+ if (!already_has[STAFF_COLD])
+ type_wanted = STAFF_COLD;
+ break;
+
+ case SK_AIR_MAGIC:
+ if (!already_has[STAFF_AIR])
+ type_wanted = STAFF_AIR;
+ break;
+
+ case SK_EARTH_MAGIC:
+ if (!already_has[STAFF_EARTH])
+ type_wanted = STAFF_EARTH;
+ break;
+
+ case SK_POISON_MAGIC:
+ if (!already_has[STAFF_POISON])
+ type_wanted = STAFF_POISON;
+ break;
+
+ case SK_NECROMANCY:
+ if (!already_has[STAFF_DEATH])
+ type_wanted = STAFF_DEATH;
+ break;
+
+ case SK_CONJURATIONS:
+ if (!already_has[STAFF_CONJURATION])
+ type_wanted = STAFF_CONJURATION;
+ break;
+
+ case SK_ENCHANTMENTS:
+ if (!already_has[STAFF_ENCHANTMENT])
+ type_wanted = STAFF_ENCHANTMENT;
+ break;
+
+ case SK_SUMMONINGS:
+ if (!already_has[STAFF_SUMMONING])
+ type_wanted = STAFF_SUMMONING;
+ break;
+
+ case SK_EVOCATIONS:
+ if (!one_chance_in(4))
+ type_wanted = STAFF_SMITING + random2(10);
+ break;
+
+ default: // invocations and leftover spell schools
+ switch (random2(5))
+ {
+ case 0:
+ type_wanted = STAFF_WIZARDRY;
+ break;
+
+ case 1:
+ type_wanted = STAFF_POWER;
+ break;
+
+ case 2:
+ type_wanted = STAFF_ENERGY;
+ break;
+
+ case 3:
+ type_wanted = STAFF_CHANNELING;
+ break;
+
+ case 4:
+ break;
+ }
+ break;
+ }
+
+ // Increased chance of getting spell staff for new or
+ // non-spellcasters. -- bwr
+ if (one_chance_in(20)
+ || (spell_skills <= 1 // short on spells
+ && (type_wanted < STAFF_SMITING // already making one
+ || type_wanted >= STAFF_AIR)
+ && !one_chance_in(4)))
+ {
+ type_wanted = (coinflip() ? STAFF_STRIKING
+ : STAFF_SMITING + random2(10));
+ }
+ break;
+
+ case OBJ_MISCELLANY:
+ do
+ type_wanted = random2(NUM_MISCELLANY);
+ while (type_wanted == MISC_HORN_OF_GERYON
+ || type_wanted == MISC_RUNE_OF_ZOT
+ || type_wanted == MISC_PORTABLE_ALTAR_OF_NEMELEX
+ || type_wanted == MISC_CRYSTAL_BALL_OF_FIXATION
+ || type_wanted == MISC_EMPTY_EBONY_CASKET);
+ break;
+
+ default:
+ mesclr();
+ goto query;
+ }
+
+ ASSERT( type_wanted < max_has_value );
+ }
+ while (already_has[type_wanted] && !one_chance_in(200));
+ }
+
+ if (grd[you.x_pos][you.y_pos] == DNGN_LAVA
+ || grd[you.x_pos][you.y_pos] == DNGN_DEEP_WATER)
+ {
+ mpr("You hear a splash."); // how sad (and stupid)
+ }
+ else
+ {
+ // BCR - unique is now used for food quantity.
+ thing_created = items( unique, class_wanted, type_wanted, true,
+ MAKE_GOOD_ITEM, 250 );
+
+ if (thing_created == NON_ITEM)
+ {
+ mpr("The demon of the infinite void smiles at you.");
+ return (false);
+ }
+
+ // remove curse flag from item
+ do_uncurse_item( mitm[thing_created] );
+
+ if (mitm[thing_created].base_type == OBJ_BOOKS)
+ {
+ if (mitm[thing_created].base_type == BOOK_MINOR_MAGIC_I
+ || mitm[thing_created].base_type == BOOK_MINOR_MAGIC_II
+ || mitm[thing_created].base_type == BOOK_MINOR_MAGIC_III)
+ {
+ you.had_book[ BOOK_MINOR_MAGIC_I ] = 1;
+ you.had_book[ BOOK_MINOR_MAGIC_II ] = 1;
+ you.had_book[ BOOK_MINOR_MAGIC_III ] = 1;
+ }
+ else if (mitm[thing_created].base_type == BOOK_CONJURATIONS_I
+ || mitm[thing_created].base_type == BOOK_CONJURATIONS_II)
+ {
+ you.had_book[ BOOK_CONJURATIONS_I ] = 1;
+ you.had_book[ BOOK_CONJURATIONS_II ] = 1;
+ }
+ else
+ {
+ you.had_book[ mitm[thing_created].sub_type ] = 1;
+ }
+ }
+ else if (mitm[thing_created].base_type == OBJ_JEWELLERY)
+ {
+ switch (mitm[thing_created].sub_type)
+ {
+ case RING_SLAYING:
+ // make sure plus to damage is >= 1
+ mitm[thing_created].plus2 = abs( mitm[thing_created].plus2 );
+ if (mitm[thing_created].plus2 == 0)
+ mitm[thing_created].plus2 = 1;
+ // fall through...
+
+ case RING_PROTECTION:
+ case RING_STRENGTH:
+ case RING_INTELLIGENCE:
+ case RING_DEXTERITY:
+ case RING_EVASION:
+ // make sure plus is >= 1
+ mitm[thing_created].plus = abs( mitm[thing_created].plus );
+ if (mitm[thing_created].plus == 0)
+ mitm[thing_created].plus = 1;
+ break;
+
+ case RING_HUNGER:
+ case AMU_INACCURACY:
+ // these are the only truly bad pieces of jewellery
+ if (!one_chance_in(9))
+ make_item_randart( mitm[thing_created] );
+ break;
+
+ default:
+ break;
+ }
+ }
+ else if (mitm[thing_created].base_type == OBJ_WEAPONS
+ && !is_fixed_artefact( mitm[thing_created] ))
+ {
+ // HACK: make unwieldable weapons wieldable
+ // Note: messing with fixed artefacts is probably very bad.
+ switch (you.species)
+ {
+ case SP_DEMONSPAWN:
+ case SP_MUMMY:
+ case SP_GHOUL:
+ {
+ int brand = get_weapon_brand( mitm[thing_created] );
+ if (brand == SPWPN_HOLY_WRATH
+ || brand == SPWPN_DISRUPTION)
+ {
+ if (!is_random_artefact( mitm[thing_created] ))
+ {
+ set_item_ego_type( mitm[thing_created],
+ OBJ_WEAPONS, SPWPN_VORPAL );
+ }
+ else
+ {
+ // keep reseting seed until it's good:
+ for (; brand == SPWPN_HOLY_WRATH
+ || brand == SPWPN_DISRUPTION;
+ brand = get_weapon_brand(mitm[thing_created]))
+ {
+ make_item_randart( mitm[thing_created] );
+ }
+ }
+ }
+ }
+ break;
+
+ case SP_HALFLING:
+ case SP_GNOME:
+ case SP_KOBOLD:
+ case SP_SPRIGGAN:
+ switch (mitm[thing_created].sub_type)
+ {
+ case WPN_GREAT_SWORD:
+ case WPN_TRIPLE_SWORD:
+ mitm[thing_created].sub_type =
+ (coinflip() ? WPN_FALCHION : WPN_LONG_SWORD);
+ break;
+
+ case WPN_GREAT_MACE:
+ case WPN_GREAT_FLAIL:
+ mitm[thing_created].sub_type =
+ (coinflip() ? WPN_MACE : WPN_FLAIL);
+ break;
+
+ case WPN_BATTLEAXE:
+ case WPN_EXECUTIONERS_AXE:
+ mitm[thing_created].sub_type =
+ (coinflip() ? WPN_HAND_AXE : WPN_WAR_AXE);
+ break;
+
+ case WPN_HALBERD:
+ case WPN_GLAIVE:
+ case WPN_SCYTHE:
+ mitm[thing_created].sub_type =
+ (coinflip() ? WPN_SPEAR : WPN_TRIDENT);
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ else if (mitm[thing_created].base_type == OBJ_ARMOUR
+ && !is_fixed_artefact( mitm[thing_created] ))
+ {
+ // HACK: make unwearable hats and boots wearable
+ // Note: messing with fixed artefacts is probably very bad.
+ switch (mitm[thing_created].sub_type)
+ {
+ case ARM_HELMET:
+ if ((cmp_helmet_type( mitm[thing_created], THELM_HELM )
+ || cmp_helmet_type( mitm[thing_created], THELM_HELMET ))
+ && ((you.species >= SP_OGRE && you.species <= SP_OGRE_MAGE)
+ || player_genus(GENPC_DRACONIAN)
+ || you.species == SP_MINOTAUR
+ || you.species == SP_KENKU
+ || you.species == SP_SPRIGGAN
+ || you.mutation[MUT_HORNS]))
+ {
+ // turn it into a cap or wizard hat
+ set_helmet_type( mitm[thing_created],
+ coinflip() ? THELM_CAP : THELM_WIZARD_HAT );
+
+ mitm[thing_created].colour = random_colour();
+ }
+ break;
+
+ case ARM_BOOTS:
+ if (you.species == SP_NAGA)
+ mitm[thing_created].plus2 = TBOOT_NAGA_BARDING;
+ else if (you.species == SP_CENTAUR)
+ mitm[thing_created].plus2 = TBOOT_CENTAUR_BARDING;
+ else
+ mitm[thing_created].plus2 = TBOOT_BOOTS;
+
+ // fix illegal barding ego types caused by above hack
+ if (mitm[thing_created].plus2 != TBOOT_BOOTS
+ && get_armour_ego_type( mitm[thing_created] ) == SPARM_RUNNING)
+ {
+ set_item_ego_type( mitm[thing_created], OBJ_ARMOUR, SPARM_NORMAL );
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ move_item_to_grid( &thing_created, you.x_pos, you.y_pos );
+
+ // This should never actually be NON_ITEM because of the way
+ // move_item_to_grid works (doesn't create a new item ever),
+ // but we're checking it anyways. -- bwr
+ if (thing_created != NON_ITEM)
+ canned_msg(MSG_SOMETHING_APPEARS);
+ }
+
+ // Well, the item may have fallen in the drink, but the intent is
+ // that acquirement happened. -- bwr
+ return (true);
+} // end acquirement()
+
+bool recharge_wand(void)
+{
+ if (you.equip[EQ_WEAPON] == -1
+ || you.inv[you.equip[EQ_WEAPON]].base_type != OBJ_WANDS)
+ {
+ return (false);
+ }
+
+ unsigned char charge_gain = 0;
+
+ switch (you.inv[you.equip[EQ_WEAPON]].sub_type)
+ {
+ case WAND_INVISIBILITY:
+ case WAND_FIREBALL:
+ case WAND_HEALING:
+ charge_gain = 3;
+ break;
+
+ case WAND_LIGHTNING:
+ case WAND_DRAINING:
+ charge_gain = 4;
+ break;
+
+ case WAND_FIRE:
+ case WAND_COLD:
+ charge_gain = 5;
+ break;
+
+ default:
+ charge_gain = 8;
+ break;
+ }
+
+ char str_pass[ ITEMNAME_SIZE ];
+ in_name(you.equip[EQ_WEAPON], DESC_CAP_YOUR, str_pass);
+ strcpy(info, str_pass);
+ strcat(info, " glows for a moment.");
+ mpr(info);
+
+ you.inv[you.equip[EQ_WEAPON]].plus +=
+ 1 + random2avg( ((charge_gain - 1) * 3) + 1, 3 );
+
+ if (you.inv[you.equip[EQ_WEAPON]].plus > charge_gain * 3)
+ you.inv[you.equip[EQ_WEAPON]].plus = charge_gain * 3;
+
+ you.wield_change = true;
+ return (true);
+} // end recharge_wand()
+
+void yell(void)
+{
+ bool targ_prev = false;
+ int mons_targd = MHITNOT;
+ struct dist targ;
+
+ if (silenced(you.x_pos, you.y_pos))
+ {
+ mpr("You are unable to make a sound!");
+ return;
+ }
+
+ mpr("What do you say?", MSGCH_PROMPT);
+ mpr(" ! - Yell");
+ mpr(" a - Order allies to attack a monster");
+
+ if (!(you.prev_targ == MHITNOT || you.prev_targ == MHITYOU))
+ {
+ struct monsters *target = &menv[you.prev_targ];
+
+ if (mons_near(target) && player_monster_visible(target))
+ {
+ mpr(" p - Order allies to attack your previous target");
+ targ_prev = true;
+ }
+ }
+
+ strcpy(info, " Anything else - Stay silent");
+
+ if (one_chance_in(20))
+ strcat(info, " (and be thought a fool)");
+
+ mpr(info);
+
+ unsigned char keyn = get_ch();
+
+ switch (keyn)
+ {
+ case '!':
+ mpr("You yell for attention!");
+ you.turn_is_over = 1;
+ noisy( 12, you.x_pos, you.y_pos );
+ return;
+
+ case 'a':
+ mpr("Gang up on whom?", MSGCH_PROMPT);
+ direction( targ, DIR_TARGET, TARG_ENEMY );
+
+ if (targ.isCancel)
+ {
+ canned_msg(MSG_OK);
+ return;
+ }
+
+ if (!targ.isValid || mgrd[targ.tx][targ.ty] == NON_MONSTER)
+ {
+ mpr("Yeah, whatever.");
+ return;
+ }
+
+ mons_targd = mgrd[targ.tx][targ.ty];
+ break;
+
+ case 'p':
+ if (targ_prev)
+ {
+ mons_targd = you.prev_targ;
+ break;
+ }
+ /* fall through... */
+ default:
+ mpr("Okely-dokely.");
+ return;
+ }
+
+ you.pet_target = mons_targd;
+
+ noisy( 10, you.x_pos, you.y_pos );
+ mpr("Attack!");
+} // end yell()
diff --git a/trunk/source/effects.h b/trunk/source/effects.h
new file mode 100644
index 0000000000..039ba80c0c
--- /dev/null
+++ b/trunk/source/effects.h
@@ -0,0 +1,92 @@
+/*
+ * File: effects.cc
+ * Summary: Misc stuff.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef EFFECTS_H
+#define EFFECTS_H
+
+#include "externs.h"
+
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - acr - beam - decks - fight - religion - spells
+ * *********************************************************************** */
+void banished(unsigned char gate_type);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: spells
+ * *********************************************************************** */
+bool forget_spell(void);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: fight - it_use2 - it_use3 - items - religion - spells -
+ * spells2 - spells4
+ * *********************************************************************** */
+bool lose_stat(unsigned char which_stat, unsigned char stat_loss,
+ bool force = false);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: item_use - spell - spells
+ * *********************************************************************** */
+void random_uselessness(unsigned char ru, unsigned char sc_read_2);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - decks - item_use - religion
+ * *********************************************************************** */
+bool acquirement(unsigned char force_class);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: item_use
+ * *********************************************************************** */
+bool recharge_wand(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: mstuff2
+ * *********************************************************************** */
+void direct_effect(struct bolt &pbolt);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: mstuff2
+ * *********************************************************************** */
+void mons_direct_effect(struct bolt &pbolt, int i);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void yell(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - decks - fight - it_use3 - item_use - mstuff2 -
+ * spell
+ * *********************************************************************** */
+void torment( int tx, int ty );
+
+
+#endif
diff --git a/trunk/source/enum.h b/trunk/source/enum.h
new file mode 100644
index 0000000000..a1b76e0422
--- /dev/null
+++ b/trunk/source/enum.h
@@ -0,0 +1,3116 @@
+/*
+ * File: enum.h
+ * Summary: Global (ick) enums.
+ * Written by: Daniel Ligon
+ *
+ * Change History (most recent first):
+ *
+ * <11> 7 Aug 01 MV Changed MSLOT_UNASSIGNED_I to MSLOT_MISCELLANY
+ * added NUM_MISCELLANY, changed MONS_ANOTHER_
+ * LAVA_THING to MONS_SALAMANDER
+ * <10> 7/29/00 JDJ Changed NUM_SPELL_TYPES to 14 (from 32767!).
+ * 24jun2000 jmf Changed comment spacing so stuff fit in 80
+ * columns; deleted some leading numbers in
+ * comments (reasoning as above).
+ * Also removed many "must be last" comments,
+ * esp. where less-than-accurate.
+ * <9> 10jan2000 dlb extensive - see changes.340 S
+ * <8> 04nov1999 cdl added killed_by
+ * <7> 29sep1999 BCR Added comments showing where uniques are
+ * <6> 25sep1999 CDL Added commands
+ * <5> 09sep1999 BWR Removed Great Swords skill
+ * <4> 06aug1999 BWR added branch and level types
+ * <3> 02jun1999 DML beams, clouds, ench, ms, kill,
+ * other minor changes
+ * <2> 26may1999 JDJ Added a header guard.
+ * <1> --/--/-- CDL Created
+ */
+
+
+#ifndef ENUM_H
+#define ENUM_H
+
+enum ABILITIES
+{
+ ABIL_NON_ABILITY = -1,
+ ABIL_SPIT_POISON = 1, // 1
+ ABIL_GLAMOUR,
+ ABIL_MAPPING,
+ ABIL_TELEPORTATION,
+ ABIL_BREATHE_FIRE, // 5
+ ABIL_BLINK,
+ ABIL_BREATHE_FROST,
+ ABIL_BREATHE_POISON,
+ ABIL_BREATHE_LIGHTNING,
+ ABIL_SPIT_ACID, // 10
+ ABIL_BREATHE_POWER,
+ ABIL_EVOKE_BERSERK,
+ ABIL_BREATHE_STICKY_FLAME,
+ ABIL_BREATHE_STEAM,
+ ABIL_FLY, // 15
+ ABIL_SUMMON_MINOR_DEMON,
+ ABIL_SUMMON_DEMON,
+ ABIL_HELLFIRE,
+ ABIL_TORMENT,
+ ABIL_RAISE_DEAD, // 20
+ ABIL_CONTROL_DEMON,
+ ABIL_TO_PANDEMONIUM,
+ ABIL_CHANNELING,
+ ABIL_THROW_FLAME,
+ ABIL_THROW_FROST, // 25
+ ABIL_BOLT_OF_DRAINING,
+ ABIL_BREATHE_HELLFIRE,
+ ABIL_FLY_II,
+ ABIL_DELAYED_FIREBALL,
+ ABIL_MUMMY_RESTORATION, // 30
+ ABIL_EVOKE_MAPPING,
+ ABIL_EVOKE_TELEPORTATION,
+ ABIL_EVOKE_BLINK, // 33
+ ABIL_EVOKE_TURN_INVISIBLE = 51, // 51
+ ABIL_EVOKE_TURN_VISIBLE,
+ ABIL_EVOKE_LEVITATE,
+ ABIL_EVOKE_STOP_LEVITATING,
+ ABIL_END_TRANSFORMATION, // 55
+ ABIL_ZIN_REPEL_UNDEAD = 110, // 110
+ ABIL_ZIN_HEALING,
+ ABIL_ZIN_PESTILENCE,
+ ABIL_ZIN_HOLY_WORD,
+ ABIL_ZIN_SUMMON_GUARDIAN, // 114
+ ABIL_TSO_REPEL_UNDEAD = 120, // 120
+ ABIL_TSO_SMITING,
+ ABIL_TSO_ANNIHILATE_UNDEAD,
+ ABIL_TSO_THUNDERBOLT,
+ ABIL_TSO_SUMMON_DAEVA, // 124
+ ABIL_KIKU_RECALL_UNDEAD_SLAVES = 130, // 130
+ ABIL_KIKU_ENSLAVE_UNDEAD = 132, // 132
+ ABIL_KIKU_INVOKE_DEATH, // 133
+ ABIL_YRED_ANIMATE_CORPSE = 140, // 140
+ ABIL_YRED_RECALL_UNDEAD,
+ ABIL_YRED_ANIMATE_DEAD,
+ ABIL_YRED_DRAIN_LIFE,
+ ABIL_YRED_CONTROL_UNDEAD, // 144
+ ABIL_VEHUMET_CHANNEL_ENERGY = 160, // 160
+ ABIL_OKAWARU_MIGHT = 170, // 170
+ ABIL_OKAWARU_HEALING,
+ ABIL_OKAWARU_HASTE, // 172
+ ABIL_MAKHLEB_MINOR_DESTRUCTION = 180, // 180
+ ABIL_MAKHLEB_LESSER_SERVANT_OF_MAKHLEB,
+ ABIL_MAKHLEB_MAJOR_DESTRUCTION,
+ ABIL_MAKHLEB_GREATER_SERVANT_OF_MAKHLEB, // 183
+ ABIL_SIF_MUNA_FORGET_SPELL = 190, // 190
+ ABIL_TROG_BERSERK = 200, // 200
+ ABIL_TROG_MIGHT,
+ ABIL_TROG_HASTE_SELF, // 202
+ ABIL_ELYVILON_LESSER_HEALING = 220, // 220
+ ABIL_ELYVILON_PURIFICATION,
+ ABIL_ELYVILON_HEALING,
+ ABIL_ELYVILON_RESTORATION,
+ ABIL_ELYVILON_GREATER_HEALING, // 224
+ ABIL_CHARM_SNAKE,
+ ABIL_TRAN_SERPENT_OF_HELL,
+ ABIL_ROTTING,
+ ABIL_TORMENT_II,
+ ABIL_SHUGGOTH_SEED,
+ ABIL_RENOUNCE_RELIGION = 250 // 250
+};
+
+enum ABILITY_FLAGS
+{
+ ABFLAG_NONE = 0x00000000,
+ ABFLAG_BREATH = 0x00000001, // ability uses DUR_BREATH_WEAPON
+ ABFLAG_DELAY = 0x00000002, // ability has its own delay (ie glamour)
+ ABFLAG_PAIN = 0x00000004, // ability must hurt player (ie torment)
+ ABFLAG_EXHAUSTION = 0x00000008, // fails if you.exhausted
+ ABFLAG_INSTANT = 0x00000010, // doesn't take time to use
+ ABFLAG_PERMANENT_HP = 0x00000020, // costs permanent HPs
+ ABFLAG_PERMANENT_MP = 0x00000040 // costs permanent MPs
+};
+
+enum AMMUNITION_DESCRIPTIONS
+{
+ DAMMO_ORCISH = 3, // 3
+ DAMMO_ELVEN,
+ DAMMO_DWARVEN // 5
+};
+
+enum ARMOUR
+{
+ ARM_ROBE, // 0
+ ARM_LEATHER_ARMOUR,
+ ARM_RING_MAIL,
+ ARM_SCALE_MAIL,
+ ARM_CHAIN_MAIL,
+ ARM_SPLINT_MAIL, // 5
+ ARM_BANDED_MAIL,
+ ARM_PLATE_MAIL,
+ ARM_SHIELD,
+ ARM_CLOAK,
+ ARM_HELMET, // 10
+ ARM_GLOVES,
+ ARM_BOOTS,
+ ARM_BUCKLER,
+ ARM_LARGE_SHIELD,
+ ARM_DRAGON_HIDE, // 15
+ ARM_TROLL_HIDE,
+ ARM_CRYSTAL_PLATE_MAIL,
+ ARM_DRAGON_ARMOUR,
+ ARM_TROLL_LEATHER_ARMOUR,
+ ARM_ICE_DRAGON_HIDE, // 20
+ ARM_ICE_DRAGON_ARMOUR,
+ ARM_STEAM_DRAGON_HIDE,
+ ARM_STEAM_DRAGON_ARMOUR,
+ ARM_MOTTLED_DRAGON_HIDE,
+ ARM_MOTTLED_DRAGON_ARMOUR, // 25
+ ARM_STORM_DRAGON_HIDE,
+ ARM_STORM_DRAGON_ARMOUR,
+ ARM_GOLD_DRAGON_HIDE,
+ ARM_GOLD_DRAGON_ARMOUR,
+ ARM_ANIMAL_SKIN, // 30
+ ARM_SWAMP_DRAGON_HIDE,
+ ARM_SWAMP_DRAGON_ARMOUR,
+ NUM_ARMOURS
+};
+
+enum ARMOUR_DESCRIPTIONS
+{
+ DARM_PLAIN, // added for the heck of it, 15 Apr 2000 {dlb}
+ DARM_EMBROIDERED_SHINY = 1, // which it is dependent upon armour subtype {dlb}
+ DARM_RUNED,
+ DARM_GLOWING,
+ DARM_ELVEN,
+ DARM_DWARVEN, // 5
+ DARM_ORCISH
+};
+
+enum ARMOUR_PROPERTIES
+{
+ PARM_AC, // 0
+ PARM_EVASION
+};
+
+// Note: currently the size of the attr array is hard coded at 30! ick! -- bwr
+enum ATTRIBUTES
+{
+ ATTR_DIVINE_LIGHTNING_PROTECTION, // 0
+ // ATTR_SPEC_AIR, // don't use this!
+ // ATTR_SPEC_EARTH,
+ ATTR_CONTROL_TELEPORT = 3,
+ ATTR_WALK_SLOWLY,
+ ATTR_TRANSFORMATION, // 5
+ ATTR_CARD_COUNTDOWN,
+ ATTR_CARD_TABLE,
+ ATTR_NUM_DEMONIC_POWERS,
+ ATTR_WAS_SILENCED, //jmf: added for silenced messages
+ ATTR_GOD_GIFT_COUNT, //jmf: added to help manage god gift giving
+ ATTR_EXPENSIVE_FLIGHT, //jmf: flag for "manual flight" (ie wings)
+ ATTR_DEMONIC_SCALES, //jmf: remember which kind of scales to improve
+ ATTR_WALLS,
+ ATTR_LAST_WALLS,
+ ATTR_DELAYED_FIREBALL, // bwr: reserve fireballs
+ NUM_ATTRIBUTES // must always remain last member {dlb}
+};
+
+enum BANDS
+{
+ BAND_NO_BAND = 0,
+ BAND_KOBOLDS = 1,
+ BAND_ORCS,
+ BAND_ORC_KNIGHT,
+ BAND_KILLER_BEES,
+ BAND_FLYING_SKULLS, // 5
+ BAND_SLIME_CREATURES,
+ BAND_YAKS,
+ BAND_UGLY_THINGS,
+ BAND_HELL_HOUNDS,
+ BAND_JACKALS, // 10
+ BAND_HELL_KNIGHTS,
+ BAND_ORC_HIGH_PRIEST,
+ BAND_GNOLLS, // 13
+ BAND_BUMBLEBEES = 16,
+ BAND_CENTAURS,
+ BAND_YAKTAURS,
+ BAND_INSUBSTANTIAL_WISPS,
+ BAND_OGRE_MAGE, // 20
+ BAND_DEATH_YAKS,
+ BAND_NECROMANCER,
+ BAND_BALRUG,
+ BAND_CACODEMON,
+ BAND_EXECUTIONER, // 25
+ BAND_HELLWING,
+ BAND_DEEP_ELF_FIGHTER,
+ BAND_DEEP_ELF_KNIGHT,
+ BAND_DEEP_ELF_HIGH_PRIEST,
+ BAND_KOBOLD_DEMONOLOGIST, // 30
+ BAND_NAGAS,
+ BAND_WAR_DOGS,
+ BAND_GREY_RATS,
+ BAND_GREEN_RATS,
+ BAND_ORANGE_RATS, // 35
+ BAND_SHEEP,
+ BAND_GHOULS,
+ BAND_DEEP_TROLLS,
+ BAND_HOGS,
+ BAND_HELL_HOGS, // 40
+ BAND_GIANT_MOSQUITOES,
+ BAND_BOGGARTS,
+ BAND_BLINK_FROGS,
+ BAND_SKELETAL_WARRIORS, // 44
+ NUM_BANDS // always last
+};
+
+enum BEAMS // beam[].flavour
+{
+ BEAM_MISSILE, // 0
+ BEAM_MMISSILE, // 1 - and similarly unresistable things
+ BEAM_FIRE,
+ BEAM_COLD,
+ BEAM_MAGIC,
+ BEAM_ELECTRICITY, // 5
+ BEAM_POISON,
+ BEAM_NEG,
+ BEAM_ACID, // 8
+ BEAM_EXPLOSION = 10, // 10
+ BEAM_SPORE, // 11
+ BEAM_POISON_ARROW, // 12
+ BEAM_HELLFIRE, // 13 - found 11jan2000 {dlb}
+ BEAM_ENERGY = 17,
+ BEAM_HOLY = 18, // 18 - aka beam of cleansing, golden flame
+ BEAM_FRAG,
+ BEAM_LAVA, // 20
+ BEAM_BACKLIGHT,
+ BEAM_SLEEP,
+ BEAM_ICE, // 23
+ BEAM_NUKE = 27, // 27
+ BEAM_RANDOM, // currently translates into FIRE..ACID
+
+ // These used to be handled in the colour field:
+ BEAM_SLOW, // BLACK
+ BEAM_HASTE, // BLUE
+ BEAM_HEALING, // GREEN
+ BEAM_PARALYSIS, // CYAN
+ BEAM_CONFUSION, // RED
+ BEAM_INVISIBILITY, // MAGENTA
+ BEAM_DIGGING, // BROWN
+ BEAM_TELEPORT, // LIGHTGREY
+ BEAM_POLYMORPH, // DARKGREY
+ BEAM_CHARM, // LIGHTBLUE
+ BEAM_BANISH, // LIGHTGREEN
+ BEAM_DEGENERATE, // LIGHTCYAN
+ BEAM_ENSLAVE_UNDEAD, // LIGHTRED
+ BEAM_PAIN, // LIGHTMAGENTA
+ BEAM_DISPEL_UNDEAD, // YELLOW
+ BEAM_DISINTEGRATION, // WHITE
+ BEAM_ENSLAVE_DEMON, // colour "16"
+
+ // new beams for evaporate
+ BEAM_POTION_STINKING_CLOUD,
+ BEAM_POTION_POISON,
+ BEAM_POTION_MIASMA,
+ BEAM_POTION_STEAM,
+ BEAM_POTION_FIRE,
+ BEAM_POTION_COLD,
+ BEAM_POTION_BLACK_SMOKE,
+ BEAM_POTION_BLUE_SMOKE,
+ BEAM_POTION_PURP_SMOKE,
+ BEAM_POTION_RANDOM
+};
+
+enum BOOKS
+{
+ BOOK_MINOR_MAGIC_I, // 0
+ BOOK_MINOR_MAGIC_II,
+ BOOK_MINOR_MAGIC_III,
+ BOOK_CONJURATIONS_I,
+ BOOK_CONJURATIONS_II,
+ BOOK_FLAMES, // 5
+ BOOK_FROST,
+ BOOK_SUMMONINGS,
+ BOOK_FIRE,
+ BOOK_ICE,
+ BOOK_SURVEYANCES, // 10
+ BOOK_SPATIAL_TRANSLOCATIONS,
+ BOOK_ENCHANTMENTS,
+ BOOK_YOUNG_POISONERS,
+ BOOK_TEMPESTS,
+ BOOK_DEATH, // 15
+ BOOK_HINDERANCE,
+ BOOK_CHANGES,
+ BOOK_TRANSFIGURATIONS,
+ BOOK_PRACTICAL_MAGIC,
+ BOOK_WAR_CHANTS, // 20
+ BOOK_CLOUDS,
+ BOOK_HEALING,
+ BOOK_NECROMANCY,
+ BOOK_NECRONOMICON,
+ BOOK_CALLINGS, // 25
+ BOOK_CHARMS,
+ BOOK_DEMONOLOGY,
+ BOOK_AIR,
+ BOOK_SKY,
+ BOOK_DIVINATIONS, // 30
+ BOOK_WARP,
+ BOOK_ENVENOMATIONS,
+ BOOK_ANNIHILATIONS,
+ BOOK_UNLIFE,
+ BOOK_DESTRUCTION, // 35
+ BOOK_CONTROL,
+ BOOK_MUTATIONS,
+ BOOK_TUKIMA,
+ BOOK_GEOMANCY,
+ BOOK_EARTH, // 40
+ BOOK_MANUAL,
+ BOOK_WIZARDRY,
+ BOOK_POWER,
+ BOOK_CANTRIPS, //jmf: 04jan2000
+ BOOK_PARTY_TRICKS, // 45 //jmf: 04jan2000
+ BOOK_BEASTS,
+ BOOK_STALKING, // renamed -- assassination was confusing -- bwr
+ NUM_BOOKS
+};
+
+enum BRANCHES // you.where_are_you
+{
+ BRANCH_MAIN_DUNGEON, // 0
+ BRANCH_DIS,
+ BRANCH_GEHENNA,
+ BRANCH_VESTIBULE_OF_HELL,
+ BRANCH_COCYTUS,
+ BRANCH_TARTARUS, // 5
+ BRANCH_INFERNO, // unimplemented
+ BRANCH_THE_PIT, // 7 // unimplemented
+ BRANCH_ORCISH_MINES = 10, // 10
+ BRANCH_HIVE,
+ BRANCH_LAIR,
+ BRANCH_SLIME_PITS,
+ BRANCH_VAULTS,
+ BRANCH_CRYPT, // 15
+ BRANCH_HALL_OF_BLADES,
+ BRANCH_HALL_OF_ZOT,
+ BRANCH_ECUMENICAL_TEMPLE,
+ BRANCH_SNAKE_PIT,
+ BRANCH_ELVEN_HALLS, // 20
+ BRANCH_TOMB,
+ BRANCH_SWAMP
+};
+
+enum BRANCH_STAIRS // you.branch_stairs[] - 10 less than BRANCHES {dlb}
+{
+ STAIRS_ORCISH_MINES, // 0
+ STAIRS_HIVE,
+ STAIRS_LAIR,
+ STAIRS_SLIME_PITS,
+ STAIRS_VAULTS,
+ STAIRS_CRYPT, // 5
+ STAIRS_HALL_OF_BLADES,
+ STAIRS_HALL_OF_ZOT,
+ STAIRS_ECUMENICAL_TEMPLE,
+ STAIRS_SNAKE_PIT,
+ STAIRS_ELVEN_HALLS, // 10
+ STAIRS_TOMB,
+ STAIRS_SWAMP
+};
+
+enum BURDEN_STATES // you.burden_state
+{
+ BS_UNENCUMBERED, // 0
+ BS_ENCUMBERED = 2, // 2
+ BS_OVERLOADED = 5 // 5
+};
+
+enum CANNED_MESSAGES // canned_msg() - unsigned char
+{
+ MSG_SOMETHING_APPEARS, // 0
+ MSG_NOTHING_HAPPENS,
+ MSG_YOU_RESIST,
+ MSG_TOO_BERSERK,
+ MSG_NOTHING_CARRIED,
+ MSG_CANNOT_DO_YET,
+ MSG_OK,
+ MSG_UNTHINKING_ACT,
+ MSG_SPELL_FIZZLES,
+ MSG_HUH,
+ MSG_EMPTY_HANDED
+};
+
+enum CLOUD_TYPES // cloud_type[], place_cloud(), big_cloud()
+{
+ CLOUD_NONE, // 0
+ CLOUD_FIRE, // 1
+ CLOUD_STINK, // 2
+ CLOUD_COLD, // 3
+ CLOUD_POISON, // 4
+ CLOUD_GREY_SMOKE = 5, // 5: found 11jan2000 {dlb}
+ CLOUD_BLUE_SMOKE = 6, // 6: found 11jan2000 {dlb}
+ CLOUD_PURP_SMOKE = 7, // was: CLOUD_ENERGY and wrong 19jan2000 {dlb}
+ CLOUD_STEAM, // 8
+ CLOUD_MIASMA = 9, // 9: found 11jan2000 {dlb}
+ CLOUD_BLACK_SMOKE = 10, //was: CLOUD_STICKY_FLAME and wrong 19jan2000 {dlb}
+ CLOUD_DEBUGGING = 99, // 99: used once as 'nonexistent cloud' {dlb}
+// if env.cloud_type > 100, it is a monster's cloud {dlb}
+ CLOUD_FIRE_MON = 101, // 101: found 11jan2000 {dlb}
+ CLOUD_STINK_MON = 102, // 102: found 11jan2000 {dlb}
+ CLOUD_COLD_MON = 103, // 103: added 11jan2000 {dlb}
+ CLOUD_POISON_MON = 104, // 104
+ CLOUD_GREY_SMOKE_MON = 105, // 105: found 11jan2000 {dlb}
+ CLOUD_BLUE_SMOKE_MON = 106, // 106: found 11jan2000 {dlb}
+ CLOUD_PURP_SMOKE_MON = 107, // 107:
+ CLOUD_STEAM_MON = 108, // 108: added 11jan2000 {dlb}
+ CLOUD_MIASMA_MON = 109, // 109: added 11jan2000 {dlb}
+ CLOUD_BLACK_SMOKE_MON = 110 // 110: added 19jan2000 {dlb}
+};
+
+enum COMMANDS
+{
+ CMD_NO_CMD = 1000, // 1000
+ CMD_MOVE_NOWHERE,
+ CMD_MOVE_LEFT,
+ CMD_MOVE_DOWN,
+ CMD_MOVE_UP,
+ CMD_MOVE_RIGHT,
+ CMD_MOVE_UP_LEFT,
+ CMD_MOVE_DOWN_LEFT,
+ CMD_MOVE_UP_RIGHT,
+ CMD_MOVE_DOWN_RIGHT,
+ CMD_RUN_LEFT, // 1000 + 10
+ CMD_RUN_DOWN,
+ CMD_RUN_UP,
+ CMD_RUN_RIGHT,
+ CMD_RUN_UP_LEFT,
+ CMD_RUN_DOWN_LEFT,
+ CMD_RUN_UP_RIGHT,
+ CMD_RUN_DOWN_RIGHT,
+ CMD_OPEN_DOOR_LEFT,
+ CMD_OPEN_DOOR_DOWN,
+ CMD_OPEN_DOOR_UP, // 1000 + 20
+ CMD_OPEN_DOOR_RIGHT,
+ CMD_OPEN_DOOR_UP_LEFT,
+ CMD_OPEN_DOOR_DOWN_LEFT,
+ CMD_OPEN_DOOR_UP_RIGHT,
+ CMD_OPEN_DOOR_DOWN_RIGHT,
+ CMD_OPEN_DOOR,
+ CMD_CLOSE_DOOR,
+ CMD_REST,
+ CMD_GO_UPSTAIRS,
+ CMD_GO_DOWNSTAIRS, // 1000 + 30
+ CMD_TOGGLE_AUTOPICKUP,
+ CMD_PICKUP,
+ CMD_DROP,
+ CMD_BUTCHER,
+ CMD_INSPECT_FLOOR,
+ CMD_EXAMINE_OBJECT,
+ CMD_EVOKE,
+ CMD_WIELD_WEAPON,
+ CMD_WEAPON_SWAP,
+ CMD_THROW, // 1000 + 40
+ CMD_FIRE,
+ CMD_WEAR_ARMOUR,
+ CMD_REMOVE_ARMOUR,
+ CMD_WEAR_JEWELLERY,
+ CMD_REMOVE_JEWELLERY,
+ CMD_LIST_WEAPONS,
+ CMD_LIST_ARMOUR,
+ CMD_LIST_JEWELLERY,
+ CMD_ZAP_WAND,
+ CMD_CAST_SPELL, // 1000 + 50
+ CMD_MEMORISE_SPELL,
+ CMD_USE_ABILITY,
+ CMD_PRAY,
+ CMD_EAT,
+ CMD_QUAFF,
+ CMD_READ,
+ CMD_LOOK_AROUND,
+ CMD_SEARCH,
+ CMD_SHOUT,
+ CMD_DISARM_TRAP, // 1000 + 60
+ CMD_CHARACTER_DUMP,
+ CMD_DISPLAY_COMMANDS,
+ CMD_DISPLAY_INVENTORY,
+ CMD_DISPLAY_KNOWN_OBJECTS,
+ CMD_DISPLAY_MUTATIONS,
+ CMD_DISPLAY_SKILLS,
+ CMD_DISPLAY_MAP,
+ CMD_DISPLAY_OVERMAP,
+ CMD_DISPLAY_RELIGION,
+ CMD_DISPLAY_CHARACTER_STATUS, // 1000 + 70
+ CMD_EXPERIENCE_CHECK,
+ CMD_GET_VERSION,
+ CMD_ADJUST_INVENTORY,
+ CMD_REPLAY_MESSAGES,
+ CMD_REDRAW_SCREEN,
+ CMD_MACRO_ADD,
+ CMD_MACRO_SAVE,
+ CMD_SAVE_GAME,
+ CMD_SAVE_GAME_NOW,
+ CMD_SUSPEND_GAME, // 1000 + 80
+ CMD_QUIT,
+ CMD_WIZARD,
+ CMD_DESTROY_ITEM,
+ CMD_OBSOLETE_INVOKE
+};
+
+enum CONFIRM_LEVEL
+{
+ CONFIRM_NONE_EASY,
+ CONFIRM_SAFE_EASY,
+ CONFIRM_ALL_EASY
+};
+
+enum CORPSE_EFFECTS
+{
+ CE_NOCORPSE, // 0
+ CE_CLEAN, // 1
+ CE_CONTAMINATED, // 2
+ CE_POISONOUS, // 3
+ CE_HCL, // 4
+ CE_MUTAGEN_RANDOM, // 5
+ CE_MUTAGEN_GOOD, // 6 - may be worth implementing {dlb}
+ CE_MUTAGEN_BAD, // 7 - may be worth implementing {dlb}
+ CE_RANDOM, // 8 - not used, but may be worth implementing {dlb}
+ CE_ROTTEN = 50 // 50 - must remain at 50 for now {dlb}
+};
+
+enum CORPSES
+{
+ CORPSE_BODY, // 0
+ CORPSE_SKELETON
+};
+
+enum DEATH_KNIGHT_CHOICES
+{
+ DK_NO_SELECTION,
+ DK_NECROMANCY,
+ DK_YREDELEMNUL,
+ DK_RANDOM
+};
+
+enum DECKS
+{
+ DECK_OF_WONDERS, // 0
+ DECK_OF_SUMMONING,
+ DECK_OF_TRICKS,
+ DECK_OF_POWER,
+ DECK_OF_PUNISHMENT
+};
+
+enum DELAY
+{
+ DELAY_NOT_DELAYED,
+ DELAY_EAT,
+ DELAY_ARMOUR_ON,
+ DELAY_ARMOUR_OFF,
+ DELAY_MEMORIZE,
+ DELAY_BUTCHER,
+ DELAY_AUTOPICKUP,
+ DELAY_WEAPON_SWAP, // for easy_butcher
+ DELAY_PASSWALL,
+ DELAY_DROP_ITEM,
+ DELAY_ASCENDING_STAIRS,
+ DELAY_DESCENDING_STAIRS,
+ DELAY_INTERUPTABLE = 100, // simple interuptable delay
+ DELAY_UNINTERUPTABLE // simple uninteruptable delay
+};
+
+enum DEMON_BEAMS
+{
+ DMNBM_HELLFIRE, // 0
+ DMNBM_SMITING,
+ DMNBM_BRAIN_FEED,
+ DMNBM_MUTATION
+};
+
+enum DEMON_CLASSES // summon_any_demon()
+{
+ DEMON_LESSER, // 0: Class V
+ DEMON_COMMON, // 1: Class II-IV
+ DEMON_GREATER // 2: Class I
+};
+
+enum DESCRIPTION_LEVEL
+{
+ DESC_CAP_THE, // 0
+ DESC_NOCAP_THE, // 1
+ DESC_CAP_A, // 2
+ DESC_NOCAP_A, // 3
+ DESC_CAP_YOUR, // 4
+ DESC_NOCAP_YOUR, // 5
+ DESC_PLAIN, // 6
+ DESC_NOCAP_ITS, // 7
+ DESC_INVENTORY_EQUIP, // 8
+ DESC_INVENTORY // 8
+};
+
+enum DIRECTION // (unsigned char) you.char_direction
+{
+ DIR_DESCENDING = 0, // 0 - change and lose savefile compatibility (!!!)
+ DIR_ASCENDING = 1 // 1 - change and lose savefile compatibility (!!!)
+};
+
+enum DUNGEON_FEATURES // (unsigned char) grd[][]
+{
+ DNGN_UNSEEN, // 0
+ DNGN_ROCK_WALL,
+ DNGN_STONE_WALL,
+ DNGN_CLOSED_DOOR,
+ DNGN_METAL_WALL,
+ DNGN_SECRET_DOOR, // 5
+ DNGN_GREEN_CRYSTAL_WALL,
+ DNGN_ORCISH_IDOL,
+ DNGN_WAX_WALL, // 8
+ DNGN_PERMAROCK_WALL, // 9 - for undiggable walls
+ DNGN_LAST_SOLID_TILE = 10, // 10 - just here temporarily {dlb}
+
+ DNGN_LAVA_X = 11, // 11
+ DNGN_WATER_X, // 12
+ DNGN_SILVER_STATUE = 21, // 21
+ DNGN_GRANITE_STATUE,
+ DNGN_ORANGE_CRYSTAL_STATUE, // 23
+ DNGN_STATUE_39 = 39, // 39
+
+ DNGN_LAVA = 61, // 61
+ DNGN_DEEP_WATER, // 62
+ DNGN_SHALLOW_WATER = 65, // 65
+ DNGN_WATER_STUCK,
+
+ DNGN_FLOOR, // 67
+ DNGN_ENTER_HELL = 69, // 69
+ DNGN_OPEN_DOOR, // 70
+ DNGN_BRANCH_STAIRS, // 71
+ DNGN_TRAP_MECHANICAL = 75, // 75
+ DNGN_TRAP_MAGICAL,
+ DNGN_TRAP_III,
+ DNGN_UNDISCOVERED_TRAP, // 78
+
+ DNGN_ENTER_SHOP = 80, // 80
+ DNGN_ENTER_LABYRINTH,
+
+ DNGN_STONE_STAIRS_DOWN_I,
+ DNGN_STONE_STAIRS_DOWN_II,
+ DNGN_STONE_STAIRS_DOWN_III,
+ DNGN_ROCK_STAIRS_DOWN, // 85 - was this supposed to be a ladder? {dlb}
+
+ DNGN_STONE_STAIRS_UP_I,
+ DNGN_STONE_STAIRS_UP_II,
+ DNGN_STONE_STAIRS_UP_III,
+ DNGN_ROCK_STAIRS_UP, // 89 - was this supposed to be a ladder? {dlb}
+
+ DNGN_ENTER_DIS = 92, // 92
+ DNGN_ENTER_GEHENNA,
+ DNGN_ENTER_COCYTUS,
+ DNGN_ENTER_TARTARUS, // 95
+ DNGN_ENTER_ABYSS,
+ DNGN_EXIT_ABYSS,
+ DNGN_STONE_ARCH,
+ DNGN_ENTER_PANDEMONIUM,
+ DNGN_EXIT_PANDEMONIUM, // 100
+ DNGN_TRANSIT_PANDEMONIUM, // 101
+
+ DNGN_BUILDER_SPECIAL_WALL = 105, // 105; builder() only
+ DNGN_BUILDER_SPECIAL_FLOOR, // 106; builder() only
+
+ DNGN_ENTER_ORCISH_MINES = 110, // 110
+ DNGN_ENTER_HIVE,
+ DNGN_ENTER_LAIR,
+ DNGN_ENTER_SLIME_PITS,
+ DNGN_ENTER_VAULTS,
+ DNGN_ENTER_CRYPT, // 115
+ DNGN_ENTER_HALL_OF_BLADES,
+ DNGN_ENTER_ZOT,
+ DNGN_ENTER_TEMPLE,
+ DNGN_ENTER_SNAKE_PIT,
+ DNGN_ENTER_ELVEN_HALLS, // 120
+ DNGN_ENTER_TOMB,
+ DNGN_ENTER_SWAMP, // 122
+
+ DNGN_RETURN_FROM_ORCISH_MINES = 130, // 130
+ DNGN_RETURN_FROM_HIVE,
+ DNGN_RETURN_FROM_LAIR,
+ DNGN_RETURN_FROM_SLIME_PITS,
+ DNGN_RETURN_FROM_VAULTS,
+ DNGN_RETURN_FROM_CRYPT, // 135
+ DNGN_RETURN_FROM_HALL_OF_BLADES,
+ DNGN_RETURN_FROM_ZOT,
+ DNGN_RETURN_FROM_TEMPLE,
+ DNGN_RETURN_FROM_SNAKE_PIT,
+ DNGN_RETURN_FROM_ELVEN_HALLS, // 140
+ DNGN_RETURN_FROM_TOMB,
+ DNGN_RETURN_FROM_SWAMP, // 142
+
+ DNGN_ALTAR_ZIN = 180, // 180
+ DNGN_ALTAR_SHINING_ONE,
+ DNGN_ALTAR_KIKUBAAQUDGHA,
+ DNGN_ALTAR_YREDELEMNUL,
+ DNGN_ALTAR_XOM,
+ DNGN_ALTAR_VEHUMET, // 185
+ DNGN_ALTAR_OKAWARU,
+ DNGN_ALTAR_MAKHLEB,
+ DNGN_ALTAR_SIF_MUNA,
+ DNGN_ALTAR_TROG,
+ DNGN_ALTAR_NEMELEX_XOBEH, // 190
+ DNGN_ALTAR_ELYVILON, // 191
+
+ DNGN_BLUE_FOUNTAIN = 200, // 200
+ DNGN_DRY_FOUNTAIN_I,
+ DNGN_SPARKLING_FOUNTAIN, // aka 'Magic Fountain' {dlb}
+ DNGN_DRY_FOUNTAIN_II,
+ DNGN_DRY_FOUNTAIN_III,
+ DNGN_DRY_FOUNTAIN_IV, // 205
+ DNGN_DRY_FOUNTAIN_V,
+ DNGN_DRY_FOUNTAIN_VI,
+ DNGN_DRY_FOUNTAIN_VII,
+ DNGN_DRY_FOUNTAIN_VIII,
+ DNGN_PERMADRY_FOUNTAIN = 210 // added (from dungeon.cc/maps.cc) 22jan2000 {dlb}
+};
+
+enum DURATIONS // you.duration[]
+{
+ DUR_LIQUID_FLAMES, // 0
+ DUR_ICY_ARMOUR,
+ DUR_REPEL_MISSILES,
+ DUR_PRAYER,
+ DUR_REGENERATION,
+ DUR_SWIFTNESS, // 5
+ DUR_INSULATION,
+ DUR_STONEMAIL,
+ DUR_CONTROLLED_FLIGHT,
+ DUR_TELEPORT,
+ DUR_CONTROL_TELEPORT, // 10
+ DUR_RESIST_POISON,
+ DUR_BREATH_WEAPON,
+ DUR_TRANSFORMATION,
+ DUR_DEATH_CHANNEL,
+ DUR_DEFLECT_MISSILES, // 15
+//jmf: new durations:
+ DUR_FORESCRY,
+ DUR_SEE_INVISIBLE,
+ DUR_WEAPON_BRAND, // general "branding" spell counter
+ DUR_SILENCE,
+ DUR_GLAMOUR, // 20
+ DUR_SHUGGOTH_SEED_RELOAD,
+ DUR_INFECTED_SHUGGOTH_SEED,
+ DUR_CONDENSATION_SHIELD, // 23
+ DUR_STONESKIN,
+ DUR_REPEL_UNDEAD, // 25
+ DUR_LAST_DUR, //jmf: for asserts
+ NUM_DURATIONS = 30
+ // set at 30 to prevent savefile incompatibilities 12mar2000{dlb}
+};
+
+enum ENCHANTMENT // menv[].enchantment[]
+{
+ ENCH_NONE = 0, // 0
+ ENCH_SLOW,
+ ENCH_HASTE, // 2
+ ENCH_FEAR = 4, // 4
+ ENCH_CONFUSION, // 5
+ ENCH_INVIS,
+ ENCH_YOUR_POISON_I,
+ ENCH_YOUR_POISON_II,
+ ENCH_YOUR_POISON_III,
+ ENCH_YOUR_POISON_IV, // 10
+ ENCH_YOUR_SHUGGOTH_I, //jmf: Shuggothim!
+ ENCH_YOUR_SHUGGOTH_II,
+ ENCH_YOUR_SHUGGOTH_III,
+ ENCH_YOUR_SHUGGOTH_IV,
+ ENCH_YOUR_ROT_I, // 15 //jmf: rotting effect for monsters
+ ENCH_YOUR_ROT_II,
+ ENCH_YOUR_ROT_III,
+ ENCH_YOUR_ROT_IV,
+ ENCH_SUMMON = 19, // 19
+ ENCH_ABJ_I, // 20
+ ENCH_ABJ_II,
+ ENCH_ABJ_III,
+ ENCH_ABJ_IV,
+ ENCH_ABJ_V,
+ ENCH_ABJ_VI, // 25
+ ENCH_BACKLIGHT_I, //jmf: backlight for Corona spell
+ ENCH_BACKLIGHT_II,
+ ENCH_BACKLIGHT_III,
+ ENCH_BACKLIGHT_IV,
+ ENCH_CHARM = 30, // 30
+ ENCH_YOUR_STICKY_FLAME_I,
+ ENCH_YOUR_STICKY_FLAME_II,
+ ENCH_YOUR_STICKY_FLAME_III,
+ ENCH_YOUR_STICKY_FLAME_IV, // 34
+ ENCH_GLOWING_SHAPESHIFTER = 38, // 38
+ ENCH_SHAPESHIFTER,
+ ENCH_TP_I, // 40
+ ENCH_TP_II,
+ ENCH_TP_III,
+ ENCH_TP_IV, // 43
+ ENCH_POISON_I = 57, // 57
+ ENCH_POISON_II,
+ ENCH_POISON_III,
+ ENCH_POISON_IV, // 60
+ ENCH_STICKY_FLAME_I,
+ ENCH_STICKY_FLAME_II,
+ ENCH_STICKY_FLAME_III,
+ ENCH_STICKY_FLAME_IV,
+ ENCH_FRIEND_ABJ_I, // no longer used
+ ENCH_FRIEND_ABJ_II, // no longer used
+ ENCH_FRIEND_ABJ_III, // no longer used
+ ENCH_FRIEND_ABJ_IV, // no longer used
+ ENCH_FRIEND_ABJ_V, // no longer used
+ ENCH_FRIEND_ABJ_VI, // no longer used
+ ENCH_CREATED_FRIENDLY, // no longer used
+ ENCH_SLEEP_WARY,
+ ENCH_SUBMERGED, // 73 (includes air elementals in air)
+ ENCH_SHORT_LIVED, // 74 for ball lightning
+ NUM_ENCHANTMENTS
+};
+
+enum ENCHANT_STATS
+{
+ ENCHANT_TO_HIT,
+ ENCHANT_TO_DAM
+};
+
+enum EQUIPMENT
+{
+ EQ_WEAPON, // 0
+ EQ_CLOAK,
+ EQ_HELMET,
+ EQ_GLOVES,
+ EQ_BOOTS,
+ EQ_SHIELD, // 5
+ EQ_BODY_ARMOUR,
+ EQ_LEFT_RING,
+ EQ_RIGHT_RING,
+ EQ_AMULET,
+ NUM_EQUIP,
+
+ // these aren't actual equipment slots, they're categories for functions
+ EQ_STAFF = 100, // weapon with base_type OBJ_STAVES
+ EQ_RINGS, // check both rings
+ EQ_RINGS_PLUS, // check both rings and sum plus
+ EQ_RINGS_PLUS2, // check both rings and sum plus2
+ EQ_ALL_ARMOUR // check all armour types
+};
+
+enum FIRE_TYPES
+{
+ FIRE_NONE,
+ FIRE_LAUNCHER,
+ FIRE_DART,
+ FIRE_STONE,
+ FIRE_DAGGER,
+ FIRE_SPEAR,
+ FIRE_HAND_AXE,
+ FIRE_CLUB,
+ NUM_FIRE_TYPES
+};
+
+enum FLUSH_REASONS
+{
+ FLUSH_ON_FAILURE, // spell/ability failed to cast
+ FLUSH_BEFORE_COMMAND, // flush before getting a command
+ FLUSH_ON_MESSAGE, // flush when printing a message
+ NUM_FLUSH_REASONS
+};
+
+enum FOODS // mitm[].sub_type[]
+{
+ FOOD_MEAT_RATION, // 0
+ FOOD_BREAD_RATION,
+ FOOD_PEAR,
+ FOOD_APPLE,
+ FOOD_CHOKO,
+ FOOD_HONEYCOMB, // 5
+ FOOD_ROYAL_JELLY,
+ FOOD_SNOZZCUMBER,
+ FOOD_PIZZA,
+ FOOD_APRICOT,
+ FOOD_ORANGE, // 10
+ FOOD_BANANA,
+ FOOD_STRAWBERRY,
+ FOOD_RAMBUTAN,
+ FOOD_LEMON,
+ FOOD_GRAPE, // 15
+ FOOD_SULTANA,
+ FOOD_LYCHEE,
+ FOOD_BEEF_JERKY,
+ FOOD_CHEESE,
+ FOOD_SAUSAGE, // 20
+ FOOD_CHUNK,
+ NUM_FOODS
+};
+
+enum GENUS_PLAYER // see player::player_genus()
+{
+ GENPC_DRACONIAN, // 0
+ GENPC_ELVEN, // 1
+ GENPC_DWARVEN // 2
+};
+
+enum GENDER
+{
+ GENDER_NEUTER,
+ GENDER_MALE,
+ GENDER_FEMALE
+};
+
+enum GHOST_VALUES
+{
+ GVAL_MAX_HP, // 0
+ GVAL_EV,
+ GVAL_AC,
+ GVAL_SEE_INVIS,
+ GVAL_RES_FIRE,
+ GVAL_RES_COLD, // 5
+ GVAL_RES_ELEC,
+ GVAL_DAMAGE,
+ GVAL_BRAND,
+ GVAL_SPECIES,
+ GVAL_BEST_SKILL, // 10
+ GVAL_SKILL_LEVEL,
+ GVAL_EXP_LEVEL,
+ GVAL_CLASS,
+ GVAL_SPELL_1, // 14
+ GVAL_SPELL_2,
+ GVAL_SPELL_3,
+ GVAL_SPELL_4,
+ GVAL_SPELL_5,
+ GVAL_SPELL_6, // 19
+ NUM_GHOST_VALUES, // should always be last value
+
+ // these values are for demonlords, which override the above:
+ GVAL_DEMONLORD_SPELLCASTER = 9,
+ GVAL_DEMONLORD_FLY, // 10
+ GVAL_DEMONLORD_UNUSED, // 11
+ GVAL_DEMONLORD_HIT_DICE, // 12
+ GVAL_DEMONLORD_CYCLE_COLOUR // 13
+};
+
+enum GODS // you.religion
+{
+ GOD_NO_GOD, // 0
+ GOD_ZIN,
+ GOD_SHINING_ONE,
+ GOD_KIKUBAAQUDGHA,
+ GOD_YREDELEMNUL,
+ GOD_XOM, // 5
+ GOD_VEHUMET,
+ GOD_OKAWARU,
+ GOD_MAKHLEB,
+ GOD_SIF_MUNA,
+ GOD_TROG, // 10
+ GOD_NEMELEX_XOBEH,
+ GOD_ELYVILON,
+ NUM_GODS, // always after last god
+
+ GOD_RANDOM = 100
+};
+
+enum GOOD_THINGS
+{
+ GOOD_KILLED_LIVING = 1, // 1 - killed a living monster in god's name
+ GOOD_KILLED_UNDEAD, // 2 - killed an undead in god's name
+ GOOD_KILLED_DEMON, // 3 - killed a demon in god's name
+ GOOD_KILLED_ANGEL_I, // 4 - killed an angel (any time)
+ GOOD_KILLED_ANGEL_II, // 5 - killed an angel in god's name
+ // (all above pass HD of monster as pgain)
+ GOOD_HACKED_CORPSE, // 6 - hacked up a corpse in god's name
+ GOOD_OFFER_STUFF, // 7 - offered inanimate stuff at an altar
+ GOOD_OFFER_CORPSE, // as above,including at least one corpse
+ GOOD_SLAVES_KILL_LIVING,// 9 - undead slaves killed a living thing
+ GOOD_SERVANTS_KILL, // 10 - any servants kill anything
+ GOOD_CARDS, // 11 - cards (Nemelex)
+ GOOD_KILLED_WIZARD,
+ GOOD_KILLED_PRIEST,
+ GOOD_POISON,
+ GOOD_ATTACKED_FRIEND,
+ NUM_GOOD_THINGS
+};
+
+enum HANDS_REQUIRED
+{
+ HANDS_ONE_HANDED = 1, // 1
+ HANDS_TWO_HANDED,
+ HANDS_ONE_OR_TWO_HANDED
+};
+
+enum HELMET_TYPES // used in pluses2
+{
+ THELM_HELMET = 0x0000,
+ THELM_HELM = 0x0001,
+ THELM_CAP = 0x0002,
+ THELM_WIZARD_HAT = 0x0003,
+ THELM_NUM_TYPES = 4,
+
+ THELM_SPECIAL = 0x0004, // type used only for artefacts (mask, hat)
+ THELM_TYPE_MASK = 0x00ff,
+
+
+ THELM_DESC_PLAIN = 0x0000,
+ THELM_DESC_WINGED = 0x0100,
+ THELM_DESC_HORNED = 0x0200,
+ THELM_DESC_CRESTED = 0x0300,
+ THELM_DESC_PLUMED = 0x0400,
+ THELM_DESC_SPIKED = 0x0500,
+ THELM_DESC_VISORED = 0x0600,
+ THELM_DESC_JEWELLED = 0x0700,
+
+ THELM_DESC_MASK = 0xff00
+};
+
+#if 0
+enum HELMET_DESCRIPTIONS
+{
+ DHELM_WINGED = 1, // 1
+ DHELM_HORNED,
+ DHELM_CRESTED,
+ DHELM_PLUMED,
+ DHELM_SPIKED, // 5
+ DHELM_VISORED,
+ DHELM_JEWELLED
+};
+
+enum HELMET_TYPES // used in pluses2
+{
+ THELM_HELMET = 0,
+ THELM_HELM,
+ THELM_CAP,
+ THELM_WIZARD_HAT,
+ NUM_HELMET_TYPES,
+ THELM_SPECIAL // type used only for artefacts (mask, hat)
+};
+#endif
+
+enum BOOT_TYPES // used in pluses2
+{
+ TBOOT_BOOTS = 0,
+ TBOOT_NAGA_BARDING,
+ TBOOT_CENTAUR_BARDING,
+ NUM_BOOT_TYPES
+};
+
+
+enum HUNGER_STATES // you.hunger_state
+{
+ HS_RAVENOUS, // 0: not used within code, really
+ HS_STARVING,
+ HS_HUNGRY,
+ HS_SATIATED, // "not hungry" state
+ HS_FULL,
+ HS_ENGORGED // 5
+};
+
+enum ITEM_STATUS_FLAGS // per item flags: ie. ident status, cursed status
+{
+ ISFLAG_KNOW_CURSE = 0x00000001, // curse status
+ ISFLAG_KNOW_TYPE = 0x00000002, // artefact name, sub/special types
+ ISFLAG_KNOW_PLUSES = 0x00000004, // to hit/to dam/to AC/charges
+ ISFLAG_KNOW_PROPERTIES = 0x00000008, // know special artefact properties
+ ISFLAG_IDENT_MASK = 0x0000000F, // mask of all id related flags
+
+ // these three masks are of the minimal flags set upon using equipment:
+ ISFLAG_EQ_WEAPON_MASK = 0x0000000B, // mask of flags for weapon equip
+ ISFLAG_EQ_ARMOUR_MASK = 0x0000000F, // mask of flags for armour equip
+ ISFLAG_EQ_JEWELLERY_MASK = 0x0000000F, // mask of flags for known jewellery
+
+ ISFLAG_CURSED = 0x00000100, // cursed
+ ISFLAG_RESERVED_1 = 0x00000200, // reserved (re-curses on wield?)
+ ISFLAG_RESERVED_2 = 0x00000400, // reserved (heavy cursed?)
+ ISFLAG_RESERVED_3 = 0x00000800, // reserved (perma-cursed?)
+ ISFLAG_CURSE_MASK = 0x00000F00, // mask of all curse related flags
+
+ ISFLAG_RANDART = 0x00001000, // special value is seed
+ ISFLAG_UNRANDART = 0x00002000, // is an unrandart
+ ISFLAG_ARTEFACT_MASK = 0x00003000, // randart or unrandart
+
+ ISFLAG_NO_DESC = 0x00000000, // used for clearing these flags
+ ISFLAG_GLOWING = 0x00010000, // weapons or armour
+ ISFLAG_RUNED = 0x00020000, // weapons or armour
+ ISFLAG_EMBROIDERED_SHINY = 0x00040000, // armour: depends on sub-type
+ ISFLAG_COSMETIC_MASK = 0x00070000, // mask of cosmetic descriptions
+
+ ISFLAG_NO_RACE = 0x00000000, // used for clearing these flags
+ ISFLAG_ORCISH = 0x01000000, // low quality items
+ ISFLAG_DWARVEN = 0x02000000, // strong and robust items
+ ISFLAG_ELVEN = 0x04000000, // light and accurate items
+ ISFLAG_RACIAL_MASK = 0x07000000, // mask of racial equipment types
+
+ ISFLAG_DEBUG_MARK = 0x80000000 // used for testing item structure
+};
+
+enum ITEM_DESCRIPTIONS
+{
+ IDESC_WANDS,
+ IDESC_POTIONS,
+ IDESC_SCROLLS, // special field (like the others)
+ IDESC_RINGS,
+ IDESC_SCROLLS_II // pluses field
+};
+
+enum ITEM_MAKE_SPECIES // used only for race during creation
+{
+ MAKE_ITEM_ELVEN = 1,
+ MAKE_ITEM_DWARVEN = 2,
+ MAKE_ITEM_ORCISH = 3,
+
+ MAKE_ITEM_NO_RACE = 100,
+ MAKE_ITEM_RANDOM_RACE = 250
+};
+
+enum ITEM_TYPE_ID // used for first index of id[4][50]
+{
+ IDTYPE_WANDS = 0,
+ IDTYPE_SCROLLS,
+ IDTYPE_JEWELLERY,
+ IDTYPE_POTIONS
+};
+
+enum ITEM_TYPE_ID_STATE // used for values in id[4][50]
+{
+ ID_UNKNOWN_TYPE = 0,
+ ID_KNOWN_TYPE,
+ ID_TRIED_TYPE
+};
+
+enum JEWELLERY
+{
+ RING_REGENERATION, // 0
+ RING_PROTECTION,
+ RING_PROTECTION_FROM_FIRE,
+ RING_POISON_RESISTANCE,
+ RING_PROTECTION_FROM_COLD,
+ RING_STRENGTH, // 5
+ RING_SLAYING,
+ RING_SEE_INVISIBLE,
+ RING_INVISIBILITY,
+ RING_HUNGER,
+ RING_TELEPORTATION, // 10
+ RING_EVASION,
+ RING_SUSTAIN_ABILITIES,
+ RING_SUSTENANCE,
+ RING_DEXTERITY,
+ RING_INTELLIGENCE, // 15
+ RING_WIZARDRY,
+ RING_MAGICAL_POWER,
+ RING_LEVITATION,
+ RING_LIFE_PROTECTION,
+ RING_PROTECTION_FROM_MAGIC, // 20
+ RING_FIRE,
+ RING_ICE,
+ RING_TELEPORT_CONTROL, // 23
+ AMU_RAGE = 35, // 35
+ AMU_RESIST_SLOW,
+ AMU_CLARITY,
+ AMU_WARDING,
+ AMU_RESIST_CORROSION,
+ AMU_THE_GOURMAND, // 40
+ AMU_CONSERVATION,
+ AMU_CONTROLLED_FLIGHT,
+ AMU_INACCURACY,
+ AMU_RESIST_MUTATION,
+ NUM_JEWELLERY
+};
+
+enum JOB
+{
+ JOB_FIGHTER, // 0
+ JOB_WIZARD,
+ JOB_PRIEST,
+ JOB_THIEF,
+ JOB_GLADIATOR,
+ JOB_NECROMANCER, // 5
+ JOB_PALADIN,
+ JOB_ASSASSIN,
+ JOB_BERSERKER,
+ JOB_HUNTER,
+ JOB_CONJURER, // 10
+ JOB_ENCHANTER,
+ JOB_FIRE_ELEMENTALIST,
+ JOB_ICE_ELEMENTALIST,
+ JOB_SUMMONER,
+ JOB_AIR_ELEMENTALIST, // 15
+ JOB_EARTH_ELEMENTALIST,
+ JOB_CRUSADER,
+ JOB_DEATH_KNIGHT,
+ JOB_VENOM_MAGE,
+ JOB_CHAOS_KNIGHT, // 20
+ JOB_TRANSMUTER,
+ JOB_HEALER, // 22
+ JOB_QUITTER, // 23 -- this is job 'x', don't use
+ JOB_REAVER, // 24
+ JOB_STALKER, // 25
+ JOB_MONK,
+ JOB_WARPER,
+ JOB_WANDERER, // 23
+ NUM_JOBS, // always after the last job
+
+ JOB_UNKNOWN = 100
+};
+
+enum KILLBY
+{
+ KILLED_BY_MONSTER, // 0
+ KILLED_BY_POISON,
+ KILLED_BY_CLOUD,
+ KILLED_BY_BEAM, // 3
+ KILLED_BY_DEATHS_DOOR, // should be deprecated, but you never know {dlb}
+ KILLED_BY_LAVA, // 5
+ KILLED_BY_WATER,
+ KILLED_BY_STUPIDITY,
+ KILLED_BY_WEAKNESS,
+ KILLED_BY_CLUMSINESS,
+ KILLED_BY_TRAP, // 10
+ KILLED_BY_LEAVING,
+ KILLED_BY_WINNING,
+ KILLED_BY_QUITTING,
+ KILLED_BY_DRAINING,
+ KILLED_BY_STARVATION, // 15
+ KILLED_BY_FREEZING,
+ KILLED_BY_BURNING,
+ KILLED_BY_WILD_MAGIC,
+ KILLED_BY_XOM,
+ KILLED_BY_STATUE, // 20
+ KILLED_BY_ROTTING,
+ KILLED_BY_TARGETTING,
+ KILLED_BY_SPORE,
+ KILLED_BY_TSO_SMITING,
+ KILLED_BY_PETRIFICATION, // 25
+ KILLED_BY_SHUGGOTH,
+ KILLED_BY_SOMETHING,
+ KILLED_BY_FALLING_DOWN_STAIRS,
+ KILLED_BY_ACID,
+ NUM_KILLBY
+};
+
+enum KILLER // monster_die(), thing_thrown
+{
+ KILL_YOU = 1, // 1
+ KILL_MON,
+ KILL_YOU_MISSILE,
+ KILL_MON_MISSILE,
+ KILL_MISC, // 5
+ KILL_RESET // abjuration, etc.
+};
+
+#define YOU_KILL(x) ((x) == KILL_YOU || (x) == KILL_YOU_MISSILE)
+#define MON_KILL(x) ((x) == KILL_MON || (x) == KILL_MON_MISSILE)
+
+enum LEVEL_TYPES // you.level_type
+{
+ LEVEL_DUNGEON, // 0
+ LEVEL_LABYRINTH,
+ LEVEL_ABYSS,
+ LEVEL_PANDEMONIUM
+};
+
+enum LOAD_MODE
+{
+ LOAD_START_GAME,
+ LOAD_RESTART_GAME,
+ LOAD_ENTER_LEVEL
+};
+
+enum MAP_SECTIONS // see maps.cc and dungeon.cc {dlb}
+{
+ MAP_NORTH = 1, // 1
+ MAP_NORTHWEST,
+ MAP_NORTHEAST,
+ MAP_SOUTHWEST,
+ MAP_SOUTHEAST, // 5
+ MAP_ENCOMPASS,
+ MAP_NORTH_DIS
+};
+
+// if you mess with this list, you'll need to make changes in initfile.cc
+enum MESSAGE_CHANNEL
+{
+ MSGCH_PLAIN, // regular text
+ MSGCH_PROMPT, // various prompts
+ MSGCH_GOD, // god/religion (param is god)
+ MSGCH_DURATION, // effect down/warnings
+ MSGCH_DANGER, // serious life threats (ie very large HP attacks)
+ MSGCH_WARN, // much less serious threats
+ MSGCH_FOOD, // hunger notices
+ MSGCH_RECOVERY, // recovery from disease/stat/poison condition
+ MSGCH_TALK, // monster talk (param is monster type)
+ MSGCH_INTRINSIC_GAIN, // player level/stat/species-power gains
+ MSGCH_MUTATION, // player gain/lose mutations
+ MSGCH_MONSTER_SPELL, // monsters casting spells
+ MSGCH_MONSTER_ENCHANT,// monsters enchantments up and down
+ MSGCH_MONSTER_DAMAGE, // monster damage reports (param is level)
+ MSGCH_ROTTEN_MEAT, // messages about chunks/corpses becoming rotten
+ MSGCH_EQUIPMENT, // equipment listing messages
+ MSGCH_DIAGNOSTICS, // various diagnostic messages
+ NUM_MESSAGE_CHANNELS // always last
+};
+
+enum MESSAGE_COLOURS
+{
+ MSGCOL_BLACK = 0, // the order of these colours is important
+ MSGCOL_BLUE,
+ MSGCOL_GREEN,
+ MSGCOL_CYAN,
+ MSGCOL_RED,
+ MSGCOL_MAGENTA,
+ MSGCOL_BROWN,
+ MSGCOL_LIGHTGRAY,
+ MSGCOL_DARKGRAY,
+ MSGCOL_LIGHTBLUE,
+ MSGCOL_LIGHTGREEN,
+ MSGCOL_LIGHTCYAN,
+ MSGCOL_LIGHTMAGENTA,
+ MSGCOL_YELLOW,
+ MSGCOL_WHITE,
+ MSGCOL_DEFAULT, // use default colour
+ MSGCOL_ALTERNATE, // use secondary default colour scheme
+ MSGCOL_MUTED, // don't print messages
+ MSGCOL_PLAIN // same as plain channel
+};
+
+enum MISCELLANY // mitm[].sub_type
+{
+ MISC_BOTTLED_EFREET, // 0
+ MISC_CRYSTAL_BALL_OF_SEEING,
+ MISC_AIR_ELEMENTAL_FAN,
+ MISC_LAMP_OF_FIRE,
+ MISC_STONE_OF_EARTH_ELEMENTALS,
+ MISC_LANTERN_OF_SHADOWS, // 5
+ MISC_HORN_OF_GERYON,
+ MISC_BOX_OF_BEASTS,
+ MISC_DECK_OF_WONDERS,
+ MISC_DECK_OF_SUMMONINGS,
+ MISC_CRYSTAL_BALL_OF_ENERGY, // 10
+ MISC_EMPTY_EBONY_CASKET,
+ MISC_CRYSTAL_BALL_OF_FIXATION,
+ MISC_DISC_OF_STORMS,
+ MISC_RUNE_OF_ZOT,
+ MISC_DECK_OF_TRICKS, // 15
+ MISC_DECK_OF_POWER,
+ MISC_PORTABLE_ALTAR_OF_NEMELEX,
+ NUM_MISCELLANY // mv: used for random generation
+};
+
+enum MISSILES // (unsigned char)
+{
+ MI_STONE, // 0
+ MI_ARROW,
+ MI_BOLT,
+ MI_DART,
+ MI_NEEDLE,
+ MI_LARGE_ROCK, //jmf: it'd be nice to move MI_LARGE_ROCK to DEBRIS_ROCK
+ NUM_MISSILES,
+ MI_EGGPLANT
+};
+
+enum MON_TARG_MODE
+{
+ TARG_ANY,
+ TARG_ENEMY,
+ TARG_FRIEND,
+ TARG_NUM_MODES
+};
+
+enum MONSTERS // (int) menv[].type
+{
+ MONS_GIANT_ANT, // 0
+ MONS_GIANT_BAT,
+ MONS_CENTAUR,
+ MONS_RED_DEVIL,
+ MONS_ETTIN,
+ MONS_FUNGUS, // 5
+ MONS_GOBLIN,
+ MONS_HOUND,
+ MONS_IMP,
+ MONS_JACKAL,
+ MONS_KILLER_BEE, // 10
+ MONS_KILLER_BEE_LARVA,
+ MONS_MANTICORE,
+ MONS_NECROPHAGE,
+ MONS_ORC,
+ MONS_PHANTOM, // 15
+ MONS_QUASIT,
+ MONS_RAT,
+ MONS_SCORPION, // 18
+ //MONS_TUNNELING_WORM, // deprecated and now officially removed {dlb}
+ MONS_UGLY_THING = 20, // 20
+ MONS_FIRE_VORTEX,
+ MONS_WORM,
+ MONS_ABOMINATION_SMALL,
+ MONS_YELLOW_WASP,
+ MONS_ZOMBIE_SMALL, // 25
+ MONS_ANGEL,
+ MONS_GIANT_BEETLE,
+ MONS_CYCLOPS,
+ MONS_DRAGON,
+ MONS_TWO_HEADED_OGRE, // 30
+ MONS_FIEND,
+ MONS_GIANT_SPORE,
+ MONS_HOBGOBLIN,
+ MONS_ICE_BEAST,
+ MONS_JELLY, // 35
+ MONS_KOBOLD,
+ MONS_LICH,
+ MONS_MUMMY,
+ MONS_GUARDIAN_NAGA,
+ MONS_OGRE, // 40
+ MONS_PLANT,
+ MONS_QUEEN_BEE,
+ MONS_RAKSHASA,
+ MONS_SNAKE,
+ MONS_TROLL, // 45
+ MONS_UNSEEN_HORROR,
+ MONS_VAMPIRE,
+ MONS_WRAITH,
+ MONS_ABOMINATION_LARGE,
+ MONS_YAK, // 50
+ MONS_ZOMBIE_LARGE,
+ MONS_ORC_WARRIOR,
+ MONS_KOBOLD_DEMONOLOGIST,
+ MONS_ORC_WIZARD,
+ MONS_ORC_KNIGHT, // 55
+ //MONS_WORM_TAIL = 56, // deprecated and now officially removed {dlb}
+ MONS_WYVERN = 57, // 57
+ MONS_BIG_KOBOLD,
+ MONS_GIANT_EYEBALL,
+ MONS_WIGHT, // 60
+ MONS_OKLOB_PLANT,
+ MONS_WOLF_SPIDER,
+ MONS_SHADOW,
+ MONS_HUNGRY_GHOST,
+ MONS_EYE_OF_DRAINING, // 65
+ MONS_BUTTERFLY,
+ MONS_WANDERING_MUSHROOM,
+ MONS_EFREET,
+ MONS_BRAIN_WORM,
+ MONS_GIANT_ORANGE_BRAIN, // 70
+ MONS_BOULDER_BEETLE,
+ MONS_FLYING_SKULL,
+ MONS_HELL_HOUND,
+ MONS_MINOTAUR,
+ MONS_ICE_DRAGON, // 75
+ MONS_SLIME_CREATURE,
+ MONS_FREEZING_WRAITH,
+ MONS_RAKSHASA_FAKE,
+ MONS_GREAT_ORB_OF_EYES,
+ MONS_HELLION, // 80
+ MONS_ROTTING_DEVIL,
+ MONS_TORMENTOR,
+ MONS_REAPER,
+ MONS_SOUL_EATER,
+ MONS_HAIRY_DEVIL, // 85
+ MONS_ICE_DEVIL,
+ MONS_BLUE_DEVIL,
+ MONS_BEAST,
+ MONS_IRON_DEVIL, // 89
+ MONS_GLOWING_SHAPESHIFTER = 98, // 98
+ MONS_SHAPESHIFTER,
+ MONS_GIANT_MITE, // 100
+ MONS_STEAM_DRAGON,
+ MONS_VERY_UGLY_THING,
+ MONS_ORC_SORCERER,
+ MONS_HIPPOGRIFF,
+ MONS_GRIFFON, // 105
+ MONS_HYDRA,
+ MONS_SKELETON_SMALL,
+ MONS_SKELETON_LARGE,
+ MONS_HELL_KNIGHT,
+ MONS_NECROMANCER, // 110
+ MONS_WIZARD,
+ MONS_ORC_PRIEST,
+ MONS_ORC_HIGH_PRIEST,
+ MONS_HUMAN,
+ MONS_GNOLL, // 115
+ MONS_CLAY_GOLEM,
+ MONS_WOOD_GOLEM,
+ MONS_STONE_GOLEM,
+ MONS_IRON_GOLEM,
+ MONS_CRYSTAL_GOLEM, // 120
+ MONS_TOENAIL_GOLEM,
+ MONS_MOTTLED_DRAGON,
+ MONS_EARTH_ELEMENTAL,
+ MONS_FIRE_ELEMENTAL,
+ MONS_AIR_ELEMENTAL, // 125
+ MONS_ICE_FIEND,
+ MONS_SHADOW_FIEND,
+ MONS_BROWN_SNAKE,
+ MONS_GIANT_LIZARD,
+ MONS_SPECTRAL_WARRIOR, // 130
+ MONS_PULSATING_LUMP,
+ MONS_STORM_DRAGON,
+ MONS_YAKTAUR,
+ MONS_DEATH_YAK,
+ MONS_ROCK_TROLL, // 135
+ MONS_STONE_GIANT,
+ MONS_FLAYED_GHOST,
+ MONS_BUMBLEBEE,
+ MONS_REDBACK,
+ MONS_INSUBSTANTIAL_WISP, // 140
+ MONS_VAPOUR,
+ MONS_OGRE_MAGE,
+ MONS_SPINY_WORM,
+ MONS_DANCING_WEAPON,
+ MONS_TITAN, // 145
+ MONS_GOLDEN_DRAGON,
+ MONS_ELF,
+ MONS_LINDWURM,
+ MONS_ELEPHANT_SLUG,
+ MONS_WAR_DOG, // 150
+ MONS_GREY_RAT,
+ MONS_GREEN_RAT,
+ MONS_ORANGE_RAT,
+ MONS_BLACK_SNAKE,
+ MONS_SHEEP, // 155
+ MONS_GHOUL,
+ MONS_HOG,
+ MONS_GIANT_MOSQUITO,
+ MONS_GIANT_CENTIPEDE,
+ MONS_IRON_TROLL, // 160
+ MONS_NAGA,
+ MONS_FIRE_GIANT,
+ MONS_FROST_GIANT,
+ MONS_FIREDRAKE,
+ MONS_SHADOW_DRAGON, // 165
+ MONS_YELLOW_SNAKE,
+ MONS_GREY_SNAKE,
+ MONS_DEEP_TROLL,
+ MONS_GIANT_BLOWFLY,
+ MONS_RED_WASP, // 170
+ MONS_SWAMP_DRAGON,
+ MONS_SWAMP_DRAKE,
+ MONS_SOLDIER_ANT,
+ MONS_HILL_GIANT,
+ MONS_QUEEN_ANT, // 175
+ MONS_ANT_LARVA,
+ MONS_GIANT_FROG,
+ MONS_GIANT_BROWN_FROG,
+ MONS_SPINY_FROG,
+ MONS_BLINK_FROG, // 180
+ MONS_GIANT_COCKROACH,
+ MONS_SMALL_SNAKE, // 182
+ //jmf: new monsters
+ MONS_SHUGGOTH, //jmf: added for evil spells
+ MONS_WOLF, //jmf: added
+ MONS_WARG, //jmf: added for orc mines
+ MONS_BEAR, //jmf: added bears!
+ MONS_GRIZZLY_BEAR,
+ MONS_POLAR_BEAR,
+ MONS_BLACK_BEAR, // 189
+ MONS_SIMULACRUM_SMALL,
+ MONS_SIMULACRUM_LARGE,
+ //jmf: end new monsters
+ MONS_WHITE_IMP = 220, // 220
+ MONS_LEMURE,
+ MONS_UFETUBUS,
+ MONS_MANES,
+ MONS_MIDGE,
+ MONS_NEQOXEC, // 225
+ MONS_ORANGE_DEMON,
+ MONS_HELLWING,
+ MONS_SMOKE_DEMON,
+ MONS_YNOXINUL,
+ MONS_EXECUTIONER, // 230
+ MONS_GREEN_DEATH,
+ MONS_BLUE_DEATH,
+ MONS_BALRUG,
+ MONS_CACODEMON,
+ MONS_DEMONIC_CRAWLER, // 235
+ MONS_SUN_DEMON,
+ MONS_SHADOW_IMP,
+ MONS_SHADOW_DEMON,
+ MONS_LOROCYPROCA,
+ MONS_SHADOW_WRAITH, // 240
+ MONS_GIANT_AMOEBA,
+ MONS_GIANT_SLUG,
+ MONS_GIANT_SNAIL,
+ MONS_SPATIAL_VORTEX,
+ MONS_PIT_FIEND, // 245
+ MONS_BORING_BEETLE,
+ MONS_GARGOYLE,
+ MONS_METAL_GARGOYLE,
+ MONS_MOLTEN_GARGOYLE,
+ MONS_PROGRAM_BUG, // 250
+// BCR - begin first batch of uniques.
+ MONS_MNOLEG,
+ MONS_LOM_LOBON,
+ MONS_CEREBOV,
+ MONS_GLOORX_VLOQ, // 254
+ MONS_MOLLUSC_LORD, // 255 - deprecated, but still referenced in code {dlb}
+// BCR - End first batch of uniques.
+ MONS_NAGA_MAGE = 260, // 260
+ MONS_NAGA_WARRIOR,
+ MONS_ORC_WARLORD,
+ MONS_DEEP_ELF_SOLDIER,
+ MONS_DEEP_ELF_FIGHTER,
+ MONS_DEEP_ELF_KNIGHT, // 265
+ MONS_DEEP_ELF_MAGE,
+ MONS_DEEP_ELF_SUMMONER,
+ MONS_DEEP_ELF_CONJURER,
+ MONS_DEEP_ELF_PRIEST,
+ MONS_DEEP_ELF_HIGH_PRIEST, // 270
+ MONS_DEEP_ELF_DEMONOLOGIST,
+ MONS_DEEP_ELF_ANNIHILATOR,
+ MONS_DEEP_ELF_SORCERER,
+ MONS_DEEP_ELF_DEATH_MAGE,
+ MONS_BROWN_OOZE, // 275
+ MONS_AZURE_JELLY,
+ MONS_DEATH_OOZE,
+ MONS_ACID_BLOB,
+ MONS_ROYAL_JELLY,
+// BCR - begin second batch of uniques.
+ MONS_TERENCE, // 280
+ MONS_JESSICA,
+ MONS_IJYB,
+ MONS_SIGMUND,
+ MONS_BLORK_THE_ORC,
+ MONS_EDMUND, // 285
+ MONS_PSYCHE,
+ MONS_EROLCHA,
+ MONS_DONALD,
+ MONS_URUG,
+ MONS_MICHAEL, // 290
+ MONS_JOSEPH,
+ MONS_SNORG, // was Anita - Snorg is correct 16jan2000 {dlb}
+ MONS_ERICA,
+ MONS_JOSEPHINE,
+ MONS_HAROLD, // 295
+ MONS_NORBERT,
+ MONS_JOZEF,
+ MONS_AGNES,
+ MONS_MAUD,
+ MONS_LOUISE, // 300
+ MONS_FRANCIS,
+ MONS_FRANCES,
+ MONS_RUPERT,
+ MONS_WAYNE,
+ MONS_DUANE, // 305
+ MONS_XTAHUA,
+ MONS_NORRIS,
+ MONS_ADOLF,
+ MONS_MARGERY,
+ MONS_BORIS, // 310
+// BCR - end second batch of uniques.
+
+ // The Lords of Hell:
+ MONS_GERYON = 340, // 340
+ MONS_DISPATER,
+ MONS_ASMODEUS,
+ MONS_ANTAEUS,
+ MONS_ERESHKIGAL, // 344
+
+ MONS_ANCIENT_LICH = 356, // 356
+ MONS_OOZE, // 357
+
+ MONS_VAULT_GUARD = 360, // 360
+ MONS_CURSE_SKULL,
+ MONS_VAMPIRE_KNIGHT,
+ MONS_VAMPIRE_MAGE,
+ MONS_SHINING_EYE,
+ MONS_ORB_GUARDIAN, // 365
+ MONS_DAEVA,
+ MONS_SPECTRAL_THING,
+ MONS_GREATER_NAGA,
+ MONS_SKELETAL_DRAGON,
+ MONS_TENTACLED_MONSTROSITY, // 370
+ MONS_SPHINX,
+ MONS_ROTTING_HULK,
+ MONS_GUARDIAN_MUMMY,
+ MONS_GREATER_MUMMY,
+ MONS_MUMMY_PRIEST, // 375
+ MONS_CENTAUR_WARRIOR,
+ MONS_YAKTAUR_CAPTAIN,
+ MONS_KILLER_KLOWN,
+ MONS_ELECTRIC_GOLEM, // replacing the guardian robot -- bwr
+ MONS_BALL_LIGHTNING, // replacing the dorgi -- bwr
+ MONS_ORB_OF_FIRE, // Swords renamed to fit -- bwr
+ MONS_QUOKKA, // Quokka are a type of wallaby, returned -- bwr 382
+
+
+ MONS_EYE_OF_DEVASTATION = 385, // 385
+ MONS_MOTH_OF_WRATH,
+ MONS_DEATH_COB,
+ MONS_CURSE_TOE,
+ MONS_GOLD_MIMIC,
+ MONS_WEAPON_MIMIC, // 390
+ MONS_ARMOUR_MIMIC,
+ MONS_SCROLL_MIMIC,
+ MONS_POTION_MIMIC,
+ MONS_HELL_HOG,
+ MONS_SERPENT_OF_HELL, // 395
+ MONS_BOGGART,
+ MONS_QUICKSILVER_DRAGON,
+ MONS_IRON_DRAGON,
+ MONS_SKELETAL_WARRIOR, // 399
+ MONS_PLAYER_GHOST, // 400
+ MONS_PANDEMONIUM_DEMON, // 401
+
+ MONS_GIANT_NEWT, // 402
+ MONS_GIANT_GECKO, // 403
+ MONS_GIANT_IGUANA, // 404
+ MONS_GILA_MONSTER, // 405
+ MONS_KOMODO_DRAGON, // 406
+
+ // Lava monsters:
+ MONS_LAVA_WORM = 420, // 420
+ MONS_LAVA_FISH,
+ MONS_LAVA_SNAKE,
+ MONS_SALAMANDER, // 423 mv: was another lava thing
+
+ // Water monsters:
+ MONS_BIG_FISH = 430, // 430
+ MONS_GIANT_GOLDFISH,
+ MONS_ELECTRICAL_EEL,
+ MONS_JELLYFISH,
+ MONS_WATER_ELEMENTAL,
+ MONS_SWAMP_WORM, // 435
+
+ NUM_MONSTERS, // used for polymorph
+ RANDOM_MONSTER = 1000, // used to distinguish between a random monster and using program bugs for error trapping {dlb}
+ WANDERING_MONSTER = 2500 // only used in monster placement routines - forced limit checks {dlb}
+
+};
+
+enum MONSTER_BEHAVIOUR // create_monster()
+{
+ BEH_SLEEP, // 0
+ BEH_WANDER,
+ BEH_SEEK,
+ BEH_FLEE,
+ BEH_CORNERED,
+ NUM_BEHAVIOURS, // max # of legal states
+ BEH_CHARMED, // hostile-but-charmed; create only
+ BEH_FRIENDLY, // used during creation only
+ BEH_HOSTILE, // creation only
+ BEH_GOD_GIFT // creation only
+};
+
+enum MONSTER_ATTITUDES
+{
+ ATT_HOSTILE, // 0, default in most cases
+ ATT_FRIENDLY, // created friendly (or tamed?)
+ ATT_NEUTRAL
+};
+
+enum MONSTER_EVENTS
+{
+ ME_EVAL, // 0, evaluate monster AI state
+ ME_DISTURB, // noisy
+ ME_ANNOY, // annoy at range
+ ME_ALERT, // alert to presence
+ ME_WHACK, // physical attack
+ ME_SCARE, // frighten monster
+ ME_CORNERED // cannot flee
+};
+
+#if 0
+// Obsolete... use mons_charclass()
+enum MONSTER_CATEGORIES
+{
+ MC_MIMIC, // 0
+ NUM_MC,
+ MC_UNSPECIFIED = 255 // keep at end !!! mind the upper limit of 255 {dlb}
+};
+#endif
+
+// Note: These are currently stored in chars!!!
+// Need to fix struct monsters and the savefile if you want more.
+enum MONSTER_FLAGS
+{
+ MF_CREATED_FRIENDLY = 0x01, // no benefit from killing
+ MF_GOD_GIFT = 0x02, // player not penalized by its death
+ MF_BATTY = 0x04, // flutters like a bat
+ MF_JUST_SUMMONED = 0x08, // monster skips next available action
+ MF_TAKING_STAIRS = 0x10, // is following player through stairs
+
+ MF_UNUSED_I = 0x20,
+ MF_UNUSED_II = 0x40,
+ MF_UNUSED_III = 0x80
+};
+
+enum MONSTER_DAMAGE
+{
+ MDAM_OKAY,
+ MDAM_LIGHTLY_DAMAGED,
+ MDAM_MODERATELY_DAMAGED,
+ MDAM_HEAVILY_DAMAGED,
+ MDAM_HORRIBLY_DAMAGED,
+ MDAM_ALMOST_DEAD,
+ MDAM_DEAD
+};
+
+enum MONSTER_DESCRIPTORS // things that cross categorical lines {dlb}
+{
+ MDSC_LEAVES_HIDE, // 0
+ MDSC_REGENERATES,
+ MDSC_NOMSG_WOUNDS
+};
+
+enum MONSTER_HOLINESS // matches (char) H_foo in mon-util.h, see: monster_holiness()
+{
+ MH_HOLY, // 0 - was -1
+ MH_NATURAL, // 1 - was 0
+ MH_UNDEAD, // 2 - was 1
+ MH_DEMONIC, // 3 - was 2
+ MH_NONLIVING, // golems and other constructs
+ MH_PLANT // plants
+};
+
+enum MONSTER_INVENTORY_SLOTS // (int) menv[].inv[]
+{
+ MSLOT_WEAPON,
+ MSLOT_MISSILE, // although it is a second weapon for MONS_TWO_HEADED_OGRE - how to reconcile cleanly? {dlb}
+ MSLOT_ARMOUR,
+ MSLOT_MISCELLANY, //mv: used for misc. obj. (7 Aug 2001)
+ MSLOT_POTION, // mv: now used only for potions (7 Aug 2001)
+ MSLOT_WAND, //
+ MSLOT_SCROLL,
+ MSLOT_GOLD, //mv: used for money :) (7 Aug 2001)
+ NUM_MONSTER_SLOTS = 8 // value must remain 8 for savefile compatibility {dlb}
+};
+
+enum MONSTER_ITEM_USE
+{
+ MONUSE_NOTHING,
+ MONUSE_EATS_ITEMS,
+ MONUSE_OPEN_DOORS,
+ MONUSE_STARTING_EQUIPMENT,
+ MONUSE_WEAPONS_ARMOUR
+};
+
+enum MONSTER_SPELLS // mons_cast(), mspell_list[], mons_spells()
+{
+ MS_MMISSILE, // 0
+ MS_FLAME,
+ MS_FROST,
+ MS_PARALYSIS,
+ MS_SLOW,
+ MS_HASTE, // 5
+ MS_CONFUSE, // 6 - do not deprecate!!! 13jan2000 {dlb}
+ MS_VENOM_BOLT,
+ MS_FIRE_BOLT,
+ MS_COLD_BOLT,
+ MS_LIGHTNING_BOLT, // 10
+ MS_INVIS,
+ MS_FIREBALL,
+ MS_HEAL,
+ MS_TELEPORT,
+ MS_TELEPORT_OTHER, // 15
+ MS_BLINK,
+ MS_CRYSTAL_SPEAR,
+ MS_DIG,
+ MS_NEGATIVE_BOLT,
+ MS_HELLFIRE_BURST, // 20
+ MS_VAMPIRE_SUMMON,
+ MS_ORB_ENERGY,
+ MS_BRAIN_FEED,
+ MS_LEVEL_SUMMON,
+ MS_FAKE_RAKSHASA_SUMMON, // 25
+ MS_STEAM_BALL,
+ MS_SUMMON_DEMON,
+ MS_ANIMATE_DEAD,
+ MS_PAIN,
+ MS_SMITE, // 30
+ MS_STICKY_FLAME,
+ MS_POISON_BLAST,
+ MS_SUMMON_DEMON_LESSER,
+ MS_SUMMON_UFETUBUS,
+ MS_PURPLE_BLAST, // 35
+ MS_SUMMON_BEAST, // MS_GERYON was not descriptive - renamed 13jan2000 {dlb}
+ MS_ENERGY_BOLT,
+ MS_STING,
+ MS_IRON_BOLT,
+ MS_STONE_ARROW, // 40
+ MS_POISON_SPLASH,
+ MS_SUMMON_UNDEAD,
+ MS_MUTATION, // 43
+ MS_CANTRIP,
+ MS_DISINTEGRATE, // 45
+ MS_MARSH_GAS,
+ MS_QUICKSILVER_BOLT,
+ MS_TORMENT,
+ MS_HELLFIRE,
+ MS_METAL_SPLINTERS, // 50
+ MS_SUMMON_DEMON_GREATER, // [foo]_1 was confusing - renamed 13jan2000 {dlb}
+ MS_BANISHMENT,
+ NUM_MONSTER_SPELLS,
+ MS_NO_SPELL = 100
+};
+
+// XXX: These still need to be applied in mon-data.h
+enum MONSTER_SPELL_TEMPLATES
+{
+ MST_ORC_WIZARD_I = 0,
+ MST_ORC_WIZARD_II,
+ MST_ORC_WIZARD_III,
+ MST_GUARDIAN_NAGA = 10,
+ MST_LICH_I = 20,
+ MST_LICH_II,
+ MST_LICH_III,
+ MST_LICH_IV,
+ MST_BURNING_DEVIL = 30,
+ MST_VAMPIRE = 40,
+ MST_VAMPIRE_KNIGHT,
+ MST_VAMPIRE_MAGE,
+ MST_EFREET = 50,
+ MST_BRAIN_WORM = 52,
+ MST_GIANT_ORANGE_BRAIN,
+ MST_RAKSHASA,
+ MST_GREAT_ORB_OF_EYES, // 55
+ MST_ORC_SORCERER,
+ MST_STEAM_DRAGON,
+ MST_HELL_KNIGHT_I,
+ MST_HELL_KNIGHT_II,
+ MST_NECROMANCER_I, // 60
+ MST_NECROMANCER_II,
+ MST_WIZARD_I,
+ MST_WIZARD_II,
+ MST_WIZARD_III,
+ MST_WIZARD_IV, // 65
+ MST_WIZARD_V,
+ MST_ORC_PRIEST,
+ MST_ORC_HIGH_PRIEST,
+ MST_MOTTLED_DRAGON,
+ MST_ICE_FIEND, // 70
+ MST_SHADOW_FIEND,
+ MST_TORMENTOR,
+ MST_STORM_DRAGON,
+ MST_WHITE_IMP,
+ MST_YNOXINUL, // 75
+ MST_NEQOXEC,
+ MST_HELLWING,
+ MST_SMOKE_DEMON,
+ MST_CACODEMON,
+ MST_GREEN_DEATH, // 80
+ MST_BALRUG,
+ MST_BLUE_DEATH,
+ MST_GERYON,
+ MST_DISPATER,
+ MST_ASMODEUS, // 85
+ MST_ERESHKIGAL,
+ MST_ANTAEUS, // 87
+ MST_MNOLEG = 90,
+ MST_LOM_LOBON,
+ MST_CEREBOV,
+ MST_GLOORX_VLOQ,
+ MST_TITAN,
+ MST_GOLDEN_DRAGON, // 95
+ MST_DEEP_ELF_SUMMONER,
+ MST_DEEP_ELF_CONJURER_I,
+ MST_DEEP_ELF_CONJURER_II,
+ MST_DEEP_ELF_PRIEST,
+ MST_DEEP_ELF_HIGH_PRIEST, // 100
+ MST_DEEP_ELF_DEMONOLOGIST,
+ MST_DEEP_ELF_ANNIHILATOR,
+ MST_DEEP_ELF_SORCERER,
+ MST_DEEP_ELF_DEATH_MAGE,
+ MST_KOBOLD_DEMONOLOGIST, // 105
+ MST_NAGA,
+ MST_NAGA_MAGE,
+ MST_CURSE_SKULL,
+ MST_SHINING_EYE,
+ MST_FROST_GIANT, // 110
+ MST_ANGEL,
+ MST_DAEVA,
+ MST_SHADOW_DRAGON,
+ MST_SPHINX,
+ MST_MUMMY, // 115
+ MST_ELECTRIC_GOLEM,
+ MST_ORB_OF_FIRE,
+ MST_SHADOW_IMP,
+ MST_GHOST,
+ MST_HELL_HOG, // 120
+ MST_SWAMP_DRAGON,
+ MST_SWAMP_DRAKE,
+ MST_SERPENT_OF_HELL,
+ MST_BOGGART,
+ MST_EYE_OF_DEVASTATION, // 125
+ MST_QUICKSILVER_DRAGON,
+ MST_IRON_DRAGON, // 127
+ MST_SKELETAL_WARRIOR,
+ NUM_MSTYPES,
+ MST_NO_SPELLS = 250
+};
+
+enum MUTATIONS
+{
+ MUT_TOUGH_SKIN, // 0
+ MUT_STRONG,
+ MUT_CLEVER,
+ MUT_AGILE,
+ MUT_GREEN_SCALES,
+ MUT_BLACK_SCALES, // 5
+ MUT_GREY_SCALES,
+ MUT_BONEY_PLATES,
+ MUT_REPULSION_FIELD,
+ MUT_POISON_RESISTANCE,
+ MUT_CARNIVOROUS, // 10
+ MUT_HERBIVOROUS,
+ MUT_HEAT_RESISTANCE,
+ MUT_COLD_RESISTANCE,
+ MUT_SHOCK_RESISTANCE,
+ MUT_REGENERATION, // 15
+ MUT_FAST_METABOLISM,
+ MUT_SLOW_METABOLISM,
+ MUT_WEAK,
+ MUT_DOPEY,
+ MUT_CLUMSY, // 20
+ MUT_TELEPORT_CONTROL,
+ MUT_TELEPORT,
+ MUT_MAGIC_RESISTANCE,
+ MUT_FAST,
+ MUT_ACUTE_VISION, // 25
+ MUT_DEFORMED,
+ MUT_TELEPORT_AT_WILL,
+ MUT_SPIT_POISON,
+ MUT_MAPPING,
+ MUT_BREATHE_FLAMES, // 30
+ MUT_BLINK,
+ MUT_HORNS,
+ MUT_STRONG_STIFF,
+ MUT_FLEXIBLE_WEAK,
+ MUT_LOST, // 35
+ MUT_CLARITY,
+ MUT_BERSERK,
+ MUT_DETERIORATION,
+ MUT_BLURRY_VISION,
+ MUT_MUTATION_RESISTANCE, // 40
+ MUT_FRAIL,
+ MUT_ROBUST,
+ MUT_TORMENT_RESISTANCE,
+ MUT_NEGATIVE_ENERGY_RESISTANCE,
+ MUT_SUMMON_MINOR_DEMONS, // 45
+ MUT_SUMMON_DEMONS,
+ MUT_HURL_HELLFIRE,
+ MUT_CALL_TORMENT,
+ MUT_RAISE_DEAD,
+ MUT_CONTROL_DEMONS, // 50
+ MUT_PANDEMONIUM,
+ MUT_DEATH_STRENGTH,
+ MUT_CHANNEL_HELL,
+ MUT_DRAIN_LIFE,
+ MUT_THROW_FLAMES, // 55
+ MUT_THROW_FROST,
+ MUT_SMITE, // 57
+ MUT_CLAWS, //jmf: added
+ MUT_HOOVES, //jmf: etc.
+ MUT_BREATHE_POISON, // 60
+ MUT_STINGER,
+ MUT_BIG_WINGS,
+ MUT_BLUE_MARKS, // 63 - decorative, as in "mark of the devil"
+ MUT_GREEN_MARKS, // 64
+ MUT_RED_SCALES = 70, // 70
+ MUT_NACREOUS_SCALES,
+ MUT_GREY2_SCALES,
+ MUT_METALLIC_SCALES,
+ MUT_BLACK2_SCALES,
+ MUT_WHITE_SCALES, // 75
+ MUT_YELLOW_SCALES,
+ MUT_BROWN_SCALES,
+ MUT_BLUE_SCALES,
+ MUT_PURPLE_SCALES,
+ MUT_SPECKLED_SCALES, // 80
+ MUT_ORANGE_SCALES,
+ MUT_INDIGO_SCALES,
+ MUT_RED2_SCALES,
+ MUT_IRIDESCENT_SCALES,
+ MUT_PATTERNED_SCALES, // 85
+ NUM_MUTATIONS
+};
+
+enum NAUGHTY_THINGS
+{
+ NAUGHTY_NECROMANCY = 1, // 1 - using necromancy (spell or device)
+ NAUGHTY_UNHOLY, // 2 - using unholy stuff (call imp, summon things)
+ NAUGHTY_KILLING, // 3 - killing in the name of a peaceful deity
+ NAUGHTY_ATTACK_HOLY, // 4 - attacking holy things
+ NAUGHTY_ATTACK_FRIEND, // 5 - attacking friendly things
+ NAUGHTY_FRIEND_DIES, // 6 - allowing friendly things to die
+ NAUGHTY_BUTCHER, // 7 - butchering in the name of a peaceful deity
+ NAUGHTY_STABBING, // 8 - stabbing
+ NAUGHTY_SPELLCASTING, // 9 - spellcasting
+ NAUGHTY_POISON, // 10 - poisoning
+ NAUGHTY_STIMULANTS, //jmf: next three new, some not yet used
+ NAUGHTY_ATE_MEAT,
+ NAUGHTY_CREATED_LIFE,
+ NUM_NAUGHTY_THINGS
+};
+
+enum OBJECT_CLASSES // (unsigned char) mitm[].base_type
+{
+ OBJ_WEAPONS, // 0
+ OBJ_MISSILES,
+ OBJ_ARMOUR,
+ OBJ_WANDS,
+ OBJ_FOOD, // 4
+ OBJ_UNKNOWN_I = 5, // (use unknown) labeled as books in invent.cc {dlb}
+ OBJ_SCROLLS = 6, // 6
+ OBJ_JEWELLERY,
+ OBJ_POTIONS, // 8
+ OBJ_UNKNOWN_II = 9, // (use unknown, stackable) labeled as gems in invent.cc {dlb}
+ OBJ_BOOKS = 10, // 10
+ OBJ_STAVES,
+ OBJ_ORBS,
+ OBJ_MISCELLANY,
+ OBJ_CORPSES,
+ OBJ_GOLD, // important role as upper limit to chardump::dump_inventory() {dlb}
+ OBJ_GEMSTONES, // found in itemname.cc, labeled as miscellaneous in invent.cc {dlb}
+ NUM_OBJECT_CLASSES,
+ OBJ_UNASSIGNED = 100, // must remain set to 100 {dlb}
+ OBJ_RANDOM = 255 // must remain set to 255 {dlb} - also used
+ // for blanket random sub_type .. see dungeon::items()
+};
+
+enum ORBS
+{
+ ORB_ZOT // 0
+};
+
+enum POTIONS
+{
+ POT_HEALING, // 0
+ POT_HEAL_WOUNDS,
+ POT_SPEED,
+ POT_MIGHT,
+ POT_GAIN_STRENGTH,
+ POT_GAIN_DEXTERITY, // 5
+ POT_GAIN_INTELLIGENCE,
+ POT_LEVITATION,
+ POT_POISON,
+ POT_SLOWING,
+ POT_PARALYSIS, // 10
+ POT_CONFUSION,
+ POT_INVISIBILITY,
+ POT_PORRIDGE,
+ POT_DEGENERATION,
+ POT_DECAY, // 15
+ POT_WATER,
+ POT_EXPERIENCE,
+ POT_MAGIC,
+ POT_RESTORE_ABILITIES,
+ POT_STRONG_POISON, // 20
+ POT_BERSERK_RAGE,
+ POT_CURE_MUTATION,
+ POT_MUTATION,
+ NUM_POTIONS
+};
+
+enum PRONOUN_TYPE
+{
+ PRONOUN_CAP, // 0
+ PRONOUN_NOCAP, // 1
+ PRONOUN_CAP_POSSESSIVE, // 2
+ PRONOUN_NOCAP_POSSESSIVE, // 3
+ PRONOUN_REFLEXIVE // 4 (reflexive is always lowercase)
+};
+
+enum PROXIMITY // proximity to player to create monster
+{
+ PROX_ANYWHERE,
+ PROX_CLOSE_TO_PLAYER,
+ PROX_AWAY_FROM_PLAYER,
+ PROX_NEAR_STAIRS
+};
+
+enum RANDART_PROP
+{
+ RAP_BRAND, // 0
+ RAP_AC,
+ RAP_EVASION,
+ RAP_STRENGTH,
+ RAP_INTELLIGENCE,
+ RAP_DEXTERITY, // 5
+ RAP_FIRE,
+ RAP_COLD,
+ RAP_ELECTRICITY,
+ RAP_POISON,
+ RAP_NEGATIVE_ENERGY, // 10
+ RAP_MAGIC,
+ RAP_EYESIGHT,
+ RAP_INVISIBLE,
+ RAP_LEVITATE,
+ RAP_BLINK, // 15
+ RAP_CAN_TELEPORT,
+ RAP_BERSERK,
+ RAP_MAPPING,
+ RAP_NOISES,
+ RAP_PREVENT_SPELLCASTING, // 20
+ RAP_CAUSE_TELEPORTATION,
+ RAP_PREVENT_TELEPORTATION,
+ RAP_ANGRY,
+ RAP_METABOLISM,
+ RAP_MUTAGENIC, // 25
+ RAP_ACCURACY,
+ RAP_DAMAGE,
+ RAP_CURSED,
+ RAP_STEALTH
+};
+
+enum READ_BOOK_ACTION
+{
+ RBOOK_USE_STAFF,
+ RBOOK_MEMORIZE,
+ RBOOK_READ_SPELL
+};
+
+enum RUN_DIR
+{
+ RDIR_UP = 0,
+ RDIR_UP_RIGHT,
+ RDIR_RIGHT,
+ RDIR_DOWN_RIGHT,
+ RDIR_DOWN,
+ RDIR_DOWN_LEFT,
+ RDIR_LEFT,
+ RDIR_UP_LEFT,
+ RDIR_REST
+};
+
+enum RUNE_TYPES
+{
+ // Note: that runes DIS-SWAMP have the same numberic value as the branch
+ RUNE_DIS = 1,
+ RUNE_GEHENNA,
+ RUNE_COCYTUS = 4,
+ RUNE_TARTARUS,
+ RUNE_SLIME_PITS = 13,
+ RUNE_VAULTS,
+ RUNE_SNAKE_PIT = 19,
+ RUNE_ELVEN_HALLS, // unused
+ RUNE_TOMB,
+ RUNE_SWAMP,
+
+ // Runes 50 and 51 are for Pandemonium (general demon) and the Abyss
+ RUNE_DEMONIC = 50,
+ RUNE_ABYSSAL,
+
+ // Runes 60-63 correspond to the Pandemonium demonlords,
+ // and are equal to the corresponding vault.
+ RUNE_MNOLEG = 60,
+ RUNE_LOM_LOBON,
+ RUNE_CEREBOV,
+ RUNE_GLOORX_VLOQ,
+ NUM_RUNE_TYPES // should always be last
+};
+
+enum SCORE_FORMAT
+{
+ SCORE_TERSE, // one line
+ SCORE_REGULAR, // two lines (name, cause, blank)
+ SCORE_VERBOSE // everything (dates, times, god, etc)
+};
+
+enum SCROLLS
+{
+ SCR_IDENTIFY, // 0
+ SCR_TELEPORTATION,
+ SCR_FEAR,
+ SCR_NOISE,
+ SCR_REMOVE_CURSE,
+ SCR_DETECT_CURSE, // 5
+ SCR_SUMMONING,
+ SCR_ENCHANT_WEAPON_I,
+ SCR_ENCHANT_ARMOUR,
+ SCR_TORMENT,
+ SCR_RANDOM_USELESSNESS, // 10
+ SCR_CURSE_WEAPON,
+ SCR_CURSE_ARMOUR,
+ SCR_IMMOLATION,
+ SCR_BLINKING,
+ SCR_PAPER, // 15
+ SCR_MAGIC_MAPPING,
+ SCR_FORGETFULNESS,
+ SCR_ACQUIREMENT,
+ SCR_ENCHANT_WEAPON_II,
+ SCR_VORPALISE_WEAPON, // 20
+ SCR_RECHARGING,
+ SCR_ENCHANT_WEAPON_III,
+ NUM_SCROLLS
+};
+
+enum SHOPS // (unsigned char) env.sh_type[], item_in_shop(), in_a_shop()
+{
+ SHOP_WEAPON, // 0
+ SHOP_ARMOUR,
+ SHOP_WEAPON_ANTIQUE,
+ SHOP_ARMOUR_ANTIQUE,
+ SHOP_GENERAL_ANTIQUE,
+ SHOP_JEWELLERY, // 5
+ SHOP_WAND,
+ SHOP_BOOK,
+ SHOP_FOOD,
+ SHOP_DISTILLERY,
+ SHOP_SCROLL, // 10
+ SHOP_GENERAL,
+ NUM_SHOPS, // must remain last 'regular' member {dlb}
+ SHOP_UNASSIGNED = 100, // keep set at 100 for now {dlb}
+ SHOP_RANDOM = 255 // keep set at 255 for now {dlb}
+};
+
+enum SKILLS
+{
+ SK_FIGHTING, // 0
+ SK_SHORT_BLADES,
+ SK_LONG_SWORDS,
+ SK_UNUSED_1, // SK_GREAT_SWORDS - now unused
+ SK_AXES,
+ SK_MACES_FLAILS, // 5
+ SK_POLEARMS,
+ SK_STAVES,
+ SK_SLINGS,
+ SK_BOWS,
+ SK_CROSSBOWS, // 10
+ SK_DARTS,
+ SK_THROWING,
+ SK_ARMOUR,
+ SK_DODGING,
+ SK_STEALTH, // 15
+ SK_STABBING,
+ SK_SHIELDS,
+ SK_TRAPS_DOORS,
+ SK_UNARMED_COMBAT, // 19
+ SK_SPELLCASTING = 25, // 25
+ SK_CONJURATIONS,
+ SK_ENCHANTMENTS,
+ SK_SUMMONINGS,
+ SK_NECROMANCY,
+ SK_TRANSLOCATIONS, // 30
+ SK_TRANSMIGRATION,
+ SK_DIVINATIONS,
+ SK_FIRE_MAGIC,
+ SK_ICE_MAGIC,
+ SK_AIR_MAGIC, // 35
+ SK_EARTH_MAGIC,
+ SK_POISON_MAGIC,
+ SK_INVOCATIONS,
+ SK_EVOCATIONS,
+ NUM_SKILLS // must remain last member {dlb}
+};
+
+enum SPECIAL_ARMOR
+{
+ SPARM_NORMAL, // 0
+ SPARM_RUNNING,
+ SPARM_FIRE_RESISTANCE,
+ SPARM_COLD_RESISTANCE,
+ SPARM_POISON_RESISTANCE,
+ SPARM_SEE_INVISIBLE, // 5
+ SPARM_DARKNESS,
+ SPARM_STRENGTH,
+ SPARM_DEXTERITY,
+ SPARM_INTELLIGENCE,
+ SPARM_PONDEROUSNESS, // 10
+ SPARM_LEVITATION,
+ SPARM_MAGIC_RESISTANCE,
+ SPARM_PROTECTION,
+ SPARM_STEALTH,
+ SPARM_RESISTANCE, // 15
+ SPARM_POSITIVE_ENERGY,
+ SPARM_ARCHMAGI,
+ SPARM_PRESERVATION, // 18
+ SPARM_RANDART_I = 25, // must remain at 25 for now - how high do they go? {dlb}
+ SPARM_RANDART_II = 26, // 26
+ SPARM_RANDART_III = 27, // 27
+ SPARM_RANDART_IV = 28, // 28
+ SPARM_RANDART_V = 29 // 29 - highest value found thus far {dlb}
+};
+
+enum SPECIAL_MISSILES // to separate from weapons in general {dlb}
+{
+ SPMSL_NORMAL, // 0
+ SPMSL_FLAME, // 1
+ SPMSL_ICE, // 2
+ SPMSL_POISONED, // 3 - from poison_ammo() enchantment {dlb}
+ SPMSL_POISONED_II, // 4
+};
+
+enum SPECIAL_ROOMS
+{
+ SROOM_LAIR_ORC, // 0
+ SROOM_LAIR_KOBOLD,
+ SROOM_TREASURY,
+ SROOM_BEEHIVE,
+ SROOM_MORGUE,
+ NUM_SPECIAL_ROOMS // 5 - must remain final member {dlb}
+};
+
+enum SPECIAL_RINGS // jewellery mitm[].special values
+{
+ SPRING_RANDART = 200,
+ SPRING_UNRANDART = 201
+};
+
+enum SPECIAL_WEAPONS // equivalent to (you.inv[].special or mitm[].special) % 30
+{
+ SPWPN_NORMAL, // 0
+ SPWPN_FLAMING,
+ SPWPN_FREEZING,
+ SPWPN_HOLY_WRATH,
+ SPWPN_ELECTROCUTION,
+ SPWPN_ORC_SLAYING, // 5
+ SPWPN_VENOM,
+ SPWPN_PROTECTION,
+ SPWPN_DRAINING,
+ SPWPN_SPEED,
+ SPWPN_VORPAL, // 10
+ SPWPN_FLAME,
+ SPWPN_FROST,
+ SPWPN_VAMPIRICISM,
+ SPWPN_DISRUPTION,
+ SPWPN_PAIN, // 15
+ SPWPN_DISTORTION,
+ SPWPN_REACHING, // 17
+ SPWPN_CONFUSE,
+ SPWPN_RANDART_I = 25, // 25
+ SPWPN_RANDART_II,
+ SPWPN_RANDART_III,
+ SPWPN_RANDART_IV,
+ SPWPN_RANDART_V,
+ NUM_SPECIAL_WEAPONS,
+ SPWPN_DUMMY_CRUSHING, // ONLY TEMPORARY USAGE -- converts to VORPAL
+
+ // everything above this point is a special artefact wield:
+ SPWPN_SINGING_SWORD = 181, // 181
+ SPWPN_WRATH_OF_TROG,
+ SPWPN_SCYTHE_OF_CURSES,
+ SPWPN_MACE_OF_VARIABILITY,
+ SPWPN_GLAIVE_OF_PRUNE, // 185
+ SPWPN_SCEPTRE_OF_TORMENT,
+ SPWPN_SWORD_OF_ZONGULDROK,
+
+ // these three are not generated randomly {dlb}
+ SPWPN_SWORD_OF_CEREBOV,
+ SPWPN_STAFF_OF_DISPATER,
+ SPWPN_SCEPTRE_OF_ASMODEUS, // 190
+
+ SPWPN_SWORD_OF_POWER,
+ SPWPN_KNIFE_OF_ACCURACY,
+ SPWPN_STAFF_OF_OLGREB,
+ SPWPN_VAMPIRES_TOOTH,
+ SPWPN_STAFF_OF_WUCAD_MU // 195
+};
+
+enum SPECIAL_WIELD // you.special_wield
+{
+ SPWLD_NONE, // 0
+ SPWLD_SING,
+ SPWLD_TROG,
+ SPWLD_CURSE,
+ SPWLD_VARIABLE, // 4
+ SPWLD_PRUNE, // 5 - implicit in it_use3::special_wielded() {dlb}
+ SPWLD_TORMENT, // 6
+ SPWLD_ZONGULDROK,
+ SPWLD_POWER,
+ SPWLD_WUCAD_MU, // 9
+ SPWLD_OLGREB, // 10
+ SPWLD_SHADOW = 50, // 50
+ SPWLD_HUM, // 51 - see it_use3::special_wielded() {dlb}
+ SPWLD_CHIME, // 52 - see it_use3::special_wielded() {dlb}
+ SPWLD_BECKON, // 53 - see it_use3::special_wielded() {dlb}
+ SPWLD_SHOUT // 54 - see it_use3::special_wielded() {dlb}
+};
+
+enum SPECIES
+{
+ SP_HUMAN = 1, // 1
+ SP_ELF,
+ SP_HIGH_ELF,
+ SP_GREY_ELF,
+ SP_DEEP_ELF, // 5
+ SP_SLUDGE_ELF,
+ SP_HILL_DWARF,
+ SP_MOUNTAIN_DWARF,
+ SP_HALFLING,
+ SP_HILL_ORC, // 10
+ SP_KOBOLD,
+ SP_MUMMY,
+ SP_NAGA,
+ SP_GNOME,
+ SP_OGRE, // 15
+ SP_TROLL,
+ SP_OGRE_MAGE,
+ SP_RED_DRACONIAN,
+ SP_WHITE_DRACONIAN,
+ SP_GREEN_DRACONIAN, // 20
+ SP_GOLDEN_DRACONIAN,
+ SP_GREY_DRACONIAN,
+ SP_BLACK_DRACONIAN,
+ SP_PURPLE_DRACONIAN,
+ SP_MOTTLED_DRACONIAN, // 25
+ SP_PALE_DRACONIAN,
+ SP_UNK0_DRACONIAN,
+ SP_UNK1_DRACONIAN,
+ SP_UNK2_DRACONIAN,
+ SP_CENTAUR, // 30
+ SP_DEMIGOD,
+ SP_SPRIGGAN,
+ SP_MINOTAUR,
+ SP_DEMONSPAWN,
+ SP_GHOUL, // 35
+ SP_KENKU,
+ SP_MERFOLK,
+ NUM_SPECIES, // always after the last species
+
+ SP_UNKNOWN = 100
+};
+
+enum SPELLS
+{
+ SPELL_IDENTIFY, // 0
+ SPELL_TELEPORT_SELF,
+ SPELL_CAUSE_FEAR,
+ SPELL_CREATE_NOISE,
+ SPELL_REMOVE_CURSE,
+ SPELL_MAGIC_DART, // 5
+ SPELL_FIREBALL,
+ SPELL_SWAP,
+ SPELL_APPORTATION,
+ SPELL_TWIST,
+ SPELL_FAR_STRIKE, // 10
+ SPELL_DELAYED_FIREBALL,
+ SPELL_STRIKING,
+ SPELL_CONJURE_FLAME,
+ SPELL_DIG,
+ SPELL_BOLT_OF_FIRE, // 15
+ SPELL_BOLT_OF_COLD,
+ SPELL_LIGHTNING_BOLT,
+ SPELL_BOLT_OF_MAGMA, // 18
+ SPELL_POLYMORPH_OTHER = 20, // 20
+ SPELL_SLOW,
+ SPELL_HASTE,
+ SPELL_PARALYZE,
+ SPELL_CONFUSE,
+ SPELL_INVISIBILITY, // 25
+ SPELL_THROW_FLAME,
+ SPELL_THROW_FROST,
+ SPELL_CONTROLLED_BLINK,
+ SPELL_FREEZING_CLOUD,
+ SPELL_MEPHITIC_CLOUD, // 30
+ SPELL_RING_OF_FLAMES,
+ SPELL_RESTORE_STRENGTH,
+ SPELL_RESTORE_INTELLIGENCE,
+ SPELL_RESTORE_DEXTERITY,
+ SPELL_VENOM_BOLT, // 35
+ SPELL_OLGREBS_TOXIC_RADIANCE,
+ SPELL_TELEPORT_OTHER,
+ SPELL_LESSER_HEALING,
+ SPELL_GREATER_HEALING,
+ SPELL_CURE_POISON_I, // 40
+ SPELL_PURIFICATION,
+ SPELL_DEATHS_DOOR,
+ SPELL_SELECTIVE_AMNESIA,
+ SPELL_MASS_CONFUSION,
+ SPELL_SMITING, // 45
+ SPELL_REPEL_UNDEAD,
+ SPELL_HOLY_WORD,
+ SPELL_DETECT_CURSE,
+ SPELL_SUMMON_SMALL_MAMMAL,
+ SPELL_ABJURATION_I, // 50
+ SPELL_SUMMON_SCORPIONS,
+ SPELL_LEVITATION,
+ SPELL_BOLT_OF_DRAINING,
+ SPELL_LEHUDIBS_CRYSTAL_SPEAR,
+ SPELL_BOLT_OF_INACCURACY, // 55
+ SPELL_POISONOUS_CLOUD,
+ SPELL_FIRE_STORM,
+ SPELL_DETECT_TRAPS,
+ SPELL_BLINK,
+ SPELL_ISKENDERUNS_MYSTIC_BLAST, // 60
+ SPELL_SWARM,
+ SPELL_SUMMON_HORRIBLE_THINGS,
+ SPELL_ENSLAVEMENT,
+ SPELL_MAGIC_MAPPING,
+ SPELL_HEAL_OTHER, // 65
+ SPELL_ANIMATE_DEAD,
+ SPELL_PAIN,
+ SPELL_EXTENSION,
+ SPELL_CONTROL_UNDEAD,
+ SPELL_ANIMATE_SKELETON, // 70
+ SPELL_VAMPIRIC_DRAINING,
+ SPELL_SUMMON_WRAITHS,
+ SPELL_DETECT_ITEMS,
+ SPELL_BORGNJORS_REVIVIFICATION,
+ SPELL_BURN, // 75
+ SPELL_FREEZE,
+ SPELL_SUMMON_ELEMENTAL,
+ SPELL_OZOCUBUS_REFRIGERATION,
+ SPELL_STICKY_FLAME,
+ SPELL_SUMMON_ICE_BEAST, // 80
+ SPELL_OZOCUBUS_ARMOUR,
+ SPELL_CALL_IMP,
+ SPELL_REPEL_MISSILES,
+ SPELL_BERSERKER_RAGE,
+ SPELL_DISPEL_UNDEAD, // 85
+ SPELL_GUARDIAN,
+ SPELL_PESTILENCE,
+ SPELL_THUNDERBOLT,
+ SPELL_FLAME_OF_CLEANSING,
+ SPELL_SHINING_LIGHT, // 90
+ SPELL_SUMMON_DAEVA,
+ SPELL_ABJURATION_II,
+ SPELL_FULSOME_DISTILLATION, // 93
+ SPELL_POISON_ARROW, // 94
+ SPELL_TWISTED_RESURRECTION = 110, // 110
+ SPELL_REGENERATION,
+ SPELL_BONE_SHARDS,
+ SPELL_BANISHMENT,
+ SPELL_CIGOTUVIS_DEGENERATION,
+ SPELL_STING, // 115
+ SPELL_SUBLIMATION_OF_BLOOD,
+ SPELL_TUKIMAS_DANCE,
+ SPELL_HELLFIRE,
+ SPELL_SUMMON_DEMON,
+ SPELL_DEMONIC_HORDE, // 120
+ SPELL_SUMMON_GREATER_DEMON,
+ SPELL_CORPSE_ROT,
+ SPELL_TUKIMAS_VORPAL_BLADE,
+ SPELL_FIRE_BRAND,
+ SPELL_FREEZING_AURA, // 125
+ SPELL_LETHAL_INFUSION,
+ SPELL_CRUSH,
+ SPELL_BOLT_OF_IRON,
+ SPELL_STONE_ARROW,
+ SPELL_TOMB_OF_DOROKLOHE, // 130
+ SPELL_STONEMAIL,
+ SPELL_SHOCK,
+ SPELL_SWIFTNESS,
+ SPELL_FLY,
+ SPELL_INSULATION, // 135
+ SPELL_ORB_OF_ELECTROCUTION,
+ SPELL_DETECT_CREATURES,
+ SPELL_CURE_POISON_II,
+ SPELL_CONTROL_TELEPORT,
+ SPELL_POISON_AMMUNITION, // 140
+ SPELL_POISON_WEAPON,
+ SPELL_RESIST_POISON,
+ SPELL_PROJECTED_NOISE,
+ SPELL_ALTER_SELF,
+ SPELL_DEBUGGING_RAY, // 145
+ SPELL_RECALL,
+ SPELL_PORTAL,
+ SPELL_AGONY,
+ SPELL_SPIDER_FORM,
+ SPELL_DISRUPT, // 150
+ SPELL_DISINTEGRATE,
+ SPELL_BLADE_HANDS,
+ SPELL_STATUE_FORM,
+ SPELL_ICE_FORM,
+ SPELL_DRAGON_FORM, // 155
+ SPELL_NECROMUTATION,
+ SPELL_DEATH_CHANNEL,
+ SPELL_SYMBOL_OF_TORMENT,
+ SPELL_DEFLECT_MISSILES,
+ SPELL_ORB_OF_FRAGMENTATION, // 160
+ SPELL_ICE_BOLT,
+ SPELL_ICE_STORM,
+ SPELL_ARC,
+ SPELL_AIRSTRIKE,
+ SPELL_SHADOW_CREATURES, // 165
+ SPELL_CONFUSING_TOUCH,
+ SPELL_SURE_BLADE,
+//jmf: new spells
+ SPELL_FLAME_TONGUE,
+ SPELL_PASSWALL,
+ SPELL_IGNITE_POISON, // 170
+ SPELL_STICKS_TO_SNAKES,
+ SPELL_SUMMON_LARGE_MAMMAL, // e.g. hound
+ SPELL_SUMMON_DRAGON,
+ SPELL_TAME_BEASTS, // charm/enslave but only animals
+ SPELL_SLEEP, // 175
+ SPELL_MASS_SLEEP,
+ SPELL_DETECT_MAGIC, //jmf: unfinished, perhaps useless
+ SPELL_DETECT_SECRET_DOORS,
+ SPELL_SEE_INVISIBLE,
+ SPELL_FORESCRY, // 180
+ SPELL_SUMMON_BUTTERFLIES,
+ SPELL_WARP_BRAND,
+ SPELL_SILENCE,
+ SPELL_SHATTER,
+ SPELL_DISPERSAL, // 185
+ SPELL_DISCHARGE,
+ SPELL_BEND,
+ SPELL_BACKLIGHT,
+ SPELL_INTOXICATE, // confusion but only "smart" creatures
+ SPELL_GLAMOUR, // charm/confuse/sleep but only "smart" creatures 190
+ SPELL_EVAPORATE, // turn a potion into a cloud
+ SPELL_ERINGYAS_SURPRISING_BOUQUET, // turn sticks into herbivore food
+ SPELL_FRAGMENTATION, // replacement for "orb of frag"
+ SPELL_AIR_WALK, // "dematerialize" (air/transmigration)
+ SPELL_SANDBLAST, // mini-frag; can use stones for material comp 195
+ SPELL_ROTTING, // evil god power or necromantic transmigration
+ SPELL_SHUGGOTH_SEED, // evil god power or necromantic summoning
+ SPELL_MAXWELLS_SILVER_HAMMER, // vorpal-brand maces etc.
+ SPELL_CONDENSATION_SHIELD, // "shield" of icy vapour
+ SPELL_SEMI_CONTROLLED_BLINK, //jmf: to test effect 200
+ SPELL_STONESKIN,
+ SPELL_SIMULACRUM,
+ SPELL_CONJURE_BALL_LIGHTNING, // 203 (be wary of 210, see below)
+ NUM_SPELLS,
+ SPELL_NO_SPELL = 210 // 210 - added 22jan2000 {dlb}
+};
+
+enum SPELL_TYPES //jmf: 24jul2000: changed from integer-list to bitfield
+{
+ SPTYP_NONE = 0, // "0" is reserved for no type at all {dlb}
+ SPTYP_CONJURATION = 1, // was 11, but only for old typematch routine {dlb}
+ SPTYP_ENCHANTMENT = 1<<1,
+ SPTYP_FIRE = 1<<2,
+ SPTYP_ICE = 1<<3,
+ SPTYP_TRANSMIGRATION = 1<<4,
+ SPTYP_NECROMANCY = 1<<5,
+ SPTYP_SUMMONING = 1<<6,
+ SPTYP_DIVINATION = 1<<7,
+ SPTYP_TRANSLOCATION = 1<<8,
+ SPTYP_POISON = 1<<9,
+ SPTYP_EARTH = 1<<10,
+ SPTYP_AIR = 1<<11,
+ SPTYP_HOLY = 1<<12, //jmf: moved to accomodate "random" miscast f/x
+ SPTYP_LAST_EXPONENT = 12, //jmf: ``NUM_SPELL_TYPES'' kinda useless
+ NUM_SPELL_TYPES = 14,
+ SPTYP_RANDOM = 1<<14
+};
+
+enum STATS
+{
+ STAT_STRENGTH, // 0
+ STAT_DEXTERITY,
+ STAT_INTELLIGENCE,
+ NUM_STATS, // added for increase_stats() {dlb}
+ STAT_ALL, // must remain after NUM_STATS -- added to handle royal jelly, etc. {dlb}
+ STAT_RANDOM = 255 // leave at 255, added for increase_stats() handling {dlb}
+};
+
+enum STATUE_TYPES
+{
+ STATUE_SILVER,
+ STATUE_ORANGE_CRYSTAL,
+ NUM_STATUE_TYPES
+};
+
+enum STATUS_REDRAW_FLAGS
+{
+ REDRAW_HUNGER = 0x00000001,
+ REDRAW_BURDEN = 0x00000002,
+ REDRAW_LINE_1_MASK = 0x00000003,
+
+ REDRAW_PRAYER = 0x00000100,
+ REDRAW_REPEL_UNDEAD = 0x00000200,
+ REDRAW_BREATH = 0x00000400,
+ REDRAW_REPEL_MISSILES = 0x00000800,
+ REDRAW_REGENERATION = 0x00001000,
+ REDRAW_INSULATION = 0x00002000,
+ REDRAW_FLY = 0x00004000,
+ REDRAW_INVISIBILITY = 0x00008000,
+ REDRAW_LINE_2_MASK = 0x0000ff00,
+
+ REDRAW_CONFUSION = 0x00010000,
+ REDRAW_POISONED = 0x00020000,
+ REDRAW_LIQUID_FLAMES = 0x00040000,
+ REDRAW_DISEASED = 0x00080000,
+ REDRAW_CONTAMINATED = 0x00100000,
+ REDRAW_SWIFTNESS = 0x00200000,
+ REDRAW_SPEED = 0x00400000,
+ REDRAW_LINE_3_MASK = 0x007f0000
+};
+
+enum STAVES
+{
+ STAFF_WIZARDRY, // 0
+ STAFF_POWER,
+ STAFF_FIRE,
+ STAFF_COLD,
+ STAFF_POISON,
+ STAFF_ENERGY, // 5
+ STAFF_DEATH,
+ STAFF_CONJURATION,
+ STAFF_ENCHANTMENT,
+ STAFF_SUMMONING,
+ STAFF_SMITING, // 10
+ STAFF_SPELL_SUMMONING,
+ STAFF_DESTRUCTION_I,
+ STAFF_DESTRUCTION_II,
+ STAFF_DESTRUCTION_III,
+ STAFF_DESTRUCTION_IV, // 15
+ STAFF_WARDING,
+ STAFF_DISCOVERY,
+ STAFF_DEMONOLOGY, // 18
+ STAFF_STRIKING, // 19
+ STAFF_AIR = 25, // 25
+ STAFF_EARTH,
+ STAFF_CHANNELING,
+ NUM_STAVES // must remain last member {dlb}
+};
+
+enum SYMBOLS // beam[].type - note that this (and its variants) also accepts values from other enums - confusing {dlb}
+{
+ SYM_SPACE = ' ', // 32
+ SYM_FLASK = '!', // 33
+ SYM_BOLT = '#', // 35
+ SYM_CHUNK = '%', // 37
+ SYM_OBJECT = '(', // 40 - actually used for books, but... {dlb}
+ SYM_WEAPON = ')', // 41
+ SYM_ZAP = '*', // 42
+ SYM_BURST = '+', // 43
+ SYM_STICK = '/', // 47
+ SYM_TRINKET = '=', // 61
+ SYM_SCROLL = '?', // 63
+ SYM_DEBUG = 'X', // 88
+ SYM_ARMOUR = '[', // 91
+ SYM_MISSILE = '`' // 96
+};
+
+enum TAGS // used during save/load process to identify data blocks
+{
+ TAG_VERSION = 0, // should NEVER be read in!
+ TAG_YOU = 1, // 'you' structure
+ TAG_YOU_ITEMS, // your items
+ TAG_YOU_DUNGEON, // dungeon specs (stairs, branches, features)
+ TAG_LEVEL, // various grids & clouds
+ TAG_LEVEL_ITEMS, // items/traps
+ TAG_LEVEL_MONSTERS, // monsters
+ TAG_GHOST, // ghost
+ TAG_LEVEL_ATTITUDE, // monster attitudes
+ NUM_TAGS
+};
+
+enum TAGTYPES // file types supported by tag system
+{
+ TAGTYPE_PLAYER=0, // Foo.sav
+ TAGTYPE_LEVEL, // Foo.00a, .01a, etc.
+ TAGTYPE_GHOST // bones.xxx
+};
+
+
+enum TRANSFORMATIONS
+{
+ TRAN_NONE, // 0
+ TRAN_SPIDER,
+ TRAN_BLADE_HANDS,
+ TRAN_STATUE,
+ TRAN_ICE_BEAST,
+ TRAN_DRAGON, // 5
+ TRAN_LICH,
+ TRAN_SERPENT_OF_HELL,
+ TRAN_AIR,
+ NUM_TRANSFORMATIONS // must remain last member {dlb}
+};
+
+enum TRAPS // env.trap_type[]
+{
+ TRAP_DART, // 0
+ TRAP_ARROW,
+ TRAP_SPEAR,
+ TRAP_AXE,
+ TRAP_TELEPORT,
+ TRAP_AMNESIA, // 5
+ TRAP_BLADE,
+ TRAP_BOLT,
+ TRAP_ZOT,
+ TRAP_NEEDLE,
+ NUM_TRAPS, // must remain last 'regular' member {dlb}
+ TRAP_UNASSIGNED = 100, // keep set at 100 for now {dlb}
+ TRAP_RANDOM = 255 // set at 255 to avoid potential conflicts {dlb}
+};
+
+enum UNARMED_ATTACKS
+{
+ UNAT_NO_ATTACK, // 0
+ UNAT_KICK,
+ UNAT_HEADBUTT,
+ UNAT_TAILSLAP,
+ UNAT_PUNCH
+};
+
+enum UNDEAD_STATES // you.is_undead
+{
+ US_ALIVE, // 0
+ US_HUNGRY_DEAD,
+ US_UNDEAD
+};
+
+enum UNIQUE_ITEM_STATUS
+{
+ UNIQ_NOT_EXISTS = 0,
+ UNIQ_EXISTS = 1,
+ UNIQ_LOST_IN_ABYSS = 2
+};
+
+enum VORPAL_DESCRIPTIONS
+{
+ DVORP_CRUSHING, // 0
+ DVORP_SLICING,
+ DVORP_PIERCING,
+ DVORP_CHOPPING
+};
+
+// NOTE: This order is very special! Its basically the same as ZAP_*,
+// and there are bits of the code that still use that fact.. see zap_wand().
+enum WANDS // mitm[].subtype
+{
+ WAND_FLAME, // 0
+ WAND_FROST,
+ WAND_SLOWING,
+ WAND_HASTING,
+ WAND_MAGIC_DARTS,
+ WAND_HEALING, // 5
+ WAND_PARALYSIS,
+ WAND_FIRE,
+ WAND_COLD,
+ WAND_CONFUSION,
+ WAND_INVISIBILITY, // 10
+ WAND_DIGGING,
+ WAND_FIREBALL,
+ WAND_TELEPORTATION,
+ WAND_LIGHTNING,
+ WAND_POLYMORPH_OTHER, // 15
+ WAND_ENSLAVEMENT,
+ WAND_DRAINING,
+ WAND_RANDOM_EFFECTS,
+ WAND_DISINTEGRATION,
+ NUM_WANDS // must remain last member {dlb}
+};
+
+enum WEAPONS
+{
+// Base weapons
+ WPN_CLUB, // 0
+ WPN_MACE,
+ WPN_FLAIL,
+ WPN_DAGGER,
+ WPN_MORNINGSTAR,
+ WPN_SHORT_SWORD, // 5
+ WPN_LONG_SWORD,
+ WPN_GREAT_SWORD,
+ WPN_SCIMITAR,
+ WPN_HAND_AXE,
+ WPN_BATTLEAXE, // 10
+ WPN_SPEAR,
+ WPN_HALBERD,
+ WPN_SLING,
+ WPN_BOW,
+ WPN_CROSSBOW, // 15
+ WPN_HAND_CROSSBOW,
+ WPN_GLAIVE,
+ WPN_QUARTERSTAFF,
+// these three not created ordinarily
+ WPN_SCYTHE,
+ WPN_GIANT_CLUB, // 20
+ WPN_GIANT_SPIKED_CLUB,
+// "rare" weapons - some have special cases and are uncommon
+ WPN_EVENINGSTAR,
+ WPN_QUICK_BLADE,
+ WPN_KATANA,
+ WPN_EXECUTIONERS_AXE, // 25
+ WPN_DOUBLE_SWORD,
+ WPN_TRIPLE_SWORD,
+ WPN_HAMMER,
+ WPN_ANCUS,
+ WPN_WHIP, // 30
+ WPN_SABRE,
+ WPN_DEMON_BLADE,
+ WPN_DEMON_WHIP,
+ WPN_DEMON_TRIDENT,
+ WPN_BROAD_AXE, // 35
+// base items (continued)
+ WPN_WAR_AXE,
+ WPN_TRIDENT,
+ WPN_SPIKED_FLAIL,
+ WPN_GREAT_MACE,
+ WPN_GREAT_FLAIL, // 40
+ WPN_KNIFE,
+ WPN_BLOWGUN,
+ WPN_FALCHION,
+ NUM_WEAPONS, // 44 - must remain last regular member {dlb}
+// special cases
+ WPN_UNARMED = 500, // 500
+ WPN_UNKNOWN = 1000, // 1000
+ WPN_RANDOM
+};
+
+enum WEAPON_DESCRIPTIONS
+{
+ DWPN_PLAIN = 0, // 0 - added to round out enum {dlb}
+ DWPN_RUNED = 1, // 1
+ DWPN_GLOWING,
+ DWPN_ORCISH,
+ DWPN_ELVEN,
+ DWPN_DWARVEN // 5
+};
+
+enum WEAPON_PROPERTIES
+{
+ PWPN_DAMAGE, // 0
+ PWPN_HIT,
+ PWPN_SPEED
+};
+
+#ifdef WIZARD
+
+enum WIZARD_OPTIONS
+{
+ WIZ_NEVER, // protect player from accidental wiz
+ WIZ_NO, // don't start character in wiz mode
+ WIZ_YES // start character in wiz mode
+};
+
+#endif
+
+enum ZAPS // zapping(), zappy()
+{
+ ZAP_FLAME, // 0
+ ZAP_FROST,
+ ZAP_SLOWING,
+ ZAP_HASTING,
+ ZAP_MAGIC_DARTS,
+ ZAP_HEALING, // 5
+ ZAP_PARALYSIS,
+ ZAP_FIRE,
+ ZAP_COLD,
+ ZAP_CONFUSION,
+ ZAP_INVISIBILITY, // 10
+ ZAP_DIGGING,
+ ZAP_FIREBALL,
+ ZAP_TELEPORTATION,
+ ZAP_LIGHTNING,
+ ZAP_POLYMORPH_OTHER, // 15
+ ZAP_VENOM_BOLT,
+ ZAP_NEGATIVE_ENERGY,
+ ZAP_CRYSTAL_SPEAR,
+ ZAP_BEAM_OF_ENERGY,
+ ZAP_MYSTIC_BLAST, // 20
+ ZAP_ENSLAVEMENT,
+ ZAP_PAIN,
+ ZAP_STICKY_FLAME,
+ ZAP_DISPEL_UNDEAD,
+ ZAP_CLEANSING_FLAME, // 25
+ ZAP_BONE_SHARDS,
+ ZAP_BANISHMENT,
+ ZAP_DEGENERATION,
+ ZAP_STING,
+ ZAP_HELLFIRE, // 30
+ ZAP_IRON_BOLT,
+ ZAP_STRIKING,
+ ZAP_STONE_ARROW,
+ ZAP_ELECTRICITY,
+ ZAP_ORB_OF_ELECTRICITY, // 35
+ ZAP_SPIT_POISON,
+ ZAP_DEBUGGING_RAY,
+ ZAP_BREATHE_FIRE,
+ ZAP_BREATHE_FROST,
+ ZAP_BREATHE_ACID, // 40
+ ZAP_BREATHE_POISON,
+ ZAP_BREATHE_POWER,
+ ZAP_ENSLAVE_UNDEAD,
+ ZAP_AGONY,
+ ZAP_DISRUPTION, // 45
+ ZAP_DISINTEGRATION, // 46
+ ZAP_ISKS_CROSS, // 47: Isk's Cross -- commented out, deprecated {dlb}
+ ZAP_BREATHE_STEAM = 48, // 48
+ ZAP_CONTROL_DEMON,
+ ZAP_ORB_OF_FRAGMENTATION, // 50
+ ZAP_ICE_BOLT,
+ ZAP_ICE_STORM,
+ ZAP_BACKLIGHT, //jmf: added next bunch 19mar2000
+ ZAP_SLEEP,
+ ZAP_FLAME_TONGUE,
+ ZAP_SANDBLAST,
+ ZAP_SMALL_SANDBLAST,
+ ZAP_MAGMA,
+ ZAP_POISON_ARROW,
+ NUM_ZAPS // must remain last member {dlb}
+};
+
+
+#endif // ENUM_H
diff --git a/trunk/source/externs.h b/trunk/source/externs.h
new file mode 100644
index 0000000000..a1d9863285
--- /dev/null
+++ b/trunk/source/externs.h
@@ -0,0 +1,553 @@
+/*
+ * File: externs.h
+ * Summary: Fixed size 2D vector class that asserts if you do something bad.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <3> 7/29/00 JDJ Renamed sh_x, sh_y, sh_greed, sh_type, sh_level so
+ * they start with shop.
+ * <2> 7/29/00 JDJ Switched to using bounds checked array classes.
+ * Made a few char arrays unsigned char arrays.
+ */
+
+#ifndef EXTERNS_H
+#define EXTERNS_H
+
+#include <queue>
+
+#include <time.h>
+
+#include "defines.h"
+#include "enum.h"
+#include "FixAry.h"
+#include "message.h"
+
+#define INFO_SIZE 200 // size of message buffers
+#define ITEMNAME_SIZE 200 // size of item names/shop names/etc
+#define HIGHSCORE_SIZE 800 // <= 10 Lines for long format scores
+
+#define MAX_NUM_GODS 21
+
+extern char info[INFO_SIZE]; // defined in acr.cc {dlb}
+
+extern unsigned char show_green; // defined in view.cc {dlb}
+
+// defined in mon-util.cc -- w/o this screen redraws *really* slow {dlb}
+extern FixedVector<unsigned short, 1000> mcolour;
+
+#ifdef SHORT_FILE_NAMES
+ const int kNameLen = 30;
+ const int kFileNameLen = 6;
+ const int kFileNameSize = 5 + kFileNameLen;
+
+#else
+ #ifdef SAVE_DIR_PATH
+ // file name length has to be able to cover full paths -- bwross
+ const int kNameLen = 30;
+ const int kFileNameLen = 250;
+ const int kFileNameSize = 5 + kFileNameLen;
+ #else
+ const int kNameLen = 30;
+ const int kFileNameLen = 28;
+ const int kFileNameSize = 5 + kFileNameLen;
+ #endif
+#endif
+
+
+// Length of Path + File Name
+const int kPathLen = 256;
+
+// This value is used to mark that the current berserk is free from
+// penalty (Xom's granted or from a deck of cards).
+#define NO_BERSERK_PENALTY -1
+
+struct coord_def
+{
+ int x;
+ int y;
+
+ // coord_def( int x_in = 0, int y_in = 0 ) : x(x_in), y(y_in) {};
+};
+
+struct dice_def
+{
+ int num;
+ int size;
+
+ dice_def( int n = 0, int s = 0 ) : num(n), size(s) {}
+};
+
+// output from direction() function:
+struct dist
+{
+ bool isValid; // valid target chosen?
+ bool isTarget; // target (true), or direction (false)?
+ bool isMe; // selected self (convenience: tx == you.x_pos,
+ // ty == you.y_pos)
+ bool isCancel; // user cancelled (usually <ESC> key)
+ int tx,ty; // target x,y or logical extension of beam to map edge
+ int dx,dy; // delta x and y if direction - always -1,0,1
+
+ // internal use - ignore
+ int prev_target; // previous target
+};
+
+
+struct bolt
+{
+ // INPUT parameters set by caller
+ int range; // minimum range
+ int rangeMax; // maximum range
+ int type; // missile gfx
+ int colour;
+ int flavour;
+ int source_x, source_y; // beam origin
+ dice_def damage;
+ int ench_power, hit;
+ int target_x, target_y; // intended target
+ char thrower; // what kind of thing threw this?
+ char ex_size; // explosion radius (0==none)
+ int beam_source; // NON_MONSTER or monster index #
+ char beam_name[40];
+ bool isBeam; // beams? (can hits multiple targets?)
+ const char *aux_source; // source of KILL_MISC beams
+
+ // OUTPUT parameters (tracing, ID)
+ bool obviousEffect; // did an 'obvious' effect happen?
+ int fr_count, foe_count; // # of times a friend/foe is "hit"
+ int fr_power, foe_power; // total levels/hit dice affected
+
+ // INTERNAL use - should not usually be set outside of beam.cc
+ bool isTracer; // is this a tracer?
+ bool aimedAtFeet; // this was aimed at self!
+ bool msgGenerated; // an appropriate msg was already mpr'd
+ bool isExplosion; // explosion phase (as opposed to beam phase)
+ bool smartMonster; // tracer firer can guess at other mons. resists?
+ bool canSeeInvis; // tracer firer can see invisible?
+ bool isFriendly; // tracer firer is enslaved or pet
+ int foeRatio; // 100* foe ratio (see mons_should_fire())
+};
+
+
+struct run_check_dir
+{
+ unsigned char grid;
+ char dx;
+ char dy;
+};
+
+
+struct delay_queue_item
+{
+ int type;
+ int duration;
+ int parm1;
+ int parm2;
+};
+
+
+struct item_def
+{
+ unsigned char base_type; // basic class (ie OBJ_WEAPON)
+ unsigned char sub_type; // type within that class (ie WPN_DAGGER)
+ short plus; // +to hit, charges, corpse mon id
+ short plus2; // +to dam, sub-sub type for boots and helms
+ long special; // special stuff
+ unsigned char colour; // item colour
+ unsigned long flags; // item statuc flags
+ short quantity; // number of items
+
+ short x; // x-location; for inventory items = -1
+ short y; // y-location; for inventory items = -1
+ short link; // link to next item; for inventory items = slot
+};
+
+
+struct player
+{
+ char turn_is_over; // flag signaling that player has performed a timed action
+
+ unsigned char prev_targ;
+ char your_name[kNameLen];
+
+ unsigned char species;
+
+ char run_x;
+ char run_y;
+ FixedVector< run_check_dir, 3 > run_check; // array of grids to check
+ char running;
+
+ char special_wield;
+ char deaths_door;
+ char fire_shield;
+
+ double elapsed_time; // total amount of elapsed time in the game
+
+ unsigned char synch_time; // amount to wait before calling handle_time
+
+ unsigned char disease;
+
+ char max_level;
+
+ int x_pos;
+ int y_pos;
+
+ int hunger;
+ FixedVector<char, NUM_EQUIP> equip;
+
+ int hp;
+ int hp_max;
+ int base_hp; // temporary max HP loss (rotting)
+ int base_hp2; // base HPs from levels (and permanent loss)
+
+ int magic_points;
+ int max_magic_points;
+ int base_magic_points; // temporary max MP loss? (currently unused)
+ int base_magic_points2; // base MPs from levels and potions of magic
+
+ char strength;
+ char intel;
+ char dex;
+ char max_strength;
+ char max_intel;
+ char max_dex;
+
+ char hunger_state;
+
+ bool wield_change; // redraw weapon
+
+ unsigned long redraw_status_flags;
+ char redraw_hit_points;
+ char redraw_magic_points;
+ char redraw_strength;
+ char redraw_intelligence;
+ char redraw_dexterity;
+ char redraw_experience;
+ char redraw_armour_class;
+
+ char redraw_gold;
+ char redraw_evasion;
+
+ unsigned char hit_points_regeneration;
+ unsigned char magic_points_regeneration;
+
+ unsigned long experience;
+ int experience_level;
+ unsigned int gold;
+ int char_class;
+ char class_name[30];
+ // char speed; // now unused
+ int time_taken;
+
+ char shield_blocks; // number of shield blocks since last action
+
+ FixedVector< item_def, ENDOFPACK > inv;
+
+ int burden;
+ char burden_state;
+ FixedVector<unsigned char, 25> spells;
+ char spell_no;
+ unsigned char char_direction; //
+
+ unsigned char pet_target;
+
+ int your_level; // offset by one (-1 == 0, 0 == 1, etc.) for display
+
+ // durational things. Why didn't I do this for haste etc
+ // right from the start? Oh well.
+ FixedVector<int, NUM_DURATIONS> duration;
+
+ int invis;
+ int conf;
+ int paralysis;
+ int slow;
+ int haste;
+ int might;
+ int levitation;
+
+ int poison;
+ int rotting;
+ int berserker;
+
+ int exhausted; // fatigue counter for berserk
+
+ int berserk_penalty; // pelnalty for moving while berserk
+
+ FixedVector<unsigned char, 30> attribute; // see ATTRIBUTES in enum.h
+
+ char is_undead; // see UNDEAD_STATES in enum.h
+
+ std::queue< delay_queue_item > delay_queue; // pending actions
+
+ FixedVector<unsigned char, 50> skills;
+ FixedVector<unsigned char, 50> practise_skill;
+ FixedVector<unsigned int, 50> skill_points;
+ FixedVector<unsigned char, 50> skill_order;
+ int skill_cost_level;
+ int total_skill_points;
+ int exp_available;
+
+ FixedArray<unsigned char, 5, 50> item_description;
+ FixedVector<unsigned char, 50> unique_items;
+ FixedVector<unsigned char, 50> unique_creatures;
+ char level_type;
+
+ char where_are_you;
+
+ FixedVector<unsigned char, 30> branch_stairs;
+
+ char religion;
+ unsigned char piety;
+ unsigned char gift_timeout;
+ FixedVector<unsigned char, MAX_NUM_GODS> penance;
+ FixedVector<unsigned char, MAX_NUM_GODS> worshipped;
+
+
+ FixedVector<unsigned char, 100> mutation;
+ FixedVector<unsigned char, 100> demon_pow;
+ unsigned char magic_contamination;
+
+ char confusing_touch;
+ char sure_blade;
+
+ FixedVector<unsigned char, 50> had_book;
+
+ unsigned char betrayal;
+ unsigned char normal_vision; // how far the species gets to see
+ unsigned char current_vision; // current sight radius (cells)
+
+ unsigned char hell_exit; // which level plyr goes to on hell exit.
+
+ // This field is here even in non-WIZARD compiles, since the
+ // player might have been playing previously under wiz mode.
+ bool wizard; // true if player has entered wiz mode.
+ time_t birth_time; // start time of game
+
+ time_t start_time; // start time of session
+ long real_time; // real time played (in seconds)
+ long num_turns; // number of turns taken
+
+ int old_hunger; // used for hunger delta-meter (see output.cc)
+
+ // Warning: these two are quite different.
+ //
+ // The spell table is an index to a specific spell slot (you.spells).
+ // The ability table lists the ability (ABIL_*) which prefers that letter.
+ //
+ // In other words, the spell table contains hard links and the ability
+ // table contains soft links.
+ FixedVector<int, 52> spell_letter_table; // ref to spell by slot
+ FixedVector<int, 52> ability_letter_table; // ref to ability by enum
+};
+
+extern struct player you;
+
+struct monsters
+{
+ int type;
+ int hit_points;
+ int max_hit_points;
+ int hit_dice;
+ int armour_class; // great -- more mixed american/proper spelling
+ int evasion;
+ unsigned int speed;
+ unsigned int speed_increment;
+ unsigned char x;
+ unsigned char y;
+ unsigned char target_x;
+ unsigned char target_y;
+ FixedVector<int, 8> inv;
+ unsigned char attitude; // from MONS_ATTITUDE
+ unsigned int behaviour;
+ unsigned int foe;
+ FixedVector<unsigned int, NUM_MON_ENCHANTS> enchantment;
+ unsigned char flags; // bitfield of boolean flags
+ unsigned int number; // #heads (hydra), etc.
+ int foe_memory; // how long to 'remember' foe x,y
+ // once they go out of sight
+};
+
+struct cloud_struct
+{
+ unsigned char x;
+ unsigned char y;
+ unsigned char type;
+ int decay;
+};
+
+struct shop_struct
+{
+ unsigned char x;
+ unsigned char y;
+ unsigned char greed;
+ unsigned char type;
+ unsigned char level;
+
+ FixedVector<unsigned char, 3> keeper_name;
+};
+
+struct trap_struct
+{
+ unsigned char x;
+ unsigned char y;
+ unsigned char type;
+};
+
+struct crawl_environment
+{
+ unsigned char rock_colour;
+ unsigned char floor_colour;
+
+ FixedVector< item_def, MAX_ITEMS > item; // item list
+ FixedVector< monsters, MAX_MONSTERS > mons; // monster list
+
+ FixedArray< unsigned char, GXM, GYM > grid; // terrain grid
+ FixedArray< unsigned char, GXM, GYM > mgrid; // monster grid
+ FixedArray< int, GXM, GYM > igrid; // item grid
+ FixedArray< unsigned char, GXM, GYM > cgrid; // cloud grid
+
+ FixedArray< unsigned char, GXM, GYM > map; // discovered terrain
+
+ FixedArray< unsigned int, 19, 19> show; // view window char
+ FixedArray< unsigned short, 19, 19> show_col; // view window colour
+
+ FixedVector< cloud_struct, MAX_CLOUDS > cloud; // cloud list
+ unsigned char cloud_no;
+
+ FixedVector< shop_struct, MAX_SHOPS > shop; // shop list
+ FixedVector< trap_struct, MAX_TRAPS > trap; // trap list
+
+ FixedVector< int, 20 > mons_alloc;
+ int trap_known;
+ double elapsed_time; // used during level load
+};
+
+extern struct crawl_environment env;
+
+
+struct ghost_struct
+{
+ char name[20];
+ FixedVector< short, NUM_GHOST_VALUES > values;
+};
+
+
+extern struct ghost_struct ghost;
+
+
+extern void (*viewwindow) (char, bool);
+
+
+struct system_environment
+{
+ char *crawl_name;
+ char *crawl_pizza;
+ char *crawl_rc;
+ char *crawl_dir;
+ char *home; // only used by MULTIUSER systems
+ bool board_with_nail; // Easter Egg silliness
+};
+
+extern system_environment SysEnv;
+
+struct game_options
+{
+ long autopickups; // items to autopickup
+ bool verbose_dump; // make character dumps contain more detail
+ bool colour_map; // add colour to the map
+ bool clean_map; // remove unseen clouds/monsters
+ bool show_uncursed; // label known uncursed items as "uncursed"
+ bool always_greet; // display greeting message when reloading
+ bool easy_open; // open doors with movement
+ bool easy_armour; // allow auto-removing of armour
+ bool easy_butcher; // open doors with movement
+ int easy_confirm; // make yesno() confirming easier
+ int easy_quit_item_prompts; // make item prompts quitable on space
+ int colour[16]; // macro fg colours to other colours
+ int background; // select default background colour
+ int channels[NUM_MESSAGE_CHANNELS]; // msg channel colouring
+ int weapon; // auto-choose weapon for character
+ int chaos_knight; // choice of god for Chaos Knights (Xom/Makleb)
+ int death_knight; // choice of god/necromancy for Death Knights
+ int priest; // choice of god for priests (Zin/Yred)
+ bool random_pick; // randomly generate character
+ int hp_warning; // percentage hp for danger warning
+ int hp_attention; // percentage hp for danger attention
+ char race; // preselected race
+ char cls; // preselected class
+ bool terse_hand; // use terse description for wielded item
+ bool delay_message_clear; // avoid clearing messages each turn
+ unsigned int friend_brand; // Attribute for branding friendly monsters
+ bool no_dark_brand; // Attribute for branding friendly monsters
+
+ int fire_items_start; // index of first item for fire command
+ FixedVector<int, NUM_FIRE_TYPES> fire_order; // order for 'f' command
+
+ bool auto_list; // automatically jump to appropriate item lists
+
+ bool flush_input[NUM_FLUSH_REASONS]; // when to flush input buff
+ bool lowercase_invocations; // prefer lowercase invocations
+
+#ifdef CURSES
+ int num_colours; // used for setting up colour table (8 or 16)
+#endif
+
+#ifdef WIZARD
+ int wiz_mode; // yes, no, never in wiz mode to start
+#endif
+
+ // internal use only:
+ int sc_entries; // # of score entries
+ int sc_format; // Format for score entries
+};
+
+extern game_options Options;
+
+struct tagHeader
+{
+ short tagID;
+ long offset;
+};
+
+struct scorefile_entry
+{
+ char version;
+ char release;
+ long points;
+ char name[kNameLen];
+ long uid; // for multiuser systems
+ char race;
+ char cls;
+ char race_class_name[5]; // overrides race & cls if non-null
+ char lvl; // player level.
+ char best_skill; // best skill #
+ char best_skill_lvl; // best skill level
+ int death_type;
+ int death_source; // 0 or monster TYPE
+ int mon_num; // sigh...
+ char death_source_name[40]; // overrides death_source
+ char auxkilldata[ITEMNAME_SIZE]; // weapon wielded, spell cast, etc
+ char dlvl; // dungeon level (relative)
+ char level_type; // what kind of level died on..
+ char branch; // dungeon branch
+ int final_hp; // actual current HPs (probably <= 0)
+ int final_max_hp; // net HPs after rot
+ int final_max_max_hp; // gross HPs before rot
+ int damage; // damage of final attack
+ int str; // final str (useful for nickname)
+ int intel; // final int
+ int dex; // final dex (useful for nickname)
+ int god; // god
+ int piety; // piety
+ int penance; // penance
+ char wiz_mode; // character used wiz mode
+ time_t birth_time; // start time of character
+ time_t death_time; // end time of character
+ long real_time; // real playing time in seconds
+ long num_turns; // number of turns taken
+ int num_diff_runes; // number of rune types in inventory
+ int num_runes; // total number of runes in inventory
+};
+
+#endif // EXTERNS_H
diff --git a/trunk/source/fight.cc b/trunk/source/fight.cc
new file mode 100644
index 0000000000..ab20364ffe
--- /dev/null
+++ b/trunk/source/fight.cc
@@ -0,0 +1,4014 @@
+/*
+ * File: fight.cc
+ * Summary: Functions used during combat.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <11> 07-jul-2000 JDJ Fixed some of the code in you_attack so it doesn't
+ * index past the end of arrays for unarmed attacks.
+ * <10> 03-mar-2000 bwr changes for new spells, no stave magic
+ * skill practising
+ * <9> 11/23/99 LRH Now you don't get xp/piety for killing
+ * monsters who were created friendly
+ * <8> 11/14/99 cdl evade with random40(ev) vice random2(ev)
+ * <7> 10/ 8/99 BCR Large races get a smaller
+ * penalty for large shields
+ * <6> 9/09/99 BWR Code for 1-1/2 hand weapons
+ * <5> 8/08/99 BWR Reduced power of EV/shields
+ * <4> 6/22/99 BWR Changes to stabbing code, made
+ * most gods not care about the
+ * deathes of summoned monsters
+ * <3> 5/21/99 BWR Upped learning of armour skill
+ * in combat slightly.
+ * <2> 5/12/99 BWR Fixed a bug where burdened
+ * barehanded attacks where free
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "fight.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#include "externs.h"
+
+#include "beam.h"
+#include "cloud.h"
+#include "debug.h"
+#include "delay.h"
+#include "effects.h"
+#include "food.h"
+#include "it_use2.h"
+#include "items.h"
+#include "itemname.h"
+#include "macro.h"
+#include "misc.h"
+#include "monplace.h"
+#include "mon-pick.h"
+#include "monstuff.h"
+#include "mon-util.h"
+#include "mstuff2.h"
+#include "mutation.h"
+#include "ouch.h"
+#include "player.h"
+#include "randart.h"
+#include "religion.h"
+#include "skills.h"
+#include "spells1.h"
+#include "spells3.h"
+#include "spells4.h"
+#include "spl-cast.h"
+#include "stuff.h"
+#include "view.h"
+#include "wpn-misc.h"
+
+#define HIT_WEAK 7
+#define HIT_MED 18
+#define HIT_STRONG 36
+// ... was 5, 12, 21
+// how these are used will be replaced by a function in a second ... :P {dlb}
+
+static int weapon_type_modify( int weap, char noise[80], char noise2[80],
+ int damage );
+
+static void stab_message(struct monsters *defender, int stab_bonus);
+
+int weapon_str_weight( int wpn_class, int wpn_type );
+
+static inline int player_weapon_str_weight( void );
+static inline int player_weapon_dex_weight( void );
+
+static inline int calc_stat_to_hit_base( void );
+static inline int calc_stat_to_dam_base( void );
+
+/*
+ **************************************************
+ * *
+ * BEGIN PUBLIC FUNCTIONS *
+ * *
+ **************************************************
+*/
+
+#if 0
+#define GUARANTEED_HIT_PERCENTAGE 5
+
+bool test_hit( int to_hit, int ev, int bonus )
+{
+ if (random2(100) < 2 * GUARANTEED_HIT_PERCENTAGE)
+ return (coinflip());
+
+ return (random2( to_hit ) + bonus >= ev);
+}
+#endif
+
+// This function returns the "extra" stats the player gets because of
+// choice of weapon... it's used only for giving warnings when a player
+// weilds a less than ideal weapon.
+int effective_stat_bonus( int wepType )
+{
+#ifdef USE_NEW_COMBAT_STATS
+ int str_weight;
+ if (wepType == -1)
+ str_weight = player_weapon_str_weight();
+ else
+ str_weight = weapon_str_weight( OBJ_WEAPONS, wepType );
+
+ return ((you.strength - you.dex) * (str_weight - 5) / 10);
+#else
+ return (0);
+#endif
+}
+
+void you_attack(int monster_attacked, bool unarmed_attacks)
+{
+ struct monsters *defender = &menv[monster_attacked];
+
+ int your_to_hit;
+ int damage_done = 0;
+ bool hit = false;
+ unsigned char stab_bonus = 0; // this is never negative {dlb}
+ int temp_rand; // for probability determination {dlb}
+
+ const int weapon = you.equip[EQ_WEAPON];
+ const bool ur_armed = (weapon != -1); // compacts code a bit {dlb}
+ const bool bearing_shield = (you.equip[EQ_SHIELD] != -1);
+
+ const int melee_brand = player_damage_brand();
+
+ bool water_attack = false;
+
+ char damage_noise[80], damage_noise2[80];
+
+ int heavy_armour = 0;
+ char str_pass[ ITEMNAME_SIZE ];
+
+#if DEBUG_DIAGNOSTICS
+ char st_prn[ 20 ];
+#endif
+
+ FixedVector< char, RA_PROPERTIES > art_proprt;
+
+ if (ur_armed && you.inv[weapon].base_type == OBJ_WEAPONS
+ && is_random_artefact( you.inv[weapon] ))
+ {
+ randart_wpn_properties( you.inv[weapon], art_proprt );
+ }
+ else
+ {
+ // Probably over protective, but in this code we're going
+ // to play it safe. -- bwr
+ for (int i = 0; i < RA_PROPERTIES; i++)
+ art_proprt[i] = 0;
+ }
+
+ // heavy armour modifiers for shield borne
+ if (bearing_shield)
+ {
+ switch (you.inv[you.equip[EQ_SHIELD]].sub_type)
+ {
+ case ARM_SHIELD:
+ if (you.skills[SK_SHIELDS] < random2(7))
+ heavy_armour++;
+ break;
+ case ARM_LARGE_SHIELD:
+ if ((you.species >= SP_OGRE && you.species <= SP_OGRE_MAGE)
+ || player_genus(GENPC_DRACONIAN))
+ {
+ if (you.skills[SK_SHIELDS] < random2(13))
+ heavy_armour++; // was potentially "+= 3" {dlb}
+ }
+ else
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ if (you.skills[SK_SHIELDS] < random2(13))
+ heavy_armour += random2(3);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ // heavy armour modifiers for PARM_EVASION
+ if (you.equip[EQ_BODY_ARMOUR] != -1)
+ {
+ const int ev_pen = property( you.inv[you.equip[EQ_BODY_ARMOUR]],
+ PARM_EVASION );
+
+ if (ev_pen < 0 && random2(you.skills[SK_ARMOUR]) < abs( ev_pen ))
+ heavy_armour += random2( abs(ev_pen) );
+ }
+
+ // ??? what is the reasoning behind this ??? {dlb}
+ // My guess is that its supposed to encourage monk-style play -- bwr
+ if (!ur_armed)
+ heavy_armour *= (coinflip() ? 3 : 2);
+
+ // Calculate the following two flags in advance
+ // to know what player does this combat turn:
+ bool can_do_unarmed_combat = false;
+
+ if (you.burden_state == BS_UNENCUMBERED
+ && random2(20) < you.skills[SK_UNARMED_COMBAT]
+ && random2(1 + heavy_armour) < 2)
+ {
+ can_do_unarmed_combat = true;
+ }
+
+ // if we're not getting potential unarmed attacks, and not wearing a
+ // shield, and have a suitable uncursed weapon we get the bonus.
+ bool use_hand_and_a_half_bonus = false;
+
+ int wpn_skill = SK_UNARMED_COMBAT;
+ int hands_reqd = HANDS_ONE_HANDED;
+
+ if (weapon != -1)
+ {
+ wpn_skill = weapon_skill( you.inv[weapon].base_type,
+ you.inv[weapon].sub_type );
+
+ hands_reqd = hands_reqd_for_weapon( you.inv[weapon].base_type,
+ you.inv[weapon].sub_type );
+ }
+
+ if (unarmed_attacks
+ && !can_do_unarmed_combat
+ && !bearing_shield && ur_armed
+ && item_uncursed( you.inv[ weapon ] )
+ && hands_reqd == HANDS_ONE_OR_TWO_HANDED)
+ {
+ // currently: +1 dam, +1 hit, -1 spd (loosly)
+ use_hand_and_a_half_bonus = true;
+ }
+
+/*
+ **************************************************************************
+ * *
+ * IMPORTANT: When altering damage routines, must also change in ouch.cc *
+ * for saving of player ghosts. *
+ * *
+ **************************************************************************
+ */
+ bool helpless = mons_flag(defender->type, M_NO_EXP_GAIN);
+
+ if (mons_friendly(defender))
+ naughty(NAUGHTY_ATTACK_FRIEND, 5);
+
+ if (you.pet_target == MHITNOT)
+ you.pet_target = monster_attacked;
+
+ // fumbling in shallow water <early return>:
+ if (player_in_water() && !player_is_swimming())
+ {
+ if (random2(you.dex) < 4 || one_chance_in(5))
+ {
+ mpr("Unstable footing causes you to fumble your attack.");
+ return;
+ }
+ }
+
+ // wet merfolk
+ if (player_is_swimming()
+ // monster not a water creature
+ && monster_habitat( defender->type ) != DNGN_DEEP_WATER
+ && !mons_flag( defender->type, M_AMPHIBIOUS )
+ // monster in water
+ && (grd[defender->x][defender->y] == DNGN_SHALLOW_WATER
+ || grd[defender->x][defender->y] == DNGN_DEEP_WATER)
+ // monster not flying
+ && !mons_flies( defender ))
+ {
+ water_attack = true;
+ }
+
+ // preliminary to_hit modifications:
+ your_to_hit = 15 + (calc_stat_to_hit_base() / 2);
+
+ if (water_attack)
+ your_to_hit += 5;
+
+ if (wearing_amulet(AMU_INACCURACY))
+ your_to_hit -= 5;
+
+ // if you can't see yourself, you're a little less acurate.
+ if (you.invis && !player_see_invis())
+ your_to_hit -= 5;
+
+ your_to_hit += random2(1 + you.skills[SK_FIGHTING]);
+
+ if (ur_armed)
+ {
+ if (wpn_skill)
+ your_to_hit += random2(you.skills[wpn_skill] + 1);
+ }
+ else // ...you must be unarmed
+ {
+ your_to_hit += (you.species == SP_TROLL
+ || you.species == SP_GHOUL) ? 4 : 2;
+
+ your_to_hit += random2(1 + you.skills[SK_UNARMED_COMBAT]);
+ }
+
+ // energy expenditure in terms of food:
+ make_hungry(3, true);
+
+ if (ur_armed
+ && you.inv[ weapon ].base_type == OBJ_WEAPONS
+ && is_random_artefact( you.inv[ weapon ] ))
+ {
+ if (art_proprt[RAP_ANGRY] >= 1)
+ {
+ if (random2(1 + art_proprt[RAP_ANGRY]))
+ {
+ go_berserk(false);
+ }
+ }
+ }
+
+ switch (you.special_wield)
+ {
+ case SPWLD_TROG:
+ if (coinflip())
+ go_berserk(false);
+ break;
+
+ case SPWLD_WUCAD_MU:
+ if (one_chance_in(9))
+ {
+ miscast_effect( SPTYP_DIVINATION, random2(9), random2(70), 100,
+ "the Staff of Wucad Mu" );
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (you.mutation[MUT_BERSERK])
+ {
+ if (random2(100) < (you.mutation[MUT_BERSERK] * 10) - 5)
+ go_berserk(false);
+ }
+
+ if (ur_armed)
+ {
+ if (you.inv[ weapon ].base_type == OBJ_WEAPONS)
+ {
+ // there was some stupid conditional here that applied this
+ // "if (plus >= 0)" and "else" that .. which is all
+ // cases (d'oh!) {dlb}
+ your_to_hit += you.inv[ weapon ].plus;
+ your_to_hit += property( you.inv[ weapon ], PWPN_HIT );
+
+ if (cmp_equip_race( you.inv[ weapon ], ISFLAG_ELVEN )
+ && player_genus(GENPC_ELVEN))
+ {
+ your_to_hit += (coinflip() ? 2 : 1);
+ }
+ }
+ else if (item_is_staff( you.inv[ weapon ] ))
+ {
+ /* magical staff */
+ your_to_hit += property( you.inv[ weapon ], PWPN_HIT );
+ }
+ }
+
+ your_to_hit += slaying_bonus(PWPN_HIT); // see: player.cc
+
+ if (you.hunger_state == HS_STARVING)
+ your_to_hit -= 3;
+
+ your_to_hit -= heavy_armour;
+
+#if DEBUG_DIAGNOSTICS
+ int roll_hit = your_to_hit;
+#endif
+
+ // why does this come here and not later? {dlb}
+ // apparently to give the following pluses more significance -- bwr
+ your_to_hit = random2(your_to_hit);
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "to hit die: %d; rolled value: %d",
+ roll_hit, your_to_hit );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ if (use_hand_and_a_half_bonus)
+ your_to_hit += random2(3);
+
+ if (ur_armed && wpn_skill == SK_SHORT_BLADES && you.sure_blade)
+ your_to_hit += 5 + random2limit( you.sure_blade, 10 );
+
+ int damage = 1;
+
+ if (!ur_armed) // empty-handed
+ {
+ damage = 3;
+
+ if (you.confusing_touch)
+ {
+ // just trying to touch is easier that trying to damage
+ // special_brand = SPWPN_CONFUSE;
+ your_to_hit += random2(you.dex);
+ // no base hand damage while using this spell
+ damage = 0;
+ }
+
+ // if (you.mutation[MUT_DRAIN_LIFE])
+ // special_brand = SPWPN_DRAINING;
+
+ if (you.attribute[ATTR_TRANSFORMATION] != TRAN_NONE)
+ {
+ switch (you.attribute[ATTR_TRANSFORMATION])
+ {
+ case TRAN_SPIDER:
+ damage = 5;
+ // special_brand = SPWPN_VENOM;
+ your_to_hit += random2(10);
+ break;
+ case TRAN_ICE_BEAST:
+ damage = 12;
+ // special_brand = SPWPN_FREEZING;
+ your_to_hit += random2(10);
+ break;
+ case TRAN_BLADE_HANDS:
+ damage = 12 + (you.strength / 4) + (you.dex / 4);
+ your_to_hit += random2(12);
+ break;
+ case TRAN_STATUE:
+ damage = 12 + you.strength;
+ your_to_hit += random2(9);
+ break;
+ case TRAN_SERPENT_OF_HELL:
+ case TRAN_DRAGON:
+ damage = 20 + you.strength;
+ your_to_hit += random2(10);
+ break;
+ case TRAN_LICH:
+ damage = 5;
+ // special_brand = SPWPN_DRAINING;
+ your_to_hit += random2(10);
+ break;
+ case TRAN_AIR:
+ damage = 0;
+ your_to_hit = 0;
+ break;
+ }
+ }
+ else if (you.equip[ EQ_GLOVES ] == -1)
+ {
+ // claw damage only applies for bare hands
+ if (you.species == SP_TROLL)
+ damage += 5;
+ else if (you.species == SP_GHOUL)
+ damage += 2;
+
+ damage += (you.mutation[ MUT_CLAWS ] * 2);
+ }
+
+ damage += you.skills[SK_UNARMED_COMBAT];
+ }
+ else
+ {
+ if (you.inv[ weapon ].base_type == OBJ_WEAPONS
+ || item_is_staff( you.inv[ weapon ] ))
+ {
+ damage = property( you.inv[ weapon ], PWPN_DAMAGE );
+ }
+ }
+
+#if DEBUG_DIAGNOSTICS
+ const int base_damage = damage;
+#endif
+
+ //jmf: check for backlight enchantment
+ if (mons_has_ench(defender, ENCH_BACKLIGHT_I, ENCH_BACKLIGHT_IV))
+ your_to_hit += 2 + random2(8);
+
+ int weapon_speed2 = 10;
+ int min_speed = 3;
+
+ if (ur_armed)
+ {
+ if (you.inv[ weapon ].base_type == OBJ_WEAPONS
+ || item_is_staff( you.inv[ weapon ] ))
+ {
+ weapon_speed2 = property( you.inv[ weapon ], PWPN_SPEED );
+ weapon_speed2 -= you.skills[ wpn_skill ] / 2;
+
+ min_speed = property( you.inv[ weapon ], PWPN_SPEED ) / 2;
+
+ // Short blades can get up to at least unarmed speed.
+ if (wpn_skill == SK_SHORT_BLADES && min_speed > 5)
+ min_speed = 5;
+
+ // Using both hands can get a weapon up to speed 7
+ if ((hands_reqd == HANDS_TWO_HANDED || use_hand_and_a_half_bonus)
+ && min_speed > 7)
+ {
+ min_speed = 7;
+ }
+
+ // never go faster than speed 3 (ie 3 attacks per round)
+ if (min_speed < 3)
+ min_speed = 3;
+
+ // Hand and a half bonus only helps speed up to a point, any more
+ // than speed 10 must come from skill and the weapon
+ if (use_hand_and_a_half_bonus && weapon_speed2 > 10)
+ weapon_speed2--;
+
+ // apply minimum to weapon skill modification
+ if (weapon_speed2 < min_speed)
+ weapon_speed2 = min_speed;
+
+ if (you.inv[weapon].base_type == OBJ_WEAPONS
+ && melee_brand == SPWPN_SPEED)
+ {
+ weapon_speed2 = (weapon_speed2 + 1) / 2;
+ }
+ }
+ }
+ else
+ {
+ // Unarmed speed
+ if (you.burden_state == BS_UNENCUMBERED
+ && one_chance_in(heavy_armour + 1))
+ {
+ weapon_speed2 = 10 - you.skills[SK_UNARMED_COMBAT] / 3;
+
+ if (weapon_speed2 < 4)
+ weapon_speed2 = 4;
+ }
+ }
+
+ if (bearing_shield)
+ {
+ switch (you.inv[you.equip[EQ_SHIELD]].sub_type)
+ {
+ case ARM_SHIELD:
+ weapon_speed2++;
+ break;
+ case ARM_LARGE_SHIELD:
+ weapon_speed2 += 2;
+ break;
+ }
+ }
+
+ // Never allow anything faster than 3 to get through... three attacks
+ // per round is enough... 5 or 10 is just silly. -- bwr
+ if (weapon_speed2 < 3)
+ weapon_speed2 = 3;
+
+ you.time_taken *= weapon_speed2;
+ you.time_taken /= 10;
+
+ if (you.time_taken < 1)
+ you.time_taken = 1;
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "Weapon speed: %d; min: %d; speed: %d; attack time: %d",
+ weapon_speed2, min_speed, weapon_speed2, you.time_taken );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ // DO STABBING
+
+ bool stabAttempt = false;
+ bool rollNeeded = true;
+
+ // This ordering is important!
+
+ // not paying attention (but not batty)
+ if (defender->foe != MHITYOU && !testbits(defender->flags, MF_BATTY))
+ {
+ stabAttempt = true;
+ stab_bonus = 3;
+ }
+
+ // confused (but not perma-confused)
+ if (mons_has_ench(defender, ENCH_CONFUSION)
+ && !mons_flag(defender->type, M_CONFUSED))
+ {
+ stabAttempt = true;
+ stab_bonus = 2;
+ }
+
+ // fleeing
+ if (defender->behaviour == BEH_FLEE)
+ {
+ stabAttempt = true;
+ stab_bonus = 2;
+ }
+
+ // sleeping
+ if (defender->behaviour == BEH_SLEEP)
+ {
+ stabAttempt = true;
+ rollNeeded = false;
+ stab_bonus = 1;
+ }
+
+ // helpless (plants, etc)
+ if (helpless)
+ stabAttempt = false;
+
+ // see if we need to roll against dexterity / stabbing
+ if (stabAttempt && rollNeeded)
+ stabAttempt = (random2(200) <= you.skills[SK_STABBING] + you.dex);
+
+ // check for invisibility - no stabs on invisible monsters.
+ if (!player_monster_visible( defender ))
+ {
+ stabAttempt = false;
+ stab_bonus = 0;
+ }
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "your to-hit: %d; defender EV: %d",
+ your_to_hit, defender->evasion );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ if ((your_to_hit >= defender->evasion || one_chance_in(30))
+ || ((defender->speed_increment <= 60
+ || defender->behaviour == BEH_SLEEP)
+ && !one_chance_in(10 + you.skills[SK_STABBING])))
+ {
+ hit = true;
+ int dammod = 78;
+
+ const int dam_stat_val = calc_stat_to_dam_base();
+
+ if (dam_stat_val > 11)
+ dammod += (random2(dam_stat_val - 11) * 2);
+ else if (dam_stat_val < 9)
+ dammod -= (random2(9 - dam_stat_val) * 3);
+
+ damage *= dammod; //random2(you.strength);
+ damage /= 78;
+
+#if DEBUG_DIAGNOSTICS
+ const int str_damage = damage;
+#endif
+
+ // Yes, this isn't the *2 damage that monsters get, but since
+ // monster hps and player hps are different (as are the sizes
+ // of the attacks) it just wouldn't be fair to give merfolk
+ // that gross a potential... still they do get something for
+ // making use of the water. -- bwr
+ if (water_attack)
+ damage += random2avg(10,2);
+
+#if DEBUG_DIAGNOSTICS
+ const int water_damage = damage;
+#endif
+
+ // apply damage bonus from ring of slaying
+ // (before randomization -- some of these rings
+ // are stupidly powerful) -- GDL
+ damage += slaying_bonus(PWPN_DAMAGE);
+
+#if DEBUG_DIAGNOSTICS
+ const int slay_damage = damage;
+
+ snprintf( info, INFO_SIZE,
+ "melee base: %d; str: %d; water: %d; to-dam: %d",
+ base_damage, str_damage, water_damage, slay_damage );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ damage_done = random2(damage);
+
+#if DEBUG_DIAGNOSTICS
+ const int roll_damage = damage_done;
+#endif
+
+ if (ur_armed && (you.inv[ weapon ].base_type == OBJ_WEAPONS
+ || item_is_staff( you.inv[ weapon ] )))
+ {
+ damage_done *= 25 + (random2( you.skills[ wpn_skill ] + 1 ));
+ damage_done /= 25;
+ }
+
+#if DEBUG_DIAGNOSTICS
+ const int skill_damage = damage_done;
+#endif
+
+ damage_done *= 30 + (random2(you.skills[SK_FIGHTING] + 1));
+ damage_done /= 30;
+
+#if DEBUG_DIAGNOSTICS
+ const int fight_damage = damage_done;
+#endif
+
+ if (you.might > 1)
+ damage_done += 1 + random2(10);
+
+ if (you.hunger_state == HS_STARVING)
+ damage_done -= random2(5);
+
+#if DEBUG_DIAGNOSTICS
+ const int preplus_damage = damage_done;
+ int plus_damage = damage_done;
+ int bonus_damage = damage_done;
+#endif
+
+ if (ur_armed && you.inv[ weapon ].base_type == OBJ_WEAPONS)
+ {
+ int hoggl = you.inv[ weapon ].plus2;
+
+ damage_done += (hoggl > -1) ? (random2(1 + hoggl)) : (hoggl);
+
+#if DEBUG_DIAGNOSTICS
+ plus_damage = damage_done;
+#endif
+
+ // removed 2-handed weapons from here... their "bonus" is
+ // already included in the damage stat for the weapon -- bwr
+ if (use_hand_and_a_half_bonus)
+ damage_done += random2(3);
+
+ if (cmp_equip_race( you.inv[ weapon ], ISFLAG_DWARVEN )
+ && player_genus(GENPC_DWARVEN))
+ {
+ damage_done += random2(3);
+ }
+
+ if (cmp_equip_race( you.inv[ weapon ], ISFLAG_ORCISH )
+ && you.species == SP_HILL_ORC && coinflip())
+ {
+ damage_done++;
+ }
+
+#if DEBUG_DIAGNOSTICS
+ bonus_damage = damage_done;
+#endif
+
+ if (!launches_things( you.inv[ weapon ].sub_type )
+ && item_not_ident( you.inv[ weapon ], ISFLAG_KNOW_PLUSES )
+ && random2(100) < you.skills[ wpn_skill ])
+ {
+ set_ident_flags( you.inv[ weapon ], ISFLAG_KNOW_PLUSES );
+ strcpy(info, "You are wielding ");
+ in_name( weapon , DESC_NOCAP_A, str_pass );
+ strcat(info, str_pass);
+ strcat(info, ".");
+ mpr(info);
+ more();
+ you.wield_change = true;
+ }
+ }
+
+ // The stabbing message looks better here:
+ if (stabAttempt)
+ {
+ // construct reasonable message
+ stab_message( defender, stab_bonus );
+
+ exercise(SK_STABBING, 1 + random2avg(5, 4));
+
+ if (mons_holiness(defender->type) == MH_NATURAL
+ || mons_holiness(defender->type) == MH_HOLY)
+ {
+ naughty(NAUGHTY_STABBING, 4);
+ }
+ }
+ else
+ {
+ stab_bonus = 0;
+ // ok.. if you didn't backstab, you wake up the neighborhood.
+ // I can live with that.
+ alert_nearby_monsters();
+ }
+
+#if DEBUG_DIAGNOSTICS
+ int stab_damage = damage_done;
+#endif
+
+ if (stab_bonus)
+ {
+ // lets make sure we have some damage to work with...
+ if (damage_done < 1)
+ damage_done = 1;
+
+ if (defender->behaviour == BEH_SLEEP)
+ {
+ // Sleeping moster wakes up when stabbed but may be groggy
+ if (random2(200) <= you.skills[SK_STABBING] + you.dex)
+ {
+ unsigned int stun = random2( you.dex + 1 );
+
+ if (defender->speed_increment > stun)
+ defender->speed_increment -= stun;
+ else
+ defender->speed_increment = 0;
+ }
+ }
+
+ switch (wpn_skill)
+ {
+ case SK_SHORT_BLADES:
+ {
+ int bonus = (you.dex * (you.skills[SK_STABBING] + 1)) / 5;
+
+ if (you.inv[ weapon ].sub_type != WPN_DAGGER)
+ bonus /= 2;
+
+ bonus = stepdown_value( bonus, 10, 10, 30, 30 );
+
+ damage_done += bonus;
+ }
+ // fall through
+ case SK_LONG_SWORDS:
+ damage_done *= 10 + you.skills[SK_STABBING] /
+ (stab_bonus + (wpn_skill == SK_SHORT_BLADES ? 0 : 1));
+ damage_done /= 10;
+ // fall through
+ default:
+ damage_done *= 12 + you.skills[SK_STABBING] / stab_bonus;
+ damage_done /= 12;
+ }
+
+#if DEBUG_DIAGNOSTICS
+ stab_damage = damage_done;
+#endif
+
+ // when stabbing we can get by some of the armour
+ if (defender->armour_class > 0)
+ {
+ int ac = defender->armour_class
+ - random2( you.skills[SK_STABBING] / stab_bonus );
+
+ if (ac > 0)
+ damage_done -= random2(1 + ac);
+ }
+ }
+ else
+ {
+ // apply AC normally
+ if (defender->armour_class > 0)
+ damage_done -= random2(1 + defender->armour_class);
+ }
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE,
+ "melee roll: %d; skill: %d; fight: %d; pre wpn plus: %d",
+ roll_damage, skill_damage, fight_damage, preplus_damage );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+
+ snprintf( info, INFO_SIZE,
+ "melee plus: %d; bonus: %d; stab: %d; post AC: %d",
+ plus_damage, bonus_damage, stab_damage, damage_done );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ // This doesn't actually modify damage -- bwr
+ damage_done = weapon_type_modify( weapon, damage_noise, damage_noise2,
+ damage_done );
+
+ if (damage_done < 0)
+ damage_done = 0;
+
+ // always upset monster regardless of damage
+ behaviour_event(defender, ME_WHACK, MHITYOU);
+
+ if (hurt_monster(defender, damage_done))
+ {
+ if (ur_armed && wpn_skill)
+ {
+ if (!helpless || you.skills[ wpn_skill ] < 2)
+ exercise( wpn_skill, 1 );
+ }
+ else
+ {
+ if (!helpless || you.skills[SK_UNARMED_COMBAT] < 2)
+ exercise(SK_UNARMED_COMBAT, 1);
+ }
+
+ if ((!helpless || you.skills[SK_FIGHTING] < 2)
+ && one_chance_in(3))
+ {
+ exercise(SK_FIGHTING, 1);
+ }
+ }
+
+ if (defender->hit_points < 1)
+ {
+#if DEBUG_DIAGNOSTICS
+ /* note: doesn't take account of special weapons etc */
+ snprintf( info, INFO_SIZE, "Hit for %d.", damage_done );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+ if (ur_armed && melee_brand == SPWPN_VAMPIRICISM)
+ {
+ if (mons_holiness(defender->type) == MH_NATURAL
+ && damage_done > 0 && you.hp < you.hp_max
+ && !one_chance_in(5))
+ {
+ mpr("You feel better.");
+
+ // more than if not killed
+ inc_hp(1 + random2(damage_done), false);
+
+ if (you.hunger_state != HS_ENGORGED)
+ lessen_hunger(30 + random2avg(59, 2), true);
+
+ naughty(NAUGHTY_NECROMANCY, 2);
+ }
+ }
+
+ monster_die(defender, KILL_YOU, 0);
+
+ if (defender->type == MONS_GIANT_SPORE)
+ {
+ snprintf( info, INFO_SIZE, "You %s the giant spore.", damage_noise);
+ mpr(info);
+ }
+ else if (defender->type == MONS_BALL_LIGHTNING)
+ {
+ snprintf( info, INFO_SIZE, "You %s the ball lightning.", damage_noise);
+ mpr(info);
+ }
+ return;
+ }
+
+ if (damage_done < 1 && player_monster_visible( defender ))
+ {
+ hit = true;
+
+ snprintf( info, INFO_SIZE, "You %s ", damage_noise);
+ strcat(info, ptr_monam(defender, DESC_NOCAP_THE));
+ strcat(info, ", but do no damage.");
+ mpr(info);
+ }
+ }
+ else
+ {
+ hit = false;
+
+ // upset only non-sleeping monsters if we missed
+ if (defender->behaviour != BEH_SLEEP)
+ behaviour_event( defender, ME_WHACK, MHITYOU );
+
+ if ((your_to_hit + heavy_armour / 2) >= defender->evasion)
+ strcpy(info, "Your armour prevents you from hitting ");
+ else
+ strcpy(info, "You miss ");
+
+ strcat(info, ptr_monam(defender, DESC_NOCAP_THE));
+ strcat(info, ".");
+ mpr(info);
+ }
+
+ if (hit && damage_done > 0
+ || (hit && damage_done < 1 && mons_has_ench(defender,ENCH_INVIS)))
+ {
+ strcpy(info, "You ");
+ strcat(info, damage_noise);
+ strcat(info, " ");
+ strcat(info, ptr_monam(defender, DESC_NOCAP_THE));
+ strcat(info, damage_noise2);
+
+#if DEBUG_DIAGNOSTICS
+ strcat( info, " for " );
+ /* note: doesn't take account of special weapons etc */
+ itoa( damage_done, st_prn, 10 );
+ strcat( info, st_prn );
+#endif
+ if (damage_done < HIT_WEAK)
+ strcat(info, ".");
+ else if (damage_done < HIT_MED)
+ strcat(info, "!");
+ else if (damage_done < HIT_STRONG)
+ strcat(info, "!!");
+ else
+ strcat(info, "!!!");
+
+ mpr(info);
+
+ if (mons_holiness(defender->type) == MH_HOLY)
+ done_good(GOOD_KILLED_ANGEL_I, 1);
+
+ if (you.special_wield == SPWLD_TORMENT)
+ {
+ torment(you.x_pos, you.y_pos);
+ naughty(NAUGHTY_UNHOLY, 5);
+ }
+
+ if (you.special_wield == SPWLD_ZONGULDROK
+ || you.special_wield == SPWLD_CURSE)
+ {
+ naughty(NAUGHTY_NECROMANCY, 3);
+ }
+ }
+
+ if (defender->type == MONS_JELLY
+ || defender->type == MONS_BROWN_OOZE
+ || defender->type == MONS_ACID_BLOB
+ || defender->type == MONS_ROYAL_JELLY)
+ {
+ weapon_acid(5);
+ }
+
+ /* remember, damage_done is still useful! */
+ if (hit)
+ {
+ int specdam = 0;
+
+ if (ur_armed
+ && you.inv[ weapon ].base_type == OBJ_WEAPONS
+ && is_demonic( you.inv[ weapon ].sub_type ))
+ {
+ naughty(NAUGHTY_UNHOLY, 1);
+ }
+
+ if (mons_holiness(defender->type) == MH_HOLY)
+ naughty(NAUGHTY_ATTACK_HOLY, defender->hit_dice);
+
+ if (defender->type == MONS_HYDRA)
+ {
+ const int dam_type = player_damage_type();
+ const int wpn_brand = player_damage_brand();
+
+ if ((dam_type == DVORP_SLICING || dam_type == DVORP_CHOPPING)
+ && damage_done > 0
+ && (damage_done >= 4 || wpn_brand == SPWPN_VORPAL || coinflip()))
+ {
+ defender->number--;
+
+ temp_rand = random2(4);
+ const char *const verb = (temp_rand == 0) ? "slice" :
+ (temp_rand == 1) ? "lop" :
+ (temp_rand == 2) ? "chop" : "hack";
+
+ if (defender->number < 1)
+ {
+ snprintf( info, INFO_SIZE, "You %s %s's last head off!",
+ verb, ptr_monam(defender, DESC_NOCAP_THE) );
+ mpr( info );
+
+ defender->hit_points = -1;
+ }
+ else
+ {
+ snprintf( info, INFO_SIZE, "You %s one of %s's heads off!",
+ verb, ptr_monam(defender, DESC_NOCAP_THE) );
+ mpr( info );
+
+ if (wpn_brand == SPWPN_FLAMING)
+ mpr( "The flame cauterises the wound!" );
+ else if (defender->number < 19)
+ {
+ simple_monster_message( defender, " grows two more!" );
+ defender->number += 2;
+ heal_monster( defender, 8 + random2(8), true );
+ }
+ }
+
+ // if the hydra looses a head:
+ // - it's dead if it has none remaining (HP set to -1)
+ // - flame used to cauterise doesn't do extra damage
+ // - ego weapons do their additional damage to the
+ // hydra's decapitated head, so it's ignored.
+ //
+ // ... and so we skip the special damage.
+ goto mons_dies;
+ }
+ }
+
+ // jmf: BEGIN STAFF HACK
+ // How much bonus damage will a staff of <foo> do?
+ // FIXME: make these not macros. inline functions?
+ // actually, it will all be pulled out and replaced by functions -- {dlb}
+ //
+ // This is similar to the previous, in both value and distribution, except
+ // that instead of just SKILL, its now averaged with Evocations. -- bwr
+#define STAFF_DAMAGE(SKILL) (roll_dice( 3, 1 + (you.skills[(SKILL)] + you.skills[SK_EVOCATIONS]) / 12 ))
+
+#define STAFF_COST 2
+
+ // magic staves have their own special damage
+ if (ur_armed && item_is_staff( you.inv[weapon] ))
+ {
+ specdam = 0;
+
+ if (you.magic_points >= STAFF_COST
+ && random2(20) <= you.skills[SK_EVOCATIONS])
+ {
+ switch (you.inv[weapon].sub_type)
+ {
+ case STAFF_AIR:
+ if (damage_done + you.skills[SK_AIR_MAGIC] > random2(30))
+ {
+ if (mons_res_elec(defender))
+ break;
+
+ specdam = STAFF_DAMAGE(SK_AIR_MAGIC);
+
+ if (specdam)
+ {
+ snprintf( info, INFO_SIZE, "%s is jolted!",
+ ptr_monam(defender, DESC_CAP_THE) );
+ mpr(info);
+ }
+ }
+ break;
+
+ case STAFF_COLD: // FIXME: I don't think I used these right ...
+ if (mons_res_cold(defender) > 0)
+ break;
+
+ specdam = STAFF_DAMAGE(SK_ICE_MAGIC);
+
+ if (mons_res_cold(defender) < 0)
+ specdam += STAFF_DAMAGE(SK_ICE_MAGIC);
+
+ if (specdam)
+ {
+
+ snprintf( info, INFO_SIZE, "You freeze %s!",
+ ptr_monam(defender, DESC_NOCAP_THE) );
+ mpr(info);
+ }
+ break;
+
+ case STAFF_EARTH:
+ if (mons_flies(defender))
+ break; //jmf: lame, but someone ought to resist
+
+ specdam = STAFF_DAMAGE(SK_EARTH_MAGIC);
+
+ if (specdam)
+ {
+ snprintf( info, INFO_SIZE, "You crush %s!",
+ ptr_monam(defender, DESC_NOCAP_THE) );
+ mpr(info);
+ }
+ break;
+
+ case STAFF_FIRE:
+ if (mons_res_fire(defender) > 0)
+ break;
+
+ specdam = STAFF_DAMAGE(SK_FIRE_MAGIC);
+
+ if (mons_res_fire(defender) < 0)
+ specdam += STAFF_DAMAGE(SK_FIRE_MAGIC);
+
+ if (specdam)
+ {
+ snprintf( info, INFO_SIZE, "You burn %s!",
+ ptr_monam(defender, DESC_NOCAP_THE) );
+ mpr(info);
+ }
+ break;
+
+ case STAFF_POISON:
+ // cap chance at 30% -- let staff of Olgreb shine
+ temp_rand = damage_done + you.skills[SK_POISON_MAGIC];
+
+ if (temp_rand > 30)
+ temp_rand = 30;
+
+ if (random2(100) < temp_rand)
+ poison_monster(defender, true);
+ break;
+
+ case STAFF_DEATH:
+ if (mons_res_negative_energy(defender) > 0)
+ break;
+
+ if (random2(8) <= you.skills[SK_NECROMANCY])
+ {
+ specdam = STAFF_DAMAGE(SK_NECROMANCY);
+
+ if (specdam)
+ {
+ snprintf( info, INFO_SIZE, "%s convulses in agony!",
+ ptr_monam(defender, DESC_CAP_THE) );
+ mpr(info);
+
+ naughty(NAUGHTY_NECROMANCY, 4);
+ }
+ }
+ break;
+
+ case STAFF_POWER:
+ case STAFF_SUMMONING:
+ case STAFF_CHANNELING:
+ case STAFF_CONJURATION:
+ case STAFF_ENCHANTMENT:
+ case STAFF_ENERGY:
+ case STAFF_WIZARDRY:
+ break;
+
+ default:
+ mpr("You're wielding some staff I've never heard of! (fight.cc)");
+ break;
+ } // end switch
+ }
+
+ if (specdam > 0)
+ {
+ dec_mp(STAFF_COST);
+
+ if (item_not_ident( you.inv[weapon], ISFLAG_KNOW_TYPE ))
+ {
+ set_ident_flags( you.inv[weapon], ISFLAG_KNOW_TYPE );
+ strcpy(info, "You are wielding ");
+ in_name( weapon, DESC_NOCAP_A, str_pass);
+ strcat(info, str_pass);
+ strcat(info, ".");
+ mpr(info);
+ more();
+ you.wield_change = true;
+ }
+ }
+#undef STAFF_DAMAGE
+#undef STAFF_COST
+// END STAFF HACK
+ }
+ else
+ {
+ // handle special brand damage (unarmed or armed non-staff ego):
+ int res = 0;
+
+ switch (melee_brand)
+ {
+ case SPWPN_NORMAL:
+ break;
+
+ case SPWPN_FLAMING:
+ specdam = 0;
+
+ res = mons_res_fire(defender);
+ if (ur_armed && you.inv[weapon].special == SPWPN_SWORD_OF_CEREBOV)
+ {
+ if (res < 3 && res > 0)
+ res = 0;
+ else if (res == 0)
+ res = -1;
+ }
+
+ if (res == 0)
+ specdam = random2(damage_done) / 2 + 1;
+ else if (res < 0)
+ specdam = random2(damage_done) + 1;
+
+ if (specdam)
+ {
+ strcpy(info, "You burn ");
+ strcat(info, ptr_monam(defender, DESC_NOCAP_THE));
+
+ if (specdam < 3)
+ strcat(info, ".");
+ else if (specdam < 7)
+ strcat(info, "!");
+ else
+ strcat(info, "!!");
+
+ mpr(info);
+ }
+ break;
+
+ case SPWPN_FREEZING:
+ specdam = 0;
+
+ res = mons_res_cold(defender);
+ if (res == 0)
+ specdam = 1 + random2(damage_done) / 2;
+ else if (res < 0)
+ specdam = 1 + random2(damage_done);
+
+ if (specdam)
+ {
+ strcpy(info, "You freeze ");
+ strcat(info, ptr_monam(defender, DESC_NOCAP_THE));
+
+ if (specdam < 3)
+ strcat(info, ".");
+ else if (specdam < 7)
+ strcat(info, "!");
+ else
+ strcat(info, "!!");
+
+ mpr(info);
+ }
+ break;
+
+ case SPWPN_HOLY_WRATH:
+ // there should be a case in here for holy monsters,
+ // see elsewhere in fight.cc {dlb}
+ specdam = 0;
+ switch (mons_holiness(defender->type))
+ {
+ case MH_UNDEAD:
+ specdam = 1 + random2(damage_done);
+ break;
+
+ case MH_DEMONIC:
+ specdam = 1 + (random2(damage_done * 15) / 10);
+ break;
+ }
+ break;
+
+
+ case SPWPN_ELECTROCUTION:
+ specdam = 0;
+
+ if (mons_flies(defender))
+ break;
+ else if (mons_res_elec(defender) > 0)
+ break;
+ else if (one_chance_in(3))
+ {
+ mpr("There is a sudden explosion of sparks!");
+ specdam = random2avg(28, 3);
+ }
+ break;
+
+ case SPWPN_ORC_SLAYING:
+ if (mons_charclass(defender->type) == MONS_ORC)
+ hurt_monster(defender, 1 + random2(damage_done));
+ break;
+
+ case SPWPN_VENOM:
+ if (!one_chance_in(4))
+ poison_monster(defender, true);
+ break;
+
+ case SPWPN_DRAINING:
+ if (mons_res_negative_energy(defender) > 0 || one_chance_in(3))
+ break;
+
+ strcpy(info, "You drain ");
+ strcat(info, ptr_monam(defender, DESC_NOCAP_THE));
+ strcat(info, "!");
+ mpr(info);
+
+ if (one_chance_in(5))
+ defender->hit_dice--;
+
+ defender->max_hit_points -= 2 + random2(3);
+ defender->hit_points -= 2 + random2(3);
+
+ if (defender->hit_points >= defender->max_hit_points)
+ defender->hit_points = defender->max_hit_points;
+
+ if (defender->hit_dice < 1)
+ defender->hit_points = 0;
+
+ specdam = 1 + (random2(damage_done) / 2);
+ naughty( NAUGHTY_NECROMANCY, 2 );
+ break;
+
+ /* 9 = speed - done before */
+
+ case SPWPN_VORPAL:
+ specdam = 1 + random2(damage_done) / 2;
+ break;
+
+ case SPWPN_VAMPIRICISM:
+ specdam = 0; // NB: does no extra damage
+
+ if (mons_holiness(defender->type) != MH_NATURAL)
+ break;
+ else if (mons_res_negative_energy(defender) > 0)
+ break;
+ else if (damage_done < 1)
+ break;
+ else if (you.hp == you.hp_max || one_chance_in(5))
+ break;
+
+ mpr("You feel better.");
+
+ // thus is probably more valuable on larger weapons?
+ if (ur_armed
+ && is_fixed_artefact( you.inv[weapon] )
+ && you.inv[weapon].special == SPWPN_VAMPIRES_TOOTH)
+ {
+ inc_hp(damage_done, false);
+ }
+ else
+ inc_hp(1 + random2(damage_done), false);
+
+ if (you.hunger_state != HS_ENGORGED)
+ lessen_hunger(random2avg(59, 2), true);
+
+ naughty( NAUGHTY_NECROMANCY, 2 );
+ break;
+
+ case SPWPN_DISRUPTION:
+ specdam = 0;
+ if (mons_holiness(defender->type) == MH_UNDEAD && !one_chance_in(3))
+ {
+ simple_monster_message(defender, " shudders.");
+ specdam += random2avg((1 + (damage_done * 3)), 3);
+ }
+ break;
+
+ case SPWPN_PAIN:
+ specdam = 0;
+ if (mons_res_negative_energy(defender) <= 0
+ && random2(8) <= you.skills[SK_NECROMANCY])
+ {
+ simple_monster_message(defender, " convulses in agony.");
+ specdam += random2( 1 + you.skills[SK_NECROMANCY] );
+ }
+ naughty(NAUGHTY_NECROMANCY, 4);
+ break;
+
+ case SPWPN_DISTORTION:
+ //jmf: blink frogs *like* distortion
+ // I think could be amended to let blink frogs "grow" like
+ // jellies do {dlb}
+ if (defender->type == MONS_BLINK_FROG)
+ {
+ if (one_chance_in(5))
+ {
+ simple_monster_message( defender,
+ " basks in the translocular energy." );
+ heal_monster(defender, 1 + random2avg(7, 2), true); // heh heh
+ }
+ break;
+ }
+
+ if (one_chance_in(3))
+ {
+ strcpy(info, "Space bends around ");
+ strcat(info, ptr_monam(defender, DESC_NOCAP_THE));
+ strcat(info, ".");
+ mpr(info);
+ specdam += 1 + random2avg(7, 2);
+ break;
+ }
+
+ if (one_chance_in(3))
+ {
+ strcpy(info, "Space warps horribly around ");
+ strcat(info, ptr_monam(defender, DESC_NOCAP_THE));
+ strcat(info, "!");
+ mpr(info);
+ specdam += 3 + random2avg(24, 2);
+ break;
+ }
+
+ if (one_chance_in(3))
+ {
+ monster_blink(defender);
+ break;
+ }
+
+ if (coinflip())
+ {
+ monster_teleport(defender, coinflip());
+ break;
+ }
+
+ if (coinflip())
+ {
+ monster_die(defender, KILL_RESET, 0);
+ return;
+ }
+ break;
+
+ case SPWPN_CONFUSE:
+ {
+ // declaring these just to pass to the enchant function
+ struct bolt beam_temp;
+ beam_temp.flavour = BEAM_CONFUSION;
+
+ mons_ench_f2( defender, beam_temp );
+
+ you.confusing_touch -= random2(20);
+
+ if (you.confusing_touch < 1)
+ you.confusing_touch = 1;
+ }
+ break;
+ } /* end switch */
+ }
+
+ /* remember, the hydra function sometimes skips straight to mons_dies */
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "brand: %d; melee special damage: %d",
+ melee_brand, specdam );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ hurt_monster( defender, specdam );
+ } // end if (hit)
+
+ mons_dies:
+ if (defender->hit_points < 1)
+ {
+ monster_die(defender, KILL_YOU, 0);
+ return;
+ }
+
+ if (unarmed_attacks)
+ {
+ char attack_name[20] = "";
+ int sc_dam = 0;
+ int brand = SPWPN_NORMAL;
+
+ int unarmed_attack = UNAT_NO_ATTACK;
+
+ if (can_do_unarmed_combat)
+ {
+ if (you.species == SP_NAGA)
+ unarmed_attack = UNAT_HEADBUTT;
+ else
+ unarmed_attack = (coinflip() ? UNAT_HEADBUTT : UNAT_KICK);
+
+ if ((you.attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON
+ || player_genus(GENPC_DRACONIAN)
+ || (you.species == SP_MERFOLK && player_is_swimming())
+ || you.mutation[ MUT_STINGER ])
+ && one_chance_in(3))
+ {
+ unarmed_attack = UNAT_TAILSLAP;
+ }
+
+ if (coinflip())
+ unarmed_attack = UNAT_PUNCH;
+ }
+
+ for (unsigned char scount = 0; scount < 4; scount++)
+ {
+ brand = SPWPN_NORMAL;
+
+ switch (scount)
+ {
+ case 0:
+ if (unarmed_attack != UNAT_KICK) //jmf: hooves mutation
+ {
+ if ((you.species != SP_CENTAUR && !you.mutation[MUT_HOOVES])
+ || coinflip())
+ {
+ continue;
+ }
+ }
+
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_SERPENT_OF_HELL
+ || you.attribute[ATTR_TRANSFORMATION] == TRAN_ICE_BEAST
+ || you.attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON
+ || you.attribute[ATTR_TRANSFORMATION] == TRAN_SPIDER)
+ {
+ continue;
+ }
+
+ strcpy(attack_name, "kick");
+ sc_dam = ((you.mutation[MUT_HOOVES]
+ || you.species == SP_CENTAUR) ? 10 : 5);
+ break;
+
+ case 1:
+ if (unarmed_attack != UNAT_HEADBUTT)
+ {
+ if ((you.species != SP_MINOTAUR
+ && (!you.mutation[MUT_HORNS]
+ && you.species != SP_KENKU))
+ || !one_chance_in(3))
+ {
+ continue;
+ }
+ }
+
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_SERPENT_OF_HELL
+ || you.attribute[ATTR_TRANSFORMATION] == TRAN_SPIDER
+ || you.attribute[ATTR_TRANSFORMATION] == TRAN_ICE_BEAST
+ || you.attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON)
+ {
+ continue;
+ }
+
+ strcpy(attack_name, (you.species == SP_KENKU) ? "peck"
+ : "headbutt");
+
+ sc_dam = 5 + you.mutation[MUT_HORNS] * 3;
+
+ if (you.species == SP_MINOTAUR)
+ sc_dam += 5;
+
+ if (you.equip[EQ_HELMET] != -1
+ && (cmp_helmet_type( you.inv[you.equip[EQ_HELMET]], THELM_HELMET )
+ || cmp_helmet_type( you.inv[you.equip[EQ_HELMET]], THELM_HELM )))
+ {
+ sc_dam += 2;
+
+ if (cmp_helmet_desc( you.inv[you.equip[EQ_HELMET]], THELM_DESC_SPIKED )
+ || cmp_helmet_desc( you.inv[you.equip[EQ_HELMET]], THELM_DESC_HORNED ))
+ {
+ sc_dam += 3;
+ }
+ }
+ break;
+
+ case 2: /* draconians */
+ if (unarmed_attack != UNAT_TAILSLAP)
+ {
+ // not draconian and not wet merfolk
+ if ((!player_genus(GENPC_DRACONIAN)
+ && (!(you.species == SP_MERFOLK && player_is_swimming()))
+ && !you.mutation[ MUT_STINGER ])
+ || (!one_chance_in(4)))
+
+ {
+ continue;
+ }
+ }
+
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_SPIDER
+ || you.attribute[ATTR_TRANSFORMATION] == TRAN_ICE_BEAST)
+ {
+ continue;
+ }
+
+ strcpy(attack_name, "tail-slap");
+ sc_dam = 6;
+
+ if (you.mutation[ MUT_STINGER ] > 0)
+ {
+ sc_dam += (you.mutation[ MUT_STINGER ] * 2 - 1);
+ brand = SPWPN_VENOM;
+ }
+
+ /* grey dracs have spiny tails, or something */
+ // maybe add this to player messaging {dlb}
+ //
+ // STINGER mutation doesn't give extra damage here... that
+ // would probably be a bit much, we'll still get the
+ // poison bonus so it's still somewhat good.
+ if (you.species == SP_GREY_DRACONIAN && you.experience_level >= 7)
+ {
+ sc_dam = 12;
+ }
+ break;
+
+ case 3:
+ if (unarmed_attack != UNAT_PUNCH)
+ continue;
+
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_SERPENT_OF_HELL
+ || you.attribute[ATTR_TRANSFORMATION] == TRAN_SPIDER
+ || you.attribute[ATTR_TRANSFORMATION] == TRAN_ICE_BEAST
+ || you.attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON)
+ {
+ continue;
+ }
+
+ /* no punching with a shield or 2-handed wpn, except staves */
+ if (bearing_shield || coinflip()
+ || (ur_armed && hands_reqd == HANDS_TWO_HANDED))
+ {
+ continue;
+ }
+
+ strcpy(attack_name, "punch");
+
+ /* applied twice */
+ sc_dam = 5 + you.skills[SK_UNARMED_COMBAT] / 3;
+
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_BLADE_HANDS)
+ {
+ strcpy(attack_name, "slash");
+ sc_dam += 6;
+ }
+ break;
+
+ /* To add more, add to while part of loop below as well */
+ default:
+ continue;
+
+ }
+
+ your_to_hit = 13 + you.dex / 2 + you.skills[SK_UNARMED_COMBAT] / 2
+ + you.skills[SK_FIGHTING] / 5;
+
+ if (wearing_amulet(AMU_INACCURACY))
+ your_to_hit -= 5;
+
+ make_hungry(2, true);
+
+ if (you.hunger_state == HS_STARVING)
+ your_to_hit -= 3;
+
+ your_to_hit += slaying_bonus(PWPN_HIT);
+ your_to_hit = random2(your_to_hit);
+
+ damage = sc_dam; //4 + you.experience_level / 3;
+
+ alert_nearby_monsters();
+
+ if (your_to_hit >= defender->evasion || one_chance_in(30))
+ {
+ bool hit = true;
+ int dammod = 10;
+
+ const int dam_stat_val = calc_stat_to_dam_base();
+
+ if (dam_stat_val > 11)
+ dammod += random2(dam_stat_val - 11) / 3;
+ if (dam_stat_val < 9)
+ dammod -= random2(9 - dam_stat_val) / 2;
+
+ damage *= dammod;
+ damage /= 10;
+
+ damage += slaying_bonus(PWPN_DAMAGE);
+
+ damage_done = (int) random2(damage);
+
+ damage_done *= 40 + (random2(you.skills[SK_FIGHTING] + 1));
+ damage_done /= 40;
+
+ damage_done *= 25 + (random2(you.skills[SK_UNARMED_COMBAT]+1));
+ damage_done /= 25;
+
+ if (you.might > 1)
+ damage_done += 1 + random2(10);
+
+ if (you.hunger_state == HS_STARVING)
+ damage_done -= random2(5);
+
+ damage_done -= random2(1 + defender->armour_class);
+
+ if (damage_done < 1)
+ damage_done = 0;
+ else
+ hurt_monster(defender, damage_done);
+
+ if (damage_done > 0)
+ {
+ if ((!helpless || you.skills[SK_FIGHTING] < 2)
+ && one_chance_in(5))
+ {
+ exercise(SK_FIGHTING, 1);
+ }
+
+ if (!helpless || you.skills[SK_UNARMED_COMBAT] < 2)
+ exercise(SK_UNARMED_COMBAT, 1);
+
+ strcpy(info, "You ");
+ strcat(info, attack_name);
+ strcat(info, " ");
+ strcat(info, ptr_monam(defender, DESC_NOCAP_THE));
+
+#if DEBUG_DIAGNOSTICS
+ strcat(info, " for ");
+ itoa(damage_done, st_prn, 10);
+ strcat(info, st_prn);
+#endif
+
+ if (damage_done < HIT_WEAK)
+ strcat(info, ".");
+ else if (damage_done < HIT_MED)
+ strcat(info, "!");
+ else if (damage_done < HIT_STRONG)
+ strcat(info, "!!");
+ else
+ strcat(info, "!!!");
+
+ mpr(info);
+
+ if (brand == SPWPN_VENOM && coinflip())
+ poison_monster( defender, true );
+
+ if (mons_holiness(defender->type) == MH_HOLY)
+ done_good(GOOD_KILLED_ANGEL_I, 1);
+
+ hit = true;
+ }
+ else // no damage was done
+ {
+ strcpy(info, "You ");
+ strcat(info, attack_name);
+ strcat(info, " ");
+ strcat(info, ptr_monam(defender, DESC_NOCAP_THE));
+
+ if (player_monster_visible( defender ))
+ strcat(info, ", but do no damage.");
+ else
+ strcat(info, ".");
+
+ mpr(info);
+ hit = true;
+ }
+
+
+ if (defender->hit_points < 1)
+ {
+ monster_die(defender, KILL_YOU, 0);
+
+ if (defender->type == MONS_GIANT_SPORE)
+ {
+ strcpy(info, "You ");
+ strcat(info, attack_name);
+ strcat(info, "the giant spore.");
+ mpr(info);
+ }
+ else if (defender->type == MONS_BALL_LIGHTNING)
+ {
+ strcpy(info, "You ");
+ strcat(info, attack_name);
+ strcat(info, "the ball lightning.");
+ mpr(info);
+ }
+ return;
+ }
+ }
+ else
+ {
+ strcpy(info, "Your ");
+ strcat(info, attack_name);
+ strcat(info, " misses ");
+ strcat(info, ptr_monam(defender, DESC_NOCAP_THE));
+ strcat(info, ".");
+ mpr(info);
+ }
+ }
+ }
+
+ if (hit)
+ print_wounds(defender);
+
+ return;
+} // end you_attack()
+
+void monster_attack(int monster_attacking)
+{
+ struct monsters *attacker = &menv[monster_attacking];
+
+ int damage_taken = 0;
+ bool hit = false;
+ bool blocked = false;
+
+ // being attacked by a water creature while standing in water?
+ bool water_attack = false;
+
+ bool bearing_shield = (you.equip[EQ_SHIELD] != -1);
+
+ int mmov_x = 0;
+ int specdam = 0;
+ char heads = 0; // for hydras {dlb}
+ int hand_used = 0;
+ int extraDamage = 0; // from special mon. attacks (burn, freeze, etc)
+ int resistValue = 0; // player resist value (varies)
+ int wpn_speed;
+ char str_pass[ ITEMNAME_SIZE ];
+
+#if DEBUG_DIAGNOSTICS
+ char st_prn[ 20 ];
+#endif
+
+ if (attacker->type == MONS_HYDRA)
+ heads = attacker->number;
+
+ if (mons_friendly(attacker))
+ return;
+
+ // This should happen after the mons_friendly check so we're
+ // only disturbed by hostiles. -- bwr
+ if (you_are_delayed())
+ stop_delay();
+
+ if (attacker->type == MONS_GIANT_SPORE
+ || attacker->type == MONS_BALL_LIGHTNING)
+ {
+ attacker->hit_points = -1;
+ return;
+ }
+
+ // if a friend wants to help, they can attack <monster_attacking>
+ if (you.pet_target == MHITNOT)
+ you.pet_target = monster_attacking;
+
+ if (mons_has_ench( attacker, ENCH_SUBMERGED ))
+ return;
+
+ if (you.duration[DUR_REPEL_UNDEAD]
+ && mons_holiness( attacker->type ) == MH_UNDEAD
+ && !check_mons_resist_magic( attacker, you.piety ))
+ {
+ simple_monster_message(attacker,
+ " tries to attack you, but is repelled by your holy aura.");
+ return;
+ }
+
+ if (wearing_amulet(AMU_WARDING)
+ || (you.religion == GOD_VEHUMET && you.duration[DUR_PRAYER]
+ && (!player_under_penance() && you.piety >= 75)))
+ {
+ if (mons_has_ench(attacker, ENCH_ABJ_I, ENCH_ABJ_VI))
+ {
+ // should be scaled {dlb}
+ if (coinflip())
+ {
+ simple_monster_message(attacker,
+ " tries to attack you, but flinches away.");
+ return;
+ }
+ }
+ }
+
+ if (grd[attacker->x][attacker->y] == DNGN_SHALLOW_WATER
+ && !mons_flies( attacker )
+ && !mons_flag( attacker->type, M_AMPHIBIOUS )
+ && monster_habitat( attacker->type ) == DNGN_FLOOR
+ && one_chance_in(4))
+ {
+ simple_monster_message(attacker, " splashes around in the water.");
+ return;
+ }
+
+ if (player_in_water()
+ && !player_is_swimming()
+ && monster_habitat( attacker->type ) == DNGN_DEEP_WATER)
+ {
+ water_attack = true;
+ simple_monster_message(attacker,
+ " uses the watery terrain to its advantage.");
+ }
+
+ char runthru;
+
+ for (runthru = 0; runthru < 4; runthru++)
+ {
+ blocked = false;
+ wpn_speed = 0; // 0 = didn't attack w/ weapon
+
+ if (attacker->type == MONS_HYDRA)
+ {
+ if (heads < 1)
+ break;
+ runthru = 0;
+ heads--;
+ }
+
+ char mdam = mons_damage( attacker->type, runthru );
+
+ if (attacker->type == MONS_ZOMBIE_SMALL
+ || attacker->type == MONS_ZOMBIE_LARGE
+ || attacker->type == MONS_SKELETON_SMALL
+ || attacker->type == MONS_SKELETON_LARGE
+ || attacker->type == MONS_SIMULACRUM_SMALL
+ || attacker->type == MONS_SIMULACRUM_LARGE
+ || attacker->type == MONS_SPECTRAL_THING)
+ {
+ mdam = mons_damage(attacker->number, runthru);
+
+ // these are cumulative, of course: {dlb}
+ if (mdam > 1)
+ mdam--;
+ if (mdam > 4)
+ mdam--;
+ if (mdam > 11)
+ mdam--;
+ if (mdam > 14)
+ mdam--;
+ }
+
+ if (mdam == 0)
+ break;
+
+ if ((attacker->type == MONS_TWO_HEADED_OGRE
+ || attacker->type == MONS_ETTIN)
+ && runthru == 1)
+ {
+ hand_used = 1;
+ }
+
+ damage_taken = 0;
+
+ int mons_to_hit = 16 + attacker->hit_dice; //* attacker->hit_dice;//* 3
+
+ if (water_attack)
+ mons_to_hit += 5;
+
+ if (attacker->inv[hand_used] != NON_ITEM
+ && mitm[attacker->inv[hand_used]].base_type == OBJ_WEAPONS)
+ {
+ mons_to_hit += mitm[attacker->inv[hand_used]].plus;
+
+ mons_to_hit += property( mitm[attacker->inv[hand_used]], PWPN_HIT );
+
+ wpn_speed = property( mitm[attacker->inv[hand_used]], PWPN_SPEED );
+ }
+
+ // Factors against blocking
+ const int con_block = 15 + attacker->hit_dice
+ + (10 * you.shield_blocks * you.shield_blocks);
+
+ // Factors for blocking
+ const int pro_block = player_shield_class() + (random2(you.dex) / 5);
+
+ if (!you.paralysis && !you_are_delayed() && !you.conf
+ && player_monster_visible( attacker )
+ && player_shield_class() > 0
+ && random2(con_block) <= random2(pro_block))
+ {
+ you.shield_blocks++;
+
+ snprintf( info, INFO_SIZE, "You block %s's attack.",
+ ptr_monam( attacker, DESC_NOCAP_THE ) );
+
+ mpr(info);
+
+ blocked = true;
+ hit = false;
+
+ if (bearing_shield && one_chance_in(4))
+ exercise(SK_SHIELDS, 1);
+ }
+ else if (player_light_armour() && one_chance_in(3))
+ {
+ exercise(SK_DODGING, 1);
+ }
+
+ const int player_dodge = random2limit(player_evasion(), 40)
+ + random2(you.dex) / 3
+ - (player_monster_visible(attacker) ? 2 : 14)
+ - (you_are_delayed() ? 5 : 0);
+
+ if (!blocked
+ && (random2(mons_to_hit) >= player_dodge || one_chance_in(30)))
+ {
+ hit = true;
+
+ int damage_size = 0;
+
+ if (attacker->inv[hand_used] != NON_ITEM
+ && mitm[attacker->inv[hand_used]].base_type == OBJ_WEAPONS
+ && (mitm[attacker->inv[hand_used]].sub_type < WPN_SLING
+ || mitm[attacker->inv[hand_used]].sub_type > WPN_CROSSBOW))
+ {
+ damage_size = property( mitm[attacker->inv[hand_used]],
+ PWPN_DAMAGE );
+
+ damage_taken = random2(damage_size);
+
+ if (cmp_equip_race(mitm[attacker->inv[hand_used]],ISFLAG_ORCISH)
+ && mons_charclass(attacker->type) == MONS_ORC
+ && coinflip())
+ {
+ damage_taken++;
+ }
+
+ if (mitm[attacker->inv[hand_used]].plus2 >= 0)
+ {
+ /* + or 0 to-dam */
+ damage_taken += random2(mitm[attacker->inv[hand_used]].plus2 + 1);
+ }
+ else
+ {
+ /* - to-dam */
+ damage_taken -= (random2(1 + abs(mitm[attacker->inv[hand_used]].plus2)));
+ }
+
+ damage_taken -= 1 + random2(3); //1;
+ }
+
+ damage_size += mdam;
+ damage_taken += 1 + random2(mdam);
+
+ if (water_attack)
+ damage_taken *= 2;
+
+ int ac = player_AC();
+
+ if (ac > 0)
+ {
+ int damage_reduction = random2(ac + 1);
+
+ if (!player_light_armour())
+ {
+ const int body_arm_ac = property( you.inv[you.equip[EQ_BODY_ARMOUR]],
+ PARM_AC );
+
+ int percent = 2 * (you.skills[SK_ARMOUR] + body_arm_ac);
+
+ if (percent > 50)
+ percent = 50;
+
+ int min = 1 + (damage_size * percent) / 100;
+
+ if (min > ac / 2)
+ min = ac / 2;
+
+ if (damage_reduction < min)
+ damage_reduction = min;
+ }
+
+ damage_taken -= damage_reduction;
+ }
+
+ if (damage_taken < 1)
+ damage_taken = 0;
+
+ }
+ else if (!blocked)
+ {
+ hit = false;
+ simple_monster_message(attacker, " misses you.");
+ }
+
+ if (damage_taken < 1 && hit && !blocked)
+ {
+ simple_monster_message(attacker,
+ " hits you but doesn't do any damage.");
+ }
+
+ if (damage_taken > 0)
+ {
+ hit = true;
+
+ mmov_x = attacker->inv[hand_used];
+
+ strcpy(info, ptr_monam(attacker, DESC_CAP_THE));
+ strcat(info, " hits you");
+
+#if DEBUG_DIAGNOSTICS
+ strcat(info, " for ");
+ // note: doesn't take account of special weapons etc
+ itoa( damage_taken, st_prn, 10 );
+ strcat( info, st_prn );
+#endif
+
+ if (attacker->type != MONS_DANCING_WEAPON && mmov_x != NON_ITEM
+ && mitm[mmov_x].base_type == OBJ_WEAPONS
+ && !launches_things( mitm[mmov_x].sub_type ))
+ {
+ strcat(info, " with ");
+ it_name(mmov_x, DESC_NOCAP_A, str_pass); // was 7
+ strcat(info, str_pass);
+ }
+
+ strcat(info, "!");
+
+ mpr( info, MSGCH_PLAIN );
+
+ if (hit)
+ {
+ if (you.equip[EQ_BODY_ARMOUR] != -1)
+ {
+ const int body_arm_mass = mass_item( you.inv[you.equip[EQ_BODY_ARMOUR]] );
+
+ if (!player_light_armour() && coinflip()
+ && random2(1000) <= body_arm_mass)
+ {
+ // raised from 1 {bwross}
+ exercise(SK_ARMOUR, (coinflip() ? 2 : 1));
+ }
+ }
+ }
+
+ /* special attacks: */
+ int mclas = attacker->type;
+
+ if (mclas == MONS_KILLER_KLOWN)
+ {
+ switch (random2(6))
+ {
+ case 0:
+ // comment and enum do not match {dlb}
+ mclas = MONS_SNAKE; // scorp
+ break;
+ case 1:
+ mclas = MONS_NECROPHAGE;
+ break;
+ case 2:
+ mclas = MONS_WRAITH;
+ break;
+ case 3:
+ mclas = MONS_FIRE_ELEMENTAL;
+ break;
+ case 4:
+ mclas = MONS_ICE_BEAST;
+ break;
+ case 5:
+ mclas = MONS_PHANTOM;
+ break;
+ }
+ }
+
+ switch (mclas)
+ {
+ case MONS_GILA_MONSTER:
+ case MONS_GIANT_ANT:
+ case MONS_WOLF_SPIDER:
+ case MONS_REDBACK:
+ if (player_res_poison())
+ break;
+
+ if (one_chance_in(20)
+ || (damage_taken > 3 && one_chance_in(4)))
+ {
+ simple_monster_message( attacker,
+ "'s bite was poisonous!" );
+
+ if (attacker->type == MONS_REDBACK)
+ poison_player( random2avg(9, 2) + 3 );
+ else
+ poison_player(1);
+ }
+ break;
+
+ case MONS_KILLER_BEE:
+ case MONS_BUMBLEBEE:
+ if (!player_res_poison()
+ && (one_chance_in(20)
+ || (damage_taken > 2 && one_chance_in(3))))
+
+ {
+ simple_monster_message( attacker, " stings you!" );
+
+ if (attacker->type == MONS_BUMBLEBEE)
+ poison_player( random2(3) );
+ else
+ poison_player(1);
+ }
+ break;
+
+ case MONS_ROTTING_DEVIL:
+ case MONS_NECROPHAGE:
+ case MONS_GHOUL:
+ case MONS_DEATH_OOZE:
+ if (you.is_undead)
+ break;
+
+ // both sides call random2() - looking familiar by now {dlb}
+ if (one_chance_in(20) || (damage_taken > 2 && one_chance_in(3)))
+ {
+ rot_player( 2 + random2(3) );
+
+ if (damage_taken > 5)
+ rot_hp(1);
+ }
+
+ if (one_chance_in(4))
+ disease_player( 50 + random2(100) );
+ break;
+
+ case MONS_KOMODO_DRAGON:
+ case MONS_GIANT_MOSQUITO:
+ if (!one_chance_in(3))
+ disease_player( 50 + random2(100) );
+ break;
+
+ case MONS_FIRE_VORTEX:
+ attacker->hit_points = -10;
+ // fall through -- intentional? {dlb}
+ case MONS_FIRE_ELEMENTAL:
+ case MONS_BALRUG:
+ case MONS_SUN_DEMON:
+ strcpy(info, "You are engulfed in flames");
+
+ resistValue = player_res_fire();
+ extraDamage = 15 + random2(15);
+ if (resistValue > 0)
+ {
+ extraDamage /= (1 + resistValue * resistValue);
+ }
+ else
+ {
+ if (resistValue < 0)
+ extraDamage += 8 + random2(8);
+ }
+
+ strcat(info, (extraDamage < 10) ? "." :
+ (extraDamage < 25) ? "!" :
+ "!!");
+
+ mpr(info);
+
+ if (you.duration[DUR_CONDENSATION_SHIELD] > 0)
+ {
+ mpr("Your icy shield dissipates!", MSGCH_DURATION);
+ you.duration[DUR_CONDENSATION_SHIELD] = 0;
+ you.redraw_armour_class = 1;
+ }
+
+ damage_taken += extraDamage;
+ scrolls_burn(1, OBJ_SCROLLS);
+ break;
+
+ case MONS_SMALL_SNAKE:
+ case MONS_SNAKE:
+ case MONS_GIANT_MITE:
+ case MONS_GOLD_MIMIC:
+ case MONS_WEAPON_MIMIC:
+ case MONS_ARMOUR_MIMIC:
+ case MONS_SCROLL_MIMIC:
+ case MONS_POTION_MIMIC:
+ if (!player_res_poison()
+ && (one_chance_in(20)
+ || (damage_taken > 2 && one_chance_in(4))))
+ {
+ poison_player(1);
+ }
+ break;
+
+ case MONS_QUEEN_BEE:
+ case MONS_GIANT_CENTIPEDE:
+ case MONS_SOLDIER_ANT:
+ case MONS_QUEEN_ANT:
+ if (!player_res_poison())
+ {
+ strcpy(info, ptr_monam(attacker, DESC_CAP_THE));
+ strcat(info, " stings you!");
+ mpr(info);
+
+ poison_player(2);
+ }
+ break;
+
+ case MONS_SCORPION:
+ case MONS_BROWN_SNAKE:
+ case MONS_BLACK_SNAKE:
+ case MONS_YELLOW_SNAKE:
+ case MONS_SPINY_FROG:
+ if (!player_res_poison()
+ && (one_chance_in(15)
+ || (damage_taken > 2 && one_chance_in(4))))
+ // ^^^yep, this should be a function^^^ {dlb}
+ {
+ strcpy(info, ptr_monam(attacker, DESC_CAP_THE));
+ strcat(info, " poisons you!");
+ mpr(info);
+
+ poison_player(1);
+ }
+ break;
+
+ case MONS_SHADOW_DRAGON:
+ case MONS_SPECTRAL_THING:
+ if (coinflip())
+ break;
+ // fall-through {dlb}
+ case MONS_WIGHT: // less likely because wights do less damage
+ case MONS_WRAITH:
+
+ // enum does not match comment 14jan2000 {dlb}
+ case MONS_SOUL_EATER: // shadow devil
+
+ // enum does not match comment 14jan2000 {dlb}
+ case MONS_SPECTRAL_WARRIOR: // spectre
+
+ case MONS_SHADOW_FIEND:
+ case MONS_ORANGE_RAT:
+ case MONS_SHADOW_WRAITH:
+ case MONS_ANCIENT_LICH:
+ case MONS_LICH:
+ case MONS_BORIS:
+ if (one_chance_in(30) || (damage_taken > 5 && coinflip()))
+ drain_exp();
+ break;
+
+
+ case MONS_RED_WASP:
+ if (!player_res_poison())
+ poison_player( (coinflip() ? 2 : 1) );
+ // intentional fall-through {dlb}
+ case MONS_YELLOW_WASP:
+ strcpy(info, ptr_monam(attacker, DESC_CAP_THE));
+ strcat(info, " stings you.");
+ mpr(info);
+
+ if (!player_res_poison()
+ && (one_chance_in(20)
+ || (damage_taken > 2 && !one_chance_in(3))))
+ // maybe I should flip back the other way? {dlb}
+ {
+ if (you.paralysis > 0)
+ mpr("You still can't move!", MSGCH_WARN);
+ else
+ mpr("You suddenly lose the ability to move!", MSGCH_WARN);
+
+ you.paralysis += 1 + random2(3);
+ }
+ break;
+
+ case MONS_SPINY_WORM:
+ if (!player_res_poison())
+ {
+ strcpy(info, ptr_monam(attacker, DESC_CAP_THE));
+ strcat(info, " stings you!");
+ mpr(info);
+
+ poison_player( 2 + random2(4) );
+ }
+ // intentional fall-through {dlb}
+ case MONS_BROWN_OOZE:
+ case MONS_ACID_BLOB:
+ case MONS_ROYAL_JELLY:
+ case MONS_JELLY:
+ mpr("You are splashed with acid!");
+ splash_with_acid(3);
+ break;
+
+ case MONS_SIMULACRUM_SMALL:
+ case MONS_SIMULACRUM_LARGE:
+ strcpy(info, ptr_monam(attacker, DESC_CAP_THE));
+
+ resistValue = player_res_cold();
+ if (resistValue > 0)
+ extraDamage = 0;
+ else if (resistValue == 0)
+ {
+ extraDamage += roll_dice( 1, 4 );
+ strcat(info, " chills you.");
+ }
+ else if (resistValue < 0)
+ {
+ extraDamage = roll_dice( 2, 4 );
+ strcat(info, " freezes you.");
+ }
+
+ mpr(info);
+ damage_taken += extraDamage;
+ scrolls_burn( 1, OBJ_POTIONS );
+ break;
+
+ case MONS_ICE_DEVIL:
+ case MONS_ICE_BEAST:
+ case MONS_FREEZING_WRAITH:
+ case MONS_ICE_FIEND:
+ case MONS_WHITE_IMP:
+ case MONS_ANTAEUS:
+ case MONS_AZURE_JELLY:
+ extraDamage = attacker->hit_dice + random2(attacker->hit_dice * 2);
+ resistValue = player_res_cold();
+
+ if (resistValue > 0)
+ {
+ extraDamage /= (1 + resistValue * resistValue);
+ }
+
+ if (resistValue < 0)
+ {
+ extraDamage += attacker->hit_dice +
+ random2(attacker->hit_dice * 2);
+ }
+
+ if (extraDamage > 4)
+ {
+ strcpy(info, ptr_monam(attacker, DESC_CAP_THE));
+ if (extraDamage < 10)
+ strcat(info, " chills you.");
+ else
+ strcat(info, " freezes you!");
+ if (extraDamage > 19)
+ strcat(info, "!");
+ mpr(info);
+ }
+
+ damage_taken += extraDamage;
+
+ scrolls_burn(1, OBJ_POTIONS);
+ break;
+
+ case MONS_ELECTRIC_GOLEM:
+ if (!player_res_electricity())
+ {
+ damage_taken += attacker->hit_dice
+ + random2(attacker->hit_dice * 2);
+
+ strcpy(info, ptr_monam(attacker, DESC_CAP_THE));
+ strcat(info, " shocks you!");
+ mpr(info);
+ }
+ break;
+
+ case MONS_VAMPIRE:
+ if (you.is_undead)
+ break;
+
+/* ******************************************************************
+ if ( damage_taken > 6 && one_chance_in(3) || !one_chance_in(20))
+ {
+ mpr("You feel less resilient.");
+ you.hp_max -= ( coinflip() ? 2 : 1 );
+ deflate_hp(you.hp_max, false);
+ heal_monster(attacker, 5 + random2(8), true);
+ }
+****************************************************************** */
+
+ // heh heh {dlb}
+ // oh, this is mean! {gdl}
+ if (heal_monster(attacker, random2(damage_taken), true))
+ simple_monster_message(attacker, " draws strength from your injuries!");
+
+ break;
+
+ case MONS_SHADOW:
+ if (player_prot_life() <= random2(3)
+ && (one_chance_in(20)
+ || (damage_taken > 0 && one_chance_in(3))))
+ {
+ lose_stat(STAT_STRENGTH, 1);
+ }
+ break;
+
+ case MONS_HUNGRY_GHOST:
+ if (you.is_undead == US_UNDEAD)
+ break;
+
+ if (one_chance_in(20) || (damage_taken > 0 && coinflip()))
+ make_hungry(400, false);
+ break;
+
+ case MONS_GUARDIAN_NAGA:
+ break;
+
+ case MONS_PHANTOM:
+ case MONS_INSUBSTANTIAL_WISP:
+ case MONS_BLINK_FROG:
+ case MONS_MIDGE:
+ if (one_chance_in(3))
+ {
+ simple_monster_message(attacker, " blinks.");
+ monster_blink(attacker);
+ }
+ break;
+
+ case MONS_JELLYFISH:
+ case MONS_ORANGE_DEMON:
+ // if ( !one_chance_in(3) ) break;
+ if (player_res_poison())
+ break;
+
+ if (attacker->type == MONS_ORANGE_DEMON
+ && (!one_chance_in(4) || runthru != 1))
+ {
+ break;
+ }
+
+ strcpy(info, ptr_monam(attacker, DESC_CAP_THE));
+ strcat(info, " stings you!");
+ mpr(info);
+
+ poison_player(1);
+ lose_stat(STAT_STRENGTH, 1);
+ break;
+
+ case MONS_PULSATING_LUMP:
+ if (one_chance_in(3))
+ {
+ if (one_chance_in(5))
+ mutate(100);
+ else
+ give_bad_mutation();
+ }
+ break;
+ } // end of switch for special attacks.
+ /* use brek for level drain, maybe with beam variables,
+ because so many creatures use it. */
+ }
+
+ /* special weapons */
+ if (hit
+ && (attacker->inv[hand_used] != NON_ITEM
+ || ((attacker->type == MONS_PLAYER_GHOST
+ || attacker->type == MONS_PANDEMONIUM_DEMON)
+ && ghost.values[ GVAL_BRAND ] != SPWPN_NORMAL)))
+ {
+ unsigned char itdam;
+
+ if (attacker->type == MONS_PLAYER_GHOST
+ || attacker->type == MONS_PANDEMONIUM_DEMON)
+ {
+ itdam = ghost.values[ GVAL_BRAND ];
+ }
+ else
+ itdam = mitm[attacker->inv[hand_used]].special;
+
+ specdam = 0;
+
+ switch (itdam)
+ {
+ case SPWPN_NORMAL:
+ default:
+ break;
+
+ case SPWPN_SWORD_OF_CEREBOV:
+ case SPWPN_FLAMING:
+ specdam = 0;
+ resistValue = player_res_fire();
+
+ if (itdam == SPWPN_SWORD_OF_CEREBOV)
+ resistValue -= 1;
+
+ if (resistValue > 0)
+ {
+ damage_taken += (random2(damage_taken) / 2 + 1) /
+ (1 + (resistValue * resistValue));
+ }
+
+ if (resistValue <= 0)
+ specdam = random2(damage_taken) / 2 + 1;
+
+ if (resistValue < 0)
+ specdam += random2(damage_taken) / 2 + 1;
+
+ if (specdam)
+ {
+ simple_monster_message(attacker, " burns you.");
+/* **********************
+
+commented out for now
+ if (specdam < 3)
+ strcat(info, ".");
+ if (specdam >= 3 && specdam < 7)
+ strcat(info, "!");
+ if (specdam >= 7)
+ strcat(info, "!!");
+
+*********************** */
+ }
+
+ if (you.duration[DUR_CONDENSATION_SHIELD] > 0)
+ {
+ mpr("Your icy shield dissipates!", MSGCH_DURATION);
+ you.duration[DUR_CONDENSATION_SHIELD] = 0;
+ you.redraw_armour_class = 1;
+ }
+ break;
+
+ case SPWPN_FREEZING:
+ specdam = 0;
+ resistValue = player_res_cold();
+
+ if (resistValue <= 0)
+ specdam = random2(damage_taken) / 2 + 1;
+
+ if (resistValue < 0)
+ specdam += random2(damage_taken) / 2 + 1;
+
+ if (resistValue > 0)
+ {
+ damage_taken += (random2(damage_taken) / 2 + 1) /
+ (1 + (resistValue * resistValue));
+ }
+
+ if (specdam)
+ {
+ simple_monster_message(attacker, " freezes you.");
+
+/* **********************
+
+commented out for now
+ if (specdam < 3)
+ strcat(info, ".");
+ if (specdam >= 3 && specdam < 7)
+ strcat(info, "!");
+ if (specdam >= 7)
+ strcat(info, "!!");
+
+*********************** */
+ }
+ break;
+
+
+ case SPWPN_HOLY_WRATH:
+ if (attacker->type == MONS_PLAYER_GHOST)
+ break; // ghosts can't wield holy wrath
+
+ if (you.is_undead)
+ {
+ specdam = random2(damage_taken);
+
+ if (specdam)
+ {
+ strcpy(info, "The wound is extremely painful");
+
+ if (specdam < 3)
+ strcat(info, ".");
+ else if (specdam < 7)
+ strcat(info, "!");
+ else
+ strcat(info, "!!");
+
+ mpr(info);
+ }
+ }
+ break;
+
+ case SPWPN_ELECTROCUTION:
+ // This runs the risk of making levitation into a
+ // cheap version of the Resist spell (with added
+ // bonuses), so it shouldn't be used anywhere else,
+ // and should possibly be removed from this case as
+ // well. -- bwr
+ if (player_is_levitating()) // you're not grounded
+ break;
+
+ if (player_res_electricity()) // resist lightning
+ break;
+
+ specdam = 0;
+
+ // This is related to old code where elec wpns had charges
+#if 0
+ if (menv[monster_attacking].type != MONS_PLAYER_GHOST
+ && (mitm[attacker->inv[hand_used]].plus2 <= 0
+ || item_cursed( mitm[attacker->inv[hand_used]] )))
+ {
+ break;
+ }
+#endif
+
+ if (one_chance_in(3))
+ {
+ mpr("You are electrocuted!");
+ specdam += 10 + random2(15);
+ }
+ break;
+
+ case SPWPN_ORC_SLAYING:
+ if (you.species == SP_HILL_ORC)
+ {
+ specdam = random2(damage_taken);
+
+ if (specdam)
+ {
+ strcpy(info, "The wound is extremely painful");
+
+ if (specdam < 3)
+ strcat(info, ".");
+ else if (specdam < 7)
+ strcat(info, "!");
+ else
+ strcat(info, "!!");
+
+ mpr(info);
+ }
+ }
+ break;
+
+ case SPWPN_STAFF_OF_OLGREB:
+ case SPWPN_VENOM:
+ if (!player_res_poison() && one_chance_in(3))
+ {
+ simple_monster_message(attacker,
+ (attacker->type == MONS_DANCING_WEAPON)
+ ? " is poisoned!" : "'s weapon is poisoned!");
+
+ poison_player(2);
+ }
+ break;
+
+ case SPWPN_PROTECTION:
+ break;
+
+ case SPWPN_DRAINING:
+ drain_exp();
+ specdam = random2(damage_taken) / (2 + player_prot_life()) + 1;
+ break;
+
+ case SPWPN_SPEED:
+ wpn_speed = (wpn_speed + 1) / 2;
+ break;
+
+ case SPWPN_VORPAL:
+ specdam = 1 + (random2(damage_taken) / 2);
+ break;
+
+ case SPWPN_VAMPIRES_TOOTH:
+ case SPWPN_VAMPIRICISM:
+ specdam = 0; // note does no extra damage
+
+ if (you.is_undead)
+ break;
+
+ if (one_chance_in(5))
+ break;
+
+ // heh heh {dlb}
+ if (heal_monster(attacker, 1 + random2(damage_taken), true))
+ simple_monster_message(attacker, " draws strength from your injuries!");
+ break;
+
+ case SPWPN_DISRUPTION:
+ if (attacker->type == MONS_PLAYER_GHOST)
+ break;
+
+ if (you.is_undead)
+ {
+ specdam = random2(damage_taken) + random2(damage_taken)
+ + random2(damage_taken) + random2(damage_taken);
+
+ if (specdam)
+ {
+ strcpy(info, "You are blasted by holy energy");
+
+ if (specdam < 7)
+ strcat(info, ".");
+ else if (specdam < 15)
+ strcat(info, "!");
+ else
+ strcat(info, "!!");
+
+ mpr(info);
+ }
+ }
+ break;
+
+
+ case SPWPN_DISTORTION:
+ //if ( !one_chance_in(3) ) break;
+
+ if (one_chance_in(3))
+ {
+ mpr("Your body is twisted painfully.");
+ specdam += 1 + random2avg(7, 2);
+ break;
+ }
+
+ if (one_chance_in(3))
+ {
+ mpr("Your body is terribly warped!");
+ specdam += 3 + random2avg(24, 2);
+ break;
+ }
+
+ if (one_chance_in(3))
+ {
+ random_blink(true);
+ break;
+ }
+
+ if (coinflip())
+ {
+ you_teleport();
+ break;
+ }
+
+ if (coinflip())
+ {
+ you_teleport2( true, one_chance_in(5) );
+ break;
+ }
+
+ if (coinflip())
+ {
+ banished(DNGN_ENTER_ABYSS);
+ break;
+ }
+ break;
+ } // end of switch
+ } // end of special weapons
+
+ damage_taken += specdam;
+
+ if (damage_taken > 0)
+ {
+ ouch(damage_taken, monster_attacking, KILLED_BY_MONSTER);
+
+ if (you.religion == GOD_XOM && you.hp <= you.hp_max / 3
+ && one_chance_in(10))
+ {
+ Xom_acts(true, you.experience_level, false);
+ }
+ }
+
+ // adjust time taken if monster used weapon
+ if (wpn_speed > 0)
+ {
+ // only get one third penalty/bonus for second weapons.
+ if (runthru > 0)
+ wpn_speed = (20 + wpn_speed) / 3;
+
+ attacker->speed_increment -= (wpn_speed - 10) / 2;
+ }
+ } // end of for runthru
+
+ return;
+} // end monster_attack()
+
+bool monsters_fight(int monster_attacking, int monster_attacked)
+{
+ struct monsters *attacker = &menv[monster_attacking];
+ struct monsters *defender = &menv[monster_attacked];
+
+ int weapon = -1; // monster weapon, if any
+ int damage_taken = 0;
+ bool hit = false;
+ int mmov_x = 0;
+ bool water_attack = false;
+ int specdam = 0;
+ int hand_used = 0;
+ bool sees = false;
+ int wpn_speed; // 0 == didn't use actual weapon
+ int habitat = monster_habitat( attacker->type );
+ char str_pass[ ITEMNAME_SIZE ];
+
+#if DEBUG_DIAGNOSTICS
+ char st_prn[ 20 ];
+#endif
+
+ if (attacker->type == MONS_GIANT_SPORE
+ || attacker->type == MONS_BALL_LIGHTNING)
+ {
+ attacker->hit_points = -1;
+ return false;
+ }
+
+ if (mons_has_ench( attacker, ENCH_SUBMERGED )
+ && habitat != DNGN_FLOOR
+ && habitat != monster_habitat( defender->type ))
+ {
+ return false;
+ }
+
+ if (grd[attacker->x][attacker->y] == DNGN_SHALLOW_WATER
+ && !mons_flies( attacker )
+ && !mons_flag( attacker->type, M_AMPHIBIOUS )
+ && habitat == DNGN_FLOOR
+ && one_chance_in(4))
+ {
+ mpr("You hear a splashing noise.");
+ return true;
+ }
+
+ if (grd[defender->x][defender->y] == DNGN_SHALLOW_WATER
+ && !mons_flies(defender)
+ && habitat == DNGN_DEEP_WATER)
+ {
+ water_attack = true;
+ }
+
+ if (mons_near(attacker) && mons_near(defender))
+ sees = true;
+
+ // now disturb defender, regardless
+ behaviour_event(defender, ME_WHACK, monster_attacking);
+
+ char runthru;
+
+ for (runthru = 0; runthru < 4; runthru++)
+ {
+ char mdam = mons_damage(attacker->type, runthru);
+ wpn_speed = 0;
+
+ if (attacker->type == MONS_ZOMBIE_SMALL
+ || attacker->type == MONS_ZOMBIE_LARGE
+ || attacker->type == MONS_SKELETON_SMALL
+ || attacker->type == MONS_SKELETON_LARGE
+ || attacker->type == MONS_SIMULACRUM_SMALL
+ || attacker->type == MONS_SIMULACRUM_LARGE
+ || attacker->type == MONS_SPECTRAL_THING)
+ // what do these things have in common? {dlb}
+ {
+ mdam = mons_damage(attacker->number, runthru);
+ // cumulative reductions - series of if-conditions
+ // is necessary: {dlb}
+ if (mdam > 1)
+ mdam--;
+ if (mdam > 2)
+ mdam--;
+ if (mdam > 5)
+ mdam--;
+ if (mdam > 9)
+ mdam--; // was: "-= 2" {dlb}
+ }
+
+ if (mdam == 0)
+ break;
+
+ if ((attacker->type == MONS_TWO_HEADED_OGRE
+ || attacker->type == MONS_ETTIN)
+ && runthru == 1 && attacker->inv[MSLOT_MISSILE] != NON_ITEM)
+ {
+ hand_used = 1;
+ }
+
+ damage_taken = 0;
+
+ int mons_to_hit = 20 + attacker->hit_dice * 5;
+ // * menv [monster_attacking].hit_dice; // * 3
+
+ if (water_attack)
+ mons_to_hit += 5;
+
+ weapon = attacker->inv[hand_used];
+
+ if (weapon != NON_ITEM)
+ {
+ mons_to_hit += mitm[weapon].plus;
+ // mons_to_hit += 3 * property( mitm[weapon], PWPN_HIT );
+ mons_to_hit += property( mitm[weapon], PWPN_HIT );
+
+ wpn_speed = property( mitm[ weapon ], PWPN_SPEED );
+ }
+
+ mons_to_hit = random2(mons_to_hit);
+
+ if (mons_to_hit >= defender->evasion
+ || ((defender->speed_increment <= 60
+ || defender->behaviour == BEH_SLEEP) && !one_chance_in(20)))
+ {
+ hit = true;
+
+ if (attacker->inv[hand_used] != NON_ITEM
+ && mitm[attacker->inv[hand_used]].base_type == OBJ_WEAPONS
+ && !launches_things( mitm[attacker->inv[hand_used]].sub_type ))
+ {
+ damage_taken = random2(property( mitm[attacker->inv[hand_used]],
+ PWPN_DAMAGE ));
+
+ if (cmp_equip_race(mitm[attacker->inv[hand_used]],ISFLAG_ORCISH)
+ && mons_charclass(attacker->type) == MONS_ORC
+ && coinflip())
+ {
+ damage_taken++;
+ }
+
+ //if (mitm[mons_inv[i][0]].plus > 80) damage_taken -= 100;
+ // damage_taken += mitm[mons_inv[i][0]].plus;
+
+ if (mitm[attacker->inv[hand_used]].plus2 >= 0)
+ {
+ /* + or 0 to-dam */
+ damage_taken += random2(mitm[attacker->inv[hand_used]].plus2 + 1);
+ }
+ else
+ {
+ /* - to-dam */
+ damage_taken -= random2(abs(mitm[attacker->inv[hand_used]].plus2 + 1));
+ }
+
+ damage_taken -= 1 + random2(3); //1;
+ }
+
+ damage_taken += 1 + random2(mdam);
+
+ if (water_attack)
+ damage_taken *= 2;
+
+ damage_taken -= random2(1 + defender->armour_class);
+
+ if (damage_taken < 1)
+ damage_taken = 0;
+ }
+ else
+ {
+ hit = false;
+
+ if (sees)
+ {
+ strcpy(info, ptr_monam(attacker, DESC_CAP_THE));
+ strcat(info, " misses ");
+ strcat(info, ptr_monam(defender, DESC_NOCAP_THE));
+ strcat(info, ".");
+ mpr(info);
+ }
+ }
+
+ if (damage_taken < 1 && hit)
+ {
+ if (sees)
+ {
+ strcpy(info, ptr_monam(attacker, DESC_CAP_THE));
+ strcat(info, " hits ");
+ strcat(info, ptr_monam(defender, DESC_NOCAP_THE));
+
+#if DEBUG_DIAGNOSTICS
+ strcat(info, " for ");
+ // note: doesn't take account of special weapons etc
+ itoa(damage_taken, st_prn, 10);
+ strcat(info, st_prn);
+#endif
+ strcat(info, "."); // but doesn't do any you.damage.");
+ mpr(info);
+ }
+ }
+
+ if (hit) //(int) damage_taken > 0)
+ {
+ int mmov_x = attacker->inv[hand_used];
+
+ if (sees)
+ {
+ strcpy(info, ptr_monam(attacker, DESC_CAP_THE));
+ strcat(info, " hits ");
+ strcat(info, ptr_monam(defender, DESC_NOCAP_THE));
+
+ if (attacker->type != MONS_DANCING_WEAPON
+ && attacker->inv[hand_used] != NON_ITEM
+ && mitm[attacker->inv[hand_used]].base_type == OBJ_WEAPONS
+ && !launches_things( mitm[attacker->inv[hand_used]].sub_type ))
+ {
+ strcat(info, " with ");
+ it_name(mmov_x, DESC_NOCAP_A, str_pass); // was 7
+ strcat(info, str_pass);
+ }
+
+ strcat(info, "! ");
+ mpr(info);
+ }
+
+ // special attacks:
+ switch (attacker->type)
+ {
+ // enum does not match comment 14jan2000 {dlb}
+ case MONS_CENTAUR: // cockatrice
+ case MONS_JELLY:
+ case MONS_GUARDIAN_NAGA:
+ break;
+
+ case MONS_GIANT_ANT:
+ case MONS_WOLF_SPIDER:
+ case MONS_REDBACK:
+ case MONS_SPINY_WORM:
+ case MONS_JELLYFISH:
+ case MONS_ORANGE_DEMON:
+ if (attacker->type == MONS_SPINY_WORM || one_chance_in(20)
+ || (damage_taken > 3 && one_chance_in(4)))
+ {
+ if (sees)
+ {
+ strcpy(info, ptr_monam(attacker, DESC_CAP_THE));
+ strcat(info, " stings ");
+ strcat(info, ptr_monam(defender, DESC_NOCAP_THE));
+ strcat(info, ".");
+ mpr(info);
+ }
+ poison_monster(defender, false);
+ }
+ break;
+
+ case MONS_KILLER_BEE:
+ case MONS_BUMBLEBEE:
+ if (one_chance_in(20)
+ || (damage_taken > 2 && one_chance_in(3)))
+ {
+ if (sees)
+ {
+ strcpy(info, ptr_monam(attacker, DESC_CAP_THE));
+ strcat(info, " stings ");
+ strcpy(info, ptr_monam(defender, DESC_NOCAP_THE));
+ strcat(info, ".");
+ mpr(info);
+ }
+ poison_monster(defender, false);
+ }
+ break;
+
+ case MONS_NECROPHAGE:
+ case MONS_ROTTING_DEVIL:
+ case MONS_GHOUL:
+ case MONS_DEATH_OOZE:
+ if (mons_res_negative_energy( defender ))
+ break;
+
+ if (one_chance_in(20)
+ || (damage_taken > 2 && one_chance_in(3)))
+ {
+ defender->max_hit_points -= 1 + random2(3);
+
+ if (defender->hit_points > defender->max_hit_points)
+ defender->hit_points = defender->max_hit_points;
+ }
+ break;
+
+ case MONS_FIRE_VORTEX:
+ attacker->hit_points = -10;
+ // deliberate fall-through
+ case MONS_FIRE_ELEMENTAL:
+ case MONS_BALRUG:
+ case MONS_SUN_DEMON:
+ specdam = 0;
+ if (mons_res_fire(defender) == 0)
+ specdam = 15 + random2(15);
+ else if (mons_res_fire(defender) < 0)
+ specdam = 20 + random2(25);
+
+ if (specdam)
+ simple_monster_message(defender, " is engulfed in flame!");
+
+ damage_taken += specdam;
+ break;
+
+ case MONS_QUEEN_BEE:
+ case MONS_GIANT_CENTIPEDE:
+ case MONS_SOLDIER_ANT:
+ case MONS_QUEEN_ANT:
+ //if ((damage_taken > 2 && one_chance_in(3) ) || one_chance_in(20) )
+ //{
+ if (sees)
+ {
+ strcpy(info, ptr_monam(attacker, DESC_CAP_THE));
+ strcat(info, " stings ");
+ strcat(info, ptr_monam(defender, DESC_NOCAP_THE));
+ strcat(info, ".");
+ mpr(info);
+ }
+ poison_monster(defender, false);
+ //}
+ break;
+
+ // enum does not match comment 14jan2000 {dlb}
+ case MONS_SCORPION: // snake
+ case MONS_BROWN_SNAKE:
+ case MONS_BLACK_SNAKE:
+ case MONS_YELLOW_SNAKE:
+ case MONS_GOLD_MIMIC:
+ case MONS_WEAPON_MIMIC:
+ case MONS_ARMOUR_MIMIC:
+ case MONS_SCROLL_MIMIC:
+ case MONS_POTION_MIMIC:
+ if (one_chance_in(20) || (damage_taken > 2 && one_chance_in(4)))
+ poison_monster(defender, false);
+ break;
+
+ case MONS_SHADOW_DRAGON:
+ case MONS_SPECTRAL_THING:
+ if (coinflip())
+ break;
+ // intentional fall-through
+ case MONS_WIGHT:
+ case MONS_WRAITH:
+ case MONS_SOUL_EATER:
+ case MONS_SHADOW_FIEND:
+ case MONS_SPECTRAL_WARRIOR:
+ case MONS_ORANGE_RAT:
+ case MONS_ANCIENT_LICH:
+ case MONS_LICH:
+ case MONS_BORIS:
+ if (mons_res_negative_energy( defender ))
+ break;
+
+ if (one_chance_in(30) || (damage_taken > 5 && coinflip()))
+ {
+ simple_monster_message(defender, " is drained.");
+
+ if (one_chance_in(5))
+ defender->hit_dice--;
+
+ defender->max_hit_points -= 2 + random2(3);
+ defender->hit_points -= 2 + random2(3);
+
+ if (defender->hit_points >= defender->max_hit_points)
+ defender->hit_points = defender->max_hit_points;
+
+ if (defender->hit_points < 1 || defender->hit_dice < 1)
+ {
+ monster_die(defender, KILL_MON, monster_attacking);
+ return true;
+ }
+ }
+ break;
+
+ // enum does not match comment 14jan2000 {dlb}
+ case MONS_WORM: // giant wasp
+ break;
+
+ case MONS_SIMULACRUM_SMALL:
+ case MONS_SIMULACRUM_LARGE:
+ specdam = 0;
+
+ if (mons_res_cold(defender) == 0)
+ specdam = roll_dice( 1, 4 );
+ else if (mons_res_cold(defender) < 0)
+ specdam = roll_dice( 2, 4 );
+
+ if (specdam && sees)
+ {
+ strcpy(info, ptr_monam(attacker, DESC_CAP_THE));
+ strcat(info, " freezes ");
+ strcat(info, ptr_monam(defender, DESC_NOCAP_THE));
+ strcat(info, ".");
+ mpr(info);
+ }
+
+ damage_taken += specdam;
+ break;
+
+ case MONS_ICE_DEVIL:
+ case MONS_ICE_BEAST:
+ case MONS_FREEZING_WRAITH:
+ case MONS_ICE_FIEND:
+ case MONS_WHITE_IMP:
+ case MONS_AZURE_JELLY:
+ case MONS_ANTAEUS:
+ specdam = 0;
+ if (mons_res_cold(defender) == 0)
+ {
+ specdam = attacker->hit_dice + random2(attacker->hit_dice * 2);
+ }
+ else if (mons_res_cold(defender) < 0)
+ {
+ specdam = random2(attacker->hit_dice * 3) + (attacker->hit_dice * 2);
+ }
+
+ if (specdam && sees)
+ {
+ strcpy(info, ptr_monam(attacker, DESC_CAP_THE));
+ strcat(info, " freezes ");
+ strcat(info, ptr_monam(defender, DESC_NOCAP_THE));
+ strcat(info, ".");
+ mpr(info);
+ }
+ damage_taken += specdam;
+ break;
+
+ case MONS_ELECTRIC_GOLEM:
+ if (mons_flies(defender) == 0 && mons_res_elec(defender) == 0)
+ {
+ specdam = attacker->hit_dice + random2(attacker->hit_dice * 2);
+ }
+
+ if (specdam && sees)
+ {
+ strcpy(info, ptr_monam(attacker, DESC_CAP_THE));
+ strcat(info, " shocks ");
+ strcat(info, ptr_monam(defender, DESC_NOCAP_THE));
+ strcat(info, ".");
+ mpr(info);
+ }
+ damage_taken += specdam;
+ break;
+
+ case MONS_VAMPIRE:
+ case MONS_VAMPIRE_KNIGHT:
+ case MONS_VAMPIRE_MAGE:
+ if (mons_res_negative_energy(defender) > 0)
+ break;
+
+ // heh heh {dlb}
+ if (heal_monster(attacker, random2(damage_taken), true))
+ simple_monster_message(attacker, " is healed.");
+ break;
+ }
+ }
+
+ // special weapons:
+ if (hit
+ && (attacker->inv[hand_used] != NON_ITEM
+ || ((attacker->type == MONS_PLAYER_GHOST
+ || attacker->type == MONS_PANDEMONIUM_DEMON)
+ && ghost.values[ GVAL_BRAND ] != SPWPN_NORMAL)))
+ {
+ unsigned char itdam;
+
+ if (attacker->type == MONS_PLAYER_GHOST
+ || attacker->type == MONS_PANDEMONIUM_DEMON)
+ {
+ itdam = ghost.values[ GVAL_BRAND ];
+ }
+ else
+ itdam = mitm[attacker->inv[hand_used]].special;
+
+ specdam = 0;
+
+ if (attacker->type == MONS_PLAYER_GHOST
+ || attacker->type == MONS_PANDEMONIUM_DEMON)
+ {
+ switch (itdam)
+ {
+ case SPWPN_NORMAL:
+ default:
+ break;
+
+ case SPWPN_SWORD_OF_CEREBOV:
+ case SPWPN_FLAMING:
+ specdam = 0;
+
+ if (itdam == SPWPN_SWORD_OF_CEREBOV
+ || mons_res_fire(defender) <= 0)
+ {
+ specdam = 1 + random2(damage_taken);
+ }
+
+ if (specdam)
+ {
+ if (sees)
+ {
+ strcpy(info, ptr_monam(attacker, DESC_CAP_THE));
+ strcat(info, " burns ");
+ strcat(info, ptr_monam(defender, DESC_NOCAP_THE ));
+
+ if (specdam < 3)
+ strcat(info, ".");
+ else if (specdam < 7)
+ strcat(info, "!");
+ else
+ strcat(info, "!!");
+
+ mpr(info);
+ }
+ }
+ break;
+
+ case SPWPN_FREEZING:
+ specdam = 0;
+
+ if (mons_res_cold(defender) <= 0)
+ specdam = 1 + random2(damage_taken);
+
+ if (specdam)
+ {
+ if (sees)
+ {
+ mmov_x = attacker->inv[hand_used];
+
+ strcpy(info, ptr_monam(attacker, DESC_CAP_THE));
+ strcat(info, " freezes ");
+ strcat(info, ptr_monam(defender, DESC_NOCAP_THE));
+
+ if (specdam < 3)
+ strcat(info, ".");
+ else if (specdam < 7)
+ strcat(info, "!");
+ else
+ strcat(info, "!!");
+
+ mpr(info);
+ }
+ }
+ break;
+
+ case SPWPN_HOLY_WRATH:
+ if (attacker->type == MONS_PLAYER_GHOST)
+ break;
+ specdam = 0;
+ switch (mons_holiness(defender->type))
+ {
+ case MH_HOLY:
+ // I would think that it would do zero damage {dlb}
+ damage_taken -= 5 + random2(5);
+ break;
+
+ case MH_UNDEAD:
+ specdam += 1 + random2(damage_taken);
+ break;
+
+ case MH_DEMONIC:
+ specdam += 1 + (random2(damage_taken) * 15) / 10;
+ break;
+ }
+ break;
+
+ case SPWPN_ELECTROCUTION:
+ //if ( attacker->type == MONS_PLAYER_GHOST ) break;
+ if (mons_flies(defender) > 0 || mons_res_elec(defender) > 0)
+ break;
+
+ specdam = 0;
+
+#if 0
+ // more of the old code... -- bwr
+ if (menv[monster_attacking].type != MONS_PLAYER_GHOST
+ && (mitm[attacker->inv[hand_used]].plus2 <= 0
+ || item_cursed( mitm[attacker->inv[hand_used]] )))
+ {
+ break;
+ }
+#endif
+
+ if (one_chance_in(3))
+ {
+ if (sees)
+ mpr("There is a sudden explosion of sparks!");
+
+ specdam += 10 + random2(15);
+ //mitm[attacker->inv[hand_used]].plus2 --;
+ }
+ break;
+
+ case SPWPN_ORC_SLAYING:
+ if (mons_charclass(defender->type) == MONS_ORC)
+ hurt_monster(defender, 1 + random2(damage_taken));
+ break;
+
+ case SPWPN_STAFF_OF_OLGREB:
+ case SPWPN_VENOM:
+ if (!one_chance_in(3))
+ poison_monster(defender, false);
+ break;
+
+ //case 7: // protection
+
+ case SPWPN_DRAINING:
+ if (!mons_res_negative_energy( defender )
+ && (one_chance_in(30)
+ || (damage_taken > 5 && coinflip())))
+ {
+ simple_monster_message(defender, " is drained");
+
+ if (one_chance_in(5))
+ defender->hit_dice--;
+
+ defender->max_hit_points -= 2 + random2(3);
+ defender->hit_points -= 2 + random2(3);
+
+ if (defender->hit_points >= defender->max_hit_points)
+ defender->hit_points = defender->max_hit_points;
+
+ if (defender->hit_points < 1
+ || defender->hit_dice < 1)
+ {
+ monster_die(defender, KILL_MON, monster_attacking);
+ return true;
+ }
+ specdam = 1 + (random2(damage_taken) / 2);
+ }
+ break;
+
+ case SPWPN_SPEED:
+ wpn_speed = (wpn_speed + 1) / 2;
+ break;
+
+ case SPWPN_VORPAL:
+ specdam += 1 + (random2(damage_taken) / 2);
+ break;
+
+ case SPWPN_VAMPIRES_TOOTH:
+ case SPWPN_VAMPIRICISM:
+ specdam = 0; // note does no extra damage
+
+ if (mons_res_negative_energy( defender ))
+ break;
+
+ if (one_chance_in(5))
+ break;
+
+ // heh heh {dlb}
+ if (heal_monster(attacker, 1 + random2(damage_taken), true))
+ simple_monster_message(attacker, " is healed.");
+ break;
+
+ case SPWPN_DISRUPTION:
+ if (attacker->type == MONS_PLAYER_GHOST)
+ break;
+
+ specdam = 0;
+
+ if (mons_holiness(defender->type) == MH_UNDEAD
+ && !one_chance_in(3))
+ {
+ simple_monster_message(defender, " shudders.");
+ specdam += random2avg(1 + (3 * damage_taken), 3);
+ }
+ break;
+
+
+ case SPWPN_DISTORTION:
+ if (one_chance_in(3))
+ {
+ if (mons_near(defender)
+ && player_monster_visible(defender))
+ {
+ strcpy(info, "Space bends around ");
+ strcat(info, ptr_monam(defender, DESC_NOCAP_THE));
+ strcat(info, ".");
+ mpr(info);
+ }
+
+ specdam += 1 + random2avg(7, 2);
+ break;
+ }
+ if (one_chance_in(3))
+ {
+ if (mons_near(defender)
+ && player_monster_visible(defender))
+ {
+ strcpy(info, "Space warps horribly around ");
+ strcat(info, ptr_monam(defender, DESC_NOCAP_THE));
+ strcat(info, "!");
+ mpr(info);
+ }
+
+ specdam += 3 + random2avg(24, 2);
+ break;
+ }
+
+ if (one_chance_in(3))
+ {
+ monster_blink(defender);
+ break;
+ }
+
+ if (coinflip())
+ {
+ monster_teleport(defender, coinflip());
+ break;
+ }
+
+ if (coinflip())
+ {
+ monster_die(defender, KILL_RESET, monster_attacking);
+ break;
+ }
+ break;
+ }
+ }
+ } // end of if special weapon
+
+ damage_taken += specdam;
+
+ if (damage_taken > 0)
+ {
+ hurt_monster(defender, damage_taken);
+
+ if (defender->hit_points < 1)
+ {
+ monster_die(defender, KILL_MON, monster_attacking);
+ return true;
+ }
+ }
+
+ // speed adjustment for weapon using monsters
+ if (wpn_speed > 0)
+ {
+ // only get one third penalty/bonus for second weapons.
+ if (runthru > 0)
+ wpn_speed = (20 + wpn_speed) / 3;
+
+ attacker->speed_increment -= (wpn_speed - 10) / 2;
+ }
+ } // end of for runthru
+
+ return true;
+} // end monsters_fight()
+
+
+/*
+ **************************************************
+ * *
+ * END PUBLIC FUNCTIONS *
+ * *
+ **************************************************
+*/
+
+
+// Added by DML 6/10/99.
+// For now, always returns damage: that is, it never modifies values,
+// just adds 'color'.
+static int weapon_type_modify( int weapnum, char noise[80], char noise2[80],
+ int damage )
+{
+ int weap_type = WPN_UNKNOWN;
+
+ if (weapnum == -1)
+ weap_type = WPN_UNARMED;
+ else if (item_is_staff( you.inv[weapnum] ))
+ weap_type = WPN_QUARTERSTAFF;
+ else if (you.inv[weapnum].base_type == OBJ_WEAPONS)
+ weap_type = you.inv[weapnum].sub_type;
+
+ noise2[0] = '\0';
+
+ // All weak hits look the same, except for when the player
+ // has a non-weapon in hand. -- bwr
+ if (damage < HIT_WEAK)
+ {
+ if (weap_type != WPN_UNKNOWN)
+ strcpy( noise, "hit" );
+ else
+ strcpy( noise, "clumsily bash" );
+
+ return (damage);
+ }
+
+ // take transformations into account, if no weapon is weilded
+ if (weap_type == WPN_UNARMED
+ && you.attribute[ATTR_TRANSFORMATION] != TRAN_NONE)
+ {
+ switch (you.attribute[ATTR_TRANSFORMATION])
+ {
+ case TRAN_SPIDER:
+ if (damage < HIT_STRONG)
+ strcpy( noise, "bite" );
+ else
+ strcpy( noise, "maul" );
+ break;
+ case TRAN_BLADE_HANDS:
+ if (damage < HIT_MED)
+ strcpy( noise, "slash" );
+ else if (damage < HIT_STRONG)
+ strcpy( noise, "slice" );
+ break;
+ case TRAN_ICE_BEAST:
+ case TRAN_STATUE:
+ case TRAN_LICH:
+ if (damage < HIT_MED)
+ strcpy( noise, "punch" );
+ else
+ strcpy( noise, "pummel" );
+ break;
+ case TRAN_DRAGON:
+ case TRAN_SERPENT_OF_HELL:
+ if (damage < HIT_MED)
+ strcpy( noise, "claw" );
+ else if (damage < HIT_STRONG)
+ strcpy( noise, "bite" );
+ else
+ strcpy( noise, "maul" );
+ break;
+ case TRAN_AIR:
+ strcpy( noise, "buffet" );
+ break;
+ } // transformations
+
+ return (damage);
+ }
+
+ switch (weap_type)
+ {
+ case WPN_KNIFE:
+ case WPN_DAGGER:
+ case WPN_SHORT_SWORD:
+ case WPN_TRIDENT:
+ case WPN_DEMON_TRIDENT:
+ case WPN_SPEAR:
+ if (damage < HIT_MED)
+ strcpy( noise, "puncture" );
+ else if (damage < HIT_STRONG)
+ strcpy( noise, "impale" );
+ else
+ {
+ strcpy( noise, "spit" );
+ strcpy( noise2, " like a pig" );
+ }
+ return (damage);
+
+ case WPN_BOW:
+ case WPN_CROSSBOW:
+ case WPN_HAND_CROSSBOW:
+ if (damage < HIT_STRONG)
+ strcpy( noise, "puncture" );
+ else
+ strcpy( noise, "skewer" );
+ return (damage);
+
+ case WPN_LONG_SWORD:
+ case WPN_GREAT_SWORD:
+ case WPN_SCIMITAR:
+ case WPN_FALCHION:
+ case WPN_HALBERD:
+ case WPN_GLAIVE:
+ case WPN_HAND_AXE:
+ case WPN_WAR_AXE:
+ case WPN_BROAD_AXE:
+ case WPN_BATTLEAXE:
+ case WPN_SCYTHE:
+ case WPN_QUICK_BLADE:
+ case WPN_KATANA:
+ case WPN_EXECUTIONERS_AXE:
+ case WPN_DOUBLE_SWORD:
+ case WPN_TRIPLE_SWORD:
+ case WPN_SABRE:
+ case WPN_DEMON_BLADE:
+ if (damage < HIT_MED)
+ strcpy( noise, "slash" );
+ else if (damage < HIT_STRONG)
+ strcpy( noise, "slice" );
+ else
+ {
+ strcpy( noise, "open" );
+ strcpy( noise2, " like a pillowcase" );
+ }
+ return (damage);
+
+ case WPN_SLING:
+ case WPN_CLUB:
+ case WPN_MACE:
+ case WPN_FLAIL:
+ case WPN_GREAT_MACE:
+ case WPN_GREAT_FLAIL:
+ case WPN_QUARTERSTAFF:
+ case WPN_GIANT_CLUB:
+ case WPN_HAMMER:
+ case WPN_ANCUS:
+ case WPN_MORNINGSTAR: /*for now, just a bludgeoning weapon */
+ case WPN_SPIKED_FLAIL: /*for now, just a bludgeoning weapon */
+ case WPN_EVENINGSTAR:
+ case WPN_GIANT_SPIKED_CLUB:
+ if (damage < HIT_MED)
+ strcpy( noise, "sock" );
+ else if (damage < HIT_STRONG)
+ strcpy( noise, "bludgeon" );
+ else
+ {
+ strcpy( noise, "crush" );
+ strcpy( noise2, " like a grape" );
+ }
+ return (damage);
+
+ case WPN_WHIP:
+ case WPN_DEMON_WHIP:
+ if (damage < HIT_MED)
+ strcpy( noise, "whack" );
+ else
+ strcpy( noise, "thrash" );
+ return (damage);
+
+ case WPN_UNARMED:
+ if (you.species == SP_TROLL || you.mutation[MUT_CLAWS])
+ {
+ if (damage < HIT_MED)
+ strcpy( noise, "claw" );
+ else if (damage < HIT_STRONG)
+ strcpy( noise, "mangle" );
+ else
+ strcpy( noise, "eviscerate" );
+ }
+ else
+ {
+ if (damage < HIT_MED)
+ strcpy( noise, "punch" );
+ else
+ strcpy( noise, "pummel" );
+ }
+ return (damage);
+
+ case WPN_UNKNOWN:
+ default:
+ strcpy( noise, "hit" );
+ return (damage);
+ }
+} // end weapon_type_modify()
+
+// Returns a value between 0 and 10 representing the weight given to str
+int weapon_str_weight( int wpn_class, int wpn_type )
+{
+ int ret;
+
+ const int wpn_skill = weapon_skill( wpn_class, wpn_type );
+ const int hands_reqd = hands_reqd_for_weapon( wpn_class, wpn_type );
+
+ // These are low values, because we'll be adding some bonus to the
+ // larger weapons later. Remember also that 1-1/2-hand weapons get
+ // a bonus in player_weapon_str_weight() as well (can't be done
+ // here because this function is used for cases where the weapon
+ // isn't being used by the player).
+
+ // Reasonings:
+ // - Short Blades are the best for the dexterous... although they
+ // are very limited in damage potential
+ // - Long Swords are better for the dexterous, the two-handed
+ // swords are a 50/50 split; bastard swords are in between.
+ // - Staves: didn't want to punish the mages who want to use
+ // these... made it a 50/50 split after the 2-hnd bonus
+ // - Polearms: Spears and tridents are the only ones that can
+ // be used one handed and are poking weapons, which requires
+ // more agility than strength. The other ones also require a
+ // fair amount of agility so they end up at 50/50 (most can poke
+ // as well as slash... although slashing is not their strong
+ // point).
+ // - Axes are weighted and edged and so require mostly strength,
+ // but not as much as Maces and Flails, which are typically
+ // blunt and spiked weapons.
+ switch (wpn_skill)
+ {
+ case SK_SHORT_BLADES: ret = 2; break;
+ case SK_LONG_SWORDS: ret = 3; break;
+ case SK_STAVES: ret = 3; break; // == 5 after 2-hand bonus
+ case SK_POLEARMS: ret = 3; break; // most are +2 for 2-hands
+ case SK_AXES: ret = 6; break;
+ case SK_MACES_FLAILS: ret = 7; break;
+ default: ret = 5; break;
+ }
+
+ // whips are special cased (because they are not much like maces)
+ if (wpn_type == WPN_WHIP || wpn_type == WPN_DEMON_WHIP)
+ ret = 2;
+ else if (wpn_type == WPN_QUICK_BLADE) // high dex is very good for these
+ ret = 1;
+
+ if (hands_reqd == HANDS_TWO_HANDED)
+ ret += 2;
+
+ // most weapons are capped at 8
+ if (ret > 8)
+ {
+ // these weapons are huge, so strength plays a larger role
+ if (wpn_type == WPN_GIANT_CLUB || wpn_type == WPN_GIANT_SPIKED_CLUB)
+ ret = 9;
+ else
+ ret = 8;
+ }
+
+ return (ret);
+}
+
+// Returns a value from 0 to 10 representing the weight of strength to
+// dexterity for the players currently wielded weapon.
+static inline int player_weapon_str_weight( void )
+{
+ const int weapon = you.equip[ EQ_WEAPON ];
+
+ // unarmed, weighted slightly towards dex -- would have been more,
+ // but then we'd be punishing Trolls and Ghouls who are strong and
+ // get special unarmed bonuses.
+ if (weapon == -1)
+ return (4);
+
+ int ret = weapon_str_weight( you.inv[weapon].base_type, you.inv[weapon].sub_type );
+
+ const bool shield = (you.equip[EQ_SHIELD] != -1);
+ const int hands_reqd = hands_reqd_for_weapon( you.inv[weapon].base_type,
+ you.inv[weapon].sub_type );
+
+ if (hands_reqd == HANDS_ONE_OR_TWO_HANDED && !shield)
+ ret += 1;
+
+ return (ret);
+}
+
+// weapon_dex_weight() + weapon_str_weight == 10 so we only need define
+// one of these.
+static inline int player_weapon_dex_weight( void )
+{
+ return (10 - player_weapon_str_weight());
+}
+
+static inline int calc_stat_to_hit_base( void )
+{
+#ifdef USE_NEW_COMBAT_STATS
+
+ // towards_str_avg is a variable, whose sign points towards strength,
+ // and the magnitude is half the difference (thus, when added directly
+ // to you.dex it gives the average of the two.
+ const signed int towards_str_avg = (you.strength - you.dex) / 2;
+
+ // dex is modified by strength towards the average, by the
+ // weighted amount weapon_str_weight() / 10.
+ return (you.dex + towards_str_avg * player_weapon_str_weight() / 10);
+
+#else
+ return (you.dex);
+#endif
+}
+
+
+static inline int calc_stat_to_dam_base( void )
+{
+#ifdef USE_NEW_COMBAT_STATS
+
+ const signed int towards_dex_avg = (you.dex - you.strength) / 2;
+ return (you.strength + towards_dex_avg * player_weapon_dex_weight() / 10);
+
+#else
+ return (you.strength);
+#endif
+}
+
+static void stab_message( struct monsters *defender, int stab_bonus )
+{
+ int r = random2(6); // for randomness
+
+ switch(stab_bonus)
+ {
+ case 3: // big melee, monster surrounded/not paying attention
+ if (r<3)
+ {
+ snprintf( info, INFO_SIZE, "You strike %s from a blind spot!",
+ ptr_monam(defender, DESC_NOCAP_THE) );
+ }
+ else
+ {
+ snprintf( info, INFO_SIZE, "You catch %s momentarily off-guard.",
+ ptr_monam(defender, DESC_NOCAP_THE) );
+ }
+ break;
+ case 2: // confused/fleeing
+ if (r<4)
+ {
+ snprintf( info, INFO_SIZE, "You catch %s completely off-guard!",
+ ptr_monam(defender, DESC_NOCAP_THE) );
+ }
+ else
+ {
+ snprintf( info, INFO_SIZE, "You strike %s from behind!",
+ ptr_monam(defender, DESC_NOCAP_THE) );
+ }
+ break;
+ case 1:
+ snprintf( info, INFO_SIZE, "%s fails to defend %s.",
+ ptr_monam(defender, DESC_CAP_THE),
+ mons_pronoun( defender->type, PRONOUN_REFLEXIVE ) );
+ break;
+ } // end switch
+
+ mpr(info);
+}
+
diff --git a/trunk/source/fight.h b/trunk/source/fight.h
new file mode 100644
index 0000000000..10515868c6
--- /dev/null
+++ b/trunk/source/fight.h
@@ -0,0 +1,52 @@
+/*
+ * File: fight.cc
+ * Summary: Functions used during combat.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef FIGHT_H
+#define FIGHT_H
+
+
+#include "externs.h"
+
+// added Sept 18, 2000 -- bwr
+/* ***********************************************************************
+ * called from: item_use.cc
+ * *********************************************************************** */
+int effective_stat_bonus( int wepType = -1 );
+
+// added Sept 18, 2000 -- bwr
+/* ***********************************************************************
+ * called from: describe.cc
+ * *********************************************************************** */
+int weapon_str_weight( int wpn_class, int wpn_type );
+
+
+// last updated: 08jun2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - it_use3
+ * *********************************************************************** */
+void you_attack(int monster_attacked, bool unarmed_attacks);
+
+
+// last updated: 08jun2000 {dlb}
+/* ***********************************************************************
+ * called from: monstuff
+ * *********************************************************************** */
+void monster_attack(int monster_attacking);
+
+
+// last updated: 08jun2000 {dlb}
+/* ***********************************************************************
+ * called from: monstuff
+ * *********************************************************************** */
+bool monsters_fight(int monster_attacking, int monster_attacked);
+
+
+#endif
diff --git a/trunk/source/files.cc b/trunk/source/files.cc
new file mode 100644
index 0000000000..65fb795e60
--- /dev/null
+++ b/trunk/source/files.cc
@@ -0,0 +1,1863 @@
+/*
+ * File: files.cc
+ * Summary: Functions used to save and load levels/games.
+ * Written by: Linley Henzell and Alexey Guzeev
+ *
+ * Change History (most recent first):
+ *
+ * <7> 19 June 2000 GDL Change handle to FILE *
+ * <6> 11/14/99 cdl Don't let player ghosts follow you up/down
+ * <5> 7/13/99 BWR Monsters now regenerate hps off level &
+ ghosts teleport
+ * <4> 6/13/99 BWR Added tmp file pairs to save file.
+ * <3> 6/11/99 DML Replaced temp file deletion code.
+ *
+ * <2> 5/12/99 BWR Multiuser system support,
+ * including appending UID to
+ * name, and compressed saves
+ * in the SAVE_DIR_PATH directory
+ *
+ * <1> --/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "files.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#ifdef DOS
+#include <conio.h>
+#include <file.h>
+#endif
+
+#ifdef LINUX
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+
+#ifdef USE_EMX
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+
+#ifdef OS9
+#include <stat.h>
+#else
+#include <sys/stat.h>
+#endif
+
+#include "externs.h"
+
+#include "cloud.h"
+#include "debug.h"
+#include "dungeon.h"
+#include "itemname.h"
+#include "items.h"
+#include "message.h"
+#include "misc.h"
+#include "monstuff.h"
+#include "mon-util.h"
+#include "mstuff2.h"
+#include "player.h"
+#include "randart.h"
+#include "skills2.h"
+#include "stuff.h"
+#include "tags.h"
+#include "wpn-misc.h"
+
+void save_level(int level_saved, bool was_a_labyrinth, char where_were_you);
+
+// temp file pairs used for file level cleanup
+extern FixedArray < bool, MAX_LEVELS, MAX_BRANCHES > tmp_file_pairs;
+
+/*
+ Order for looking for conjurations for the 1st & 2nd spell slots,
+ when finding spells to be remembered by a player's ghost:
+ */
+unsigned char search_order_conj[] = {
+/* 0 */
+ SPELL_LEHUDIBS_CRYSTAL_SPEAR,
+ SPELL_BOLT_OF_DRAINING,
+ SPELL_AGONY,
+ SPELL_DISINTEGRATE,
+ SPELL_LIGHTNING_BOLT,
+ SPELL_STICKY_FLAME,
+ SPELL_ISKENDERUNS_MYSTIC_BLAST,
+ SPELL_BOLT_OF_FIRE,
+ SPELL_BOLT_OF_COLD,
+ SPELL_FIREBALL,
+ SPELL_DELAYED_FIREBALL,
+/* 10 */
+ SPELL_VENOM_BOLT,
+ SPELL_BOLT_OF_IRON,
+ SPELL_STONE_ARROW,
+ SPELL_THROW_FLAME,
+ SPELL_THROW_FROST,
+ SPELL_PAIN,
+ SPELL_STING,
+ SPELL_MAGIC_DART,
+ SPELL_NO_SPELL, // end search
+};
+
+/*
+ Order for looking for summonings and self-enchants for the 3rd spell slot:
+ */
+unsigned char search_order_third[] = {
+/* 0 */
+ SPELL_SYMBOL_OF_TORMENT,
+ SPELL_SUMMON_GREATER_DEMON,
+ SPELL_SUMMON_WRAITHS,
+ SPELL_SUMMON_HORRIBLE_THINGS,
+ SPELL_SUMMON_DEMON,
+ SPELL_DEMONIC_HORDE,
+ SPELL_HASTE,
+ SPELL_ANIMATE_DEAD,
+ SPELL_INVISIBILITY,
+ SPELL_CALL_IMP,
+ SPELL_SUMMON_SMALL_MAMMAL,
+/* 10 */
+ SPELL_CONTROLLED_BLINK,
+ SPELL_BLINK,
+ SPELL_NO_SPELL, // end search
+};
+
+/*
+ Order for looking for enchants for the 4th + 5th spell slot. If fails, will
+ go through conjs.
+ Note: Dig must be in misc2 (5th) position to work.
+ */
+unsigned char search_order_misc[] = {
+/* 0 */
+ SPELL_AGONY,
+ SPELL_BANISHMENT,
+ SPELL_PARALYZE,
+ SPELL_CONFUSE,
+ SPELL_SLOW,
+ SPELL_POLYMORPH_OTHER,
+ SPELL_TELEPORT_OTHER,
+ SPELL_DIG,
+ SPELL_NO_SPELL, // end search
+};
+
+/* Last slot (emergency) can only be teleport self or blink. */
+
+static void redraw_all(void)
+{
+ you.redraw_hit_points = 1;
+ you.redraw_magic_points = 1;
+ you.redraw_strength = 1;
+ you.redraw_intelligence = 1;
+ you.redraw_dexterity = 1;
+ you.redraw_armour_class = 1;
+ you.redraw_evasion = 1;
+ you.redraw_experience = 1;
+ you.redraw_gold = 1;
+
+ you.redraw_status_flags = REDRAW_LINE_1_MASK | REDRAW_LINE_2_MASK | REDRAW_LINE_3_MASK;
+}
+
+struct ghost_struct ghost;
+
+unsigned char translate_spell(unsigned char spel);
+unsigned char search_third_list(unsigned char ignore_spell);
+unsigned char search_second_list(unsigned char ignore_spell);
+unsigned char search_first_list(unsigned char ignore_spell);
+
+void add_spells( struct ghost_struct &gs );
+void generate_random_demon();
+
+static bool determine_version( FILE *restoreFile,
+ char &majorVersion, char &minorVersion );
+
+static void restore_version( FILE *restoreFile,
+ char majorVersion, char minorVersion );
+
+static bool determine_level_version( FILE *levelFile,
+ char &majorVersion, char &minorVersion );
+
+static void restore_level_version( FILE *levelFile,
+ char majorVersion, char minorVersion );
+
+static bool determine_ghost_version( FILE *ghostFile,
+ char &majorVersion, char &minorVersion );
+
+static void restore_ghost_version( FILE *ghostFile,
+ char majorVersion, char minorVersion );
+
+static void restore_tagged_file( FILE *restoreFile, int fileType,
+ char minorVersion );
+
+static void load_ghost();
+
+void make_filename( char *buf, const char *prefix, int level, int where,
+ bool isLabyrinth, bool isGhost )
+{
+ UNUSED( isGhost );
+
+ char suffix[4], lvl[5];
+ char finalprefix[kFileNameLen];
+
+ strcpy(suffix, (level < 10) ? "0" : "");
+ itoa(level, lvl, 10);
+ strcat(suffix, lvl);
+ suffix[2] = where + 97;
+ suffix[3] = '\0';
+
+ // init buf
+ buf[0] = '\0';
+
+#ifdef SAVE_DIR_PATH
+ strcpy(buf, SAVE_DIR_PATH);
+#endif
+
+ strncpy(finalprefix, prefix, kFileNameLen);
+ finalprefix[kFileNameLen] = '\0';
+
+ strcat(buf, finalprefix);
+
+#ifdef SAVE_DIR_PATH
+ // everyone sees everyone else's ghosts. :)
+ char uid[10];
+ if (!isGhost)
+ {
+ itoa( (int) getuid(), uid, 10 );
+ strcat(buf, uid);
+ }
+#endif
+
+ strcat(buf, ".");
+ if (isLabyrinth)
+ strcat(buf, "lab"); // temporary level
+ else
+ strcat(buf, suffix);
+}
+
+static void write_tagged_file( FILE *dataFile, char majorVersion,
+ char minorVersion, int fileType )
+{
+ struct tagHeader th;
+
+ // find all relevant tags
+ char tags[NUM_TAGS];
+ tag_set_expected(tags, fileType);
+
+ // write version
+ struct tagHeader versionTag;
+ versionTag.offset = 0;
+ versionTag.tagID = TAG_VERSION;
+ marshallByte(versionTag, majorVersion);
+ marshallByte(versionTag, minorVersion);
+ tag_write(versionTag, dataFile);
+
+ // all other tags
+ for(int i=1; i<NUM_TAGS; i++)
+ {
+ if (tags[i] == 1)
+ {
+ tag_construct(th, i);
+ tag_write(th, dataFile);
+ }
+ }
+}
+
+void load( unsigned char stair_taken, int load_mode, bool was_a_labyrinth,
+ char old_level, char where_were_you2 )
+{
+ int j = 0;
+ int i = 0, count_x = 0, count_y = 0;
+ char cha_fil[kFileNameSize];
+
+ int foll_class[8];
+ int foll_hp[8];
+ int foll_hp_max[8];
+ unsigned char foll_HD[8];
+ int foll_AC[8];
+ char foll_ev[8];
+ unsigned char foll_speed[8];
+ unsigned char foll_speed_inc[8];
+
+ unsigned char foll_targ_1_x[8];
+ unsigned char foll_targ_1_y[8];
+ unsigned char foll_beh[8];
+ unsigned char foll_att[8];
+ int foll_sec[8];
+ unsigned char foll_hit[8];
+
+ unsigned char foll_ench[8][NUM_MON_ENCHANTS];
+ unsigned char foll_flags[8];
+
+ item_def foll_item[8][8];
+
+ int itmf = 0;
+ int ic = 0;
+ int imn = 0;
+ int val;
+
+ bool just_created_level = false;
+
+#ifdef DOS_TERM
+ window(1, 1, 80, 25);
+#endif
+
+ make_filename( cha_fil, you.your_name, you.your_level, you.where_are_you,
+ you.level_type != LEVEL_DUNGEON, false );
+
+ if (you.level_type == LEVEL_DUNGEON)
+ {
+ if (tmp_file_pairs[you.your_level][you.where_are_you] == false)
+ {
+ // make sure old file is gone
+ unlink(cha_fil);
+
+ // save the information for later deletion -- DML 6/11/99
+ tmp_file_pairs[you.your_level][you.where_are_you] = true;
+ }
+ }
+
+ you.prev_targ = MHITNOT;
+
+ int following = -1;
+ int fmenv = 0; // not used again until after found_stair label {dlb}
+ int minvc = 0;
+
+ // Don't delete clouds just because the player saved and restarted.
+ if (load_mode != LOAD_RESTART_GAME)
+ {
+ for (int clouty = 0; clouty < MAX_CLOUDS; ++clouty)
+ delete_cloud( clouty );
+
+ ASSERT( env.cloud_no == 0 );
+ }
+
+ // This block is to grab followers and save the old level to disk.
+ if (load_mode == LOAD_ENTER_LEVEL)
+ {
+ // grab followers
+ for (count_x = you.x_pos - 1; count_x < you.x_pos + 2; count_x++)
+ {
+ for (count_y = you.y_pos - 1; count_y < you.y_pos + 2; count_y++)
+ {
+ if (count_x == you.x_pos && count_y == you.y_pos)
+ continue;
+
+ following++;
+ foll_class[following] = -1;
+
+ if (mgrd[count_x][count_y] == NON_MONSTER)
+ continue;
+
+ struct monsters *fmenv = &menv[mgrd[count_x][count_y]];
+
+ if (fmenv->type == MONS_PLAYER_GHOST
+ && fmenv->hit_points < fmenv->max_hit_points / 2)
+ {
+ mpr("The ghost fades into the shadows.");
+ monster_teleport(fmenv, true);
+ continue;
+ }
+
+ // monster has to be already tagged in order to follow:
+ if (!testbits( fmenv->flags, MF_TAKING_STAIRS ))
+ continue;
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "%s is following.",
+ ptr_monam( fmenv, DESC_CAP_THE ) );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ foll_class[following] = fmenv->type;
+ foll_hp[following] = fmenv->hit_points;
+ foll_hp_max[following] = fmenv->max_hit_points;
+ foll_HD[following] = fmenv->hit_dice;
+ foll_AC[following] = fmenv->armour_class;
+ foll_ev[following] = fmenv->evasion;
+ foll_speed[following] = fmenv->speed;
+ foll_speed_inc[following] = fmenv->speed_increment;
+ foll_targ_1_x[following] = fmenv->target_x;
+ foll_targ_1_y[following] = fmenv->target_y;
+
+ for (minvc = 0; minvc < NUM_MONSTER_SLOTS; ++minvc)
+ {
+ const int item = fmenv->inv[minvc];
+ if (item == NON_ITEM)
+ {
+ foll_item[following][minvc].quantity = 0;
+ continue;
+ }
+
+ foll_item[following][minvc] = mitm[item];
+ destroy_item( item );
+ }
+
+ foll_beh[following] = fmenv->behaviour;
+ foll_att[following] = fmenv->attitude;
+ foll_sec[following] = fmenv->number;
+ foll_hit[following] = fmenv->foe;
+
+ for (j = 0; j < NUM_MON_ENCHANTS; j++)
+ {
+ foll_ench[following][j] = fmenv->enchantment[j];
+ fmenv->enchantment[j] = ENCH_NONE;
+ }
+
+ foll_flags[following] = fmenv->flags;
+
+ fmenv->flags = 0;
+ fmenv->type = -1;
+ fmenv->hit_points = 0;
+ fmenv->max_hit_points = 0;
+ fmenv->hit_dice = 0;
+ fmenv->armour_class = 0;
+ fmenv->evasion = 0;
+
+ mgrd[count_x][count_y] = NON_MONSTER;
+ }
+ } // end of grabbing followers
+
+ if (!was_a_labyrinth)
+ save_level( old_level, false, where_were_you2 );
+
+ was_a_labyrinth = false;
+ }
+
+ // clear out ghost/demon lord information:
+ strcpy( ghost.name, "" );
+ for (ic = 0; ic < NUM_GHOST_VALUES; ++ic)
+ ghost.values[ic] = 0;
+
+#ifdef DOS
+ strupr(cha_fil);
+#endif
+
+ // Try to open level savefile.
+ FILE *levelFile = fopen(cha_fil, "rb");
+
+ // GENERATE new level when the file can't be opened:
+ if (levelFile == NULL)
+ {
+ strcpy(ghost.name, "");
+
+ for (imn = 0; imn < NUM_GHOST_VALUES; ++imn)
+ ghost.values[imn] = 0;
+
+ builder( you.your_level, you.level_type );
+ just_created_level = true;
+
+ if (you.level_type == LEVEL_PANDEMONIUM)
+ generate_random_demon();
+
+ if (you.your_level > 1 && one_chance_in(3))
+ load_ghost();
+ }
+ else
+ {
+ // BEGIN -- must load the old level : pre-load tasks
+
+ // LOAD various tags
+ char majorVersion;
+ char minorVersion;
+
+ if (!determine_level_version( levelFile, majorVersion, minorVersion ))
+ {
+ perror("\nLevel file appears to be invalid.\n");
+ end(-1);
+ }
+
+ restore_level_version( levelFile, majorVersion, minorVersion );
+
+ // sanity check - EOF
+ if (!feof( levelFile ))
+ {
+ snprintf( info, INFO_SIZE, "\nIncomplete read of \"%s\" - aborting.\n", cha_fil);
+ perror(info);
+ end(-1);
+ }
+
+ fclose( levelFile );
+
+ // POST-LOAD tasks :
+ link_items();
+ redraw_all();
+ }
+
+ // closes all the gates if you're on the way out
+ for (i = 0; i < GXM; i++)
+ {
+ for (j = 0; j < GYM; j++)
+ {
+ if (just_created_level)
+ env.map[i][j] = 0;
+
+ if (you.char_direction == DIR_ASCENDING
+ && you.level_type != LEVEL_PANDEMONIUM)
+ {
+ if (grd[i][j] == DNGN_ENTER_HELL
+ || grd[i][j] == DNGN_ENTER_ABYSS
+ || grd[i][j] == DNGN_ENTER_PANDEMONIUM)
+ {
+ grd[i][j] = DNGN_STONE_ARCH;
+ }
+ }
+
+ if (load_mode != LOAD_RESTART_GAME)
+ env.cgrid[i][j] = EMPTY_CLOUD;
+ }
+ }
+
+ // This next block is for cases where we want to look for a stairs
+ // to place the player.
+ if (load_mode != LOAD_RESTART_GAME && you.level_type != LEVEL_ABYSS)
+ {
+ bool find_first = true;
+
+ // Order is important here:
+ if (you.level_type == LEVEL_DUNGEON
+ && where_were_you2 == BRANCH_VESTIBULE_OF_HELL
+ && stair_taken == DNGN_STONE_STAIRS_UP_I)
+ {
+ // leaving hell - look for entry potal first
+ stair_taken = DNGN_ENTER_HELL;
+ find_first = false;
+ }
+ else if (stair_taken == DNGN_EXIT_PANDEMONIUM)
+ {
+ stair_taken = DNGN_ENTER_PANDEMONIUM;
+ find_first = false;
+ }
+ else if (stair_taken == DNGN_EXIT_ABYSS)
+ {
+ stair_taken = DNGN_ENTER_ABYSS;
+ find_first = false;
+ }
+ else if (stair_taken == DNGN_ENTER_HELL
+ || stair_taken == DNGN_ENTER_LABYRINTH)
+ {
+ // the vestibule and labyrith always start from this stair
+ stair_taken = DNGN_STONE_STAIRS_UP_I;
+ }
+ else if (stair_taken >= DNGN_STONE_STAIRS_DOWN_I
+ && stair_taken <= DNGN_ROCK_STAIRS_DOWN)
+ {
+ // look for coresponding up stair
+ stair_taken += (DNGN_STONE_STAIRS_UP_I - DNGN_STONE_STAIRS_DOWN_I);
+ }
+ else if (stair_taken >= DNGN_STONE_STAIRS_UP_I
+ && stair_taken <= DNGN_ROCK_STAIRS_UP)
+ {
+ // look for coresponding down stair
+ stair_taken += (DNGN_STONE_STAIRS_DOWN_I - DNGN_STONE_STAIRS_UP_I);
+ }
+ else if (stair_taken >= DNGN_RETURN_FROM_ORCISH_MINES
+ && stair_taken < 150) // 20 slots reserved
+ {
+ // find entry point to subdungeon when leaving
+ stair_taken += (DNGN_ENTER_ORCISH_MINES - DNGN_RETURN_FROM_ORCISH_MINES);
+ }
+ else if (stair_taken >= DNGN_ENTER_ORCISH_MINES
+ && stair_taken < DNGN_RETURN_FROM_ORCISH_MINES)
+ {
+ // find exit staircase from subdungeon when entering
+ stair_taken += (DNGN_RETURN_FROM_ORCISH_MINES - DNGN_ENTER_ORCISH_MINES);
+ }
+ else if (stair_taken >= DNGN_ENTER_DIS
+ && stair_taken <= DNGN_TRANSIT_PANDEMONIUM)
+ {
+ // when entering a hell or pandemonium
+ stair_taken = DNGN_STONE_STAIRS_UP_I;
+ }
+ else // Note: stair_taken can equal things like DNGN_FLOOR
+ {
+ // just find a nice empty square
+ stair_taken = DNGN_FLOOR;
+ find_first = false;
+ }
+
+ int found = 0;
+ int x_pos = 0, y_pos = 0;
+
+ // Start by looking for the expected entry point:
+ for (count_x = 0; count_x < GXM; count_x++)
+ {
+ for (count_y = 0; count_y < GYM; count_y++)
+ {
+ if (grd[count_x][count_y] == stair_taken)
+ {
+ found++;
+ if (one_chance_in( found ))
+ {
+ x_pos = count_x;
+ y_pos = count_y;
+ }
+
+ if (find_first)
+ goto found_stair; // double break
+ }
+ }
+ }
+
+found_stair:
+ if (!found)
+ {
+ // See if we can find a stairway in the "right" direction:
+ for (count_x = 0; count_x < GXM; count_x++)
+ {
+ for (count_y = 0; count_y < GYM; count_y++)
+ {
+ if (stair_taken <= DNGN_ROCK_STAIRS_DOWN)
+ {
+ // looking for any down stairs
+ if (grd[count_x][count_y] >= DNGN_STONE_STAIRS_DOWN_I
+ && grd[count_x][count_y] <= DNGN_ROCK_STAIRS_DOWN)
+ {
+ found++;
+ if (one_chance_in( found ))
+ {
+ x_pos = count_x;
+ y_pos = count_y;
+ }
+ }
+ }
+ else
+ {
+ // looking for any up stairs
+ if (grd[count_x][count_y] >= DNGN_STONE_STAIRS_UP_I
+ && grd[count_x][count_y] <= DNGN_ROCK_STAIRS_UP)
+ {
+ found++;
+ if (one_chance_in( found ))
+ {
+ x_pos = count_x;
+ y_pos = count_y;
+ }
+ }
+ }
+ }
+ }
+
+ if (!found)
+ {
+ // Still not found? Look for any clear terrain:
+ for (count_x = 0; count_x < GXM; count_x++)
+ {
+ for (count_y = 0; count_y < GYM; count_y++)
+ {
+ if (grd[count_x][count_y] >= DNGN_FLOOR)
+ {
+ found++;
+ if (one_chance_in( found ))
+ {
+ x_pos = count_x;
+ y_pos = count_y;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // If still not found, the level is very buggy.
+ ASSERT( found );
+
+ you.x_pos = x_pos;
+ you.y_pos = y_pos;
+ }
+ else if (load_mode != LOAD_RESTART_GAME && you.level_type == LEVEL_ABYSS)
+ {
+ you.x_pos = 45;
+ you.y_pos = 35;
+ }
+
+ // This should fix the "monster occuring under the player" bug?
+ if (mgrd[you.x_pos][you.y_pos] != NON_MONSTER)
+ monster_teleport(&menv[mgrd[you.x_pos][you.y_pos]], true);
+
+ if (you.level_type == LEVEL_LABYRINTH || you.level_type == LEVEL_ABYSS)
+ grd[you.x_pos][you.y_pos] = DNGN_FLOOR;
+
+ following = 0;
+ fmenv = -1;
+
+ // actually "move" the followers if applicable
+ if ((you.level_type == LEVEL_DUNGEON
+ || you.level_type == LEVEL_PANDEMONIUM)
+ && load_mode == LOAD_ENTER_LEVEL)
+ {
+ for (ic = 0; ic < 2; ic++)
+ {
+ for (count_x = you.x_pos - 6; count_x < you.x_pos + 7;
+ count_x++)
+ {
+ for (count_y = you.y_pos - 6; count_y < you.y_pos + 7;
+ count_y++)
+ {
+ if (ic == 0
+ && ((count_x < you.x_pos - 1)
+ || (count_x > you.x_pos + 1)
+ || (count_y < you.y_pos - 1)
+ || (count_y > you.y_pos + 1)))
+ {
+ continue;
+ }
+
+ if (count_x == you.x_pos && count_y == you.y_pos)
+ continue;
+
+ if (mgrd[count_x][count_y] != NON_MONSTER
+ || grd[count_x][count_y] < DNGN_FLOOR)
+ {
+ continue;
+ }
+
+ while (menv[following].type != -1)
+ {
+ following++;
+
+ if (following >= MAX_MONSTERS)
+ goto out_of_foll;
+ }
+
+ while (fmenv < 7)
+ {
+ fmenv++;
+
+ if (foll_class[fmenv] == -1)
+ continue;
+
+ menv[following].type = foll_class[fmenv];
+ menv[following].hit_points = foll_hp[fmenv];
+ menv[following].max_hit_points = foll_hp_max[fmenv];
+ menv[following].hit_dice = foll_HD[fmenv];
+ menv[following].armour_class = foll_AC[fmenv];
+ menv[following].evasion = foll_ev[fmenv];
+ menv[following].speed = foll_speed[fmenv];
+ menv[following].x = count_x;
+ menv[following].y = count_y;
+ menv[following].target_x = 0;
+ menv[following].target_y = 0;
+ menv[following].speed_increment = foll_speed_inc[fmenv];
+
+ for (minvc = 0; minvc < NUM_MONSTER_SLOTS; minvc++)
+ {
+
+ if (!is_valid_item(foll_item[fmenv][minvc]))
+ {
+ menv[following].inv[minvc] = NON_ITEM;
+ continue;
+ }
+
+ itmf = get_item_slot(0);
+ if (itmf == NON_ITEM)
+ {
+ menv[following].inv[minvc] = NON_ITEM;
+ continue;
+ }
+
+ mitm[itmf] = foll_item[fmenv][minvc];
+ mitm[itmf].x = 0;
+ mitm[itmf].y = 0;
+ mitm[itmf].link = NON_ITEM;
+
+ menv[following].inv[minvc] = itmf;
+ }
+
+ menv[following].behaviour = foll_beh[fmenv];
+ menv[following].attitude = foll_att[fmenv];
+ menv[following].number = foll_sec[fmenv];
+ menv[following].foe = foll_hit[fmenv];
+
+ for (j = 0; j < NUM_MON_ENCHANTS; j++)
+ menv[following].enchantment[j]=foll_ench[fmenv][j];
+
+ menv[following].flags = foll_flags[fmenv];
+ menv[following].flags |= MF_JUST_SUMMONED;
+
+ mgrd[count_x][count_y] = following;
+ break;
+ }
+ }
+ }
+ }
+ } // end of moving followers
+
+ out_of_foll:
+ redraw_all();
+
+ // Sanity forcing of monster inventory items (required?)
+ for (i = 0; i < MAX_MONSTERS; i++)
+ {
+ if (menv[i].type == -1)
+ continue;
+
+ for (j = 0; j < NUM_MONSTER_SLOTS; j++)
+ {
+ if (menv[i].inv[j] == NON_ITEM)
+ continue;
+
+ /* items carried by monsters shouldn't be linked */
+ if (mitm[menv[i].inv[j]].link != NON_ITEM)
+ mitm[menv[i].inv[j]].link = NON_ITEM;
+ }
+ }
+
+ // Translate stairs for pandemonium levels:
+ if (you.level_type == LEVEL_PANDEMONIUM)
+ {
+ for (count_x = 0; count_x < GXM; count_x++)
+ {
+ for (count_y = 0; count_y < GYM; count_y++)
+ {
+ if (grd[count_x][count_y] >= DNGN_STONE_STAIRS_UP_I
+ && grd[count_x][count_y] <= DNGN_ROCK_STAIRS_UP)
+ {
+ if (one_chance_in( you.mutation[MUT_PANDEMONIUM] ? 5 : 50 ))
+ grd[count_x][count_y] = DNGN_EXIT_PANDEMONIUM;
+ else
+ grd[count_x][count_y] = DNGN_FLOOR;
+ }
+
+ if (grd[count_x][count_y] >= DNGN_ENTER_LABYRINTH
+ && grd[count_x][count_y] <= DNGN_ROCK_STAIRS_DOWN)
+ {
+ grd[count_x][count_y] = DNGN_TRANSIT_PANDEMONIUM;
+ }
+ }
+ }
+ }
+
+ // Things to update for player entering level
+ if (load_mode == LOAD_ENTER_LEVEL)
+ {
+ // update corpses and fountains
+ if (env.elapsed_time != 0.0)
+ update_level( you.elapsed_time - env.elapsed_time );
+
+ // Centaurs have difficulty with stairs
+ val = ((you.species != SP_CENTAUR) ? player_movement_speed() : 15);
+
+ // new levels have less wary monsters:
+ if (just_created_level)
+ val /= 2;
+
+ val -= (stepdown_value( check_stealth(), 50, 50, 150, 150 ) / 10);
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "arrival time: %d", val );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ if (val > 0)
+ {
+ you.time_taken = val;
+ handle_monsters();
+ }
+ }
+
+ // Save the created/updated level out to disk:
+ save_level( you.your_level, (you.level_type != LEVEL_DUNGEON),
+ you.where_are_you );
+} // end load()
+
+void save_level(int level_saved, bool was_a_labyrinth, char where_were_you)
+{
+ char cha_fil[kFileNameSize];
+
+ make_filename( cha_fil, you.your_name, level_saved, where_were_you,
+ was_a_labyrinth, false );
+
+ you.prev_targ = MHITNOT;
+
+#ifdef DOS
+ strupr(cha_fil);
+#endif
+
+ FILE *saveFile = fopen(cha_fil, "wb");
+
+ if (saveFile == NULL)
+ {
+ strcpy(info, "Unable to open \"");
+ strcat(info, cha_fil );
+ strcat(info, "\" for writing!");
+ perror(info);
+ end(-1);
+ }
+
+ // nail all items to the ground
+ fix_item_coordinates();
+
+ // 4.0 initial genesis of saved format
+ // 4.1 added attitude tag
+ // 4.2 replaced old 'enchantment1' and with 'flags' (bitfield)
+ // 4.3 changes to make the item structure more sane
+ // 4.4 changes to the ghost save section
+ // 4.5 spell and ability letter arrays
+
+ write_tagged_file( saveFile, 4, 5, TAGTYPE_LEVEL );
+
+ fclose(saveFile);
+
+#ifdef SHARED_FILES_CHMOD_PRIVATE
+ chmod(cha_fil, SHARED_FILES_CHMOD_PRIVATE);
+#endif
+} // end save_level()
+
+void save_game(bool leave_game)
+{
+ char charFile[kFileNameSize];
+
+#ifdef SAVE_PACKAGE_CMD
+ char cmd_buff[1024];
+ char name_buff[kFileNameSize];
+
+ snprintf( name_buff, sizeof(name_buff),
+ SAVE_DIR_PATH "%s%d", you.your_name, (int) getuid() );
+
+ snprintf( cmd_buff, sizeof(cmd_buff),
+ SAVE_PACKAGE_CMD, name_buff, name_buff );
+
+ snprintf( charFile, sizeof(charFile),
+ "%s.sav", name_buff );
+
+#else
+ strncpy(charFile, you.your_name, kFileNameLen);
+ charFile[kFileNameLen] = 0;
+ strcat(charFile, ".sav");
+
+#ifdef DOS
+ strupr(charFile);
+#endif
+#endif
+
+ FILE *saveFile = fopen(charFile, "wb");
+
+ if (saveFile == NULL)
+ {
+ strcpy(info, "Unable to open \"");
+ strcat(info, charFile );
+ strcat(info, "\" for writing!");
+ perror(info);
+ end(-1);
+ }
+
+ // 4.0 initial genesis of saved format
+ // 4.1 changes to make the item structure more sane
+ // 4.2 spell and ability tables
+
+ write_tagged_file( saveFile, 4, 2, TAGTYPE_PLAYER );
+
+ fclose(saveFile);
+
+#ifdef SHARED_FILES_CHMOD_PRIVATE
+ // change mode (unices)
+ chmod(charFile, SHARED_FILES_CHMOD_PRIVATE);
+#endif
+
+ // if just save, early out
+ if (!leave_game)
+ return;
+
+ // must be exiting -- save level & goodbye!
+ save_level(you.your_level, (you.level_type != LEVEL_DUNGEON),
+ you.where_are_you);
+
+#ifdef DOS_TERM
+ window(1, 1, 80, 25);
+#endif
+
+ clrscr();
+
+#ifdef SAVE_PACKAGE_CMD
+ if (system( cmd_buff ) != 0)
+ {
+ cprintf( EOL "Warning: Zip command (SAVE_PACKAGE_CMD) returned non-zero value!" EOL );
+ }
+
+#ifdef SHARED_FILES_CHMOD_PRIVATE
+ strcat( name_buff, PACKAGE_SUFFIX );
+ // change mode (unices)
+ chmod( name_buff, SHARED_FILES_CHMOD_PRIVATE );
+#endif
+
+#endif
+
+ cprintf( "See you soon, %s!" EOL , you.your_name );
+
+ end(0);
+} // end save_game()
+
+void load_ghost(void)
+{
+ char majorVersion;
+ char minorVersion;
+ char cha_fil[kFileNameSize];
+ int imn;
+ int i;
+
+ make_filename( cha_fil, "bones", you.your_level, you.where_are_you,
+ (you.level_type != LEVEL_DUNGEON), true );
+
+ FILE *gfile = fopen(cha_fil, "rb");
+
+ if (gfile == NULL)
+ return; // no such ghost.
+
+ if (!determine_ghost_version(gfile, majorVersion, minorVersion))
+ {
+ fclose(gfile);
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "Ghost file \"%s\" seems to be invalid.",
+ cha_fil);
+ mpr( info, MSGCH_DIAGNOSTICS );
+ more();
+#endif
+ return;
+ }
+
+ restore_ghost_version(gfile, majorVersion, minorVersion);
+
+ // sanity check - EOF
+ if (!feof(gfile))
+ {
+ fclose(gfile);
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "Incomplete read of \"%s\".", cha_fil);
+ mpr( info, MSGCH_DIAGNOSTICS );
+ more();
+#endif
+ return;
+ }
+
+ fclose(gfile);
+
+#if DEBUG_DIAGNOSTICS
+ mpr( "Loaded ghost.", MSGCH_DIAGNOSTICS );
+#endif
+
+ // remove bones file - ghosts are hardly permanent.
+ unlink(cha_fil);
+
+ // translate ghost to monster and place.
+ for (imn = 0; imn < MAX_MONSTERS - 10; imn++)
+ {
+ if (menv[imn].type != -1)
+ continue;
+
+ menv[imn].type = MONS_PLAYER_GHOST;
+ menv[imn].hit_dice = ghost.values[ GVAL_EXP_LEVEL ];
+ menv[imn].hit_points = ghost.values[ GVAL_MAX_HP ];
+ menv[imn].max_hit_points = ghost.values[ GVAL_MAX_HP ];
+ menv[imn].armour_class = ghost.values[ GVAL_AC];
+ menv[imn].evasion = ghost.values[ GVAL_EV ];
+ menv[imn].speed = 10;
+ menv[imn].speed_increment = 70;
+ menv[imn].attitude = ATT_HOSTILE;
+ menv[imn].behaviour = BEH_WANDER;
+ menv[imn].flags = 0;
+ menv[imn].foe = MHITNOT;
+ menv[imn].foe_memory = 0;
+
+ menv[imn].number = 250;
+
+ for (i = GVAL_SPELL_1; i <= GVAL_SPELL_6; i++)
+ {
+ if (ghost.values[i] != MS_NO_SPELL)
+ {
+ menv[imn].number = MST_GHOST;
+ break;
+ }
+ }
+
+ for (i = 0; i < NUM_MONSTER_SLOTS; i++)
+ menv[imn].inv[i] = NON_ITEM;
+
+ for (i = 0; i < NUM_MON_ENCHANTS; i++)
+ menv[imn].enchantment[i] = ENCH_NONE;
+
+ do
+ {
+ menv[imn].x = random2(GXM - 20) + 10;
+ menv[imn].y = random2(GYM - 20) + 10;
+ }
+ while ((grd[menv[imn].x][menv[imn].y] != DNGN_FLOOR)
+ || (mgrd[menv[imn].x][menv[imn].y] != NON_MONSTER));
+
+ mgrd[menv[imn].x][menv[imn].y] = imn;
+ break;
+ }
+}
+
+
+void restore_game(void)
+{
+ char char_f[kFileNameSize];
+
+#ifdef SAVE_DIR_PATH
+ snprintf( char_f, sizeof(char_f),
+ SAVE_DIR_PATH "%s%d", you.your_name, (int) getuid() );
+#else
+ strncpy(char_f, you.your_name, kFileNameLen);
+ char_f[kFileNameLen] = 0;
+#endif
+
+ strcat(char_f, ".sav");
+
+#ifdef DOS
+ strupr(char_f);
+#endif
+
+ FILE *restoreFile = fopen(char_f, "rb");
+
+ if (restoreFile == NULL)
+ {
+ strcpy(info, "Unable to open \"");
+ strcat(info, char_f );
+ strcat(info, "\" for reading!");
+ perror(info);
+ end(-1);
+ }
+
+ char majorVersion;
+ char minorVersion;
+
+ if (!determine_version(restoreFile, majorVersion, minorVersion))
+ {
+ perror("\nSavefile appears to be invalid.\n");
+ end(-1);
+ }
+
+ restore_version(restoreFile, majorVersion, minorVersion);
+
+ // sanity check - EOF
+ if (!feof(restoreFile))
+ {
+ snprintf( info, INFO_SIZE, "\nIncomplete read of \"%s\" - aborting.\n", char_f);
+ perror(info);
+ end(-1);
+ }
+
+ fclose(restoreFile);
+}
+
+static bool determine_version( FILE *restoreFile,
+ char &majorVersion, char &minorVersion )
+{
+ // read first two bytes.
+ char buf[2];
+ if (read2(restoreFile, buf, 2) != 2)
+ return false; // empty file?
+
+ // check for 3.30
+ if (buf[0] == you.your_name[0] && buf[1] == you.your_name[1])
+ {
+ majorVersion = 0;
+ minorVersion = 0;
+ rewind(restoreFile);
+ return true;
+ }
+
+ // otherwise, read version and validate.
+ majorVersion = buf[0];
+ minorVersion = buf[1];
+
+ if (majorVersion == 1 || majorVersion == 4)
+ return true;
+
+ return false; // if its not 1 or 4, no idea!
+}
+
+static void restore_version( FILE *restoreFile,
+ char majorVersion, char minorVersion )
+{
+ // assuming the following check can be removed once we can read all
+ // savefile versions.
+ if (majorVersion < 4)
+ {
+ snprintf( info, INFO_SIZE, "\nSorry, this release cannot read a v%d.%d savefile.\n",
+ majorVersion, minorVersion);
+ perror(info);
+ end(-1);
+ }
+
+ switch(majorVersion)
+ {
+ case 4:
+ restore_tagged_file(restoreFile, TAGTYPE_PLAYER, minorVersion);
+ break;
+ default:
+ break;
+ }
+}
+
+// generic v4 restore function
+static void restore_tagged_file( FILE *restoreFile, int fileType,
+ char minorVersion )
+{
+ int i;
+
+ char tags[NUM_TAGS];
+ tag_set_expected(tags, fileType);
+
+ while(1)
+ {
+ i = tag_read(restoreFile, minorVersion);
+ if (i == 0) // no tag!
+ break;
+ tags[i] = 0; // tag read
+ }
+
+ // go through and init missing tags
+ for(i=0; i<NUM_TAGS; i++)
+ {
+ if (tags[i] == 1) // expected but never read
+ tag_missing(i, minorVersion);
+ }
+}
+
+static bool determine_level_version( FILE *levelFile,
+ char &majorVersion, char &minorVersion )
+{
+ // read first two bytes.
+ char buf[2];
+ if (read2(levelFile, buf, 2) != 2)
+ return false; // empty file?
+
+ // check for 3.30 -- simply started right in with player name.
+ if (isprint(buf[0]) && buf[0] > 4) // who knows?
+ {
+ majorVersion = 0;
+ minorVersion = 0;
+ rewind(levelFile);
+ return true;
+ }
+
+ // otherwise, read version and validate.
+ majorVersion = buf[0];
+ minorVersion = buf[1];
+
+ if (majorVersion == 1 || majorVersion == 4)
+ return true;
+
+ return false; // if its not 1 or 4, no idea!
+}
+
+static void restore_level_version( FILE *levelFile,
+ char majorVersion, char minorVersion )
+{
+ // assuming the following check can be removed once we can read all
+ // savefile versions.
+ if (majorVersion < 4)
+ {
+ snprintf( info, INFO_SIZE, "\nSorry, this release cannot read a v%d.%d level file.\n",
+ majorVersion, minorVersion);
+ perror(info);
+ end(-1);
+ }
+
+ switch(majorVersion)
+ {
+ case 4:
+ restore_tagged_file(levelFile, TAGTYPE_LEVEL, minorVersion);
+ break;
+ default:
+ break;
+ }
+}
+
+static bool determine_ghost_version( FILE *ghostFile,
+ char &majorVersion, char &minorVersion )
+{
+ // read first two bytes.
+ char buf[2];
+ if (read2(ghostFile, buf, 2) != 2)
+ return false; // empty file?
+
+ // check for pre-v4 -- simply started right in with ghost name.
+ if (isprint(buf[0]) && buf[0] > 4)
+ {
+ majorVersion = 0;
+ minorVersion = 0;
+ rewind(ghostFile);
+ return true;
+ }
+
+ // otherwise, read version and validate.
+ majorVersion = buf[0];
+ minorVersion = buf[1];
+
+ if (majorVersion == 4)
+ return true;
+
+ return false; // if its not 4, no idea!
+}
+
+static void restore_old_ghost( FILE *ghostFile )
+{
+ char buf[41];
+
+ read2(ghostFile, buf, 41); // 41 causes EOF. 40 will not.
+
+ // translate
+ memcpy( ghost.name, buf, 20 );
+
+ for (int i = 0; i < 20; i++)
+ ghost.values[i] = static_cast< unsigned short >( buf[i+20] );
+
+ if (ghost.values[ GVAL_RES_FIRE ] >= 97)
+ ghost.values[ GVAL_RES_FIRE ] -= 100;
+
+ if (ghost.values[ GVAL_RES_COLD ] >= 97)
+ ghost.values[ GVAL_RES_COLD ] -= 100;
+}
+
+static void restore_ghost_version( FILE *ghostFile,
+ char majorVersion, char minorVersion )
+{
+ // currently, we can read all known ghost versions.
+ switch(majorVersion)
+ {
+ case 4:
+ restore_tagged_file(ghostFile, TAGTYPE_GHOST, minorVersion);
+ break;
+ case 0:
+ restore_old_ghost(ghostFile);
+ break;
+ default:
+ break;
+ }
+}
+
+void save_ghost( bool force )
+{
+ char cha_fil[kFileNameSize];
+ const int wpn = you.equip[EQ_WEAPON];
+
+ if (!force && (you.your_level < 2 || you.is_undead))
+ return;
+
+ make_filename( cha_fil, "bones", you.your_level, you.where_are_you,
+ (you.level_type != LEVEL_DUNGEON), true );
+
+ FILE *gfile = fopen(cha_fil, "rb");
+
+ // don't overwrite existing bones!
+ if (gfile != NULL)
+ {
+ fclose(gfile);
+ return;
+ }
+
+ memcpy(ghost.name, you.your_name, 20);
+
+ ghost.values[ GVAL_MAX_HP ] = ((you.hp_max >= 150) ? 150 : you.hp_max);
+ ghost.values[ GVAL_EV ] = player_evasion();
+ ghost.values[ GVAL_AC ] = player_AC();
+ ghost.values[ GVAL_SEE_INVIS ] = player_see_invis();
+ ghost.values[ GVAL_RES_FIRE ] = player_res_fire();
+ ghost.values[ GVAL_RES_COLD ] = player_res_cold();
+ ghost.values[ GVAL_RES_ELEC ] = player_res_electricity();
+
+ /* note - as ghosts, automatically get res poison + prot_life */
+
+ int d = 4;
+ int e = 0;
+
+ if (wpn != -1)
+ {
+ if (you.inv[wpn].base_type == OBJ_WEAPONS
+ || you.inv[wpn].base_type == OBJ_STAVES)
+ {
+ d = property( you.inv[wpn], PWPN_DAMAGE );
+
+ d *= 25 + you.skills[weapon_skill( you.inv[wpn].base_type,
+ you.inv[wpn].sub_type )];
+ d /= 25;
+
+ if (you.inv[wpn].base_type == OBJ_WEAPONS)
+ {
+ if (is_random_artefact( you.inv[wpn] ))
+ e = randart_wpn_property( you.inv[wpn], RAP_BRAND );
+ else
+ e = you.inv[wpn].special;
+ }
+ }
+ }
+ else
+ {
+ /* Unarmed combat */
+ if (you.species == SP_TROLL)
+ d += you.experience_level;
+
+ d += you.skills[SK_UNARMED_COMBAT];
+ }
+
+ d *= 30 + you.skills[SK_FIGHTING];
+ d /= 30;
+
+ d += you.strength / 4;
+
+ if (d > 50)
+ d = 50;
+
+ ghost.values[ GVAL_DAMAGE ] = d;
+ ghost.values[ GVAL_BRAND ] = e;
+ ghost.values[ GVAL_SPECIES ] = you.species;
+ ghost.values[ GVAL_BEST_SKILL ] = best_skill(SK_FIGHTING, (NUM_SKILLS - 1), 99);
+ ghost.values[ GVAL_SKILL_LEVEL ] = you.skills[best_skill(SK_FIGHTING, (NUM_SKILLS - 1), 99)];
+ ghost.values[ GVAL_EXP_LEVEL ] = you.experience_level;
+ ghost.values[ GVAL_CLASS ] = you.char_class;
+
+ add_spells(ghost);
+
+ gfile = fopen(cha_fil, "wb");
+
+ if (gfile == NULL)
+ {
+ strcpy(info, "Error creating ghost file: ");
+ strcat(info, cha_fil);
+ mpr(info);
+ more();
+ return;
+ }
+
+ // 4.0-4.3 old tagged savefile (values as unsigned char)
+ // 4.4 new tagged savefile (values as signed short)
+ write_tagged_file( gfile, 4, 4, TAGTYPE_GHOST );
+
+ fclose(gfile);
+
+#if DEBUG_DIAGNOSTICS
+ mpr( "Saved ghost.", MSGCH_DIAGNOSTICS );
+#endif
+
+#ifdef SHARED_FILES_CHMOD_PUBLIC
+ chmod(cha_fil, SHARED_FILES_CHMOD_PUBLIC);
+#endif
+} // end save_ghost()
+
+/*
+ Used when creating ghosts: goes through and finds spells for the ghost to
+ cast. Death is a traumatic experience, so ghosts only remember a few spells.
+ */
+void add_spells( struct ghost_struct &gs )
+{
+ int i = 0;
+
+ for (i = GVAL_SPELL_1; i <= GVAL_SPELL_6; i++)
+ gs.values[i] = SPELL_NO_SPELL;
+
+ gs.values[ GVAL_SPELL_1 ] = search_first_list(SPELL_NO_SPELL);
+ gs.values[ GVAL_SPELL_2 ] = search_first_list(gs.values[GVAL_SPELL_1]);
+ gs.values[ GVAL_SPELL_3 ] = search_second_list(SPELL_NO_SPELL);
+ gs.values[ GVAL_SPELL_4 ] = search_third_list(SPELL_NO_SPELL);
+
+ if (gs.values[ GVAL_SPELL_4 ] == SPELL_NO_SPELL)
+ gs.values[ GVAL_SPELL_4 ] = search_first_list(SPELL_NO_SPELL);
+
+ gs.values[ GVAL_SPELL_5 ] = search_first_list(gs.values[GVAL_SPELL_4]);
+
+ if (gs.values[ GVAL_SPELL_5 ] == SPELL_NO_SPELL)
+ gs.values[ GVAL_SPELL_5 ] = search_first_list(gs.values[GVAL_SPELL_4]);
+
+ if (player_has_spell( SPELL_DIG ))
+ gs.values[ GVAL_SPELL_5 ] = SPELL_DIG;
+
+ /* Looks for blink/tport for emergency slot */
+ if (player_has_spell( SPELL_CONTROLLED_BLINK )
+ || player_has_spell( SPELL_BLINK ))
+ {
+ gs.values[ GVAL_SPELL_6 ] = SPELL_CONTROLLED_BLINK;
+ }
+
+ if (player_has_spell( SPELL_TELEPORT_SELF ))
+ gs.values[ GVAL_SPELL_6 ] = SPELL_TELEPORT_SELF;
+
+ for (i = GVAL_SPELL_1; i <= GVAL_SPELL_6; i++)
+ gs.values[i] = translate_spell( gs.values[i] );
+} // end add_spells()
+
+unsigned char search_first_list(unsigned char ignore_spell)
+{
+ for (int i = 0; i < 20; i++)
+ {
+ if (search_order_conj[i] == SPELL_NO_SPELL)
+ return SPELL_NO_SPELL;
+
+ if (search_order_conj[i] == ignore_spell)
+ continue;
+
+ if (player_has_spell(search_order_conj[i]))
+ return search_order_conj[i];
+ }
+
+ return SPELL_NO_SPELL;
+} // end search_first_list()
+
+unsigned char search_second_list(unsigned char ignore_spell)
+{
+ for (int i = 0; i < 20; i++)
+ {
+ if (search_order_third[i] == SPELL_NO_SPELL)
+ return SPELL_NO_SPELL;
+
+ if (search_order_third[i] == ignore_spell)
+ continue;
+
+ if (player_has_spell(search_order_third[i]))
+ return search_order_third[i];
+ }
+
+ return SPELL_NO_SPELL;
+} // end search_second_list()
+
+unsigned char search_third_list(unsigned char ignore_spell)
+{
+ for (int i = 0; i < 20; i++)
+ {
+ if (search_order_misc[i] == SPELL_NO_SPELL)
+ return SPELL_NO_SPELL;
+
+ if (search_order_misc[i] == ignore_spell)
+ continue;
+
+ if (player_has_spell(search_order_misc[i]))
+ return search_order_misc[i];
+ }
+
+ return SPELL_NO_SPELL;
+} // end search_third_list()
+
+
+/*
+ When passed the number for a player spell, returns the equivalent monster
+ spell. Returns SPELL_NO_SPELL on failure (no equiv).
+ */
+unsigned char translate_spell(unsigned char spel)
+{
+ switch (spel)
+ {
+ case SPELL_TELEPORT_SELF:
+ return (MS_TELEPORT);
+
+ case SPELL_MAGIC_DART:
+ return (MS_MMISSILE);
+ case SPELL_FIREBALL:
+ case SPELL_DELAYED_FIREBALL:
+ return (MS_FIREBALL);
+ case SPELL_DIG:
+ return (MS_DIG);
+ case SPELL_BOLT_OF_FIRE:
+ return (MS_FIRE_BOLT);
+ case SPELL_BOLT_OF_COLD:
+ return (MS_COLD_BOLT);
+ case SPELL_LIGHTNING_BOLT:
+ return (MS_LIGHTNING_BOLT);
+ case SPELL_POLYMORPH_OTHER:
+ return (MS_MUTATION);
+ case SPELL_SLOW:
+ return (MS_SLOW);
+ case SPELL_HASTE:
+ return (MS_HASTE);
+ case SPELL_PARALYZE:
+ return (MS_PARALYSIS);
+ case SPELL_CONFUSE:
+ return (MS_CONFUSE);
+ case SPELL_INVISIBILITY:
+ return (MS_INVIS);
+ case SPELL_THROW_FLAME:
+ return (MS_FLAME);
+ case SPELL_THROW_FROST:
+ return (MS_FROST);
+ case SPELL_CONTROLLED_BLINK:
+ return (MS_BLINK); /* approximate */
+/* case FREEZING_CLOUD: return ; no freezing/mephitic cloud yet
+ case MEPHITIC_CLOUD: return ; */
+ case SPELL_VENOM_BOLT:
+ return (MS_VENOM_BOLT);
+ case SPELL_TELEPORT_OTHER:
+ return (MS_TELEPORT_OTHER);
+ case SPELL_SUMMON_SMALL_MAMMAL:
+ return (MS_VAMPIRE_SUMMON); /* approximate */
+ case SPELL_BOLT_OF_DRAINING:
+ return (MS_NEGATIVE_BOLT);
+ case SPELL_LEHUDIBS_CRYSTAL_SPEAR:
+ return (MS_CRYSTAL_SPEAR);
+ case SPELL_BLINK:
+ return (MS_BLINK);
+ case SPELL_ISKENDERUNS_MYSTIC_BLAST:
+ return (MS_ORB_ENERGY);
+ case SPELL_SUMMON_HORRIBLE_THINGS:
+ return (MS_LEVEL_SUMMON); /* approximate */
+ case SPELL_ANIMATE_DEAD:
+ return (MS_ANIMATE_DEAD);
+ case SPELL_PAIN:
+ return (MS_PAIN);
+ case SPELL_SUMMON_WRAITHS:
+ return (MS_SUMMON_UNDEAD); /* approximate */
+ case SPELL_STICKY_FLAME:
+ return (MS_STICKY_FLAME);
+ case SPELL_CALL_IMP:
+ return (MS_SUMMON_DEMON_LESSER);
+ case SPELL_BANISHMENT:
+ return (MS_BANISHMENT);
+ case SPELL_STING:
+ return (MS_STING);
+ case SPELL_SUMMON_DEMON:
+ return (MS_SUMMON_DEMON);
+ case SPELL_DEMONIC_HORDE:
+ return (MS_SUMMON_DEMON_LESSER);
+ case SPELL_SUMMON_GREATER_DEMON:
+ return (MS_SUMMON_DEMON_GREATER);
+ case SPELL_BOLT_OF_IRON:
+ return (MS_IRON_BOLT);
+ case SPELL_STONE_ARROW:
+ return (MS_STONE_ARROW);
+ case SPELL_DISINTEGRATE:
+ return (MS_DISINTEGRATE);
+ case SPELL_AGONY:
+ /* Too powerful to give ghosts Torment for Agony? Nah. */
+ return (MS_TORMENT);
+ case SPELL_SYMBOL_OF_TORMENT:
+ return (MS_TORMENT);
+ default:
+ break;
+ }
+
+ return (MS_NO_SPELL);
+}
+
+void generate_random_demon(void)
+{
+ int rdem = 0;
+ int i = 0;
+
+ for (rdem = 0; rdem < MAX_MONSTERS + 1; rdem++)
+ {
+ if (rdem == MAX_MONSTERS)
+ return;
+
+ if (menv[rdem].type == MONS_PANDEMONIUM_DEMON)
+ break;
+ }
+
+ char st_p[ITEMNAME_SIZE];
+
+ make_name(random2(250), random2(250), random2(250), 3, st_p);
+ strcpy(ghost.name, st_p);
+
+ // hp - could be defined below (as could ev, AC etc). Oh well, too late:
+ ghost.values[ GVAL_MAX_HP ] = 100 + roll_dice( 3, 50 );
+
+ ghost.values[ GVAL_EV ] = 5 + random2(20);
+ ghost.values[ GVAL_AC ] = 5 + random2(20);
+
+ ghost.values[ GVAL_SEE_INVIS ] = (one_chance_in(10) ? 0 : 1);
+
+ if (!one_chance_in(3))
+ ghost.values[ GVAL_RES_FIRE ] = (coinflip() ? 2 : 3);
+ else
+ {
+ ghost.values[ GVAL_RES_FIRE ] = 0; /* res_fire */
+
+ if (one_chance_in(10))
+ ghost.values[ GVAL_RES_FIRE ] = -1;
+ }
+
+ if (!one_chance_in(3))
+ ghost.values[ GVAL_RES_COLD ] = 2;
+ else
+ {
+ ghost.values[ GVAL_RES_COLD ] = 0; /* res_cold */
+
+ if (one_chance_in(10))
+ ghost.values[ GVAL_RES_COLD ] = -1;
+ }
+
+ // demons, like ghosts, automatically get poison res. and life prot.
+
+ // resist electricity:
+ ghost.values[ GVAL_RES_ELEC ] = (!one_chance_in(3) ? 1 : 0);
+
+ // HTH damage:
+ ghost.values[ GVAL_DAMAGE ] = 20 + roll_dice( 2, 20 );
+
+ // special attack type (uses weapon brand code):
+ ghost.values[ GVAL_BRAND ] = SPWPN_NORMAL;
+
+ if (!one_chance_in(3))
+ {
+ ghost.values[ GVAL_BRAND ] = random2(17);
+
+ /* some brands inappropriate (eg holy wrath) */
+ if (ghost.values[ GVAL_BRAND ] == SPWPN_HOLY_WRATH
+ || ghost.values[ GVAL_BRAND ] == SPWPN_ORC_SLAYING
+ || ghost.values[ GVAL_BRAND ] == SPWPN_PROTECTION
+ || ghost.values[ GVAL_BRAND ] == SPWPN_FLAME
+ || ghost.values[ GVAL_BRAND ] == SPWPN_FROST
+ || ghost.values[ GVAL_BRAND ] == SPWPN_DISRUPTION)
+ {
+ ghost.values[ GVAL_BRAND ] = SPWPN_SPEED;
+ }
+ }
+
+ // is demon a spellcaster?
+ // upped from one_chance_in(3)... spellcasters are more interesting
+ // and I expect named demons to typically have a trick or two -- bwr
+ ghost.values[GVAL_DEMONLORD_SPELLCASTER] = (one_chance_in(10) ? 0 : 1);
+
+ // does demon fly? (0 = no, 1 = fly, 2 = levitate)
+ ghost.values[GVAL_DEMONLORD_FLY] = (one_chance_in(3) ? 0 :
+ one_chance_in(5) ? 2 : 1);
+
+ // vacant <ghost best skill level>:
+ ghost.values[GVAL_DEMONLORD_UNUSED] = 0;
+
+ // hit dice:
+ ghost.values[GVAL_DEMONLORD_HIT_DICE] = 10 + roll_dice(2, 10);
+
+ // does demon cycle colours?
+ ghost.values[GVAL_DEMONLORD_CYCLE_COLOUR] = (one_chance_in(10) ? 1 : 0);
+
+ menv[rdem].hit_dice = ghost.values[ GVAL_DEMONLORD_HIT_DICE ];
+ menv[rdem].hit_points = ghost.values[ GVAL_MAX_HP ];
+ menv[rdem].max_hit_points = ghost.values[ GVAL_MAX_HP ];
+ menv[rdem].armour_class = ghost.values[ GVAL_AC ];
+ menv[rdem].evasion = ghost.values[ GVAL_EV ];
+ menv[rdem].speed = (one_chance_in(3) ? 10 : 6 + roll_dice(2, 9));
+ menv[rdem].speed_increment = 70;
+ menv[rdem].number = random_colour(); // demon's colour
+
+ for (i = GVAL_SPELL_1; i <= GVAL_SPELL_6; i++)
+ ghost.values[i] = SPELL_NO_SPELL;
+
+ /* This bit uses the list of player spells to find appropriate spells
+ for the demon, then converts those spells to the monster spell indices.
+ Some special monster-only spells are at the end. */
+ if (ghost.values[ GVAL_DEMONLORD_SPELLCASTER ] == 1)
+ {
+ if (coinflip())
+ {
+ for (;;)
+ {
+ if (one_chance_in(3))
+ break;
+
+ ghost.values[ GVAL_SPELL_1 ] = search_order_conj[i];
+ i++;
+
+ if (search_order_conj[i] == SPELL_NO_SPELL)
+ break;
+ }
+ }
+
+ if (coinflip())
+ {
+ for (;;)
+ {
+ if (one_chance_in(3))
+ break;
+
+ ghost.values[ GVAL_SPELL_2 ] = search_order_conj[i];
+
+ if (search_order_conj[i] == SPELL_NO_SPELL)
+ break;
+ }
+ }
+
+ if (!one_chance_in(4))
+ {
+ for (;;)
+ {
+ if (one_chance_in(3))
+ break;
+
+ ghost.values[ GVAL_SPELL_3 ] = search_order_third[i];
+ i++;
+
+ if (search_order_third[i] == SPELL_NO_SPELL)
+ break;
+ }
+ }
+
+ if (coinflip())
+ {
+ for (;;)
+ {
+ if (one_chance_in(3))
+ break;
+
+ ghost.values[ GVAL_SPELL_4 ] = search_order_misc[i];
+ i++;
+
+ if (search_order_misc[i] == SPELL_NO_SPELL)
+ break;
+ }
+ }
+
+ if (coinflip())
+ {
+ for(;;)
+ {
+ if (one_chance_in(3))
+ break;
+
+ ghost.values[ GVAL_SPELL_5 ] = search_order_misc[i];
+ i++;
+
+ if (search_order_misc[i] == SPELL_NO_SPELL)
+ break;
+ }
+ }
+
+ if (coinflip())
+ ghost.values[ GVAL_SPELL_6 ] = SPELL_BLINK;
+ if (coinflip())
+ ghost.values[ GVAL_SPELL_6 ] = SPELL_TELEPORT_SELF;
+
+ /* Converts the player spell indices to monster spell ones */
+ for (i = GVAL_SPELL_1; i <= GVAL_SPELL_6; i++)
+ ghost.values[i] = translate_spell( ghost.values[i] );
+
+ /* give demon a chance for some monster-only spells: */
+ /* and demon-summoning should be fairly common: */
+ if (one_chance_in(25))
+ ghost.values[GVAL_SPELL_1] = MS_HELLFIRE_BURST;
+ if (one_chance_in(25))
+ ghost.values[GVAL_SPELL_1] = MS_METAL_SPLINTERS;
+ if (one_chance_in(25))
+ ghost.values[GVAL_SPELL_1] = MS_ENERGY_BOLT; /* eye of devas */
+
+ if (one_chance_in(25))
+ ghost.values[GVAL_SPELL_2] = MS_STEAM_BALL;
+ if (one_chance_in(25))
+ ghost.values[GVAL_SPELL_2] = MS_PURPLE_BLAST;
+ if (one_chance_in(25))
+ ghost.values[GVAL_SPELL_2] = MS_HELLFIRE;
+
+ if (one_chance_in(25))
+ ghost.values[GVAL_SPELL_3] = MS_SMITE;
+ if (one_chance_in(25))
+ ghost.values[GVAL_SPELL_3] = MS_HELLFIRE_BURST;
+ if (one_chance_in(12))
+ ghost.values[GVAL_SPELL_3] = MS_SUMMON_DEMON_GREATER;
+ if (one_chance_in(12))
+ ghost.values[GVAL_SPELL_3] = MS_SUMMON_DEMON;
+
+ if (one_chance_in(20))
+ ghost.values[GVAL_SPELL_4] = MS_SUMMON_DEMON_GREATER;
+ if (one_chance_in(20))
+ ghost.values[GVAL_SPELL_4] = MS_SUMMON_DEMON;
+
+ /* at least they can summon demons */
+ if (ghost.values[17] == SPELL_NO_SPELL)
+ ghost.values[GVAL_SPELL_4] = MS_SUMMON_DEMON;
+
+ if (one_chance_in(15))
+ ghost.values[GVAL_SPELL_5] = MS_DIG;
+ }
+} // end generate_random_demon()
diff --git a/trunk/source/files.h b/trunk/source/files.h
new file mode 100644
index 0000000000..d0b2c68362
--- /dev/null
+++ b/trunk/source/files.h
@@ -0,0 +1,67 @@
+/*
+ * File: files.cc
+ * Summary: Functions used to save and load levels/games.
+ * Written by: Linley Henzell and Alexey Guzeev
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef FILES_H
+#define FILES_H
+
+#include "FixAry.h"
+
+
+// referenced in files - newgame - ouch - overmap:
+#define MAX_LEVELS 50
+// referenced in files - newgame - ouch - overmap:
+#define MAX_BRANCHES 30 // there must be a way this can be extracted from other data
+
+
+// referenced in files - newgame - ouch:
+extern FixedArray<bool, MAX_LEVELS, MAX_BRANCHES> tmp_file_pairs;
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - misc
+ * *********************************************************************** */
+#if 0
+void load( unsigned char stair_taken, bool moving_level,
+ bool was_a_labyrinth, char old_level, bool want_followers,
+ bool is_new_game, char where_were_you2 );
+#endif
+
+void load( unsigned char stair_taken, int load_mode, bool was_a_labyrinth,
+ char old_level, char where_were_you2 );
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - libmac - misc
+ * *********************************************************************** */
+void save_game(bool leave_game);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void restore_game(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: ouch
+ * *********************************************************************** */
+void save_ghost( bool force = false );
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: files hiscores
+ * *********************************************************************** */
+void make_filename( char *buf, const char *prefix, int level, int where,
+ bool isLabyrinth, bool isGhost );
+
+#endif
diff --git a/trunk/source/food.cc b/trunk/source/food.cc
new file mode 100644
index 0000000000..c481186ca3
--- /dev/null
+++ b/trunk/source/food.cc
@@ -0,0 +1,1303 @@
+/*
+ * File: food.cc
+ * Summary: Functions for eating and butchering.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <2> 5/20/99 BWR Added CRAWL_PIZZA.
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "food.h"
+
+#include <string.h>
+// required for abs() {dlb}:
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#include "externs.h"
+
+#include "debug.h"
+#include "delay.h"
+#include "invent.h"
+#include "items.h"
+#include "itemname.h"
+#include "item_use.h"
+#include "it_use2.h"
+#include "macro.h"
+#include "misc.h"
+#include "mon-util.h"
+#include "mutation.h"
+#include "player.h"
+#include "religion.h"
+#include "skills2.h"
+#include "spells2.h"
+#include "stuff.h"
+#include "wpn-misc.h"
+
+static bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg);
+static bool eat_from_floor(void);
+static int determine_chunk_effect(int which_chunk_type, bool rotten_chunk);
+static void eat_chunk( int chunk_effect );
+static void eat_from_inventory(int which_inventory_slot);
+static void eating(unsigned char item_class, int item_type);
+static void ghoul_eat_flesh( int chunk_effect );
+static void describe_food_change(int hunger_increment);
+static bool food_change(bool suppress_message);
+
+/*
+ **************************************************
+ * *
+ * BEGIN PUBLIC FUNCTIONS *
+ * *
+ **************************************************
+*/
+
+void make_hungry( int hunger_amount, bool suppress_msg )
+{
+ if (you.is_undead == US_UNDEAD)
+ return;
+
+#if DEBUG_DIAGNOSTICS
+ set_redraw_status( REDRAW_HUNGER );
+#endif
+
+ you.hunger -= hunger_amount;
+
+ if (you.hunger < 0)
+ you.hunger = 0;
+
+ // so we don't get two messages, ever.
+ bool state_message = food_change(false);
+
+ if (!suppress_msg && !state_message)
+ describe_food_change( -hunger_amount );
+} // end make_hungry()
+
+void lessen_hunger( int satiated_amount, bool suppress_msg )
+{
+ if (you.is_undead == US_UNDEAD)
+ return;
+
+ you.hunger += satiated_amount;
+
+ if (you.hunger > 12000)
+ you.hunger = 12000;
+
+ // so we don't get two messages, ever
+ bool state_message = food_change(false);
+
+ if (!suppress_msg && !state_message)
+ describe_food_change(satiated_amount);
+} // end lessen_hunger()
+
+void set_hunger( int new_hunger_level, bool suppress_msg )
+{
+ if (you.is_undead == US_UNDEAD)
+ return;
+
+ int hunger_difference = (new_hunger_level - you.hunger);
+
+ if (hunger_difference < 0)
+ make_hungry( abs(hunger_difference), suppress_msg );
+ else if (hunger_difference > 0)
+ lessen_hunger( hunger_difference, suppress_msg );
+} // end set_hunger()
+
+// more of a "weapon_switch back from butchering" function, switching
+// to a weapon is done using the wield_weapon code.
+// special cases like staves of power or other special weps are taken
+// care of by calling wield_effects() {gdl}
+
+void weapon_switch( int targ )
+{
+ if (targ == -1)
+ {
+ mpr( "You switch back to your bare hands." );
+ }
+ else
+ {
+ char buff[80];
+ in_name( targ, DESC_NOCAP_A, buff );
+
+ char let = index_to_letter( targ );
+
+ snprintf( info, INFO_SIZE, "Switching back to %c - %s.", let, buff );
+ mpr( info );
+ }
+
+ // unwield the old weapon and wield the new.
+ // XXX This is a pretty dangerous hack; I don't like it.--GDL
+ //
+ // Well yeah, but that's because interacting with the wielding
+ // code is a mess... this whole function's purpose was to
+ // isolate this hack until there's a proper way to do things. -- bwr
+ if (you.equip[EQ_WEAPON] != -1)
+ unwield_item(you.equip[EQ_WEAPON]);
+
+ you.equip[EQ_WEAPON] = targ;
+
+ // special checks: staves of power, etc
+ if (targ != -1)
+ wield_effects( targ, false );
+}
+
+bool butchery(void)
+{
+ char str_pass[ ITEMNAME_SIZE ];
+ int items_here = 0;
+ int o = igrd[you.x_pos][you.y_pos];
+ int k = 0;
+ int item_got;
+ unsigned char keyin;
+
+ bool can_butcher = false;
+ bool wpn_switch = false;
+ bool new_cursed = false;
+ int old_weapon = you.equip[EQ_WEAPON];
+
+ bool barehand_butcher = (you.equip[ EQ_GLOVES ] == -1)
+ && (you.species == SP_TROLL
+ || you.species == SP_GHOUL
+ || you.attribute[ATTR_TRANSFORMATION] == TRAN_BLADE_HANDS
+ || you.attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON
+ || you.mutation[MUT_CLAWS]);
+
+
+ if (igrd[you.x_pos][you.y_pos] == NON_ITEM)
+ {
+ mpr("There isn't anything here!");
+ return (false);
+ }
+
+ if (player_is_levitating() && !wearing_amulet(AMU_CONTROLLED_FLIGHT))
+ {
+ mpr("You can't reach the floor from up here.");
+ return (false);
+ }
+
+ if (barehand_butcher)
+ can_butcher = true;
+ else
+ {
+ if (you.equip[EQ_WEAPON] != -1)
+ {
+ can_butcher = can_cut_meat( you.inv[you.equip[EQ_WEAPON]].base_type,
+ you.inv[you.equip[EQ_WEAPON]].sub_type );
+ }
+
+ // Should probably check for cursed-weapons, bare hands and
+ // non-weapons in hand here, but wield_weapon will be used for
+ // this swap and it will do all that (although the player might
+ // be annoyed with the excess prompt).
+ if (Options.easy_butcher && !can_butcher)
+ {
+ const int a_slot = letter_to_index('a');
+ const int b_slot = letter_to_index('b');
+ int swap_slot = a_slot;
+
+ //mv: check for berserk first
+ if (you.berserker)
+ {
+ mpr ("You are too berserk to search for a butchering knife!");
+ return (false);
+ }
+
+ // Find out which slot is our auto-swap slot
+ if (you.equip[EQ_WEAPON] == a_slot)
+ swap_slot = b_slot;
+
+
+ // check if the swap slot is appropriate first
+ if (you.equip[EQ_WEAPON] != swap_slot)
+ {
+ if (is_valid_item( you.inv[ swap_slot ] ) // must have one
+
+ // must be able to cut with it
+ && can_cut_meat( you.inv[ swap_slot ].base_type,
+ you.inv[ swap_slot ].sub_type )
+
+ // must be known to be uncursed weapon
+ && you.inv[ swap_slot ].base_type == OBJ_WEAPONS
+ && item_known_uncursed( you.inv[ swap_slot ] ))
+ {
+ mpr( "Switching to your swap slot weapon." );
+ wpn_switch = true;
+ wield_weapon( true );
+ }
+ }
+
+ // if we didn't swap above, then we still can't cut... let's
+ // call wield_weapon() in the "prompt the user" way...
+ if (!wpn_switch)
+ {
+ // prompt for new weapon
+ mpr( "What would you like to use?", MSGCH_PROMPT );
+ wield_weapon( false );
+
+ // let's see if the user did something...
+ if (you.equip[EQ_WEAPON] != old_weapon)
+ wpn_switch = true;
+ }
+ }
+
+ // weapon might have changed (to bare hands as well), we'll
+ // update the can_butcher status accordingly (note: if we could
+ // butcher with our bare hands we wouldn't be here) -- bwr
+ if (wpn_switch && you.equip[EQ_WEAPON] != -1)
+ {
+ can_butcher = can_cut_meat( you.inv[you.equip[EQ_WEAPON]].base_type,
+ you.inv[you.equip[EQ_WEAPON]].sub_type );
+ }
+ }
+
+ // Account for the weapon switch above if it happened... we're
+ // doing this here since the above switch may reveal information
+ // about the weapon (curse status, ego type). So even if the
+ // character fails to or decides not to butcher past this point,
+ // they have achieved something and there should be a cost.
+ if (wpn_switch)
+ start_delay( DELAY_UNINTERUPTABLE, 1, old_weapon );
+
+ // check to see if the new implement is cursed - if so, set a
+ // flag indicating this. If a player actually butchers anything,
+ // this flag can be checked before switching back.
+ int wpn = you.equip[EQ_WEAPON];
+
+ if (wpn != -1
+ && you.inv[wpn].base_type == OBJ_WEAPONS
+ && item_cursed( you.inv[wpn] ))
+ {
+ new_cursed = true;
+ }
+
+ // Final checks and clue-giving...
+ if (!barehand_butcher && you.equip[EQ_WEAPON] == -1)
+ {
+ if (you.equip[ EQ_GLOVES ] == -1)
+ mpr("What, with your bare hands?");
+ else
+ mpr("You can't use your claws with your gloves on!");
+
+ // Switching back to avoid possible bug where player can use
+ // this to switch weapons in zero time.
+ if (wpn_switch)
+ weapon_switch( old_weapon );
+
+ return (false);
+ }
+ else if (!can_butcher)
+ {
+ mpr("Maybe you should try using a sharper implement.");
+
+ // Switching back to avoid possible bug where player can use
+ // this to switch weapons in zero time.
+ if (wpn_switch && !new_cursed)
+ weapon_switch( old_weapon );
+
+ return (false);
+ }
+
+ // No turning back at this point, we better be qualified.
+ ASSERT( can_butcher );
+
+ int last_item = NON_ITEM;
+
+ int objl = igrd[you.x_pos][you.y_pos];
+ int hrg = 0;
+ int counter = 0;
+
+ while (objl != NON_ITEM)
+ {
+ counter++;
+
+ last_item = objl;
+
+ hrg = mitm[objl].link;
+ objl = hrg;
+ items_here++;
+
+ if (counter > 1000)
+ {
+ error_message_to_player();
+
+ if (wpn_switch && !new_cursed)
+ weapon_switch( old_weapon );
+
+ return (false);
+ }
+ }
+
+ if (items_here == 1
+ && (mitm[igrd[you.x_pos][you.y_pos]].base_type == OBJ_CORPSES &&
+ mitm[igrd[you.x_pos][you.y_pos]].sub_type == CORPSE_BODY))
+ {
+ strcpy(info, "Butcher ");
+ it_name(igrd[you.x_pos][you.y_pos], DESC_NOCAP_A, str_pass);
+ strcat(info, str_pass);
+ strcat(info, "\?");
+ mpr(info, MSGCH_PROMPT);
+
+ unsigned char keyin = getch();
+
+ if (keyin == 0)
+ {
+ getch();
+ keyin = 0;
+ }
+
+ if (keyin != 'y' && keyin != 'Y')
+ {
+ if (wpn_switch && !new_cursed)
+ weapon_switch( old_weapon );
+
+ return (false);
+ }
+
+ int item_got = igrd[you.x_pos][you.y_pos];
+
+ last_item = NON_ITEM;
+
+ if (barehand_butcher)
+ mpr("You start tearing the corpse apart.");
+ else
+ mpr("You start hacking away.");
+
+ if (you.duration[DUR_PRAYER]
+ && (you.religion == GOD_OKAWARU
+ || you.religion == GOD_MAKHLEB || you.religion == GOD_TROG))
+ {
+ offer_corpse(item_got);
+ destroy_item(item_got);
+ // XXX: need an extra turn here for weapon swapping?
+ }
+ else
+ {
+ int work_req = 3 - mitm[item_got].plus2;
+ if (work_req < 0)
+ work_req = 0;
+
+ start_delay( DELAY_BUTCHER, work_req, item_got );
+ }
+
+ // cue up switching weapon back
+ if (wpn_switch && !new_cursed)
+ start_delay( DELAY_WEAPON_SWAP, 1, old_weapon );
+
+ you.turn_is_over = 1;
+
+ return (true);
+
+ } // end "if items_here == 1"
+ else if (items_here > 1)
+ {
+ last_item = NON_ITEM;
+ o = igrd[you.x_pos][you.y_pos];
+
+ for (k = 0; k < items_here; k++)
+ {
+ if (mitm[o].base_type != OBJ_CORPSES
+ || mitm[o].sub_type != CORPSE_BODY)
+ {
+ goto out_of_eating;
+ }
+
+ strcpy(info, "Butcher ");
+ it_name(o, DESC_NOCAP_A, str_pass);
+ strcat(info, str_pass);
+ strcat(info, "\?");
+ mpr(info, MSGCH_PROMPT);
+
+ keyin = getch();
+ if (keyin == 0)
+ {
+ getch();
+ keyin = 0;
+ }
+
+ if (keyin == 'q')
+ {
+ if (wpn_switch && !new_cursed)
+ weapon_switch( old_weapon );
+
+ return (false);
+ }
+
+ if (keyin == 'y')
+ {
+ item_got = o;
+
+ if (barehand_butcher)
+ mpr("You start tearing the corpse apart.");
+ else
+ mpr("You start hacking away.");
+
+ if (you.duration[DUR_PRAYER]
+ && (you.religion == GOD_OKAWARU
+ || you.religion == GOD_MAKHLEB
+ || you.religion == GOD_TROG))
+ {
+ offer_corpse(item_got);
+ destroy_item(item_got);
+ // XXX: need an extra turn here for weapon swapping?
+ }
+ else
+ {
+ int work_req = 3 - mitm[item_got].plus2;
+ if (work_req < 0)
+ work_req = 0;
+
+ start_delay( DELAY_BUTCHER, work_req, item_got );
+ }
+
+ if (wpn_switch && !new_cursed)
+ {
+ // weapon_switch( old_weapon );
+ // need to count the swap delay in this case
+ start_delay( DELAY_WEAPON_SWAP, 1, old_weapon );
+ }
+
+ you.turn_is_over = 1;
+ return (true);
+ }
+
+ out_of_eating:
+
+ if (is_valid_item( mitm[o] ))
+ last_item = o;
+
+ hrg = mitm[o].link;
+ o = hrg;
+
+ if (o == NON_ITEM)
+ break;
+
+ if (items_here == 0)
+ break;
+ } // end "for k" loop
+ }
+
+ mpr("There isn't anything to dissect here.");
+
+ if (wpn_switch && !new_cursed)
+ weapon_switch( old_weapon );
+
+ return (false);
+} // end butchery()
+
+void eat_food(void)
+{
+ int which_inventory_slot;
+
+ if (you.is_undead == US_UNDEAD)
+ {
+ mpr("You can't eat.");
+ return;
+ }
+
+ if (you.hunger >= 11000)
+ {
+ mpr("You're too full to eat anything.");
+ return;
+ }
+
+ if (igrd[you.x_pos][you.y_pos] != NON_ITEM)
+ {
+ if (eat_from_floor())
+ {
+ burden_change(); // ghouls regain strength from rotten food
+ return;
+ }
+ }
+
+ if (inv_count() < 1)
+ {
+ canned_msg(MSG_NOTHING_CARRIED);
+ return;
+ }
+
+ which_inventory_slot = prompt_invent_item( "Eat which item?", OBJ_FOOD );
+ if (which_inventory_slot == PROMPT_ABORT)
+ {
+ canned_msg( MSG_OK );
+ return;
+ }
+
+ // this conditional can later be merged into food::can_ingest() when
+ // expanded to handle more than just OBJ_FOOD 16mar200 {dlb}
+ if (you.inv[which_inventory_slot].base_type != OBJ_FOOD)
+ {
+ mpr("You can't eat that!");
+ return;
+ }
+
+ if (!can_ingest( you.inv[which_inventory_slot].base_type,
+ you.inv[which_inventory_slot].sub_type, false ))
+ {
+ return;
+ }
+
+ eat_from_inventory(which_inventory_slot);
+
+ burden_change();
+ you.turn_is_over = 1;
+} // end eat_food()
+
+/*
+ **************************************************
+ * *
+ * END PUBLIC FUNCTIONS *
+ * *
+ **************************************************
+*/
+
+static bool food_change(bool suppress_message)
+{
+ char newstate = HS_ENGORGED;
+ bool state_changed = false;
+
+ // this case shouldn't actually happen:
+ if (you.is_undead == US_UNDEAD)
+ you.hunger = 6000;
+
+ // take care of ghouls - they can never be 'full'
+ if (you.species == SP_GHOUL && you.hunger > 6999)
+ you.hunger = 6999;
+
+ // get new hunger state
+ if (you.hunger <= 1000)
+ newstate = HS_STARVING;
+ else if (you.hunger <= 2600)
+ newstate = HS_HUNGRY;
+ else if (you.hunger < 7000)
+ newstate = HS_SATIATED;
+ else if (you.hunger < 11000)
+ newstate = HS_FULL;
+
+ if (newstate != you.hunger_state)
+ {
+ state_changed = true;
+ you.hunger_state = newstate;
+ set_redraw_status( REDRAW_HUNGER );
+
+ if (suppress_message == false)
+ {
+ switch (you.hunger_state)
+ {
+ case HS_STARVING:
+ mpr("You are starving!", MSGCH_FOOD);
+ break;
+ case HS_HUNGRY:
+ mpr("You are feeling hungry.", MSGCH_FOOD);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ return (state_changed);
+} // end food_change()
+
+
+// food_increment is positive for eating, negative for hungering
+static void describe_food_change(int food_increment)
+{
+ int magnitude = (food_increment > 0)?food_increment:(-food_increment);
+
+ if (magnitude == 0)
+ return;
+
+ strcpy(info, (magnitude <= 100) ? "You feel slightly " :
+ (magnitude <= 350) ? "You feel somewhat " :
+ (magnitude <= 800) ? "You feel a quite a bit "
+ : "You feel a lot ");
+
+ if ((you.hunger_state > HS_SATIATED) ^ (food_increment < 0))
+ strcat(info, "more ");
+ else
+ strcat(info, "less ");
+
+ strcat(info, (you.hunger_state > HS_SATIATED) ? "full."
+ : "hungry.");
+ mpr(info);
+} // end describe_food_change()
+
+static void eat_from_inventory(int which_inventory_slot)
+{
+ if (you.inv[which_inventory_slot].sub_type == FOOD_CHUNK)
+ {
+ // this is a bit easier to read... most compilers should
+ // handle this the same -- bwr
+ const int mons_type = you.inv[ which_inventory_slot ].plus;
+ const int chunk_type = mons_corpse_thingy( mons_type );
+ const bool rotten = (you.inv[which_inventory_slot].special < 100);
+
+ eat_chunk( determine_chunk_effect( chunk_type, rotten ) );
+ }
+ else
+ {
+ eating( you.inv[which_inventory_slot].base_type,
+ you.inv[which_inventory_slot].sub_type );
+ }
+
+ dec_inv_item_quantity( which_inventory_slot, 1 );
+} // end eat_from_inventory()
+
+
+static bool eat_from_floor(void)
+{
+ char str_pass[ ITEMNAME_SIZE ];
+
+ if (player_is_levitating() && !wearing_amulet(AMU_CONTROLLED_FLIGHT))
+ return (false);
+
+ for (int o = igrd[you.x_pos][you.y_pos]; o != NON_ITEM; o = mitm[o].link)
+ {
+ if (mitm[o].base_type != OBJ_FOOD)
+ continue;
+
+ it_name( o, DESC_NOCAP_A, str_pass );
+ snprintf( info, INFO_SIZE, "Eat %s%s?", (mitm[o].quantity > 1) ? "one of " : "",
+ str_pass );
+ mpr( info, MSGCH_PROMPT );
+
+ unsigned char keyin = tolower( getch() );
+
+ if (keyin == 0)
+ {
+ getch();
+ keyin = 0;
+ }
+
+ if (keyin == 'q')
+ return (false);
+
+ if (keyin == 'y')
+ {
+ if (!can_ingest( mitm[o].base_type, mitm[o].sub_type, false ))
+ return (false);
+
+ if (mitm[o].sub_type == FOOD_CHUNK)
+ {
+ const int chunk_type = mons_corpse_thingy( mitm[o].plus );
+ const bool rotten = (mitm[o].special < 100);
+
+ eat_chunk( determine_chunk_effect( chunk_type, rotten ) );
+ }
+ else
+ {
+ eating( mitm[o].base_type, mitm[o].sub_type );
+ }
+
+ you.turn_is_over = 1;
+
+ dec_mitm_item_quantity( o, 1 );
+
+ return (true);
+ }
+ }
+
+ return (false);
+}
+
+
+// never called directly - chunk_effect values must pass
+// through food::determine_chunk_effect() first {dlb}:
+static void eat_chunk( int chunk_effect )
+{
+
+ bool likes_chunks = (you.species == SP_KOBOLD || you.species == SP_OGRE
+ || you.species == SP_TROLL
+ || you.mutation[MUT_CARNIVOROUS] > 0);
+
+ if (you.species == SP_GHOUL)
+ {
+ ghoul_eat_flesh( chunk_effect );
+ start_delay( DELAY_EAT, 2 );
+ lessen_hunger( 1000, true );
+ }
+ else
+ {
+ switch (chunk_effect)
+ {
+ case CE_MUTAGEN_RANDOM:
+ mpr("This meat tastes really weird.");
+ mutate(100);
+ break;
+
+ case CE_MUTAGEN_BAD:
+ mpr("This meat tastes *really* weird.");
+ give_bad_mutation();
+ break;
+
+ case CE_HCL:
+ rot_player( 10 + random2(10) );
+ disease_player( 50 + random2(100) );
+ break;
+
+ case CE_POISONOUS:
+ mpr("Yeeuch - this meat is poisonous!");
+ poison_player( 3 + random2(4) );
+ break;
+
+ case CE_ROTTEN:
+ case CE_CONTAMINATED:
+ mpr("There is something wrong with this meat.");
+ disease_player( 50 + random2(100) );
+ break;
+
+ // note that this is the only case that takes time and forces redraw
+ case CE_CLEAN:
+ strcpy(info, "This raw flesh ");
+
+ strcat(info, (likes_chunks) ? "tastes good."
+ : "is not very appetising.");
+ mpr(info);
+
+ start_delay( DELAY_EAT, 2 );
+ lessen_hunger( 1000, true );
+ break;
+ }
+ }
+
+ return;
+} // end eat_chunk()
+
+static void ghoul_eat_flesh( int chunk_effect )
+{
+ bool healed = false;
+
+ if (chunk_effect != CE_ROTTEN && chunk_effect != CE_CONTAMINATED)
+ {
+ mpr("This raw flesh tastes good.");
+
+ if (!one_chance_in(5))
+ healed = true;
+
+ if (player_rotted() && !one_chance_in(3))
+ {
+ mpr("You feel more resilient.");
+ unrot_hp(1);
+ }
+ }
+ else
+ {
+ if (chunk_effect == CE_ROTTEN)
+ mpr( "This rotting flesh tastes delicious!" );
+ else // CE_CONTAMINATED
+ mpr( "This flesh tastes delicious!" );
+
+ healed = true;
+
+ if (player_rotted() && !one_chance_in(4))
+ {
+ mpr("You feel more resilient.");
+ unrot_hp(1);
+ }
+ }
+
+ if (you.strength < you.max_strength && one_chance_in(5))
+ {
+ mpr("You feel your strength returning.");
+ you.strength++;
+ you.redraw_strength = 1;
+ }
+
+ if (healed && you.hp < you.hp_max)
+ inc_hp(1 + random2(5) + random2(1 + you.experience_level), false);
+
+ calc_hp();
+
+ return;
+} // end ghoul_eat_flesh()
+
+static void eating(unsigned char item_class, int item_type)
+{
+ int temp_rand; // probability determination {dlb}
+ int food_value = 0;
+ int how_herbivorous = you.mutation[MUT_HERBIVOROUS];
+ int how_carnivorous = you.mutation[MUT_CARNIVOROUS];
+ int carnivore_modifier = 0;
+ int herbivore_modifier = 0;
+
+ switch (item_class)
+ {
+ case OBJ_FOOD:
+ // apply base sustenance {dlb}:
+ switch (item_type)
+ {
+ case FOOD_MEAT_RATION:
+ case FOOD_ROYAL_JELLY:
+ food_value = 5000;
+ break;
+ case FOOD_BREAD_RATION:
+ food_value = 4400;
+ break;
+ case FOOD_HONEYCOMB:
+ food_value = 2000;
+ break;
+ case FOOD_SNOZZCUMBER: // maybe a nasty side-effect from RD's book?
+ case FOOD_PIZZA:
+ case FOOD_BEEF_JERKY:
+ food_value = 1500;
+ break;
+ case FOOD_CHEESE:
+ case FOOD_SAUSAGE:
+ food_value = 1200;
+ break;
+ case FOOD_ORANGE:
+ case FOOD_BANANA:
+ case FOOD_LEMON:
+ food_value = 1000;
+ break;
+ case FOOD_PEAR:
+ case FOOD_APPLE:
+ case FOOD_APRICOT:
+ food_value = 700;
+ break;
+ case FOOD_CHOKO:
+ case FOOD_RAMBUTAN:
+ case FOOD_LYCHEE:
+ food_value = 600;
+ break;
+ case FOOD_STRAWBERRY:
+ food_value = 200;
+ break;
+ case FOOD_GRAPE:
+ food_value = 100;
+ break;
+ case FOOD_SULTANA:
+ food_value = 70; // will not save you from starvation
+ break;
+ default:
+ break;
+ } // end base sustenance listing {dlb}
+
+ // next, sustenance modifier for carnivores/herbivores {dlb}:
+ // for some reason, sausages do not penalize herbivores {dlb}:
+ switch (item_type)
+ {
+ case FOOD_MEAT_RATION:
+ carnivore_modifier = 500;
+ herbivore_modifier = -1500;
+ break;
+ case FOOD_BEEF_JERKY:
+ carnivore_modifier = 200;
+ herbivore_modifier = -200;
+ break;
+ case FOOD_BREAD_RATION:
+ carnivore_modifier = -1000;
+ herbivore_modifier = 500;
+ break;
+ case FOOD_BANANA:
+ case FOOD_ORANGE:
+ case FOOD_LEMON:
+ carnivore_modifier = -300;
+ herbivore_modifier = 300;
+ break;
+ case FOOD_PEAR:
+ case FOOD_APPLE:
+ case FOOD_APRICOT:
+ case FOOD_CHOKO:
+ case FOOD_SNOZZCUMBER:
+ case FOOD_RAMBUTAN:
+ case FOOD_LYCHEE:
+ carnivore_modifier = -200;
+ herbivore_modifier = 200;
+ break;
+ case FOOD_STRAWBERRY:
+ carnivore_modifier = -50;
+ herbivore_modifier = 50;
+ break;
+ case FOOD_GRAPE:
+ case FOOD_SULTANA:
+ carnivore_modifier = -20;
+ herbivore_modifier = 20;
+ break;
+ default:
+ carnivore_modifier = 0;
+ herbivore_modifier = 0;
+ break;
+ } // end carnivore/herbivore modifier listing {dlb}
+
+ // next, let's take care of messaging {dlb}:
+ if (how_carnivorous > 0 && carnivore_modifier < 0)
+ mpr("Blech - you need meat!");
+ else if (how_herbivorous > 0 && herbivore_modifier < 0)
+ mpr("Blech - you need greens!");
+
+ if (how_herbivorous < 1)
+ {
+ switch (item_type)
+ {
+ case FOOD_MEAT_RATION:
+ mpr("That meat ration really hit the spot!");
+ break;
+ case FOOD_BEEF_JERKY:
+ strcpy(info, "That beef jerky was ");
+ strcat(info, (one_chance_in(4)) ? "jerk-a-riffic"
+ : "delicious");
+ strcat(info, "!");
+ mpr(info);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (how_carnivorous < 1)
+ {
+ switch (item_type)
+ {
+ case FOOD_BREAD_RATION:
+ mpr("That bread ration really hit the spot!");
+ break;
+ case FOOD_PEAR:
+ case FOOD_APPLE:
+ case FOOD_APRICOT:
+ strcpy(info, "Mmmm... Yummy ");
+ strcat(info, (item_type == FOOD_APPLE) ? "apple." :
+ (item_type == FOOD_PEAR) ? "pear." :
+ (item_type == FOOD_APRICOT) ? "apricot."
+ : "fruit.");
+ mpr(info);
+ break;
+ case FOOD_CHOKO:
+ mpr("That choko was very bland.");
+ break;
+ case FOOD_SNOZZCUMBER:
+ mpr("That snozzcumber tasted truly putrid!");
+ break;
+ case FOOD_ORANGE:
+ strcpy(info, "That orange was delicious!");
+ if (one_chance_in(8))
+ strcat(info, " Even the peel tasted good!");
+ mpr(info);
+ break;
+ case FOOD_BANANA:
+ strcpy(info, "That banana was delicious!");
+ if (one_chance_in(8))
+ strcat(info, " Even the peel tasted good!");
+ mpr(info);
+ break;
+ case FOOD_STRAWBERRY:
+ mpr("That strawberry was delicious!");
+ break;
+ case FOOD_RAMBUTAN:
+ mpr("That rambutan was delicious!");
+ break;
+ case FOOD_LEMON:
+ mpr("That lemon was rather sour... But delicious nonetheless!");
+ break;
+ case FOOD_GRAPE:
+ mpr("That grape was delicious!");
+ break;
+ case FOOD_SULTANA:
+ mpr("That sultana was delicious! (but very small)");
+ break;
+ case FOOD_LYCHEE:
+ mpr("That lychee was delicious!");
+ break;
+ default:
+ break;
+ }
+ }
+
+ switch (item_type)
+ {
+ case FOOD_HONEYCOMB:
+ mpr("That honeycomb was delicious.");
+ break;
+ case FOOD_ROYAL_JELLY:
+ mpr("That royal jelly was delicious!");
+ restore_stat(STAT_ALL, false);
+ break;
+ case FOOD_PIZZA:
+ strcpy(info, "Mmm... ");
+
+ if (SysEnv.crawl_pizza && !one_chance_in(3))
+ strcat(info, SysEnv.crawl_pizza);
+ else
+ {
+ temp_rand = random2(9);
+
+ strcat(info, (temp_rand == 0) ? "Ham and pineapple." :
+ (temp_rand == 1) ? "Extra thick crust." :
+ (temp_rand == 2) ? "Vegetable." :
+ (temp_rand == 3) ? "Pepperoni." :
+ (temp_rand == 4) ? "Yeuchh - Anchovies!" :
+ (temp_rand == 5) ? "Cheesy." :
+ (temp_rand == 6) ? "Supreme." :
+ (temp_rand == 7) ? "Super Supreme!"
+ : "Chicken.");
+ }
+ mpr(info);
+ break;
+ case FOOD_CHEESE:
+ strcpy(info, "Mmm... ");
+ temp_rand = random2(9);
+
+ strcat(info, (temp_rand == 0) ? "Cheddar" :
+ (temp_rand == 1) ? "Edam" :
+ (temp_rand == 2) ? "Wensleydale" :
+ (temp_rand == 3) ? "Camembert" :
+ (temp_rand == 4) ? "Goat cheese" :
+ (temp_rand == 5) ? "Fruit cheese" :
+ (temp_rand == 6) ? "Mozzarella" :
+ (temp_rand == 7) ? "Sheep cheese"
+ : "Yak cheese");
+
+ strcat(info, ".");
+ mpr(info);
+ break;
+ case FOOD_SAUSAGE:
+ mpr("That sausage was delicious!");
+ break;
+ default:
+ break;
+ }
+
+ // finally, modify player's hunger level {dlb}:
+ if (carnivore_modifier && how_carnivorous > 0)
+ food_value += (carnivore_modifier * how_carnivorous);
+
+ if (herbivore_modifier && how_herbivorous > 0)
+ food_value += (herbivore_modifier * how_herbivorous);
+
+ if (food_value > 0)
+ {
+ if (item_type == FOOD_MEAT_RATION || item_type == FOOD_BREAD_RATION)
+ start_delay( DELAY_EAT, 3 );
+ else
+ start_delay( DELAY_EAT, 1 );
+
+ lessen_hunger( food_value, true );
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return;
+} // end eating()
+
+static bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg)
+{
+ bool survey_says = false;
+
+ bool ur_carnivorous = (you.species == SP_GHOUL
+ || you.species == SP_KOBOLD
+ || you.mutation[MUT_CARNIVOROUS] == 3);
+
+ bool ur_herbivorous = (you.mutation[MUT_HERBIVOROUS] > 1);
+
+ // ur_chunkslover not defined in terms of ur_carnivorous because
+ // a player could be one and not the other IMHO - 13mar2000 {dlb}
+ bool ur_chunkslover = (you.hunger_state <= HS_HUNGRY
+ || wearing_amulet(AMU_THE_GOURMAND)
+ || you.species == SP_KOBOLD
+ || you.species == SP_OGRE
+ || you.species == SP_TROLL
+ || you.species == SP_GHOUL
+ || you.mutation[MUT_CARNIVOROUS]);
+
+ switch (what_isit)
+ {
+ case OBJ_FOOD:
+ switch (kindof_thing)
+ {
+ case FOOD_BREAD_RATION:
+ case FOOD_PEAR:
+ case FOOD_APPLE:
+ case FOOD_CHOKO:
+ case FOOD_SNOZZCUMBER:
+ case FOOD_PIZZA:
+ case FOOD_APRICOT:
+ case FOOD_ORANGE:
+ case FOOD_BANANA:
+ case FOOD_STRAWBERRY:
+ case FOOD_RAMBUTAN:
+ case FOOD_LEMON:
+ case FOOD_GRAPE:
+ case FOOD_SULTANA:
+ case FOOD_LYCHEE:
+ if (ur_carnivorous)
+ {
+ survey_says = false;
+ if (!suppress_msg)
+ mpr("Sorry, you're a carnivore.");
+ }
+ else
+ survey_says = true;
+ break;
+
+ case FOOD_CHUNK:
+ if (ur_herbivorous)
+ {
+ survey_says = false;
+ if (!suppress_msg)
+ mpr("You can't eat raw meat!");
+ }
+ else if (!ur_chunkslover)
+ {
+ survey_says = false;
+ if (!suppress_msg)
+ mpr("You aren't quite hungry enough to eat that!");
+ }
+ else
+ survey_says = true;
+ break;
+
+ default:
+ return (true);
+ }
+ break;
+
+ // other object types are set to return false for now until
+ // someone wants to recode the eating code to permit consumption
+ // of things other than just food -- corpses first, then more
+ // exotic stuff later would be good to explore - 13mar2000 {dlb}
+ case OBJ_CORPSES:
+ default:
+ return (false);
+ }
+
+ return (survey_says);
+} // end can_ingest()
+
+// see if you can follow along here -- except for the Amulet of the Gourmand
+// addition (long missing and requested), what follows is an expansion of how
+// chunks were handled in the codebase up to this date -- I have never really
+// understood why liches are hungry and not true undead beings ... {dlb}:
+static int determine_chunk_effect(int which_chunk_type, bool rotten_chunk)
+{
+ int poison_resistance_level = player_res_poison();
+ int this_chunk_effect = which_chunk_type;
+
+ // determine the initial effect of eating a particular chunk {dlb}:
+ switch (this_chunk_effect)
+ {
+ case CE_HCL:
+ case CE_MUTAGEN_RANDOM:
+ if (you.species == SP_GHOUL
+ || you.attribute[ATTR_TRANSFORMATION] == TRAN_LICH)
+ {
+ this_chunk_effect = CE_CLEAN;
+ }
+ break;
+
+ case CE_POISONOUS:
+ if (you.species == SP_GHOUL
+ || you.attribute[ATTR_TRANSFORMATION] == TRAN_LICH
+ || poison_resistance_level > 0)
+ {
+ this_chunk_effect = CE_CLEAN;
+ }
+ break;
+
+ case CE_CONTAMINATED:
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_LICH)
+ this_chunk_effect = CE_CLEAN;
+ else
+ {
+ switch (you.species)
+ {
+ case SP_GHOUL:
+ // Doing this here causes a odd message later. -- bwr
+ // this_chunk_effect = CE_ROTTEN;
+ break;
+
+ case SP_KOBOLD:
+ case SP_TROLL:
+ if (!one_chance_in(45))
+ this_chunk_effect = CE_CLEAN;
+ break;
+
+ case SP_HILL_ORC:
+ case SP_OGRE:
+ if (!one_chance_in(15))
+ this_chunk_effect = CE_CLEAN;
+ break;
+
+ default:
+ if (!one_chance_in(3))
+ this_chunk_effect = CE_CLEAN;
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // determine effects of rotting on base chunk effect {dlb}:
+ if (rotten_chunk)
+ {
+ switch (this_chunk_effect)
+ {
+ case CE_CLEAN:
+ case CE_CONTAMINATED:
+ this_chunk_effect = CE_ROTTEN;
+ break;
+ case CE_MUTAGEN_RANDOM:
+ this_chunk_effect = CE_MUTAGEN_BAD;
+ break;
+ default:
+ break;
+ }
+ }
+
+ // one last chance for some species to safely eat rotten food {dlb}:
+ if (this_chunk_effect == CE_ROTTEN)
+ {
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_LICH)
+ this_chunk_effect = CE_CLEAN;
+ else
+ {
+ switch (you.species)
+ {
+ case SP_KOBOLD:
+ case SP_TROLL:
+ if (!one_chance_in(15))
+ this_chunk_effect = CE_CLEAN;
+ break;
+ case SP_HILL_ORC:
+ case SP_OGRE:
+ if (!one_chance_in(5))
+ this_chunk_effect = CE_CLEAN;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ // the amulet of the gourmad will permit consumption of rotting meat as
+ // though it were "clean" meat - ghouls can expect the reverse, as they
+ // prize rotten meat ... yum! {dlb}:
+ if (wearing_amulet(AMU_THE_GOURMAND))
+ {
+ if (you.species == SP_GHOUL)
+ {
+ if (this_chunk_effect == CE_CLEAN)
+ this_chunk_effect = CE_ROTTEN;
+ }
+ else
+ {
+ if (this_chunk_effect == CE_ROTTEN)
+ this_chunk_effect = CE_CLEAN;
+ }
+ }
+
+ return (this_chunk_effect);
+} // end determine_chunk_effect()
diff --git a/trunk/source/food.h b/trunk/source/food.h
new file mode 100644
index 0000000000..49b072a54f
--- /dev/null
+++ b/trunk/source/food.h
@@ -0,0 +1,57 @@
+/*
+ * File: food.cc
+ * Summary: Functions for eating and butchering.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef FOOD_H
+#define FOOD_H
+
+
+// last updated 19jun2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+bool butchery(void);
+
+
+// last updated 19jun2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void eat_food(void);
+
+
+// last updated 19jun2000 {dlb}
+/* ***********************************************************************
+ * called from: abl-show - acr - fight - food - spell
+ * *********************************************************************** */
+void make_hungry(int hunger_amount, bool suppress_msg);
+
+
+// last updated 19jun2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - fight - food - it_use2 - item_use
+ * *********************************************************************** */
+void lessen_hunger(int statiated_amount, bool suppress_msg);
+
+
+// last updated 19jun2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - decks - food - religion
+ * *********************************************************************** */
+void set_hunger(int new_hunger_level, bool suppress_msg);
+
+
+// last updated 10sept2000 {bwr}
+/* ***********************************************************************
+ * called from: delay.cc
+ * *********************************************************************** */
+void weapon_switch( int targ );
+
+#endif
diff --git a/trunk/source/hiscores.cc b/trunk/source/hiscores.cc
new file mode 100644
index 0000000000..cbdab9ed2b
--- /dev/null
+++ b/trunk/source/hiscores.cc
@@ -0,0 +1,1824 @@
+/*
+ * File: highscore.cc
+ * Summary: deal with reading and writing of highscore file
+ * Written by: Gordon Lipford
+ *
+ * Change History (most recent first):
+ *
+ * <1> 16feb2001 gdl Created
+ */
+
+/*
+ * ----------- MODIFYING THE PRINTED SCORE FORMAT ---------------------
+ * Do this at your leisure. Change hiscores_format_single() as much
+ * as you like.
+ *
+ *
+ * ----------- IF YOU MODIFY THE INTERNAL SCOREFILE FORMAT ------------
+ * .. as defined by the struct 'scorefile_entry' ..
+ * You MUST change hs_copy(), hs_parse_numeric(), hs_parse_string(),
+ * and hs_write(). It's also a really good idea to change the
+ * version numbers assigned in ouch() so that Crawl can tell the
+ * difference between your new entry and previous versions.
+ *
+ *
+ *
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "AppHdr.h"
+#include "externs.h"
+
+#include "hiscores.h"
+#include "itemname.h"
+#include "mon-util.h"
+#include "player.h"
+#include "religion.h"
+#include "stuff.h"
+#include "tags.h"
+#include "view.h"
+
+#include "skills2.h"
+
+#ifdef MULTIUSER
+ // includes to get passwd file access:
+ #include <pwd.h>
+ #include <sys/types.h>
+#endif
+
+// enough memory allocated to snarf in the scorefile entries
+static struct scorefile_entry hs_list[SCORE_FILE_ENTRIES];
+
+// hackish: scorefile position of newest entry. Will be highlit during
+// highscore printing (always -1 when run from command line).
+static int newest_entry = -1;
+
+static FILE *hs_open(const char *mode);
+static void hs_close(FILE *handle, const char *mode);
+static bool hs_read(FILE *scores, struct scorefile_entry &dest);
+static void hs_parse_numeric(char *inbuf, struct scorefile_entry &dest);
+static void hs_parse_string(char *inbuf, struct scorefile_entry &dest);
+static void hs_copy(struct scorefile_entry &dest, struct scorefile_entry &src);
+static void hs_write(FILE *scores, struct scorefile_entry &entry);
+static void hs_nextstring(char *&inbuf, char *dest);
+static int hs_nextint(char *&inbuf);
+static long hs_nextlong(char *&inbuf);
+
+// functions dealing with old scorefile entries
+static void hs_parse_generic_1(char *&inbuf, char *outbuf, const char *stopvalues);
+static void hs_parse_generic_2(char *&inbuf, char *outbuf, const char *continuevalues);
+static void hs_stripblanks(char *buf);
+static void hs_search_death(char *inbuf, struct scorefile_entry &se);
+static void hs_search_where(char *inbuf, struct scorefile_entry &se);
+
+// file locking stuff
+#ifdef USE_FILE_LOCKING
+static bool lock_file_handle( FILE *handle, int type );
+static bool unlock_file_handle( FILE *handle );
+#endif // USE_FILE_LOCKING
+
+void hiscores_new_entry( struct scorefile_entry &ne )
+{
+ FILE *scores;
+ int i, total_entries;
+ bool inserted = false;
+
+ // open highscore file (reading) -- note that NULL is not fatal!
+ scores = hs_open("r");
+
+ // read highscore file, inserting new entry at appropriate point,
+ for (i = 0; i < SCORE_FILE_ENTRIES; i++)
+ {
+ if (hs_read(scores, hs_list[i]) == false)
+ break;
+
+ // compare points..
+ if (ne.points >= hs_list[i].points && inserted == false)
+ {
+ newest_entry = i; // for later printing
+ inserted = true;
+ // copy read entry to i+1th position
+ // Fixed a nasty overflow bug here -- Sharp
+ if (i+1 < SCORE_FILE_ENTRIES)
+ {
+ hs_copy(hs_list[i+1], hs_list[i]);
+ hs_copy(hs_list[i], ne);
+ i++;
+ } else {
+ // copy new entry to current position
+ hs_copy(hs_list[i], ne);
+ }
+ }
+ }
+
+ // special case: lowest score, with room
+ if (!inserted && i < SCORE_FILE_ENTRIES)
+ {
+ newest_entry = i;
+ inserted = true;
+ // copy new entry
+ hs_copy(hs_list[i], ne);
+ i++;
+ }
+
+ total_entries = i;
+
+ // close so we can re-open for writing
+ hs_close(scores,"r");
+
+ // open highscore file (writing) -- NULL *is* fatal here.
+ scores = hs_open("w");
+ if (scores == NULL)
+ {
+ perror("Entry not added - failure opening score file for writing.");
+ return;
+ }
+
+ // write scorefile entries.
+ for (i = 0; i < total_entries; i++)
+ {
+ hs_write(scores, hs_list[i]);
+ }
+
+ // close scorefile.
+ hs_close(scores, "w");
+}
+
+void hiscores_print_list( int display_count, int format )
+{
+ FILE *scores;
+ int i, total_entries;
+ bool use_printf = (Options.sc_entries > 0);
+
+ if (display_count <= 0)
+ display_count = SCORE_FILE_ENTRIES;
+
+ // open highscore file (reading)
+ scores = hs_open("r");
+ if (scores == NULL)
+ {
+ // will only happen from command line
+ puts( "No high scores." );
+ return;
+ }
+
+ // read highscore file
+ for (i = 0; i < SCORE_FILE_ENTRIES; i++)
+ {
+ if (hs_read( scores, hs_list[i] ) == false)
+ break;
+ }
+ total_entries = i;
+
+ // close off
+ hs_close( scores, "r" );
+
+ if (!use_printf)
+ textcolor(LIGHTGREY);
+
+ int start = (newest_entry > 10) ? newest_entry - 10: 0;
+
+ if (start + display_count > total_entries)
+ start = total_entries - display_count;
+
+ if (start < 0)
+ start = 0;
+
+ const int finish = start + display_count;
+
+ for (i = start; i < finish && i < total_entries; i++)
+ {
+ // check for recently added entry
+ if (i == newest_entry && !use_printf)
+ textcolor(YELLOW);
+
+ // print position (tracked implicitly by order score file)
+ snprintf( info, INFO_SIZE, "%3d.", i + 1 );
+ if (use_printf)
+ printf(info);
+ else
+ cprintf(info);
+
+ // format the entry
+ if (format == SCORE_TERSE)
+ {
+ hiscores_format_single( info, hs_list[i] );
+ // truncate if we want short format
+ info[75] = '\0';
+ }
+ else
+ {
+ hiscores_format_single_long( info, hs_list[i],
+ (format == SCORE_VERBOSE) );
+ }
+
+ // print entry
+ strcat(info, EOL);
+ if(use_printf)
+ printf(info);
+ else
+ cprintf(info);
+
+ if (i == newest_entry && !use_printf)
+ textcolor(LIGHTGREY);
+ }
+}
+
+// Trying to supply an appropriate verb for the attack type. -- bwr
+static const char *const range_type_verb( const char *const aux )
+{
+ if (strncmp( aux, "Shot ", 5 ) == 0) // launched
+ return ("shot");
+ else if (aux[0] == '\0' // unknown
+ || strncmp( aux, "Hit ", 4 ) == 0 // thrown
+ || strncmp( aux, "volley ", 7 ) == 0) // manticore spikes
+ {
+ return ("hit from afar");
+ }
+
+ return ("blasted"); // spells, wands
+}
+
+void hiscores_format_single(char *buf, struct scorefile_entry &se)
+{
+ char scratch[100];
+
+ // Now that we have a long format, I'm starting to make this
+ // more terse, in hopes that it will better fit. -- bwr
+
+ // race_class_name overrides race & class
+ if (se.race_class_name[0] == '\0')
+ {
+ snprintf( scratch, sizeof(scratch), "%s%s",
+ get_species_abbrev( se.race ), get_class_abbrev( se.cls ) );
+ }
+ else
+ {
+ strcpy( scratch, se.race_class_name );
+ }
+
+ se.name[10]='\0';
+ sprintf( buf, "%8ld %-10s %s-%02d%s", se.points, se.name,
+ scratch, se.lvl, (se.wiz_mode == 1) ? "W" : "" );
+
+ // get monster type & number, if applicable
+ int mon_type = se.death_source;
+ int mon_number = se.mon_num;
+
+ // remember -- we have 36 characters (not including initial space):
+ switch (se.death_type)
+ {
+ case KILLED_BY_MONSTER:
+ strcat( buf, " slain by " );
+
+ // if death_source_name is non-null, override lookup (names might have
+ // changed!)
+ if (se.death_source_name[0] != '\0')
+ strcat( buf, se.death_source_name );
+ else
+ strcat( buf, monam( mon_number, mon_type, true, DESC_PLAIN ) );
+
+ break;
+
+ case KILLED_BY_POISON:
+ //if (dam == -9999) strcat(buf, "an overload of ");
+ strcat( buf, " succumbed to poison" );
+ break;
+
+ case KILLED_BY_CLOUD:
+ if (se.auxkilldata[0] == '\0')
+ strcat( buf, " engulfed by a cloud" );
+ else
+ {
+ const int len = strlen( se.auxkilldata );
+
+ // Squeeze out "a cloud of" if required. -- bwr
+ snprintf( scratch, sizeof(scratch), " engulfed by %s%s",
+ (len < 15) ? "a cloud of " : "",
+ se.auxkilldata );
+
+ strcat( buf, scratch );
+ }
+ break;
+
+ case KILLED_BY_BEAM:
+ // keeping this short to leave room for the deep elf spellcasters:
+ snprintf( scratch, sizeof(scratch), " %s by ",
+ range_type_verb( se.auxkilldata ) );
+ strcat( buf, scratch );
+
+ // if death_source_name is non-null, override this
+ if (se.death_source_name[0] != '\0')
+ strcat( buf, se.death_source_name );
+ else
+ strcat( buf, monam( mon_number, mon_type, true, DESC_PLAIN ) );
+ break;
+
+/*
+ case KILLED_BY_DEATHS_DOOR:
+ // death's door running out - NOTE: This is no longer fatal
+ strcat(buf, " ran out of time");
+ break;
+*/
+
+ case KILLED_BY_LAVA:
+ if (se.race == SP_MUMMY)
+ strcat( buf, " turned to ash by lava" );
+ else
+ strcat( buf, " took a swim in lava" );
+ break;
+
+ case KILLED_BY_WATER:
+ if (se.race == SP_MUMMY)
+ strcat( buf, " soaked and fell apart" );
+ else
+ strcat( buf, " drowned" );
+ break;
+
+ // these three are probably only possible if you wear a ring
+ // of >= +3 ability, get drained to 3, then take it off, or have a very
+ // low abil and wear a -ve ring. or, as of 2.7x, mutations can cause this
+ // Don't forget decks of cards (they have some nasty code for this) -- bwr
+ case KILLED_BY_STUPIDITY:
+ strcat( buf, " died of stupidity" );
+ break;
+
+ case KILLED_BY_WEAKNESS:
+ strcat( buf, " became too weak to continue" );
+ break;
+
+ case KILLED_BY_CLUMSINESS:
+ strcat( buf, " slipped on a banana peel" );
+ break;
+
+ case KILLED_BY_TRAP:
+ snprintf( scratch, sizeof(scratch), " triggered a%s trap",
+ (se.auxkilldata[0] != '\0') ? se.auxkilldata : "" );
+ strcat( buf, scratch );
+ break;
+
+ case KILLED_BY_LEAVING:
+ strcat( buf, " got out of the dungeon alive" );
+ break;
+
+ case KILLED_BY_WINNING:
+ strcat( buf, " escaped with the Orb!" );
+ break;
+
+ case KILLED_BY_QUITTING:
+ strcat( buf, " quit the game" );
+ break;
+
+ case KILLED_BY_DRAINING:
+ strcat( buf, " drained of all life" );
+ break;
+
+ case KILLED_BY_STARVATION:
+ strcat( buf, " starved to death" );
+ break;
+
+ case KILLED_BY_FREEZING:
+ strcat( buf, " froze to death" );
+ break;
+
+ case KILLED_BY_BURNING: // only sticky flame
+ strcat( buf, " burnt to a crisp" );
+ break;
+
+ case KILLED_BY_WILD_MAGIC:
+ if (se.auxkilldata[0] == '\0')
+ strcat( buf, " killed by wild magic" );
+ else
+ {
+ const bool need_by = (strncmp( se.auxkilldata, "by ", 3 ) == 0);
+ const int len = strlen( se.auxkilldata );
+
+ // Squeeze out "killed" if we're getting a bit long. -- bwr
+ snprintf( scratch, sizeof(scratch), " %s%s%s",
+ (len + 3 * (need_by) < 30) ? "killed" : "",
+ (need_by) ? "by " : "",
+ se.auxkilldata );
+
+ strcat( buf, scratch );
+ }
+ break;
+
+ case KILLED_BY_XOM: // only used for old Xom kills
+ strcat( buf, " killed for Xom's enjoyment" );
+ break;
+
+ case KILLED_BY_STATUE:
+ strcat( buf, " killed by a statue" );
+ break;
+
+ case KILLED_BY_ROTTING:
+ strcat( buf, " rotted away" );
+ break;
+
+ case KILLED_BY_TARGETTING:
+ strcat( buf, " killed by bad targeting" );
+ break;
+
+ case KILLED_BY_SPORE:
+ strcat( buf, " killed by an exploding spore" );
+ break;
+
+ case KILLED_BY_TSO_SMITING:
+ strcat( buf, " smote by The Shining One" );
+ break;
+
+ case KILLED_BY_PETRIFICATION:
+ strcat( buf, " turned to stone" );
+ break;
+
+ case KILLED_BY_SHUGGOTH:
+ strcat( buf, " eviscerated by a hatching shuggoth" );
+ break;
+
+ case KILLED_BY_SOMETHING:
+ strcat( buf, " died" );
+ break;
+
+ case KILLED_BY_FALLING_DOWN_STAIRS:
+ strcat( buf, " fell down a flight of stairs" );
+ break;
+
+ case KILLED_BY_ACID:
+ strcat( buf, " splashed by acid" );
+ break;
+
+ default:
+ strcat( buf, " nibbled to death by software bugs" );
+ break;
+ } // end switch
+
+ if (se.death_type != KILLED_BY_LEAVING && se.death_type != KILLED_BY_WINNING)
+ {
+ if (se.level_type == LEVEL_ABYSS)
+ {
+ strcat(buf, " (Abyss)");
+ return;
+ }
+ else if (se.level_type == LEVEL_PANDEMONIUM)
+ {
+ strcat(buf, " (Pan)");
+ return;
+ }
+ else if (se.level_type == LEVEL_LABYRINTH)
+ {
+ strcat(buf, " (Lab)");
+ return;
+ }
+ else if (se.branch == BRANCH_VESTIBULE_OF_HELL)
+ {
+ strcat(buf, " (Hell)"); // Gate? Vest?
+ return;
+ }
+ else if (se.branch == BRANCH_HALL_OF_BLADES)
+ {
+ strcat(buf, " (Blade)");
+ return;
+ }
+ else if (se.branch == BRANCH_ECUMENICAL_TEMPLE)
+ {
+ strcat(buf, " (Temple)");
+ return;
+ }
+
+ snprintf( scratch, sizeof(scratch), " (%s%d)",
+ (se.branch == BRANCH_DIS) ? "Dis " :
+ (se.branch == BRANCH_GEHENNA) ? "Geh " :
+ (se.branch == BRANCH_COCYTUS) ? "Coc " :
+ (se.branch == BRANCH_TARTARUS) ? "Tar " :
+ (se.branch == BRANCH_ORCISH_MINES) ? "Orc " :
+ (se.branch == BRANCH_HIVE) ? "Hive " :
+ (se.branch == BRANCH_LAIR) ? "Lair " :
+ (se.branch == BRANCH_SLIME_PITS) ? "Slime " :
+ (se.branch == BRANCH_VAULTS) ? "Vault " :
+ (se.branch == BRANCH_CRYPT) ? "Crypt " :
+ (se.branch == BRANCH_HALL_OF_ZOT) ? "Zot " :
+ (se.branch == BRANCH_SNAKE_PIT) ? "Snake " :
+ (se.branch == BRANCH_ELVEN_HALLS) ? "Elf " :
+ (se.branch == BRANCH_TOMB) ? "Tomb " :
+ (se.branch == BRANCH_SWAMP) ? "Swamp " : "DLv ",
+ se.dlvl );
+
+ strcat( buf, scratch );
+ } // endif - killed by winning
+
+ return;
+}
+
+static bool hiscore_same_day( time_t t1, time_t t2 )
+{
+ struct tm *d1 = localtime( &t1 );
+ const int year = d1->tm_year;
+ const int mon = d1->tm_mon;
+ const int day = d1->tm_mday;
+
+ struct tm *d2 = localtime( &t2 );
+
+ return (d2->tm_mday == day && d2->tm_mon == mon && d2->tm_year == year);
+}
+
+static void hiscore_date_string( time_t time, char buff[INFO_SIZE] )
+{
+ struct tm *date = localtime( &time );
+
+ const char *mons[12] = { "Jan", "Feb", "Mar", "Apr", "May", "June",
+ "July", "Aug", "Sept", "Oct", "Nov", "Dec" };
+
+ snprintf( buff, INFO_SIZE, "%s %d, %d", mons[date->tm_mon],
+ date->tm_mday, date->tm_year + 1900 );
+}
+
+static void hiscore_newline( char *buf, int &line_count )
+{
+ strncat( buf, EOL " ", HIGHSCORE_SIZE );
+ line_count++;
+}
+
+int hiscores_format_single_long( char *buf, struct scorefile_entry &se,
+ bool verbose )
+{
+ char scratch[INFO_SIZE];
+ int line_count = 1;
+
+ // race_class_name could/used to override race & class
+ // strcpy(scratch, se.race_class_name);
+
+ // Please excuse the following bit of mess in the name of flavour ;)
+ if (verbose)
+ {
+ strncpy( scratch, skill_title( se.best_skill, se.best_skill_lvl,
+ se.race, se.str, se.dex, se.god ),
+ INFO_SIZE );
+
+ snprintf( buf, HIGHSCORE_SIZE, "%8ld %s the %s (level %d",
+ se.points, se.name, scratch, se.lvl );
+
+ }
+ else
+ {
+ snprintf( buf, HIGHSCORE_SIZE, "%8ld %s the %s %s (level %d",
+ se.points, se.name, species_name(se.race, se.lvl),
+ get_class_name(se.cls), se.lvl );
+ }
+
+ if (se.final_max_max_hp > 0) // as the other two may be negative
+ {
+ snprintf( scratch, INFO_SIZE, ", %d/%d", se.final_hp, se.final_max_hp );
+ strncat( buf, scratch, HIGHSCORE_SIZE );
+
+ if (se.final_max_hp < se.final_max_max_hp)
+ {
+ snprintf( scratch, INFO_SIZE, " (%d)", se.final_max_max_hp );
+ strncat( buf, scratch, HIGHSCORE_SIZE );
+ }
+
+ strncat( buf, " HPs", HIGHSCORE_SIZE );
+ }
+
+ strncat( buf, ((se.wiz_mode) ? ") *WIZ*" : ")"), HIGHSCORE_SIZE );
+ hiscore_newline( buf, line_count );
+
+ if (verbose)
+ {
+ const char *const race = species_name( se.race, se.lvl );
+
+ snprintf( scratch, INFO_SIZE, "Began as a%s %s %s",
+ is_vowel(race[0]) ? "n" : "", race, get_class_name(se.cls) );
+ strncat( buf, scratch, HIGHSCORE_SIZE );
+
+ if (se.birth_time > 0)
+ {
+ strncat( buf, " on ", HIGHSCORE_SIZE );
+ hiscore_date_string( se.birth_time, scratch );
+ strncat( buf, scratch, HIGHSCORE_SIZE );
+ }
+
+ strncat( buf, "." , HIGHSCORE_SIZE );
+ hiscore_newline( buf, line_count );
+
+ if (se.race != SP_DEMIGOD && se.god != -1)
+ {
+ if (se.god == GOD_XOM)
+ {
+ snprintf( scratch, INFO_SIZE, "Was a %sPlaything of Xom.",
+ (se.lvl >= 20) ? "Favourite " : "" );
+
+ strncat( buf, scratch, HIGHSCORE_SIZE );
+ hiscore_newline( buf, line_count );
+ }
+ else if (se.god != GOD_NO_GOD)
+ {
+ // Not exactly the same as the religon screen, but
+ // good enough to fill this slot for now.
+ snprintf( scratch, INFO_SIZE, "Was %s of %s%s",
+ (se.piety > 160) ? "the Champion" :
+ (se.piety >= 120) ? "a High Priest" :
+ (se.piety >= 100) ? "an Elder" :
+ (se.piety >= 75) ? "a Priest" :
+ (se.piety >= 50) ? "a Believer" :
+ (se.piety >= 30) ? "a Follower"
+ : "an Initiate",
+ god_name( se.god ),
+ (se.penance > 0) ? " (penitent)." : "." );
+
+ strncat( buf, scratch, HIGHSCORE_SIZE );
+ hiscore_newline( buf, line_count );
+ }
+ }
+ }
+
+ // get monster type & number, if applicable
+ int mon_type = se.death_source;
+ int mon_number = se.mon_num;
+
+ bool needs_beam_cause_line = false;
+ bool needs_called_by_monster_line = false;
+ bool needs_damage = false;
+
+ switch (se.death_type)
+ {
+ case KILLED_BY_MONSTER:
+ // GDL: here's an example of using final_hp. Verbiage could be better.
+ // bwr: changed "blasted" since this is for melee
+ snprintf( scratch, INFO_SIZE, "%s %s",
+ (se.final_hp > -6) ? "Slain by" :
+ (se.final_hp > -14) ? "Mangled by" :
+ (se.final_hp > -22) ? "Demolished by"
+ : "Annihilated by",
+
+ (se.death_source_name[0] != '\0')
+ ? se.death_source_name
+ : monam( mon_number, mon_type, true, DESC_PLAIN ) );
+
+ strncat( buf, scratch, HIGHSCORE_SIZE );
+
+ // put the damage on the weapon line if there is one
+ if (se.auxkilldata[0] == '\0')
+ needs_damage = true;
+ break;
+
+ case KILLED_BY_POISON:
+ //if (dam == -9999) strcat(buf, "an overload of ");
+ strcat( buf, "Succumbed to poison" );
+ break;
+
+ case KILLED_BY_CLOUD:
+ if (se.auxkilldata[0] == '\0')
+ strcat( buf, "Engulfed by a cloud" );
+ else
+ {
+ snprintf( scratch, sizeof(scratch), "Engulfed by a cloud of %s",
+ se.auxkilldata );
+ strcat( buf, scratch );
+ }
+ needs_damage = true;
+ break;
+
+ case KILLED_BY_BEAM:
+ if (isupper( se.auxkilldata[0] )) // already made (ie shot arrows)
+ {
+ strcat( buf, se.auxkilldata );
+ needs_damage = true;
+ }
+ else if (verbose && strncmp( se.auxkilldata, "by ", 3 ) == 0)
+ {
+ // "by" is used for priest attacks where the effect is indirect
+ // in verbose format we have another line for the monster
+ needs_called_by_monster_line = true;
+ snprintf( scratch, sizeof(scratch), "Killed %s", se.auxkilldata );
+ strncat( buf, scratch, HIGHSCORE_SIZE );
+ }
+ else
+ {
+ // Note: This is also used for the "by" cases in non-verbose
+ // mode since listing the monster is more imporatant.
+ strcat( buf, "Killed from afar by " );
+
+ // if death_source_name is non-null, override this
+ if (se.death_source_name[0] != '\0')
+ strcat(buf, se.death_source_name);
+ else
+ strcat(buf, monam( mon_number, mon_type, true, DESC_PLAIN ));
+
+ if (se.auxkilldata[0] != '\0')
+ needs_beam_cause_line = true;
+ }
+ break;
+
+ case KILLED_BY_LAVA:
+ if (se.race == SP_MUMMY)
+ strcat( buf, "Turned to ash by lava" );
+ else
+ strcat( buf, "Took a swim in molten lava" );
+ break;
+
+ case KILLED_BY_WATER:
+ if (se.race == SP_MUMMY)
+ strcat( buf, "Soaked and fell apart" );
+ else
+ strcat( buf, "Drowned" );
+ break;
+
+ case KILLED_BY_STUPIDITY:
+ strcat( buf, "Forgot to breathe" );
+ break;
+
+ case KILLED_BY_WEAKNESS:
+ strcat( buf, "Collapsed under their own weight" );
+ break;
+
+ case KILLED_BY_CLUMSINESS:
+ strcat( buf, "Slipped on a banana peel" );
+ break;
+
+ case KILLED_BY_TRAP:
+ snprintf( scratch, sizeof(scratch), "Killed by triggering a%s trap",
+ (se.auxkilldata[0] != '\0') ? se.auxkilldata : "" );
+ strcat( buf, scratch );
+ needs_damage = true;
+ break;
+
+ case KILLED_BY_LEAVING:
+ if (se.num_runes > 0)
+ strcat( buf, "Got out of the dungeon" );
+ else
+ strcat( buf, "Got out of the dungeon alive!" );
+ break;
+
+ case KILLED_BY_WINNING:
+ strcat( buf, "Escaped with the Orb" );
+ if (se.num_runes < 1)
+ strcat( buf, "!" );
+ break;
+
+ case KILLED_BY_QUITTING:
+ strcat( buf, "Quit the game" );
+ break;
+
+ case KILLED_BY_DRAINING:
+ strcat( buf, "Was drained of all life" );
+ break;
+
+ case KILLED_BY_STARVATION:
+ strcat( buf, "Starved to death" );
+ break;
+
+ case KILLED_BY_FREEZING: // refrigeration spell
+ strcat( buf, "Froze to death" );
+ needs_damage = true;
+ break;
+
+ case KILLED_BY_BURNING: // sticky flame
+ strcat( buf, "Burnt to a crisp" );
+ needs_damage = true;
+ break;
+
+ case KILLED_BY_WILD_MAGIC:
+ if (se.auxkilldata[0] == '\0')
+ strcat( buf, "Killed by wild magic" );
+ else
+ {
+ // A lot of sources for this case... some have "by" already.
+ snprintf( scratch, sizeof(scratch), "Killed %s%s",
+ (strncmp( se.auxkilldata, "by ", 3 ) != 0) ? "by " : "",
+ se.auxkilldata );
+
+ strcat( buf, scratch );
+ }
+
+ needs_damage = true;
+ break;
+
+ case KILLED_BY_XOM: // only used for old Xom kills
+ strcat( buf, "It was good that Xom killed them" );
+ needs_damage = true;
+ break;
+
+ case KILLED_BY_STATUE:
+ strcat( buf, "Killed by a statue" );
+ needs_damage = true;
+ break;
+
+ case KILLED_BY_ROTTING:
+ strcat( buf, "Rotted away" );
+ break;
+
+ case KILLED_BY_TARGETTING:
+ strcat( buf, "Killed themselves with bad targeting" );
+ needs_damage = true;
+ break;
+
+ case KILLED_BY_SPORE:
+ strcat( buf, "Killed by an exploding spore" );
+ needs_damage = true;
+ break;
+
+ case KILLED_BY_TSO_SMITING:
+ strcat( buf, "Smote by The Shining One" );
+ needs_damage = true;
+ break;
+
+ case KILLED_BY_PETRIFICATION:
+ strcat( buf, "Turned to stone" );
+ break;
+
+ case KILLED_BY_SHUGGOTH:
+ strcat( buf, "Eviscerated by a hatching shuggoth" );
+ needs_damage = true;
+ break;
+
+ case KILLED_BY_SOMETHING:
+ strcat( buf, "Died" );
+ break;
+
+ case KILLED_BY_FALLING_DOWN_STAIRS:
+ strcat( buf, "Fell down a flight of stairs" );
+ needs_damage = true;
+ break;
+
+ case KILLED_BY_ACID:
+ strcat( buf, "Splashed by acid" );
+ needs_damage = true;
+ break;
+
+ default:
+ strcat( buf, "Nibbled to death by software bugs" );
+ break;
+ } // end switch
+
+ // TODO: Eventually, get rid of "..." for cases where the text fits.
+ if (verbose)
+ {
+ bool done_damage = false; // paranoia
+
+ if (needs_damage && se.damage > 0)
+ {
+ snprintf( scratch, INFO_SIZE, " (%d damage)", se.damage );
+ strncat( buf, scratch, HIGHSCORE_SIZE );
+ needs_damage = false;
+ done_damage = true;
+ }
+
+ if ((se.death_type == KILLED_BY_LEAVING
+ || se.death_type == KILLED_BY_WINNING)
+ && se.num_runes > 0)
+ {
+ hiscore_newline( buf, line_count );
+
+ snprintf( scratch, INFO_SIZE, "... %s %d rune%s",
+ (se.death_type == KILLED_BY_WINNING) ? "and" : "with",
+ se.num_runes, (se.num_runes > 1) ? "s" : "" );
+ strncat( buf, scratch, HIGHSCORE_SIZE );
+
+ if (se.num_diff_runes > 1)
+ {
+ snprintf( scratch, INFO_SIZE, " (of %d types)",
+ se.num_diff_runes );
+ strncat( buf, scratch, HIGHSCORE_SIZE );
+ }
+
+ if (se.death_time > 0
+ && !hiscore_same_day( se.birth_time, se.death_time ))
+ {
+ strcat( buf, " on " );
+ hiscore_date_string( se.death_time, scratch );
+ strcat( buf, scratch );
+ }
+
+ strcat( buf, "!" );
+ hiscore_newline( buf, line_count );
+ }
+ else if (se.death_type != KILLED_BY_QUITTING)
+ {
+ hiscore_newline( buf, line_count );
+
+ if (se.death_type == KILLED_BY_MONSTER && se.auxkilldata[0])
+ {
+ snprintf(scratch, INFO_SIZE, "... wielding %s", se.auxkilldata);
+ strncat(buf, scratch, HIGHSCORE_SIZE);
+ needs_damage = true;
+ }
+ else if (needs_beam_cause_line)
+ {
+ strcat( buf, (is_vowel( se.auxkilldata[0] )) ? "... with an "
+ : "... with a " );
+ strcat( buf, se.auxkilldata );
+ needs_damage = true;
+ }
+ else if (needs_called_by_monster_line)
+ {
+ snprintf( scratch, sizeof(scratch), "... called down by %s",
+ se.death_source_name );
+ strncat( buf, scratch, HIGHSCORE_SIZE );
+ needs_damage = true;
+ }
+
+ if (needs_damage && !done_damage)
+ {
+ if (se.damage > 0)
+ {
+ snprintf( scratch, INFO_SIZE, " (%d damage)", se.damage );
+ strncat( buf, scratch, HIGHSCORE_SIZE );
+ hiscore_newline( buf, line_count );
+ }
+ }
+ }
+ }
+
+ if (se.death_type == KILLED_BY_LEAVING
+ || se.death_type == KILLED_BY_WINNING)
+ {
+ // TODO: strcat "after reaching level %d"; for LEAVING
+ if (!verbose)
+ {
+ if (se.num_runes > 0)
+ strcat( buf, "!" );
+
+ hiscore_newline( buf, line_count );
+ }
+ }
+ else
+ {
+ if (verbose && se.death_type != KILLED_BY_QUITTING)
+ strcat( buf, "..." );
+
+ if (se.level_type == LEVEL_ABYSS)
+ strcat( buf, " in the Abyss" );
+ else if (se.level_type == LEVEL_PANDEMONIUM)
+ strcat( buf, " in Pandemonium" );
+ else if (se.level_type == LEVEL_LABYRINTH)
+ strcat( buf, " in a labyrinth" );
+ else
+ {
+ switch (se.branch)
+ {
+ case BRANCH_ECUMENICAL_TEMPLE:
+ strcat( buf, " in the Ecumenical Temple" );
+ break;
+ case BRANCH_HALL_OF_BLADES:
+ strcat( buf, " in the Hall of Blades" );
+ break;
+ case BRANCH_VESTIBULE_OF_HELL:
+ strcat( buf, " in the Vestibule" );
+ break;
+
+ case BRANCH_DIS:
+ strcat( buf, " on Dis" );
+ break;
+ case BRANCH_GEHENNA:
+ strcat( buf, " on Gehenna" );
+ break;
+ case BRANCH_COCYTUS:
+ strcat( buf, " on Cocytus" );
+ break;
+ case BRANCH_TARTARUS:
+ strcat( buf, " on Tartarus" );
+ break;
+ case BRANCH_ORCISH_MINES:
+ strcat( buf, " on Orcish Mines" );
+ break;
+ case BRANCH_HIVE:
+ strcat( buf, " on Hive" );
+ break;
+ case BRANCH_LAIR:
+ strcat( buf, " on Lair" );
+ break;
+ case BRANCH_SLIME_PITS:
+ strcat( buf, " on Slime Pits" );
+ break;
+ case BRANCH_VAULTS:
+ strcat( buf, " on Vault" );
+ break;
+ case BRANCH_CRYPT:
+ strcat( buf, " on Crypt" );
+ break;
+ case BRANCH_HALL_OF_ZOT:
+ strcat( buf, " on Hall of Zot" );
+ break;
+ case BRANCH_SNAKE_PIT:
+ strcat( buf, " on Snake Pit" );
+ break;
+ case BRANCH_ELVEN_HALLS:
+ strcat( buf, " on Elven Halls" );
+ break;
+ case BRANCH_TOMB:
+ strcat( buf, " on Tomb" );
+ break;
+ case BRANCH_SWAMP:
+ strcat( buf, " on Swamp" );
+ break;
+ case BRANCH_MAIN_DUNGEON:
+ strcat( buf, " on Dungeon" );
+ break;
+ }
+
+ if (se.branch != BRANCH_VESTIBULE_OF_HELL
+ && se.branch != BRANCH_ECUMENICAL_TEMPLE
+ && se.branch != BRANCH_HALL_OF_BLADES)
+ {
+ snprintf( scratch, sizeof(scratch), " Level %d", se.dlvl );
+ strcat( buf, scratch );
+ }
+ }
+
+ if (verbose && se.death_time
+ && !hiscore_same_day( se.birth_time, se.death_time ))
+ {
+ strcat( buf, " on " );
+ hiscore_date_string( se.death_time, scratch );
+ strcat( buf, scratch );
+ }
+
+ strcat( buf, "." );
+ hiscore_newline( buf, line_count );
+ } // endif - killed by winning
+
+ if (verbose)
+ {
+ if (se.real_time > 0)
+ {
+ char username[80] = "The";
+ char tmp[80];
+
+#ifdef MULTIUSER
+ if (se.uid > 0)
+ {
+ struct passwd *pw_entry = getpwuid( se.uid );
+ strncpy( username, pw_entry->pw_name, sizeof(username) );
+ strncat( username, "'s", sizeof(username) );
+ username[0] = toupper( username[0] );
+ }
+#endif
+
+ make_time_string( se.real_time, tmp, sizeof(tmp) );
+
+ snprintf( scratch, INFO_SIZE, "%s game lasted %s (%ld turns).",
+ username, tmp, se.num_turns );
+
+ strncat( buf, scratch, HIGHSCORE_SIZE );
+ hiscore_newline( buf, line_count );
+ }
+ }
+
+ return (line_count);
+}
+
+// --------------------------------------------------------------------------
+// BEGIN private functions
+// --------------------------------------------------------------------------
+
+// first, some file locking stuff for multiuser crawl
+#ifdef USE_FILE_LOCKING
+
+static bool lock_file_handle( FILE *handle, int type )
+{
+ struct flock lock;
+ int status;
+
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+ lock.l_type = type;
+
+#ifdef USE_BLOCKING_LOCK
+
+ status = fcntl( fileno( handle ), F_SETLKW, &lock );
+
+#else
+
+ for (int i = 0; i < 30; i++)
+ {
+ status = fcntl( fileno( handle ), F_SETLK, &lock );
+
+ // success
+ if (status == 0)
+ break;
+
+ // known failure
+ if (status == -1 && (errno != EACCES && errno != EAGAIN))
+ break;
+
+ perror( "Problems locking file... retrying..." );
+ delay( 1000 );
+ }
+
+#endif
+
+ return (status == 0);
+}
+
+static bool unlock_file_handle( FILE *handle )
+{
+ struct flock lock;
+ int status;
+
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+ lock.l_type = F_UNLCK;
+
+#ifdef USE_BLOCKING_LOCK
+
+ status = fcntl( fileno( handle ), F_SETLKW, &lock );
+
+#else
+
+ for (int i = 0; i < 30; i++)
+ {
+ status = fcntl( fileno( handle ), F_SETLK, &lock );
+
+ // success
+ if (status == 0)
+ break;
+
+ // known failure
+ if (status == -1 && (errno != EACCES && errno != EAGAIN))
+ break;
+
+ perror( "Problems unlocking file... retrying..." );
+ delay( 1000 );
+ }
+
+#endif
+
+ return (status == 0);
+}
+
+#endif
+
+
+
+FILE *hs_open( const char *mode )
+{
+#ifdef SAVE_DIR_PATH
+ FILE *handle = fopen(SAVE_DIR_PATH "scores", mode);
+#else
+ FILE *handle = fopen("scores", mode);
+#endif
+
+#ifdef USE_FILE_LOCKING
+ int locktype = F_RDLCK;
+ if (stricmp(mode, "w") == 0)
+ locktype = F_WRLCK;
+
+ if (handle && !lock_file_handle( handle, locktype ))
+ {
+ perror( "Could not lock scorefile... " );
+ fclose( handle );
+ handle = NULL;
+ }
+#endif
+ return handle;
+}
+
+void hs_close( FILE *handle, const char *mode )
+{
+ UNUSED( mode );
+
+ if (handle == NULL)
+ return;
+
+#ifdef USE_FILE_LOCKING
+ unlock_file_handle( handle );
+#endif
+
+ // actually close
+ fclose(handle);
+
+#ifdef SHARED_FILES_CHMOD_PUBLIC
+ if (stricmp(mode, "w") == 0)
+ {
+ #ifdef SAVE_DIR_PATH
+ chmod(SAVE_DIR_PATH "scores", SHARED_FILES_CHMOD_PUBLIC);
+ #else
+ chmod("scores", SHARED_FILES_CHMOD_PUBLIC);
+ #endif
+ }
+#endif
+}
+
+static void hs_init( struct scorefile_entry &dest )
+{
+ // simple init
+ dest.version = 0;
+ dest.release = 0;
+ dest.points = -1;
+ dest.name[0] = '\0';
+ dest.uid = 0;
+ dest.race = 0;
+ dest.cls = 0;
+ dest.lvl = 0;
+ dest.race_class_name[0] = '\0';
+ dest.best_skill = 0;
+ dest.best_skill_lvl = 0;
+ dest.death_type = KILLED_BY_SOMETHING;
+ dest.death_source = 0;
+ dest.mon_num = 0;
+ dest.death_source_name[0] = '\0';
+ dest.auxkilldata[0] = '\0';
+ dest.dlvl = 0;
+ dest.level_type = 0;
+ dest.branch = 0;
+ dest.final_hp = -1;
+ dest.final_max_hp = -1;
+ dest.final_max_max_hp = -1;
+ dest.str = -1;
+ dest.intel = -1;
+ dest.dex = -1;
+ dest.damage = -1;
+ dest.god = -1;
+ dest.piety = -1;
+ dest.penance = -1;
+ dest.wiz_mode = 0;
+ dest.birth_time = 0;
+ dest.death_time = 0;
+ dest.real_time = -1;
+ dest.num_turns = -1;
+ dest.num_diff_runes = 0;
+ dest.num_runes = 0;
+}
+
+void hs_copy(struct scorefile_entry &dest, struct scorefile_entry &src)
+{
+ // simple field copy -- assume src is well constructed.
+
+ dest.version = src.version;
+ dest.release = src.release;
+ dest.points = src.points;
+ strcpy(dest.name, src.name);
+ dest.uid = src.uid;
+ dest.race = src.race;
+ dest.cls = src.cls;
+ dest.lvl = src.lvl;
+ strcpy(dest.race_class_name, src.race_class_name);
+ dest.best_skill = src.best_skill;
+ dest.best_skill_lvl = src.best_skill_lvl;
+ dest.death_type = src.death_type;
+ dest.death_source = src.death_source;
+ dest.mon_num = src.mon_num;
+ strcpy( dest.death_source_name, src.death_source_name );
+ strcpy( dest.auxkilldata, src.auxkilldata );
+ dest.dlvl = src.dlvl;
+ dest.level_type = src.level_type;
+ dest.branch = src.branch;
+ dest.final_hp = src.final_hp;
+ dest.final_max_hp = src.final_max_hp;
+ dest.final_max_max_hp = src.final_max_max_hp;
+ dest.str = src.str;
+ dest.intel = src.intel;
+ dest.dex = src.dex;
+ dest.damage = src.damage;
+ dest.god = src.god;
+ dest.piety = src.piety;
+ dest.penance = src.penance;
+ dest.wiz_mode = src.wiz_mode;
+ dest.birth_time = src.birth_time;
+ dest.death_time = src.death_time;
+ dest.real_time = src.real_time;
+ dest.num_turns = src.num_turns;
+ dest.num_diff_runes = src.num_diff_runes;
+ dest.num_runes = src.num_runes;
+}
+
+bool hs_read( FILE *scores, struct scorefile_entry &dest )
+{
+ char inbuf[200];
+ int c = EOF;
+
+ hs_init( dest );
+
+ // get a character..
+ if (scores != NULL)
+ c = fgetc(scores);
+
+ // check for NULL scores file or EOF
+ if (scores == NULL || c == EOF)
+ return false;
+
+ // get a line - this is tricky. "Lines" come in three flavors:
+ // 1) old-style lines which were 80 character blocks
+ // 2) 4.0 pr1 through pr7 versions which were newline terminated
+ // 3) 4.0 pr8 and onwards which are 'current' ASCII format, and
+ // may exceed 80 characters!
+
+ // put 'c' in first spot
+ inbuf[0] = c;
+
+ if (fgets(&inbuf[1], (c==':') ? (sizeof(inbuf) - 2) : 81, scores) == NULL)
+ return false;
+
+ // check type; lines starting with a colon are new-style scores.
+ if (c == ':')
+ hs_parse_numeric(inbuf, dest);
+ else
+ hs_parse_string(inbuf, dest);
+
+ return true;
+}
+
+static void hs_nextstring(char *&inbuf, char *dest)
+{
+ char *p = dest;
+
+ if (*inbuf == '\0')
+ {
+ *p = '\0';
+ return;
+ }
+
+ // assume we're on a ':'
+ inbuf ++;
+ while(*inbuf != ':' && *inbuf != '\0')
+ *p++ = *inbuf++;
+
+ *p = '\0';
+}
+
+static int hs_nextint(char *&inbuf)
+{
+ char num[20];
+ hs_nextstring(inbuf, num);
+
+ return (num[0] == '\0' ? 0 : atoi(num));
+}
+
+static long hs_nextlong(char *&inbuf)
+{
+ char num[20];
+ hs_nextstring(inbuf, num);
+
+ return (num[0] == '\0' ? 0 : atol(num));
+}
+
+static int val_char( char digit )
+{
+ return (digit - '0');
+}
+
+static time_t hs_nextdate(char *&inbuf)
+{
+ char buff[20];
+ struct tm date;
+
+ hs_nextstring( inbuf, buff );
+
+ if (strlen( buff ) < 15)
+ return (static_cast<time_t>(0));
+
+ date.tm_year = val_char( buff[0] ) * 1000 + val_char( buff[1] ) * 100
+ + val_char( buff[2] ) * 10 + val_char( buff[3] ) - 1900;
+
+ date.tm_mon = val_char( buff[4] ) * 10 + val_char( buff[5] );
+ date.tm_mday = val_char( buff[6] ) * 10 + val_char( buff[7] );
+ date.tm_hour = val_char( buff[8] ) * 10 + val_char( buff[9] );
+ date.tm_min = val_char( buff[10] ) * 10 + val_char( buff[11] );
+ date.tm_sec = val_char( buff[12] ) * 10 + val_char( buff[13] );
+ date.tm_isdst = (buff[14] == 'D');
+
+ return (mktime( &date ));
+}
+
+static void hs_parse_numeric(char *inbuf, struct scorefile_entry &se)
+{
+ se.version = hs_nextint(inbuf);
+ se.release = hs_nextint(inbuf);
+
+ // this would be a good point to check for version numbers and branch
+ // appropriately
+
+ // acceptable versions are 0 (converted from old hiscore format) and 4
+ if (se.version != 0 && se.version != 4)
+ return;
+
+ se.points = hs_nextlong(inbuf);
+
+ hs_nextstring(inbuf, se.name);
+
+ se.uid = hs_nextlong(inbuf);
+ se.race = hs_nextint(inbuf);
+ se.cls = hs_nextint(inbuf);
+
+ hs_nextstring(inbuf, se.race_class_name);
+
+ se.lvl = hs_nextint(inbuf);
+ se.best_skill = hs_nextint(inbuf);
+ se.best_skill_lvl = hs_nextint(inbuf);
+ se.death_type = hs_nextint(inbuf);
+ se.death_source = hs_nextint(inbuf);
+ se.mon_num = hs_nextint(inbuf);
+
+ hs_nextstring(inbuf, se.death_source_name);
+
+ // To try and keep the scorefile backwards compatible,
+ // we'll branch on version > 4.0 to read the auxkilldata
+ // text field.
+ if (se.version == 4 && se.release >= 1)
+ hs_nextstring( inbuf, se.auxkilldata );
+ else
+ se.auxkilldata[0] = '\0';
+
+ se.dlvl = hs_nextint(inbuf);
+ se.level_type = hs_nextint(inbuf);
+ se.branch = hs_nextint(inbuf);
+
+ // Trying to fix some bugs that have been around since at
+ // least pr19, if not longer. From now on, dlvl should
+ // be calculated on death and need no further modification.
+ if (se.version < 4 || se.release < 2)
+ {
+ if (se.level_type == LEVEL_DUNGEON)
+ {
+ if (se.branch == BRANCH_MAIN_DUNGEON)
+ se.dlvl += 1;
+ else if (se.branch < BRANCH_ORCISH_MINES) // ie the hells
+ se.dlvl -= 1;
+ }
+ }
+
+ se.final_hp = hs_nextint(inbuf);
+ if (se.version == 4 && se.release >= 2)
+ {
+ se.final_max_hp = hs_nextint(inbuf);
+ se.final_max_max_hp = hs_nextint(inbuf);
+ se.damage = hs_nextint(inbuf);
+ se.str = hs_nextint(inbuf);
+ se.intel = hs_nextint(inbuf);
+ se.dex = hs_nextint(inbuf);
+ se.god = hs_nextint(inbuf);
+ se.piety = hs_nextint(inbuf);
+ se.penance = hs_nextint(inbuf);
+ }
+ else
+ {
+ se.final_max_hp = -1;
+ se.final_max_max_hp = -1;
+ se.damage = -1;
+ se.str = -1;
+ se.intel = -1;
+ se.dex = -1;
+ se.god = -1;
+ se.piety = -1;
+ se.penance = -1;
+ }
+
+ se.wiz_mode = hs_nextint(inbuf);
+
+ se.birth_time = hs_nextdate(inbuf);
+ se.death_time = hs_nextdate(inbuf);
+
+ if (se.version == 4 && se.release >= 2)
+ {
+ se.real_time = hs_nextint(inbuf);
+ se.num_turns = hs_nextint(inbuf);
+ }
+ else
+ {
+ se.real_time = -1;
+ se.num_turns = -1;
+ }
+
+ se.num_diff_runes = hs_nextint(inbuf);
+ se.num_runes = hs_nextint(inbuf);
+}
+
+static void hs_write( FILE *scores, struct scorefile_entry &se )
+{
+ char buff[80]; // should be more than enough for date stamps
+
+ se.version = 4;
+ se.release = 2;
+
+ fprintf( scores, ":%d:%d:%ld:%s:%ld:%d:%d:%s:%d:%d:%d",
+ se.version, se.release, se.points, se.name,
+ se.uid, se.race, se.cls, se.race_class_name, se.lvl,
+ se.best_skill, se.best_skill_lvl );
+
+ // XXX: need damage
+ fprintf( scores, ":%d:%d:%d:%s:%s:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
+ se.death_type, se.death_source, se.mon_num,
+ se.death_source_name, se.auxkilldata,
+ se.dlvl, se.level_type, se.branch,
+ se.final_hp, se.final_max_hp, se.final_max_max_hp, se.damage,
+ se.str, se.intel, se.dex,
+ se.god, se.piety, se.penance, se.wiz_mode );
+
+ make_date_string( se.birth_time, buff );
+ fprintf( scores, ":%s", buff );
+
+ make_date_string( se.death_time, buff );
+ fprintf( scores, ":%s", buff );
+
+ fprintf( scores, ":%ld:%ld:%d:%d:\n",
+ se.real_time, se.num_turns, se.num_diff_runes, se.num_runes );
+}
+// -------------------------------------------------------------------------
+// functions dealing with old-style scorefile entries.
+// -------------------------------------------------------------------------
+
+static void hs_parse_string(char *inbuf, struct scorefile_entry &se)
+{
+ /* old entries are of the following format (Brent introduced some
+ spacing at one point, we have to take this into account):
+
+ // Actually, I believe it might have been Brian who added the spaces,
+ // I was quite happy with the condensed version, given the 80 column
+ // restriction. -- bwr
+
+6263 BoBo - DSD10 Wiz, killed by an acid blob on L1 of the Slime Pits.
+5877 Aldus-DGM10, killed by a lethal dose of poison on L10.
+5419 Yarf - Koa10, killed by a warg on L1 of the Mines.
+
+ 1. All numerics up to the first non-numeric are the score
+ 2. All non '-' characters are the name. Strip spaces.
+ 3. All alphabetics up to the first numeric are race/class
+ 4. All numerics up to the comma are the clevel
+ 5. From the comma, search for known fixed substrings and
+ translate to death_type. Leave death source = 0 for old
+ scores, and just copy in the monster name.
+ 6. Look for the branch type (again, substring search for
+ fixed strings) and level.
+
+ Very ugly and time consuming.
+
+ */
+
+ char scratch[80];
+
+ // 1. get score
+ hs_parse_generic_2(inbuf, scratch, "0123456789");
+
+ se.version = 0; // version # of converted score
+ se.release = 0;
+ se.points = atoi(scratch);
+
+ // 2. get name
+ hs_parse_generic_1(inbuf, scratch, "-");
+ hs_stripblanks(scratch);
+ strcpy(se.name, scratch);
+
+ // 3. get race, class
+ inbuf++; // skip '-'
+ hs_parse_generic_1(inbuf, scratch, "0123456789");
+ hs_stripblanks(scratch);
+ strcpy(se.race_class_name, scratch);
+ se.race = 0;
+ se.cls = 0;
+
+ // 4. get clevel
+ hs_parse_generic_2(inbuf, scratch, "0123456789");
+ se.lvl = atoi(scratch);
+
+ // 4a. get wizard mode
+ hs_parse_generic_1(inbuf, scratch, ",");
+ if (strstr(scratch, "Wiz") != NULL)
+ se.wiz_mode = 1;
+ else
+ se.wiz_mode = 0;
+
+ // 5. get death type
+ inbuf++; // skip comma
+ hs_search_death(inbuf, se);
+
+ // 6. get branch, level
+ hs_search_where(inbuf, se);
+
+ // set things that can't be picked out of old scorefile entries
+ se.uid = 0;
+ se.best_skill = 0;
+ se.best_skill_lvl = 0;
+ se.final_hp = 0;
+ se.final_max_hp = -1;
+ se.final_max_max_hp = -1;
+ se.damage = -1;
+ se.str = -1;
+ se.intel = -1;
+ se.dex = -1;
+ se.god = -1;
+ se.piety = -1;
+ se.penance = -1;
+ se.birth_time = 0;
+ se.death_time = 0;
+ se.real_time = -1;
+ se.num_turns = -1;
+ se.num_runes = 0;
+ se.num_diff_runes = 0;
+ se.auxkilldata[0] = '\0';
+}
+
+static void hs_parse_generic_1(char *&inbuf, char *outbuf, const char *stopvalues)
+{
+ char *p = outbuf;
+
+ while(strchr(stopvalues, *inbuf) == NULL && *inbuf != '\0')
+ *p++ = *inbuf++;
+
+ *p = '\0';
+}
+
+static void hs_parse_generic_2(char *&inbuf, char *outbuf, const char *continuevalues)
+{
+ char *p = outbuf;
+
+ while(strchr(continuevalues, *inbuf) != NULL && *inbuf != '\0')
+ *p++ = *inbuf++;
+
+ *p = '\0';
+}
+
+static void hs_stripblanks(char *buf)
+{
+ char *p = buf;
+ char *q = buf;
+
+ // strip leading
+ while(*p == ' ')
+ p++;
+ while(*p != '\0')
+ *q++ = *p++;
+
+ *q-- = '\0';
+ // strip trailing
+ while(*q == ' ')
+ {
+ *q = '\0';
+ q--;
+ }
+}
+
+static void hs_search_death(char *inbuf, struct scorefile_entry &se)
+{
+ // assume killed by monster
+ se.death_type = KILLED_BY_MONSTER;
+
+ // sigh..
+ if (strstr(inbuf, "killed by a lethal dose of poison") != NULL)
+ se.death_type = KILLED_BY_POISON;
+ else if (strstr(inbuf, "killed by a cloud") != NULL)
+ se.death_type = KILLED_BY_CLOUD;
+ else if (strstr(inbuf, "killed from afar by") != NULL)
+ se.death_type = KILLED_BY_BEAM;
+ else if (strstr(inbuf, "took a swim in molten lava") != NULL)
+ se.death_type = KILLED_BY_LAVA;
+ else if (strstr(inbuf, "soaked and fell apart") != NULL)
+ {
+ se.death_type = KILLED_BY_WATER;
+ se.race = SP_MUMMY;
+ }
+ else if (strstr(inbuf, "drowned") != NULL)
+ se.death_type = KILLED_BY_WATER;
+ else if (strstr(inbuf, "died of stupidity") != NULL)
+ se.death_type = KILLED_BY_STUPIDITY;
+ else if (strstr(inbuf, "too weak to continue adventuring") != NULL)
+ se.death_type = KILLED_BY_WEAKNESS;
+ else if (strstr(inbuf, "slipped on a banana peel") != NULL)
+ se.death_type = KILLED_BY_CLUMSINESS;
+ else if (strstr(inbuf, "killed by a trap") != NULL)
+ se.death_type = KILLED_BY_TRAP;
+ else if (strstr(inbuf, "got out of the dungeon alive") != NULL)
+ se.death_type = KILLED_BY_LEAVING;
+ else if (strstr(inbuf, "escaped with the Orb") != NULL)
+ se.death_type = KILLED_BY_WINNING;
+ else if (strstr(inbuf, "quit") != NULL)
+ se.death_type = KILLED_BY_QUITTING;
+ else if (strstr(inbuf, "was drained of all life") != NULL)
+ se.death_type = KILLED_BY_DRAINING;
+ else if (strstr(inbuf, "starved to death") != NULL)
+ se.death_type = KILLED_BY_STARVATION;
+ else if (strstr(inbuf, "froze to death") != NULL)
+ se.death_type = KILLED_BY_FREEZING;
+ else if (strstr(inbuf, "burnt to a crisp") != NULL)
+ se.death_type = KILLED_BY_BURNING;
+ else if (strstr(inbuf, "killed by wild magic") != NULL)
+ se.death_type = KILLED_BY_WILD_MAGIC;
+ else if (strstr(inbuf, "killed by Xom") != NULL)
+ se.death_type = KILLED_BY_XOM;
+ else if (strstr(inbuf, "killed by a statue") != NULL)
+ se.death_type = KILLED_BY_STATUE;
+ else if (strstr(inbuf, "rotted away") != NULL)
+ se.death_type = KILLED_BY_ROTTING;
+ else if (strstr(inbuf, "killed by bad target") != NULL)
+ se.death_type = KILLED_BY_TARGETTING;
+ else if (strstr(inbuf, "killed by an exploding spore") != NULL)
+ se.death_type = KILLED_BY_SPORE;
+ else if (strstr(inbuf, "smote by The Shining One") != NULL)
+ se.death_type = KILLED_BY_TSO_SMITING;
+ else if (strstr(inbuf, "turned to stone") != NULL)
+ se.death_type = KILLED_BY_PETRIFICATION;
+ else if (strstr(inbuf, "eviscerated by a hatching") != NULL)
+ se.death_type = KILLED_BY_SHUGGOTH;
+
+ // whew!
+
+ // now, if we're still KILLED_BY_MONSTER, make sure that there is
+ // a "killed by" somewhere, or else we're setting it to UNKNOWN.
+ if (se.death_type == KILLED_BY_MONSTER)
+ {
+ if (strstr(inbuf, "killed by") == NULL)
+ se.death_type = KILLED_BY_SOMETHING;
+ }
+
+ // set some fields
+ se.death_source = 0;
+ se.mon_num = 0;
+ strcpy(se.death_source_name, "");
+
+ // now try to pull the monster out.
+ if (se.death_type == KILLED_BY_MONSTER || se.death_type == KILLED_BY_BEAM)
+ {
+ char *p = strstr(inbuf, " by ");
+ p += 4;
+ char *q = strstr(inbuf, " on ");
+ if (q == NULL)
+ q = strstr(inbuf, " in ");
+ char *d = se.death_source_name;
+ while(p != q)
+ *d++ = *p++;
+
+ *d = '\0';
+ }
+}
+
+static void hs_search_where(char *inbuf, struct scorefile_entry &se)
+{
+ char scratch[6];
+
+ se.level_type = LEVEL_DUNGEON;
+ se.branch = BRANCH_MAIN_DUNGEON;
+ se.dlvl = 0;
+
+ // early out
+ if (se.death_type == KILLED_BY_LEAVING || se.death_type == KILLED_BY_WINNING)
+ return;
+
+ // here we go again.
+ if (strstr(inbuf, "in the Abyss") != NULL)
+ se.level_type = LEVEL_ABYSS;
+ else if (strstr(inbuf, "in Pandemonium") != NULL)
+ se.level_type = LEVEL_PANDEMONIUM;
+ else if (strstr(inbuf, "in a labyrinth") != NULL)
+ se.level_type = LEVEL_LABYRINTH;
+
+ // early out for special level types
+ if (se.level_type != LEVEL_DUNGEON)
+ return;
+
+ // check for vestible
+ if (strstr(inbuf, "in the Vestibule") != NULL)
+ {
+ se.branch = BRANCH_VESTIBULE_OF_HELL;
+ return;
+ }
+
+ // from here, we have branch and level.
+ char *p = strstr(inbuf, "on L");
+ if (p != NULL)
+ {
+ p += 4;
+ hs_parse_generic_2(p, scratch, "0123456789");
+ se.dlvl = atoi( scratch );
+ }
+
+ // get branch.
+ if (strstr(inbuf, "of Dis") != NULL)
+ se.branch = BRANCH_DIS;
+ else if (strstr(inbuf, "of Gehenna") != NULL)
+ se.branch = BRANCH_GEHENNA;
+ else if (strstr(inbuf, "of Cocytus") != NULL)
+ se.branch = BRANCH_COCYTUS;
+ else if (strstr(inbuf, "of Tartarus") != NULL)
+ se.branch = BRANCH_TARTARUS;
+ else if (strstr(inbuf, "of the Mines") != NULL)
+ se.branch = BRANCH_ORCISH_MINES;
+ else if (strstr(inbuf, "of the Hive") != NULL)
+ se.branch = BRANCH_HIVE;
+ else if (strstr(inbuf, "of the Lair") != NULL)
+ se.branch = BRANCH_LAIR;
+ else if (strstr(inbuf, "of the Slime Pits") != NULL)
+ se.branch = BRANCH_SLIME_PITS;
+ else if (strstr(inbuf, "of the Vaults") != NULL)
+ se.branch = BRANCH_VAULTS;
+ else if (strstr(inbuf, "of the Crypt") != NULL)
+ se.branch = BRANCH_CRYPT;
+ else if (strstr(inbuf, "of the Hall") != NULL)
+ se.branch = BRANCH_HALL_OF_BLADES;
+ else if (strstr(inbuf, "of Zot's Hall") != NULL)
+ se.branch = BRANCH_HALL_OF_ZOT;
+ else if (strstr(inbuf, "of the Temple") != NULL)
+ se.branch = BRANCH_ECUMENICAL_TEMPLE;
+ else if (strstr(inbuf, "of the Snake Pit") != NULL)
+ se.branch = BRANCH_SNAKE_PIT;
+ else if (strstr(inbuf, "of the Elf Hall") != NULL)
+ se.branch = BRANCH_ELVEN_HALLS;
+ else if (strstr(inbuf, "of the Tomb") != NULL)
+ se.branch = BRANCH_TOMB;
+ else if (strstr(inbuf, "of the Swamp") != NULL)
+ se.branch = BRANCH_SWAMP;
+}
diff --git a/trunk/source/hiscores.h b/trunk/source/hiscores.h
new file mode 100644
index 0000000000..2cb5f4786f
--- /dev/null
+++ b/trunk/source/hiscores.h
@@ -0,0 +1,35 @@
+/*
+ * File: hiscores.h
+ * Summary: Scorefile manipulation functions
+ * Written by: Gordon Lipford
+ *
+ * Change History (most recent first):
+ *
+ * <1> 16feb2001 GDL Created
+ */
+
+
+#ifndef HISCORES_H
+#define HISCORES_H
+
+// last updated 16feb2001 {gdl}
+/* ***********************************************************************
+ * called from: ouch
+ * *********************************************************************** */
+void hiscores_new_entry( struct scorefile_entry &se );
+
+// last updated 16feb2001 {gdl}
+/* ***********************************************************************
+ * called from: acr ouch
+ * *********************************************************************** */
+void hiscores_print_list( int display_count = -1, int format = SCORE_TERSE );
+
+// last updated 16feb2001 {gdl}
+/* ***********************************************************************
+ * called from: ouch hiscores
+ * *********************************************************************** */
+void hiscores_format_single( char *buffer, struct scorefile_entry &se );
+int hiscores_format_single_long( char *buffer, struct scorefile_entry &se,
+ bool verbose = false );
+
+#endif // HISCORES_H
diff --git a/trunk/source/initfile.cc b/trunk/source/initfile.cc
new file mode 100644
index 0000000000..2d00edcb18
--- /dev/null
+++ b/trunk/source/initfile.cc
@@ -0,0 +1,968 @@
+/*
+ * File: initfile.cc
+ * Summary: Simple reading of an init file and system variables
+ * Written by: David Loewenstern
+ *
+ * Change History (most recent first):
+ *
+ * <3> 5 May 2000 GDL Add field stripping for 'name'
+ * <2> 6/12/99 BWR Added get_system_environment
+ * <1> 6/9/99 DML Created
+ */
+
+#include "AppHdr.h"
+#include "initfile.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+#include <ctype.h>
+
+#include "externs.h"
+#include "defines.h"
+#include "player.h"
+#include "stuff.h"
+#include "items.h"
+#include "view.h"
+
+game_options Options;
+
+extern void (*viewwindow) (char, bool);
+extern unsigned char (*mapch) (unsigned char);
+extern unsigned char (*mapch2) (unsigned char);
+extern unsigned char mapchar3(unsigned char ldfk);
+extern unsigned char mapchar4(unsigned char ldfk);
+
+#ifdef LINUX
+extern int character_set; // unices only
+#endif
+
+static std::string & tolower_string( std::string &str );
+
+const static char *obj_syms = ")([/%.?=!.+\\0}X$";
+const static int obj_syms_len = 16;
+
+// also used with macros
+std::string & trim_string( std::string &str )
+{
+ // OK, this is really annoying. Borland C++ seems to define
+ // basic_string::erase to take iterators, and basic_string::remove
+ // to take size_t or integer. This is ass-backwards compared to
+ // nearly all other C++ compilers. Crap. (GDL)
+ //
+ // Borland 5.5 does this correctly now... leaving the old code
+ // around for now in case anyone needs it. -- bwr
+// #ifdef __BCPLUSPLUS__
+// str.remove( 0, str.find_first_not_of( " \t\n\r" ) );
+// str.remove( str.find_last_not_of( " \t\n\r" ) + 1 );
+// #else
+ str.erase( 0, str.find_first_not_of( " \t\n\r" ) );
+ str.erase( str.find_last_not_of( " \t\n\r" ) + 1 );
+// #endif
+
+ return (str);
+}
+
+// returns -1 if unmatched else returns 0-15
+static short str_to_colour( const std::string &str )
+{
+ int ret;
+
+ const std::string cols[16] =
+ {
+ "black", "blue", "green", "cyan", "red", "magenta", "brown",
+ "lightgrey", "darkgrey", "lightblue", "lightgreen", "lightcyan",
+ "lightred", "lightmagenta", "yellow", "white"
+ };
+
+ for (ret = 0; ret < 16; ret++)
+ {
+ if (str == cols[ret])
+ break;
+ }
+
+ // check for alternate spellings
+ if (ret == 16)
+ {
+ if (str == "lightgray")
+ ret = 7;
+ else if (str == "darkgray")
+ ret = 8;
+ }
+
+ return ((ret == 16) ? -1 : ret);
+}
+
+// returns -1 if unmatched else returns 0-15
+static short str_to_channel_colour( const std::string &str )
+{
+ int ret = str_to_colour( str );
+
+ if (ret == -1)
+ {
+ if (str == "mute")
+ ret = MSGCOL_MUTED;
+ else if (str == "plain" || str == "off")
+ ret = MSGCOL_PLAIN;
+ else if (str == "default" || str == "on")
+ ret = MSGCOL_DEFAULT;
+ else if (str == "alternate")
+ ret = MSGCOL_ALTERNATE;
+ }
+
+ return (ret);
+}
+
+// returns -1 if unmatched else returns 0-15
+static short str_to_channel( const std::string &str )
+{
+ short ret;
+
+ const std::string cols[ NUM_MESSAGE_CHANNELS ] =
+ {
+ "plain", "prompt", "god", "duration", "danger", "warning", "food",
+ "recovery", "talk", "intrinsic_gain", "mutation", "monster_spell",
+ "monster_enchant", "monster_damage", "rotten_meat", "equipment",
+ "diagnostic",
+ };
+
+ for (ret = 0; ret < NUM_MESSAGE_CHANNELS; ret++)
+ {
+ if (str == cols[ret])
+ break;
+ }
+
+ return (ret == NUM_MESSAGE_CHANNELS ? -1 : ret);
+}
+
+static int str_to_weapon( const std::string &str )
+{
+ if (str == "shortsword" || str == "short sword")
+ return (WPN_SHORT_SWORD);
+ else if (str == "mace")
+ return (WPN_MACE);
+ else if (str == "spear")
+ return (WPN_SPEAR);
+ else if (str == "trident")
+ return (WPN_TRIDENT);
+ else if (str == "hand axe" || str == "handaxe")
+ return (WPN_HAND_AXE);
+ else if (str == "random")
+ return (WPN_RANDOM);
+
+ return (WPN_UNKNOWN);
+}
+
+static unsigned int str_to_fire_types( const std::string &str )
+{
+ if (str == "launcher")
+ return (FIRE_LAUNCHER);
+ else if (str == "dart")
+ return (FIRE_DART);
+ else if (str == "stone")
+ return (FIRE_STONE);
+ else if (str == "dagger")
+ return (FIRE_DAGGER);
+ else if (str == "spear")
+ return (FIRE_SPEAR);
+ else if (str == "hand axe" || str == "handaxe")
+ return (FIRE_HAND_AXE);
+ else if (str == "club")
+ return (FIRE_CLUB);
+
+ return (FIRE_NONE);
+}
+
+static void str_to_fire_order( const std::string &str,
+ FixedVector< int, NUM_FIRE_TYPES > &list )
+{
+ int i;
+ size_t pos = 0;
+ std::string item = "";
+
+ for (i = 0; i < NUM_FIRE_TYPES; i++)
+ {
+ // get next item from comma delimited list
+ const size_t end = str.find( ',', pos );
+ item = str.substr( pos, end - pos );
+ trim_string( item );
+
+ list[i] = str_to_fire_types( item );
+
+ if (end == std::string::npos)
+ break;
+ else
+ pos = end + 1;
+ }
+}
+
+static char str_to_race( const std::string &str )
+{
+ int index = -1;
+
+ if (str.length() == 1) // old system of using menu letter
+ return (str[0]);
+ else if (str.length() == 2) // scan abbreviations
+ index = get_species_index_by_abbrev( str.c_str() );
+
+ // if we don't have a match, scan the full names
+ if (index == -1)
+ index = get_species_index_by_name( str.c_str() );
+
+ // skip over the extra draconians here
+ if (index > SP_RED_DRACONIAN)
+ index -= (SP_CENTAUR - SP_RED_DRACONIAN - 1);
+
+ // SP_HUMAN is at 1, therefore we must subtract one.
+ return ((index != -1) ? index_to_letter( index - 1 ) : '\0');
+}
+
+static char str_to_class( const std::string &str )
+{
+ int index = -1;
+
+ if (str.length() == 1) // old system of using menu letter
+ return (str[0]);
+ else if (str.length() == 2) // scan abbreviations
+ index = get_class_index_by_abbrev( str.c_str() );
+
+ // if we don't have a match, scan the full names
+ if (index == -1)
+ index = get_class_index_by_name( str.c_str() );
+
+ return ((index != -1) ? index_to_letter( index ) : '\0');
+}
+
+static std::string & tolower_string( std::string &str )
+{
+ if (str.length())
+ {
+ for (std::string::iterator cp = str.begin(); cp != str.end(); cp++)
+ {
+ *cp = tolower( *cp );
+ }
+ }
+
+ return (str);
+}
+
+static bool read_bool( const std::string &field, bool def_value )
+{
+ bool ret = def_value;
+
+ if (field == "true" || field == "1")
+ ret = true;
+
+ if (field == "false" || field == "0")
+ ret = false;
+
+ return (ret);
+}
+
+void read_init_file(void)
+{
+ unsigned int i;
+
+ // Option initialization
+ Options.autopickups = 0x0000;
+ Options.verbose_dump = false;
+ Options.colour_map = false;
+ Options.clean_map = false;
+ Options.show_uncursed = true;
+ Options.always_greet = false;
+ Options.easy_open = true;
+ Options.easy_armour = true;
+ Options.easy_butcher = false;
+ Options.easy_confirm = CONFIRM_SAFE_EASY;
+ Options.easy_quit_item_prompts = false;
+ Options.weapon = WPN_UNKNOWN;
+ Options.random_pick = false;
+ Options.chaos_knight = GOD_NO_GOD;
+ Options.death_knight = DK_NO_SELECTION;
+ Options.priest = GOD_NO_GOD;
+ Options.hp_warning = 10;
+ Options.hp_attention = 25;
+ Options.race = '\0';
+ Options.cls = '\0';
+ Options.terse_hand = true;
+ Options.auto_list = false;
+ Options.delay_message_clear = false;
+
+ Options.flush_input[ FLUSH_ON_FAILURE ] = true;
+ Options.flush_input[ FLUSH_BEFORE_COMMAND ] = false;
+ Options.flush_input[ FLUSH_ON_MESSAGE ] = false;
+
+ Options.lowercase_invocations = false;
+
+ // Note: These fire options currently match the old behaviour. -- bwr
+ Options.fire_items_start = 0; // start at slot 'a'
+
+ Options.fire_order[0] = FIRE_LAUNCHER; // fire first from bow...
+ Options.fire_order[1] = FIRE_DART; // then only consider darts
+
+ // clear the reast of the list
+ for (i = 2; i < NUM_FIRE_TYPES; i++)
+ Options.fire_order[i] = FIRE_NONE;
+
+ // These are only used internally, and only from the commandline:
+ // XXX: These need a better place.
+ Options.sc_entries = 0;
+ Options.sc_format = SCORE_REGULAR;
+
+#ifdef USE_COLOUR_OPTS
+ Options.friend_brand = CHATTR_NORMAL;
+ Options.no_dark_brand = 0;
+#endif
+
+#ifdef WIZARD
+ Options.wiz_mode = WIZ_NO;
+#endif
+
+ // map each colour to itself as default
+#ifdef USE_8_COLOUR_TERM_MAP
+ for (i = 0; i < 16; i++)
+ Options.colour[i] = i % 8;
+
+ Options.colour[ DARKGREY ] = COL_TO_REPLACE_DARKGREY;
+#else
+ for (i = 0; i < 16; i++)
+ Options.colour[i] = i;
+#endif
+
+ // map each channel to plain (well, default for now since I'm testing)
+ for (int i = 0; i < NUM_MESSAGE_CHANNELS; i++)
+ Options.channels[i] = MSGCOL_DEFAULT;
+
+ FILE *f;
+ char s[255];
+ unsigned int line = 0;
+ int j;
+ char name_buff[kPathLen];
+
+ you.your_name[0] = '\0';
+
+ if (SysEnv.crawl_rc)
+ {
+ f = fopen(SysEnv.crawl_rc, "r");
+ }
+ else if (SysEnv.crawl_dir)
+ {
+ strncpy(name_buff, SysEnv.crawl_dir, kPathLen);
+ name_buff[ kPathLen - 1 ] = '\0';
+ strncat(name_buff, "init.txt", kPathLen);
+ name_buff[ kPathLen - 1 ] = '\0';
+
+ f = fopen(name_buff, "r");
+ }
+#ifdef MULTIUSER
+ else if (SysEnv.home)
+ {
+ // init.txt isn't such a good choice if we're looking in
+ // the user's home directory, we'll use Un*x standard
+ strncpy(name_buff, SysEnv.home, kPathLen);
+ name_buff[ kPathLen - 1 ] = '\0';
+
+ // likely not to have a closing slash so we'll insert one...
+ strncat(name_buff, "/.crawlrc", kPathLen);
+ name_buff[ kPathLen - 1 ] = '\0';
+
+ f = fopen(name_buff, "r");
+ }
+#endif
+ else
+ {
+ f = fopen("init.txt", "r");
+ }
+
+ if (f == NULL)
+ return;
+
+ while (!feof(f))
+ {
+ fgets(s, 255, f);
+
+ line++;
+
+ std::string str = s;
+ trim_string( str );
+
+ // This is to make some efficient comments
+ if (s[0] == '#' || s[0] == '\0')
+ continue;
+
+ std::string key = "";
+ std::string subkey = "";
+ std::string field = "";
+
+ int first_equals = str.find('=');
+ int first_dot = str.find('.');
+
+ // all lines with no equal-signs we ignore
+ if (first_equals < 0)
+ continue;
+
+ if (first_dot > 0 && first_dot < first_equals)
+ {
+ key = str.substr( 0, first_dot );
+ subkey = str.substr( first_dot + 1, first_equals - first_dot - 1 );
+ field = str.substr( first_equals + 1 );
+ }
+ else
+ {
+ // no subkey (dots are okay in value field)
+ key = str.substr( 0, first_equals );
+ subkey = "";
+ field = str.substr( first_equals + 1 );
+ }
+
+ // Clean up our data...
+ tolower_string( trim_string( key ) );
+ tolower_string( trim_string( subkey ) );
+
+ // some fields want capitals... none care about external spaces
+ trim_string( field );
+ if (key != "name" && key != "crawl_dir"
+ && key != "race" && key != "class")
+ {
+ tolower_string( field );
+ }
+
+ // everything not a valid line is treated as a comment
+ if (key == "autopickup")
+ {
+ for (i = 0; i < field.length(); i++)
+ {
+ char type = field[i];
+
+ // Make the amulet symbol equiv to ring -- bwross
+ switch (type)
+ {
+ case '"':
+ // also represents jewellery
+ type = '=';
+ break;
+
+ case '|':
+ // also represents staves
+ type = '\\';
+ break;
+
+ case ':':
+ // also represents books
+ type = '+';
+ break;
+
+ case 'x':
+ // also corpses
+ type = 'X';
+ break;
+ }
+
+ for (j = 0; j < obj_syms_len && type != obj_syms[j]; j++)
+ ;
+
+ if (j < obj_syms_len)
+ Options.autopickups |= (1L << j);
+ else
+ {
+ fprintf( stderr, "Bad object type '%c' for autopickup.\n",
+ type );
+ }
+ }
+ }
+ else if (key == "name")
+ {
+ // field is already cleaned up from trim_string()
+ strncpy(you.your_name, field.c_str(), kNameLen);
+ you.your_name[ kNameLen - 1 ] = '\0';
+ }
+ else if (key == "verbose_dump")
+ {
+ // gives verbose info in char dumps
+ Options.verbose_dump = read_bool( field, Options.verbose_dump );
+ }
+ else if (key == "clean_map")
+ {
+ // removes monsters/clouds from map
+ Options.clean_map = read_bool( field, Options.clean_map );
+ }
+ else if (key == "colour_map" || key == "color_map")
+ {
+ // colour-codes play-screen map
+ Options.colour_map = read_bool( field, Options.colour_map );
+ }
+ else if (key == "easy_confirm")
+ {
+ // allows both 'Y'/'N' and 'y'/'n' on yesno() prompts
+ if (field == "none")
+ Options.easy_confirm = CONFIRM_NONE_EASY;
+ else if (field == "safe")
+ Options.easy_confirm = CONFIRM_SAFE_EASY;
+ else if (field == "all")
+ Options.easy_confirm = CONFIRM_ALL_EASY;
+ }
+ else if (key == "easy_quit_item_lists")
+ {
+ // allow aborting of item lists with space
+ Options.easy_quit_item_prompts = read_bool( field,
+ Options.easy_quit_item_prompts );
+ }
+ else if (key == "easy_open")
+ {
+ // automatic door opening with movement
+ Options.easy_open = read_bool( field, Options.easy_open );
+ }
+ else if (key == "easy_armour" || key == "easy_armour")
+ {
+ // automatic removal of armour when dropping
+ Options.easy_armour = read_bool( field, Options.easy_armour );
+ }
+ else if (key == "easy_butcher")
+ {
+ // automatic knife switching
+ Options.easy_butcher = read_bool( field, Options.easy_butcher );
+ }
+ else if (key == "colour" || key == "color")
+ {
+ const int orig_col = str_to_colour( subkey );
+ const int result_col = str_to_colour( field );
+
+ if (orig_col != -1 && result_col != -1)
+ Options.colour[orig_col] = result_col;
+ else
+ {
+ fprintf( stderr, "Bad colour -- %s=%d or %s=%d\n",
+ subkey.c_str(), orig_col, field.c_str(), result_col );
+ }
+ }
+ else if (key == "channel")
+ {
+ const int chnl = str_to_channel( subkey );
+ const int col = str_to_channel_colour( field );
+
+ if (chnl != -1 && col != -1)
+ Options.channels[chnl] = col;
+ else if (chnl == -1)
+ fprintf( stderr, "Bad channel -- %s\n", subkey.c_str() );
+ else if (col == -1)
+ fprintf( stderr, "Bad colour -- %s\n", field.c_str() );
+ }
+ else if (key == "background")
+ {
+ // change background colour
+ // Experimental! This may look really bad!
+ const int col = str_to_colour( field );
+
+ if (col != -1)
+ Options.background = col;
+ else
+ fprintf( stderr, "Bad colour -- %s\n", field.c_str() );
+
+ }
+#ifdef USE_COLOUR_OPTS
+ else if (key == "friend_brand")
+ {
+ // Use curses attributes to mark friend
+ // Some may look bad on some terminals.
+ // As a suggestion, try "rxvt -rv -fn 10x20" under Un*xes
+ if (field == "standout") // probably reverses
+ Options.friend_brand = CHATTR_STANDOUT;
+ else if (field == "bold") // probably brightens fg
+ Options.friend_brand = CHATTR_BOLD;
+ else if (field == "blink") // probably brightens bg
+ Options.friend_brand = CHATTR_BLINK;
+ else if (field == "underline")
+ Options.friend_brand = CHATTR_UNDERLINE;
+ else if (field == "reverse")
+ Options.friend_brand = CHATTR_REVERSE;
+ else if (field == "dim")
+ Options.friend_brand = CHATTR_DIM;
+ else
+ fprintf( stderr, "Bad colour -- %s\n", field.c_str() );
+ }
+ else if (key == "no_dark_brand")
+ {
+ // This is useful for terms where dark grey does
+ // not have standout modes (since it's black on black).
+ // This option will use light-grey instead in these cases.
+ Options.no_dark_brand = read_bool( field, Options.no_dark_brand );
+ }
+#endif
+ else if (key == "show_uncursed")
+ {
+ // label known uncursed items as "uncursed"
+ Options.show_uncursed = read_bool( field, Options.show_uncursed );
+ }
+ else if (key == "always_greet")
+ {
+ // show greeting when reloading game
+ Options.always_greet = read_bool( field, Options.always_greet );
+ }
+ else if (key == "weapon")
+ {
+ // choose this weapon for classes that get choice
+ Options.weapon = str_to_weapon( field );
+ }
+ else if (key == "chaos_knight")
+ {
+ // choose god for Chaos Knights
+ if (field == "xom")
+ Options.chaos_knight = GOD_XOM;
+ else if (field == "makhleb")
+ Options.chaos_knight = GOD_MAKHLEB;
+ else if (field == "random")
+ Options.chaos_knight = GOD_RANDOM;
+ }
+ else if (key == "death_knight")
+ {
+ if (field == "necromancy")
+ Options.death_knight = DK_NECROMANCY;
+ else if (field == "yredelemnul")
+ Options.death_knight = DK_YREDELEMNUL;
+ else if (field == "random")
+ Options.death_knight = DK_RANDOM;
+ }
+ else if (key == "priest")
+ {
+ // choose this weapon for classes that get choice
+ if (field == "zin")
+ Options.priest = GOD_ZIN;
+ else if (field == "yredelemnul")
+ Options.priest = GOD_YREDELEMNUL;
+ else if (field == "random")
+ Options.priest = GOD_RANDOM;
+ }
+ else if (key == "fire_items_start")
+ {
+ if (isalpha( field[0] ))
+ Options.fire_items_start = letter_to_index( field[0] );
+ else
+ {
+ fprintf( stderr, "Bad fire item start index -- %s\n",
+ field.c_str() );
+ }
+ }
+ else if (key == "fire_order")
+ {
+ str_to_fire_order( field, Options.fire_order );
+ }
+ else if (key == "random_pick")
+ {
+ // randomly generate character
+ Options.random_pick = read_bool( field, Options.random_pick );
+ }
+ else if (key == "hp_warning")
+ {
+ Options.hp_warning = atoi( field.c_str() );
+ if (Options.hp_warning < 0 || Options.hp_warning > 100)
+ {
+ Options.hp_warning = 0;
+ fprintf( stderr, "Bad HP warning percentage -- %s\n",
+ field.c_str() );
+ }
+ }
+ else if (key == "hp_attention")
+ {
+ Options.hp_attention = atoi( field.c_str() );
+ if (Options.hp_attention < 0 || Options.hp_attention > 100)
+ {
+ Options.hp_attention = 0;
+ fprintf( stderr, "Bad HP attention percentage -- %s\n",
+ field.c_str() );
+ }
+ }
+ else if (key == "crawl_dir")
+ {
+ // We shouldn't bother to allocate this a second time
+ // if the user puts two crawl_dir lines in the init file.
+ if (!SysEnv.crawl_dir)
+ SysEnv.crawl_dir = (char *) calloc(kPathLen, sizeof(char));
+
+ if (SysEnv.crawl_dir)
+ {
+ strncpy(SysEnv.crawl_dir, field.c_str(), kNameLen - 1);
+ SysEnv.crawl_dir[ kNameLen - 1 ] = '\0';
+ }
+ }
+ else if (key == "race")
+ {
+ Options.race = str_to_race( field );
+
+ if (Options.race == '\0')
+ fprintf( stderr, "Unknown race choice: %s\n", field.c_str() );
+ }
+ else if (key == "class")
+ {
+ Options.cls = str_to_class( field );
+
+ if (Options.cls == '\0')
+ fprintf( stderr, "Unknown class choice: %s\n", field.c_str() );
+ }
+ else if (key == "auto_list")
+ {
+ Options.auto_list = read_bool( field, Options.auto_list );
+ }
+ else if (key == "delay_message_clear")
+ {
+ Options.delay_message_clear = read_bool( field, Options.delay_message_clear );
+ }
+ else if (key == "terse_hand")
+ {
+ Options.terse_hand = read_bool( field, Options.terse_hand );
+ }
+ else if (key == "flush")
+ {
+ if (subkey == "failure")
+ {
+ Options.flush_input[FLUSH_ON_FAILURE]
+ = read_bool(field, Options.flush_input[FLUSH_ON_FAILURE]);
+ }
+ else if (subkey == "command")
+ {
+ Options.flush_input[FLUSH_BEFORE_COMMAND]
+ = read_bool(field, Options.flush_input[FLUSH_BEFORE_COMMAND]);
+ }
+ else if (subkey == "message")
+ {
+ Options.flush_input[FLUSH_ON_MESSAGE]
+ = read_bool(field, Options.flush_input[FLUSH_ON_MESSAGE]);
+ }
+ }
+ else if (key == "lowercase_invocations")
+ {
+ Options.lowercase_invocations
+ = read_bool(field, Options.lowercase_invocations);
+ }
+ else if (key == "wiz_mode")
+ {
+ // wiz_mode is recognized as a legal key in all compiles -- bwr
+#ifdef WIZARD
+ if (field == "never")
+ Options.wiz_mode = WIZ_NEVER;
+ else if (field == "no")
+ Options.wiz_mode = WIZ_NO;
+ else if (field == "yes")
+ Options.wiz_mode = WIZ_YES;
+ else
+ fprintf(stderr, "Unknown wiz_mode option: %s\n", field.c_str());
+#endif
+ }
+ }
+
+ fclose(f);
+} // end read_init_file()
+
+void get_system_environment(void)
+{
+ // The player's name
+ SysEnv.crawl_name = getenv("CRAWL_NAME");
+
+ // The player's pizza
+ SysEnv.crawl_pizza = getenv("CRAWL_PIZZA");
+
+ // The directory which contians init.txt, macro.txt, morgue.txt
+ // This should end with the appropriate path delimiter.
+ SysEnv.crawl_dir = getenv("CRAWL_DIR");
+
+ // The full path to the init file -- this over-rides CRAWL_DIR
+ SysEnv.crawl_rc = getenv("CRAWL_RC");
+
+ // rename giant and giant spiked clubs
+ SysEnv.board_with_nail = (getenv("BOARD_WITH_NAIL") != NULL);
+
+#ifdef MULTIUSER
+ // The user's home directory (used to look for ~/.crawlrc file)
+ SysEnv.home = getenv("HOME");
+#endif
+} // end get_system_environment()
+
+
+// parse args, filling in Options and game environment as we go.
+// returns true if no unknown or malformed arguments were found.
+
+static const char *cmd_ops[] = { "scores", "name", "race", "class",
+ "pizza", "plain", "dir", "rc", "tscores",
+ "vscores" };
+
+const int num_cmd_ops = 10;
+bool arg_seen[num_cmd_ops];
+
+bool parse_args( int argc, char **argv, bool rc_only )
+{
+ if (argc < 2) // no args!
+ return (true);
+
+ char *arg, *next_arg;
+ int current = 1;
+ bool nextUsed = false;
+ int ecount;
+
+ // initialize
+ for(int i=0; i<num_cmd_ops; i++)
+ arg_seen[i] = false;
+
+ while(current < argc)
+ {
+ // get argument
+ arg = argv[current];
+
+ // next argument (if there is one)
+ if (current+1 < argc)
+ next_arg = argv[current+1];
+ else
+ next_arg = NULL;
+
+ nextUsed = false;
+
+ // arg MUST begin with '-' or '/'
+ char c = arg[0];
+ if (c != '-' && c != '/')
+ return (false);
+
+ // look for match (now we also except --scores)
+ if (arg[1] == '-')
+ arg = &arg[2];
+ else
+ arg = &arg[1];
+
+ int o;
+ for(o = 0; o < num_cmd_ops; o++)
+ {
+ if (stricmp(cmd_ops[o], arg) == 0)
+ break;
+ }
+
+ if (o == num_cmd_ops)
+ return (false);
+
+ // disallow options specified more than once.
+ if (arg_seen[o] == true)
+ return (false);
+
+ // set arg to 'seen'
+ arg_seen[o] = true;
+
+ // partially parse next argument
+ bool next_is_param = false;
+ if (next_arg != NULL)
+ {
+ if (next_arg[0] != '-' && next_arg[0] != '/')
+ next_is_param = true;
+ }
+
+ //.take action according to the cmd chosen
+ switch(o)
+ {
+ case 0: // scores
+ case 8: // tscores
+ case 9: // vscores
+ if (!next_is_param)
+ ecount = SCORE_FILE_ENTRIES; // default
+ else // optional number given
+ {
+ ecount = atoi(next_arg);
+ if (ecount < 1)
+ ecount = 1;
+
+ if (ecount > SCORE_FILE_ENTRIES)
+ ecount = SCORE_FILE_ENTRIES;
+
+ nextUsed = true;
+ }
+
+ if (!rc_only)
+ {
+ Options.sc_entries = ecount;
+
+ if (o == 8)
+ Options.sc_format = SCORE_TERSE;
+ else if (o == 9)
+ Options.sc_format = SCORE_VERBOSE;
+
+ }
+ break;
+
+ case 1: // name
+ if (!next_is_param)
+ return (false);
+
+ if (!rc_only)
+ {
+ strncpy(you.your_name, next_arg, kNameLen);
+ you.your_name[ kNameLen - 1 ] = '\0';
+ }
+
+ nextUsed = true;
+ break;
+
+ case 2: // race
+ case 3: // class
+ if (!next_is_param)
+ return (false);
+
+ // if (strlen(next_arg) != 1)
+ // return (false);
+
+ if (!rc_only)
+ {
+ if (o == 2)
+ Options.race = str_to_race( std::string( next_arg ) );
+
+ if (o == 3)
+ Options.cls = str_to_class( std::string( next_arg ) );
+ }
+ nextUsed = true;
+ break;
+
+ case 4: // pizza
+ if (!next_is_param)
+ return (false);
+
+ if (!rc_only)
+ SysEnv.crawl_pizza = next_arg;
+
+ nextUsed = true;
+ break;
+
+ case 5: // plain
+ if (next_is_param)
+ return (false);
+
+ if (!rc_only)
+ {
+ viewwindow = &viewwindow3;
+ mapch = &mapchar3;
+ mapch2 = &mapchar4;
+#ifdef LINUX
+ character_set = 0;
+#endif
+ }
+ break;
+
+ case 6: // dir
+ // ALWAYS PARSE
+ if (!next_is_param)
+ return (false);
+
+ SysEnv.crawl_dir = next_arg;
+ nextUsed = true;
+ break;
+
+ case 7:
+ // ALWAYS PARSE
+ if (!next_is_param)
+ return (false);
+
+ SysEnv.crawl_rc = next_arg;
+ nextUsed = true;
+ break;
+ } // end switch -- which option?
+
+ // update position
+ current++;
+ if (nextUsed)
+ current++;
+ }
+
+ return (true);
+}
diff --git a/trunk/source/initfile.h b/trunk/source/initfile.h
new file mode 100644
index 0000000000..6b641eb523
--- /dev/null
+++ b/trunk/source/initfile.h
@@ -0,0 +1,40 @@
+/*
+ * File: initfile.h
+ * Summary: Simple reading of init file.
+ * Written by: David Loewenstern
+ *
+ * Change History (most recent first):
+ *
+ * <1> 6/9/99 DML Created
+ */
+
+
+#ifndef INITFILE_H
+#define INITFILE_H
+
+#include <string>
+
+std::string & trim_string( std::string &str );
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void read_init_file(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void get_system_environment(void);
+
+
+// last updated 16feb2001 {gdl}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+bool parse_args(int argc, char **argv, bool rc_only);
+
+
+#endif
diff --git a/trunk/source/insult.cc b/trunk/source/insult.cc
new file mode 100644
index 0000000000..1e8c629ab9
--- /dev/null
+++ b/trunk/source/insult.cc
@@ -0,0 +1,672 @@
+// insult generator
+// Josh Fishman (c) 2001, All Rights Reserved
+// This file is released under the GNU GPL, but special permission is granted
+// to link with Linley Henzel's Dungeon Crawl (or Crawl) without change to
+// Crawl's license.
+//
+// The goal of this stuff is catachronistic feel.
+
+#include "AppHdr.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "externs.h"
+#include "insult.h"
+#include "mon-util.h"
+#include "stuff.h"
+
+static const char* insults1(void);
+static const char* insults2(void);
+static const char* insults3(void);
+static const char* run_away(void);
+static const char* give_up(void);
+static const char* meal(void);
+static const char* whilst_thou_can(void);
+static const char* important_body_part(void);
+static const char* important_spiritual_part(void);
+
+static void init_cap(char *);
+
+void init_cap(char * str)
+{
+ if (str != NULL)
+ str[0] = toupper( str[0] );
+}
+
+void imp_taunt( struct monsters *mons )
+{
+ char buff[80];
+ const char *mon_name = ptr_monam( mons, DESC_CAP_THE );
+
+ snprintf( buff, sizeof(buff),
+ "%s, thou %s!",
+ random2(7) ? run_away() : give_up(),
+ generic_insult() );
+
+ init_cap( buff );
+
+ // XXX: Not pretty, but stops truncation...
+ if (strlen( mon_name ) + 11 + strlen( buff ) >= 79)
+ {
+ snprintf( info, INFO_SIZE, "%s shouts:", mon_name );
+ mpr( info, MSGCH_TALK );
+
+ mpr( buff, MSGCH_TALK );
+ }
+ else
+ {
+ snprintf( info, INFO_SIZE, "%s shouts, \"%s\"", mon_name, buff );
+ mpr( info, MSGCH_TALK );
+ }
+}
+
+void demon_taunt( struct monsters *mons )
+{
+ static const char * sound_list[] =
+ {
+ "says", // actually S_SILENT
+ "shouts",
+ "barks",
+ "shouts",
+ "roars",
+ "screams",
+ "bellows",
+ "screeches",
+ "buzzes",
+ "moans",
+ "whines",
+ "croaks",
+ "growls",
+ };
+
+ char buff[80];
+ const char *mon_name = ptr_monam( mons, DESC_CAP_THE );
+ const char *voice = sound_list[ mons_shouts(mons->type) ];
+
+ if (coinflip())
+ {
+ snprintf( buff, sizeof(buff),
+ "%s, thou %s!",
+ random2(3) ? give_up() : run_away(),
+ generic_insult() );
+ }
+ else
+ {
+ switch( random2( 4 ) )
+ {
+ case 0:
+ snprintf( buff, sizeof(buff),
+ "Thy %s shall be my %s!",
+ random2(4) ? important_body_part()
+ : important_spiritual_part(), meal() );
+ break;
+ case 1:
+ snprintf( buff, sizeof(buff),
+ "%s, thou tasty %s!", give_up(), meal() );
+ break;
+ case 2:
+ snprintf( buff, sizeof(buff),
+ "%s %s!", run_away(), whilst_thou_can() );
+ break;
+ case 3:
+ snprintf( buff, sizeof(buff),
+ "I %s %s thy %s!",
+ coinflip() ? "will" : "shall",
+ coinflip() ? "feast upon" : "devour",
+ random2(4) ? important_body_part()
+ : important_spiritual_part() );
+ break;
+ default:
+ snprintf( buff, sizeof(buff), "Thou %s!", generic_insult() );
+ break;
+ }
+ }
+
+ init_cap( buff );
+
+ // XXX: Not pretty, but stops truncation...
+ if (strlen(mon_name) + strlen(voice) + strlen(buff) + 5 >= 79)
+ {
+ snprintf( info, INFO_SIZE, "%s %s:", mon_name, voice );
+ mpr( info, MSGCH_TALK );
+
+ mpr( buff, MSGCH_TALK );
+ }
+ else
+ {
+ snprintf( info, INFO_SIZE, "%s %s, \"%s\"", mon_name, voice, buff );
+ mpr( info, MSGCH_TALK );
+ }
+}
+
+const char * generic_insult(void)
+{
+ static char buffer[80]; //FIXME: use string objects or whatnot
+
+ strcpy(buffer, insults1());
+ strcat(buffer, " ");
+ strcat(buffer, insults2());
+ strcat(buffer, " ");
+ strcat(buffer, insults3());
+
+ return (buffer);
+}
+
+static const char * important_body_part(void)
+{
+ static const char * part_list[] = {
+ "head",
+ "brain",
+ "heart",
+ "viscera",
+ "eyes",
+ "lungs",
+ "liver",
+ "throat",
+ "neck",
+ "skull",
+ "spine",
+ };
+
+ return (part_list[random2(sizeof(part_list) / sizeof(char *))]);
+}
+
+static const char * important_spiritual_part(void)
+{
+ static const char * part_list[] = {
+ "soul",
+ "spirit",
+ "inner light",
+ "hope",
+ "faith",
+ "will",
+ "heart",
+ "mind",
+ "sanity",
+ "fortitude",
+ "life force",
+ };
+
+ return (part_list[random2(sizeof(part_list) / sizeof(char *))]);
+}
+
+static const char * meal(void)
+{
+ static const char * meal_list[] = {
+ "meal",
+ "breakfast",
+ "lunch",
+ "dinner",
+ "supper",
+ "repast",
+ "snack",
+ "victuals",
+ "refection",
+ "junket",
+ "luncheon",
+ "snackling",
+ "curdle",
+ "snacklet",
+ "mouthful",
+ };
+
+ return (meal_list[random2(sizeof(meal_list) / sizeof(char *))]);
+}
+
+static const char * run_away(void)
+{
+ static const char * run_away_list[] = {
+ "give up",
+ "quit",
+ "run away",
+ "escape",
+ "flee",
+ "fly",
+ "take thy face hence",
+ "remove thy stench",
+ "go and return not",
+ "get thee hence",
+ "back with thee",
+ "away with thee",
+ "turn tail",
+ "leave",
+ "return whence thou came",
+ "begone",
+ "get thee gone",
+ "get thee hence",
+ "slither away",
+ "slither home",
+ "slither hence",
+ "crawl home",
+ "scamper home",
+ "scamper hence",
+ "scamper away",
+ "bolt",
+ "decamp",
+ };
+
+ return (run_away_list[random2(sizeof(run_away_list) / sizeof(char *))]);
+}
+
+static const char * give_up(void)
+{
+ static const char * give_up_list[] = {
+ "give up",
+ "give in",
+ "quit",
+ "surrender",
+ "kneel",
+ "beg for mercy",
+ "despair",
+ "submit",
+ "succumb",
+ "quail",
+ "embrace thy failure",
+ "embrace thy fall",
+ "embrace thy doom",
+ "embrace thy dedition",
+ "embrace submission",
+ "accept thy failure",
+ "accept thy fall",
+ "accept thy doom",
+ "capitulate",
+ "tremble",
+ "relinquish hope",
+ "taste defeat",
+ "despond",
+ "disclaim thyself",
+ "abandon hope",
+ "face thy requiem",
+ "face thy fugue",
+ "admit defeat",
+ "flounder",
+ };
+
+ return (give_up_list[random2(sizeof(give_up_list) / sizeof(char *))]);
+}
+
+static const char * whilst_thou_can(void)
+{
+ static const char * threat_list[] = {
+ "whilst thou can",
+ "whilst thou may",
+ "whilst thou are able",
+ "if wit thou hast",
+ "whilst thy luck holds",
+ "before doom catcheth thee",
+ "lest death find thee",
+ "whilst thou art whole",
+ "whilst life thou hast", //jmf: hmm. screen vs. this for undead?
+ };
+
+ return (threat_list[random2(sizeof(threat_list) / sizeof(char *))]);
+}
+
+static const char * insults1(void)
+{
+ static const char * insults1_list[] = {
+ "artless",
+ "baffled",
+ "bawdy",
+ "beslubbering",
+ "bootless",
+ "bumbling",
+ "canting",
+ "churlish",
+ "cockered",
+ "clouted",
+ "craven",
+ "currish",
+ "dankish",
+ "dissembling",
+ "droning",
+ "ducking",
+ "errant",
+ "fawning",
+ "feckless",
+ "feeble",
+ "fobbing",
+ "foppish",
+ "froward",
+ "frothy",
+ "fulsome",
+ "gleeking",
+ "goatish",
+ "gorbellied",
+ "grime-gilt",
+ "horrid",
+ "hateful",
+ "impertinent",
+ "infectious",
+ "jarring",
+ "loggerheaded",
+ "lumpish",
+ "mammering",
+ "mangled",
+ "mewling",
+ "odious",
+ "paunchy",
+ "pribbling",
+ "puking",
+ "puny",
+ "qualling",
+ "quaking",
+ "rank",
+ "pandering",
+ "pecksniffian",
+ "plume-plucked",
+ "pottle-deep",
+ "pox-marked",
+ "reeling-ripe",
+ "rough-hewn",
+ "simpering",
+ "spongy",
+ "surly",
+ "tottering",
+ "twisted",
+ "unctious",
+ "unhinged",
+ "unmuzzled",
+ "vain",
+ "venomed",
+ "villainous",
+ "warped",
+ "wayward",
+ "weedy",
+ "worthless",
+ "yeasty",
+ };
+
+ return (insults1_list[random2(sizeof(insults1_list) / sizeof(char*))]);
+}
+
+static const char * insults2(void)
+{
+ static const char * insults2_list[] = {
+ "base-court",
+ "bat-fowling",
+ "beef-witted",
+ "beetle-headed",
+ "boil-brained",
+ "clapper-clawed",
+ "clay-brained",
+ "common-kissing",
+ "crook-pated",
+ "dismal-dreaming",
+ "ditch-delivered",
+ "dizzy-eyed",
+ "doghearted",
+ "dread-bolted",
+ "earth-vexing",
+ "elf-skinned",
+ "fat-kidneyed",
+ "fen-sucked",
+ "flap-mouthed",
+ "fly-bitten",
+ "folly-fallen",
+ "fool-born",
+ "full-gorged",
+ "guts-griping",
+ "half-faced",
+ "hasty-witted",
+ "hedge-born",
+ "hell-hated",
+ "idle-headed",
+ "ill-breeding",
+ "ill-nurtured",
+ "kobold-kissing",
+ "knotty-pated",
+ "limp-willed",
+ "milk-livered",
+ "moon-mazed",
+ "motley-minded",
+ "onion-eyed",
+ "miscreant",
+ "roguish",
+ "moldwarp",
+ "ruttish",
+ "mumble-news",
+ "saucy",
+ "nut-hook",
+ "spleeny",
+ "pigeon-egg",
+ "rude-growing",
+ "rump-fed",
+ "shard-borne",
+ "sheep-biting",
+ "sow-suckled",
+ "spur-galled",
+ "swag-bellied",
+ "tardy-gaited",
+ "tickle-brained",
+ "toad-spotted",
+ "toenail-biting",
+ "unchin-snouted",
+ "weather-bitten",
+ "weevil-witted",
+ };
+
+ return (insults2_list[random2(sizeof(insults2_list) / sizeof(char*))]);
+}
+
+static const char * insults3(void)
+{
+ static const char * insults3_list[] = {
+ "apple-john",
+ "baggage",
+ "bandersnitch",
+ "barnacle",
+ "beggar",
+ "bladder",
+ "boar-pig",
+ "bounder",
+ "bugbear",
+ "bum-bailey",
+ "canker-blossom",
+ "clack-dish",
+ "clam",
+ "clotpole",
+ "coxcomb",
+ "codpiece",
+ "death-token",
+ "dewberry",
+ "dingleberry",
+ "flap-bat",
+ "flax-wench",
+ "flirt-gill",
+ "foot-licker",
+ "fustilarian",
+ "giglet",
+ "gnoll-tail",
+ "gudgeon",
+ "guttersnipe",
+ "haggard",
+ "harpy",
+ "hedge-pig",
+ "horn-beast",
+ "hugger-mugger",
+ "joithead",
+ "lewdster",
+ "lout",
+ "maggot-pie",
+ "malt-worm",
+ "mammet",
+ "measle",
+ "mendicant",
+ "minnow reeky",
+ "mule",
+ "nightsoil",
+ "nobody",
+ "nothing",
+ "pigeon-egg",
+ "pignut",
+ "pimple",
+ "pustule",
+ "puttock",
+ "pumpion",
+ "ratsbane",
+ "scavenger",
+ "scut",
+ "serf",
+ "simpleton",
+ "skainsmate",
+ "slime mold",
+ "snaffler",
+ "snake-molt",
+ "strumpet",
+ "surfacer",
+ "tinkerer",
+ "tiddler",
+ "urchin",
+ "varlet",
+ "vassal",
+ "vulture",
+ "wastrel",
+ "wagtail",
+ "whey-face",
+ "wormtrail",
+ "yak-dropping",
+ "zombie-fodder",
+ };
+
+ return (insults3_list[random2(sizeof(insults3_list) / sizeof(char*))]);
+}
+
+// currently unused:
+#if 0
+const char * racial_insult(void)
+{
+ static const char * food3[] = {
+ "snackling",
+ "crunchlet",
+ "half-meal",
+ "supper-setting",
+ "snacklet",
+ "noshlet",
+ "morsel",
+ "mug-up",
+ "bite-bait",
+ "crunch-chow",
+ "snack-pap",
+ "grub",
+ };
+
+ static const char * elf1[] = {
+ "weakly",
+ "sickly",
+ "frail",
+ "delicate",
+ "fragile",
+ "brittle",
+ "tender",
+ "mooning",
+ "painted",
+ "lily-hearted",
+ "dandy",
+ "featherweight",
+ "flimsy",
+ "rootless",
+ "spindly",
+ "puny",
+ "shaky",
+ "prissy",
+ };
+
+ static const char * halfling3[] = {
+ "half-pint",
+ "footstool",
+ "munchkin",
+ "side-stool",
+ "pudgelet",
+ "groundling",
+ "burrow-snipe",
+ "hole-bolter",
+ "low-roller",
+ "runt",
+ "peewee",
+ "mimicus",
+ "manikin",
+ "hop-o-thumb",
+ "knee-biter",
+ "burrow-botch",
+ "hole-pimple",
+ "hovel-pustule",
+ };
+
+ static const char * spriggan3[] = {
+ "rat-rider",
+ "mouthfull",
+ "quarter-pint",
+ "nissette",
+ "fizzle-flop",
+ "spell-botch",
+ "feeblet",
+ "weakling",
+ "pinchbeck-pixie",
+ "ankle-biter",
+ "bootstain",
+ "nano-nebbish",
+ "sopling",
+ "shrunken violet",
+ "sissy-prig",
+ "pussyfoot",
+ "creepsneak",
+ };
+
+ static const char * dwarf2[] = {
+ "dirt-grubbing",
+ "grit-sucking",
+ "muck-plodding",
+ "stone-broke",
+ "pelf-dandling",
+ "fault-botching",
+ "gravel-groveling",
+ "boodle-bothering",
+ "cabbage-coddling",
+ "rhino-raveling",
+ "thigh-biting",
+ "dirt-delving",
+ };
+
+ static const char * kenku2[] = {
+ "hollow-boned",
+ "feather-brained",
+ "beak-witted",
+ "hen-pecked",
+ "lightweight",
+ "frail-limbed",
+ "bird-brained",
+ "featherweight",
+ "pigeon-toed",
+ "crow-beaked",
+ "magpie-eyed",
+ "mallardish",
+ };
+
+ static const char * minotaur3[] = {
+ "bull-brain",
+ "cud-chewer",
+ "calf-wit",
+ "bovine",
+ //"mooer", // of Venice
+ "cow",
+ "cattle",
+ "meatloaf",
+ "veal",
+ "meatball",
+ "rump-roast",
+ "briscut",
+ "cretin",
+ "walking sirloin",
+ };
+
+ switch (you.species)
+ {
+ default:
+ break;
+ }
+}
+#endif
diff --git a/trunk/source/insult.h b/trunk/source/insult.h
new file mode 100644
index 0000000000..143d0ecae3
--- /dev/null
+++ b/trunk/source/insult.h
@@ -0,0 +1,11 @@
+#ifndef INSULT_H
+#define INSULT_H
+
+#include "externs.h"
+
+void imp_taunt( struct monsters *mons );
+void demon_taunt( struct monsters *mons );
+const char * generic_insult(void);
+const char * racial_insult(void);
+
+#endif
diff --git a/trunk/source/invent.cc b/trunk/source/invent.cc
new file mode 100644
index 0000000000..1a6db7d1bc
--- /dev/null
+++ b/trunk/source/invent.cc
@@ -0,0 +1,631 @@
+/*
+ * File: invent.cc
+ * Summary: Functions for inventory related commands.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <5> 10/9/99 BCR Added wizard help screen
+ * <4> 10/1/99 BCR Clarified help screen
+ * <3> 6/9/99 DML Autopickup
+ * <2> 5/20/99 BWR Extended screen lines support
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "invent.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#include "externs.h"
+
+#include "itemname.h"
+#include "items.h"
+#include "macro.h"
+#include "player.h"
+#include "shopping.h"
+#include "stuff.h"
+#include "view.h"
+
+
+const char *command_string( int i );
+const char *wizard_string( int i );
+
+unsigned char get_invent( int invent_type )
+{
+ unsigned char nothing = invent( invent_type, false );
+
+ redraw_screen();
+
+ return (nothing);
+} // end get_invent()
+
+unsigned char invent( int item_class_inv, bool show_price )
+{
+ char st_pass[ ITEMNAME_SIZE ] = "";
+
+ int i, j;
+ char lines = 0;
+ unsigned char anything = 0;
+ char tmp_quant[20] = "";
+ char yps = 0;
+ char temp_id[4][50];
+
+ const int num_lines = get_number_of_lines();
+
+ FixedVector< int, NUM_OBJECT_CLASSES > inv_class2;
+ int inv_count = 0;
+ unsigned char ki = 0;
+
+#ifdef DOS_TERM
+ char buffer[4600];
+
+ gettext(1, 1, 80, 25, buffer);
+ window(1, 1, 80, 25);
+#endif
+
+ for (i = 0; i < 4; i++)
+ {
+ for (j = 0; j < 50; j++)
+ {
+ temp_id[i][j] = 1;
+ }
+ }
+
+ clrscr();
+
+ for (i = 0; i < NUM_OBJECT_CLASSES; i++)
+ inv_class2[i] = 0;
+
+ for (i = 0; i < ENDOFPACK; i++)
+ {
+ if (you.inv[i].quantity)
+ {
+ inv_class2[ you.inv[i].base_type ]++;
+ inv_count++;
+ }
+ }
+
+ if (!inv_count)
+ {
+ cprintf("You aren't carrying anything.");
+
+ if (getch() == 0)
+ getch();
+
+ goto putty;
+ }
+
+ if (item_class_inv != -1)
+ {
+ for (i = 0; i < NUM_OBJECT_CLASSES; i++)
+ {
+ if (item_class_inv == OBJ_MISSILES && i == OBJ_WEAPONS)
+ i++;
+
+ if (item_class_inv == OBJ_WEAPONS
+ && (i == OBJ_STAVES || i == OBJ_MISCELLANY))
+ {
+ i++;
+ }
+
+ if (item_class_inv == OBJ_SCROLLS && i == OBJ_BOOKS)
+ i++;
+
+ if (i < NUM_OBJECT_CLASSES && item_class_inv != i)
+ inv_class2[i] = 0;
+ }
+ }
+
+ if ((item_class_inv == -1 && inv_count > 0)
+ || (item_class_inv != -1 && inv_class2[item_class_inv] > 0)
+ || (item_class_inv == OBJ_MISSILES && inv_class2[OBJ_WEAPONS] > 0)
+ || (item_class_inv == OBJ_WEAPONS
+ && (inv_class2[OBJ_STAVES] > 0 || inv_class2[OBJ_MISCELLANY] > 0))
+ || (item_class_inv == OBJ_SCROLLS && inv_class2[OBJ_BOOKS] > 0))
+ {
+ const int cap = carrying_capacity();
+
+ cprintf( " Inventory: %d.%d aum (%d%% of %d.%d aum maximum)",
+ you.burden / 10, you.burden % 10,
+ (you.burden * 100) / cap, cap / 10, cap % 10 );
+ lines++;
+
+ for (i = 0; i < 15; i++)
+ {
+ if (inv_class2[i] != 0)
+ {
+ if (lines > num_lines - 3)
+ {
+ gotoxy(1, num_lines);
+ cprintf("-more-");
+
+ ki = getch();
+
+ if (ki == ESCAPE)
+ {
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+#endif
+ return (ESCAPE);
+ }
+ else if (isalpha(ki) || ki == '?' || ki == '*')
+ {
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+#endif
+ return (ki);
+ }
+
+ if (ki == 0)
+ ki = getch();
+
+ lines = 0;
+ clrscr();
+ gotoxy(1, 1);
+ anything = 0;
+
+ }
+
+ if (lines > 0)
+ cprintf(EOL " ");
+
+ textcolor(BLUE);
+
+ switch (i)
+ {
+ case OBJ_WEAPONS: cprintf("Hand Weapons"); break;
+ case OBJ_MISSILES: cprintf("Missiles"); break;
+ case OBJ_ARMOUR: cprintf("Armour"); break;
+ case OBJ_WANDS: cprintf("Magical Devices"); break;
+ case OBJ_FOOD: cprintf("Comestibles"); break;
+ case OBJ_UNKNOWN_I: cprintf("Books"); break;
+ case OBJ_SCROLLS: cprintf("Scrolls"); break;
+ case OBJ_JEWELLERY: cprintf("Jewellery"); break;
+ case OBJ_POTIONS: cprintf("Potions"); break;
+ case OBJ_UNKNOWN_II: cprintf("Gems"); break;
+ case OBJ_BOOKS: cprintf("Books"); break;
+ case OBJ_STAVES: cprintf("Magical Staves and Rods"); break;
+ case OBJ_ORBS: cprintf("Orbs of Power"); break;
+ case OBJ_MISCELLANY: cprintf("Miscellaneous"); break;
+ case OBJ_CORPSES: cprintf("Carrion"); break;
+ //case OBJ_GEMSTONES: cprintf("Miscellaneous"); break;
+ }
+
+ textcolor(LIGHTGREY);
+ lines++;
+
+ for (j = 0; j < ENDOFPACK; j++)
+ {
+ if (lines > num_lines - 2 && inv_count > 0)
+ {
+ gotoxy(1, num_lines);
+ cprintf("-more-");
+ ki = getch();
+
+ if (ki == ESCAPE)
+ {
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+#endif
+ return (ESCAPE);
+ }
+ else if (isalpha(ki) || ki == '?' || ki == '*')
+ {
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+#endif
+ return (ki);
+ }
+
+ if (ki == 0)
+ ki = getch();
+
+ lines = 0;
+ clrscr();
+ gotoxy(1, 1);
+ anything = 0;
+ }
+
+ if (is_valid_item(you.inv[j]) && you.inv[j].base_type==i)
+ {
+ anything++;
+
+ if (lines > 0)
+ cprintf(EOL);
+
+ lines++;
+
+ yps = wherey();
+
+ in_name( j, DESC_INVENTORY_EQUIP, st_pass );
+ cprintf( st_pass );
+
+ inv_count--;
+
+
+ if (show_price)
+ {
+ cprintf(" (");
+
+ itoa( item_value( you.inv[j], temp_id, true ),
+ tmp_quant, 10 );
+
+ cprintf( tmp_quant );
+ cprintf( " gold)" );
+ }
+
+ if (wherey() != yps)
+ lines++;
+ }
+ } // end of j loop
+ } // end of if inv_class2
+ } // end of i loop.
+ }
+ else
+ {
+ if (item_class_inv == -1)
+ cprintf("You aren't carrying anything.");
+ else
+ {
+ if (item_class_inv == OBJ_WEAPONS)
+ cprintf("You aren't carrying any weapons.");
+ else if (item_class_inv == OBJ_MISSILES)
+ cprintf("You aren't carrying any ammunition.");
+ else
+ cprintf("You aren't carrying any such object.");
+
+ anything++;
+ }
+ }
+
+ if (anything > 0)
+ {
+ ki = getch();
+
+ if (isalpha(ki) || ki == '?' || ki == '*')
+ {
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+#endif
+ return (ki);
+ }
+
+ if (ki == 0)
+ ki = getch();
+ }
+
+ putty:
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+#endif
+
+ return (ki);
+} // end invent()
+
+
+// Reads in digits for a count and apprends then to val, the
+// return value is the character that stopped the reading.
+static unsigned char get_invent_quant( unsigned char keyin, int &quant )
+{
+ quant = keyin - '0';
+
+ for(;;)
+ {
+ keyin = get_ch();
+
+ if (!isdigit( keyin ))
+ break;
+
+ quant *= 10;
+ quant += (keyin - '0');
+
+ if (quant > 9999999)
+ {
+ quant = 9999999;
+ keyin = '\0';
+ break;
+ }
+ }
+
+ return (keyin);
+}
+
+
+// This function prompts the user for an item, handles the '?' and '*'
+// listings, and returns the inventory slot to the caller (which if
+// must_exist is true (the default) will be an assigned item, with
+// a positive quantity.
+//
+// It returns PROMPT_ABORT if the player hits escape.
+// It returns PROMPT_GOT_SPECIAL if the player hits the "other_valid_char".
+//
+// Note: This function never checks if the item is appropriate.
+int prompt_invent_item( const char *prompt, int type_expect,
+ bool must_exist, bool allow_auto_list,
+ bool allow_easy_quit,
+ const char other_valid_char,
+ int *const count )
+{
+ unsigned char keyin = 0;
+ int ret = -1;
+
+ bool need_redraw = false;
+ bool need_prompt = true;
+ bool need_getch = true;
+
+ if (Options.auto_list && allow_auto_list)
+ {
+ // pretend the player has hit '?' and setup state.
+ keyin = invent( type_expect, false );
+
+ need_getch = false;
+
+ // Don't redraw if we're just going to display another listing
+ need_redraw = (keyin != '?' && keyin != '*');
+
+ // A prompt is nice for when we're moving to "count" mode.
+ need_prompt = (count != NULL && isdigit( keyin ));
+ }
+
+ for (;;)
+ {
+ if (need_redraw)
+ {
+ redraw_screen();
+ mesclr( true );
+ }
+
+ if (need_prompt)
+ mpr( prompt, MSGCH_PROMPT );
+
+ if (need_getch)
+ keyin = get_ch();
+
+ need_redraw = false;
+ need_prompt = true;
+ need_getch = true;
+
+ // Note: We handle any "special" character first, so that
+ // it can be used to override the others.
+ if (other_valid_char != '\0' && keyin == other_valid_char)
+ {
+ ret = PROMPT_GOT_SPECIAL;
+ break;
+ }
+ else if (keyin == '?' || keyin == '*')
+ {
+ // The "view inventory listing" mode.
+ if (keyin == '*')
+ keyin = invent( -1, false );
+ else
+ keyin = invent( type_expect, false );
+
+ need_getch = false;
+
+ // Don't redraw if we're just going to display another listing
+ need_redraw = (keyin != '?' && keyin != '*');
+
+ // A prompt is nice for when we're moving to "count" mode.
+ need_prompt = (count != NULL && isdigit( keyin ));
+ }
+ else if (count != NULL && isdigit( keyin ))
+ {
+ // The "read in quantity" mode
+ keyin = get_invent_quant( keyin, *count );
+
+ need_prompt = false;
+ need_getch = false;
+ }
+ else if (keyin == ESCAPE
+ || (Options.easy_quit_item_prompts
+ && allow_easy_quit
+ && keyin == ' '))
+ {
+ ret = PROMPT_ABORT;
+ break;
+ }
+ else if (isalpha( keyin ))
+ {
+ ret = letter_to_index( keyin );
+
+ if (must_exist && !is_valid_item( you.inv[ret] ))
+ mpr( "You do not have any such object." );
+ else
+ break;
+ }
+ else if (!isspace( keyin ))
+ {
+ // we've got a character we don't understand...
+ canned_msg( MSG_HUH );
+ }
+ }
+
+ return (ret);
+}
+
+void list_commands(bool wizard)
+{
+ const char *line;
+ int j = 0;
+
+#ifdef DOS_TERM
+ char buffer[4800];
+
+ window(1, 1, 80, 25);
+ gettext(1, 1, 80, 25, buffer);
+#endif
+
+ clrscr();
+
+ // BCR - Set to screen length - 1 to display the "more" string
+ int moreLength = (get_number_of_lines() - 1) * 2;
+
+ for (int i = 0; i < 500; i++)
+ {
+ if (wizard)
+ line = wizard_string( i );
+ else
+ line = command_string( i );
+
+ if (strlen( line ) != 0)
+ {
+ // BCR - If we've reached the end of the screen, clear
+ if (j == moreLength)
+ {
+ gotoxy(2, j / 2 + 1);
+ cprintf("More...");
+ getch();
+ clrscr();
+ j = 0;
+ }
+
+ gotoxy( ((j % 2) ? 40 : 2), ((j / 2) + 1) );
+ cprintf( line );
+
+ j++;
+ }
+ }
+
+ getch();
+
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+#endif
+
+ return;
+} // end list_commands()
+
+const char *wizard_string( int i )
+{
+ UNUSED( i );
+
+#ifdef WIZARD
+ return((i == 10) ? "a : acquirement" :
+ (i == 13) ? "A : set all skills to level" :
+ (i == 15) ? "b : controlled blink" :
+ (i == 20) ? "B : banish yourself to the Abyss" :
+ (i == 30) ? "g : add a skill" :
+ (i == 35) ? "G : remove all monsters" :
+ (i == 40) ? "h/H : heal yourself (super-Heal)" :
+ (i == 50) ? "i/I : identify/unidentify inventory":
+ (i == 70) ? "l : make entrance to labyrinth" :
+ (i == 80) ? "m/M : create monster by number/name":
+ (i == 90) ? "o/%% : create an object" :
+ (i == 100) ? "p : make entrance to pandemonium" :
+ (i == 110) ? "x : gain an experience level" :
+ (i == 115) ? "r : change character's species" :
+ (i == 120) ? "s : gain 20000 skill points" :
+ (i == 130) ? "S : set skill to level" :
+ (i == 140) ? "t : tweak object properties" :
+ (i == 150) ? "X : Receive a gift from Xom" :
+ (i == 160) ? "z/Z : cast any spell by number/name":
+ (i == 200) ? "$ : get 1000 gold" :
+ (i == 210) ? "</> : create up/down staircase" :
+ (i == 220) ? "u/d : shift up/down one level" :
+ (i == 230) ? "~/\" : goto a level" :
+ (i == 240) ? "( : create a feature" :
+ (i == 250) ? "] : get a mutation" :
+ (i == 260) ? "[ : get a demonspawn mutation" :
+ (i == 270) ? ": : find branch" :
+ (i == 280) ? "{ : magic mapping" :
+ (i == 290) ? "^ : gain piety" :
+ (i == 300) ? "_ : gain religion" :
+ (i == 310) ? "\' : list items" :
+ (i == 320) ? "? : list wizard commands" :
+ (i == 330) ? "| : acquire all unrand artefacts" :
+ (i == 340) ? "+ : turn item into random artefact" :
+ (i == 350) ? "= : sum skill points"
+ : "");
+
+#else
+ return ("");
+#endif
+} // end wizard_string()
+
+const char *command_string( int i )
+{
+ /*
+ * BCR - Command printing, case statement
+ * Note: The numbers in this case indicate the order in which the
+ * commands will be printed out. Make sure none of these
+ * numbers is greater than 500, because that is the limit.
+ *
+ * Arranged alpha lower, alpha upper, punctuation, ctrl.
+ *
+ */
+
+ return((i == 10) ? "a : use special ability" :
+ (i == 20) ? "d(#) : drop (exact quantity of) items" :
+ (i == 30) ? "e : eat food" :
+ (i == 40) ? "f : fire first available missile" :
+ (i == 50) ? "i : inventory listing" :
+ (i == 55) ? "m : check skills" :
+ (i == 60) ? "o/c : open / close a door" :
+ (i == 65) ? "p : pray" :
+ (i == 70) ? "q : quaff a potion" :
+ (i == 80) ? "r : read a scroll or book" :
+ (i == 90) ? "s : search adjacent tiles" :
+ (i == 100) ? "t : throw/shoot an item" :
+ (i == 110) ? "v : view item description" :
+ (i == 120) ? "w : wield an item" :
+ (i == 130) ? "x : examine visible surroundings" :
+ (i == 135) ? "z : zap a wand" :
+ (i == 140) ? "A : list abilities/mutations" :
+ (i == 141) ? "C : check experience" :
+ (i == 142) ? "D : dissect a corpse" :
+ (i == 145) ? "E : evoke power of wielded item" :
+ (i == 150) ? "M : memorise a spell" :
+ (i == 155) ? "O : overview of the dungeon" :
+ (i == 160) ? "P/R : put on / remove jewellery" :
+ (i == 165) ? "Q : quit without saving" :
+ (i == 168) ? "S : save game and exit" :
+ (i == 179) ? "V : version information" :
+ (i == 200) ? "W/T : wear / take off armour" :
+ (i == 210) ? "X : examine level map" :
+ (i == 220) ? "Z : cast a spell" :
+ (i == 240) ? ",/g : pick up items" :
+ (i == 242) ? "./del: rest one turn" :
+ (i == 250) ? "</> : ascend / descend a staircase" :
+ (i == 270) ? "; : examine occupied tile" :
+ (i == 280) ? "\\ : check item knowledge" :
+#ifdef WIZARD
+ (i == 290) ? "& : invoke your Wizardly powers" :
+#endif
+ (i == 300) ? "+/- : scroll up/down [level map only]" :
+ (i == 310) ? "! : shout or command allies" :
+ (i == 325) ? "^ : describe religion" :
+ (i == 337) ? "@ : status" :
+ (i == 340) ? "# : dump character to file" :
+ (i == 350) ? "= : reassign inventory/spell letters" :
+ (i == 360) ? "\' : wield item a, or switch to b" :
+#ifdef USE_MACROS
+ (i == 380) ? "` : add macro" :
+ (i == 390) ? "~ : save macros" :
+#endif
+ (i == 400) ? "] : display worn armour" :
+ (i == 410) ? "\" : display worn jewellery" :
+ (i == 420) ? "Ctrl-P : see old messages" :
+#ifdef PLAIN_TERM
+ (i == 430) ? "Ctrl-R : Redraw screen" :
+#endif
+ (i == 440) ? "Ctrl-A : toggle autopickup" :
+ (i == 450) ? "Ctrl-X : Save game without query" :
+
+#ifdef ALLOW_DESTROY_ITEM_COMMAND
+ (i == 455) ? "Ctrl-D : Destroy inventory item" :
+#endif
+
+ (i == 460) ? "Shift & DIR : long walk" :
+ (i == 465) ? "/ DIR : long walk" :
+ (i == 470) ? "Ctrl & DIR : door; untrap; attack" :
+ (i == 475) ? "* DIR : door; untrap; attack" :
+ (i == 478) ? "Shift & 5 on keypad : rest 100 turns"
+ : "");
+} // end command_string()
diff --git a/trunk/source/invent.h b/trunk/source/invent.h
new file mode 100644
index 0000000000..2de7636200
--- /dev/null
+++ b/trunk/source/invent.h
@@ -0,0 +1,48 @@
+/*
+ * File: invent.cc
+ * Summary: Functions for inventory related commands.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef INVENT_H
+#define INVENT_H
+
+#include <stddef.h>
+
+#define PROMPT_ABORT -1
+#define PROMPT_GOT_SPECIAL -2
+
+int prompt_invent_item( const char *prompt, int type_expect,
+ bool must_exist = true,
+ bool allow_auto_list = true,
+ bool allow_easy_quit = true,
+ const char other_valid_char = '\0',
+ int *const count = NULL );
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: invent - ouch - shopping
+ * *********************************************************************** */
+unsigned char invent(int item_class_inv, bool show_price);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - command - food - item_use - items - spl-book - spells1
+ * *********************************************************************** */
+unsigned char get_invent(int invent_type);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void list_commands(bool wizard);
+
+
+#endif
diff --git a/trunk/source/it_use2.cc b/trunk/source/it_use2.cc
new file mode 100644
index 0000000000..45449716d9
--- /dev/null
+++ b/trunk/source/it_use2.cc
@@ -0,0 +1,523 @@
+/*
+ * File: it_use2.cc
+ * Summary: Functions for using wands, potions, and weapon/armour removal.4\3
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * 26jun2000 jmf added ZAP_MAGMA
+ * <4> 19mar2000 jmf Added ZAP_BACKLIGHT and ZAP_SLEEP
+ * <3> 10/1/99 BCR Changed messages for speed and
+ * made amulet resist slow up speed
+ * <2> 5/20/99 BWR Fixed bug with RAP_METABOLISM
+ * and RAP_NOISES artefacts/
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "it_use2.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "externs.h"
+
+#include "beam.h"
+#include "effects.h"
+#include "food.h"
+#include "itemname.h"
+#include "misc.h"
+#include "mutation.h"
+#include "player.h"
+#include "randart.h"
+#include "religion.h"
+#include "skills2.h"
+#include "spells2.h"
+#include "spl-cast.h"
+#include "stuff.h"
+#include "view.h"
+
+// From an actual potion, pow == 40 -- bwr
+bool potion_effect( char pot_eff, int pow )
+{
+ bool effect = true; // current behaviour is all potions id on quaffing
+
+ int new_value = 0;
+ unsigned char i;
+
+ if (pow > 150)
+ pow = 150;
+
+ switch (pot_eff)
+ {
+ case POT_HEALING:
+ mpr("You feel better.");
+ inc_hp(5 + random2(7), false);
+
+ // only fix rot when healed to full
+ if (you.hp == you.hp_max)
+ {
+ unrot_hp(1);
+ set_hp(you.hp_max, false);
+ }
+
+ you.poison = 0;
+ you.rotting = 0;
+ you.disease = 0;
+ you.conf = 0;
+ break;
+
+ case POT_HEAL_WOUNDS:
+ mpr("You feel much better.");
+ inc_hp(10 + random2avg(28, 3), false);
+
+ // only fix rot when healed to full
+ if (you.hp == you.hp_max)
+ {
+ unrot_hp( 2 + random2avg(5, 2) );
+ set_hp(you.hp_max, false);
+ }
+ break;
+
+ case POT_SPEED:
+ haste_player( 40 + random2(pow) );
+ break;
+
+ case POT_MIGHT:
+ {
+ bool were_mighty = (you.might > 0);
+
+ if (!were_mighty)
+ mpr( "You feel very mighty all of a sudden." );
+ else
+ {
+ mpr( "You still feel pretty mighty." );
+ contaminate_player(1);
+ }
+
+ // conceivable max gain of +184 {dlb}
+ you.might += 35 + random2(pow);
+
+ if (!were_mighty)
+ modify_stat(STAT_STRENGTH, 5, true);
+
+ // files.cc permits values up to 215, but ... {dlb}
+ if (you.might > 80)
+ you.might = 80;
+
+ naughty( NAUGHTY_STIMULANTS, 4 + random2(4) );
+ }
+ break;
+
+ case POT_GAIN_STRENGTH:
+ mutate(MUT_STRONG);
+ break;
+
+ case POT_GAIN_DEXTERITY:
+ mutate(MUT_AGILE);
+ break;
+
+ case POT_GAIN_INTELLIGENCE:
+ mutate(MUT_CLEVER);
+ break;
+
+ case POT_LEVITATION:
+ strcpy(info, "You feel");
+ strcat(info, (!player_is_levitating()) ? " very" : " more");
+ strcat(info, " buoyant.");
+ mpr(info);
+
+ if (!player_is_levitating())
+ mpr("You gently float upwards from the floor.");
+
+ you.levitation += 25 + random2(pow);
+
+ if (you.levitation > 100)
+ you.levitation = 100;
+
+ burden_change();
+ break;
+
+ case POT_POISON:
+ case POT_STRONG_POISON:
+ if (player_res_poison())
+ {
+ snprintf( info, INFO_SIZE, "You feel %s nauseous.",
+ (pot_eff == POT_POISON) ? "slightly" : "quite" );
+
+ mpr(info);
+ }
+ else
+ {
+ snprintf( info, INFO_SIZE, "That liquid tasted %s nasty...",
+ (pot_eff == POT_POISON) ? "very" : "extremely" );
+
+ mpr(info);
+
+ poison_player( ((pot_eff == POT_POISON) ? 1 + random2avg(5, 2)
+ : 3 + random2avg(13, 2)) );
+ }
+ break;
+
+ case POT_SLOWING:
+ slow_player( 10 + random2(pow) );
+ break;
+
+ case POT_PARALYSIS:
+ snprintf( info, INFO_SIZE, "You %s the ability to move!",
+ (you.paralysis) ? "still haven't" : "suddenly lose" );
+
+ mpr( info, MSGCH_WARN );
+
+ new_value = 2 + random2( 6 + you.paralysis );
+
+ if (new_value > you.paralysis)
+ you.paralysis = new_value;
+
+ if (you.paralysis > 13)
+ you.paralysis = 13;
+ break;
+
+ case POT_CONFUSION:
+ confuse_player( 3 + random2(8) );
+ break;
+
+ case POT_INVISIBILITY:
+ mpr( (!you.invis) ? "You fade into invisibility!"
+ : "You feel safely hidden away." );
+
+ // now multiple invisiblity casts aren't as good -- bwr
+ if (!you.invis)
+ you.invis = 15 + random2(pow);
+ else
+ you.invis += random2(pow);
+
+ if (you.invis > 100)
+ you.invis = 100;
+ break;
+
+ // carnivore check here? {dlb}
+ case POT_PORRIDGE: // oatmeal - always gluggy white/grey?
+ mpr("That potion was really gluggy!");
+ lessen_hunger(6000, true);
+ break;
+
+ case POT_DEGENERATION:
+ mpr("There was something very wrong with that liquid!");
+ lose_stat(STAT_RANDOM, 1 + random2avg(4, 2));
+ break;
+
+ // Don't generate randomly - should be rare and interesting
+ case POT_DECAY:
+ if (you.is_undead)
+ mpr( "You feel terrible." );
+ else
+ rot_player( 10 + random2(10) );
+ break;
+
+ case POT_WATER:
+ mpr("This tastes like water.");
+ // we should really separate thirst from hunger {dlb}
+ // Thirst would just be annoying for the player, the
+ // 20 points here doesn't represesent real food anyways -- bwr
+ lessen_hunger(20, true);
+ break;
+
+ case POT_EXPERIENCE:
+ if (you.experience_level < 27)
+ {
+ mpr("You feel more experienced!");
+
+ you.experience = 1 + exp_needed( 2 + you.experience_level );
+ level_change();
+ }
+ else
+ mpr("A flood of memories washes over you.");
+ break; // I'll let this slip past robe of archmagi
+
+ case POT_MAGIC:
+ mpr( "You feel magical!" );
+ new_value = 5 + random2avg(19, 2);
+
+ // increase intrinsic MP points
+ if (you.magic_points + new_value > you.max_magic_points)
+ {
+ new_value = (you.max_magic_points - you.magic_points)
+ + (you.magic_points + new_value - you.max_magic_points) / 4 + 1;
+ }
+
+ inc_mp( new_value, true );
+ break;
+
+ case POT_RESTORE_ABILITIES:
+ // messaging taken care of within function {dlb}
+ // not quite true... if no stat's are restore = no message, and
+ // that's just confusing when trying out random potions (this one
+ // still auto-identifies so we know what the effect is, but it
+ // shouldn't require bringing up the descovery screen to do that -- bwr
+ if (restore_stat(STAT_ALL, false) == false)
+ mpr( "You feel refreshed." );
+ break;
+
+ case POT_BERSERK_RAGE:
+ go_berserk(true);
+ break;
+
+ case POT_CURE_MUTATION:
+ mpr("It has a very clean taste.");
+ for (i = 0; i < 7; i++)
+ {
+ if (random2(10) > i)
+ delete_mutation(100);
+ }
+ break;
+
+ case POT_MUTATION:
+ mpr("You feel extremely strange.");
+ for (i = 0; i < 3; i++)
+ {
+ mutate(100, false);
+ }
+
+ naughty(NAUGHTY_STIMULANTS, 4 + random2(4));
+ break;
+ }
+
+ return (effect);
+} // end potion_effect()
+
+void unwield_item(char unw)
+{
+ you.special_wield = SPWLD_NONE;
+ you.wield_change = true;
+
+ if (you.inv[unw].base_type == OBJ_WEAPONS)
+ {
+ if (is_fixed_artefact( you.inv[unw] ))
+ {
+ switch (you.inv[unw].special)
+ {
+ case SPWPN_SINGING_SWORD:
+ mpr("The Singing Sword sighs.");
+ break;
+ case SPWPN_WRATH_OF_TROG:
+ mpr("You feel less violent.");
+ break;
+ case SPWPN_SCYTHE_OF_CURSES:
+ case SPWPN_STAFF_OF_OLGREB:
+ you.inv[unw].plus = 0;
+ you.inv[unw].plus2 = 0;
+ break;
+ case SPWPN_STAFF_OF_WUCAD_MU:
+ you.inv[unw].plus = 0;
+ you.inv[unw].plus2 = 0;
+ miscast_effect( SPTYP_DIVINATION, 9, 90, 100, "the Staff of Wucad Mu" );
+ break;
+ default:
+ break;
+ }
+
+ return;
+ }
+
+ int brand = get_weapon_brand( you.inv[unw] );
+
+ if (is_random_artefact( you.inv[unw] ))
+ unuse_randart(unw);
+
+ if (brand != SPWPN_NORMAL)
+ {
+ char str_pass[ ITEMNAME_SIZE ];
+ in_name(unw, DESC_CAP_YOUR, str_pass);
+ strcpy(info, str_pass);
+
+ switch (brand)
+ {
+ case SPWPN_SWORD_OF_CEREBOV:
+ case SPWPN_FLAMING:
+ strcat(info, " stops flaming.");
+ mpr(info);
+ break;
+
+ case SPWPN_FREEZING:
+ case SPWPN_HOLY_WRATH:
+ strcat(info, " stops glowing.");
+ mpr(info);
+ break;
+
+ case SPWPN_ELECTROCUTION:
+ strcat(info, " stops crackling.");
+ mpr(info);
+ break;
+
+ case SPWPN_VENOM:
+ strcat(info, " stops dripping with poison.");
+ mpr(info);
+ break;
+
+ case SPWPN_PROTECTION:
+ mpr("You feel less protected.");
+ you.redraw_armour_class = 1;
+ break;
+
+ case SPWPN_VAMPIRICISM:
+ mpr("You feel the strange hunger wane.");
+ break;
+
+ /* case 8: draining
+ case 9: speed, 10 slicing etc */
+
+ case SPWPN_DISTORTION:
+ // Removing the translocations skill reduction of effect,
+ // it might seem sensible, but this brand is supposted
+ // to be dangerous because it does large bonus damage,
+ // as well as free teleport other side effects, and
+ // even with the miscast effects you can rely on the
+ // occasional spatial bonus to mow down some opponents.
+ // It's far too powerful without a real risk, especially
+ // if it's to be allowed as a player spell. -- bwr
+
+ // int effect = 9 - random2avg( you.skills[SK_TRANSLOCATIONS] * 2, 2 );
+ miscast_effect( SPTYP_TRANSLOCATION, 9, 90, 100, "a distortion effect" );
+ break;
+
+ // when more are added here, *must* duplicate unwielding
+ // effect in vorpalise weapon scroll effect in read_scoll
+ } // end switch
+
+
+ if (you.duration[DUR_WEAPON_BRAND])
+ {
+ you.duration[DUR_WEAPON_BRAND] = 0;
+ set_item_ego_type( you.inv[unw], OBJ_WEAPONS, SPWPN_NORMAL );
+ mpr("Your branding evaporates.");
+ }
+ } // end if
+ }
+
+ if (player_equip( EQ_STAFF, STAFF_POWER ))
+ {
+ // XXX: Ugly hack so that thhis currently works (don't want to
+ // mess with the fact that currently this function doesn't
+ // actually unwield the item, but we need it out of the player's
+ // hand for this to work. -- bwr
+ int tmp = you.equip[ EQ_WEAPON ];
+
+ you.equip[ EQ_WEAPON ] = -1;
+ calc_mp();
+ you.equip[ EQ_WEAPON ] = tmp;
+ }
+
+ return;
+} // end unwield_item()
+
+// This does *not* call ev_mod!
+void unwear_armour(char unw)
+{
+ you.redraw_armour_class = 1;
+ you.redraw_evasion = 1;
+
+ switch (get_armour_ego_type( you.inv[unw] ))
+ {
+ case SPARM_RUNNING:
+ mpr("You feel rather sluggish.");
+ break;
+
+ case SPARM_FIRE_RESISTANCE:
+ mpr("\"Was it this warm in here before?\"");
+ break;
+
+ case SPARM_COLD_RESISTANCE:
+ mpr("You catch a bit of a chill.");
+ break;
+
+ case SPARM_POISON_RESISTANCE:
+ if (!player_res_poison())
+ mpr("You feel less healthy.");
+ break;
+
+ case SPARM_SEE_INVISIBLE:
+ if (!player_see_invis())
+ mpr("You feel less perceptive.");
+ break;
+
+ case SPARM_DARKNESS: // I do not understand this {dlb}
+ if (you.invis)
+ you.invis = 1;
+ break;
+
+ case SPARM_STRENGTH:
+ modify_stat(STAT_STRENGTH, -3, false);
+ break;
+
+ case SPARM_DEXTERITY:
+ modify_stat(STAT_DEXTERITY, -3, false);
+ break;
+
+ case SPARM_INTELLIGENCE:
+ modify_stat(STAT_INTELLIGENCE, -3, false);
+ break;
+
+ case SPARM_PONDEROUSNESS:
+ mpr("That put a bit of spring back into your step.");
+ // you.speed -= 2;
+ break;
+
+ case SPARM_LEVITATION:
+ //you.levitation++;
+ if (you.levitation)
+ you.levitation = 1;
+ break;
+
+ case SPARM_MAGIC_RESISTANCE:
+ mpr("You feel less resistant to magic.");
+ break;
+
+ case SPARM_PROTECTION:
+ mpr("You feel less protected.");
+ break;
+
+ case SPARM_STEALTH:
+ mpr("You feel less stealthy.");
+ break;
+
+ case SPARM_RESISTANCE:
+ mpr("You feel hot and cold all over.");
+ break;
+
+ case SPARM_POSITIVE_ENERGY:
+ mpr("You feel vulnerable.");
+ break;
+
+ case SPARM_ARCHMAGI:
+ mpr("You feel strangely numb.");
+ break;
+ }
+
+ if (is_random_artefact( you.inv[unw] ))
+ unuse_randart(unw);
+
+ return;
+} // end unwear_armour()
+
+void unuse_randart(unsigned char unw)
+{
+ ASSERT( is_random_artefact( you.inv[unw] ) );
+
+ FixedVector< char, RA_PROPERTIES > proprt;
+ randart_wpn_properties( you.inv[unw], proprt );
+
+ if (proprt[RAP_AC])
+ you.redraw_armour_class = 1;
+
+ if (proprt[RAP_EVASION])
+ you.redraw_evasion = 1;
+
+ // modify ability scores
+ modify_stat( STAT_STRENGTH, -proprt[RAP_STRENGTH], true );
+ modify_stat( STAT_INTELLIGENCE, -proprt[RAP_INTELLIGENCE], true );
+ modify_stat( STAT_DEXTERITY, -proprt[RAP_DEXTERITY], true );
+
+ if (proprt[RAP_NOISES] != 0)
+ you.special_wield = SPWLD_NONE;
+} // end unuse_randart()
diff --git a/trunk/source/it_use2.h b/trunk/source/it_use2.h
new file mode 100644
index 0000000000..2177b4083b
--- /dev/null
+++ b/trunk/source/it_use2.h
@@ -0,0 +1,43 @@
+/*
+ * File: it_use2.cc
+ * Summary: Functions for using wands, potions, and weapon/armour removal.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef IT_USE2_H
+#define IT_USE2_H
+
+
+#include "externs.h"
+
+
+/* ***********************************************************************
+ * called from: ability - beam - decks - item_use - misc - religion -
+ * spell - spells - spells1
+ * *********************************************************************** */
+bool potion_effect(char pot_eff, int pow);
+
+
+/* ***********************************************************************
+ * called from: item_use
+ * *********************************************************************** */
+void unuse_randart(unsigned char unw);
+
+
+/* ***********************************************************************
+ * called from: item_use - transfor
+ * *********************************************************************** */
+void unwear_armour(char unw);
+
+
+/* ***********************************************************************
+ * called from: decks - it_use3 - item_use - items - spells3 - transfor
+ * *********************************************************************** */
+void unwield_item(char unw);
+
+#endif
diff --git a/trunk/source/it_use3.cc b/trunk/source/it_use3.cc
new file mode 100644
index 0000000000..f3973806b2
--- /dev/null
+++ b/trunk/source/it_use3.cc
@@ -0,0 +1,1065 @@
+/*
+ * File: it_use3.cc
+ * Summary: Functions for using some of the wackier inventory items.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <4> 6/13/99 BWR Auto ID Channel staff
+ * <3> 5/22/99 BWR SPWLD_POWER is now HP/13 - 3
+ * <2> 5/20/99 BWR Capped SPWLD_POWER to +20
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "it_use3.h"
+
+#include <string.h>
+
+#include "externs.h"
+
+#include "beam.h"
+#include "decks.h"
+#include "direct.h"
+#include "effects.h"
+#include "fight.h"
+#include "food.h"
+#include "items.h"
+#include "it_use2.h"
+#include "itemname.h"
+#include "misc.h"
+#include "monplace.h"
+#include "monstuff.h"
+#include "player.h"
+#include "randart.h"
+#include "religion.h"
+#include "skills.h"
+#include "skills2.h"
+#include "spells1.h"
+#include "spells2.h"
+#include "spl-book.h"
+#include "spl-cast.h"
+#include "spl-util.h"
+#include "stuff.h"
+#include "view.h"
+#include "wpn-misc.h"
+
+static bool ball_of_energy(void);
+static bool ball_of_fixation(void);
+static bool ball_of_seeing(void);
+static bool box_of_beasts(void);
+static bool disc_of_storms(void);
+static bool efreet_flask(void);
+
+void special_wielded(void)
+{
+ const int wpn = you.equip[EQ_WEAPON];
+ const int old_plus = you.inv[wpn].plus;
+ const int old_plus2 = you.inv[wpn].plus2;
+ const char old_colour = you.inv[wpn].colour;
+
+ char str_pass[ ITEMNAME_SIZE ];
+ int temp_rand = 0; // for probability determination {dlb}
+ bool makes_noise = (one_chance_in(20) && !silenced(you.x_pos, you.y_pos));
+
+ switch (you.special_wield)
+ {
+ case SPWLD_SING:
+ if (makes_noise)
+ {
+ strcpy(info, "The Singing Sword ");
+ temp_rand = random2(32);
+ strcat(info,
+ (temp_rand == 0) ? "hums a little tune." :
+ (temp_rand == 1) ? "breaks into glorious song!" :
+ (temp_rand == 2) ? "sings." :
+ (temp_rand == 3) ? "sings loudly." :
+ (temp_rand == 4) ? "chimes melodiously." :
+ (temp_rand == 5) ? "makes a horrible noise." :
+ (temp_rand == 6) ? "sings off-key." :
+ (temp_rand == 7) ? "sings 'tra-la-la'." :
+ (temp_rand == 8) ? "burbles away merrily." :
+ (temp_rand == 9) ? "gurgles." :
+ (temp_rand == 10) ? "suddenly shrieks!" :
+ (temp_rand == 11) ? "cackles." :
+ (temp_rand == 12) ? "warbles." :
+ (temp_rand == 13) ? "chimes harmoniously." :
+ (temp_rand == 14) ? "makes beautiful music." :
+ (temp_rand == 15) ? "produces a loud orchestral chord." :
+ (temp_rand == 16) ? "whines plaintively." :
+ (temp_rand == 17) ? "tinkles." :
+ (temp_rand == 18) ? "rings like a bell." :
+ (temp_rand == 19) ? "wails mournfully." :
+ (temp_rand == 20) ? "practices its scales." :
+ (temp_rand == 21) ? "lilts tunefully." :
+ (temp_rand == 22) ? "hums tunelessly." :
+ (temp_rand == 23) ? "sighs." :
+ (temp_rand == 24) ? "makes a deep moaning sound." :
+ (temp_rand == 25) ? "makes a popping sound." :
+ (temp_rand == 26) ? "sings a sudden staccato note." :
+ (temp_rand == 27) ? "says 'Hi! I'm the Singing Sword!'." :
+ (temp_rand == 28) ? "whispers something." :
+ (temp_rand == 29) ? "speaks gibberish." :
+ (temp_rand == 30) ? "raves incoherently."
+ : "yells in some weird language.");
+ mpr(info);
+ }
+ break;
+
+ case SPWLD_CURSE:
+ makes_noise = false;
+
+ if (one_chance_in(30))
+ curse_an_item(0, 0);
+ break;
+
+ case SPWLD_VARIABLE:
+ makes_noise = false;
+
+ do_uncurse_item( you.inv[wpn] );
+
+ if (random2(5) < 2) // 40% chance {dlb}
+ you.inv[wpn].plus += (coinflip() ? +1 : -1);
+
+ if (random2(5) < 2) // 40% chance {dlb}
+ you.inv[wpn].plus2 += (coinflip() ? +1 : -1);
+
+ if (you.inv[wpn].plus < -4)
+ you.inv[wpn].plus = -4;
+ else if (you.inv[wpn].plus > 16)
+ you.inv[wpn].plus = 16;
+
+ if (you.inv[wpn].plus2 < -4)
+ you.inv[wpn].plus2 = -4;
+ else if (you.inv[wpn].plus2 > 16)
+ you.inv[wpn].plus2 = 16;
+
+ you.inv[wpn].colour = random_colour();
+ break;
+
+ case SPWLD_TORMENT:
+ makes_noise = false;
+
+ if (one_chance_in(200))
+ {
+ torment( you.x_pos, you.y_pos );
+ naughty( NAUGHTY_UNHOLY, 1 );
+ }
+ break;
+
+ case SPWLD_ZONGULDROK:
+ makes_noise = false;
+
+ if (one_chance_in(5))
+ {
+ animate_dead( 1 + random2(3), BEH_HOSTILE, MHITYOU, 1 );
+ naughty( NAUGHTY_NECROMANCY, 1 );
+ }
+ break;
+
+ case SPWLD_POWER:
+ makes_noise = false;
+
+ you.inv[wpn].plus = stepdown_value( -4 + (you.hp / 5), 4, 4, 4, 20 );
+ you.inv[wpn].plus2 = you.inv[wpn].plus;
+ break;
+
+ case SPWLD_OLGREB:
+ makes_noise = false;
+
+ // Giving Olgreb's staff a little lift since staves of poison have
+ // been made better. -- bwr
+ you.inv[wpn].plus = you.skills[SK_POISON_MAGIC] / 3;
+ you.inv[wpn].plus2 = you.inv[wpn].plus;
+ break;
+
+ case SPWLD_WUCAD_MU:
+ makes_noise = false;
+
+ you.inv[wpn].plus = ((you.intel > 25) ? 22 : you.intel - 3);
+ you.inv[wpn].plus2 = ((you.intel > 25) ? 13 : you.intel / 2);
+ break;
+
+ case SPWLD_SHADOW:
+ makes_noise = false;
+
+ if (random2(8) <= player_spec_death())
+ {
+ naughty( NAUGHTY_NECROMANCY, 1 );
+ create_monster( MONS_SHADOW, ENCH_ABJ_II, BEH_FRIENDLY,
+ you.x_pos, you.y_pos, you.pet_target, 250 );
+ }
+
+ show_green = DARKGREY;
+ break;
+
+ case SPWLD_HUM:
+ if (makes_noise)
+ {
+ in_name(wpn, DESC_CAP_YOUR, str_pass);
+ strcpy(info, str_pass);
+ strcat(info, " lets out a weird humming sound.");
+ mpr(info);
+ }
+ break; // to noisy() call at foot 2apr2000 {dlb}
+
+ case SPWLD_CHIME:
+ if (makes_noise)
+ {
+ in_name(wpn, DESC_CAP_YOUR, str_pass);
+ strcpy(info, str_pass);
+ strcat(info, " chimes like a gong.");
+ mpr(info);
+ }
+ break;
+
+ case SPWLD_BECKON:
+ if (makes_noise)
+ mpr("You hear a voice call your name.");
+ break;
+
+ case SPWLD_SHOUT:
+ if (makes_noise)
+ mpr("You hear a shout.");
+ break;
+
+ //case SPWLD_PRUNE:
+ default:
+ return;
+ }
+
+ if (makes_noise)
+ noisy( 25, you.x_pos, you.y_pos );
+
+ if (old_plus != you.inv[wpn].plus
+ || old_plus2 != you.inv[wpn].plus2
+ || old_colour != you.inv[wpn].colour)
+ {
+ you.wield_change = true;
+ }
+
+ return;
+} // end special_wielded()
+
+static void reaching_weapon_attack(void)
+{
+ struct dist beam;
+ int x_distance, y_distance;
+ int x_middle, y_middle;
+ int skill;
+
+ mpr("Attack whom?", MSGCH_PROMPT);
+
+ direction( beam, DIR_TARGET, TARG_ENEMY );
+ if (!beam.isValid)
+ return;
+
+ if (beam.isMe)
+ {
+ canned_msg(MSG_UNTHINKING_ACT);
+ return;
+ }
+
+ x_distance = abs(beam.tx - you.x_pos);
+ y_distance = abs(beam.ty - you.y_pos);
+
+ if (x_distance > 2 || y_distance > 2)
+ mpr("Your weapon cannot reach that far!");
+ else if (mgrd[beam.tx][beam.ty] == NON_MONSTER)
+ {
+ mpr("You attack empty space.");
+ }
+ else
+ {
+ /* BCR - Added a check for monsters in the way. Only checks cardinal
+ * directions. Knight moves are ignored. Assume the weapon
+ * slips between the squares.
+ */
+
+ // if we're attacking more than a space away
+ if ((x_distance > 1) || (y_distance > 1))
+ {
+
+#define MAX(x,y) (((x) > (y)) ? (x) : (y))
+ x_middle = MAX(beam.tx, you.x_pos) - (x_distance / 2);
+ y_middle = MAX(beam.ty, you.y_pos) - (y_distance / 2);
+#undef MAX
+
+ // if either the x or the y is the same, we should check for
+ // a monster:
+ if (((beam.tx == you.x_pos) || (beam.ty == you.y_pos))
+ && (mgrd[x_middle][y_middle] != NON_MONSTER))
+ {
+ skill = weapon_skill( you.inv[you.equip[EQ_WEAPON]].base_type,
+ you.inv[you.equip[EQ_WEAPON]].sub_type );
+
+ if ((5 + (3 * skill)) > random2(100))
+ {
+ mpr("You reach to attack!");
+ you_attack(mgrd[beam.tx][beam.ty], false);
+ }
+ else
+ {
+ mpr("You could not reach far enough!");
+ you_attack(mgrd[x_middle][y_middle], false);
+ }
+ }
+ else
+ {
+ mpr("You reach to attack!");
+ you_attack(mgrd[beam.tx][beam.ty], false);
+ }
+ }
+ else
+ {
+ you_attack(mgrd[beam.tx][beam.ty], false);
+ }
+ }
+
+ return;
+} // end reaching_weapon_attack()
+
+// returns true if item successfully evoked.
+bool evoke_wielded( void )
+{
+ char opened_gates = 0;
+ unsigned char spell_casted = random2(21);
+ int count_x, count_y;
+ int temp_rand = 0; // for probability determination {dlb}
+ int power = 0;
+
+ int pract = 0;
+ bool did_work = false; // used for default "nothing happens" message
+
+ char str_pass[ ITEMNAME_SIZE ];
+
+ int wield = you.equip[EQ_WEAPON];
+
+ if (you.berserker)
+ {
+ canned_msg( MSG_TOO_BERSERK );
+ return (false);
+ }
+ else if (wield == -1)
+ {
+ mpr("You aren't wielding anything!");
+ return (false);
+ }
+
+ switch (you.inv[wield].base_type)
+ {
+ case OBJ_WEAPONS:
+ if (get_weapon_brand( you.inv[wield] ) == SPWPN_REACHING
+ && enough_mp(1, false))
+ {
+ // needed a cost to prevent evocation training abuse -- bwr
+ dec_mp(1);
+ make_hungry( 50, false );
+ reaching_weapon_attack();
+ pract = (one_chance_in(5) ? 1 : 0);
+ did_work = true;
+ }
+ else if (is_fixed_artefact( you.inv[wield] ))
+ {
+ switch (you.inv[wield].special)
+ {
+ case SPWPN_STAFF_OF_DISPATER:
+ if (you.deaths_door || !enough_hp(11, true)
+ || !enough_mp(5, true))
+ {
+ break;
+ }
+
+ mpr("You feel the staff feeding on your energy!");
+
+ dec_hp( 5 + random2avg(19, 2), false );
+ dec_mp( 2 + random2avg(5, 2) );
+ make_hungry( 100, false );
+
+ power = you.skills[SK_EVOCATIONS] * 8;
+ your_spells( SPELL_HELLFIRE, power, false );
+ pract = (coinflip() ? 2 : 1);
+ did_work = true;
+ break;
+
+ // let me count the number of ways spell_casted is
+ // used here ... one .. two .. three ... >CRUNCH<
+ // three licks to get to the center of a ... {dlb}
+ case SPWPN_SCEPTRE_OF_ASMODEUS:
+ spell_casted = random2(21);
+
+ if (spell_casted == 0)
+ break;
+
+ make_hungry( 200, false );
+ pract = 1;
+
+ if (spell_casted < 2) // summon devils, maybe a Fiend
+ {
+
+ spell_casted = (one_chance_in(4) ? MONS_FIEND
+ : MONS_HELLION + random2(10));
+
+ bool good_summon = (create_monster( spell_casted,
+ ENCH_ABJ_VI, BEH_HOSTILE,
+ you.x_pos, you.y_pos,
+ MHITYOU, 250) != -1);
+
+ if (good_summon)
+ {
+ if (spell_casted == MONS_FIEND)
+ mpr("\"Your arrogance condemns you, mortal!\"");
+ else
+ mpr("The Sceptre summons one of its servants.");
+ }
+
+ did_work = true;
+ break;
+ }
+
+ temp_rand = random2(240);
+
+ if (temp_rand > 125)
+ spell_casted = SPELL_BOLT_OF_FIRE; // 114 in 240
+ else if (temp_rand > 68)
+ spell_casted = SPELL_LIGHTNING_BOLT; // 57 in 240
+ else if (temp_rand > 11)
+ spell_casted = SPELL_BOLT_OF_DRAINING; // 57 in 240
+ else
+ spell_casted = SPELL_HELLFIRE; // 12 in 240
+
+ power = you.skills[SK_EVOCATIONS] * 8;
+ your_spells( spell_casted, power, false );
+ did_work = true;
+ break;
+
+ case SPWPN_STAFF_OF_OLGREB:
+ if (!enough_mp( 4, true )
+ || you.skills[SK_EVOCATIONS] < random2(6))
+ {
+ break;
+ }
+
+ dec_mp(4);
+ make_hungry( 50, false );
+ pract = 1;
+ did_work = true;
+
+ power = 10 + you.skills[SK_EVOCATIONS] * 8;
+
+ your_spells( SPELL_OLGREBS_TOXIC_RADIANCE, power, false );
+
+ if (you.skills[SK_EVOCATIONS] >= random2(10))
+ your_spells( SPELL_VENOM_BOLT, power, false );
+ break;
+
+ case SPWPN_STAFF_OF_WUCAD_MU:
+ if (you.magic_points == you.max_magic_points
+ || you.skills[SK_EVOCATIONS] < random2(25))
+ {
+ break;
+ }
+
+ mpr("Magical energy flows into your mind!");
+
+ inc_mp( 3 + random2(5) + you.skills[SK_EVOCATIONS] / 3, false );
+ make_hungry( 50, false );
+ pract = 1;
+ did_work = true;
+
+ if (one_chance_in(3))
+ {
+ miscast_effect( SPTYP_DIVINATION, random2(9),
+ random2(70), 100, "the Staff of Wucad Mu" );
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case OBJ_STAVES:
+ if (item_is_rod( you.inv[wield] ))
+ {
+ pract = staff_spell( wield );
+ did_work = true; // staff_spell() will handle messages
+ }
+ else if (you.inv[wield].sub_type == STAFF_CHANNELING)
+ {
+ if (you.magic_points < you.max_magic_points
+ && you.skills[SK_EVOCATIONS] >= random2(30))
+ {
+ mpr("You channel some magical energy.");
+ inc_mp( 1 + random2(3), false );
+ make_hungry( 50, false );
+ pract = (one_chance_in(5) ? 1 : 0);
+ did_work = true;
+
+ if (item_not_ident( you.inv[you.equip[EQ_WEAPON]],
+ ISFLAG_KNOW_TYPE ))
+ {
+ set_ident_flags( you.inv[you.equip[EQ_WEAPON]],
+ ISFLAG_KNOW_TYPE );
+
+ strcpy( info, "You are wielding " );
+ in_name( you.equip[EQ_WEAPON], DESC_NOCAP_A, str_pass );
+ strcat( info, str_pass );
+ strcat( info, "." );
+
+ mpr( info );
+ more();
+
+ you.wield_change = true;
+ }
+ }
+ }
+ break;
+
+ case OBJ_MISCELLANY:
+ did_work = true; // easier to do it this way for misc items
+ switch (you.inv[wield].sub_type)
+ {
+ case MISC_BOTTLED_EFREET:
+ if (efreet_flask())
+ pract = 2;
+ break;
+
+ case MISC_CRYSTAL_BALL_OF_SEEING:
+ if (ball_of_seeing())
+ pract = 1;
+ break;
+
+ case MISC_AIR_ELEMENTAL_FAN:
+ if (you.skills[SK_EVOCATIONS] <= random2(30))
+ canned_msg(MSG_NOTHING_HAPPENS);
+ else
+ {
+ summon_elemental(100, MONS_AIR_ELEMENTAL, 4);
+ pract = (one_chance_in(5) ? 1 : 0);
+ }
+ break;
+
+ case MISC_LAMP_OF_FIRE:
+ if (you.skills[SK_EVOCATIONS] <= random2(30))
+ canned_msg(MSG_NOTHING_HAPPENS);
+ else
+ {
+ summon_elemental(100, MONS_FIRE_ELEMENTAL, 4);
+ pract = (one_chance_in(5) ? 1 : 0);
+ }
+ break;
+
+ case MISC_STONE_OF_EARTH_ELEMENTALS:
+ if (you.skills[SK_EVOCATIONS] <= random2(30))
+ canned_msg(MSG_NOTHING_HAPPENS);
+ else
+ {
+ summon_elemental(100, MONS_EARTH_ELEMENTAL, 4);
+ pract = (one_chance_in(5) ? 1 : 0);
+ }
+ break;
+
+ case MISC_HORN_OF_GERYON:
+ // Note: This assumes that the Vestibule has not been changed.
+ if (player_in_branch( BRANCH_VESTIBULE_OF_HELL ))
+ {
+ mpr("You produce a weird and mournful sound.");
+
+ for (count_x = 0; count_x < GXM; count_x++)
+ {
+ for (count_y = 0; count_y < GYM; count_y++)
+ {
+ if (grd[count_x][count_y] == DNGN_STONE_ARCH)
+ {
+ opened_gates++;
+
+ // this may generate faulty [][] values {dlb}
+ switch (grd[count_x + 2][count_y])
+ {
+ case DNGN_FLOOR:
+ grd[count_x][count_y] = DNGN_ENTER_DIS;
+ break;
+ case DNGN_LAVA:
+ grd[count_x][count_y] = DNGN_ENTER_GEHENNA;
+ break;
+ case DNGN_ROCK_WALL:
+ grd[count_x][count_y] = DNGN_ENTER_TARTARUS;
+ break;
+ case DNGN_DEEP_WATER:
+ grd[count_x][count_y] = DNGN_ENTER_COCYTUS;
+ break;
+ }
+ }
+ }
+ }
+
+ if (opened_gates)
+ {
+ mpr("Your way has been unbarred.");
+ pract = 1;
+ }
+ }
+ else
+ {
+ mpr("You produce a hideous howling noise!");
+ pract = (one_chance_in(3) ? 1 : 0);
+ create_monster( MONS_BEAST, ENCH_ABJ_IV, BEH_HOSTILE,
+ you.x_pos, you.y_pos, MHITYOU, 250 );
+ }
+ break;
+
+ case MISC_DECK_OF_WONDERS:
+ deck_of_cards(DECK_OF_WONDERS);
+ pract = 1;
+ break;
+
+ case MISC_DECK_OF_SUMMONINGS:
+ deck_of_cards(DECK_OF_SUMMONING);
+ pract = 1;
+ break;
+
+ case MISC_DECK_OF_TRICKS:
+ deck_of_cards(DECK_OF_TRICKS);
+ pract = 1;
+ break;
+
+ case MISC_DECK_OF_POWER:
+ deck_of_cards(DECK_OF_POWER);
+ pract = 1;
+ break;
+
+ case MISC_BOX_OF_BEASTS:
+ if (box_of_beasts())
+ pract = 1;
+ break;
+
+ case MISC_CRYSTAL_BALL_OF_ENERGY:
+ if (ball_of_energy())
+ pract = 1;
+ break;
+
+ case MISC_CRYSTAL_BALL_OF_FIXATION:
+ if (ball_of_fixation())
+ pract = 1;
+ break;
+
+ case MISC_DISC_OF_STORMS:
+ if (disc_of_storms())
+ pract = (coinflip() ? 2 : 1);
+ break;
+
+ case MISC_PORTABLE_ALTAR_OF_NEMELEX:
+ if (player_in_branch( BRANCH_ECUMENICAL_TEMPLE ))
+ {
+ mpr( "Don't you think this level already has more than "
+ "enough altars?" );
+ }
+ else if (grd[you.x_pos][you.y_pos] != DNGN_FLOOR)
+ mpr("You need a clear area to place this item.");
+ else
+ {
+ mpr("You unfold the altar and place it on the floor.");
+ grd[you.x_pos][you.y_pos] = DNGN_ALTAR_NEMELEX_XOBEH;
+ dec_inv_item_quantity( you.equip[EQ_WEAPON], 1 );
+ }
+ break;
+
+ default:
+ did_work = false;
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (!did_work)
+ canned_msg(MSG_NOTHING_HAPPENS);
+ else if (pract > 0)
+ exercise( SK_EVOCATIONS, pract );
+
+ you.turn_is_over = 1;
+
+ return (did_work);
+} // end evoke_wielded()
+
+static bool efreet_flask(void)
+{
+ const int behaviour = ((you.skills[SK_EVOCATIONS] > random2(20))
+ ? BEH_FRIENDLY : BEH_HOSTILE);
+
+ mpr("You open the flask...");
+
+ dec_inv_item_quantity( you.equip[EQ_WEAPON], 1 );
+
+ if (create_monster( MONS_EFREET, ENCH_ABJ_V, behaviour,
+ you.x_pos, you.y_pos, MHITYOU, 250 ) != -1)
+ {
+ mpr( "...and a huge efreet comes out." );
+
+ mpr( (behaviour == BEH_FRIENDLY) ? "\"Thank you for releasing me!\""
+ : "It howls insanely!" );
+ }
+ else
+ canned_msg(MSG_NOTHING_HAPPENS);
+
+ return (true);
+} // end efreet_flask()
+
+static bool ball_of_seeing(void)
+{
+ int use = 0;
+ bool ret = false;
+
+ mpr("You gaze into the crystal ball.");
+
+ use = ((!you.conf) ? random2(you.skills[SK_EVOCATIONS] * 6) : random2(5));
+
+ if (use < 2)
+ {
+ lose_stat( STAT_INTELLIGENCE, 1 );
+ }
+ else if (use < 5 && enough_mp(1, true))
+ {
+ mpr("You feel power drain from you!");
+ set_mp(0, false);
+ }
+ else if (use < 10)
+ {
+ confuse_player( 10 + random2(10), false );
+ }
+ else if (use < 15
+ || you.level_type == LEVEL_LABYRINTH
+ || you.level_type == LEVEL_ABYSS || coinflip())
+ {
+ mpr("You see nothing.");
+ }
+ else
+ {
+ mpr("You see a map of your surroundings!");
+ magic_mapping( 15, 50 + random2( you.skills[SK_EVOCATIONS] ) );
+ ret = true;
+ }
+
+ return (ret);
+} // end ball_of_seeing()
+
+static bool disc_of_storms(void)
+{
+ int temp_rand = 0; // probability determination {dlb}
+ struct bolt beam;
+ int disc_count = 0;
+ unsigned char which_zap = 0;
+
+ const int fail_rate = (30 - you.skills[SK_EVOCATIONS]);
+ bool ret = false;
+
+ if (player_res_electricity() || (random2(100) < fail_rate))
+ canned_msg(MSG_NOTHING_HAPPENS);
+ else if (random2(100) < fail_rate)
+ mpr("The disc glows for a moment, then fades.");
+ else if (random2(100) < fail_rate)
+ mpr("Little bolts of electricity crackle over the disc.");
+ else
+ {
+ mpr("The disc erupts in an explosion of electricity!");
+
+ disc_count = roll_dice( 2, 1 + you.skills[SK_EVOCATIONS] / 7 );
+
+ while (disc_count)
+ {
+ temp_rand = random2(3);
+
+ which_zap = ((temp_rand > 1) ? ZAP_LIGHTNING :
+ (temp_rand > 0) ? ZAP_ELECTRICITY
+ : ZAP_ORB_OF_ELECTRICITY);
+
+ beam.source_x = you.x_pos;
+ beam.source_y = you.y_pos;
+ beam.target_x = you.x_pos + random2(13) - 6;
+ beam.target_y = you.y_pos + random2(13) - 6;
+
+ zapping( which_zap, 30 + you.skills[SK_EVOCATIONS] * 2, beam );
+
+ disc_count--;
+ }
+
+ ret = true;
+ }
+
+ return (ret);
+} // end disc_of_storms()
+
+void tome_of_power(char sc_read_2)
+{
+ int temp_rand = 0; // probability determination {dlb}
+
+ int powc = 5 + you.skills[SK_EVOCATIONS]
+ + roll_dice( 5, you.skills[SK_EVOCATIONS] );
+
+ int spell_casted = 0;
+ struct bolt beam;
+
+ strcpy(info, "The book opens to a page covered in ");
+
+ char wc[30];
+ weird_writing( wc );
+ strcat( info, wc );
+ strcat( info, "." );
+ mpr( info );
+
+ you.turn_is_over = 1;
+
+ if (!yesno("Read it?"))
+ return;
+
+ set_ident_flags( you.inv[sc_read_2], ISFLAG_IDENT_MASK );
+
+ if (you.mutation[MUT_BLURRY_VISION] > 0
+ && random2(4) < you.mutation[MUT_BLURRY_VISION])
+ {
+ mpr("The page is too blurry for you to read.");
+ return;
+ }
+
+ mpr("You find yourself reciting the magical words!");
+ exercise( SK_EVOCATIONS, 1 );
+
+ temp_rand = random2(50) + random2( you.skills[SK_EVOCATIONS] / 3 );
+
+ switch (random2(50))
+ {
+ case 0:
+ case 3:
+ case 4:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ mpr("A cloud of weird smoke pours from the book's pages!");
+ big_cloud( CLOUD_GREY_SMOKE + random2(3), you.x_pos, you.y_pos, 20,
+ 10 + random2(8) );
+ return;
+ case 1:
+ case 14:
+ mpr("A cloud of choking fumes pours from the book's pages!");
+ big_cloud(CLOUD_POISON, you.x_pos, you.y_pos, 20, 7 + random2(5));
+ return;
+
+ case 2:
+ case 13:
+ mpr("A cloud of freezing gas pours from the book's pages!");
+ big_cloud(CLOUD_COLD, you.x_pos, you.y_pos, 20, 8 + random2(5));
+ return;
+
+ case 5:
+ case 11:
+ case 12:
+ if (one_chance_in(5))
+ {
+ mpr("The book disappears in a mighty explosion!");
+ dec_inv_item_quantity( sc_read_2, 1 );
+ }
+
+ beam.type = SYM_BURST;
+ beam.damage = dice_def( 3, 15 );
+ // unsure about this // BEAM_EXPLOSION instead? [dlb]
+ beam.flavour = BEAM_FIRE;
+ beam.target_x = you.x_pos;
+ beam.target_y = you.y_pos;
+ strcpy( beam.beam_name, "fiery explosion" );
+ beam.colour = RED;
+ // your explosion, (not someone else's explosion)
+ beam.beam_source = NON_MONSTER;
+ beam.thrower = KILL_YOU;
+ beam.aux_source = "an exploding Tome of Power";
+ beam.ex_size = 2;
+ beam.isTracer = false;
+
+ explosion(beam);
+ return;
+
+
+ case 10:
+ if (create_monster( MONS_ABOMINATION_SMALL, ENCH_ABJ_VI, BEH_HOSTILE,
+ you.x_pos, you.y_pos, MHITYOU, 250 ) != -1)
+ {
+ mpr("A horrible Thing appears!");
+ mpr("It doesn't look too friendly.");
+ }
+ return;
+ }
+
+ viewwindow(1, false);
+
+ temp_rand = random2(23) + random2( you.skills[SK_EVOCATIONS] / 3 );
+
+ if (temp_rand > 25)
+ temp_rand = 25;
+
+ spell_casted = ((temp_rand > 19) ? SPELL_FIREBALL :
+ (temp_rand > 16) ? SPELL_BOLT_OF_FIRE :
+ (temp_rand > 13) ? SPELL_BOLT_OF_COLD :
+ (temp_rand > 11) ? SPELL_LIGHTNING_BOLT :
+ (temp_rand > 10) ? SPELL_LEHUDIBS_CRYSTAL_SPEAR :
+ (temp_rand > 9) ? SPELL_VENOM_BOLT :
+ (temp_rand > 8) ? SPELL_BOLT_OF_DRAINING :
+ (temp_rand > 7) ? SPELL_BOLT_OF_INACCURACY :
+ (temp_rand > 6) ? SPELL_STICKY_FLAME :
+ (temp_rand > 5) ? SPELL_TELEPORT_SELF :
+ (temp_rand > 4) ? SPELL_CIGOTUVIS_DEGENERATION :
+ (temp_rand > 3) ? SPELL_POLYMORPH_OTHER :
+ (temp_rand > 2) ? SPELL_MEPHITIC_CLOUD :
+ (temp_rand > 1) ? SPELL_THROW_FLAME :
+ (temp_rand > 0) ? SPELL_THROW_FROST
+ : SPELL_MAGIC_DART);
+
+ your_spells( spell_casted, powc, false );
+} // end tome_of_power()
+
+void skill_manual(char sc_read_2)
+{
+ char skname[30];
+
+ set_ident_flags( you.inv[sc_read_2], ISFLAG_IDENT_MASK );
+
+ strcpy(skname, skill_name(you.inv[sc_read_2].plus));
+
+ strcpy(info, "This is a manual of ");
+ strcat(info, skname);
+ strcat(info, "!");
+ mpr(info);
+
+ you.turn_is_over = 1;
+
+ if (!yesno("Read it?"))
+ return;
+
+ strcpy(info, "You read about ");
+ strcat(info, strlwr(skname));
+ strcat(info, ".");
+ mpr(info);
+
+ exercise( you.inv[sc_read_2].plus, 500 );
+
+ if (one_chance_in(10))
+ {
+ mpr("The book crumbles into dust.");
+ dec_inv_item_quantity( sc_read_2, 1 );
+ }
+ else
+ {
+ mpr("The book looks somewhat more worn.");
+ }
+} // end skill_manual()
+
+static bool box_of_beasts(void)
+{
+ int beasty = MONS_PROGRAM_BUG; // error trapping {dlb}
+ int temp_rand = 0; // probability determination {dlb}
+
+ int ret = false;
+
+ mpr("You open the lid...");
+
+ if (random2(100) < 60 + you.skills[SK_EVOCATIONS])
+ {
+ temp_rand = random2(11);
+
+ beasty = ((temp_rand == 0) ? MONS_GIANT_BAT :
+ (temp_rand == 1) ? MONS_HOUND :
+ (temp_rand == 2) ? MONS_JACKAL :
+ (temp_rand == 3) ? MONS_RAT :
+ (temp_rand == 4) ? MONS_ICE_BEAST :
+ (temp_rand == 5) ? MONS_SNAKE :
+ (temp_rand == 6) ? MONS_YAK :
+ (temp_rand == 7) ? MONS_BUTTERFLY :
+ (temp_rand == 8) ? MONS_HELL_HOUND :
+ (temp_rand == 9) ? MONS_BROWN_SNAKE
+ : MONS_GIANT_LIZARD);
+
+ int beh = (one_chance_in(you.skills[SK_EVOCATIONS] + 5) ? BEH_HOSTILE
+ : BEH_FRIENDLY);
+
+ if (create_monster( beasty, ENCH_ABJ_II + random2(4), beh,
+ you.x_pos, you.y_pos, MHITYOU, 250 ) != -1)
+ {
+ mpr("...and something leaps out!");
+ ret = true;
+ }
+ }
+ else
+ {
+ if (!one_chance_in(6))
+ mpr("...but nothing happens.");
+ else
+ {
+ mpr("...but the box appears empty.");
+ you.inv[you.equip[EQ_WEAPON]].sub_type = MISC_EMPTY_EBONY_CASKET;
+ }
+ }
+
+ return (ret);
+} // end box_of_beasts()
+
+static bool ball_of_energy(void)
+{
+ int use = 0;
+ int proportional = 0;
+
+ bool ret = false;
+
+ mpr("You gaze into the crystal ball.");
+
+ use = ((!you.conf) ? random2(you.skills[SK_EVOCATIONS] * 6) : random2(6));
+
+ if (use < 2 || you.max_magic_points == 0)
+ {
+ lose_stat(STAT_INTELLIGENCE, 1);
+ }
+ else if ((use < 4 && enough_mp(1, true))
+ || you.magic_points == you.max_magic_points)
+ {
+ mpr( "You feel your power drain away!" );
+ set_mp( 0, false );
+ }
+ else if (use < 6)
+ {
+ confuse_player( 10 + random2(10), false );
+ }
+ else
+ {
+ proportional = you.magic_points * 100;
+ proportional /= you.max_magic_points;
+
+ if (random2avg(77 - you.skills[SK_EVOCATIONS] * 2, 4) > proportional
+ || one_chance_in(25))
+ {
+ mpr( "You feel your power drain away!" );
+ set_mp( 0, false );
+ }
+ else
+ {
+ mpr( "You are suffused with power!" );
+ inc_mp( 6 + roll_dice( 2, you.skills[SK_EVOCATIONS] ), false );
+
+ ret = true;
+ }
+ }
+
+ return (ret);
+} // end ball_of_energy()
+
+static bool ball_of_fixation(void)
+{
+ mpr("You gaze into the crystal ball.");
+ mpr("You are mesmerised by a rainbow of scintillating colours!");
+
+ you.paralysis = 100;
+ you.slow = 100;
+
+ return (true);
+} // end ball_of_fixation()
diff --git a/trunk/source/it_use3.h b/trunk/source/it_use3.h
new file mode 100644
index 0000000000..2e5efae7c3
--- /dev/null
+++ b/trunk/source/it_use3.h
@@ -0,0 +1,44 @@
+/*
+ * File: it_use3.cc
+ * Summary: Functions for using some of the wackier inventory items.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef IT_USE3_H
+#define IT_USE3_H
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: item_use
+ * *********************************************************************** */
+void skill_manual(char sc_read_2);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: item_use - spl-book
+ * *********************************************************************** */
+void tome_of_power(char sc_read_2);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+bool evoke_wielded(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void special_wielded(void);
+
+
+#endif
diff --git a/trunk/source/item_use.cc b/trunk/source/item_use.cc
new file mode 100644
index 0000000000..b36a097eed
--- /dev/null
+++ b/trunk/source/item_use.cc
@@ -0,0 +1,3107 @@
+/*
+ * File: item_use.cc
+ * Summary: Functions for making use of inventory items.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <8> 28July2000 GDL Revised player throwing
+ * <7> 11/23/99 LRH Horned characters can wear hats/caps
+ * <6> 7/13/99 BWR Lowered learning rates for
+ * throwing skills, and other
+ * balance tweaks
+ * <5> 5/28/99 JDJ Changed wear_armour to allow Spriggans to
+ * wear bucklers.
+ * <4> 5/26/99 JDJ body armour can be removed and worn if an
+ * uncursed cloak is being worn.
+ * Removed lots of unnessary mpr string copying.
+ * Added missing ponderous message.
+ * <3> 5/20/99 BWR Fixed staff of air bug, output of trial
+ * identified items, a few you.wield_changes so
+ * that the weapon gets updated.
+ * <2> 5/08/99 JDJ Added armour_prompt.
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "item_use.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "externs.h"
+
+#include "beam.h"
+#include "debug.h"
+#include "delay.h"
+#include "describe.h"
+#include "direct.h"
+#include "effects.h"
+#include "fight.h"
+#include "food.h"
+#include "invent.h"
+#include "it_use2.h"
+#include "it_use3.h"
+#include "items.h"
+#include "itemname.h"
+#include "misc.h"
+#include "monplace.h"
+#include "monstuff.h"
+#include "mstuff2.h"
+#include "mon-util.h"
+#include "ouch.h"
+#include "player.h"
+#include "randart.h"
+#include "religion.h"
+#include "skills.h"
+#include "skills2.h"
+#include "spells1.h"
+#include "spells2.h"
+#include "spells3.h"
+#include "spl-book.h"
+#include "spl-cast.h"
+#include "stuff.h"
+#include "transfor.h"
+#include "view.h"
+#include "wpn-misc.h"
+
+bool drink_fountain(void);
+static void throw_it(struct bolt &pbolt, int throw_2);
+void use_randart(unsigned char item_wield_2);
+static bool enchant_weapon( int which_stat, bool quiet = false );
+static bool enchant_armour( void );
+
+void wield_weapon(bool auto_wield)
+{
+ int item_slot = 0;
+ char str_pass[ ITEMNAME_SIZE ];
+
+ if (inv_count() < 1)
+ {
+ canned_msg(MSG_NOTHING_CARRIED);
+ return;
+ }
+
+ if (you.berserker)
+ {
+ canned_msg(MSG_TOO_BERSERK);
+ return;
+ }
+
+ if (you.attribute[ATTR_TRANSFORMATION] != TRAN_NONE)
+ {
+ if (!can_equip( EQ_WEAPON ))
+ {
+ mpr("You can't wield anything in your present form.");
+ return;
+ }
+ }
+
+ if (you.equip[EQ_WEAPON] != -1
+ && you.inv[you.equip[EQ_WEAPON]].base_type == OBJ_WEAPONS
+ && item_cursed( you.inv[you.equip[EQ_WEAPON]] ))
+ {
+ mpr("You can't unwield your weapon to draw a new one!");
+ return;
+ }
+
+ if (you.sure_blade)
+ {
+ mpr("The bond with your blade fades away.");
+ you.sure_blade = 0;
+ }
+
+ if (auto_wield)
+ {
+ if (you.equip[EQ_WEAPON] == 0) // ie. weapon is currently 'a'
+ item_slot = 1;
+ else
+ item_slot = 0;
+ }
+
+ // Prompt if not using the auto swap command,
+ // or if the swap slot is empty.
+ if (!auto_wield || !is_valid_item( you.inv[item_slot] ))
+ {
+ item_slot = prompt_invent_item( "Wield which item (- for none)?",
+ OBJ_WEAPONS, true, true, true, '-' );
+
+ if (item_slot == PROMPT_ABORT)
+ {
+ canned_msg( MSG_OK );
+ return;
+ }
+ else if (item_slot == PROMPT_GOT_SPECIAL) // '-' or bare hands
+ {
+ if (you.equip[EQ_WEAPON] != -1)
+ {
+ unwield_item(you.equip[EQ_WEAPON]);
+ you.turn_is_over = 1;
+
+ you.equip[EQ_WEAPON] = -1;
+ canned_msg( MSG_EMPTY_HANDED );
+ you.time_taken *= 3;
+ you.time_taken /= 10;
+ }
+ else
+ {
+ mpr( "You are already empty-handed." );
+ }
+ return;
+ }
+ }
+
+ if (item_slot == you.equip[EQ_WEAPON])
+ {
+ mpr("You are already wielding that!");
+ return;
+ }
+
+ for (int i = EQ_CLOAK; i <= EQ_AMULET; i++)
+ {
+ if (item_slot == you.equip[i])
+ {
+ mpr("You are wearing that object!");
+ return;
+ }
+ }
+
+ if (you.inv[item_slot].base_type != OBJ_WEAPONS)
+ {
+ if (you.inv[item_slot].base_type == OBJ_STAVES
+ && you.equip[EQ_SHIELD] != -1)
+ {
+ mpr("You can't wield that with a shield.");
+ return;
+ }
+
+ if (you.equip[EQ_WEAPON] != -1)
+ unwield_item(you.equip[EQ_WEAPON]);
+
+ you.equip[EQ_WEAPON] = item_slot;
+ }
+ else
+ {
+ if ((you.species < SP_OGRE || you.species > SP_OGRE_MAGE)
+ && mass_item( you.inv[item_slot] ) >= 500)
+ {
+ mpr("That's too large and heavy for you to wield.");
+ return;
+ }
+
+ if ((you.species == SP_HALFLING || you.species == SP_GNOME
+ || you.species == SP_KOBOLD || you.species == SP_SPRIGGAN)
+
+ && (you.inv[item_slot].sub_type == WPN_GREAT_SWORD
+ || you.inv[item_slot].sub_type == WPN_TRIPLE_SWORD
+ || you.inv[item_slot].sub_type == WPN_GREAT_MACE
+ || you.inv[item_slot].sub_type == WPN_GREAT_FLAIL
+ || you.inv[item_slot].sub_type == WPN_BATTLEAXE
+ || you.inv[item_slot].sub_type == WPN_EXECUTIONERS_AXE
+ || you.inv[item_slot].sub_type == WPN_HALBERD
+ || you.inv[item_slot].sub_type == WPN_GLAIVE
+ || you.inv[item_slot].sub_type == WPN_GIANT_CLUB
+ || you.inv[item_slot].sub_type == WPN_GIANT_SPIKED_CLUB
+ || you.inv[item_slot].sub_type == WPN_SCYTHE))
+ {
+ mpr("That's too large for you to wield.");
+ return;
+
+ }
+
+ if (hands_reqd_for_weapon( you.inv[item_slot].base_type,
+ you.inv[item_slot].sub_type ) == HANDS_TWO_HANDED
+ && you.equip[EQ_SHIELD] != -1)
+ {
+ mpr("You can't wield that with a shield.");
+ return;
+ }
+
+ int weap_brand = get_weapon_brand( you.inv[item_slot] );
+
+ if ((you.is_undead || you.species == SP_DEMONSPAWN)
+ && (!is_fixed_artefact( you.inv[item_slot] )
+ && (weap_brand == SPWPN_HOLY_WRATH
+ || weap_brand == SPWPN_DISRUPTION)))
+ {
+ mpr("This weapon will not allow you to wield it.");
+ you.turn_is_over = 1;
+ return;
+ }
+
+ if (you.equip[EQ_WEAPON] != -1)
+ unwield_item(you.equip[EQ_WEAPON]);
+
+ you.equip[EQ_WEAPON] = item_slot;
+ }
+
+ // any oddness on wielding taken care of here
+ wield_effects(item_slot, true);
+
+ in_name( item_slot, DESC_INVENTORY_EQUIP, str_pass );
+ mpr( str_pass );
+
+ // warn player about low str/dex or throwing skill
+ wield_warning();
+
+ // time calculations
+ you.time_taken *= 5;
+ you.time_taken /= 10;
+
+ you.wield_change = true;
+ you.turn_is_over = 1;
+}
+
+// provide a function for handling initial wielding of 'special'
+// weapons, or those whose function is annoying to reproduce in
+// other places *cough* auto-butchering *cough* {gdl}
+
+void wield_effects(int item_wield_2, bool showMsgs)
+{
+ unsigned char i_dam = 0;
+
+ // and here we finally get to the special effects of wielding {dlb}
+ if (you.inv[item_wield_2].base_type == OBJ_MISCELLANY)
+ {
+ if (you.inv[item_wield_2].sub_type == MISC_LANTERN_OF_SHADOWS)
+ {
+ if (showMsgs)
+ mpr("The area is filled with flickering shadows.");
+
+ you.special_wield = SPWLD_SHADOW;
+ }
+ }
+
+ if (you.inv[item_wield_2].base_type == OBJ_STAVES)
+ {
+ if (you.inv[item_wield_2].sub_type == STAFF_POWER)
+ {
+ // inc_max_mp(13);
+ calc_mp();
+ set_ident_flags( you.inv[item_wield_2], ISFLAG_EQ_WEAPON_MASK );
+ }
+ else
+ {
+ // Most staves only give curse status when wielded and
+ // right now that's always "uncursed". -- bwr
+ set_ident_flags( you.inv[item_wield_2], ISFLAG_KNOW_CURSE );
+ }
+ }
+
+ if (you.inv[item_wield_2].base_type == OBJ_WEAPONS)
+ {
+ if (is_demonic(you.inv[item_wield_2].sub_type)
+ && (you.religion == GOD_ZIN || you.religion == GOD_SHINING_ONE
+ || you.religion == GOD_ELYVILON))
+ {
+ if (showMsgs)
+ mpr("You really shouldn't be using a nasty item like this.");
+ }
+
+ set_ident_flags( you.inv[item_wield_2], ISFLAG_EQ_WEAPON_MASK );
+
+ if (is_random_artefact( you.inv[item_wield_2] ))
+ {
+ i_dam = randart_wpn_property(you.inv[item_wield_2], RAP_BRAND);
+ use_randart(item_wield_2);
+ }
+ else
+ {
+ i_dam = you.inv[item_wield_2].special;
+ }
+
+ if (i_dam != SPWPN_NORMAL)
+ {
+ // message first
+ if (showMsgs)
+ {
+ switch (i_dam)
+ {
+ case SPWPN_SWORD_OF_CEREBOV:
+ case SPWPN_FLAMING:
+ mpr("It bursts into flame!");
+ break;
+
+ case SPWPN_FREEZING:
+ mpr("It glows with a cold blue light!");
+ break;
+
+ case SPWPN_HOLY_WRATH:
+ mpr("It softly glows with a divine radiance!");
+ break;
+
+ case SPWPN_ELECTROCUTION:
+ mpr("You hear the crackle of electricity.");
+ break;
+
+ case SPWPN_ORC_SLAYING:
+ mpr((you.species == SP_HILL_ORC)
+ ? "You feel a sudden desire to commit suicide."
+ : "You feel a sudden desire to kill orcs!");
+ break;
+
+ case SPWPN_VENOM:
+ mpr("It begins to drip with poison!");
+ break;
+
+ case SPWPN_PROTECTION:
+ mpr("You feel protected!");
+ break;
+
+ case SPWPN_DRAINING:
+ mpr("You sense an unholy aura.");
+ break;
+
+ case SPWPN_SPEED:
+ mpr("Your hands tingle!");
+ break;
+
+ case SPWPN_FLAME:
+ mpr("It glows red for a moment.");
+ break;
+
+ case SPWPN_FROST:
+ mpr("It is covered in frost.");
+ break;
+
+ case SPWPN_VAMPIRICISM:
+ if (!you.is_undead)
+ mpr("You feel a strange hunger.");
+ else
+ mpr("You feel strangely empty.");
+ break;
+
+ case SPWPN_DISRUPTION:
+ mpr("You sense a holy aura.");
+ break;
+
+ case SPWPN_PAIN:
+ mpr("A searing pain shoots up your arm!");
+ break;
+
+ case SPWPN_SINGING_SWORD:
+ mpr("The Singing Sword hums in delight!");
+ break;
+
+ case SPWPN_WRATH_OF_TROG:
+ mpr("You feel bloodthirsty!");
+ break;
+
+ case SPWPN_SCYTHE_OF_CURSES:
+ mpr("A shiver runs down your spine.");
+ break;
+
+ case SPWPN_GLAIVE_OF_PRUNE:
+ mpr("You feel pruney.");
+ break;
+
+ case SPWPN_SCEPTRE_OF_TORMENT:
+ mpr("A terribly searing pain shoots up your arm!");
+ break;
+
+ case SPWPN_SWORD_OF_ZONGULDROK:
+ mpr("You sense an extremely unholy aura.");
+ break;
+
+ case SPWPN_SWORD_OF_POWER:
+ mpr("You sense an aura of extreme power.");
+ break;
+
+ case SPWPN_STAFF_OF_OLGREB:
+ // mummies cannot smell
+ if (you.species != SP_MUMMY)
+ mpr("You smell chlorine.");
+ else
+ mpr("The staff glows slightly green.");
+ break;
+
+ case SPWPN_VAMPIRES_TOOTH:
+ // mummies cannot smell, and do not hunger {dlb}
+ if (!you.is_undead)
+ mpr("You feel a strange hunger, and smell blood on the air...");
+ else
+ mpr("You feel strangely empty.");
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // effect second
+ switch (i_dam)
+ {
+ case SPWPN_PROTECTION:
+ you.redraw_armour_class = 1;
+ break;
+
+ case SPWPN_DISTORTION:
+ miscast_effect( SPTYP_TRANSLOCATION, 9, 90, 100, "a distortion effect" );
+ break;
+
+ case SPWPN_SINGING_SWORD:
+ you.special_wield = SPWLD_SING;
+ break;
+
+ case SPWPN_WRATH_OF_TROG:
+ you.special_wield = SPWLD_TROG;
+ break;
+
+ case SPWPN_SCYTHE_OF_CURSES:
+ you.special_wield = SPWLD_CURSE;
+ if (one_chance_in(5))
+ do_curse_item( you.inv[item_wield_2] );
+ break;
+
+ case SPWPN_MACE_OF_VARIABILITY:
+ you.special_wield = SPWLD_VARIABLE;
+ break;
+
+ case SPWPN_GLAIVE_OF_PRUNE:
+ you.special_wield = SPWLD_NONE;
+ break;
+
+ case SPWPN_SCEPTRE_OF_TORMENT:
+ you.special_wield = SPWLD_TORMENT;
+ break;
+
+ case SPWPN_SWORD_OF_ZONGULDROK:
+ you.special_wield = SPWLD_ZONGULDROK;
+ break;
+
+ case SPWPN_SWORD_OF_POWER:
+ you.special_wield = SPWLD_POWER;
+ break;
+
+ case SPWPN_STAFF_OF_OLGREB:
+ // josh declares mummies cannot smell {dlb}
+ you.special_wield = SPWLD_OLGREB;
+ break;
+
+ case SPWPN_STAFF_OF_WUCAD_MU:
+ miscast_effect( SPTYP_DIVINATION, 9, 90, 100, "the Staff of Wucad Mu" );
+ you.special_wield = SPWLD_WUCAD_MU;
+ break;
+ }
+ }
+
+ if (item_cursed( you.inv[item_wield_2] ))
+ mpr("It sticks to your hand!");
+ }
+} // end wield_weapon()
+
+//---------------------------------------------------------------
+//
+// armour_prompt
+//
+// Prompt the user for some armour. Returns true if the user picked
+// something legit.
+//
+//---------------------------------------------------------------
+bool armour_prompt( const std::string & mesg, int *index )
+{
+ ASSERT(index != NULL);
+
+ bool succeeded = false;
+ int slot;
+
+ if (inv_count() < 1)
+ canned_msg(MSG_NOTHING_CARRIED);
+ else if (you.berserker)
+ canned_msg(MSG_TOO_BERSERK);
+ else
+ {
+ slot = prompt_invent_item( mesg.c_str(), OBJ_ARMOUR );
+
+ if (slot != PROMPT_ABORT)
+ {
+ *index = slot;
+ succeeded = true;
+ }
+ }
+
+ return (succeeded);
+} // end armour_prompt()
+
+static bool cloak_is_being_removed( void )
+{
+ if (current_delay_action() != DELAY_ARMOUR_OFF)
+ return (false);
+
+ if (you.delay_queue.front().parm1 != you.equip[ EQ_CLOAK ])
+ return (false);
+
+ return (true);
+}
+
+//---------------------------------------------------------------
+//
+// wear_armour
+//
+//---------------------------------------------------------------
+void wear_armour(void)
+{
+ int armour_wear_2;
+
+ if (!armour_prompt("Wear which item?", &armour_wear_2))
+ return;
+
+ do_wear_armour( armour_wear_2, false );
+}
+
+bool do_wear_armour( int item, bool quiet )
+{
+ char wh_equip = 0;
+
+ if (!is_valid_item( you.inv[item] ))
+ {
+ if (!quiet)
+ mpr("You don't have any such object.");
+
+ return (false);
+ }
+
+ if (you.inv[item].base_type != OBJ_ARMOUR)
+ {
+ if (!quiet)
+ mpr("You can't wear that.");
+
+ return (false);
+ }
+
+ if (item == you.equip[EQ_WEAPON])
+ {
+ if (!quiet)
+ mpr("You are wielding that object!");
+
+ return (false);
+ }
+
+ for (int loopy = EQ_CLOAK; loopy <= EQ_BODY_ARMOUR; loopy++)
+ {
+ if (item == you.equip[loopy])
+ {
+ if (!quiet)
+ mpr("You are already wearing that!");
+
+ return (false);
+ }
+ }
+
+ // if you're wielding something,
+ if (you.equip[EQ_WEAPON] != -1
+ // attempting to wear a shield,
+ && (you.inv[item].sub_type == ARM_SHIELD
+ || you.inv[item].sub_type == ARM_BUCKLER
+ || you.inv[item].sub_type == ARM_LARGE_SHIELD)
+ // weapon is two-handed
+ && hands_reqd_for_weapon(you.inv[you.equip[EQ_WEAPON]].base_type,
+ you.inv[you.equip[EQ_WEAPON]].sub_type) == HANDS_TWO_HANDED)
+ {
+ if (!quiet)
+ mpr("You'd need three hands to do that!");
+
+ return (false);
+ }
+
+ if (you.inv[item].sub_type == ARM_BOOTS)
+ {
+ if (you.species != SP_NAGA && you.inv[item].plus2 == TBOOT_NAGA_BARDING)
+ {
+ if (!quiet)
+ mpr("You can't wear that!");
+
+ return (false);
+ }
+
+ if (you.species != SP_CENTAUR && you.inv[item].plus2 == TBOOT_CENTAUR_BARDING)
+ {
+ if (!quiet)
+ mpr("You can't wear that!");
+
+ return (false);
+ }
+
+ if (player_is_swimming() && you.species == SP_MERFOLK)
+ {
+ if (!quiet)
+ mpr("You don't currently have feet!");
+
+ return (false);
+ }
+ }
+
+ wh_equip = EQ_BODY_ARMOUR;
+
+ switch (you.inv[item].sub_type)
+ {
+ case ARM_BUCKLER:
+ case ARM_LARGE_SHIELD:
+ case ARM_SHIELD:
+ wh_equip = EQ_SHIELD;
+ break;
+ case ARM_CLOAK:
+ wh_equip = EQ_CLOAK;
+ break;
+ case ARM_HELMET:
+ wh_equip = EQ_HELMET;
+ break;
+ case ARM_GLOVES:
+ wh_equip = EQ_GLOVES;
+ break;
+ case ARM_BOOTS:
+ wh_equip = EQ_BOOTS;
+ break;
+ }
+
+ if (you.species == SP_NAGA && you.inv[item].sub_type == ARM_BOOTS
+ && you.inv[item].plus2 == TBOOT_NAGA_BARDING
+ && !player_is_shapechanged())
+ {
+ // it fits
+ }
+ else if (you.species == SP_CENTAUR
+ && you.inv[item].sub_type == ARM_BOOTS
+ && you.inv[item].plus2 == TBOOT_CENTAUR_BARDING
+ && !player_is_shapechanged())
+ {
+ // it fits
+ }
+ else if (you.inv[item].sub_type == ARM_HELMET
+ && (cmp_helmet_type( you.inv[item], THELM_CAP )
+ || cmp_helmet_type( you.inv[item], THELM_WIZARD_HAT )))
+ {
+ // caps & wiz hats always fit, unless your head's too big (ogres &c)
+ }
+ else if (!can_equip( wh_equip ))
+ {
+ if (!quiet)
+ mpr("You can't wear that in your present form.");
+
+ return (false);
+ }
+
+ // Cannot swim in heavy armour
+ if (player_is_swimming()
+ && wh_equip == EQ_BODY_ARMOUR
+ && !is_light_armour( you.inv[item] ))
+ {
+ if (!quiet)
+ mpr("You can't swim in that!");
+
+ return (false);
+ }
+
+ // Giant races
+ if ((you.species >= SP_OGRE && you.species <= SP_OGRE_MAGE)
+ || player_genus(GENPC_DRACONIAN))
+ {
+ if ((you.inv[item].sub_type >= ARM_LEATHER_ARMOUR
+ && you.inv[item].sub_type <= ARM_PLATE_MAIL)
+ || (you.inv[item].sub_type >= ARM_GLOVES
+ && you.inv[item].sub_type <= ARM_BUCKLER)
+ || you.inv[item].sub_type == ARM_CRYSTAL_PLATE_MAIL
+ || (you.inv[item].sub_type == ARM_HELMET
+ && (cmp_helmet_type( you.inv[item], THELM_HELM )
+ || cmp_helmet_type( you.inv[item], THELM_HELMET ))))
+ {
+ if (!quiet)
+ mpr("This armour doesn't fit on your body.");
+
+ return (false);
+ }
+ }
+
+ // Tiny races
+ if (you.species == SP_SPRIGGAN)
+ {
+ if ((you.inv[item].sub_type >= ARM_LEATHER_ARMOUR
+ && you.inv[item].sub_type <= ARM_PLATE_MAIL)
+ || you.inv[item].sub_type == ARM_GLOVES
+ || you.inv[item].sub_type == ARM_BOOTS
+ || you.inv[item].sub_type == ARM_SHIELD
+ || you.inv[item].sub_type == ARM_LARGE_SHIELD
+ || you.inv[item].sub_type == ARM_CRYSTAL_PLATE_MAIL
+ || (you.inv[item].sub_type == ARM_HELMET
+ && (cmp_helmet_type( you.inv[item], THELM_HELM )
+ || cmp_helmet_type( you.inv[item], THELM_HELMET ))))
+ {
+ if (!quiet)
+ mpr("This armour doesn't fit on your body.");
+
+ return (false);
+ }
+ }
+
+ bool removedCloak = false;
+ int cloak = -1;
+
+ if ((you.inv[item].sub_type < ARM_SHIELD
+ || you.inv[item].sub_type > ARM_LARGE_SHIELD)
+ && (you.equip[EQ_CLOAK] != -1 && !cloak_is_being_removed()))
+ {
+ if (item_uncursed( you.inv[you.equip[EQ_CLOAK]] ))
+ {
+ cloak = you.equip[ EQ_CLOAK ];
+ if (!takeoff_armour(you.equip[EQ_CLOAK]))
+ return (false);
+
+ removedCloak = true;
+ }
+ else
+ {
+ if (!quiet)
+ mpr("Your cloak prevents you from wearing the armour.");
+
+ return (false);
+ }
+ }
+
+ if (you.inv[item].sub_type == ARM_CLOAK && you.equip[EQ_CLOAK] != -1)
+ {
+ if (!takeoff_armour(you.equip[EQ_CLOAK]))
+ return (false);
+ }
+
+ if (you.inv[item].sub_type == ARM_HELMET && you.equip[EQ_HELMET] != -1)
+ {
+ if (!takeoff_armour(you.equip[EQ_HELMET]))
+ return (false);
+ }
+
+ if (you.inv[item].sub_type == ARM_GLOVES && you.equip[EQ_GLOVES] != -1)
+ {
+ if (!takeoff_armour(you.equip[EQ_GLOVES]))
+ return (false);
+ }
+
+ if (you.inv[item].sub_type == ARM_BOOTS && you.equip[EQ_BOOTS] != -1)
+ {
+ if (!takeoff_armour(you.equip[EQ_BOOTS]))
+ return (false);
+ }
+
+ if ((you.inv[item].sub_type == ARM_SHIELD
+ || you.inv[item].sub_type == ARM_LARGE_SHIELD
+ || you.inv[item].sub_type == ARM_BUCKLER)
+ && you.equip[EQ_SHIELD] != -1)
+ {
+ if (!takeoff_armour(you.equip[EQ_SHIELD]))
+ return (false);
+ }
+
+ if ((you.inv[item].sub_type < ARM_SHIELD
+ || you.inv[item].sub_type > ARM_LARGE_SHIELD)
+ && you.equip[EQ_BODY_ARMOUR] != -1)
+ {
+ if (!takeoff_armour(you.equip[EQ_BODY_ARMOUR]))
+ return (false);
+ }
+
+ you.turn_is_over = 1;
+
+ int delay = property( you.inv[item], PARM_AC );
+
+ if (delay < 1)
+ delay = 1;
+
+ if (delay)
+ start_delay( DELAY_ARMOUR_ON, delay, item );
+
+ if (removedCloak)
+ start_delay( DELAY_ARMOUR_ON, 1, cloak );
+
+ return (true);
+} // do_end wear_armour()
+
+bool takeoff_armour(int item)
+{
+ if (you.inv[item].base_type != OBJ_ARMOUR)
+ {
+ mpr("You aren't wearing that!");
+ return false;
+ }
+
+ if (item_cursed( you.inv[item] ))
+ {
+ for (int loopy = EQ_CLOAK; loopy <= EQ_BODY_ARMOUR; loopy++)
+ {
+ if (item == you.equip[loopy])
+ {
+ in_name(item, DESC_CAP_YOUR, info);
+ strcat(info, " is stuck to your body!");
+ mpr(info);
+ return false;
+ }
+ }
+ }
+
+ bool removedCloak = false;
+ int cloak = -1;
+
+ if (you.inv[item].sub_type < ARM_SHIELD
+ || you.inv[item].sub_type > ARM_LARGE_SHIELD)
+ {
+ if (you.equip[EQ_CLOAK] != -1 && !cloak_is_being_removed())
+ {
+ if (item_uncursed( you.inv[you.equip[EQ_CLOAK]] ))
+ {
+ cloak = you.equip[ EQ_CLOAK ];
+ if (!takeoff_armour(you.equip[EQ_CLOAK]))
+ return (false);
+
+ removedCloak = true;
+ }
+ else
+ {
+ mpr("Your cloak prevents you from removing the armour.");
+ return false;
+ }
+ }
+
+ if (item != you.equip[EQ_BODY_ARMOUR])
+ {
+ mpr("You aren't wearing that!");
+ return false;
+ }
+
+ // you.equip[EQ_BODY_ARMOUR] = -1;
+ }
+ else
+ {
+ switch (you.inv[item].sub_type)
+ {
+ case ARM_BUCKLER:
+ case ARM_LARGE_SHIELD:
+ case ARM_SHIELD:
+ if (item != you.equip[EQ_SHIELD])
+ {
+ mpr("You aren't wearing that!");
+ return false;
+ }
+ break;
+
+ case ARM_CLOAK:
+ if (item != you.equip[EQ_CLOAK])
+ {
+ mpr("You aren't wearing that!");
+ return false;
+ }
+ break;
+
+ case ARM_HELMET:
+ if (item != you.equip[EQ_HELMET])
+ {
+ mpr("You aren't wearing that!");
+ return false;
+ }
+ break;
+
+
+ case ARM_GLOVES:
+ if (item != you.equip[EQ_GLOVES])
+ {
+ mpr("You aren't wearing that!");
+ return false;
+ }
+ break;
+
+ case ARM_BOOTS:
+ if (item != you.equip[EQ_BOOTS])
+ {
+ mpr("You aren't wearing that!");
+ return false;
+ }
+ break;
+ }
+ }
+
+ you.turn_is_over = 1;
+
+ int delay = property( you.inv[item], PARM_AC );
+
+ if (delay < 1)
+ delay = 1;
+
+ start_delay( DELAY_ARMOUR_OFF, delay, item );
+
+ if (removedCloak)
+ start_delay( DELAY_ARMOUR_ON, 1, cloak );
+
+ return true;
+} // end takeoff_armour()
+
+void throw_anything(void)
+{
+ struct bolt beam;
+ int throw_slot;
+
+ if (you.berserker)
+ {
+ canned_msg(MSG_TOO_BERSERK);
+ return;
+ }
+ else if (inv_count() < 1)
+ {
+ canned_msg(MSG_NOTHING_CARRIED);
+ return;
+ }
+
+ throw_slot = prompt_invent_item( "Throw which item?", OBJ_MISSILES );
+ if (throw_slot == PROMPT_ABORT)
+ {
+ canned_msg( MSG_OK );
+ return;
+ }
+
+ if (throw_slot == you.equip[EQ_WEAPON]
+ && (item_cursed( you.inv[you.equip[EQ_WEAPON]] )))
+ {
+ mpr("That thing is stuck to your hand!");
+ return;
+ }
+ else
+ {
+ for (int loopy = EQ_CLOAK; loopy <= EQ_AMULET; loopy++)
+ {
+ if (throw_slot == you.equip[loopy])
+ {
+ mpr("You are wearing that object!");
+ return;
+ }
+ }
+ }
+
+ throw_it(beam, throw_slot);
+} // end throw_anything()
+
+// Return index of first valid balanced throwing weapon or ENDOFPACK
+static int try_finding_throwing_weapon( int sub_type )
+{
+ int i;
+
+ for (i = Options.fire_items_start; i < ENDOFPACK; i++)
+ {
+ // skip invalid objects, wielded object
+ if (!is_valid_item( you.inv[i] ) || you.equip[EQ_WEAPON] == i)
+ continue;
+
+ // consider melee weapons that can also be thrown
+ if (you.inv[i].base_type == OBJ_WEAPONS
+ && you.inv[i].sub_type == sub_type)
+ {
+ break;
+ }
+ }
+
+ return (i);
+}
+
+// Return index of first missile of sub_type or ENDOFPACK
+static int try_finding_missile( int sub_type )
+{
+ int i;
+
+ for (i = Options.fire_items_start; i < ENDOFPACK; i++)
+ {
+ // skip invalid objects
+ if (!is_valid_item( you.inv[i] ))
+ continue;
+
+ // consider melee weapons that can also be thrown
+ if (you.inv[i].base_type == OBJ_MISSILES
+ && you.inv[i].sub_type == sub_type)
+ {
+ break;
+ }
+ }
+
+ return (i);
+}
+
+// Note: This is a simple implementation, not an efficient one. -- bwr
+//
+// Returns item index or ENDOFPACK if no item found for auto-firing
+int get_fire_item_index( void )
+{
+ int item = ENDOFPACK;
+ const int weapon = you.equip[ EQ_WEAPON ];
+
+ for (int i = 0; i < NUM_FIRE_TYPES; i++)
+ {
+ // look for next type on list... if found item is set != ENDOFPACK
+ switch (Options.fire_order[i])
+ {
+ case FIRE_LAUNCHER:
+ // check if we have ammo for a wielded launcher:
+ if (weapon != -1
+ && you.inv[ weapon ].base_type == OBJ_WEAPONS
+ && launches_things( you.inv[ weapon ].sub_type ))
+ {
+ int type_wanted = launched_by( you.inv[ weapon ].sub_type );
+ item = try_finding_missile( type_wanted );
+ }
+ break;
+
+ case FIRE_DART:
+ item = try_finding_missile( MI_DART );
+ break;
+
+ case FIRE_STONE:
+ item = try_finding_missile( MI_STONE );
+ break;
+
+ case FIRE_DAGGER:
+ item = try_finding_throwing_weapon( WPN_DAGGER );
+ break;
+
+ case FIRE_SPEAR:
+ item = try_finding_throwing_weapon( WPN_SPEAR );
+ break;
+
+ case FIRE_HAND_AXE:
+ item = try_finding_throwing_weapon( WPN_HAND_AXE );
+ break;
+
+ case FIRE_CLUB:
+ item = try_finding_throwing_weapon( WPN_CLUB );
+ break;
+
+ case FIRE_NONE:
+ default:
+ break;
+ }
+
+ // if successful break
+ if (item != ENDOFPACK)
+ break;
+ }
+
+ // either item was found or is still ENDOFPACK for no item
+ return (item);
+}
+
+void shoot_thing(void)
+{
+ struct bolt beam; // passed in by reference, but never used here
+ char str_pass[ ITEMNAME_SIZE ];
+
+ if (you.berserker)
+ {
+ canned_msg(MSG_TOO_BERSERK);
+ return;
+ }
+
+ const int item = get_fire_item_index();
+
+ if (item == ENDOFPACK)
+ {
+ mpr("No suitable missiles.");
+ return;
+ }
+
+ in_name( item, DESC_INVENTORY_EQUIP, str_pass );
+ snprintf( info, INFO_SIZE, "Firing: %s", str_pass );
+ mpr( info );
+
+ throw_it( beam, item );
+} // end shoot_thing()
+
+// throw_it - currently handles player throwing only. Monster
+// throwing is handled in mstuff2:mons_throw()
+static void throw_it(struct bolt &pbolt, int throw_2)
+{
+ struct dist thr;
+ char shoot_skill = 0;
+
+ char wepClass, wepType; // ammo class and type
+ char lnchClass, lnchType; // launcher class and type
+
+ int baseHit = 0, baseDam = 0; // from thrown or ammo
+ int ammoHitBonus = 0, ammoDamBonus = 0; // from thrown or ammo
+ int lnchHitBonus = 0, lnchDamBonus = 0; // special add from launcher
+ int exHitBonus = 0, exDamBonus = 0; // 'extra' bonus from skill/dex/str
+ int effSkill = 0; // effective launcher skill
+ bool launched = false; // item is launched
+ bool thrown = false; // item is sensible thrown item
+
+ // Making a copy of the item: changed only for venom launchers
+ item_def item = you.inv[throw_2];
+ item.quantity = 1;
+
+ char str_pass[ ITEMNAME_SIZE ];
+
+ mpr( STD_DIRECTION_PROMPT, MSGCH_PROMPT );
+
+ message_current_target();
+
+ direction( thr, DIR_NONE, TARG_ENEMY );
+
+ if (!thr.isValid)
+ {
+ if (thr.isCancel)
+ canned_msg(MSG_OK);
+
+ return;
+ }
+
+ if (you.conf)
+ {
+ thr.isTarget = true;
+ thr.tx = you.x_pos + random2(13) - 6;
+ thr.ty = you.y_pos + random2(13) - 6;
+ }
+
+ // even though direction is allowed, we're throwing so we
+ // want to use tx, ty to make the missile fly to map edge.
+ pbolt.target_x = thr.tx;
+ pbolt.target_y = thr.ty;
+
+ pbolt.flavour = BEAM_MISSILE;
+ // pbolt.range is set below
+
+ switch (item.base_type)
+ {
+ case OBJ_WEAPONS: pbolt.type = SYM_WEAPON; break;
+ case OBJ_MISSILES: pbolt.type = SYM_MISSILE; break;
+ case OBJ_ARMOUR: pbolt.type = SYM_ARMOUR; break;
+ case OBJ_WANDS: pbolt.type = SYM_STICK; break;
+ case OBJ_FOOD: pbolt.type = SYM_CHUNK; break;
+ case OBJ_UNKNOWN_I: pbolt.type = SYM_BURST; break;
+ case OBJ_SCROLLS: pbolt.type = SYM_SCROLL; break;
+ case OBJ_JEWELLERY: pbolt.type = SYM_TRINKET; break;
+ case OBJ_POTIONS: pbolt.type = SYM_FLASK; break;
+ case OBJ_UNKNOWN_II: pbolt.type = SYM_ZAP; break;
+ case OBJ_BOOKS: pbolt.type = SYM_OBJECT; break;
+ // this does not seem right, but value was 11 {dlb}
+ // notice how the .type does not match the class -- hmmm... {dlb}
+ case OBJ_STAVES: pbolt.type = SYM_CHUNK; break;
+ }
+
+ pbolt.source_x = you.x_pos;
+ pbolt.source_y = you.y_pos;
+ pbolt.colour = item.colour;
+
+ item_name( item, DESC_PLAIN, str_pass );
+ strcpy( pbolt.beam_name, str_pass );
+
+ pbolt.thrower = KILL_YOU_MISSILE;
+ pbolt.aux_source = NULL;
+
+ // get the ammo/weapon type. Convenience.
+ wepClass = item.base_type;
+ wepType = item.sub_type;
+
+ // get the launcher class,type. Convenience.
+ if (you.equip[EQ_WEAPON] < 0)
+ {
+ lnchClass = -1;
+ // set lnchType to 0 so the 'figure out if launched'
+ // code doesn't break
+ lnchType = 0;
+ }
+ else
+ {
+ lnchClass = you.inv[you.equip[EQ_WEAPON]].base_type;
+ lnchType = you.inv[you.equip[EQ_WEAPON]].sub_type;
+ }
+
+ // baseHit and damage for generic objects
+ baseHit = you.strength - mass_item(item) / 10;
+ if (baseHit > 0)
+ baseHit = 0;
+
+ baseDam = mass_item(item) / 100;
+
+ // special: might be throwing generic weapon;
+ // use base wep. damage, w/ penalty
+ if (wepClass == OBJ_WEAPONS)
+ {
+ baseDam = property( item, PWPN_DAMAGE ) - 4;
+ if (baseDam < 0)
+ baseDam = 0;
+ }
+
+ // figure out if we're thrown or launched
+ throw_type(lnchClass, lnchType, wepClass, wepType, launched, thrown);
+
+ // extract launcher bonuses due to magic
+ if (launched)
+ {
+ lnchHitBonus = you.inv[you.equip[EQ_WEAPON]].plus;
+ lnchDamBonus = you.inv[you.equip[EQ_WEAPON]].plus2;
+ }
+
+ // extract weapon/ammo bonuses due to magic
+ ammoHitBonus = item.plus;
+ ammoDamBonus = item.plus2;
+
+ // CALCULATIONS FOR LAUNCHED WEAPONS
+ if (launched)
+ {
+ const int bow_brand = get_weapon_brand( you.inv[you.equip[EQ_WEAPON]] );
+ const int ammo_brand = get_ammo_brand( item );
+ bool poisoned = (ammo_brand == SPMSL_POISONED
+ || ammo_brand == SPMSL_POISONED_II);
+
+ // this is deliberately confusing: the 'hit' value for
+ // ammo is the _damage_ when used with a launcher. Geez.
+ baseHit = 0;
+ baseDam = property( item, PWPN_HIT );
+
+ // fix ammo damage bonus, since missiles only use inv_plus
+ ammoDamBonus = ammoHitBonus;
+
+ // check for matches; dwarven,elven,orcish
+ if (!cmp_equip_race( you.inv[you.equip[EQ_WEAPON]], 0 ))
+ {
+ if (get_equip_race( you.inv[you.equip[EQ_WEAPON]] )
+ == get_equip_race( item ))
+ {
+ baseHit += 1;
+ baseDam += 1;
+
+ // elves with elven bows
+ if (cmp_equip_race(you.inv[you.equip[EQ_WEAPON]], ISFLAG_ELVEN)
+ && player_genus(GENPC_ELVEN))
+ {
+ baseHit += 1;
+ }
+ }
+ }
+
+ if (you.inv[you.equip[EQ_WEAPON]].sub_type == WPN_CROSSBOW)
+ {
+ // extra time taken, as a percentage. range from 30 -> 12
+ int extraTime = 30 - ((you.skills[SK_CROSSBOWS] * 2) / 3);
+
+ you.time_taken = (100 + extraTime) * you.time_taken;
+ you.time_taken /= 100;
+ }
+
+ if (bow_brand == SPWPN_SPEED)
+ {
+ you.time_taken *= 5;
+ you.time_taken /= 10;
+ }
+
+ // for all launched weapons, maximum effective specific skill
+ // is twice throwing skill. This models the fact that no matter
+ // how 'good' you are with a bow, if you know nothing about
+ // trajectories you're going to be a damn poor bowman. Ditto
+ // for crossbows and slings.
+ switch (lnchType)
+ {
+ case WPN_SLING:
+ shoot_skill = you.skills[SK_SLINGS];
+ break;
+ case WPN_BOW:
+ shoot_skill = you.skills[SK_BOWS];
+ break;
+ case WPN_BLOWGUN:
+ shoot_skill = you.skills[SK_DARTS];
+ break;
+ case WPN_CROSSBOW:
+ case WPN_HAND_CROSSBOW:
+ shoot_skill = you.skills[SK_CROSSBOWS];
+ break;
+ default:
+ shoot_skill = 0;
+ break;
+ }
+
+ effSkill = you.skills[SK_THROWING] * 2 + 1;
+ effSkill = (shoot_skill > effSkill) ? effSkill : shoot_skill;
+
+ // removed 2 random2(2)s from each of the learning curves, but
+ // left slings because they're hard enough to develop without
+ // a good source of shot in the dungeon.
+ switch (lnchType)
+ {
+ case WPN_SLING:
+ // Slings are really easy to learn because they're not
+ // really all that good, and its harder to get ammo anyways.
+ exercise(SK_SLINGS, 1 + random2avg(3, 2));
+ baseHit += 0;
+ exHitBonus = (effSkill * 3) / 2;
+
+ // strength is good if you're using a nice sling.
+ exDamBonus = (10 * (you.strength - 10)) / 9;
+ exDamBonus = (exDamBonus * (2 * baseDam + ammoDamBonus)) / 20;
+
+ // cap
+ if (exDamBonus > lnchDamBonus + 1)
+ exDamBonus = lnchDamBonus + 1;
+
+ // add skill for slings.. helps to find those vulnerable spots
+ exDamBonus += effSkill / 2;
+
+ // now kill the launcher damage bonus
+ if (lnchDamBonus > 0)
+ lnchDamBonus = 0;
+ break;
+
+ // blowguns take a _very_ steady hand; a lot of the bonus
+ // comes from dexterity. (Dex bonus here as well as below)
+ case WPN_BLOWGUN:
+ exercise(SK_DARTS, (coinflip()? 2 : 1));
+ baseHit -= 2;
+ exHitBonus = (effSkill * 3) / 2 + you.dex / 2;
+
+ // no extra damage for blowguns
+ exDamBonus = 0;
+
+ // now kill the launcher damage and ammo bonuses
+ if (lnchDamBonus > 0)
+ lnchDamBonus = 0;
+ if (ammoDamBonus > 0)
+ ammoDamBonus = 0;
+ break;
+
+
+ case WPN_BOW:
+ exercise(SK_BOWS, (coinflip()? 2 : 1));
+ baseHit -= 4;
+ exHitBonus = (effSkill * 2);
+
+ // strength is good if you're using a nice bow
+ exDamBonus = (10 * (you.strength - 10)) / 4;
+ exDamBonus = (exDamBonus * (2 * baseDam + ammoDamBonus)) / 20;
+
+ // cap
+ if (exDamBonus > (lnchDamBonus + 1) * 3)
+ exDamBonus = (lnchDamBonus + 1) * 3;
+
+ // add in skill for bows.. help you to find those vulnerable spots.
+ exDamBonus += effSkill;
+
+ // now kill the launcher damage bonus
+ if (lnchDamBonus > 0)
+ lnchDamBonus = 0;
+ break;
+
+ // Crossbows are easy for unskilled people.
+
+ case WPN_CROSSBOW:
+ exercise(SK_CROSSBOWS, (coinflip()? 2 : 1));
+ baseHit += 2;
+ exHitBonus = (3 * effSkill) / 2 + 6;
+ exDamBonus = effSkill / 2 + 4;
+ break;
+
+ case WPN_HAND_CROSSBOW:
+ exercise(SK_CROSSBOWS, (coinflip()? 2 : 1));
+ baseHit += 1;
+ exHitBonus = (3 * effSkill) / 2 + 4;
+ exDamBonus = effSkill / 2 + 2;
+ break;
+ }
+
+ // all launched weapons have a slight chance of improving
+ // throwing skill
+ if (coinflip())
+ exercise(SK_THROWING, 1);
+
+ // all launched weapons get a tohit boost from throwing skill.
+ exHitBonus += (3 * you.skills[SK_THROWING]) / 4;
+
+ // special cases for flame, frost, poison, etc.
+ // check for venom brand (usually only available for blowguns)
+ if (bow_brand == SPWPN_VENOM && ammo_brand == SPMSL_NORMAL)
+ {
+ // poison brand the ammo
+ set_item_ego_type( item, OBJ_MISSILES, SPMSL_POISONED );
+ item_name( item, DESC_PLAIN, str_pass );
+ strcpy( pbolt.beam_name, str_pass );
+ }
+
+ // Note that bow_brand is known since the bow is equiped.
+ if ((bow_brand == SPWPN_FLAME || ammo_brand == SPMSL_FLAME)
+ && ammo_brand != SPMSL_ICE && bow_brand != SPWPN_FROST)
+ {
+ baseDam += 1 + random2(5);
+ pbolt.flavour = BEAM_FIRE;
+ strcpy(pbolt.beam_name, "bolt of ");
+
+ if (poisoned)
+ strcat(pbolt.beam_name, "poison ");
+
+ strcat(pbolt.beam_name, "flame");
+ pbolt.colour = RED;
+ pbolt.type = SYM_BOLT;
+ pbolt.thrower = KILL_YOU_MISSILE;
+ pbolt.aux_source = NULL;
+
+ // ammo known if we can't attribute it to the bow
+ if (bow_brand != SPWPN_FLAME)
+ {
+ set_ident_flags( item, ISFLAG_KNOW_TYPE );
+ set_ident_flags( you.inv[throw_2], ISFLAG_KNOW_TYPE );
+ }
+ }
+
+ if ((bow_brand == SPWPN_FROST || ammo_brand == SPMSL_ICE)
+ && ammo_brand != SPMSL_FLAME && bow_brand != SPWPN_FLAME)
+ {
+ baseDam += 1 + random2(5);
+ pbolt.flavour = BEAM_COLD;
+ strcpy(pbolt.beam_name, "bolt of ");
+
+ if (poisoned)
+ strcat(pbolt.beam_name, "poison ");
+
+ strcat(pbolt.beam_name, "frost");
+ pbolt.colour = WHITE;
+ pbolt.type = SYM_BOLT;
+ pbolt.thrower = KILL_YOU_MISSILE;
+ pbolt.aux_source = NULL;
+
+ // ammo known if we can't attribute it to the bow
+ if (bow_brand != SPWPN_FROST)
+ {
+ set_ident_flags( item, ISFLAG_KNOW_TYPE );
+ set_ident_flags( you.inv[throw_2], ISFLAG_KNOW_TYPE );
+ }
+ }
+
+ // ammo known if it cancels the effect of the bow
+ if ((bow_brand == SPWPN_FLAME && ammo_brand == SPMSL_ICE)
+ || (bow_brand == SPWPN_FROST && ammo_brand == SPMSL_FLAME))
+ {
+ set_ident_flags( item, ISFLAG_KNOW_TYPE );
+ set_ident_flags( you.inv[throw_2], ISFLAG_KNOW_TYPE );
+ }
+
+ /* the chief advantage here is the extra damage this does
+ * against susceptible creatures */
+
+ /* Note: weapons & ammo of eg fire are not cumulative
+ * ammo of fire and weapons of frost don't work together,
+ * and vice versa */
+
+ // ID check
+ if (item_not_ident( you.inv[you.equip[EQ_WEAPON]], ISFLAG_KNOW_PLUSES )
+ && random2(100) < shoot_skill)
+ {
+ set_ident_flags(you.inv[you.equip[EQ_WEAPON]], ISFLAG_KNOW_PLUSES);
+
+ strcpy(info, "You are wielding ");
+ in_name(you.equip[EQ_WEAPON], DESC_NOCAP_A, str_pass);
+ strcat(info, str_pass);
+ strcat(info, ".");
+ mpr(info);
+
+ more();
+ you.wield_change = true;
+ }
+ }
+
+ // CALCULATIONS FOR THROWN WEAPONS
+ if (thrown)
+ {
+ baseHit = 0;
+
+ // since darts/rocks are missiles, they only use inv_plus
+ if (wepClass == OBJ_MISSILES)
+ ammoDamBonus = ammoHitBonus;
+
+ // all weapons that use 'throwing' go here..
+ if (wepClass == OBJ_WEAPONS
+ || (wepClass == OBJ_MISSILES && wepType == MI_STONE))
+ {
+ // elves with elven weapons
+ if (cmp_equip_race(item, ISFLAG_ELVEN) && player_genus(GENPC_ELVEN))
+ baseHit += 1;
+
+ // give an appropriate 'tohit' -
+ // hand axes and clubs are -5
+ // daggers are +1
+ // spears are -1
+ // rocks are 0
+ if (wepClass == OBJ_WEAPONS)
+ {
+ switch (wepType)
+ {
+ case WPN_DAGGER:
+ baseHit += 1;
+ break;
+ case WPN_SPEAR:
+ baseHit -= 1;
+ break;
+ default:
+ baseHit -= 5;
+ break;
+ }
+ }
+
+ exHitBonus = you.skills[SK_THROWING] * 2;
+
+ baseDam = property( item, PWPN_DAMAGE );
+ exDamBonus =
+ (10 * (you.skills[SK_THROWING] / 2 + you.strength - 10)) / 12;
+
+ // now, exDamBonus is a multiplier. The full multiplier
+ // is applied to base damage, but only a third is applied
+ // to the magical modifier.
+ exDamBonus = (exDamBonus * (3 * baseDam + ammoDamBonus)) / 30;
+ }
+
+ if (wepClass == OBJ_MISSILES && wepType == MI_DART)
+ {
+ // give an appropriate 'tohit' & damage
+ baseHit = 2;
+ baseDam = property( item, PWPN_DAMAGE );
+
+ exHitBonus = you.skills[SK_DARTS] * 2;
+ exHitBonus += (you.skills[SK_THROWING] * 2) / 3;
+ exDamBonus = you.skills[SK_DARTS] / 4;
+
+ // exercise skills
+ exercise(SK_DARTS, 1 + random2avg(3, 2));
+ }
+
+ // exercise skill
+ if (coinflip())
+ exercise(SK_THROWING, 1);
+ }
+
+ // range, dexterity bonus, possible skill increase for silly throwing
+ if (thrown || launched)
+ {
+ if (wepType == MI_LARGE_ROCK)
+ {
+ pbolt.range = 1 + random2( you.strength / 5 );
+ if (pbolt.range > 9)
+ pbolt.range = 9;
+
+ pbolt.rangeMax = pbolt.range;
+ }
+ else
+ {
+ pbolt.range = 9;
+ pbolt.rangeMax = 9;
+
+ exHitBonus += you.dex / 2;
+
+ // slaying bonuses
+ if (!(launched && wepType == MI_NEEDLE))
+ exDamBonus += slaying_bonus(PWPN_DAMAGE);
+
+ exHitBonus += slaying_bonus(PWPN_HIT);
+ }
+ }
+ else
+ {
+ // range based on mass & strength, between 1 and 9
+ pbolt.range = you.strength - mass_item(item) / 10 + 3;
+ if (pbolt.range < 1)
+ pbolt.range = 1;
+
+ if (pbolt.range > 9)
+ pbolt.range = 9;
+
+ // set max range equal to range for this
+ pbolt.rangeMax = pbolt.range;
+
+ if (one_chance_in(20))
+ exercise(SK_THROWING, 1);
+
+ exHitBonus = you.dex / 4;
+ }
+
+ // FINALIZE tohit and damage
+ if (exHitBonus >= 0)
+ pbolt.hit = baseHit + random2avg(exHitBonus + 1, 2);
+ else
+ pbolt.hit = baseHit - random2avg(0 - (exHitBonus - 1), 2);
+
+ if (exDamBonus >= 0)
+ pbolt.damage = dice_def( 1, baseDam + random2(exDamBonus + 1) );
+ else
+ pbolt.damage = dice_def( 1, baseDam - random2(0 - (exDamBonus - 1)) );
+
+ // only add bonuses if we're throwing something sensible
+ if (thrown || launched || wepClass == OBJ_WEAPONS)
+ {
+ pbolt.hit += ammoHitBonus + lnchHitBonus;
+ pbolt.damage.size += ammoDamBonus + lnchDamBonus;
+ }
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE,
+ "H:%d+%d;a%dl%d. D:%d+%d;a%dl%d -> %d,%dd%d",
+ baseHit, exHitBonus, ammoHitBonus, lnchHitBonus,
+ baseDam, exDamBonus, ammoDamBonus, lnchDamBonus,
+ pbolt.hit, pbolt.damage.num, pbolt.damage.size );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ // Must unwield before fire_beam() makes a copy in order to remove things
+ // like temporary branding. -- bwr
+ if (throw_2 == you.equip[EQ_WEAPON] && you.inv[throw_2].quantity == 1)
+ {
+ unwield_item( throw_2 );
+ you.equip[EQ_WEAPON] = -1;
+ canned_msg( MSG_EMPTY_HANDED );
+ }
+
+ // create message
+ if (launched)
+ strcpy(info, "You shoot ");
+ else
+ strcpy(info, "You throw ");
+
+ item_name( item, DESC_NOCAP_A, str_pass );
+
+ strcat(info, str_pass);
+ strcat(info, ".");
+ mpr(info);
+
+ // ensure we're firing a 'missile'-type beam
+ pbolt.isBeam = false;
+ pbolt.isTracer = false;
+
+ // using copy, since the launched item might be differect (venom blowgun)
+ fire_beam( pbolt, &item );
+
+ dec_inv_item_quantity( throw_2, 1 );
+
+ // throwing and blowguns are silent
+ if (launched && lnchType != WPN_BLOWGUN)
+ noisy( 6, you.x_pos, you.y_pos );
+
+ // but any monster nearby can see that something has been thrown:
+ alert_nearby_monsters();
+
+ you.turn_is_over = 1;
+} // end throw_it()
+
+void puton_ring(void)
+{
+ bool is_amulet = false;
+ int item_slot;
+ char str_pass[ ITEMNAME_SIZE ];
+
+ if (inv_count() < 1)
+ {
+ canned_msg(MSG_NOTHING_CARRIED);
+ return;
+ }
+
+ if (you.berserker)
+ {
+ canned_msg(MSG_TOO_BERSERK);
+ return;
+ }
+
+ item_slot = prompt_invent_item( "Put on which piece of jewellery?",
+ OBJ_JEWELLERY );
+
+ if (item_slot == PROMPT_ABORT)
+ {
+ canned_msg( MSG_OK );
+ return;
+ }
+
+ if (item_slot == you.equip[EQ_LEFT_RING]
+ || item_slot == you.equip[EQ_RIGHT_RING]
+ || item_slot == you.equip[EQ_AMULET])
+ {
+ mpr("You've already put that on!");
+ return;
+ }
+
+ if (item_slot == you.equip[EQ_WEAPON])
+ {
+ mpr("You are wielding that object.");
+ return;
+ }
+
+ if (you.inv[item_slot].base_type != OBJ_JEWELLERY)
+ {
+ //jmf: let's not take our inferiority complex out on players, eh? :-p
+ //mpr("You're sadly mistaken if you consider that jewellery.")
+ mpr("You can only put on jewellery.");
+ return;
+ }
+
+ is_amulet = (you.inv[item_slot].sub_type >= AMU_RAGE);
+
+ if (!is_amulet) // ie it's a ring
+ {
+ if (you.equip[EQ_GLOVES] != -1
+ && item_cursed( you.inv[you.equip[EQ_GLOVES]] ))
+ {
+ mpr("You can't take your gloves off to put on a ring!");
+ return;
+ }
+
+ if (you.inv[item_slot].base_type == OBJ_JEWELLERY
+ && you.equip[EQ_LEFT_RING] != -1
+ && you.equip[EQ_RIGHT_RING] != -1)
+ {
+ // and you are trying to wear body you.equip.
+ mpr("You've already put a ring on each hand.");
+ return;
+ }
+ }
+ else if (you.equip[EQ_AMULET] != -1)
+ {
+ strcpy(info, "You are already wearing an amulet.");
+
+ if (one_chance_in(20))
+ {
+ strcat(info, " And I must say it looks quite fetching.");
+ }
+
+ mpr(info);
+ return;
+ }
+
+ int hand_used = 0;
+
+ if (you.equip[EQ_LEFT_RING] != -1)
+ hand_used = 1;
+
+ if (you.equip[EQ_RIGHT_RING] != -1)
+ hand_used = 0;
+
+ if (is_amulet)
+ hand_used = 2;
+ else if (you.equip[EQ_LEFT_RING] == -1 && you.equip[EQ_RIGHT_RING] == -1)
+ {
+ mpr("Put on which hand (l or r)?", MSGCH_PROMPT);
+
+ int keyin = get_ch();
+
+ if (keyin == 'l')
+ hand_used = 0;
+ else if (keyin == 'r')
+ hand_used = 1;
+ else if (keyin == ESCAPE)
+ return;
+ else
+ {
+ mpr("You don't have such a hand!");
+ return;
+ }
+ }
+
+ you.equip[ EQ_LEFT_RING + hand_used ] = item_slot;
+
+ int ident = ID_TRIED_TYPE;
+
+ switch (you.inv[item_slot].sub_type)
+ {
+ case RING_FIRE:
+ case RING_HUNGER:
+ case RING_ICE:
+ case RING_LIFE_PROTECTION:
+ case RING_POISON_RESISTANCE:
+ case RING_PROTECTION_FROM_COLD:
+ case RING_PROTECTION_FROM_FIRE:
+ case RING_PROTECTION_FROM_MAGIC:
+ case RING_SUSTAIN_ABILITIES:
+ case RING_SUSTENANCE:
+ case RING_SLAYING:
+ case RING_SEE_INVISIBLE:
+ case RING_TELEPORTATION:
+ case RING_WIZARDRY:
+ case RING_REGENERATION:
+ break;
+
+ case RING_PROTECTION:
+ you.redraw_armour_class = 1;
+ if (you.inv[item_slot].plus != 0)
+ ident = ID_KNOWN_TYPE;
+ break;
+
+ case RING_INVISIBILITY:
+ if (!you.invis)
+ {
+ mpr("You become transparent for a moment.");
+ ident = ID_KNOWN_TYPE;
+ }
+ break;
+
+ case RING_EVASION:
+ you.redraw_evasion = 1;
+ if (you.inv[item_slot].plus != 0)
+ ident = ID_KNOWN_TYPE;
+ break;
+
+ case RING_STRENGTH:
+ modify_stat(STAT_STRENGTH, you.inv[item_slot].plus, true);
+ if (you.inv[item_slot].plus != 0)
+ ident = ID_KNOWN_TYPE;
+ break;
+
+ case RING_DEXTERITY:
+ modify_stat(STAT_DEXTERITY, you.inv[item_slot].plus, true);
+ if (you.inv[item_slot].plus != 0)
+ ident = ID_KNOWN_TYPE;
+ break;
+
+ case RING_INTELLIGENCE:
+ modify_stat(STAT_INTELLIGENCE, you.inv[item_slot].plus, true);
+ if (you.inv[item_slot].plus != 0)
+ ident = ID_KNOWN_TYPE;
+ break;
+
+ case RING_MAGICAL_POWER:
+ calc_mp();
+ ident = ID_KNOWN_TYPE;
+ break;
+
+ case RING_LEVITATION:
+ mpr("You feel buoyant.");
+ ident = ID_KNOWN_TYPE;
+ break;
+
+ case RING_TELEPORT_CONTROL:
+ // XXX: is this safe or should we make it a function -- bwr
+ you.attribute[ATTR_CONTROL_TELEPORT]++;
+ break;
+
+ case AMU_RAGE:
+ mpr("You feel a brief urge to hack something to bits.");
+ ident = ID_KNOWN_TYPE;
+ break;
+ }
+
+ you.turn_is_over = 1;
+
+ // Artefacts have completely different appearance than base types
+ // so we don't allow them to make the base types known
+ if (is_random_artefact( you.inv[item_slot] ))
+ use_randart(item_slot);
+ else
+ {
+ set_ident_type( you.inv[item_slot].base_type,
+ you.inv[item_slot].sub_type, ident );
+ }
+
+ if (ident == ID_KNOWN_TYPE)
+ set_ident_flags( you.inv[item_slot], ISFLAG_EQ_JEWELLERY_MASK );
+
+ if (item_cursed( you.inv[item_slot] ))
+ {
+ snprintf( info, INFO_SIZE,
+ "Oops, that %s feels deathly cold.", (is_amulet) ? "amulet"
+ : "ring" );
+ mpr(info);
+ }
+
+ // cursed or not, we know that since we've put the ring on
+ set_ident_flags( you.inv[item_slot], ISFLAG_KNOW_CURSE );
+
+ in_name( item_slot, DESC_INVENTORY_EQUIP, str_pass );
+ mpr( str_pass );
+} // end puton_ring()
+
+void remove_ring(void)
+{
+ int hand_used = 10;
+ int ring_wear_2;
+ char str_pass[ ITEMNAME_SIZE ];
+
+ if (you.equip[EQ_LEFT_RING] == -1 && you.equip[EQ_RIGHT_RING] == -1
+ && you.equip[EQ_AMULET] == -1)
+ {
+ mpr("You aren't wearing any rings or amulets.");
+ return;
+ }
+
+ if (you.berserker)
+ {
+ canned_msg(MSG_TOO_BERSERK);
+ return;
+ }
+
+ if (you.equip[EQ_GLOVES] != -1
+ && item_cursed( you.inv[you.equip[EQ_GLOVES]] )
+ && you.equip[EQ_AMULET] == -1)
+ {
+ mpr("You can't take your gloves off to remove any rings!");
+ return;
+ }
+
+ if (you.equip[EQ_LEFT_RING] != -1 && you.equip[EQ_RIGHT_RING] == -1
+ && you.equip[EQ_AMULET] == -1)
+ {
+ hand_used = 0;
+ }
+
+ if (you.equip[EQ_LEFT_RING] == -1 && you.equip[EQ_RIGHT_RING] != -1
+ && you.equip[EQ_AMULET] == -1)
+ {
+ hand_used = 1;
+ }
+
+ if (you.equip[EQ_LEFT_RING] == -1 && you.equip[EQ_RIGHT_RING] == -1
+ && you.equip[EQ_AMULET] != -1)
+ {
+ hand_used = 2;
+ }
+
+ if (hand_used == 10)
+ {
+ int equipn = prompt_invent_item( "Remove which piece of jewellery?",
+ OBJ_JEWELLERY );
+
+ if (equipn == PROMPT_ABORT)
+ {
+ canned_msg( MSG_OK );
+ return;
+ }
+
+ if (you.inv[equipn].base_type != OBJ_JEWELLERY)
+ {
+ mpr("That isn't a piece of jewellery.");
+ return;
+ }
+
+ if (you.equip[EQ_LEFT_RING] == equipn)
+ hand_used = 0;
+ else if (you.equip[EQ_RIGHT_RING] == equipn)
+ hand_used = 1;
+ else if (you.equip[EQ_AMULET] == equipn)
+ hand_used = 2;
+ else
+ {
+ mpr("You aren't wearing that.");
+ return;
+ }
+ }
+
+ if (you.equip[EQ_GLOVES] != -1
+ && item_cursed( you.inv[you.equip[EQ_GLOVES]] )
+ && (hand_used == 0 || hand_used == 1))
+ {
+ mpr("You can't take your gloves off to remove any rings!");
+ return;
+ }
+
+ if (you.equip[hand_used + 7] == -1)
+ {
+ mpr("I don't think you really meant that.");
+ return;
+ }
+
+ if (item_cursed( you.inv[you.equip[hand_used + 7]] ))
+ {
+ mpr("It's stuck to you!");
+
+ set_ident_flags( you.inv[you.equip[hand_used + 7]], ISFLAG_KNOW_CURSE );
+ return;
+ }
+
+ strcpy(info, "You remove ");
+ in_name(you.equip[hand_used + 7], DESC_NOCAP_YOUR, str_pass);
+
+ strcat(info, str_pass);
+ strcat(info, ".");
+ mpr(info);
+
+ // I'll still use ring_wear_2 here.
+ ring_wear_2 = you.equip[hand_used + 7];
+
+ switch (you.inv[ring_wear_2].sub_type)
+ {
+ case RING_FIRE:
+ case RING_HUNGER:
+ case RING_ICE:
+ case RING_LIFE_PROTECTION:
+ case RING_POISON_RESISTANCE:
+ case RING_PROTECTION_FROM_COLD:
+ case RING_PROTECTION_FROM_FIRE:
+ case RING_PROTECTION_FROM_MAGIC:
+ case RING_REGENERATION:
+ case RING_SEE_INVISIBLE:
+ case RING_SLAYING:
+ case RING_SUSTAIN_ABILITIES:
+ case RING_SUSTENANCE:
+ case RING_TELEPORTATION:
+ case RING_WIZARDRY:
+ break;
+
+ case RING_PROTECTION:
+ you.redraw_armour_class = 1;
+ break;
+
+ case RING_EVASION:
+ you.redraw_evasion = 1;
+ break;
+
+ case RING_STRENGTH:
+ modify_stat(STAT_STRENGTH, -you.inv[ring_wear_2].plus, true);
+ break;
+
+ case RING_DEXTERITY:
+ modify_stat(STAT_DEXTERITY, -you.inv[ring_wear_2].plus, true);
+ break;
+
+ case RING_INTELLIGENCE:
+ modify_stat(STAT_INTELLIGENCE, -you.inv[ring_wear_2].plus, true);
+ break;
+
+ case RING_INVISIBILITY:
+ // removing this ring effectively cancels all invisibility {dlb}
+ if (you.invis)
+ you.invis = 1;
+ break;
+
+ case RING_LEVITATION:
+ // removing this ring effectively cancels all levitation {dlb}
+ if (you.levitation)
+ you.levitation = 1;
+ break;
+
+ case RING_MAGICAL_POWER:
+ // dec_max_mp(9);
+ break;
+
+ case RING_TELEPORT_CONTROL:
+ you.attribute[ATTR_CONTROL_TELEPORT]--;
+ break;
+ }
+
+ if (is_random_artefact( you.inv[ring_wear_2] ))
+ unuse_randart(ring_wear_2);
+
+ you.equip[hand_used + 7] = -1;
+
+ // must occur after ring is removed -- bwr
+ calc_mp();
+
+ you.turn_is_over = 1;
+} // end remove_ring()
+
+void zap_wand(void)
+{
+ struct bolt beam;
+ struct dist zap_wand;
+ int item_slot;
+ char str_pass[ ITEMNAME_SIZE ];
+
+ // Unless the character knows the type of the wand, the targeting
+ // system will default to cycling through all monsters. -- bwr
+ int targ_mode = TARG_ANY;
+
+ beam.obviousEffect = false;
+
+ if (inv_count() < 1)
+ {
+ canned_msg(MSG_NOTHING_CARRIED);
+ return;
+ }
+
+ if (you.berserker)
+ {
+ canned_msg(MSG_TOO_BERSERK);
+ return;
+ }
+
+ item_slot = prompt_invent_item( "Zap which item?", OBJ_WANDS );
+ if (item_slot == PROMPT_ABORT)
+ {
+ canned_msg( MSG_OK );
+ return;
+ }
+
+ if (you.inv[item_slot].base_type != OBJ_WANDS
+ || you.inv[item_slot].plus < 1)
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ you.turn_is_over = 1;
+ return;
+ }
+
+ if (item_ident( you.inv[item_slot], ISFLAG_KNOW_TYPE ))
+ {
+ if (you.inv[item_slot].sub_type == WAND_HASTING
+ || you.inv[item_slot].sub_type == WAND_HEALING
+ || you.inv[item_slot].sub_type == WAND_INVISIBILITY)
+ {
+ targ_mode = TARG_FRIEND;
+ }
+ else
+ {
+ targ_mode = TARG_ENEMY;
+ }
+ }
+
+ mpr( STD_DIRECTION_PROMPT, MSGCH_PROMPT );
+ message_current_target();
+
+ direction( zap_wand, DIR_NONE, targ_mode );
+
+ if (!zap_wand.isValid)
+ {
+ if (zap_wand.isCancel)
+ canned_msg(MSG_OK);
+ return;
+ }
+
+ if (you.conf)
+ {
+ zap_wand.tx = you.x_pos + random2(13) - 6;
+ zap_wand.ty = you.y_pos + random2(13) - 6;
+ }
+
+ // blargh! blech! this is just begging to be a problem ...
+ // not to mention work-around after work-around as wands are
+ // added, removed, or altered {dlb}:
+ char type_zapped = you.inv[item_slot].sub_type;
+
+ if (type_zapped == WAND_ENSLAVEMENT)
+ type_zapped = ZAP_ENSLAVEMENT;
+
+ if (type_zapped == WAND_DRAINING)
+ type_zapped = ZAP_NEGATIVE_ENERGY;
+
+ if (type_zapped == WAND_DISINTEGRATION)
+ type_zapped = ZAP_DISINTEGRATION;
+
+ if (type_zapped == WAND_RANDOM_EFFECTS)
+ {
+ type_zapped = random2(16);
+ if (one_chance_in(20))
+ type_zapped = ZAP_NEGATIVE_ENERGY;
+ if (one_chance_in(17))
+ type_zapped = ZAP_ENSLAVEMENT;
+ }
+
+ beam.source_x = you.x_pos;
+ beam.source_y = you.y_pos;
+ beam.target_x = zap_wand.tx;
+ beam.target_y = zap_wand.ty;
+
+ zapping( type_zapped, 30 + roll_dice(2, you.skills[SK_EVOCATIONS]), beam );
+
+ if (beam.obviousEffect == 1 || you.inv[item_slot].sub_type == WAND_FIREBALL)
+ {
+ if (get_ident_type( you.inv[item_slot].base_type,
+ you.inv[item_slot].sub_type ) != ID_KNOWN_TYPE)
+ {
+ set_ident_type( you.inv[item_slot].base_type,
+ you.inv[item_slot].sub_type, ID_KNOWN_TYPE );
+
+ in_name(item_slot, DESC_INVENTORY_EQUIP, str_pass);
+ mpr( str_pass );
+
+ // update if wielding
+ if (you.equip[EQ_WEAPON] == item_slot)
+ you.wield_change = true;
+ }
+ }
+ else
+ {
+ set_ident_type( you.inv[item_slot].base_type,
+ you.inv[item_slot].sub_type, ID_TRIED_TYPE );
+ }
+
+ you.inv[item_slot].plus--;
+
+ if (get_ident_type( you.inv[item_slot].base_type,
+ you.inv[item_slot].sub_type ) == ID_KNOWN_TYPE
+ && (item_ident( you.inv[item_slot], ISFLAG_KNOW_PLUSES )
+ || you.skills[SK_EVOCATIONS] > 5 + random2(15)))
+ {
+ if (item_not_ident( you.inv[item_slot], ISFLAG_KNOW_PLUSES ))
+ {
+ mpr("Your skill with magical items lets you calculate the power of this device...");
+ }
+
+ snprintf( info, INFO_SIZE, "This wand has %d charge%s left.",
+ you.inv[item_slot].plus,
+ (you.inv[item_slot].plus == 1) ? "" : "s" );
+
+ mpr(info);
+ set_ident_flags( you.inv[item_slot], ISFLAG_KNOW_PLUSES );
+ }
+
+ exercise( SK_EVOCATIONS, 1 );
+ alert_nearby_monsters();
+
+ you.turn_is_over = 1;
+} // end zap_wand()
+
+void drink(void)
+{
+ int item_slot;
+
+ if (you.is_undead == US_UNDEAD)
+ {
+ mpr("You can't drink.");
+ return;
+ }
+
+ if (grd[you.x_pos][you.y_pos] == DNGN_BLUE_FOUNTAIN
+ || grd[you.x_pos][you.y_pos] == DNGN_SPARKLING_FOUNTAIN)
+ {
+ if (drink_fountain())
+ return;
+ }
+
+ if (inv_count() < 1)
+ {
+ canned_msg(MSG_NOTHING_CARRIED);
+ return;
+ }
+
+ if (you.berserker)
+ {
+ canned_msg(MSG_TOO_BERSERK);
+ return;
+ }
+
+ item_slot = prompt_invent_item( "Drink which item?", OBJ_POTIONS );
+ if (item_slot == PROMPT_ABORT)
+ {
+ canned_msg( MSG_OK );
+ return;
+ }
+
+ if (you.inv[item_slot].base_type != OBJ_POTIONS)
+ {
+ mpr("You can't drink that!");
+ return;
+ }
+
+ if (potion_effect( you.inv[item_slot].sub_type, 40 ))
+ {
+ set_ident_flags( you.inv[item_slot], ISFLAG_IDENT_MASK );
+
+ set_ident_type( you.inv[item_slot].base_type,
+ you.inv[item_slot].sub_type, ID_KNOWN_TYPE );
+ }
+ else
+ {
+ set_ident_type( you.inv[item_slot].base_type,
+ you.inv[item_slot].sub_type, ID_TRIED_TYPE );
+ }
+
+ dec_inv_item_quantity( item_slot, 1 );
+ you.turn_is_over = 1;
+
+ lessen_hunger(40, true);
+} // end drink()
+
+bool drink_fountain(void)
+{
+ bool gone_dry = false;
+ int temp_rand; // for probability determinations {dlb}
+ int fountain_effect = POT_WATER; // for fountain effects {dlb}
+
+ switch (grd[you.x_pos][you.y_pos])
+ {
+ case DNGN_BLUE_FOUNTAIN:
+ if (!yesno("Drink from the fountain?"))
+ return false;
+
+ mpr("You drink the pure, clear water.");
+ break;
+
+ case DNGN_SPARKLING_FOUNTAIN:
+ if (!yesno("Drink from the sparkling fountain?"))
+ return false;
+
+ mpr("You drink the sparkling water.");
+ break;
+ }
+
+ if (grd[you.x_pos][you.y_pos] == DNGN_SPARKLING_FOUNTAIN)
+ {
+ temp_rand = random2(4500);
+
+ fountain_effect = ((temp_rand > 2399) ? POT_WATER : // 46.7%
+ (temp_rand > 2183) ? POT_DECAY : // 4.8%
+ (temp_rand > 2003) ? POT_MUTATION : // 4.0%
+ (temp_rand > 1823) ? POT_HEALING : // 4.0%
+ (temp_rand > 1643) ? POT_HEAL_WOUNDS :// 4.0%
+ (temp_rand > 1463) ? POT_SPEED : // 4.0%
+ (temp_rand > 1283) ? POT_MIGHT : // 4.0%
+ (temp_rand > 1139) ? POT_DEGENERATION ://3.2%
+ (temp_rand > 1019) ? POT_LEVITATION :// 2.7%
+ (temp_rand > 899) ? POT_POISON : // 2.7%
+ (temp_rand > 779) ? POT_SLOWING : // 2.7%
+ (temp_rand > 659) ? POT_PARALYSIS : // 2.7%
+ (temp_rand > 539) ? POT_CONFUSION : // 2.7%
+ (temp_rand > 419) ? POT_INVISIBILITY :// 2.7%
+ (temp_rand > 329) ? POT_MAGIC : // 2.0%
+ (temp_rand > 239) ? POT_RESTORE_ABILITIES :// 2.0%
+ (temp_rand > 149) ? POT_STRONG_POISON ://2.0%
+ (temp_rand > 59) ? POT_BERSERK_RAGE : //2.0%
+ (temp_rand > 39) ? POT_GAIN_STRENGTH : //0.4%
+ (temp_rand > 19) ? POT_GAIN_DEXTERITY //0.4%
+ : POT_GAIN_INTELLIGENCE);//0.4%
+ }
+
+ potion_effect(fountain_effect, 100);
+
+ switch (grd[you.x_pos][you.y_pos])
+ {
+ case DNGN_BLUE_FOUNTAIN:
+ if (one_chance_in(20))
+ gone_dry = true;
+ break;
+
+ case DNGN_SPARKLING_FOUNTAIN:
+ if (one_chance_in(10))
+ {
+ gone_dry = true;
+ break;
+ }
+ else
+ {
+ temp_rand = random2(50);
+
+ // you won't know it (yet)
+ if (temp_rand > 40) // 18% probability
+ grd[you.x_pos][you.y_pos] = DNGN_BLUE_FOUNTAIN;
+ }
+ break;
+ }
+
+ if (gone_dry)
+ {
+ mpr("The fountain dries up!");
+ if (grd[you.x_pos][you.y_pos] == DNGN_BLUE_FOUNTAIN)
+ grd[you.x_pos][you.y_pos] = DNGN_DRY_FOUNTAIN_I;
+ else if (grd[you.x_pos][you.y_pos] == DNGN_SPARKLING_FOUNTAIN)
+ grd[you.x_pos][you.y_pos] = DNGN_DRY_FOUNTAIN_II;
+ }
+
+ you.turn_is_over = 1;
+ return true;
+} // end drink_fountain()
+
+static bool affix_weapon_enchantment( void )
+{
+ const int wpn = you.equip[ EQ_WEAPON ];
+ bool success = true;
+
+ struct bolt beam;
+
+ if (wpn == -1 || !you.duration[ DUR_WEAPON_BRAND ])
+ return (false);
+
+ switch (get_weapon_brand( you.inv[wpn] ))
+ {
+ case SPWPN_VORPAL:
+ if (damage_type( you.inv[wpn].base_type,
+ you.inv[wpn].sub_type ) != DVORP_CRUSHING)
+ {
+ strcat(info, "'s sharpness seems more permanent.");
+ }
+ else
+ {
+ strcat(info, "'s heaviness feels very stable.");
+ }
+ mpr(info);
+ break;
+
+ case SPWPN_FLAMING:
+ strcat(info," is engulfed in an explosion of flames!");
+ mpr(info);
+
+ beam.type = SYM_BURST;
+ beam.damage = dice_def( 3, 10 );
+ beam.flavour = 2;
+ beam.target_x = you.x_pos;
+ beam.target_y = you.y_pos;
+ strcpy(beam.beam_name, "fiery explosion");
+ beam.colour = RED;
+ beam.thrower = KILL_YOU;
+ beam.aux_source = "a fiery explosion";
+ beam.ex_size = 2;
+ beam.isTracer = false;
+
+ explosion(beam);
+ break;
+
+ case SPWPN_FREEZING:
+ strcat(info," glows brilliantly blue for a moment.");
+ mpr(info);
+ cast_refrigeration(60);
+ break;
+
+ case SPWPN_DRAINING:
+ strcat(info," thirsts for the lives of mortals!");
+ mpr(info);
+ drain_exp();
+ break;
+
+ case SPWPN_VENOM:
+ strcat(info, " seems more permanently poisoned.");
+ mpr(info);
+ cast_toxic_radiance();
+ break;
+
+ case SPWPN_DISTORTION:
+ strcat(info, " twongs alarmingly.");
+ mpr(info);
+
+ // from unwield_item
+ miscast_effect( SPTYP_TRANSLOCATION, 9, 90, 100, "a distortion effect" );
+ break;
+
+ default:
+ success = false;
+ break;
+ }
+
+ if (success)
+ you.duration[DUR_WEAPON_BRAND] = 0;
+
+ return (success);
+}
+
+static bool enchant_weapon( int which_stat, bool quiet )
+{
+ const int wpn = you.equip[ EQ_WEAPON ];
+ bool affected = true;
+ int enchant_level;
+ char str_pass[ ITEMNAME_SIZE ];
+
+ if (wpn == -1
+ || (you.inv[ wpn ].base_type != OBJ_WEAPONS
+ && you.inv[ wpn ].base_type != OBJ_MISSILES))
+ {
+ if (!quiet)
+ canned_msg(MSG_NOTHING_HAPPENS);
+
+ return (false);
+ }
+
+ you.wield_change = true;
+
+ // missiles only have one stat
+ if (you.inv[ wpn ].base_type == OBJ_MISSILES)
+ which_stat = ENCHANT_TO_HIT;
+
+ if (which_stat == ENCHANT_TO_HIT)
+ enchant_level = you.inv[ wpn ].plus;
+ else
+ enchant_level = you.inv[ wpn ].plus2;
+
+ // artefacts can't be enchanted, but scrolls still remove curses
+ if (you.inv[ wpn ].base_type == OBJ_WEAPONS
+ && (is_fixed_artefact( you.inv[wpn] )
+ || is_random_artefact( you.inv[wpn] )))
+ {
+ affected = false;
+ }
+
+ if (enchant_level >= 4 && random2(9) < enchant_level)
+ {
+ affected = false;
+ }
+
+ // if it isn't affected by the enchantment, it will still
+ // be uncursed:
+ if (!affected)
+ {
+ if (item_cursed( you.inv[you.equip[EQ_WEAPON]] ))
+ {
+ if (!quiet)
+ {
+ in_name(you.equip[EQ_WEAPON], DESC_CAP_YOUR, str_pass);
+ strcpy(info, str_pass);
+ strcat(info, " glows silver for a moment.");
+ mpr(info);
+ }
+
+ do_uncurse_item( you.inv[you.equip[EQ_WEAPON]] );
+
+ return (true);
+ }
+ else
+ {
+ if (!quiet)
+ canned_msg(MSG_NOTHING_HAPPENS);
+
+ return (false);
+ }
+ }
+
+ // vVvVv This is *here* (as opposed to lower down) for a reason!
+ in_name( wpn, DESC_CAP_YOUR, str_pass );
+ strcpy( info, str_pass );
+
+ do_uncurse_item( you.inv[ wpn ] );
+
+ if (you.inv[ wpn ].base_type == OBJ_WEAPONS)
+ {
+ if (which_stat == ENCHANT_TO_DAM)
+ {
+ you.inv[ wpn ].plus2++;
+
+ if (!quiet)
+ {
+ strcat(info, " glows red for a moment.");
+ mpr(info);
+ }
+ }
+ else if (which_stat == ENCHANT_TO_HIT)
+ {
+ you.inv[ wpn ].plus++;
+
+ if (!quiet)
+ {
+ strcat(info, " glows green for a moment.");
+ mpr(info);
+ }
+ }
+ }
+ else if (you.inv[ wpn ].base_type == OBJ_MISSILES)
+ {
+ strcat( info, (you.inv[ wpn ].quantity > 1) ? " glow"
+ : " glows" );
+
+ strcat(info, " red for a moment.");
+
+ you.inv[ wpn ].plus++;
+ }
+
+ return (true);
+}
+
+static bool enchant_armour( void )
+{
+ // NOTE: It is assumed that armour which changes in this way does
+ // not change into a form of armour with a different evasion modifier.
+ char str_pass[ ITEMNAME_SIZE ];
+ int nthing = you.equip[EQ_BODY_ARMOUR];
+
+ if (nthing != -1
+ && (you.inv[nthing].sub_type == ARM_DRAGON_HIDE
+ || you.inv[nthing].sub_type == ARM_ICE_DRAGON_HIDE
+ || you.inv[nthing].sub_type == ARM_STEAM_DRAGON_HIDE
+ || you.inv[nthing].sub_type == ARM_MOTTLED_DRAGON_HIDE
+ || you.inv[nthing].sub_type == ARM_STORM_DRAGON_HIDE
+ || you.inv[nthing].sub_type == ARM_GOLD_DRAGON_HIDE
+ || you.inv[nthing].sub_type == ARM_SWAMP_DRAGON_HIDE
+ || you.inv[nthing].sub_type == ARM_TROLL_HIDE))
+ {
+ in_name( you.equip[EQ_BODY_ARMOUR], DESC_CAP_YOUR, str_pass );
+ strcpy(info, str_pass);
+ strcat(info, " glows purple and changes!");
+ mpr(info);
+
+ you.redraw_armour_class = 1;
+
+ hide2armour( &(you.inv[nthing].sub_type) );
+ return (true);
+ }
+
+ // pick random piece of armour
+ int count = 0;
+ int affected_slot = EQ_WEAPON;
+
+ for (int i = EQ_CLOAK; i <= EQ_BODY_ARMOUR; i++)
+ {
+ if (you.equip[i] != -1)
+ {
+ count++;
+ if (one_chance_in( count ))
+ affected_slot = i;
+ }
+ }
+
+ // no armour == no enchantment
+ if (affected_slot == EQ_WEAPON)
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ return (false);
+ }
+
+ bool affected = true;
+ item_def &item = you.inv[you.equip[ affected_slot ]];
+
+ if (is_random_artefact( item )
+ || ((item.sub_type >= ARM_CLOAK && item.sub_type <= ARM_BOOTS)
+ && item.plus >= 2)
+ || ((item.sub_type == ARM_SHIELD
+ || item.sub_type == ARM_BUCKLER
+ || item.sub_type == ARM_LARGE_SHIELD)
+ && item.plus >= 2)
+ || (item.plus >= 3 && random2(8) < item.plus))
+ {
+ affected = false;
+ }
+
+ // even if not affected, it may be uncursed.
+ if (!affected)
+ {
+ if (item_cursed( item ))
+ {
+ in_name(you.equip[affected], DESC_CAP_YOUR, str_pass);
+ strcpy(info, str_pass);
+ strcat(info, " glows silver for a moment.");
+ mpr(info);
+
+ do_uncurse_item( you.inv[you.equip[affected]] );
+ return (true);
+ }
+ else
+ {
+ canned_msg( MSG_NOTHING_HAPPENS );
+ return (false);
+ }
+ }
+
+ // vVvVv This is *here* for a reason!
+ item_name(item, DESC_CAP_YOUR, str_pass);
+ strcpy(info, str_pass);
+ strcat(info, " glows green for a moment.");
+ mpr(info);
+
+ item.plus++;
+
+ do_uncurse_item( item );
+ you.redraw_armour_class = 1;
+ return (true);
+}
+
+static void handle_read_book( int item_slot )
+{
+ int spell, spell_index, nthing;
+
+ if (you.inv[item_slot].sub_type == BOOK_DESTRUCTION)
+ {
+ if (silenced(you.x_pos, you.y_pos))
+ {
+ mpr("This book does not work if you cannot read it aloud!");
+ return;
+ }
+
+ tome_of_power(item_slot);
+ return;
+ }
+ else if (you.inv[item_slot].sub_type == BOOK_MANUAL)
+ {
+ skill_manual(item_slot);
+ return;
+ }
+ else
+ {
+ // Spellbook
+ spell = read_book( you.inv[item_slot], RBOOK_READ_SPELL );
+ }
+
+ if (spell < 'a' || spell > 'h') //jmf: was 'g', but 8=h
+ {
+ mesclr( true );
+ return;
+ }
+
+ spell_index = letter_to_index( spell );
+
+ nthing = which_spell_in_book(you.inv[item_slot].sub_type, spell_index);
+ if (nthing == SPELL_NO_SPELL)
+ {
+ mesclr( true );
+ return;
+ }
+
+ describe_spell( nthing );
+ redraw_screen();
+
+ mesclr( true );
+ return;
+}
+
+void read_scroll(void)
+{
+ int affected = 0;
+ int i;
+ int count;
+ int nthing;
+ struct bolt beam;
+ char str_pass[ ITEMNAME_SIZE ];
+
+ // added: scroll effects are never tracers.
+ beam.isTracer = false;
+
+ if (you.berserker)
+ {
+ canned_msg(MSG_TOO_BERSERK);
+ return;
+ }
+
+ if (inv_count() < 1)
+ {
+ canned_msg(MSG_NOTHING_CARRIED);
+ return;
+ }
+
+ int item_slot = prompt_invent_item( "Read which item?", OBJ_SCROLLS );
+ if (item_slot == PROMPT_ABORT)
+ {
+ canned_msg( MSG_OK );
+ return;
+ }
+
+ if (you.inv[item_slot].base_type != OBJ_BOOKS
+ && you.inv[item_slot].base_type != OBJ_SCROLLS)
+ {
+ mpr("You can't read that!");
+ return;
+ }
+
+ // here we try to read a book {dlb}:
+ if (you.inv[item_slot].base_type == OBJ_BOOKS)
+ {
+ handle_read_book( item_slot );
+ return;
+ }
+
+ if (silenced(you.x_pos, you.y_pos))
+ {
+ mpr("Magic scrolls do not work when you're silenced!");
+ return;
+ }
+
+ // ok - now we FINALLY get to read a scroll !!! {dlb}
+ you.turn_is_over = 1;
+
+ // imperfect vision prevents players from reading actual content {dlb}:
+ if (you.mutation[MUT_BLURRY_VISION]
+ && random2(5) < you.mutation[MUT_BLURRY_VISION])
+ {
+ mpr((you.mutation[MUT_BLURRY_VISION] == 3 && one_chance_in(3))
+ ? "This scroll appears to be blank."
+ : "The writing blurs in front of your eyes.");
+ return;
+ }
+
+ // decrement and handle inventory if any scroll other than paper {dlb}:
+ const int scroll_type = you.inv[item_slot].sub_type;
+ if (scroll_type != SCR_PAPER)
+ {
+ mpr("As you read the scroll, it crumbles to dust.");
+ // Actual removal of scroll done afterwards. -- bwr
+ }
+
+ // scrolls of paper are also exempted from this handling {dlb}:
+ if (scroll_type != SCR_PAPER)
+ {
+ if (you.conf)
+ {
+ random_uselessness(random2(9), item_slot);
+ return;
+ }
+
+ if (!you.skills[SK_SPELLCASTING])
+ exercise(SK_SPELLCASTING, (coinflip()? 2 : 1));
+ }
+
+ bool id_the_scroll = true; // to prevent unnecessary repetition
+
+ // it is the exception, not the rule, that
+ // the scroll will not be identified {dlb}:
+ switch (scroll_type)
+ {
+ case SCR_PAPER:
+ // remember paper scrolls handled as special case above, too:
+ mpr("This scroll appears to be blank.");
+ break;
+
+ case SCR_RANDOM_USELESSNESS:
+ random_uselessness(random2(9), item_slot);
+ id_the_scroll = false;
+ break;
+
+ case SCR_BLINKING:
+ blink();
+ break;
+
+ case SCR_TELEPORTATION:
+ you_teleport();
+ break;
+
+ case SCR_REMOVE_CURSE:
+ if (!remove_curse(false))
+ id_the_scroll = false;
+ break;
+
+ case SCR_DETECT_CURSE:
+ if (!detect_curse(false))
+ id_the_scroll = false;
+ break;
+
+ case SCR_ACQUIREMENT:
+ acquirement(OBJ_RANDOM);
+ break;
+
+ case SCR_FEAR:
+ if (!mass_enchantment(ENCH_FEAR, 1000, MHITYOU))
+ id_the_scroll = false;
+ break;
+
+ case SCR_NOISE:
+ mpr("You hear a loud clanging noise!");
+ noisy( 25, you.x_pos, you.y_pos );
+ break;
+
+ case SCR_SUMMONING:
+ if (create_monster( MONS_ABOMINATION_SMALL, ENCH_ABJ_VI, BEH_FRIENDLY,
+ you.x_pos, you.y_pos, you.pet_target, 250 ) != -1)
+ {
+ mpr("A horrible Thing appears!");
+ }
+ break;
+
+ case SCR_FORGETFULNESS:
+ mpr("You feel momentarily disoriented.");
+ if (!wearing_amulet(AMU_CLARITY))
+ forget_map(50 + random2(50));
+ break;
+
+ case SCR_MAGIC_MAPPING:
+ if (you.level_type == LEVEL_LABYRINTH
+ || you.level_type == LEVEL_ABYSS)
+ {
+ mpr("You feel momentarily disoriented.");
+ id_the_scroll = false;
+ }
+ else
+ {
+ mpr("You feel aware of your surroundings.");
+ magic_mapping(50, 90 + random2(11));
+ }
+ break;
+
+ case SCR_TORMENT:
+ torment( you.x_pos, you.y_pos );
+
+ // is only naughty if you know you're doing it
+ if (get_ident_type( OBJ_SCROLLS, SCR_TORMENT ) == ID_KNOWN_TYPE)
+ {
+ naughty(NAUGHTY_UNHOLY, 10);
+ }
+ break;
+
+ case SCR_IMMOLATION:
+ mpr("The scroll explodes in your hands!");
+
+ beam.type = SYM_BURST;
+ beam.damage = dice_def( 3, 10 );
+ // unsure about this // BEAM_EXPLOSION instead? {dlb}
+ beam.flavour = BEAM_FIRE;
+ beam.target_x = you.x_pos;
+ beam.target_y = you.y_pos;
+ strcpy(beam.beam_name, "fiery explosion");
+ beam.colour = RED;
+ // your explosion, (not someone else's explosion)
+ beam.thrower = KILL_YOU;
+ beam.aux_source = "reading a scroll of immolation";
+ beam.ex_size = 2;
+
+ explosion(beam);
+ break;
+
+ case SCR_IDENTIFY:
+ set_ident_flags( you.inv[item_slot], ISFLAG_IDENT_MASK );
+
+ // important {dlb}
+ set_ident_type( OBJ_SCROLLS, SCR_IDENTIFY, ID_KNOWN_TYPE );
+
+ identify(-1);
+ you.wield_change = true;
+ break;
+
+ case SCR_CURSE_WEAPON:
+ nthing = you.equip[EQ_WEAPON];
+
+ if (nthing == -1
+ || you.inv[nthing].base_type != OBJ_WEAPONS
+ || item_cursed( you.inv[nthing] ))
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ id_the_scroll = false;
+ }
+ else
+ {
+ in_name( nthing, DESC_CAP_YOUR, str_pass );
+ strcpy(info, str_pass);
+ strcat(info, " glows black for a moment.");
+ mpr(info);
+
+ do_curse_item( you.inv[nthing] );
+ you.wield_change = true;
+ }
+ break;
+
+ // everything [in the switch] below this line is a nightmare {dlb}:
+ case SCR_ENCHANT_WEAPON_I:
+ id_the_scroll = enchant_weapon( ENCHANT_TO_HIT );
+ break;
+
+ case SCR_ENCHANT_WEAPON_II:
+ id_the_scroll = enchant_weapon( ENCHANT_TO_DAM );
+ break;
+
+ case SCR_ENCHANT_WEAPON_III:
+ if (you.equip[ EQ_WEAPON ] != -1)
+ {
+ if (!affix_weapon_enchantment())
+ {
+ in_name( you.equip[EQ_WEAPON], DESC_CAP_YOUR, str_pass );
+ strcpy( info, str_pass );
+ strcat( info, " glows bright yellow for a while." );
+ mpr( info );
+
+ enchant_weapon( ENCHANT_TO_HIT, true );
+
+ if (coinflip())
+ enchant_weapon( ENCHANT_TO_HIT, true );
+
+ enchant_weapon( ENCHANT_TO_DAM, true );
+
+ if (coinflip())
+ enchant_weapon( ENCHANT_TO_DAM, true );
+
+ do_uncurse_item( you.inv[you.equip[EQ_WEAPON]] );
+ }
+ }
+ else
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ id_the_scroll = false;
+ }
+ break;
+
+ case SCR_VORPALISE_WEAPON:
+ nthing = you.equip[EQ_WEAPON];
+ if (nthing == -1
+ || you.inv[ nthing ].base_type != OBJ_WEAPONS
+ || (you.inv[ nthing ].base_type == OBJ_WEAPONS
+ && (is_fixed_artefact( you.inv[ nthing ] )
+ || is_random_artefact( you.inv[ nthing ] )
+ || launches_things( you.inv[ nthing ].sub_type ))))
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ break;
+ }
+
+ in_name(nthing, DESC_CAP_YOUR, str_pass);
+
+ strcpy(info, str_pass);
+ strcat(info, " emits a brilliant flash of light!");
+ mpr(info);
+
+ alert_nearby_monsters();
+
+ if (get_weapon_brand( you.inv[nthing] ) != SPWPN_NORMAL)
+ {
+ mpr("You feel strangely frustrated.");
+ break;
+ }
+
+ you.wield_change = true;
+ set_item_ego_type( you.inv[nthing], OBJ_WEAPONS, SPWPN_VORPAL );
+ break;
+
+ case SCR_RECHARGING:
+ nthing = you.equip[EQ_WEAPON];
+
+ if (nthing != -1
+ && !is_random_artefact( you.inv[nthing] )
+ && !is_fixed_artefact( you.inv[nthing] )
+ && get_weapon_brand( you.inv[nthing] ) == SPWPN_ELECTROCUTION)
+ {
+ id_the_scroll = !enchant_weapon( ENCHANT_TO_DAM );
+ break;
+ }
+
+ if (!recharge_wand())
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ id_the_scroll = false;
+ }
+ break;
+
+ case SCR_ENCHANT_ARMOUR:
+ id_the_scroll = enchant_armour();
+ break;
+
+ case SCR_CURSE_ARMOUR:
+ // make sure there's something to curse first
+ count = 0;
+ affected = EQ_WEAPON;
+ for (i = EQ_CLOAK; i <= EQ_BODY_ARMOUR; i++)
+ {
+ if (you.equip[i] != -1 && item_uncursed( you.inv[you.equip[i]] ))
+ {
+ count++;
+ if (one_chance_in( count ))
+ affected = i;
+ }
+ }
+
+ if (affected == EQ_WEAPON)
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ id_the_scroll = false;
+ break;
+ }
+
+ // make the name _before_ we curse it
+ in_name( you.equip[affected], DESC_CAP_YOUR, str_pass );
+ do_curse_item( you.inv[you.equip[affected]] );
+
+ strcpy(info, str_pass);
+ strcat(info, " glows black for a moment.");
+ mpr(info);
+ break;
+ } // end switch
+
+ // finally, destroy and identify the scroll
+ if (scroll_type != SCR_PAPER)
+ {
+ dec_inv_item_quantity( item_slot, 1 );
+ }
+
+ set_ident_type( OBJ_SCROLLS, scroll_type,
+ (id_the_scroll) ? ID_KNOWN_TYPE : ID_TRIED_TYPE );
+} // end read_scroll()
+
+void original_name(void)
+{
+ int item_slot = prompt_invent_item( "Examine which item?", -1 );
+ if (item_slot == PROMPT_ABORT)
+ {
+ canned_msg( MSG_OK );
+ return;
+ }
+
+ describe_item( you.inv[item_slot] );
+ redraw_screen();
+} // end original_name()
+
+void use_randart(unsigned char item_wield_2)
+{
+ ASSERT( is_random_artefact( you.inv[ item_wield_2 ] ) );
+
+ FixedVector< char, RA_PROPERTIES > proprt;
+ randart_wpn_properties( you.inv[item_wield_2], proprt );
+
+ if (proprt[RAP_AC])
+ you.redraw_armour_class = 1;
+
+ if (proprt[RAP_EVASION])
+ you.redraw_evasion = 1;
+
+ // modify ability scores
+ modify_stat( STAT_STRENGTH, proprt[RAP_STRENGTH], true );
+ modify_stat( STAT_INTELLIGENCE, proprt[RAP_INTELLIGENCE], true );
+ modify_stat( STAT_DEXTERITY, proprt[RAP_DEXTERITY], true );
+
+ if (proprt[RAP_NOISES])
+ you.special_wield = 50 + proprt[RAP_NOISES];
+}
diff --git a/trunk/source/item_use.h b/trunk/source/item_use.h
new file mode 100644
index 0000000000..b5bed8cbc8
--- /dev/null
+++ b/trunk/source/item_use.h
@@ -0,0 +1,123 @@
+/*
+ * File: item_use.cc
+ * Summary: Functions for making use of inventory items.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <2> 5/26/99 JDJ Exposed armour_prompt. takeoff_armour takes an index argument.
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef ITEM_USE_H
+#define ITEM_USE_H
+
+
+#include <string>
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - item_use
+ * *********************************************************************** */
+bool armour_prompt(const std::string & mesg, int *index);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - item_use - items
+ * *********************************************************************** */
+bool takeoff_armour(int index);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void drink(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void original_name(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void puton_ring(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void read_scroll(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void remove_ring(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+int get_fire_item_index(void);
+void shoot_thing(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void throw_anything(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void wear_armour( void );
+
+// last updated 10Sept2001 {bwr}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+bool do_wear_armour( int item, bool quiet );
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void wield_weapon(bool auto_wield);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void zap_wand(void);
+
+
+// last updated 15jan2001 {gdl}
+/* ***********************************************************************
+ * called from: item_use food
+ * *********************************************************************** */
+void wield_effects(int item_wield_2, bool showMsgs);
+
+// last updated 10sept2001 {bwr}
+/* ***********************************************************************
+ * called from: delay.cc item_use.cc it_use2.cc
+ * *********************************************************************** */
+void use_randart( unsigned char item_wield_2 );
+
+#endif
diff --git a/trunk/source/itemname.cc b/trunk/source/itemname.cc
new file mode 100644
index 0000000000..98737c7896
--- /dev/null
+++ b/trunk/source/itemname.cc
@@ -0,0 +1,3196 @@
+/*
+ * File: itemname.cc
+ * Summary: Misc functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <4> 9/09/99 BWR Added hands_required function
+ * <3> 6/13/99 BWR Upped the base AC for heavy armour
+ * <2> 5/20/99 BWR Extended screen lines support
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "itemname.h"
+
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#include "externs.h"
+
+#include "macro.h"
+#include "mon-util.h"
+#include "randart.h"
+#include "skills2.h"
+#include "stuff.h"
+#include "wpn-misc.h"
+#include "view.h"
+
+
+char id[4][50];
+int prop[4][50][3];
+FixedArray < int, 20, 50 > mss;
+
+static bool is_random_name_vowel(unsigned char let);
+static char item_name_2( const item_def &item, char buff[ ITEMNAME_SIZE ], bool terse );
+
+char reduce(unsigned char reducee);
+char retbit(char sed);
+char retvow(char sed);
+
+bool is_vowel( const char chr )
+{
+ const char low = tolower( chr );
+
+ return (low == 'a' || low == 'e' || low == 'i' || low == 'o' || low == 'u');
+}
+
+// Some convenient functions to hide the bit operations and create
+// an interface layer between the code and the data in case this
+// gets changed again. -- bwr
+bool item_cursed( const item_def &item )
+{
+ return (item.flags & ISFLAG_CURSED);
+}
+
+bool item_uncursed( const item_def &item )
+{
+ return !(item.flags & ISFLAG_CURSED);
+}
+
+bool item_known_cursed( const item_def &item )
+{
+ return ((item.flags & ISFLAG_KNOW_CURSE) && (item.flags & ISFLAG_CURSED));
+}
+
+bool item_known_uncursed( const item_def &item )
+{
+ return ((item.flags & ISFLAG_KNOW_CURSE) && !(item.flags & ISFLAG_CURSED));
+}
+
+#if 0
+// currently unused
+bool fully_identified( const item_def &item )
+{
+ return ((item.flags & ISFLAG_IDENT_MASK) == ISFLAG_IDENT_MASK);
+}
+#endif
+
+bool item_ident( const item_def &item, unsigned long flags )
+{
+ return (item.flags & flags);
+}
+
+bool item_not_ident( const item_def &item, unsigned long flags )
+{
+ return ( !(item.flags & flags) );
+}
+
+void do_curse_item( item_def &item )
+{
+ item.flags |= ISFLAG_CURSED;
+}
+
+void do_uncurse_item( item_def &item )
+{
+ item.flags &= (~ISFLAG_CURSED);
+}
+
+void set_ident_flags( item_def &item, unsigned long flags )
+{
+ item.flags |= flags;
+}
+
+void unset_ident_flags( item_def &item, unsigned long flags )
+{
+ item.flags &= (~flags);
+}
+
+// These six functions might seem silly, but they provide a nice layer
+// for later changes to these systems. -- bwr
+unsigned long get_equip_race( const item_def &item )
+{
+ return (item.flags & ISFLAG_RACIAL_MASK);
+}
+
+unsigned long get_equip_desc( const item_def &item )
+{
+ return (item.flags & ISFLAG_COSMETIC_MASK);
+}
+
+bool cmp_equip_race( const item_def &item, unsigned long val )
+{
+ return (get_equip_race( item ) == val);
+}
+
+bool cmp_equip_desc( const item_def &item, unsigned long val )
+{
+ return (get_equip_desc( item ) == val);
+}
+
+void set_equip_race( item_def &item, unsigned long flags )
+{
+ ASSERT( (flags & ~ISFLAG_RACIAL_MASK) == 0 );
+
+ // first check for base-sub pairs that can't ever have racial types
+ switch (item.base_type)
+ {
+ case OBJ_WEAPONS:
+ if (item.sub_type == WPN_GIANT_CLUB
+ || item.sub_type == WPN_GIANT_SPIKED_CLUB
+ || item.sub_type == WPN_KATANA
+ || item.sub_type == WPN_SLING
+ || item.sub_type == WPN_KNIFE
+ || item.sub_type == WPN_QUARTERSTAFF
+ || item.sub_type == WPN_DEMON_BLADE
+ || item.sub_type == WPN_DEMON_WHIP
+ || item.sub_type == WPN_DEMON_TRIDENT)
+ {
+ return;
+ }
+ break;
+
+ case OBJ_ARMOUR:
+ if (item.sub_type >= ARM_DRAGON_HIDE)
+ {
+ return;
+ }
+ break;
+
+ case OBJ_MISSILES:
+ if (item.sub_type == MI_STONE || item.sub_type == MI_LARGE_ROCK)
+ {
+ return;
+ }
+ break;
+
+ default:
+ return;
+ }
+
+ // check that item is appropriate for racial type
+ switch (flags)
+ {
+ case ISFLAG_ELVEN:
+ if (item.base_type == OBJ_ARMOUR
+ && (item.sub_type == ARM_SPLINT_MAIL
+ || item.sub_type == ARM_BANDED_MAIL
+ || item.sub_type == ARM_PLATE_MAIL))
+ {
+ return;
+ }
+ break;
+
+ case ISFLAG_DWARVEN:
+ if (item.base_type == OBJ_ARMOUR
+ && (item.sub_type == ARM_ROBE
+ || item.sub_type == ARM_LEATHER_ARMOUR))
+ {
+ return;
+ }
+ break;
+
+ case ISFLAG_ORCISH:
+ default:
+ break;
+ }
+
+ item.flags &= ~ISFLAG_RACIAL_MASK; // delete previous
+ item.flags |= flags;
+}
+
+void set_equip_desc( item_def &item, unsigned long flags )
+{
+ ASSERT( (flags & ~ISFLAG_COSMETIC_MASK) == 0 );
+
+ item.flags &= ~ISFLAG_COSMETIC_MASK; // delete previous
+ item.flags |= flags;
+}
+
+short get_helmet_type( const item_def &item )
+{
+ ASSERT( item.base_type == OBJ_ARMOUR && item.sub_type == ARM_HELMET );
+
+ return (item.plus2 & THELM_TYPE_MASK);
+}
+
+short get_helmet_desc( const item_def &item )
+{
+ ASSERT( item.base_type == OBJ_ARMOUR && item.sub_type == ARM_HELMET );
+
+ return (item.plus2 & THELM_DESC_MASK);
+}
+
+void set_helmet_type( item_def &item, short type )
+{
+ ASSERT( (type & ~THELM_TYPE_MASK) == 0 );
+ ASSERT( item.base_type == OBJ_ARMOUR && item.sub_type == ARM_HELMET );
+
+ item.plus2 &= ~THELM_TYPE_MASK;
+ item.plus2 |= type;
+}
+
+void set_helmet_desc( item_def &item, short type )
+{
+ ASSERT( (type & ~THELM_DESC_MASK) == 0 );
+ ASSERT( item.base_type == OBJ_ARMOUR && item.sub_type == ARM_HELMET );
+
+ item.plus2 &= ~THELM_DESC_MASK;
+ item.plus2 |= type;
+}
+
+void set_helmet_random_desc( item_def &item )
+{
+ ASSERT( item.base_type == OBJ_ARMOUR && item.sub_type == ARM_HELMET );
+
+ item.plus2 &= ~THELM_DESC_MASK;
+ item.plus2 |= (random2(8) << 8);
+}
+
+bool cmp_helmet_type( const item_def &item, short val )
+{
+ ASSERT( item.base_type == OBJ_ARMOUR && item.sub_type == ARM_HELMET );
+
+ return (get_helmet_type( item ) == val);
+}
+
+bool cmp_helmet_desc( const item_def &item, short val )
+{
+ ASSERT( item.base_type == OBJ_ARMOUR && item.sub_type == ARM_HELMET );
+
+ return (get_helmet_desc( item ) == val);
+}
+
+bool set_item_ego_type( item_def &item, int item_type, int ego_type )
+{
+ if (item.base_type == item_type
+ && !is_random_artefact( item )
+ && !is_fixed_artefact( item ))
+ {
+ item.special = ego_type;
+ return (true);
+ }
+
+ return (false);
+}
+
+int get_weapon_brand( const item_def &item )
+{
+ // Weapon ego types are "brands", so we do the randart lookup here.
+
+ // Staves "brands" handled specially
+ if (item.base_type != OBJ_WEAPONS)
+ return (SPWPN_NORMAL);
+
+ if (is_fixed_artefact( item ))
+ {
+ switch (item.special)
+ {
+ case SPWPN_SWORD_OF_CEREBOV:
+ return (SPWPN_FLAMING);
+
+ case SPWPN_STAFF_OF_OLGREB:
+ return (SPWPN_VENOM);
+
+ case SPWPN_VAMPIRES_TOOTH:
+ return (SPWPN_VAMPIRICISM);
+
+ default:
+ return (SPWPN_NORMAL);
+ }
+ }
+ else if (is_random_artefact( item ))
+ {
+ return (randart_wpn_property( item, RAP_BRAND ));
+ }
+
+ return (item.special);
+}
+
+int get_ammo_brand( const item_def &item )
+{
+ // no artefact arrows yet -- bwr
+ if (item.base_type != OBJ_MISSILES || is_random_artefact( item ))
+ return (SPMSL_NORMAL);
+
+ return (item.special);
+}
+
+int get_armour_ego_type( const item_def &item )
+{
+ // artefact armours have no ego type, must look up powers separately
+ if (item.base_type != OBJ_ARMOUR
+ || (is_random_artefact( item ) && !is_unrandom_artefact( item )))
+ {
+ return (SPARM_NORMAL);
+ }
+
+ return (item.special);
+}
+
+bool item_is_rod( const item_def &item )
+{
+ return (item.base_type == OBJ_STAVES
+ && item.sub_type >= STAFF_SMITING && item.sub_type < STAFF_AIR);
+}
+
+bool item_is_staff( const item_def &item )
+{
+ // Isn't De Morgan's law wonderful. -- bwr
+ return (item.base_type == OBJ_STAVES
+ && (item.sub_type < STAFF_SMITING || item.sub_type >= STAFF_AIR));
+}
+
+// it_name() and in_name() are now somewhat obsolete now that itemname
+// takes item_def, so consider them depricated.
+void it_name( int itn, char des, char buff[ ITEMNAME_SIZE ], bool terse )
+{
+ item_name( mitm[itn], des, buff, terse );
+} // end it_name()
+
+
+void in_name( int inn, char des, char buff[ ITEMNAME_SIZE ], bool terse )
+{
+ item_name( you.inv[inn], des, buff, terse );
+} // end in_name()
+
+// quant_name is usful since it prints out a different number of items
+// than the item actually contains.
+void quant_name( const item_def &item, int quant, char des,
+ char buff[ ITEMNAME_SIZE ], bool terse )
+{
+ // item_name now requires a "real" item, so we'll mangle a tmp
+ item_def tmp = item;
+ tmp.quantity = quant;
+
+ item_name( tmp, des, buff, terse );
+} // end quant_name()
+
+char item_name( const item_def &item, char descrip, char buff[ ITEMNAME_SIZE ],
+ bool terse )
+{
+ const int item_clas = item.base_type;
+ const int item_typ = item.sub_type;
+ const int it_quant = item.quantity;
+
+ char tmp_quant[20];
+ char itm_name[ ITEMNAME_SIZE ] = "";
+
+ item_name_2( item, itm_name, terse );
+
+ buff[0] = '\0';
+
+ if (descrip == DESC_INVENTORY_EQUIP || descrip == DESC_INVENTORY)
+ {
+ if (item.x == -1 && item.y == -1) // actually in inventory
+ snprintf( buff, ITEMNAME_SIZE, (terse) ? "%c) " : "%c - ",
+ index_to_letter( item.link ) );
+ else
+ descrip = DESC_CAP_A;
+ }
+
+ if (terse)
+ descrip = DESC_PLAIN;
+
+ if (item_clas == OBJ_ORBS
+ || (item_ident( item, ISFLAG_KNOW_TYPE )
+ && ((item_clas == OBJ_MISCELLANY
+ && item_typ == MISC_HORN_OF_GERYON)
+ || (is_fixed_artefact( item )
+ || (is_random_artefact( item ))))))
+ {
+ // artefacts always get "the" unless we just want the plain name
+ switch (descrip)
+ {
+ case DESC_CAP_A:
+ case DESC_CAP_YOUR:
+ case DESC_CAP_THE:
+ strncat(buff, "The ", ITEMNAME_SIZE );
+ break;
+ case DESC_NOCAP_A:
+ case DESC_NOCAP_YOUR:
+ case DESC_NOCAP_THE:
+ case DESC_NOCAP_ITS:
+ case DESC_INVENTORY_EQUIP:
+ case DESC_INVENTORY:
+ strncat(buff, "the ", ITEMNAME_SIZE );
+ break;
+ default:
+ case DESC_PLAIN:
+ break;
+ }
+ }
+ else if (it_quant > 1)
+ {
+ switch (descrip)
+ {
+ case DESC_CAP_THE:
+ strncat(buff, "The ", ITEMNAME_SIZE );
+ break;
+ case DESC_NOCAP_THE:
+ strncat(buff, "the ", ITEMNAME_SIZE );
+ break;
+ case DESC_CAP_A:
+ case DESC_NOCAP_A:
+ case DESC_INVENTORY_EQUIP:
+ case DESC_INVENTORY:
+ break;
+ case DESC_CAP_YOUR:
+ strncat(buff, "Your ", ITEMNAME_SIZE );
+ break;
+ case DESC_NOCAP_YOUR:
+ strncat(buff, "your ", ITEMNAME_SIZE );
+ break;
+ case DESC_NOCAP_ITS:
+ strncat(buff, "its ", ITEMNAME_SIZE );
+ break;
+ case DESC_PLAIN:
+ default:
+ break;
+ }
+
+ itoa(it_quant, tmp_quant, 10);
+ strncat(buff, tmp_quant, ITEMNAME_SIZE );
+ strncat(buff, " ", ITEMNAME_SIZE );
+ }
+ else
+ {
+ switch (descrip)
+ {
+ case DESC_CAP_THE:
+ strncat(buff, "The ", ITEMNAME_SIZE );
+ break;
+ case DESC_NOCAP_THE:
+ strncat(buff, "the ", ITEMNAME_SIZE );
+ break;
+ case DESC_CAP_A:
+ strncat(buff, "A", ITEMNAME_SIZE );
+
+ if (itm_name[0] == 'a' || itm_name[0] == 'e' || itm_name[0] == 'i'
+ || itm_name[0] == 'o' || itm_name[0] == 'u')
+ {
+ strncat(buff, "n", ITEMNAME_SIZE );
+ }
+
+ strncat(buff, " ", ITEMNAME_SIZE );
+ break; // A/An
+
+ case DESC_NOCAP_A:
+ case DESC_INVENTORY_EQUIP:
+ case DESC_INVENTORY:
+ strncat(buff, "a", ITEMNAME_SIZE );
+
+ if (itm_name[0] == 'a' || itm_name[0] == 'e' || itm_name[0] == 'i'
+ || itm_name[0] == 'o' || itm_name[0] == 'u')
+ {
+ strncat(buff, "n", ITEMNAME_SIZE );
+ }
+
+ strncat(buff, " ", ITEMNAME_SIZE );
+ break; // a/an
+
+ case DESC_CAP_YOUR:
+ strncat(buff, "Your ", ITEMNAME_SIZE );
+ break;
+ case DESC_NOCAP_YOUR:
+ strncat(buff, "your ", ITEMNAME_SIZE );
+ break;
+ case DESC_NOCAP_ITS:
+ strncat(buff, "its ", ITEMNAME_SIZE );
+ break;
+ case DESC_PLAIN:
+ default:
+ break;
+ }
+ } // end of else
+
+ strncat(buff, itm_name, ITEMNAME_SIZE );
+
+ if (descrip == DESC_INVENTORY_EQUIP && item.x == -1 && item.y == -1)
+ {
+ ASSERT( item.link != -1 );
+
+ if (item.link == you.equip[EQ_WEAPON])
+ {
+ if (you.inv[ you.equip[EQ_WEAPON] ].base_type == OBJ_WEAPONS
+ || item_is_staff( you.inv[ you.equip[EQ_WEAPON] ] ))
+ {
+ strncat( buff, " (weapon)", ITEMNAME_SIZE );
+ }
+ else
+ {
+ strncat( buff, " (in hand)", ITEMNAME_SIZE );
+ }
+ }
+ else if (item.link == you.equip[EQ_CLOAK]
+ || item.link == you.equip[EQ_HELMET]
+ || item.link == you.equip[EQ_GLOVES]
+ || item.link == you.equip[EQ_BOOTS]
+ || item.link == you.equip[EQ_SHIELD]
+ || item.link == you.equip[EQ_BODY_ARMOUR])
+ {
+ strncat( buff, " (worn)", ITEMNAME_SIZE );
+ }
+ else if (item.link == you.equip[EQ_LEFT_RING])
+ {
+ strncat( buff, " (left hand)", ITEMNAME_SIZE );
+ }
+ else if (item.link == you.equip[EQ_RIGHT_RING])
+ {
+ strncat( buff, " (right hand)", ITEMNAME_SIZE );
+ }
+ else if (item.link == you.equip[EQ_AMULET])
+ {
+ strncat( buff, " (around neck)", ITEMNAME_SIZE );
+ }
+ }
+
+ return (1);
+} // end item_name()
+
+
+// Note that "terse" is only currently used for the "in hand" listing on
+// the game screen.
+static char item_name_2( const item_def &item, char buff[ITEMNAME_SIZE],
+ bool terse )
+{
+ const int item_clas = item.base_type;
+ const int item_typ = item.sub_type;
+ const int it_plus = item.plus;
+ const int item_plus2 = item.plus2;
+ const int it_quant = item.quantity;
+
+ char tmp_quant[20];
+ char tmp_buff[ITEMNAME_SIZE];
+ int brand;
+ unsigned char sparm;
+
+ buff[0] = '\0';
+
+ switch (item_clas)
+ {
+ case OBJ_WEAPONS:
+ if (item_ident( item, ISFLAG_KNOW_CURSE ) && !terse)
+ {
+ // We don't bother printing "uncursed" if the item is identified
+ // for pluses (it's state should be obvious), this is so that
+ // the weapon name is kept short (there isn't a lot of room
+ // for the name on the main screen). If you're going to change
+ // this behaviour, *please* make it so that there is an option
+ // that maintains this behaviour. -- bwr
+ if (item_cursed( item ))
+ strncat(buff, "cursed ", ITEMNAME_SIZE );
+ else if (Options.show_uncursed
+ && item_not_ident( item, ISFLAG_KNOW_PLUSES ))
+ {
+ strncat(buff, "uncursed ", ITEMNAME_SIZE );
+ }
+ }
+
+ if (item_ident( item, ISFLAG_KNOW_PLUSES ))
+ {
+ if (it_plus == 0 && item_plus2 == 0)
+ strncat(buff, "+0 ", ITEMNAME_SIZE );
+ else
+ {
+ if (it_plus >= 0)
+ strncat( buff, "+" , ITEMNAME_SIZE );
+
+ itoa( it_plus, tmp_quant, 10 );
+ strncat( buff, tmp_quant , ITEMNAME_SIZE );
+
+ if (it_plus != item_plus2 || !terse)
+ {
+ strncat( buff, "," , ITEMNAME_SIZE );
+
+ if (item_plus2 >= 0)
+ strncat(buff, "+", ITEMNAME_SIZE );
+
+ itoa( item_plus2, tmp_quant, 10 );
+ strncat( buff, tmp_quant , ITEMNAME_SIZE );
+ }
+
+ strncat( buff, " " , ITEMNAME_SIZE );
+ }
+ }
+
+ if (is_random_artefact( item ))
+ {
+ strncat( buff, randart_name(item), ITEMNAME_SIZE );
+ break;
+ }
+
+ if (is_fixed_artefact( item ))
+ {
+ if (item_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ strncat(buff,
+ (item.special == SPWPN_SINGING_SWORD) ? "Singing Sword" :
+ (item.special == SPWPN_WRATH_OF_TROG) ? "Wrath of Trog" :
+ (item.special == SPWPN_SCYTHE_OF_CURSES) ? "Scythe of Curses" :
+ (item.special == SPWPN_MACE_OF_VARIABILITY) ? "Mace of Variability" :
+ (item.special == SPWPN_GLAIVE_OF_PRUNE) ? "Glaive of Prune" :
+ (item.special == SPWPN_SCEPTRE_OF_TORMENT) ? "Sceptre of Torment" :
+ (item.special == SPWPN_SWORD_OF_ZONGULDROK) ? "Sword of Zonguldrok" :
+ (item.special == SPWPN_SWORD_OF_CEREBOV) ? "Sword of Cerebov" :
+ (item.special == SPWPN_STAFF_OF_DISPATER) ? "Staff of Dispater" :
+ (item.special == SPWPN_SCEPTRE_OF_ASMODEUS) ? "Sceptre of Asmodeus" :
+ (item.special == SPWPN_SWORD_OF_POWER) ? "Sword of Power" :
+ (item.special == SPWPN_KNIFE_OF_ACCURACY) ? "Knife of Accuracy" :
+ (item.special == SPWPN_STAFF_OF_OLGREB) ? "Staff of Olgreb" :
+ (item.special == SPWPN_VAMPIRES_TOOTH) ? "Vampire's Tooth" :
+ (item.special == SPWPN_STAFF_OF_WUCAD_MU) ? "Staff of Wucad Mu"
+ : "Brodale's Buggy Bola",
+ ITEMNAME_SIZE );
+ }
+ else
+ {
+ strncat(buff,
+ (item.special == SPWPN_SINGING_SWORD) ? "golden long sword" :
+ (item.special == SPWPN_WRATH_OF_TROG) ? "bloodstained battleaxe" :
+ (item.special == SPWPN_SCYTHE_OF_CURSES) ? "warped scythe" :
+ (item.special == SPWPN_MACE_OF_VARIABILITY) ? "shimmering mace" :
+ (item.special == SPWPN_GLAIVE_OF_PRUNE) ? "purple glaive" :
+ (item.special == SPWPN_SCEPTRE_OF_TORMENT) ? "jeweled golden mace" :
+ (item.special == SPWPN_SWORD_OF_ZONGULDROK) ? "bone long sword" :
+ (item.special == SPWPN_SWORD_OF_CEREBOV) ? "great serpentine sword" :
+ (item.special == SPWPN_STAFF_OF_DISPATER) ? "golden staff" :
+ (item.special == SPWPN_SCEPTRE_OF_ASMODEUS) ? "ruby sceptre" :
+ (item.special == SPWPN_SWORD_OF_POWER) ? "chunky great sword" :
+ (item.special == SPWPN_KNIFE_OF_ACCURACY) ? "thin dagger" :
+ (item.special == SPWPN_STAFF_OF_OLGREB) ? "green glowing staff" :
+ (item.special == SPWPN_VAMPIRES_TOOTH) ? "ivory dagger" :
+ (item.special == SPWPN_STAFF_OF_WUCAD_MU) ? "quarterstaff"
+ : "buggy bola",
+ ITEMNAME_SIZE );
+ }
+ break;
+ }
+
+ // Now that we can have "glowing elven" weapons, it's
+ // probably a good idea to cut out the descriptive
+ // term once it's become obsolete. -- bwr
+ if (item_not_ident( item, ISFLAG_KNOW_PLUSES ) && !terse)
+ {
+ switch (get_equip_desc( item ))
+ {
+ case ISFLAG_RUNED:
+ strncat(buff, "runed ", ITEMNAME_SIZE );
+ break;
+ case ISFLAG_GLOWING:
+ strncat(buff, "glowing ", ITEMNAME_SIZE );
+ break;
+ }
+ }
+
+ // always give racial type (it does have game effects)
+
+ switch (get_equip_race( item ))
+ {
+ case ISFLAG_ORCISH:
+ strncat( buff, (terse) ? "orc " : "orcish ", ITEMNAME_SIZE );
+ break;
+ case ISFLAG_ELVEN:
+ strncat( buff, (terse) ? "elf " : "elven ", ITEMNAME_SIZE );
+ break;
+ case ISFLAG_DWARVEN:
+ strncat( buff, (terse) ? "dwarf " : "dwarven ", ITEMNAME_SIZE );
+ break;
+ }
+
+ brand = get_weapon_brand( item );
+
+ if (item_ident( item, ISFLAG_KNOW_TYPE ) && !terse)
+ {
+ if (brand == SPWPN_VAMPIRICISM)
+ strncat(buff, "vampiric ", ITEMNAME_SIZE );
+ } // end if
+
+ standard_name_weap( item_typ, tmp_buff );
+ strncat( buff, tmp_buff, ITEMNAME_SIZE );
+
+ if (item_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ switch (brand)
+ {
+ case SPWPN_NORMAL:
+ break;
+ case SPWPN_FLAMING:
+ strncat(buff, (terse) ? " (flame)" : " of flaming", ITEMNAME_SIZE );
+ break;
+ case SPWPN_FREEZING:
+ strncat(buff, (terse) ? " (freeze)" : " of freezing", ITEMNAME_SIZE );
+ break;
+ case SPWPN_HOLY_WRATH:
+ strncat(buff, (terse) ? " (holy)" : " of holy wrath", ITEMNAME_SIZE );
+ break;
+ case SPWPN_ELECTROCUTION:
+ strncat(buff, (terse) ? " (elec)" : " of electrocution", ITEMNAME_SIZE );
+ break;
+ case SPWPN_ORC_SLAYING:
+ strncat(buff, (terse) ? " (slay orc)" : " of orc slaying", ITEMNAME_SIZE );
+ break;
+ case SPWPN_VENOM:
+ strncat(buff, (terse) ? " (venom)" : " of venom", ITEMNAME_SIZE );
+ break;
+ case SPWPN_PROTECTION:
+ strncat(buff, (terse) ? " (protect)" : " of protection", ITEMNAME_SIZE );
+ break;
+ case SPWPN_DRAINING:
+ strncat(buff, (terse) ? " (drain)" : " of draining", ITEMNAME_SIZE );
+ break;
+ case SPWPN_SPEED:
+ strncat(buff, (terse) ? " (speed)" : " of speed", ITEMNAME_SIZE );
+ break;
+ case SPWPN_VORPAL:
+ switch (damage_type(item_clas, item_typ))
+ {
+ case DVORP_CRUSHING:
+ strncat(buff, (terse) ? " (crush)" : " of crushing", ITEMNAME_SIZE );
+ break;
+ case DVORP_SLICING:
+ strncat(buff, (terse) ? " (slice)" : " of slicing", ITEMNAME_SIZE );
+ break;
+ case DVORP_PIERCING:
+ strncat(buff, (terse) ? " (pierce)" : " of piercing", ITEMNAME_SIZE );
+ break;
+ case DVORP_CHOPPING:
+ strncat(buff, (terse) ? " (chop)" : " of chopping", ITEMNAME_SIZE );
+ break;
+ }
+ break;
+
+ case SPWPN_FLAME:
+ strncat(buff, (terse) ? " (flame)" : " of flame", ITEMNAME_SIZE );
+ break; // bows/xbows
+
+ case SPWPN_FROST:
+ strncat(buff, (terse) ? " (frost)" : " of frost", ITEMNAME_SIZE );
+ break; // bows/xbows
+
+ case SPWPN_VAMPIRICISM:
+ if (terse)
+ strncat( buff, " (vamp)", ITEMNAME_SIZE );
+ break;
+
+ case SPWPN_DISRUPTION:
+ strncat(buff, (terse) ? " (disrupt)" : " of disruption", ITEMNAME_SIZE );
+ break;
+ case SPWPN_PAIN:
+ strncat(buff, (terse) ? " (pain)" : " of pain", ITEMNAME_SIZE );
+ break;
+ case SPWPN_DISTORTION:
+ strncat(buff, (terse) ? " (distort)" : " of distortion", ITEMNAME_SIZE );
+ break;
+
+ case SPWPN_REACHING:
+ strncat(buff, (terse) ? " (reach)" : " of reaching", ITEMNAME_SIZE );
+ break;
+
+ /* 25 - 29 are randarts */
+ }
+ }
+
+ if (item_ident(item, ISFLAG_KNOW_CURSE) && item_cursed(item) && terse)
+ strncat( buff, " (curse)", ITEMNAME_SIZE );
+ break;
+
+ case OBJ_MISSILES:
+ brand = get_ammo_brand( item );
+
+ if (brand == SPMSL_POISONED || brand == SPMSL_POISONED_II)
+ {
+ strncat( buff, (terse) ? "poison " : "poisoned ", ITEMNAME_SIZE );
+ }
+
+ if (item_ident( item, ISFLAG_KNOW_PLUSES ))
+ {
+ if (it_plus >= 0)
+ strncat(buff, "+", ITEMNAME_SIZE );
+
+ itoa( it_plus, tmp_quant, 10 );
+
+ strncat(buff, tmp_quant, ITEMNAME_SIZE );
+ strncat(buff, " ", ITEMNAME_SIZE );
+ }
+
+ if (get_equip_race( item ))
+ {
+ int dwpn = get_equip_race( item );
+
+ strncat(buff,
+ (dwpn == ISFLAG_ORCISH) ? ((terse) ? "orc " : "orcish ") :
+ (dwpn == ISFLAG_ELVEN) ? ((terse) ? "elf " : "elven ") :
+ (dwpn == ISFLAG_DWARVEN) ? ((terse) ? "dwarf " : "dwarven ")
+ : "buggy ",
+ ITEMNAME_SIZE);
+ }
+
+ strncat(buff, (item_typ == MI_STONE) ? "stone" :
+ (item_typ == MI_ARROW) ? "arrow" :
+ (item_typ == MI_BOLT) ? "bolt" :
+ (item_typ == MI_DART) ? "dart" :
+ (item_typ == MI_NEEDLE) ? "needle" :
+ (item_typ == MI_EGGPLANT) ? "eggplant" :
+ (item_typ == MI_LARGE_ROCK) ? "large rock" : "", ITEMNAME_SIZE);
+ // this should probably be "" {dlb}
+
+ if (it_quant > 1)
+ strncat(buff, "s", ITEMNAME_SIZE );
+
+ if (item_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ strncat( buff,
+ (brand == SPMSL_FLAME) ? ((terse) ? " (flame)" : " of flame") :
+ (brand == SPMSL_ICE) ? ((terse) ? " (ice)" : " of ice") :
+ (brand == SPMSL_NORMAL) ? "" :
+ (brand == SPMSL_POISONED) ? "" :
+ (brand == SPMSL_POISONED_II) ? "" : " (buggy)", ITEMNAME_SIZE );
+ }
+ break;
+
+ case OBJ_ARMOUR:
+ if (item_ident( item, ISFLAG_KNOW_CURSE ) && !terse)
+ {
+ if (item_cursed( item ))
+ strncat(buff, "cursed ", ITEMNAME_SIZE );
+ else if (Options.show_uncursed
+ && item_not_ident( item, ISFLAG_KNOW_PLUSES ))
+ {
+ strncat(buff, "uncursed ", ITEMNAME_SIZE );
+ }
+ }
+
+ if (item_ident( item, ISFLAG_KNOW_PLUSES ))
+ {
+ if (it_plus >= 0)
+ strncat(buff, "+", ITEMNAME_SIZE );
+
+ itoa( it_plus, tmp_quant, 10 );
+
+ strncat(buff, tmp_quant, ITEMNAME_SIZE );
+ strncat(buff, " ", ITEMNAME_SIZE );
+ }
+
+ if (item_typ == ARM_GLOVES
+ || (item_typ == ARM_BOOTS && item_plus2 == TBOOT_BOOTS))
+ {
+ strncat( buff, "pair of ", ITEMNAME_SIZE );
+ }
+
+ if (is_random_artefact( item ))
+ {
+ strncat(buff, randart_armour_name(item), ITEMNAME_SIZE);
+ break;
+ }
+
+ // Now that we can have "glowing elven" armour, it's
+ // probably a good idea to cut out the descriptive
+ // term once it's become obsolete. -- bwr
+ if (item_not_ident( item, ISFLAG_KNOW_PLUSES ) && !terse)
+ {
+ switch (get_equip_desc( item ))
+ {
+ case ISFLAG_EMBROIDERED_SHINY:
+ if (item_typ == ARM_ROBE || item_typ == ARM_CLOAK
+ || item_typ == ARM_GLOVES || item_typ == ARM_BOOTS)
+ {
+ strncat(buff, "embroidered ", ITEMNAME_SIZE );
+ }
+ else if (item_typ != ARM_LEATHER_ARMOUR
+ && item_typ != ARM_ANIMAL_SKIN)
+ {
+ strncat(buff, "shiny ", ITEMNAME_SIZE );
+ }
+ break;
+
+ case ISFLAG_RUNED:
+ strncat(buff, "runed ", ITEMNAME_SIZE );
+ break;
+
+ case ISFLAG_GLOWING:
+ strncat(buff, "glowing ", ITEMNAME_SIZE );
+ break;
+ }
+ }
+
+ // always give racial description (has game effects)
+ switch (get_equip_race( item ))
+ {
+ case ISFLAG_ELVEN:
+ strncat(buff, (terse) ? "elf " :"elven ", ITEMNAME_SIZE );
+ break;
+ case ISFLAG_DWARVEN:
+ strncat(buff, (terse) ? "dwarf " : "dwarven ", ITEMNAME_SIZE );
+ break;
+ case ISFLAG_ORCISH:
+ strncat(buff, (terse) ? "orc " : "orcish ", ITEMNAME_SIZE );
+ break;
+ } // end switch
+
+ standard_name_armour( item, tmp_buff ); // in randart.cc
+ strncat( buff, tmp_buff, ITEMNAME_SIZE );
+
+ sparm = get_armour_ego_type( item );
+
+ if (item_ident( item, ISFLAG_KNOW_TYPE ) && sparm != SPARM_NORMAL)
+ {
+ if (!terse)
+ {
+ strncat(buff, " of ", ITEMNAME_SIZE );
+
+ strncat(buff, (sparm == SPARM_RUNNING) ? "running" :
+ (sparm == SPARM_FIRE_RESISTANCE) ? "fire resistance" :
+ (sparm == SPARM_COLD_RESISTANCE) ? "cold resistance" :
+ (sparm == SPARM_POISON_RESISTANCE) ? "poison resistance" :
+ (sparm == SPARM_SEE_INVISIBLE) ? "see invisible" :
+ (sparm == SPARM_DARKNESS) ? "darkness" :
+ (sparm == SPARM_STRENGTH) ? "strength" :
+ (sparm == SPARM_DEXTERITY) ? "dexterity" :
+ (sparm == SPARM_INTELLIGENCE) ? "intelligence" :
+ (sparm == SPARM_PONDEROUSNESS) ? "ponderousness" :
+ (sparm == SPARM_LEVITATION) ? "levitation" :
+ (sparm == SPARM_MAGIC_RESISTANCE) ? "magic resistance" :
+ (sparm == SPARM_PROTECTION) ? "protection" :
+ (sparm == SPARM_STEALTH) ? "stealth" :
+ (sparm == SPARM_RESISTANCE) ? "resistance" :
+ (sparm == SPARM_POSITIVE_ENERGY) ? "positive energy" :
+ (sparm == SPARM_ARCHMAGI) ? "the Archmagi" :
+ (sparm == SPARM_PRESERVATION) ? "preservation"
+ : "bugginess",
+ ITEMNAME_SIZE);
+ }
+ else
+ {
+ strncat(buff, (sparm == SPARM_RUNNING) ? " (run)" :
+ (sparm == SPARM_FIRE_RESISTANCE) ? " (R-fire)" :
+ (sparm == SPARM_COLD_RESISTANCE) ? " (R-cold)" :
+ (sparm == SPARM_POISON_RESISTANCE) ? " (R-poison)" :
+ (sparm == SPARM_SEE_INVISIBLE) ? " (see invis)" :
+ (sparm == SPARM_DARKNESS) ? " (darkness)" :
+ (sparm == SPARM_STRENGTH) ? " (str)" :
+ (sparm == SPARM_DEXTERITY) ? " (dex)" :
+ (sparm == SPARM_INTELLIGENCE) ? " (int)" :
+ (sparm == SPARM_PONDEROUSNESS) ? " (ponderous)" :
+ (sparm == SPARM_LEVITATION) ? " (levitate)" :
+ (sparm == SPARM_MAGIC_RESISTANCE) ? " (R-magic)" :
+ (sparm == SPARM_PROTECTION) ? " (protect)" :
+ (sparm == SPARM_STEALTH) ? " (stealth)" :
+ (sparm == SPARM_RESISTANCE) ? " (resist)" :
+ (sparm == SPARM_POSITIVE_ENERGY) ? " (R-neg)" : // ha ha
+ (sparm == SPARM_ARCHMAGI) ? " (Archmagi)" :
+ (sparm == SPARM_PRESERVATION) ? " (preserve)"
+ : " (buggy)",
+ ITEMNAME_SIZE);
+ }
+ }
+
+ if (item_ident(item, ISFLAG_KNOW_CURSE) && item_cursed(item) && terse)
+ strncat( buff, " (curse)", ITEMNAME_SIZE );
+ break;
+
+ // compacted 15 Apr 2000 {dlb}:
+ case OBJ_WANDS:
+ if (id[ IDTYPE_WANDS ][item_typ] == ID_KNOWN_TYPE
+ || item_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ strncat(buff, "wand of ", ITEMNAME_SIZE );
+ strncat(buff, (item_typ == WAND_FLAME) ? "flame" :
+ (item_typ == WAND_FROST) ? "frost" :
+ (item_typ == WAND_SLOWING) ? "slowing" :
+ (item_typ == WAND_HASTING) ? "hasting" :
+ (item_typ == WAND_MAGIC_DARTS) ? "magic darts" :
+ (item_typ == WAND_HEALING) ? "healing" :
+ (item_typ == WAND_PARALYSIS) ? "paralysis" :
+ (item_typ == WAND_FIRE) ? "fire" :
+ (item_typ == WAND_COLD) ? "cold" :
+ (item_typ == WAND_CONFUSION) ? "confusion" :
+ (item_typ == WAND_INVISIBILITY) ? "invisibility" :
+ (item_typ == WAND_DIGGING) ? "digging" :
+ (item_typ == WAND_FIREBALL) ? "fireball" :
+ (item_typ == WAND_TELEPORTATION) ? "teleportation" :
+ (item_typ == WAND_LIGHTNING) ? "lightning" :
+ (item_typ == WAND_POLYMORPH_OTHER) ? "polymorph other" :
+ (item_typ == WAND_ENSLAVEMENT) ? "enslavement" :
+ (item_typ == WAND_DRAINING) ? "draining" :
+ (item_typ == WAND_RANDOM_EFFECTS) ? "random effects" :
+ (item_typ == WAND_DISINTEGRATION) ? "disintegration"
+ : "bugginess",
+ ITEMNAME_SIZE );
+ }
+ else
+ {
+ char primary = (item.special % 12);
+ char secondary = (item.special / 12);
+
+ strncat(buff,(secondary == 0) ? "" : // hope this works {dlb}
+ (secondary == 1) ? "jeweled" :
+ (secondary == 2) ? "curved" :
+ (secondary == 3) ? "long" :
+ (secondary == 4) ? "short" :
+ (secondary == 5) ? "twisted" :
+ (secondary == 6) ? "crooked" :
+ (secondary == 7) ? "forked" :
+ (secondary == 8) ? "shiny" :
+ (secondary == 9) ? "blackened" :
+ (secondary == 10) ? "tapered" :
+ (secondary == 11) ? "glowing" :
+ (secondary == 12) ? "worn" :
+ (secondary == 13) ? "encrusted" :
+ (secondary == 14) ? "runed" :
+ (secondary == 15) ? "sharpened" : "buggily", ITEMNAME_SIZE);
+
+ if (secondary != 0)
+ strncat(buff, " ", ITEMNAME_SIZE );
+
+ strncat(buff, (primary == 0) ? "iron" :
+ (primary == 1) ? "brass" :
+ (primary == 2) ? "bone" :
+ (primary == 3) ? "wooden" :
+ (primary == 4) ? "copper" :
+ (primary == 5) ? "gold" :
+ (primary == 6) ? "silver" :
+ (primary == 7) ? "bronze" :
+ (primary == 8) ? "ivory" :
+ (primary == 9) ? "glass" :
+ (primary == 10) ? "lead" :
+ (primary == 11) ? "plastic" : "buggy", ITEMNAME_SIZE);
+
+ strncat(buff, " wand", ITEMNAME_SIZE );
+
+ if (id[ IDTYPE_WANDS ][item_typ] == ID_TRIED_TYPE)
+ {
+ strncat( buff, " {tried}" , ITEMNAME_SIZE );
+ }
+ }
+
+ if (item_ident( item, ISFLAG_KNOW_PLUSES ))
+ {
+ strncat(buff, " (", ITEMNAME_SIZE );
+ itoa( it_plus, tmp_quant, 10 );
+ strncat(buff, tmp_quant, ITEMNAME_SIZE );
+ strncat(buff, ")", ITEMNAME_SIZE);
+ }
+ break;
+
+ // NB: potions, food, and scrolls stack on the basis of class and
+ // type ONLY !!!
+
+ // compacted 15 Apr 2000 {dlb}:
+ case OBJ_POTIONS:
+ if (id[ IDTYPE_POTIONS ][item_typ] == ID_KNOWN_TYPE
+ || item_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ strncat(buff, "potion", ITEMNAME_SIZE );
+ strncat(buff, (it_quant == 1) ? " " : "s ", ITEMNAME_SIZE);
+ strncat(buff, "of ", ITEMNAME_SIZE );
+ strncat(buff, (item_typ == POT_HEALING) ? "healing" :
+ (item_typ == POT_HEAL_WOUNDS) ? "heal wounds" :
+ (item_typ == POT_SPEED) ? "speed" :
+ (item_typ == POT_MIGHT) ? "might" :
+ (item_typ == POT_GAIN_STRENGTH) ? "gain strength" :
+ (item_typ == POT_GAIN_DEXTERITY) ? "gain dexterity" :
+ (item_typ == POT_GAIN_INTELLIGENCE) ? "gain intelligence" :
+ (item_typ == POT_LEVITATION) ? "levitation" :
+ (item_typ == POT_POISON) ? "poison" :
+ (item_typ == POT_SLOWING) ? "slowing" :
+ (item_typ == POT_PARALYSIS) ? "paralysis" :
+ (item_typ == POT_CONFUSION) ? "confusion" :
+ (item_typ == POT_INVISIBILITY) ? "invisibility" :
+ (item_typ == POT_PORRIDGE) ? "porridge" :
+ (item_typ == POT_DEGENERATION) ? "degeneration" :
+ (item_typ == POT_DECAY) ? "decay" :
+ (item_typ == POT_WATER) ? "water" :
+ (item_typ == POT_EXPERIENCE) ? "experience" :
+ (item_typ == POT_MAGIC) ? "magic" :
+ (item_typ == POT_RESTORE_ABILITIES) ? "restore abilities" :
+ (item_typ == POT_STRONG_POISON) ? "strong poison" :
+ (item_typ == POT_BERSERK_RAGE) ? "berserk rage" :
+ (item_typ == POT_CURE_MUTATION) ? "cure mutation" :
+ (item_typ == POT_MUTATION) ? "mutation" : "bugginess",
+ ITEMNAME_SIZE);
+ }
+ else
+ {
+ char primary = item.special / 14;
+ char secondary = item.special % 14;
+
+ strncat(buff,
+ (primary == 0) ? "" :
+ (primary == 1) ? "bubbling " :
+ (primary == 2) ? "lumpy " :
+ (primary == 3) ? "fuming " :
+ (primary == 4) ? "smoky " :
+ (primary == 5) ? "fizzy " :
+ (primary == 6) ? "glowing " :
+ (primary == 7) ? "sedimented " :
+ (primary == 8) ? "metallic " :
+ (primary == 9) ? "murky " :
+ (primary == 10) ? "gluggy " :
+ (primary == 11) ? "viscous " :
+ (primary == 12) ? "oily " :
+ (primary == 13) ? "slimy " :
+ (primary == 14) ? "emulsified " : "buggy ", ITEMNAME_SIZE);
+
+ strncat(buff,
+ (secondary == 0) ? "clear" :
+ (secondary == 1) ? "blue" :
+ (secondary == 2) ? "black" :
+ (secondary == 3) ? "silvery" :
+ (secondary == 4) ? "cyan" :
+ (secondary == 5) ? "purple" :
+ (secondary == 6) ? "orange" :
+ (secondary == 7) ? "inky" :
+ (secondary == 8) ? "red" :
+ (secondary == 9) ? "yellow" :
+ (secondary == 10) ? "green" :
+ (secondary == 11) ? "brown" :
+ (secondary == 12) ? "pink" :
+ (secondary == 13) ? "white" : "buggy", ITEMNAME_SIZE);
+
+ strncat(buff, " potion", ITEMNAME_SIZE );
+
+ if (it_quant > 1)
+ strncat(buff, "s", ITEMNAME_SIZE );
+
+ if (id[ IDTYPE_POTIONS ][item_typ] == ID_TRIED_TYPE)
+ {
+ strncat( buff, " {tried}" , ITEMNAME_SIZE );
+ }
+ }
+ break;
+
+ // NB: adding another food type == must set for carnivorous chars
+ // (Kobolds and mutants)
+ case OBJ_FOOD:
+ switch (item_typ)
+ {
+ case FOOD_MEAT_RATION:
+ strncat(buff, "meat ration", ITEMNAME_SIZE );
+ break;
+ case FOOD_BREAD_RATION:
+ strncat(buff, "bread ration", ITEMNAME_SIZE );
+ break;
+ case FOOD_PEAR:
+ strncat(buff, "pear", ITEMNAME_SIZE );
+ break;
+ case FOOD_APPLE: // make this less common
+ strncat(buff, "apple", ITEMNAME_SIZE );
+ break;
+ case FOOD_CHOKO:
+ strncat(buff, "choko", ITEMNAME_SIZE );
+ break;
+ case FOOD_HONEYCOMB:
+ strncat(buff, "honeycomb", ITEMNAME_SIZE );
+ break;
+ case FOOD_ROYAL_JELLY:
+ strncat(buff, "royal jell", ITEMNAME_SIZE );
+ break;
+ case FOOD_SNOZZCUMBER:
+ strncat(buff, "snozzcumber", ITEMNAME_SIZE );
+ break;
+ case FOOD_PIZZA:
+ strncat(buff, "slice of pizza", ITEMNAME_SIZE );
+ break;
+ case FOOD_APRICOT:
+ strncat(buff, "apricot", ITEMNAME_SIZE );
+ break;
+ case FOOD_ORANGE:
+ strncat(buff, "orange", ITEMNAME_SIZE );
+ break;
+ case FOOD_BANANA:
+ strncat(buff, "banana", ITEMNAME_SIZE );
+ break;
+ case FOOD_STRAWBERRY:
+ strncat(buff, "strawberr", ITEMNAME_SIZE );
+ break;
+ case FOOD_RAMBUTAN:
+ strncat(buff, "rambutan", ITEMNAME_SIZE );
+ break;
+ case FOOD_LEMON:
+ strncat(buff, "lemon", ITEMNAME_SIZE );
+ break;
+ case FOOD_GRAPE:
+ strncat(buff, "grape", ITEMNAME_SIZE );
+ break;
+ case FOOD_SULTANA:
+ strncat(buff, "sultana", ITEMNAME_SIZE );
+ break;
+ case FOOD_LYCHEE:
+ strncat(buff, "lychee", ITEMNAME_SIZE );
+ break;
+ case FOOD_BEEF_JERKY:
+ strncat(buff, "beef jerk", ITEMNAME_SIZE );
+ break;
+ case FOOD_CHEESE:
+ strncat(buff, "cheese", ITEMNAME_SIZE );
+ break;
+ case FOOD_SAUSAGE:
+ strncat(buff, "sausage", ITEMNAME_SIZE );
+ break;
+ case FOOD_CHUNK:
+ moname( it_plus, true, DESC_PLAIN, tmp_buff );
+
+ if (item.special < 100)
+ strncat(buff, "rotting ", ITEMNAME_SIZE );
+
+ strncat(buff, "chunk", ITEMNAME_SIZE );
+
+ if (it_quant > 1)
+ strncat(buff, "s", ITEMNAME_SIZE );
+
+ strncat(buff, " of ", ITEMNAME_SIZE );
+ strncat(buff, tmp_buff, ITEMNAME_SIZE );
+ strncat(buff, " flesh", ITEMNAME_SIZE );
+ break;
+
+ }
+
+ if (item_typ == FOOD_ROYAL_JELLY || item_typ == FOOD_STRAWBERRY
+ || item_typ == FOOD_BEEF_JERKY)
+ strncat(buff, (it_quant > 1) ? "ie" : "y", ITEMNAME_SIZE );
+ break;
+
+ // compacted 15 Apr 2000 {dlb}:
+ case OBJ_SCROLLS:
+ strncat(buff, "scroll", ITEMNAME_SIZE );
+ strncat(buff, (it_quant == 1) ? " " : "s ", ITEMNAME_SIZE);
+
+ if (id[ IDTYPE_SCROLLS ][item_typ] == ID_KNOWN_TYPE
+ || item_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ strncat(buff, "of ", ITEMNAME_SIZE );
+ strncat(buff, (item_typ == SCR_IDENTIFY) ? "identify" :
+ (item_typ == SCR_TELEPORTATION) ? "teleportation" :
+ (item_typ == SCR_FEAR) ? "fear" :
+ (item_typ == SCR_NOISE) ? "noise" :
+ (item_typ == SCR_REMOVE_CURSE) ? "remove curse" :
+ (item_typ == SCR_DETECT_CURSE) ? "detect curse" :
+ (item_typ == SCR_SUMMONING) ? "summoning" :
+ (item_typ == SCR_ENCHANT_WEAPON_I) ? "enchant weapon I" :
+ (item_typ == SCR_ENCHANT_ARMOUR) ? "enchant armour" :
+ (item_typ == SCR_TORMENT) ? "torment" :
+ (item_typ == SCR_RANDOM_USELESSNESS) ? "random uselessness" :
+ (item_typ == SCR_CURSE_WEAPON) ? "curse weapon" :
+ (item_typ == SCR_CURSE_ARMOUR) ? "curse armour" :
+ (item_typ == SCR_IMMOLATION) ? "immolation" :
+ (item_typ == SCR_BLINKING) ? "blinking" :
+ (item_typ == SCR_PAPER) ? "paper" :
+ (item_typ == SCR_MAGIC_MAPPING) ? "magic mapping" :
+ (item_typ == SCR_FORGETFULNESS) ? "forgetfulness" :
+ (item_typ == SCR_ACQUIREMENT) ? "acquirement" :
+ (item_typ == SCR_ENCHANT_WEAPON_II) ? "enchant weapon II" :
+ (item_typ == SCR_VORPALISE_WEAPON) ? "vorpalise weapon" :
+ (item_typ == SCR_RECHARGING) ? "recharging" :
+ //(item_typ == 23) ? "portal travel" :
+ (item_typ == SCR_ENCHANT_WEAPON_III) ? "enchant weapon III"
+ : "bugginess",
+ ITEMNAME_SIZE);
+ }
+ else
+ {
+ strncat(buff, "labeled ", ITEMNAME_SIZE );
+ char buff3[ ITEMNAME_SIZE ];
+
+ make_name( item.special, it_plus, item_clas, 2, buff3 );
+ strncat( buff, buff3 , ITEMNAME_SIZE );
+
+ if (id[ IDTYPE_SCROLLS ][item_typ] == ID_TRIED_TYPE)
+ {
+ strncat( buff, " {tried}" , ITEMNAME_SIZE );
+ }
+ }
+ break;
+
+ // compacted 15 Apr 2000 {dlb}: -- on hold ... what a mess!
+ case OBJ_JEWELLERY:
+ // not using {tried} here because there are some confusing
+ // issues to work out with how we want to handle jewellery
+ // artefacts and base type id. -- bwr
+ if (item_ident( item, ISFLAG_KNOW_CURSE ))
+ {
+ if (item_cursed( item ))
+ strncat(buff, "cursed ", ITEMNAME_SIZE );
+ else if (Options.show_uncursed
+ && item_not_ident( item, ISFLAG_KNOW_PLUSES ))
+ {
+ strncat(buff, "uncursed ", ITEMNAME_SIZE );
+ }
+ }
+
+ if (is_random_artefact( item ))
+ {
+ strncat(buff, randart_ring_name(item), ITEMNAME_SIZE);
+ break;
+ }
+
+ if (id[ IDTYPE_JEWELLERY ][item_typ] == ID_KNOWN_TYPE
+ || item_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+
+ if (item_ident( item, ISFLAG_KNOW_PLUSES )
+ && (item_typ == RING_PROTECTION || item_typ == RING_STRENGTH
+ || item_typ == RING_SLAYING || item_typ == RING_EVASION
+ || item_typ == RING_DEXTERITY
+ || item_typ == RING_INTELLIGENCE))
+ {
+ char gokh = it_plus;
+
+ if (gokh >= 0)
+ strncat( buff, "+" , ITEMNAME_SIZE );
+
+ itoa( gokh, tmp_quant, 10 );
+ strncat( buff, tmp_quant , ITEMNAME_SIZE );
+
+ if (item_typ == RING_SLAYING)
+ {
+ strncat( buff, "," , ITEMNAME_SIZE );
+
+ if (item_plus2 >= 0)
+ strncat(buff, "+", ITEMNAME_SIZE );
+
+ itoa( item_plus2, tmp_quant, 10 );
+ strncat( buff, tmp_quant , ITEMNAME_SIZE );
+ }
+
+ strncat(buff, " ", ITEMNAME_SIZE );
+ }
+
+ switch (item_typ)
+ {
+ case RING_REGENERATION:
+ strncat(buff, "ring of regeneration", ITEMNAME_SIZE );
+ break;
+ case RING_PROTECTION:
+ strncat(buff, "ring of protection", ITEMNAME_SIZE );
+ break;
+ case RING_PROTECTION_FROM_FIRE:
+ strncat(buff, "ring of protection from fire", ITEMNAME_SIZE );
+ break;
+ case RING_POISON_RESISTANCE:
+ strncat(buff, "ring of poison resistance", ITEMNAME_SIZE );
+ break;
+ case RING_PROTECTION_FROM_COLD:
+ strncat(buff, "ring of protection from cold", ITEMNAME_SIZE );
+ break;
+ case RING_STRENGTH:
+ strncat(buff, "ring of strength", ITEMNAME_SIZE );
+ break;
+ case RING_SLAYING:
+ strncat(buff, "ring of slaying", ITEMNAME_SIZE );
+ break;
+ case RING_SEE_INVISIBLE:
+ strncat(buff, "ring of see invisible", ITEMNAME_SIZE );
+ break;
+ case RING_INVISIBILITY:
+ strncat(buff, "ring of invisibility", ITEMNAME_SIZE );
+ break;
+ case RING_HUNGER:
+ strncat(buff, "ring of hunger", ITEMNAME_SIZE );
+ break;
+ case RING_TELEPORTATION:
+ strncat(buff, "ring of teleportation", ITEMNAME_SIZE );
+ break;
+ case RING_EVASION:
+ strncat(buff, "ring of evasion", ITEMNAME_SIZE );
+ break;
+ case RING_SUSTAIN_ABILITIES:
+ strncat(buff, "ring of sustain abilities", ITEMNAME_SIZE );
+ break;
+ case RING_SUSTENANCE:
+ strncat(buff, "ring of sustenance", ITEMNAME_SIZE );
+ break;
+ case RING_DEXTERITY:
+ strncat(buff, "ring of dexterity", ITEMNAME_SIZE );
+ break;
+ case RING_INTELLIGENCE:
+ strncat(buff, "ring of intelligence", ITEMNAME_SIZE );
+ break;
+ case RING_WIZARDRY:
+ strncat(buff, "ring of wizardry", ITEMNAME_SIZE );
+ break;
+ case RING_MAGICAL_POWER:
+ strncat(buff, "ring of magical power", ITEMNAME_SIZE );
+ break;
+ case RING_LEVITATION:
+ strncat(buff, "ring of levitation", ITEMNAME_SIZE );
+ break;
+ case RING_LIFE_PROTECTION:
+ strncat(buff, "ring of life protection", ITEMNAME_SIZE );
+ break;
+ case RING_PROTECTION_FROM_MAGIC:
+ strncat(buff, "ring of protection from magic", ITEMNAME_SIZE );
+ break;
+ case RING_FIRE:
+ strncat(buff, "ring of fire", ITEMNAME_SIZE );
+ break;
+ case RING_ICE:
+ strncat(buff, "ring of ice", ITEMNAME_SIZE );
+ break;
+ case RING_TELEPORT_CONTROL:
+ strncat(buff, "ring of teleport control", ITEMNAME_SIZE );
+ break;
+ case AMU_RAGE:
+ strncat(buff, "amulet of rage", ITEMNAME_SIZE );
+ break;
+ case AMU_RESIST_SLOW:
+ strncat(buff, "amulet of resist slowing", ITEMNAME_SIZE );
+ break;
+ case AMU_CLARITY:
+ strncat(buff, "amulet of clarity", ITEMNAME_SIZE );
+ break;
+ case AMU_WARDING:
+ strncat(buff, "amulet of warding", ITEMNAME_SIZE );
+ break;
+ case AMU_RESIST_CORROSION:
+ strncat(buff, "amulet of resist corrosion", ITEMNAME_SIZE );
+ break;
+ case AMU_THE_GOURMAND:
+ strncat(buff, "amulet of the gourmand", ITEMNAME_SIZE );
+ break;
+ case AMU_CONSERVATION:
+ strncat(buff, "amulet of conservation", ITEMNAME_SIZE );
+ break;
+ case AMU_CONTROLLED_FLIGHT:
+ strncat(buff, "amulet of controlled flight", ITEMNAME_SIZE );
+ break;
+ case AMU_INACCURACY:
+ strncat(buff, "amulet of inaccuracy", ITEMNAME_SIZE );
+ break;
+ case AMU_RESIST_MUTATION:
+ strncat(buff, "amulet of resist mutation", ITEMNAME_SIZE );
+ break;
+ }
+ /* ? of imputed learning - 100% exp from tames/summoned kills */
+ break;
+ }
+
+ if (item_typ < AMU_RAGE) // rings
+ {
+ if (is_random_artefact( item ))
+ {
+ strncat(buff, randart_ring_name(item), ITEMNAME_SIZE);
+ break;
+ }
+
+ switch (item.special / 13) // secondary characteristic of ring
+ {
+ case 1:
+ strncat(buff, "encrusted ", ITEMNAME_SIZE );
+ break;
+ case 2:
+ strncat(buff, "glowing ", ITEMNAME_SIZE );
+ break;
+ case 3:
+ strncat(buff, "tubular ", ITEMNAME_SIZE );
+ break;
+ case 4:
+ strncat(buff, "runed ", ITEMNAME_SIZE );
+ break;
+ case 5:
+ strncat(buff, "blackened ", ITEMNAME_SIZE );
+ break;
+ case 6:
+ strncat(buff, "scratched ", ITEMNAME_SIZE );
+ break;
+ case 7:
+ strncat(buff, "small ", ITEMNAME_SIZE );
+ break;
+ case 8:
+ strncat(buff, "large ", ITEMNAME_SIZE );
+ break;
+ case 9:
+ strncat(buff, "twisted ", ITEMNAME_SIZE );
+ break;
+ case 10:
+ strncat(buff, "shiny ", ITEMNAME_SIZE );
+ break;
+ case 11:
+ strncat(buff, "notched ", ITEMNAME_SIZE );
+ break;
+ case 12:
+ strncat(buff, "knobbly ", ITEMNAME_SIZE );
+ break;
+ }
+
+ switch (item.special % 13)
+ {
+ case 0:
+ strncat(buff, "wooden ring", ITEMNAME_SIZE );
+ break;
+ case 1:
+ strncat(buff, "silver ring", ITEMNAME_SIZE );
+ break;
+ case 2:
+ strncat(buff, "golden ring", ITEMNAME_SIZE );
+ break;
+ case 3:
+ strncat(buff, "iron ring", ITEMNAME_SIZE );
+ break;
+ case 4:
+ strncat(buff, "steel ring", ITEMNAME_SIZE );
+ break;
+ case 5:
+ strncat(buff, "bronze ring", ITEMNAME_SIZE );
+ break;
+ case 6:
+ strncat(buff, "brass ring", ITEMNAME_SIZE );
+ break;
+ case 7:
+ strncat(buff, "copper ring", ITEMNAME_SIZE );
+ break;
+ case 8:
+ strncat(buff, "granite ring", ITEMNAME_SIZE );
+ break;
+ case 9:
+ strncat(buff, "ivory ring", ITEMNAME_SIZE );
+ break;
+ case 10:
+ strncat(buff, "bone ring", ITEMNAME_SIZE );
+ break;
+ case 11:
+ strncat(buff, "marble ring", ITEMNAME_SIZE );
+ break;
+ case 12:
+ strncat(buff, "jade ring", ITEMNAME_SIZE );
+ break;
+ case 13:
+ strncat(buff, "glass ring", ITEMNAME_SIZE );
+ break;
+ }
+ } // end of rings
+ else // ie is an amulet
+ {
+ if (is_random_artefact( item ))
+ {
+ strncat(buff, randart_ring_name(item), ITEMNAME_SIZE);
+ break;
+ }
+
+ if (item.special > 13)
+ {
+ switch (item.special / 13) // secondary characteristic of amulet
+ {
+ case 0:
+ strncat(buff, "dented ", ITEMNAME_SIZE );
+ break;
+ case 1:
+ strncat(buff, "square ", ITEMNAME_SIZE );
+ break;
+ case 2:
+ strncat(buff, "thick ", ITEMNAME_SIZE );
+ break;
+ case 3:
+ strncat(buff, "thin ", ITEMNAME_SIZE );
+ break;
+ case 4:
+ strncat(buff, "runed ", ITEMNAME_SIZE );
+ break;
+ case 5:
+ strncat(buff, "blackened ", ITEMNAME_SIZE );
+ break;
+ case 6:
+ strncat(buff, "glowing ", ITEMNAME_SIZE );
+ break;
+ case 7:
+ strncat(buff, "small ", ITEMNAME_SIZE );
+ break;
+ case 8:
+ strncat(buff, "large ", ITEMNAME_SIZE );
+ break;
+ case 9:
+ strncat(buff, "twisted ", ITEMNAME_SIZE );
+ break;
+ case 10:
+ strncat(buff, "tiny ", ITEMNAME_SIZE );
+ break;
+ case 11:
+ strncat(buff, "triangular ", ITEMNAME_SIZE );
+ break;
+ case 12:
+ strncat(buff, "lumpy ", ITEMNAME_SIZE );
+ break;
+ }
+ }
+
+ switch (item.special % 13)
+ {
+ case 0:
+ strncat(buff, "zirconium amulet", ITEMNAME_SIZE );
+ break;
+ case 1:
+ strncat(buff, "sapphire amulet", ITEMNAME_SIZE );
+ break;
+ case 2:
+ strncat(buff, "golden amulet", ITEMNAME_SIZE );
+ break;
+ case 3:
+ strncat(buff, "emerald amulet", ITEMNAME_SIZE );
+ break;
+ case 4:
+ strncat(buff, "garnet amulet", ITEMNAME_SIZE );
+ break;
+ case 5:
+ strncat(buff, "bronze amulet", ITEMNAME_SIZE );
+ break;
+ case 6:
+ strncat(buff, "brass amulet", ITEMNAME_SIZE );
+ break;
+ case 7:
+ strncat(buff, "copper amulet", ITEMNAME_SIZE );
+ break;
+ case 8:
+ strncat(buff, "ruby amulet", ITEMNAME_SIZE );
+ break;
+ case 9:
+ strncat(buff, "ivory amulet", ITEMNAME_SIZE );
+ break;
+ case 10:
+ strncat(buff, "bone amulet", ITEMNAME_SIZE );
+ break;
+ case 11:
+ strncat(buff, "platinum amulet", ITEMNAME_SIZE );
+ break;
+ case 12:
+ strncat(buff, "jade amulet", ITEMNAME_SIZE );
+ break;
+ case 13:
+ strncat(buff, "plastic amulet", ITEMNAME_SIZE );
+ break;
+ }
+ } // end of amulets
+ break;
+
+ // compacted 15 Apr 2000 {dlb}:
+ case OBJ_MISCELLANY:
+ switch (item_typ)
+ {
+ case MISC_RUNE_OF_ZOT:
+ strncat( buff, (it_plus == RUNE_DIS) ? "iron" :
+ (it_plus == RUNE_GEHENNA) ? "obsidian" :
+ (it_plus == RUNE_COCYTUS) ? "icy" :
+ (it_plus == RUNE_TARTARUS) ? "bone" :
+ (it_plus == RUNE_SLIME_PITS) ? "slimy" :
+ (it_plus == RUNE_VAULTS) ? "silver" :
+ (it_plus == RUNE_SNAKE_PIT) ? "serpentine" :
+ (it_plus == RUNE_ELVEN_HALLS) ? "elven" :
+ (it_plus == RUNE_TOMB) ? "golden" :
+ (it_plus == RUNE_SWAMP) ? "decaying" :
+
+ // pandemonium and abyss runes:
+ (it_plus == RUNE_DEMONIC) ? "demonic" :
+ (it_plus == RUNE_ABYSSAL) ? "abyssal" :
+
+ // special pandemonium runes:
+ (it_plus == RUNE_MNOLEG) ? "glowing" :
+ (it_plus == RUNE_LOM_LOBON) ? "magical" :
+ (it_plus == RUNE_CEREBOV) ? "fiery" :
+ (it_plus == RUNE_GLOORX_VLOQ) ? "dark"
+ : "buggy",
+ ITEMNAME_SIZE);
+
+ strncat(buff, " ", ITEMNAME_SIZE );
+ strncat(buff, "rune", ITEMNAME_SIZE );
+
+ if (it_quant > 1)
+ strncat(buff, "s", ITEMNAME_SIZE );
+
+ if (item_ident( item, ISFLAG_KNOW_TYPE ))
+ strncat(buff, " of Zot", ITEMNAME_SIZE );
+ break;
+
+ case MISC_DECK_OF_POWER:
+ case MISC_DECK_OF_SUMMONINGS:
+ case MISC_DECK_OF_TRICKS:
+ case MISC_DECK_OF_WONDERS:
+ strncat(buff, "deck of ", ITEMNAME_SIZE );
+ strncat(buff, item_not_ident( item, ISFLAG_KNOW_TYPE ) ? "cards" :
+ (item_typ == MISC_DECK_OF_WONDERS) ? "wonders" :
+ (item_typ == MISC_DECK_OF_SUMMONINGS) ? "summonings" :
+ (item_typ == MISC_DECK_OF_TRICKS) ? "tricks" :
+ (item_typ == MISC_DECK_OF_POWER) ? "power"
+ : "bugginess",
+ ITEMNAME_SIZE);
+ break;
+
+ case MISC_CRYSTAL_BALL_OF_ENERGY:
+ case MISC_CRYSTAL_BALL_OF_FIXATION:
+ case MISC_CRYSTAL_BALL_OF_SEEING:
+ strncat(buff, "crystal ball", ITEMNAME_SIZE );
+ if (item_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ strncat(buff, " of ", ITEMNAME_SIZE );
+ strncat(buff,
+ (item_typ == MISC_CRYSTAL_BALL_OF_SEEING) ? "seeing" :
+ (item_typ == MISC_CRYSTAL_BALL_OF_ENERGY) ? "energy" :
+ (item_typ == MISC_CRYSTAL_BALL_OF_FIXATION) ? "fixation"
+ : "bugginess",
+ ITEMNAME_SIZE);
+ }
+ break;
+
+ case MISC_BOX_OF_BEASTS:
+ if (item_ident( item, ISFLAG_KNOW_TYPE ))
+ strncat(buff, "box of beasts", ITEMNAME_SIZE );
+ else
+ strncat(buff, "small ebony casket", ITEMNAME_SIZE );
+ break;
+
+ case MISC_EMPTY_EBONY_CASKET:
+ if (item_ident( item, ISFLAG_KNOW_TYPE ))
+ strncat(buff, "empty ebony casket", ITEMNAME_SIZE );
+ else
+ strncat(buff, "small ebony casket", ITEMNAME_SIZE );
+ break;
+
+ case MISC_AIR_ELEMENTAL_FAN:
+ if (item_ident( item, ISFLAG_KNOW_TYPE ))
+ strncat(buff, "air elemental ", ITEMNAME_SIZE );
+ strncat(buff, "fan", ITEMNAME_SIZE );
+ break;
+
+ case MISC_LAMP_OF_FIRE:
+ strncat(buff, "lamp", ITEMNAME_SIZE );
+ if (item_ident( item, ISFLAG_KNOW_TYPE ))
+ strncat(buff, " of fire", ITEMNAME_SIZE );
+ break;
+
+ case MISC_LANTERN_OF_SHADOWS:
+ if (item_not_ident( item, ISFLAG_KNOW_TYPE ))
+ strncat(buff, "bone ", ITEMNAME_SIZE );
+ strncat(buff, "lantern", ITEMNAME_SIZE );
+
+ if (item_ident( item, ISFLAG_KNOW_TYPE ))
+ strncat(buff, " of shadows", ITEMNAME_SIZE );
+ break;
+
+ case MISC_HORN_OF_GERYON:
+ if (item_not_ident( item, ISFLAG_KNOW_TYPE ))
+ strncat(buff, "silver ", ITEMNAME_SIZE );
+ strncat(buff, "horn", ITEMNAME_SIZE );
+
+ if (item_ident( item, ISFLAG_KNOW_TYPE ))
+ strncat(buff, " of Geryon", ITEMNAME_SIZE );
+ break;
+
+ case MISC_DISC_OF_STORMS:
+ if (item_not_ident( item, ISFLAG_KNOW_TYPE ))
+ strncat(buff, "grey ", ITEMNAME_SIZE );
+ strncat(buff, "disc", ITEMNAME_SIZE );
+
+ if (item_ident( item, ISFLAG_KNOW_TYPE ))
+ strncat(buff, " of storms", ITEMNAME_SIZE );
+ break;
+
+ case MISC_STONE_OF_EARTH_ELEMENTALS:
+ if (item_not_ident( item, ISFLAG_KNOW_TYPE ))
+ strncat(buff, "nondescript ", ITEMNAME_SIZE );
+ strncat(buff, "stone", ITEMNAME_SIZE );
+
+ if (item_ident( item, ISFLAG_KNOW_TYPE ))
+ strncat(buff, " of earth elementals", ITEMNAME_SIZE );
+ break;
+
+ case MISC_BOTTLED_EFREET:
+ strncat(buff, (item_not_ident( item, ISFLAG_KNOW_TYPE ))
+ ? "sealed bronze flask" : "bottled efreet",
+ ITEMNAME_SIZE );
+ break;
+
+ case MISC_PORTABLE_ALTAR_OF_NEMELEX:
+ strncat(buff, "portable altar of Nemelex", ITEMNAME_SIZE );
+ break;
+
+ default:
+ strncat(buff, "buggy miscellaneous item", ITEMNAME_SIZE );
+ break;
+ }
+ break;
+
+ // compacted 15 Apr 2000 {dlb}:
+ case OBJ_BOOKS:
+ if (item_not_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ char primary = (item.special / 10);
+ char secondary = (item.special % 10);
+
+ strncat(buff, (primary == 0) ? "" :
+ (primary == 1) ? "chunky " :
+ (primary == 2) ? "thick " :
+ (primary == 3) ? "thin " :
+ (primary == 4) ? "wide " :
+ (primary == 5) ? "glowing " :
+ (primary == 6) ? "dog-eared " :
+ (primary == 7) ? "oblong " :
+ (primary == 8) ? "runed " :
+
+ // these last three were single spaces {dlb}
+ (primary == 9) ? "" :
+ (primary == 10) ? "" : (primary == 11) ? "" : "buggily ",
+ ITEMNAME_SIZE);
+
+ strncat(buff, (secondary == 0) ? "paperback " :
+ (secondary == 1) ? "hardcover " :
+ (secondary == 2) ? "leatherbound " :
+ (secondary == 3) ? "metal-bound " :
+ (secondary == 4) ? "papyrus " :
+ // these two were single spaces, too {dlb}
+ (secondary == 5) ? "" :
+ (secondary == 6) ? "" : "buggy ", ITEMNAME_SIZE);
+
+ strncat(buff, "book", ITEMNAME_SIZE );
+ }
+ else if (item_typ == BOOK_MANUAL)
+ {
+ strncat(buff, "manual of ", ITEMNAME_SIZE );
+ strncat(buff, skill_name(it_plus), ITEMNAME_SIZE );
+ }
+ else if (item_typ == BOOK_NECRONOMICON)
+ strncat(buff, "Necronomicon", ITEMNAME_SIZE );
+ else if (item_typ == BOOK_DESTRUCTION)
+ strncat(buff, "tome of Destruction", ITEMNAME_SIZE );
+ else if (item_typ == BOOK_YOUNG_POISONERS)
+ strncat(buff, "Young Poisoner's Handbook", ITEMNAME_SIZE );
+ else if (item_typ == BOOK_BEASTS)
+ strncat(buff, "Monster Manual", ITEMNAME_SIZE );
+ else
+ {
+ strncat(buff, "book of ", ITEMNAME_SIZE );
+ strncat(buff, (item_typ == BOOK_MINOR_MAGIC_I
+ || item_typ == BOOK_MINOR_MAGIC_II
+ || item_typ == BOOK_MINOR_MAGIC_III) ? "Minor Magic" :
+ (item_typ == BOOK_CONJURATIONS_I
+ || item_typ == BOOK_CONJURATIONS_II) ? "Conjurations" :
+ (item_typ == BOOK_FLAMES) ? "Flames" :
+ (item_typ == BOOK_FROST) ? "Frost" :
+ (item_typ == BOOK_SUMMONINGS) ? "Summonings" :
+ (item_typ == BOOK_FIRE) ? "Fire" :
+ (item_typ == BOOK_ICE) ? "Ice" :
+ (item_typ == BOOK_SURVEYANCES) ? "Surveyances" :
+ (item_typ == BOOK_SPATIAL_TRANSLOCATIONS) ? "Spatial Translocations" :
+ (item_typ == BOOK_ENCHANTMENTS) ? "Enchantments" :
+ (item_typ == BOOK_TEMPESTS) ? "the Tempests" :
+ (item_typ == BOOK_DEATH) ? "Death" :
+ (item_typ == BOOK_HINDERANCE) ? "Hinderance" :
+ (item_typ == BOOK_CHANGES) ? "Changes" :
+ (item_typ == BOOK_TRANSFIGURATIONS) ? "Transfigurations" :
+ (item_typ == BOOK_PRACTICAL_MAGIC) ? "Practical Magic" :
+ (item_typ == BOOK_WAR_CHANTS) ? "War Chants" :
+ (item_typ == BOOK_CLOUDS) ? "Clouds" :
+ (item_typ == BOOK_HEALING) ? "Healing" :
+ (item_typ == BOOK_NECROMANCY) ? "Necromancy" :
+ (item_typ == BOOK_CALLINGS) ? "Callings" :
+ (item_typ == BOOK_CHARMS) ? "Charms" :
+ (item_typ == BOOK_DEMONOLOGY) ? "Demonology" :
+ (item_typ == BOOK_AIR) ? "Air" :
+ (item_typ == BOOK_SKY) ? "the Sky" :
+ (item_typ == BOOK_DIVINATIONS) ? "Divinations" :
+ (item_typ == BOOK_WARP) ? "the Warp" :
+ (item_typ == BOOK_ENVENOMATIONS) ? "Envenomations" :
+ (item_typ == BOOK_ANNIHILATIONS) ? "Annihilations" :
+ (item_typ == BOOK_UNLIFE) ? "Unlife" :
+ (item_typ == BOOK_CONTROL) ? "Control" :
+ (item_typ == BOOK_MUTATIONS) ? "Morphology" :
+ (item_typ == BOOK_TUKIMA) ? "Tukima" :
+ (item_typ == BOOK_GEOMANCY) ? "Geomancy" :
+ (item_typ == BOOK_EARTH) ? "the Earth" :
+ (item_typ == BOOK_WIZARDRY) ? "Wizardry" :
+ (item_typ == BOOK_POWER) ? "Power" :
+ (item_typ == BOOK_CANTRIPS) ? "Cantrips" :
+ (item_typ == BOOK_PARTY_TRICKS) ? "Party Tricks" :
+ (item_typ == BOOK_STALKING) ? "Stalking"
+ : "Bugginess",
+ ITEMNAME_SIZE );
+ }
+ break;
+
+ // compacted 15 Apr 2000 {dlb}:
+ case OBJ_STAVES:
+ if (item_not_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ strncat(buff, (item.special == 0) ? "curved" :
+ (item.special == 1) ? "glowing" :
+ (item.special == 2) ? "thick" :
+ (item.special == 3) ? "thin" :
+ (item.special == 4) ? "long" :
+ (item.special == 5) ? "twisted" :
+ (item.special == 6) ? "jeweled" :
+ (item.special == 7) ? "runed" :
+ (item.special == 8) ? "smoking" :
+ (item.special == 9) ? "gnarled" : // was "" {dlb}
+ (item.special == 10) ? "" :
+ (item.special == 11) ? "" :
+ (item.special == 12) ? "" :
+ (item.special == 13) ? "" :
+ (item.special == 14) ? "" :
+ (item.special == 15) ? "" :
+ (item.special == 16) ? "" :
+ (item.special == 17) ? "" :
+ (item.special == 18) ? "" :
+ (item.special == 19) ? "" :
+ (item.special == 20) ? "" :
+ (item.special == 21) ? "" :
+ (item.special == 22) ? "" :
+ (item.special == 23) ? "" :
+ (item.special == 24) ? "" :
+ (item.special == 25) ? "" :
+ (item.special == 26) ? "" :
+ (item.special == 27) ? "" :
+ (item.special == 28) ? "" :
+ (item.special == 29) ? "" : "buggy", ITEMNAME_SIZE);
+ strncat(buff, " ", ITEMNAME_SIZE );
+ }
+
+ strncat( buff, (item_is_rod( item ) ? "rod" : "staff"), ITEMNAME_SIZE );
+
+ if (item_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ strncat(buff, " of ", ITEMNAME_SIZE );
+
+ strncat(buff, (item_typ == STAFF_WIZARDRY) ? "wizardry" :
+ (item_typ == STAFF_POWER) ? "power" :
+ (item_typ == STAFF_FIRE) ? "fire" :
+ (item_typ == STAFF_COLD) ? "cold" :
+ (item_typ == STAFF_POISON) ? "poison" :
+ (item_typ == STAFF_ENERGY) ? "energy" :
+ (item_typ == STAFF_DEATH) ? "death" :
+ (item_typ == STAFF_CONJURATION) ? "conjuration" :
+ (item_typ == STAFF_ENCHANTMENT) ? "enchantment" :
+ (item_typ == STAFF_SMITING) ? "smiting" :
+ (item_typ == STAFF_STRIKING) ? "striking" :
+ (item_typ == STAFF_WARDING) ? "warding" :
+ (item_typ == STAFF_DISCOVERY) ? "discovery" :
+ (item_typ == STAFF_DEMONOLOGY) ? "demonology" :
+ (item_typ == STAFF_AIR) ? "air" :
+ (item_typ == STAFF_EARTH) ? "earth" :
+ (item_typ == STAFF_SUMMONING
+ || item_typ == STAFF_SPELL_SUMMONING) ? "summoning" :
+ (item_typ == STAFF_DESTRUCTION_I
+ || item_typ == STAFF_DESTRUCTION_II
+ || item_typ == STAFF_DESTRUCTION_III
+ || item_typ == STAFF_DESTRUCTION_IV) ? "destruction" :
+ (item_typ == STAFF_CHANNELING) ? "channeling"
+ : "bugginess", ITEMNAME_SIZE );
+ }
+ break;
+
+
+ // rearranged 15 Apr 2000 {dlb}:
+ case OBJ_ORBS:
+ strncpy( buff, "Orb of ", ITEMNAME_SIZE );
+ strncat( buff, (item_typ == ORB_ZOT) ? "Zot" :
+/* ******************************************************************
+ (item_typ == 1) ? "Zug" :
+ (item_typ == 2) ? "Xob" :
+ (item_typ == 3) ? "Ix" :
+ (item_typ == 4) ? "Xug" :
+ (item_typ == 5) ? "Zob" :
+ (item_typ == 6) ? "Ik" :
+ (item_typ == 7) ? "Grolp" :
+ (item_typ == 8) ? "fo brO ehT" :
+ (item_typ == 9) ? "Plob" :
+ (item_typ == 10) ? "Zuggle-Glob" :
+ (item_typ == 11) ? "Zin" :
+ (item_typ == 12) ? "Qexigok" :
+ (item_typ == 13) ? "Bujuk" :
+ (item_typ == 14) ? "Uhen Tiquritu" :
+ (item_typ == 15) ? "Idohoxom Sovuf" :
+ (item_typ == 16) ? "Voc Vocilicoso" :
+ (item_typ == 17) ? "Chanuaxydiviha" :
+ (item_typ == 18) ? "Ihexodox" :
+ (item_typ == 19) ? "Rynok Pol" :
+ (item_typ == 20) ? "Nemelex" :
+ (item_typ == 21) ? "Sif Muna" :
+ (item_typ == 22) ? "Okawaru" :
+ (item_typ == 23) ? "Kikubaaqudgha" :
+****************************************************************** */
+ "Bugginess", ITEMNAME_SIZE ); // change back to "Zot" if source of problems cannot be found {dlb}
+ break;
+
+ case OBJ_GOLD:
+ strncat(buff, "gold piece", ITEMNAME_SIZE );
+ break;
+
+ // still not implemented, yet:
+ case OBJ_GEMSTONES:
+ break;
+
+ // rearranged 15 Apr 2000 {dlb}:
+ case OBJ_CORPSES:
+ if (item_typ == CORPSE_BODY && item.special < 100)
+ strncat(buff, "rotting ", ITEMNAME_SIZE );
+
+ moname( it_plus, true, DESC_PLAIN, tmp_buff );
+
+ strncat(buff, tmp_buff, ITEMNAME_SIZE );
+ strncat(buff, " ", ITEMNAME_SIZE );
+ strncat(buff, (item_typ == CORPSE_BODY) ? "corpse" :
+ (item_typ == CORPSE_SKELETON) ? "skeleton" : "corpse bug",
+ ITEMNAME_SIZE );
+ break;
+
+ default:
+ strncat(buff, "!", ITEMNAME_SIZE );
+ } // end of switch?
+
+ // debugging output -- oops, I probably block it above ... dang! {dlb}
+ if (strlen(buff) < 3)
+ {
+ char ugug[20];
+
+ strncat(buff, "bad item (cl:", ITEMNAME_SIZE );
+ itoa(item_clas, ugug, 10);
+ strncat(buff, ugug, ITEMNAME_SIZE );
+ strncat(buff, ",ty:", ITEMNAME_SIZE );
+ itoa(item_typ, ugug, 10);
+ strncat(buff, ugug, ITEMNAME_SIZE );
+ strncat(buff, ",pl:", ITEMNAME_SIZE );
+ itoa(it_plus, ugug, 10);
+ strncat(buff, ugug, ITEMNAME_SIZE );
+ strncat(buff, ",pl2:", ITEMNAME_SIZE );
+ itoa(item_plus2, ugug, 10);
+ strncat(buff, ugug, ITEMNAME_SIZE );
+ strncat(buff, ",sp:", ITEMNAME_SIZE );
+ itoa(item.special, ugug, 10);
+ strncat(buff, ugug, ITEMNAME_SIZE );
+ strncat(buff, ",qu:", ITEMNAME_SIZE );
+ itoa(it_quant, ugug, 10);
+ strncat(buff, ugug, ITEMNAME_SIZE );
+ strncat(buff, ")", ITEMNAME_SIZE );
+ }
+
+ // hackish {dlb}
+ if (it_quant > 1
+ && item_clas != OBJ_MISSILES
+ && item_clas != OBJ_SCROLLS
+ && item_clas != OBJ_POTIONS
+ && item_clas != OBJ_MISCELLANY
+ && (item_clas != OBJ_FOOD || item_typ != FOOD_CHUNK))
+ {
+ strncat(buff, "s", ITEMNAME_SIZE );
+ }
+
+ return 1;
+} // end item_name_2()
+
+void save_id(char identy[4][50])
+{
+ char x = 0, jx = 0;
+
+ for (x = 0; x < 4; x++)
+ {
+ for (jx = 0; jx < 50; jx++)
+ {
+ identy[x][jx] = id[x][jx];
+ }
+ }
+} // end save_id()
+
+void clear_ids(void)
+{
+
+ char i = 0, j = 0;
+
+ for (i = 0; i < 4; i++)
+ {
+ for (j = 0; j < 50; j++)
+ {
+ id[i][j] = ID_UNKNOWN_TYPE;
+ }
+ }
+
+} // end clear_ids()
+
+
+void set_ident_type( char cla, char ty, char setting, bool force )
+{
+ // Don't allow overwriting of known type with tried unless forced.
+ if (!force
+ && setting == ID_TRIED_TYPE
+ && get_ident_type( cla, ty ) == ID_KNOWN_TYPE)
+ {
+ return;
+ }
+
+ switch (cla)
+ {
+ case OBJ_WANDS:
+ id[ IDTYPE_WANDS ][ty] = setting;
+ break;
+
+ case OBJ_SCROLLS:
+ id[ IDTYPE_SCROLLS ][ty] = setting;
+ break;
+
+ case OBJ_JEWELLERY:
+ id[ IDTYPE_JEWELLERY ][ty] = setting;
+ break;
+
+ case OBJ_POTIONS:
+ id[ IDTYPE_POTIONS ][ty] = setting;
+ break;
+
+ default:
+ break;
+ }
+} // end set_ident_type()
+
+char get_ident_type(char cla, char ty)
+{
+ switch (cla)
+ {
+ case OBJ_WANDS:
+ return id[ IDTYPE_WANDS ][ty];
+
+ case OBJ_SCROLLS:
+ return id[ IDTYPE_SCROLLS ][ty];
+
+ case OBJ_JEWELLERY:
+ return id[ IDTYPE_JEWELLERY ][ty];
+
+ case OBJ_POTIONS:
+ return id[ IDTYPE_POTIONS ][ty];
+
+ default:
+ return (ID_UNKNOWN_TYPE);
+ }
+} // end get_ident_type()
+
+int property( const item_def &item, int prop_type )
+{
+ switch (item.base_type)
+ {
+ case OBJ_ARMOUR:
+ case OBJ_WEAPONS:
+ case OBJ_MISSILES:
+ return (prop[ item.base_type ][ item.sub_type ][ prop_type ]);
+
+ case OBJ_STAVES:
+ if (item_is_staff( item ))
+ return (prop[ OBJ_WEAPONS ][ WPN_QUARTERSTAFF ][ prop_type ]);
+ else if (prop_type == PWPN_SPEED) // item is rod
+ return (10); // extra protection against speed 0
+ else
+ return (0);
+
+ default:
+ return (0);
+ }
+}
+
+int mass_item( const item_def &item )
+{
+ int unit_mass = 0;
+
+ if (item.base_type == OBJ_GOLD)
+ {
+ unit_mass = 0;
+ }
+ else if (item.base_type == OBJ_CORPSES)
+ {
+ unit_mass = mons_weight( item.plus );
+
+ if (item.sub_type == CORPSE_SKELETON)
+ unit_mass /= 2;
+ }
+ else
+ {
+ unit_mass = mss[ item.base_type ][ item.sub_type ];
+ }
+
+ return (unit_mass > 0 ? unit_mass : 0);
+}
+
+void init_properties(void)
+{
+ prop[OBJ_ARMOUR][ARM_ROBE][PARM_AC] = 1;
+ prop[OBJ_ARMOUR][ARM_ROBE][PARM_EVASION] = 0;
+ mss[OBJ_ARMOUR][ARM_ROBE] = 60;
+
+ prop[OBJ_ARMOUR][ARM_LEATHER_ARMOUR][PARM_AC] = 2;
+ prop[OBJ_ARMOUR][ARM_LEATHER_ARMOUR][PARM_EVASION] = -1;
+ mss[OBJ_ARMOUR][ARM_LEATHER_ARMOUR] = 150;
+
+ prop[OBJ_ARMOUR][ARM_RING_MAIL][PARM_AC] = 4;
+ prop[OBJ_ARMOUR][ARM_RING_MAIL][PARM_EVASION] = -2;
+ mss[OBJ_ARMOUR][ARM_RING_MAIL] = 300;
+
+ prop[OBJ_ARMOUR][ARM_SCALE_MAIL][PARM_AC] = 5;
+ prop[OBJ_ARMOUR][ARM_SCALE_MAIL][PARM_EVASION] = -2;
+ mss[OBJ_ARMOUR][ARM_SCALE_MAIL] = 400;
+
+ prop[OBJ_ARMOUR][ARM_CHAIN_MAIL][PARM_AC] = 6;
+ prop[OBJ_ARMOUR][ARM_CHAIN_MAIL][PARM_EVASION] = -3;
+ mss[OBJ_ARMOUR][ARM_CHAIN_MAIL] = 450;
+
+ prop[OBJ_ARMOUR][ARM_SPLINT_MAIL][PARM_AC] = 8;
+ prop[OBJ_ARMOUR][ARM_SPLINT_MAIL][PARM_EVASION] = -5;
+ mss[OBJ_ARMOUR][ARM_SPLINT_MAIL] = 550;
+
+ prop[OBJ_ARMOUR][ARM_BANDED_MAIL][PARM_AC] = 7;
+ prop[OBJ_ARMOUR][ARM_BANDED_MAIL][PARM_EVASION] = -4;
+ mss[OBJ_ARMOUR][ARM_BANDED_MAIL] = 500;
+
+ prop[OBJ_ARMOUR][ARM_PLATE_MAIL][PARM_AC] = 9;
+ prop[OBJ_ARMOUR][ARM_PLATE_MAIL][PARM_EVASION] = -5;
+ mss[OBJ_ARMOUR][ARM_PLATE_MAIL] = 650;
+
+ prop[OBJ_ARMOUR][ARM_DRAGON_HIDE][PARM_AC] = 2;
+ prop[OBJ_ARMOUR][ARM_DRAGON_HIDE][PARM_EVASION] = -2;
+ mss[OBJ_ARMOUR][ARM_DRAGON_HIDE] = 220;
+
+ prop[OBJ_ARMOUR][ARM_TROLL_HIDE][PARM_AC] = 1;
+ prop[OBJ_ARMOUR][ARM_TROLL_HIDE][PARM_EVASION] = -1;
+ mss[OBJ_ARMOUR][ARM_TROLL_HIDE] = 180;
+
+ prop[OBJ_ARMOUR][ARM_CRYSTAL_PLATE_MAIL][PARM_AC] = 16;
+ prop[OBJ_ARMOUR][ARM_CRYSTAL_PLATE_MAIL][PARM_EVASION] = -8;
+ mss[OBJ_ARMOUR][ARM_CRYSTAL_PLATE_MAIL] = 1200;
+
+ prop[OBJ_ARMOUR][ARM_DRAGON_ARMOUR][PARM_AC] = 8;
+ prop[OBJ_ARMOUR][ARM_DRAGON_ARMOUR][PARM_EVASION] = -2;
+ mss[OBJ_ARMOUR][ARM_DRAGON_ARMOUR] = 220;
+
+ prop[OBJ_ARMOUR][ARM_TROLL_LEATHER_ARMOUR][PARM_AC] = 3;
+ prop[OBJ_ARMOUR][ARM_TROLL_LEATHER_ARMOUR][PARM_EVASION] = -1;
+ mss[OBJ_ARMOUR][ARM_TROLL_LEATHER_ARMOUR] = 180;
+
+ prop[OBJ_ARMOUR][ARM_ICE_DRAGON_HIDE][PARM_AC] = 2;
+ prop[OBJ_ARMOUR][ARM_ICE_DRAGON_HIDE][PARM_EVASION] = -2;
+ mss[OBJ_ARMOUR][ARM_ICE_DRAGON_HIDE] = 220;
+
+ prop[OBJ_ARMOUR][ARM_ICE_DRAGON_ARMOUR][PARM_AC] = 9;
+ prop[OBJ_ARMOUR][ARM_ICE_DRAGON_ARMOUR][PARM_EVASION] = -2;
+ mss[OBJ_ARMOUR][ARM_ICE_DRAGON_ARMOUR] = 220;
+
+ prop[OBJ_ARMOUR][ARM_STEAM_DRAGON_HIDE][PARM_AC] = 0;
+ prop[OBJ_ARMOUR][ARM_STEAM_DRAGON_HIDE][PARM_EVASION] = 0;
+ mss[OBJ_ARMOUR][ARM_STEAM_DRAGON_HIDE] = 120;
+
+ prop[OBJ_ARMOUR][ARM_STEAM_DRAGON_ARMOUR][PARM_AC] = 3;
+ prop[OBJ_ARMOUR][ARM_STEAM_DRAGON_ARMOUR][PARM_EVASION] = 0;
+ mss[OBJ_ARMOUR][ARM_STEAM_DRAGON_ARMOUR] = 120;
+
+ prop[OBJ_ARMOUR][ARM_MOTTLED_DRAGON_HIDE][PARM_AC] = 1;
+ prop[OBJ_ARMOUR][ARM_MOTTLED_DRAGON_HIDE][PARM_EVASION] = -1;
+ mss[OBJ_ARMOUR][ARM_MOTTLED_DRAGON_HIDE] = 150;
+
+ prop[OBJ_ARMOUR][ARM_MOTTLED_DRAGON_ARMOUR][PARM_AC] = 5;
+ prop[OBJ_ARMOUR][ARM_MOTTLED_DRAGON_ARMOUR][PARM_EVASION] = -1;
+ mss[OBJ_ARMOUR][ARM_MOTTLED_DRAGON_ARMOUR] = 150;
+
+ prop[OBJ_ARMOUR][ARM_STORM_DRAGON_HIDE][PARM_AC] = 2;
+ prop[OBJ_ARMOUR][ARM_STORM_DRAGON_HIDE][PARM_EVASION] = -5;
+ mss[OBJ_ARMOUR][ARM_STORM_DRAGON_HIDE] = 400;
+
+ prop[OBJ_ARMOUR][ARM_STORM_DRAGON_ARMOUR][PARM_AC] = 10;
+ prop[OBJ_ARMOUR][ARM_STORM_DRAGON_ARMOUR][PARM_EVASION] = -5;
+ mss[OBJ_ARMOUR][ARM_STORM_DRAGON_ARMOUR] = 400;
+
+ prop[OBJ_ARMOUR][ARM_GOLD_DRAGON_HIDE][PARM_AC] = 2;
+ prop[OBJ_ARMOUR][ARM_GOLD_DRAGON_HIDE][PARM_EVASION] = -10;
+ mss[OBJ_ARMOUR][ARM_GOLD_DRAGON_HIDE] = 1100;
+
+ prop[OBJ_ARMOUR][ARM_GOLD_DRAGON_ARMOUR][PARM_AC] = 13;
+ prop[OBJ_ARMOUR][ARM_GOLD_DRAGON_ARMOUR][PARM_EVASION] = -10;
+ mss[OBJ_ARMOUR][ARM_GOLD_DRAGON_ARMOUR] = 1100;
+
+ prop[OBJ_ARMOUR][ARM_ANIMAL_SKIN][PARM_AC] = 1;
+ prop[OBJ_ARMOUR][ARM_ANIMAL_SKIN][PARM_EVASION] = 0;
+ mss[OBJ_ARMOUR][ARM_ANIMAL_SKIN] = 100;
+
+ prop[OBJ_ARMOUR][ARM_SWAMP_DRAGON_HIDE][PARM_AC] = 1;
+ prop[OBJ_ARMOUR][ARM_SWAMP_DRAGON_HIDE][PARM_EVASION] = -2;
+ mss[OBJ_ARMOUR][ARM_SWAMP_DRAGON_HIDE] = 200;
+
+ prop[OBJ_ARMOUR][ARM_SWAMP_DRAGON_ARMOUR][PARM_AC] = 7;
+ prop[OBJ_ARMOUR][ARM_SWAMP_DRAGON_ARMOUR][PARM_EVASION] = -2;
+ mss[OBJ_ARMOUR][ARM_SWAMP_DRAGON_ARMOUR] = 200;
+
+ prop[OBJ_ARMOUR][ARM_SHIELD][PARM_AC] = 0;
+ prop[OBJ_ARMOUR][ARM_SHIELD][PARM_EVASION] = 0;
+ mss[OBJ_ARMOUR][ARM_SHIELD] = 100;
+
+ prop[OBJ_ARMOUR][ARM_CLOAK][PARM_AC] = 1;
+ prop[OBJ_ARMOUR][ARM_CLOAK][PARM_EVASION] = 0;
+ mss[OBJ_ARMOUR][ARM_CLOAK] = 20;
+
+ prop[OBJ_ARMOUR][ARM_HELMET][PARM_AC] = 1;
+ prop[OBJ_ARMOUR][ARM_HELMET][PARM_EVASION] = 0;
+ mss[OBJ_ARMOUR][ARM_HELMET] = 80;
+
+ prop[OBJ_ARMOUR][ARM_GLOVES][PARM_AC] = 1;
+ prop[OBJ_ARMOUR][ARM_GLOVES][PARM_EVASION] = 0;
+ mss[OBJ_ARMOUR][ARM_GLOVES] = 20;
+
+ prop[OBJ_ARMOUR][ARM_BOOTS][PARM_AC] = 1;
+ prop[OBJ_ARMOUR][ARM_BOOTS][PARM_EVASION] = 0;
+ mss[OBJ_ARMOUR][ARM_BOOTS] = 40;
+
+ prop[OBJ_ARMOUR][ARM_BUCKLER][PARM_AC] = 0;
+ prop[OBJ_ARMOUR][ARM_BUCKLER][PARM_EVASION] = 0;
+ mss[OBJ_ARMOUR][ARM_BUCKLER] = 50;
+
+ prop[OBJ_ARMOUR][ARM_LARGE_SHIELD][PARM_AC] = 0;
+ prop[OBJ_ARMOUR][ARM_LARGE_SHIELD][PARM_EVASION] = 0;
+ mss[OBJ_ARMOUR][ARM_LARGE_SHIELD] = 250;
+
+ int i = 0;
+
+ for (i = 0; i < 50; i++)
+ {
+ mss[OBJ_WANDS][i] = 100;
+ mss[OBJ_FOOD][i] = 100;
+ mss[OBJ_UNKNOWN_I][i] = 200; // labeled as "books" elsewhere
+
+ //jmf: made scrolls, jewellery and potions weigh less.
+ mss[OBJ_SCROLLS][i] = 20;
+ mss[OBJ_JEWELLERY][i] = 10;
+ mss[OBJ_POTIONS][i] = 40;
+ mss[OBJ_UNKNOWN_II][i] = 5; // "gems"
+ mss[OBJ_BOOKS][i] = 70;
+
+ mss[OBJ_STAVES][i] = 130;
+ mss[OBJ_ORBS][i] = 300;
+ mss[OBJ_MISCELLANY][i] = 100;
+ mss[OBJ_CORPSES][i] = 100;
+ }
+
+ // rods are lighter than staves
+ for (i = STAFF_SMITING; i < STAFF_AIR; i++)
+ {
+ mss[OBJ_STAVES][i] = 70;
+ }
+
+ // this is food, right?
+ mss[OBJ_FOOD][FOOD_MEAT_RATION] = 80;
+ mss[OBJ_FOOD][FOOD_BREAD_RATION] = 80;
+ mss[OBJ_FOOD][FOOD_PEAR] = 20;
+ mss[OBJ_FOOD][FOOD_APPLE] = 20;
+ mss[OBJ_FOOD][FOOD_CHOKO] = 30;
+ mss[OBJ_FOOD][FOOD_HONEYCOMB] = 40;
+ mss[OBJ_FOOD][FOOD_ROYAL_JELLY] = 55;
+ mss[OBJ_FOOD][FOOD_SNOZZCUMBER] = 50;
+ mss[OBJ_FOOD][FOOD_PIZZA] = 40;
+ mss[OBJ_FOOD][FOOD_APRICOT] = 15;
+ mss[OBJ_FOOD][FOOD_ORANGE] = 20;
+ mss[OBJ_FOOD][FOOD_BANANA] = 20;
+ mss[OBJ_FOOD][FOOD_STRAWBERRY] = 5;
+ mss[OBJ_FOOD][FOOD_RAMBUTAN] = 10;
+ mss[OBJ_FOOD][FOOD_LEMON] = 20;
+ mss[OBJ_FOOD][FOOD_GRAPE] = 5;
+ mss[OBJ_FOOD][FOOD_SULTANA] = 3;
+ mss[OBJ_FOOD][FOOD_LYCHEE] = 10;
+ mss[OBJ_FOOD][FOOD_BEEF_JERKY] = 20;
+ mss[OBJ_FOOD][FOOD_CHEESE] = 40;
+ mss[OBJ_FOOD][FOOD_SAUSAGE] = 40;
+ mss[OBJ_FOOD][FOOD_CHUNK] = 100;
+ /* mss [OBJ_FOOD] [21] = 40;
+ mss [OBJ_FOOD] [22] = 50;
+ mss [OBJ_FOOD] [23] = 60;
+ mss [OBJ_FOOD] [24] = 60;
+ mss [OBJ_FOOD] [25] = 100; */
+
+ mss[OBJ_MISCELLANY][MISC_BOTTLED_EFREET] = 250;
+
+ mss[OBJ_MISCELLANY][MISC_CRYSTAL_BALL_OF_SEEING] = 200;
+ mss[OBJ_MISCELLANY][MISC_CRYSTAL_BALL_OF_ENERGY] = 200;
+ mss[OBJ_MISCELLANY][MISC_CRYSTAL_BALL_OF_FIXATION] = 200;
+
+ // weapons: blunt weapons are first to help grouping them together
+ // note: AC prop can't be 0 or less because of division.
+ // If it's 1, makes no difference
+
+ // NOTE: I have *removed* AC bit for weapons - just doesn't work
+ // prop [x] [2] is speed
+
+ prop[OBJ_WEAPONS][WPN_CLUB][PWPN_DAMAGE] = 5;
+ prop[OBJ_WEAPONS][WPN_CLUB][PWPN_HIT] = 4; // helps to get past evasion
+ prop[OBJ_WEAPONS][WPN_CLUB][PWPN_SPEED] = 12;
+ mss[OBJ_WEAPONS][WPN_CLUB] = 50;
+
+ prop[OBJ_WEAPONS][WPN_MACE][PWPN_DAMAGE] = 8;
+ prop[OBJ_WEAPONS][WPN_MACE][PWPN_HIT] = 3; // helps to get past evasion
+ prop[OBJ_WEAPONS][WPN_MACE][PWPN_SPEED] = 14;
+ mss[OBJ_WEAPONS][WPN_MACE] = 140;
+
+ prop[OBJ_WEAPONS][WPN_GREAT_MACE][PWPN_DAMAGE] = 16;
+ prop[OBJ_WEAPONS][WPN_GREAT_MACE][PWPN_HIT] = -3;
+ prop[OBJ_WEAPONS][WPN_GREAT_MACE][PWPN_SPEED] = 18;
+ mss[OBJ_WEAPONS][WPN_GREAT_MACE] = 260;
+
+ prop[OBJ_WEAPONS][WPN_FLAIL][PWPN_DAMAGE] = 9;
+ prop[OBJ_WEAPONS][WPN_FLAIL][PWPN_HIT] = 2; // helps to get past evasion
+ prop[OBJ_WEAPONS][WPN_FLAIL][PWPN_SPEED] = 15;
+ mss[OBJ_WEAPONS][WPN_FLAIL] = 150;
+
+ prop[OBJ_WEAPONS][WPN_SPIKED_FLAIL][PWPN_DAMAGE] = 12;
+ prop[OBJ_WEAPONS][WPN_SPIKED_FLAIL][PWPN_HIT] = 1;
+ prop[OBJ_WEAPONS][WPN_SPIKED_FLAIL][PWPN_SPEED] = 16;
+ mss[OBJ_WEAPONS][WPN_SPIKED_FLAIL] = 170;
+
+ prop[OBJ_WEAPONS][WPN_GREAT_FLAIL][PWPN_DAMAGE] = 17;
+ prop[OBJ_WEAPONS][WPN_GREAT_FLAIL][PWPN_HIT] = -4;
+ prop[OBJ_WEAPONS][WPN_GREAT_FLAIL][PWPN_SPEED] = 19;
+ mss[OBJ_WEAPONS][WPN_GREAT_FLAIL] = 300;
+
+ prop[OBJ_WEAPONS][WPN_DAGGER][PWPN_DAMAGE] = 3;
+ prop[OBJ_WEAPONS][WPN_DAGGER][PWPN_HIT] = 6; // helps to get past evasion
+ prop[OBJ_WEAPONS][WPN_DAGGER][PWPN_SPEED] = 11;
+ mss[OBJ_WEAPONS][WPN_DAGGER] = 20;
+
+ prop[OBJ_WEAPONS][WPN_KNIFE][PWPN_DAMAGE] = 2;
+ prop[OBJ_WEAPONS][WPN_KNIFE][PWPN_HIT] = 0; // helps to get past evasion
+ prop[OBJ_WEAPONS][WPN_KNIFE][PWPN_SPEED] = 11;
+ mss[OBJ_WEAPONS][WPN_KNIFE] = 10;
+
+ prop[OBJ_WEAPONS][WPN_MORNINGSTAR][PWPN_DAMAGE] = 10;
+ prop[OBJ_WEAPONS][WPN_MORNINGSTAR][PWPN_HIT] = 2;
+ prop[OBJ_WEAPONS][WPN_MORNINGSTAR][PWPN_SPEED] = 15;
+ mss[OBJ_WEAPONS][WPN_MORNINGSTAR] = 150;
+
+ prop[OBJ_WEAPONS][WPN_SHORT_SWORD][PWPN_DAMAGE] = 6;
+ prop[OBJ_WEAPONS][WPN_SHORT_SWORD][PWPN_HIT] = 5;
+ prop[OBJ_WEAPONS][WPN_SHORT_SWORD][PWPN_SPEED] = 12;
+ mss[OBJ_WEAPONS][WPN_SHORT_SWORD] = 100;
+
+ prop[OBJ_WEAPONS][WPN_LONG_SWORD][PWPN_DAMAGE] = 10;
+ prop[OBJ_WEAPONS][WPN_LONG_SWORD][PWPN_HIT] = 3;
+ prop[OBJ_WEAPONS][WPN_LONG_SWORD][PWPN_SPEED] = 14;
+ mss[OBJ_WEAPONS][WPN_LONG_SWORD] = 160;
+
+ prop[OBJ_WEAPONS][WPN_GREAT_SWORD][PWPN_DAMAGE] = 16;
+ prop[OBJ_WEAPONS][WPN_GREAT_SWORD][PWPN_HIT] = -1;
+ prop[OBJ_WEAPONS][WPN_GREAT_SWORD][PWPN_SPEED] = 17;
+ mss[OBJ_WEAPONS][WPN_GREAT_SWORD] = 250;
+
+ prop[OBJ_WEAPONS][WPN_FALCHION][PWPN_DAMAGE] = 8;
+ prop[OBJ_WEAPONS][WPN_FALCHION][PWPN_HIT] = 2;
+ prop[OBJ_WEAPONS][WPN_FALCHION][PWPN_SPEED] = 13;
+ mss[OBJ_WEAPONS][WPN_FALCHION] = 130;
+
+ prop[OBJ_WEAPONS][WPN_SCIMITAR][PWPN_DAMAGE] = 11;
+ prop[OBJ_WEAPONS][WPN_SCIMITAR][PWPN_HIT] = 1;
+ prop[OBJ_WEAPONS][WPN_SCIMITAR][PWPN_SPEED] = 14;
+ mss[OBJ_WEAPONS][WPN_SCIMITAR] = 170;
+
+ prop[OBJ_WEAPONS][WPN_HAND_AXE][PWPN_DAMAGE] = 7;
+ prop[OBJ_WEAPONS][WPN_HAND_AXE][PWPN_HIT] = 2;
+ prop[OBJ_WEAPONS][WPN_HAND_AXE][PWPN_SPEED] = 13;
+ mss[OBJ_WEAPONS][WPN_HAND_AXE] = 110;
+
+ prop[OBJ_WEAPONS][WPN_WAR_AXE][PWPN_DAMAGE] = 11;
+ prop[OBJ_WEAPONS][WPN_WAR_AXE][PWPN_HIT] = 0;
+ prop[OBJ_WEAPONS][WPN_WAR_AXE][PWPN_SPEED] = 16;
+ mss[OBJ_WEAPONS][WPN_WAR_AXE] = 150;
+
+ prop[OBJ_WEAPONS][WPN_BROAD_AXE][PWPN_DAMAGE] = 14;
+ prop[OBJ_WEAPONS][WPN_BROAD_AXE][PWPN_HIT] = 1;
+ prop[OBJ_WEAPONS][WPN_BROAD_AXE][PWPN_SPEED] = 17;
+ mss[OBJ_WEAPONS][WPN_BROAD_AXE] = 180;
+
+ prop[OBJ_WEAPONS][WPN_BATTLEAXE][PWPN_DAMAGE] = 17;
+ prop[OBJ_WEAPONS][WPN_BATTLEAXE][PWPN_HIT] = -2;
+ prop[OBJ_WEAPONS][WPN_BATTLEAXE][PWPN_SPEED] = 18;
+ mss[OBJ_WEAPONS][WPN_BATTLEAXE] = 200;
+
+ prop[OBJ_WEAPONS][WPN_SPEAR][PWPN_DAMAGE] = 5;
+ prop[OBJ_WEAPONS][WPN_SPEAR][PWPN_HIT] = 3;
+ prop[OBJ_WEAPONS][WPN_SPEAR][PWPN_SPEED] = 13;
+ mss[OBJ_WEAPONS][WPN_SPEAR] = 50;
+
+ prop[OBJ_WEAPONS][WPN_TRIDENT][PWPN_DAMAGE] = 9;
+ prop[OBJ_WEAPONS][WPN_TRIDENT][PWPN_HIT] = -2;
+ prop[OBJ_WEAPONS][WPN_TRIDENT][PWPN_SPEED] = 17;
+ mss[OBJ_WEAPONS][WPN_TRIDENT] = 160;
+
+ prop[OBJ_WEAPONS][WPN_DEMON_TRIDENT][PWPN_DAMAGE] = 15;
+ prop[OBJ_WEAPONS][WPN_DEMON_TRIDENT][PWPN_HIT] = -2;
+ prop[OBJ_WEAPONS][WPN_DEMON_TRIDENT][PWPN_SPEED] = 17;
+ mss[OBJ_WEAPONS][WPN_DEMON_TRIDENT] = 160;
+
+ prop[OBJ_WEAPONS][WPN_HALBERD][PWPN_DAMAGE] = 13;
+ prop[OBJ_WEAPONS][WPN_HALBERD][PWPN_HIT] = -3;
+ prop[OBJ_WEAPONS][WPN_HALBERD][PWPN_SPEED] = 19;
+ mss[OBJ_WEAPONS][WPN_HALBERD] = 200;
+
+ // sling
+ // - the three properties are _not_ irrelevant here
+ // - when something hits something else (either may be you)
+ // in melee, these are used.
+ prop[OBJ_WEAPONS][WPN_SLING][PWPN_DAMAGE] = 1;
+ prop[OBJ_WEAPONS][WPN_SLING][PWPN_HIT] = -1;
+ prop[OBJ_WEAPONS][WPN_SLING][PWPN_SPEED] = 11;
+ mss[OBJ_WEAPONS][WPN_SLING] = 10;
+
+ prop[OBJ_WEAPONS][WPN_BOW][PWPN_DAMAGE] = 2;
+ prop[OBJ_WEAPONS][WPN_BOW][PWPN_HIT] = -3; // helps to get past evasion
+ prop[OBJ_WEAPONS][WPN_BOW][PWPN_SPEED] = 11;
+ mss[OBJ_WEAPONS][WPN_BOW] = 100;
+
+ prop[OBJ_WEAPONS][WPN_BLOWGUN][PWPN_DAMAGE] = 1;
+ prop[OBJ_WEAPONS][WPN_BLOWGUN][PWPN_HIT] = 0; // helps to get past evasion
+ prop[OBJ_WEAPONS][WPN_BLOWGUN][PWPN_SPEED] = 10;
+ mss[OBJ_WEAPONS][WPN_BLOWGUN] = 50;
+
+ prop[OBJ_WEAPONS][WPN_CROSSBOW][PWPN_DAMAGE] = 2;
+ prop[OBJ_WEAPONS][WPN_CROSSBOW][PWPN_HIT] = -1;
+ prop[OBJ_WEAPONS][WPN_CROSSBOW][PWPN_SPEED] = 15;
+ mss[OBJ_WEAPONS][WPN_CROSSBOW] = 250;
+
+ prop[OBJ_WEAPONS][WPN_HAND_CROSSBOW][PWPN_DAMAGE] = 1;
+ prop[OBJ_WEAPONS][WPN_HAND_CROSSBOW][PWPN_HIT] = -1;
+ prop[OBJ_WEAPONS][WPN_HAND_CROSSBOW][PWPN_SPEED] = 15;
+ mss[OBJ_WEAPONS][WPN_HAND_CROSSBOW] = 70;
+
+ prop[OBJ_WEAPONS][WPN_GLAIVE][PWPN_DAMAGE] = 15;
+ prop[OBJ_WEAPONS][WPN_GLAIVE][PWPN_HIT] = -3;
+ prop[OBJ_WEAPONS][WPN_GLAIVE][PWPN_SPEED] = 18;
+ mss[OBJ_WEAPONS][WPN_GLAIVE] = 200;
+
+ // staff - hmmm
+ prop[OBJ_WEAPONS][WPN_QUARTERSTAFF][PWPN_DAMAGE] = 7;
+ prop[OBJ_WEAPONS][WPN_QUARTERSTAFF][PWPN_HIT] = 6;
+ prop[OBJ_WEAPONS][WPN_QUARTERSTAFF][PWPN_SPEED] = 12;
+ mss[OBJ_WEAPONS][WPN_QUARTERSTAFF] = 130;
+
+ prop[OBJ_WEAPONS][WPN_SCYTHE][PWPN_DAMAGE] = 14;
+ prop[OBJ_WEAPONS][WPN_SCYTHE][PWPN_HIT] = -4;
+ prop[OBJ_WEAPONS][WPN_SCYTHE][PWPN_SPEED] = 22;
+ mss[OBJ_WEAPONS][WPN_SCYTHE] = 230;
+
+ // these two should have the same speed because of 2-h ogres.
+ prop[OBJ_WEAPONS][WPN_GIANT_CLUB][PWPN_DAMAGE] = 15;
+ prop[OBJ_WEAPONS][WPN_GIANT_CLUB][PWPN_HIT] = -5;
+ prop[OBJ_WEAPONS][WPN_GIANT_CLUB][PWPN_SPEED] = 16;
+ mss[OBJ_WEAPONS][WPN_GIANT_CLUB] = 750;
+
+ prop[OBJ_WEAPONS][WPN_GIANT_SPIKED_CLUB][PWPN_DAMAGE] = 18;
+ prop[OBJ_WEAPONS][WPN_GIANT_SPIKED_CLUB][PWPN_HIT] = -6;
+ prop[OBJ_WEAPONS][WPN_GIANT_SPIKED_CLUB][PWPN_SPEED] = 17;
+ mss[OBJ_WEAPONS][WPN_GIANT_SPIKED_CLUB] = 850;
+ // these two should have the same speed because of 2-h ogres.
+
+ prop[OBJ_WEAPONS][WPN_EVENINGSTAR][PWPN_DAMAGE] = 12;
+ prop[OBJ_WEAPONS][WPN_EVENINGSTAR][PWPN_HIT] = 2;
+ prop[OBJ_WEAPONS][WPN_EVENINGSTAR][PWPN_SPEED] = 15;
+ mss[OBJ_WEAPONS][WPN_EVENINGSTAR] = 150;
+
+ prop[OBJ_WEAPONS][WPN_QUICK_BLADE][PWPN_DAMAGE] = 5;
+ prop[OBJ_WEAPONS][WPN_QUICK_BLADE][PWPN_HIT] = 6;
+ prop[OBJ_WEAPONS][WPN_QUICK_BLADE][PWPN_SPEED] = 7;
+ mss[OBJ_WEAPONS][WPN_QUICK_BLADE] = 100;
+
+ prop[OBJ_WEAPONS][WPN_KATANA][PWPN_DAMAGE] = 13;
+ prop[OBJ_WEAPONS][WPN_KATANA][PWPN_HIT] = 4;
+ prop[OBJ_WEAPONS][WPN_KATANA][PWPN_SPEED] = 13;
+ mss[OBJ_WEAPONS][WPN_KATANA] = 160;
+
+ prop[OBJ_WEAPONS][WPN_EXECUTIONERS_AXE][PWPN_DAMAGE] = 20;
+ prop[OBJ_WEAPONS][WPN_EXECUTIONERS_AXE][PWPN_HIT] = -4;
+ prop[OBJ_WEAPONS][WPN_EXECUTIONERS_AXE][PWPN_SPEED] = 20;
+ mss[OBJ_WEAPONS][WPN_EXECUTIONERS_AXE] = 320;
+
+ prop[OBJ_WEAPONS][WPN_DOUBLE_SWORD][PWPN_DAMAGE] = 15;
+ prop[OBJ_WEAPONS][WPN_DOUBLE_SWORD][PWPN_HIT] = 3;
+ prop[OBJ_WEAPONS][WPN_DOUBLE_SWORD][PWPN_SPEED] = 16;
+ mss[OBJ_WEAPONS][WPN_DOUBLE_SWORD] = 220;
+
+ prop[OBJ_WEAPONS][WPN_TRIPLE_SWORD][PWPN_DAMAGE] = 19;
+ prop[OBJ_WEAPONS][WPN_TRIPLE_SWORD][PWPN_HIT] = -1;
+ prop[OBJ_WEAPONS][WPN_TRIPLE_SWORD][PWPN_SPEED] = 19;
+ mss[OBJ_WEAPONS][WPN_TRIPLE_SWORD] = 300;
+
+ prop[OBJ_WEAPONS][WPN_HAMMER][PWPN_DAMAGE] = 7;
+ prop[OBJ_WEAPONS][WPN_HAMMER][PWPN_HIT] = 2;
+ prop[OBJ_WEAPONS][WPN_HAMMER][PWPN_SPEED] = 13;
+ mss[OBJ_WEAPONS][WPN_HAMMER] = 130;
+
+ prop[OBJ_WEAPONS][WPN_ANCUS][PWPN_DAMAGE] = 9;
+ prop[OBJ_WEAPONS][WPN_ANCUS][PWPN_HIT] = 1;
+ prop[OBJ_WEAPONS][WPN_ANCUS][PWPN_SPEED] = 14;
+ mss[OBJ_WEAPONS][WPN_ANCUS] = 160;
+
+ prop[OBJ_WEAPONS][WPN_WHIP][PWPN_DAMAGE] = 3;
+ prop[OBJ_WEAPONS][WPN_WHIP][PWPN_HIT] = 1; // helps to get past evasion
+ prop[OBJ_WEAPONS][WPN_WHIP][PWPN_SPEED] = 14;
+ mss[OBJ_WEAPONS][WPN_WHIP] = 30;
+
+ prop[OBJ_WEAPONS][WPN_SABRE][PWPN_DAMAGE] = 7;
+ prop[OBJ_WEAPONS][WPN_SABRE][PWPN_HIT] = 4;
+ prop[OBJ_WEAPONS][WPN_SABRE][PWPN_SPEED] = 12;
+ mss[OBJ_WEAPONS][WPN_SABRE] = 110;
+
+ prop[OBJ_WEAPONS][WPN_DEMON_BLADE][PWPN_DAMAGE] = 13;
+ prop[OBJ_WEAPONS][WPN_DEMON_BLADE][PWPN_HIT] = 2;
+ prop[OBJ_WEAPONS][WPN_DEMON_BLADE][PWPN_SPEED] = 15;
+ mss[OBJ_WEAPONS][WPN_DEMON_BLADE] = 200;
+
+ prop[OBJ_WEAPONS][WPN_DEMON_WHIP][PWPN_DAMAGE] = 10;
+ prop[OBJ_WEAPONS][WPN_DEMON_WHIP][PWPN_HIT] = 1;
+ prop[OBJ_WEAPONS][WPN_DEMON_WHIP][PWPN_SPEED] = 14;
+ mss[OBJ_WEAPONS][WPN_DEMON_WHIP] = 30;
+
+
+ // MISSILES:
+
+ prop[OBJ_MISSILES][MI_STONE][PWPN_DAMAGE] = 2;
+ prop[OBJ_MISSILES][MI_STONE][PWPN_HIT] = 4;
+ mss[OBJ_MISSILES][MI_STONE] = 5;
+
+ prop[OBJ_MISSILES][MI_ARROW][PWPN_DAMAGE] = 2;
+ prop[OBJ_MISSILES][MI_ARROW][PWPN_HIT] = 6;
+ mss[OBJ_MISSILES][MI_ARROW] = 10;
+
+ prop[OBJ_MISSILES][MI_NEEDLE][PWPN_DAMAGE] = 0;
+ prop[OBJ_MISSILES][MI_NEEDLE][PWPN_HIT] = 1;
+ mss[OBJ_MISSILES][MI_NEEDLE] = 1;
+
+ prop[OBJ_MISSILES][MI_BOLT][PWPN_DAMAGE] = 2;
+ prop[OBJ_MISSILES][MI_BOLT][PWPN_HIT] = 8;
+ mss[OBJ_MISSILES][MI_BOLT] = 12;
+
+ prop[OBJ_MISSILES][MI_DART][PWPN_DAMAGE] = 2;
+ prop[OBJ_MISSILES][MI_DART][PWPN_HIT] = 4; //whatever - for hand crossbow
+ mss[OBJ_MISSILES][MI_DART] = 5;
+
+ // large rock
+ prop[OBJ_MISSILES][MI_LARGE_ROCK][PWPN_DAMAGE] = 20;
+ prop[OBJ_MISSILES][MI_LARGE_ROCK][PWPN_HIT] = 10;
+ mss[OBJ_MISSILES][MI_LARGE_ROCK] = 1000;
+}
+
+
+unsigned char check_item_knowledge(void)
+{
+ char st_pass[ITEMNAME_SIZE] = "";
+ int i, j;
+ char lines = 0;
+ unsigned char anything = 0;
+ int ft = 0;
+ int max = 0;
+ int yps = 0;
+ int inv_count = 0;
+ unsigned char ki = 0;
+
+ const int num_lines = get_number_of_lines();
+
+#ifdef DOS_TERM
+ char buffer[2400];
+
+ gettext(35, 1, 80, 25, buffer);
+#endif
+
+#ifdef DOS_TERM
+ window(35, 1, 80, 25);
+#endif
+
+ clrscr();
+
+ for (i = 0; i < 4; i++)
+ {
+ for (j = 0; j < 30; j++)
+ {
+ if (id[i][j] == ID_KNOWN_TYPE)
+ inv_count++;
+ }
+ }
+
+ if (inv_count == 0)
+ {
+ cprintf("You don't recognise anything yet!");
+ if (getch() == 0)
+ getch();
+ goto putty;
+ }
+
+ textcolor(BLUE);
+ cprintf(" You recognise:");
+ textcolor(LIGHTGREY);
+ lines++;
+
+ for (i = 0; i < 4; i++)
+ {
+ switch (i)
+ {
+ case IDTYPE_WANDS:
+ ft = OBJ_WANDS;
+ max = NUM_WANDS;
+ break;
+ case IDTYPE_SCROLLS:
+ ft = OBJ_SCROLLS;
+ max = NUM_SCROLLS;
+ break;
+ case IDTYPE_JEWELLERY:
+ ft = OBJ_JEWELLERY;
+ max = NUM_JEWELLERY;
+ break;
+ case IDTYPE_POTIONS:
+ ft = OBJ_POTIONS;
+ max = NUM_POTIONS;
+ break;
+ }
+
+ for (j = 0; j < max; j++)
+ {
+ if (lines > num_lines - 2 && inv_count > 0)
+ {
+ gotoxy(1, num_lines);
+ cprintf("-more-");
+
+ ki = getch();
+
+ if (ki == ESCAPE)
+ {
+#ifdef DOS_TERM
+ puttext(35, 1, 80, 25, buffer);
+#endif
+ return ESCAPE;
+ }
+ if (ki >= 'A' && ki <= 'z')
+ {
+#ifdef DOS_TERM
+ puttext(35, 1, 80, 25, buffer);
+#endif
+ return ki;
+ }
+
+ if (ki == 0)
+ ki = getch();
+
+ lines = 0;
+ clrscr();
+ gotoxy(1, 1);
+ anything = 0;
+ }
+
+ int ident_level = get_ident_type( ft, j );
+
+ if (ident_level == ID_KNOWN_TYPE)
+ {
+ anything++;
+
+ if (lines > 0)
+ cprintf(EOL);
+ lines++;
+ cprintf(" ");
+
+ yps = wherey();
+
+ // item_name now requires a "real" item, so we'll create a tmp
+ item_def tmp = { ft, j, 0, 0, 0, 1, 0, 0, 0, 0, 0 };
+ item_name( tmp, DESC_PLAIN, st_pass );
+
+ cprintf(st_pass);
+
+ inv_count--;
+
+ if (wherey() != yps)
+ lines++;
+ }
+ } // end of j loop
+ }
+
+ if (anything > 0)
+ {
+ ki = getch();
+ //ki = getch();
+ //ki = anything;
+
+ if (ki >= 'A' && ki <= 'z')
+ {
+#ifdef DOS_TERM
+ puttext(35, 1, 80, 25, buffer);
+#endif
+ return ki;
+ }
+
+ if (ki == 0)
+ ki = getch();
+#ifdef DOS_TERM
+ puttext(35, 1, 80, 25, buffer);
+#endif
+ return anything;
+ }
+
+ putty:
+#ifdef DOS_TERM
+ puttext(35, 1, 80, 25, buffer);
+#endif
+
+ return ki;
+} // end check_item_knowledge()
+
+
+// must be certain that you are passing the subtype
+// to an OBJ_ARMOUR and nothing else, or as they say,
+// "Bad Things Will Happen" {dlb}:
+bool hide2armour( unsigned char *which_subtype )
+{
+ switch (*which_subtype)
+ {
+ case ARM_DRAGON_HIDE:
+ *which_subtype = ARM_DRAGON_ARMOUR;
+ return true;
+ case ARM_TROLL_HIDE:
+ *which_subtype = ARM_TROLL_LEATHER_ARMOUR;
+ return true;
+ case ARM_ICE_DRAGON_HIDE:
+ *which_subtype = ARM_ICE_DRAGON_ARMOUR;
+ return true;
+ case ARM_MOTTLED_DRAGON_HIDE:
+ *which_subtype = ARM_MOTTLED_DRAGON_ARMOUR;
+ return true;
+ case ARM_STORM_DRAGON_HIDE:
+ *which_subtype = ARM_STORM_DRAGON_ARMOUR;
+ return true;
+ case ARM_GOLD_DRAGON_HIDE:
+ *which_subtype = ARM_GOLD_DRAGON_ARMOUR;
+ return true;
+ case ARM_SWAMP_DRAGON_HIDE:
+ *which_subtype = ARM_SWAMP_DRAGON_ARMOUR;
+ return true;
+ case ARM_STEAM_DRAGON_HIDE:
+ *which_subtype = ARM_STEAM_DRAGON_ARMOUR;
+ return true;
+ default:
+ return false;
+ }
+} // end hide2armour()
+
+
+void make_name(unsigned char var1, unsigned char var2, unsigned char var3,
+ char ncase, char buff[ITEMNAME_SIZE])
+{
+ char name[ ITEMNAME_SIZE ] = "";
+ FixedVector < unsigned char, 15 > numb;
+ char len;
+ char i = 0;
+ char nexty = 0;
+ char j = 0;
+ char igo = 0;
+
+ int x = 0;
+
+ numb[0] = var1 * var2;
+ numb[1] = var1 * var3;
+ numb[2] = var2 * var3;
+ numb[3] = var1 * var2 * var3;
+ numb[4] = var1 + var2;
+ numb[5] = var2 + var3;
+ numb[6] = var1 * var2 + var3;
+ numb[7] = var1 * var3 + var2;
+ numb[8] = var2 * var3 + var1;
+ numb[9] = var1 * var2 * var3 - var1;
+ numb[10] = var1 + var2 + var2;
+ numb[11] = var2 + var3 * var1;
+ numb[12] = var1 * var2 * var3;
+ numb[13] = var1 * var3 * var1;
+ numb[14] = var2 * var3 * var3;
+
+ for (i = 0; i < 15; i++)
+ {
+ while (numb[i] >= 25)
+ {
+ numb[i] -= 25;
+ }
+ }
+
+ j = numb[6];
+
+ len = reduce(numb[reduce(numb[11]) / 2]);
+
+ while (len < 5 && j < 10)
+ {
+ len += 1 + reduce(1 + numb[j]);
+ j++;
+ }
+
+ while (len > 14)
+ {
+ len -= 8;
+ }
+
+ nexty = retbit(numb[4]);
+
+ char k = 0;
+
+ j = 0;
+
+ for (i = 0; i < len; i++)
+ {
+ j++;
+
+ if (j >= 15)
+ {
+ j = 0;
+
+ k++;
+
+ if (k > 9)
+ break;
+ }
+
+ if (nexty == 1 || (i > 0 && !is_random_name_vowel(name[i])))
+ {
+ name[i] = retvow(numb[j]);
+ if ((i == 0 || i == len - 1) && name[i] == 32)
+ {
+ i--;
+ continue;
+ }
+ }
+ else
+ {
+ if (numb[i / 2] <= 1 && i > 3 && is_random_name_vowel(name[i]))
+ goto two_letter;
+ else
+ name[i] = numb[j];
+
+ hello:
+ igo++;
+ }
+
+ if ((nexty == 0 && is_random_name_vowel(name[i]))
+ || (nexty == 1 && !is_random_name_vowel(name[i])))
+ {
+ if (nexty == 1 && i > 0 && !is_random_name_vowel(name[i - 1]))
+ i--;
+
+ i--;
+ continue;
+ }
+
+ if (!is_random_name_vowel(name[i]))
+ nexty = 1;
+ else
+ nexty = 0;
+
+ x++;
+ }
+
+ switch (ncase)
+ {
+ case 2:
+ for (i = 0; i < len + 1; i++)
+ {
+ if (i > 3 && name[i] == 0 && name[i + 1] == 0)
+ {
+ name[i] = 0;
+ if (name[i - 1] == 32)
+ name[i - 1] = 0;
+ break;
+ }
+ if (name[i] != 32 && name[i] < 30)
+ name[i] += 65;
+ if (name[i] > 96)
+ name[i] -= 32;
+ }
+ break;
+
+ case 3:
+ for (i = 0; i < len + 0; i++)
+ {
+ if (i != 0 && name[i] >= 65 && name[i] < 97)
+ {
+ if (name[i - 1] == 32)
+ name[i] += 32;
+ }
+
+ if (name[i] > 97)
+ {
+ if (i == 0 || name[i - 1] == 32)
+ name[i] -= 32;
+ }
+
+ if (name[i] < 30)
+ {
+ if (i == 0 || (name[i] != 32 && name[i - 1] == 32))
+ name[i] += 65;
+ else
+ name[i] += 97;
+ }
+ }
+ break;
+
+ case 0:
+ for (i = 0; i < len; i++)
+ {
+ if (name[i] != 32 && name[i] < 30)
+ name[i] += 97;
+ }
+ break;
+
+ case 1:
+ name[i] += 65;
+
+ for (i = 1; i < len; i++)
+ {
+ if (name[i] != 32 && name[i] < 30)
+ name[i] += 97; //97;
+ }
+ break;
+ }
+
+ if (strlen( name ) == 0)
+ strncpy( buff, "Plog", 80 );
+ else
+ strncpy( buff, name, 80 );
+
+ buff[79] = '\0';
+ return;
+
+ two_letter:
+ if (nexty == 1)
+ goto hello;
+
+ if (!is_random_name_vowel(name[i - 1]))
+ goto hello;
+
+ i++;
+
+ switch (i * (retbit(j) + 1))
+ {
+ case 0:
+ strcat(name, "sh");
+ break;
+ case 1:
+ strcat(name, "ch");
+ break;
+ case 2:
+ strcat(name, "tz");
+ break;
+ case 3:
+ strcat(name, "ts");
+ break;
+ case 4:
+ strcat(name, "cs");
+ break;
+ case 5:
+ strcat(name, "cz");
+ break;
+ case 6:
+ strcat(name, "xt");
+ break;
+ case 7:
+ strcat(name, "xk");
+ break;
+ case 8:
+ strcat(name, "kl");
+ break;
+ case 9:
+ strcat(name, "cl");
+ break;
+ case 10:
+ strcat(name, "fr");
+ break;
+ case 11:
+ strcat(name, "sh");
+ break;
+ case 12:
+ strcat(name, "ch");
+ break;
+ case 13:
+ strcat(name, "gh");
+ break;
+ case 14:
+ strcat(name, "pr");
+ break;
+ case 15:
+ strcat(name, "tr");
+ break;
+ case 16:
+ strcat(name, "mn");
+ break;
+ case 17:
+ strcat(name, "ph");
+ break;
+ case 18:
+ strcat(name, "pn");
+ break;
+ case 19:
+ strcat(name, "cv");
+ break;
+ case 20:
+ strcat(name, "zx");
+ break;
+ case 21:
+ strcat(name, "xz");
+ break;
+ case 23:
+ strcat(name, "dd");
+ break;
+ case 24:
+ strcat(name, "tt");
+ break;
+ case 25:
+ strcat(name, "ll");
+ break;
+ //case 26: strcat(name, "sh"); break;
+ //case 12: strcat(name, "sh"); break;
+ //case 13: strcat(name, "sh"); break;
+ default:
+ i--;
+ goto hello;
+ }
+
+ x += 2;
+
+ goto hello;
+} // end make_name()
+
+
+char reduce(unsigned char reducee)
+{
+ while (reducee >= 26)
+ {
+ reducee -= 26;
+ }
+
+ return reducee;
+} // end reduce()
+
+bool is_random_name_vowel(unsigned char let)
+{
+ return (let == 0 || let == 4 || let == 8 || let == 14 || let == 20
+ || let == 24 || let == 32);
+} // end is_random_name_vowel()
+
+char retvow(char sed)
+{
+
+ while (sed > 6)
+ sed -= 6;
+
+ switch (sed)
+ {
+ case 0:
+ return 0;
+ case 1:
+ return 4;
+ case 2:
+ return 8;
+ case 3:
+ return 14;
+ case 4:
+ return 20;
+ case 5:
+ return 24;
+ case 6:
+ return 32;
+ }
+
+ return 0;
+} // end retvow()
+
+char retbit(char sed)
+{
+ return (sed % 2);
+} // end retbit()
diff --git a/trunk/source/itemname.h b/trunk/source/itemname.h
new file mode 100644
index 0000000000..63a606440d
--- /dev/null
+++ b/trunk/source/itemname.h
@@ -0,0 +1,156 @@
+/*
+ * File: itemname.cc
+ * Summary: Misc functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef ITEMNAME_H
+#define ITEMNAME_H
+
+#include "externs.h"
+
+bool is_vowel( const char chr );
+
+/* ***********************************************************************
+ * called from: describe - effects - item_use - shopping
+ * *********************************************************************** */
+char get_ident_type(char cla, char ty);
+
+
+/* ***********************************************************************
+ * called from: acr - chardump - direct - effects - fight - invent -
+ * it_use2 - item_use - items - monstuff - mstuff2 - ouch -
+ * shopping - spells1 - spells2 - spells3
+ * *********************************************************************** */
+char item_name( const item_def &item, char descrip, char buff[ITEMNAME_SIZE],
+ bool terse = false );
+
+
+/* ***********************************************************************
+ * called from: beam - describe - fight - item_use - items - monstuff -
+ * player
+ * *********************************************************************** */
+int mass_item( const item_def &item );
+
+
+/* ***********************************************************************
+ * called from: debug - describe - dungeon - fight - files - item_use -
+ * monstuff - mstuff2 - players - spells0
+ * *********************************************************************** */
+int property( const item_def &item, int prop_type );
+
+
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+unsigned char check_item_knowledge(void);
+
+
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void clear_ids(void);
+
+
+/* ***********************************************************************
+ * called from: direct - fight - food - items - monstuff - religion -
+ * shopping
+ * *********************************************************************** */
+void it_name(int itn, char des, char buff[ITEMNAME_SIZE], bool terse = false);
+
+/* ***********************************************************************
+ * called from: acr - chardump - command - effects - fight - invent -
+ * it_use2 - it_use3 - item_use - items - ouch - output -
+ * spell - spells1 - spells2 - spells3 - spells4 - transfor
+ * *********************************************************************** */
+void in_name(int inn, char des, char buff[ITEMNAME_SIZE], bool terse = false);
+
+/* ***********************************************************************
+ * called from: itemname.cc items.cc item_use.cc mstuff2.cc
+ * *********************************************************************** */
+void quant_name( const item_def &item, int quant, char des,
+ char buff[ITEMNAME_SIZE], bool terse = false );
+
+/* ***********************************************************************
+ * bit operations called from a large number of files
+ * *********************************************************************** */
+bool item_cursed( const item_def &item );
+bool item_uncursed( const item_def &item );
+
+bool item_known_cursed( const item_def &item );
+bool item_known_uncursed( const item_def &item );
+// bool fully_indentified( const item_def &item );
+
+bool item_ident( const item_def &item, unsigned long flags );
+bool item_not_ident( const item_def &item, unsigned long flags );
+
+void do_curse_item( item_def &item );
+void do_uncurse_item( item_def &item );
+
+void set_ident_flags( item_def &item, unsigned long flags );
+void unset_ident_flags( item_def &item, unsigned long flags );
+
+void set_equip_race( item_def &item, unsigned long flags );
+void set_equip_desc( item_def &item, unsigned long flags );
+
+unsigned long get_equip_race( const item_def &item );
+unsigned long get_equip_desc( const item_def &item );
+
+bool cmp_equip_race( const item_def &item, unsigned long val );
+bool cmp_equip_desc( const item_def &item, unsigned long val );
+
+void set_helmet_type( item_def &item, short flags );
+void set_helmet_desc( item_def &item, short flags );
+void set_helmet_random_desc( item_def &item );
+
+short get_helmet_type( const item_def &item );
+short get_helmet_desc( const item_def &item );
+
+bool cmp_helmet_type( const item_def &item, short val );
+bool cmp_helmet_desc( const item_def &item, short val );
+
+bool set_item_ego_type( item_def &item, int item_type, int ego_type );
+
+int get_weapon_brand( const item_def &item );
+int get_ammo_brand( const item_def &item );
+int get_armour_ego_type( const item_def &item );
+
+bool item_is_rod( const item_def &item );
+bool item_is_staff( const item_def &item );
+
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void init_properties(void);
+
+/* ***********************************************************************
+ * called from: files - randart - shopping
+ * *********************************************************************** */
+void make_name( unsigned char var1, unsigned char var2, unsigned char var3,
+ char ncase, char buff[ITEMNAME_SIZE] );
+
+
+/* ***********************************************************************
+ * called from: files - shopping
+ * *********************************************************************** */
+void save_id(char identy[4][50]);
+
+
+/* ***********************************************************************
+ * called from: files - item_use - newgame - ouch - shopping - spells1
+ * *********************************************************************** */
+void set_ident_type( char cla, char ty, char setting, bool force = false );
+
+
+/* ***********************************************************************
+ * called from: dungeon - item_use
+ * *********************************************************************** */
+bool hide2armour( unsigned char *which_subtype );
+
+
+#endif
diff --git a/trunk/source/items.cc b/trunk/source/items.cc
new file mode 100644
index 0000000000..30bd65a8cb
--- /dev/null
+++ b/trunk/source/items.cc
@@ -0,0 +1,2551 @@
+/*
+ * File: items.cc
+ * Summary: Misc (mostly) inventory related functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <9> 7/08/01 MV Added messages for chunks/corpses rotting
+ * <8> 8/07/99 BWR Added Rune stacking
+ * <7> 6/13/99 BWR Added auto staff detection
+ * <6> 6/12/99 BWR Fixed time system.
+ * <5> 6/9/99 DML Autopickup
+ * <4> 5/26/99 JDJ Drop will attempt to take off armour.
+ * <3> 5/21/99 BWR Upped armour skill learning slightly.
+ * <2> 5/20/99 BWR Added assurance that against inventory count being wrong.
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "items.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#include "externs.h"
+
+#include "beam.h"
+#include "cloud.h"
+#include "debug.h"
+#include "delay.h"
+#include "effects.h"
+#include "invent.h"
+#include "it_use2.h"
+#include "item_use.h"
+#include "itemname.h"
+#include "misc.h"
+#include "monplace.h"
+#include "monstuff.h"
+#include "mstuff2.h"
+#include "mon-util.h"
+#include "mutation.h"
+#include "player.h"
+#include "randart.h"
+#include "religion.h"
+#include "shopping.h"
+#include "skills.h"
+#include "spl-cast.h"
+#include "stuff.h"
+
+static void autopickup(void);
+
+// Used to be called "unlink_items", but all it really does is make
+// sure item coordinates are correct to the stack they're in. -- bwr
+void fix_item_coordinates(void)
+{
+ int x,y,i;
+
+ // nails all items to the ground (i.e. sets x,y)
+ for (x = 0; x < GXM; x++)
+ {
+ for (y = 0; y < GYM; y++)
+ {
+ i = igrd[x][y];
+
+ while (i != NON_ITEM)
+ {
+ mitm[i].x = x;
+ mitm[i].y = y;
+ i = mitm[i].link;
+ }
+ }
+ }
+}
+
+// This function uses the items coordinates to relink all the igrd lists.
+void link_items(void)
+{
+ int i,j;
+
+ // first, initailize igrd array
+ for (i = 0; i < GXM; i++)
+ {
+ for (j = 0; j < GYM; j++)
+ igrd[i][j] = NON_ITEM;
+ }
+
+ // link all items on the grid, plus shop inventory,
+ // DON'T link the huge pile of monster items at (0,0)
+
+ for (i = 0; i < MAX_ITEMS; i++)
+ {
+ if (!is_valid_item(mitm[i]) || (mitm[i].x == 0 && mitm[i].y == 0))
+ {
+ // item is not assigned, or is monster item. ignore.
+ mitm[i].link = NON_ITEM;
+ continue;
+ }
+
+ // link to top
+ mitm[i].link = igrd[ mitm[i].x ][ mitm[i].y ];
+ igrd[ mitm[i].x ][ mitm[i].y ] = i;
+ }
+} // end link_items()
+
+static bool item_ok_to_clean(int item)
+{
+ // 5. never clean food or Orbs
+ if (mitm[item].base_type == OBJ_FOOD || mitm[item].base_type == OBJ_ORBS)
+ return false;
+
+ // never clean runes
+ if (mitm[item].base_type == OBJ_MISCELLANY
+ && mitm[item].sub_type == MISC_RUNE_OF_ZOT)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// returns index number of first available space, or NON_ITEM for
+// unsuccessful cleanup (should be exceedingly rare!)
+int cull_items(void)
+{
+ // XXX: Not the prettiest of messages, but the player
+ // deserves to know whenever this kicks in. -- bwr
+ mpr( "Too many items on level, removing some.", MSGCH_WARN );
+
+ /* rules:
+ 1. Don't cleanup anything nearby the player
+ 2. Don't cleanup shops
+ 3. Don't cleanup monster inventory
+ 4. Clean 15% of items
+ 5. never remove food, orbs, runes
+ 7. uniques weapons are moved to the abyss
+ 8. randarts are simply lost
+ 9. unrandarts are 'destroyed', but may be generated again
+ */
+
+ int x,y, item, next;
+ int first_cleaned = NON_ITEM;
+
+ // 2. avoid shops by avoiding (0,5..9)
+ // 3. avoid monster inventory by iterating over the dungeon grid
+ for (x = 5; x < GXM; x++)
+ {
+ for (y = 5; y < GYM; y++)
+ {
+ // 1. not near player!
+ if (x > you.x_pos - 9 && x < you.x_pos + 9
+ && y > you.y_pos - 9 && y < you.y_pos + 9)
+ {
+ continue;
+ }
+
+ // iterate through the grids list of items:
+ for (item = igrd[x][y]; item != NON_ITEM; item = next)
+ {
+ next = mitm[item].link; // in case we can't get it later.
+
+ if (item_ok_to_clean(item) && random2(100) < 15)
+ {
+ if (is_fixed_artefact( mitm[item] ))
+ {
+ // 7. move uniques to abyss
+ set_unique_item_status( OBJ_WEAPONS, mitm[item].special,
+ UNIQ_LOST_IN_ABYSS );
+ }
+ else if (is_unrandom_artefact( mitm[item] ))
+ {
+ // 9. unmark unrandart
+ int x = find_unrandart_index(item);
+ if (x >= 0)
+ set_unrandart_exist(x, 0);
+ }
+
+ // POOF!
+ destroy_item( item );
+ if (first_cleaned == NON_ITEM)
+ first_cleaned = item;
+ }
+ } // end for item
+
+ } // end y
+ } // end x
+
+ return (first_cleaned);
+}
+
+// Note: This function is to isolate all the checks to see if
+// an item is valid (often just checking the quantity).
+//
+// It shouldn't be used a a substitute for those cases
+// which actually want to check the quantity (as the
+// rules for unused objects might change).
+bool is_valid_item( const item_def &item )
+{
+ return (item.base_type != OBJ_UNASSIGNED && item.quantity > 0);
+}
+
+// Reduce quantity of an inventory item, do cleanup if item goes away.
+//
+// Returns true if stack of items no longer exists.
+bool dec_inv_item_quantity( int obj, int amount )
+{
+ bool ret = false;
+
+ if (you.equip[EQ_WEAPON] == obj)
+ you.wield_change = true;
+
+ if (you.inv[obj].quantity <= amount)
+ {
+ for (int i = 0; i < NUM_EQUIP; i++)
+ {
+ if (you.equip[i] == obj)
+ {
+ you.equip[i] = -1;
+ if (i == EQ_WEAPON)
+ {
+ unwield_item( obj );
+ canned_msg( MSG_EMPTY_HANDED );
+ }
+ }
+ }
+
+ you.inv[obj].base_type = OBJ_UNASSIGNED;
+ you.inv[obj].quantity = 0;
+
+ ret = true;
+ }
+ else
+ {
+ you.inv[obj].quantity -= amount;
+ }
+
+ burden_change();
+
+ return (ret);
+}
+
+// Reduce quantity of a monster/grid item, do cleanup if item goes away.
+//
+// Returns true if stack of items no longer exists.
+bool dec_mitm_item_quantity( int obj, int amount )
+{
+ if (mitm[obj].quantity <= amount)
+ {
+ destroy_item( obj );
+ return (true);
+ }
+
+ mitm[obj].quantity -= amount;
+
+ return (false);
+}
+
+void inc_inv_item_quantity( int obj, int amount )
+{
+ if (you.equip[EQ_WEAPON] == obj)
+ you.wield_change = true;
+
+ you.inv[obj].quantity += amount;
+ burden_change();
+}
+
+void inc_mitm_item_quantity( int obj, int amount )
+{
+ mitm[obj].quantity += amount;
+}
+
+void init_item( int item )
+{
+ if (item == NON_ITEM)
+ return;
+
+ mitm[item].base_type = OBJ_UNASSIGNED;
+ mitm[item].sub_type = 0;
+ mitm[item].plus = 0;
+ mitm[item].plus2 = 0;
+ mitm[item].special = 0;
+ mitm[item].quantity = 0;
+ mitm[item].colour = 0;
+ mitm[item].flags = 0;
+
+ mitm[item].x = 0;
+ mitm[item].y = 0;
+ mitm[item].link = NON_ITEM;
+}
+
+// Returns an unused mitm slot, or NON_ITEM if none available.
+// The reserve is the number of item slots to not check.
+// Items may be culled if a reserve <= 10 is specified.
+int get_item_slot( int reserve )
+{
+ ASSERT( reserve >= 0 );
+
+ int item = NON_ITEM;
+
+ for (item = 0; item < (MAX_ITEMS - reserve); item++)
+ {
+ if (!is_valid_item( mitm[item] ))
+ break;
+ }
+
+ if (item >= MAX_ITEMS - reserve)
+ {
+ item = (reserve <= 10) ? cull_items() : NON_ITEM;
+
+ if (item == NON_ITEM)
+ return (NON_ITEM);
+ }
+
+ ASSERT( item != NON_ITEM );
+
+ init_item( item );
+
+ return (item);
+}
+
+void unlink_item( int dest )
+{
+ int c = 0;
+ int cy = 0;
+
+ // Don't destroy non-items, may be called after an item has been
+ // reduced to zero quantity however.
+ if (dest == NON_ITEM || !is_valid_item( mitm[dest] ))
+ return;
+
+ if (mitm[dest].x == 0 && mitm[dest].y == 0)
+ {
+ // (0,0) is where the monster items are (and they're unlinked by igrd),
+ // although it also contains items that are not linked in yet.
+ //
+ // Check if a monster has it:
+ for (c = 0; c < MAX_MONSTERS; c++)
+ {
+ struct monsters *monster = &menv[c];
+
+ if (monster->type == -1)
+ continue;
+
+ for (cy = 0; cy < NUM_MONSTER_SLOTS; cy++)
+ {
+ if (monster->inv[cy] == dest)
+ {
+ monster->inv[cy] = NON_ITEM;
+
+ mitm[dest].x = 0;
+ mitm[dest].y = 0;
+ mitm[dest].link = NON_ITEM;
+
+ // This causes problems when changing levels. -- bwr
+ // if (monster->type == MONS_DANCING_WEAPON)
+ // monster_die(monster, KILL_RESET, 0);
+ return;
+ }
+ }
+ }
+
+ // Always return because this item might just be temporary.
+ return;
+ }
+ else
+ {
+ // Linked item on map:
+ //
+ // Use the items (x,y) to access the list (igrd[x][y]) where
+ // the item should be linked.
+
+ // First check the top:
+ if (igrd[ mitm[dest].x ][ mitm[dest].y ] == dest)
+ {
+ // link igrd to the second item
+ igrd[ mitm[dest].x ][ mitm[dest].y ] = mitm[dest].link;
+
+ mitm[dest].x = 0;
+ mitm[dest].y = 0;
+ mitm[dest].link = NON_ITEM;
+ return;
+ }
+
+ // Okay, item is buried, find item that's on top of it:
+ for (c = igrd[ mitm[dest].x ][ mitm[dest].y ]; c != NON_ITEM; c = mitm[c].link)
+ {
+ // find item linking to dest item
+ if (is_valid_item( mitm[c] ) && mitm[c].link == dest)
+ {
+ // unlink dest
+ mitm[c].link = mitm[dest].link;
+
+ mitm[dest].x = 0;
+ mitm[dest].y = 0;
+ mitm[dest].link = NON_ITEM;
+ return;
+ }
+ }
+ }
+
+#if DEBUG
+ // Okay, the sane ways are gone... let's warn the player:
+ mpr( "BUG WARNING: Problems unlinking item!!!", MSGCH_DANGER );
+
+ // Okay, first we scan all items to see if we have something
+ // linked to this item. We're not going to return if we find
+ // such a case... instead, since things are already out of
+ // alignment, let's assume there might be multiple links as well.
+ bool linked = false;
+ int old_link = mitm[dest].link; // used to try linking the first
+
+ // clean the relevant parts of the object:
+ mitm[dest].base_type = OBJ_UNASSIGNED;
+ mitm[dest].quantity = 0;
+ mitm[dest].x = 0;
+ mitm[dest].y = 0;
+ mitm[dest].link = NON_ITEM;
+
+ // Look through all items for links to this item.
+ for (c = 0; c < MAX_ITEMS; c++)
+ {
+ if (is_valid_item( mitm[c] ) && mitm[c].link == dest)
+ {
+ // unlink item
+ mitm[c].link = old_link;
+
+ if (!linked)
+ {
+ old_link = NON_ITEM;
+ linked = true;
+ }
+ }
+ }
+
+ // Now check the grids to see if it's linked as a list top.
+ for (c = 2; c < (GXM - 1); c++)
+ {
+ for (cy = 2; cy < (GYM - 1); cy++)
+ {
+ if (igrd[c][cy] == dest)
+ {
+ igrd[c][cy] = old_link;
+
+ if (!linked)
+ {
+ old_link = NON_ITEM; // cleaned after the first
+ linked = true;
+ }
+ }
+ }
+ }
+
+
+ // Okay, finally warn player if we didn't do anything.
+ if (!linked)
+ mpr("BUG WARNING: Item didn't seem to be linked at all.", MSGCH_DANGER);
+#endif
+} // end unlink_item()
+
+void destroy_item( int dest )
+{
+ // Don't destroy non-items, but this function may be called upon
+ // to remove items reduced to zero quantity, so we allow "invalid"
+ // objects in.
+ if (dest == NON_ITEM || !is_valid_item( mitm[dest] ))
+ return;
+
+ unlink_item( dest );
+
+ mitm[dest].base_type = OBJ_UNASSIGNED;
+ mitm[dest].quantity = 0;
+}
+
+void destroy_item_stack( int x, int y )
+{
+ int o = igrd[x][y];
+
+ igrd[x][y] = NON_ITEM;
+
+ while (o != NON_ITEM)
+ {
+ int next = mitm[o].link;
+
+ if (is_valid_item( mitm[o] ))
+ {
+ if (mitm[o].base_type == OBJ_ORBS)
+ {
+ set_unique_item_status( OBJ_ORBS, mitm[o].sub_type,
+ UNIQ_LOST_IN_ABYSS );
+ }
+ else if (is_fixed_artefact( mitm[o] ))
+ {
+ set_unique_item_status( OBJ_WEAPONS, mitm[o].special,
+ UNIQ_LOST_IN_ABYSS );
+ }
+
+ mitm[o].base_type = OBJ_UNASSIGNED;
+ mitm[o].quantity = 0;
+ }
+
+ o = next;
+ }
+}
+
+
+/*
+ * Takes keyin as an argument because it will only display a long list of items
+ * if ; is pressed.
+ */
+void item_check(char keyin)
+{
+ char item_show[50][50];
+ char temp_quant[10];
+
+ int counter = 0;
+ int counter_max = 0;
+
+ const int grid = grd[you.x_pos][you.y_pos];
+
+ if (grid >= DNGN_ENTER_HELL && grid <= DNGN_PERMADRY_FOUNTAIN)
+ {
+ if (grid >= DNGN_STONE_STAIRS_DOWN_I && grid <= DNGN_ROCK_STAIRS_DOWN)
+ {
+ snprintf( info, INFO_SIZE, "There is a %s staircase leading down here.",
+ (grid == DNGN_ROCK_STAIRS_DOWN) ? "rock" : "stone" );
+
+ mpr(info);
+ }
+ else if (grid >= DNGN_STONE_STAIRS_UP_I && grid <= DNGN_ROCK_STAIRS_UP)
+ {
+ snprintf( info, INFO_SIZE, "There is a %s staircase leading upwards here.",
+ (grid == DNGN_ROCK_STAIRS_DOWN) ? "rock" : "stone" );
+
+ mpr(info);
+ }
+ else
+ {
+ switch (grid)
+ {
+ case DNGN_ENTER_HELL:
+ mpr("There is a gateway to Hell here.");
+ break;
+ case DNGN_ENTER_GEHENNA:
+ mpr("There is a gateway to Gehenna here.");
+ break;
+ case DNGN_ENTER_COCYTUS:
+ mpr("There is a gateway to the frozen wastes of Cocytus here.");
+ break;
+ case DNGN_ENTER_TARTARUS:
+ mpr("There is a gateway to Tartarus here.");
+ break;
+ case DNGN_ENTER_DIS:
+ mpr("There is a gateway to the Iron City of Dis here.");
+ break;
+ case DNGN_ENTER_SHOP:
+ snprintf( info, INFO_SIZE, "There is an entrance to %s here.", shop_name(you.x_pos, you.y_pos));
+ mpr(info);
+ break;
+ case DNGN_ENTER_LABYRINTH:
+ mpr("There is an entrance to a labyrinth here.");
+ mpr("Beware, for starvation awaits!");
+ break;
+ case DNGN_ENTER_ABYSS:
+ mpr("There is a one-way gate to the infinite horrors of the Abyss here.");
+ break;
+ case DNGN_STONE_ARCH:
+ mpr("There is an empty stone archway here.");
+ break;
+ case DNGN_EXIT_ABYSS:
+ mpr("There is a gateway leading out of the Abyss here.");
+ break;
+ case DNGN_ENTER_PANDEMONIUM:
+ mpr("There is a gate leading to the halls of Pandemonium here.");
+ break;
+ case DNGN_EXIT_PANDEMONIUM:
+ mpr("There is a gate leading out of Pandemonium here.");
+ break;
+ case DNGN_TRANSIT_PANDEMONIUM:
+ mpr("There is a gate leading to another region of Pandemonium here.");
+ break;
+ case DNGN_ENTER_ORCISH_MINES:
+ mpr("There is a staircase to the Orcish Mines here.");
+ break;
+ case DNGN_ENTER_HIVE:
+ mpr("There is a staircase to the Hive here.");
+ break;
+ case DNGN_ENTER_LAIR:
+ mpr("There is a staircase to the Lair here.");
+ break;
+ case DNGN_ENTER_SLIME_PITS:
+ mpr("There is a staircase to the Slime Pits here.");
+ break;
+ case DNGN_ENTER_VAULTS:
+ mpr("There is a staircase to the Vaults here.");
+ break;
+ case DNGN_ENTER_CRYPT:
+ mpr("There is a staircase to the Crypt here.");
+ break;
+ case DNGN_ENTER_HALL_OF_BLADES:
+ mpr("There is a staircase to the Hall of Blades here.");
+ break;
+ case DNGN_ENTER_ZOT:
+ mpr("There is a gate to the Realm of Zot here.");
+ break;
+ case DNGN_ENTER_TEMPLE:
+ mpr("There is a staircase to the Ecumenical Temple here.");
+ break;
+ case DNGN_ENTER_SNAKE_PIT:
+ mpr("There is a staircase to the Snake Pit here.");
+ break;
+ case DNGN_ENTER_ELVEN_HALLS:
+ mpr("There is a staircase to the Elven Halls here.");
+ break;
+ case DNGN_ENTER_TOMB:
+ mpr("There is a staircase to the Tomb here.");
+ break;
+ case DNGN_ENTER_SWAMP:
+ mpr("There is a staircase to the Swamp here.");
+ break;
+ case DNGN_RETURN_FROM_ORCISH_MINES:
+ case DNGN_RETURN_FROM_HIVE:
+ case DNGN_RETURN_FROM_LAIR:
+ case DNGN_RETURN_FROM_VAULTS:
+ case DNGN_RETURN_FROM_TEMPLE:
+ mpr("There is a staircase back to the Dungeon here.");
+ break;
+ case DNGN_RETURN_FROM_SLIME_PITS:
+ case DNGN_RETURN_FROM_SNAKE_PIT:
+ case DNGN_RETURN_FROM_SWAMP:
+ mpr("There is a staircase back to the Lair here.");
+ break;
+ case DNGN_RETURN_FROM_CRYPT:
+ case DNGN_RETURN_FROM_HALL_OF_BLADES:
+ mpr("There is a staircase back to the Vaults here.");
+ break;
+ case DNGN_RETURN_FROM_TOMB:
+ mpr("There is a staircase back to the Crypt here.");
+ break;
+ case DNGN_RETURN_FROM_ELVEN_HALLS:
+ mpr("There is a staircase back to the Mines here.");
+ break;
+ case DNGN_RETURN_FROM_ZOT:
+ mpr("There is a gate leading back out of this place here.");
+ break;
+ case DNGN_ALTAR_ZIN:
+ mpr("There is a glowing white marble altar of Zin here.");
+ break;
+ case DNGN_ALTAR_SHINING_ONE:
+ mpr("There is a glowing golden altar of the Shining One here.");
+ break;
+ case DNGN_ALTAR_KIKUBAAQUDGHA:
+ mpr("There is an ancient bone altar of Kikubaaqudgha here.");
+ break;
+ case DNGN_ALTAR_YREDELEMNUL:
+ mpr("There is a basalt altar of Yredelemnul here.");
+ break;
+ case DNGN_ALTAR_XOM:
+ mpr("There is a shimmering altar of Xom here.");
+ break;
+ case DNGN_ALTAR_VEHUMET:
+ mpr("There is a shining altar of Vehumet here.");
+ break;
+ case DNGN_ALTAR_OKAWARU:
+ mpr("There is an iron altar of Okawaru here.");
+ break;
+ case DNGN_ALTAR_MAKHLEB:
+ mpr("There is a burning altar of Makhleb here.");
+ break;
+ case DNGN_ALTAR_SIF_MUNA:
+ mpr("There is a deep blue altar of Sif Muna here.");
+ break;
+ case DNGN_ALTAR_TROG:
+ mpr("There is a bloodstained altar of Trog here.");
+ break;
+ case DNGN_ALTAR_NEMELEX_XOBEH:
+ mpr("There is a sparkling altar of Nemelex Xobeh here.");
+ break;
+ case DNGN_ALTAR_ELYVILON:
+ mpr("There is a silver altar of Elyvilon here.");
+ break;
+ case DNGN_BLUE_FOUNTAIN:
+ mpr("There is a fountain here (q to drink).");
+ break;
+ case DNGN_SPARKLING_FOUNTAIN:
+ mpr("There is a sparkling fountain here (q to drink).");
+ break;
+ case DNGN_DRY_FOUNTAIN_I:
+ case DNGN_DRY_FOUNTAIN_II:
+ case DNGN_DRY_FOUNTAIN_IV:
+ case DNGN_DRY_FOUNTAIN_VI:
+ case DNGN_DRY_FOUNTAIN_VIII:
+ case DNGN_PERMADRY_FOUNTAIN:
+ mpr("There is a dry fountain here.");
+ break;
+ }
+ }
+ }
+
+ if (igrd[you.x_pos][you.y_pos] == NON_ITEM && keyin == ';')
+ {
+ mpr("There are no items here.");
+ return;
+ }
+
+ autopickup();
+
+ int objl = igrd[you.x_pos][you.y_pos];
+
+ while (objl != NON_ITEM)
+ {
+ counter++;
+
+ if (counter > 45)
+ {
+ strcpy(item_show[counter], "Too many items.");
+ break;
+ }
+
+ if (mitm[objl].base_type == OBJ_GOLD)
+ {
+ itoa(mitm[objl].quantity, temp_quant, 10);
+ strcpy(item_show[counter], temp_quant);
+ strcat(item_show[counter], " gold piece");
+ if (mitm[objl].quantity > 1)
+ strcat(item_show[counter], "s");
+
+ }
+ else
+ {
+ char str_pass[ ITEMNAME_SIZE ];
+ it_name(objl, DESC_NOCAP_A, str_pass);
+ strcpy(item_show[counter], str_pass);
+ }
+
+ objl = mitm[objl].link;
+ }
+
+ counter_max = counter;
+ counter = 0;
+
+ if (counter_max == 1)
+ {
+ strcpy(info, "You see here "); // remember 'an'.
+
+ strcat(info, item_show[counter_max]);
+ strcat(info, ".");
+ mpr(info);
+
+ counter++;
+ counter_max = 0; // to skip next part.
+
+ }
+
+ if ((counter_max > 0 && counter_max < 6)
+ || (counter_max > 1 && keyin == ';'))
+ {
+ mpr("Things that are here:");
+
+ while (counter < counter_max)
+ {
+ // this is before the strcpy because item_show start at 1, not 0.
+ counter++;
+ mpr(item_show[counter]);
+ }
+ }
+
+ if (counter_max > 5 && keyin != ';')
+ mpr("There are several objects here.");
+}
+
+
+void pickup(void)
+{
+ int o = 0;
+ int m = 0;
+ int num = 0;
+ unsigned char keyin = 0;
+ int next;
+ char str_pass[ ITEMNAME_SIZE ];
+
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_AIR
+ && you.duration[DUR_TRANSFORMATION] > 0)
+ {
+ mpr("You can't pick up anything in this form!");
+ return;
+ }
+
+ if (player_is_levitating() && !wearing_amulet(AMU_CONTROLLED_FLIGHT))
+ {
+ mpr("You can't reach the floor from up here.");
+ return;
+ }
+
+ // Fortunately, the player is prevented from testing their
+ // portable altar in the Ecumenical Temple. -- bwr
+ if (grd[you.x_pos][you.y_pos] == DNGN_ALTAR_NEMELEX_XOBEH
+ && !player_in_branch( BRANCH_ECUMENICAL_TEMPLE ))
+ {
+ if (inv_count() >= ENDOFPACK)
+ {
+ mpr("There is a portable altar here, but you can't carry anything else.");
+ return;
+ }
+
+ if (yesno("There is a portable altar here. Pick it up?"))
+ {
+ for (m = 0; m < ENDOFPACK; m++)
+ {
+ if (!is_valid_item( you.inv[m] ))
+ {
+ you.inv[m].base_type = OBJ_MISCELLANY;
+ you.inv[m].sub_type = MISC_PORTABLE_ALTAR_OF_NEMELEX;
+ you.inv[m].plus = 0;
+ you.inv[m].plus2 = 0;
+ you.inv[m].special = 0;
+ you.inv[m].colour = LIGHTMAGENTA;
+ you.inv[m].quantity = 1;
+ set_ident_flags( you.inv[m], ISFLAG_IDENT_MASK );
+
+ you.inv[m].x = -1;
+ you.inv[m].y = -1;
+ you.inv[m].link = m;
+
+ burden_change();
+
+ in_name( m, DESC_INVENTORY_EQUIP, str_pass );
+ strcpy( info, str_pass );
+ mpr( info );
+ break;
+ }
+ }
+
+ grd[you.x_pos][you.y_pos] = DNGN_FLOOR;
+ }
+ }
+
+ o = igrd[you.x_pos][you.y_pos];
+
+ if (o == NON_ITEM)
+ {
+ mpr("There are no items here.");
+ }
+ else if (mitm[o].link == NON_ITEM) // just one item?
+ {
+ num = move_item_to_player( o, mitm[o].quantity );
+
+ if (num == -1)
+ mpr("You can't carry that many items.");
+ else if (num == 0)
+ mpr("You can't carry that much weight.");
+ } // end of if items_here
+ else
+ {
+ mpr("There are several objects here.");
+
+ while (o != NON_ITEM)
+ {
+ next = mitm[o].link;
+
+ if (keyin != 'a')
+ {
+ strcpy(info, "Pick up ");
+
+ if (mitm[o].base_type == OBJ_GOLD)
+ {
+ char st_prn[20];
+ itoa(mitm[o].quantity, st_prn, 10);
+ strcat(info, st_prn);
+ strcat(info, " gold piece");
+
+ if (mitm[o].quantity > 1)
+ strcat(info, "s");
+ }
+ else
+ {
+ it_name(o, DESC_NOCAP_A, str_pass);
+ strcat(info, str_pass);
+ }
+
+ strcat(info, "\? (y,n,a,q)");
+ mpr( info, MSGCH_PROMPT );
+
+ keyin = get_ch();
+ }
+
+ if (keyin == 'q')
+ break;
+
+ if (keyin == 'y' || keyin == 'a')
+ {
+ int result = move_item_to_player( o, mitm[o].quantity );
+
+ if (result == 0)
+ {
+ mpr("You can't carry that much weight.");
+ keyin = 'x'; // resets from 'a'
+ }
+ else if (result == -1)
+ {
+ mpr("You can't carry that many items.");
+ break;
+ }
+ }
+
+ o = next;
+ }
+ }
+} // end pickup()
+
+static bool is_stackable_item( const item_def &item )
+{
+ if (!is_valid_item( item ))
+ return (false);
+
+ if (item.base_type == OBJ_MISSILES
+ || (item.base_type == OBJ_FOOD && item.sub_type != FOOD_CHUNK)
+ || item.base_type == OBJ_SCROLLS
+ || item.base_type == OBJ_POTIONS
+ || item.base_type == OBJ_UNKNOWN_II
+ || (item.base_type == OBJ_MISCELLANY
+ && item.sub_type == MISC_RUNE_OF_ZOT))
+ {
+ return (true);
+ }
+
+ return (false);
+}
+
+bool items_stack( const item_def &item1, const item_def &item2 )
+{
+ // both items must be stackable
+ if (!is_stackable_item( item1 ) || !is_stackable_item( item2 ))
+ return (false);
+
+ // base and sub-types must always be the same to stack
+ if (item1.base_type != item2.base_type || item1.sub_type != item2.sub_type)
+ return (false);
+
+ // These classes also require pluses and special
+ if (item1.base_type == OBJ_MISSILES
+ || item1.base_type == OBJ_MISCELLANY) // only runes
+ {
+ if (item1.plus != item2.plus
+ || item1.plus2 != item2.plus2
+ || item1.special != item2.special)
+ {
+ return (false);
+ }
+ }
+
+ // Check the flags, food/scrolls/potions don't care about the item's
+ // ident status (scrolls and potions are known by identifying any
+ // one of them, the individual status might not be the same).
+ if (item1.base_type == OBJ_FOOD
+ || item1.base_type == OBJ_SCROLLS
+ || item1.base_type == OBJ_POTIONS)
+ {
+ if ((item1.flags & ~ISFLAG_IDENT_MASK)
+ != (item2.flags & ~ISFLAG_IDENT_MASK))
+ {
+ return (false);
+ }
+
+ // Thanks to mummy cursing, we can have potions of decay
+ // that don't look alike... so we don't stack potions
+ // if either isn't identified and they look different. -- bwr
+ if (item1.base_type == OBJ_POTIONS
+ && item1.special != item2.special
+ && (item_not_ident( item1, ISFLAG_KNOW_TYPE )
+ || item_not_ident( item2, ISFLAG_KNOW_TYPE )))
+ {
+ return (false);
+ }
+ }
+ else if (item1.flags != item2.flags)
+ {
+ return (false);
+ }
+
+ return (true);
+}
+
+// Returns quantity of items moved into player's inventory and -1 if
+// the player's inventory is full.
+int move_item_to_player( int obj, int quant_got, bool quiet )
+{
+ int item_mass = 0;
+ int unit_mass = 0;
+ int retval = quant_got;
+ char brek = 0;
+ bool partialPickup = false;
+
+ int m = 0;
+
+ // Gold has no mass, so we handle it first.
+ if (mitm[obj].base_type == OBJ_GOLD)
+ {
+ you.gold += quant_got;
+ dec_mitm_item_quantity( obj, quant_got );
+ you.redraw_gold = 1;
+
+ if (!quiet)
+ {
+ snprintf( info, INFO_SIZE, "You pick up %d gold piece%s.",
+ quant_got, (quant_got > 1) ? "s" : "" );
+
+ mpr(info);
+ }
+
+ you.turn_is_over = 1;
+ return (retval);
+ }
+
+ unit_mass = mass_item( mitm[obj] );
+ item_mass = unit_mass * mitm[obj].quantity;
+ quant_got = mitm[obj].quantity;
+ brek = 0;
+
+ // multiply both constants * 10
+
+ if ((int) you.burden + item_mass > carrying_capacity())
+ {
+ // calculate quantity we can actually pick up
+ int part = (carrying_capacity() - (int)you.burden) / unit_mass;
+
+ if (part < 1)
+ return (0);
+
+ // only pickup 'part' items
+ quant_got = part;
+ partialPickup = true;
+
+ retval = part;
+ }
+
+ if (is_stackable_item( mitm[obj] ))
+ {
+ for (m = 0; m < ENDOFPACK; m++)
+ {
+ if (items_stack( you.inv[m], mitm[obj] ))
+ {
+ if (!quiet && partialPickup)
+ mpr("You can only carry some of what is here.");
+
+ inc_inv_item_quantity( m, quant_got );
+ dec_mitm_item_quantity( obj, quant_got );
+ burden_change();
+
+ if (!quiet)
+ {
+ in_name( m, DESC_INVENTORY, info );
+ mpr(info);
+ }
+
+ you.turn_is_over = 1;
+
+ return (retval);
+ }
+ } // end of for m loop.
+ }
+
+ // can't combine, check for slot space
+ if (inv_count() >= ENDOFPACK)
+ return (-1);
+
+ if (!quiet && partialPickup)
+ mpr("You can only carry some of what is here.");
+
+ for (m = 0; m < ENDOFPACK; m++)
+ {
+ // find first empty slot
+ if (!is_valid_item( you.inv[m] ))
+ {
+ // copy item
+ you.inv[m] = mitm[obj];
+ you.inv[m].x = -1;
+ you.inv[m].y = -1;
+ you.inv[m].link = m;
+
+ you.inv[m].quantity = quant_got;
+ dec_mitm_item_quantity( obj, quant_got );
+ burden_change();
+
+ if (!quiet)
+ {
+ in_name( m, DESC_INVENTORY, info );
+ mpr(info);
+ }
+
+ if (you.inv[m].base_type == OBJ_ORBS
+ && you.char_direction == DIR_DESCENDING)
+ {
+ if (!quiet)
+ mpr("Now all you have to do is get back out of the dungeon!");
+ you.char_direction = DIR_ASCENDING;
+ }
+ break;
+ }
+ }
+
+ you.turn_is_over = 1;
+
+ return (retval);
+} // end move_item_to_player()
+
+
+// Moves mitm[obj] to (x,y)... will modify the value of obj to
+// be the index of the final object (possibly different).
+//
+// Done this way in the hopes that it will be obvious from
+// calling code that "obj" is possibly modified.
+void move_item_to_grid( int *const obj, int x, int y )
+{
+ // must be a valid reference to a valid object
+ if (*obj == NON_ITEM || !is_valid_item( mitm[*obj] ))
+ return;
+
+ // If it's a stackable type...
+ if (is_stackable_item( mitm[*obj] ))
+ {
+ // Look for similar item to stack:
+ for (int i = igrd[x][y]; i != NON_ITEM; i = mitm[i].link)
+ {
+ // check if item already linked here -- don't want to unlink it
+ if (*obj == i)
+ return;
+
+ if (items_stack( mitm[*obj], mitm[i] ))
+ {
+ // Add quantity to item already here, and dispose
+ // of obj, while returning the found item. -- bwr
+ inc_mitm_item_quantity( i, mitm[*obj].quantity );
+ destroy_item( *obj );
+ *obj = i;
+ return;
+ }
+ }
+ }
+
+ ASSERT( *obj != NON_ITEM );
+
+ // Need to actually move object, so first unlink from old position.
+ unlink_item( *obj );
+
+ // move item to coord:
+ mitm[*obj].x = x;
+ mitm[*obj].y = y;
+
+ // link item to top of list.
+ mitm[*obj].link = igrd[x][y];
+ igrd[x][y] = *obj;
+
+ return;
+}
+
+void move_item_stack_to_grid( int x, int y, int targ_x, int targ_y )
+{
+ // Tell all items in stack what the new coordinate is.
+ for (int o = igrd[x][y]; o != NON_ITEM; o = mitm[o].link)
+ {
+ mitm[o].x = targ_x;
+ mitm[o].y = targ_y;
+ }
+
+ igrd[targ_x][targ_y] = igrd[x][y];
+ igrd[x][y] = NON_ITEM;
+}
+
+
+// returns quantity dropped
+bool copy_item_to_grid( const item_def &item, int x_plos, int y_plos,
+ int quant_drop )
+{
+ if (quant_drop == 0)
+ return (false);
+
+ // default quant_drop == -1 => drop all
+ if (quant_drop < 0)
+ quant_drop = item.quantity;
+
+ // loop through items at current location
+ if (is_stackable_item( item ))
+ {
+ for (int i = igrd[x_plos][y_plos]; i != NON_ITEM; i = mitm[i].link)
+ {
+ if (items_stack( item, mitm[i] ))
+ {
+ inc_mitm_item_quantity( i, quant_drop );
+ return (true);
+ }
+ }
+ }
+
+ // item not found in current stack, add new item to top.
+ int new_item = get_item_slot(10);
+ if (new_item == NON_ITEM)
+ return (false);
+
+ // copy item
+ mitm[new_item] = item;
+
+ // set quantity, and set the item as unlinked
+ mitm[new_item].quantity = quant_drop;
+ mitm[new_item].x = 0;
+ mitm[new_item].y = 0;
+ mitm[new_item].link = NON_ITEM;
+
+ move_item_to_grid( &new_item, x_plos, y_plos );
+
+ return (true);
+} // end copy_item_to_grid()
+
+
+//---------------------------------------------------------------
+//
+// move_top_item -- moves the top item of a stack to a new
+// location.
+//
+//---------------------------------------------------------------
+bool move_top_item( int src_x, int src_y, int dest_x, int dest_y )
+{
+ int item = igrd[ src_x ][ src_y ];
+ if (item == NON_ITEM)
+ return (false);
+
+ // Now move the item to its new possition...
+ move_item_to_grid( &item, dest_x, dest_y );
+
+ return (true);
+}
+
+
+//---------------------------------------------------------------
+//
+// drop_gold
+//
+//---------------------------------------------------------------
+static void drop_gold(unsigned int amount)
+{
+ if (you.gold > 0)
+ {
+ if (amount > you.gold)
+ amount = you.gold;
+
+ snprintf( info, INFO_SIZE, "You drop %d gold piece%s.",
+ amount, (amount > 1) ? "s" : "" );
+ mpr(info);
+
+ // loop through items at grid location, look for gold
+ int i = igrd[you.x_pos][you.y_pos];
+
+ while(i != NON_ITEM)
+ {
+ if (mitm[i].base_type == OBJ_GOLD)
+ {
+ inc_mitm_item_quantity( i, amount );
+ you.gold -= amount;
+ you.redraw_gold = 1;
+ return;
+ }
+
+ // follow link
+ i = mitm[i].link;
+ }
+
+ // place on top.
+ i = get_item_slot(10);
+ if (i == NON_ITEM)
+ {
+ mpr( "Too many items on this level, not dropping the gold." );
+ return;
+ }
+
+ mitm[i].base_type = OBJ_GOLD;
+ mitm[i].quantity = amount;
+ mitm[i].flags = 0;
+
+ move_item_to_grid( &i, you.x_pos, you.y_pos );
+
+ you.gold -= amount;
+ you.redraw_gold = 1;
+ }
+ else
+ {
+ mpr("You don't have any money.");
+ }
+} // end drop_gold()
+
+
+//---------------------------------------------------------------
+//
+// drop
+//
+// Prompts the user for an item to drop
+//
+//---------------------------------------------------------------
+void drop(void)
+{
+ int i;
+
+ int item_dropped;
+ int quant_drop = -1;
+
+ char str_pass[ ITEMNAME_SIZE ];
+
+ if (inv_count() < 1 && you.gold == 0)
+ {
+ canned_msg(MSG_NOTHING_CARRIED);
+ return;
+ }
+
+ // XXX: Need to handle quantities:
+ item_dropped = prompt_invent_item( "Drop which item?", -1, true, true,
+ true, '$', &quant_drop );
+
+ if (item_dropped == PROMPT_ABORT || quant_drop == 0)
+ {
+ canned_msg( MSG_OK );
+ return;
+ }
+ else if (item_dropped == PROMPT_GOT_SPECIAL) // ie '$' for gold
+ {
+ // drop gold
+ if (quant_drop < 0 || quant_drop > static_cast< int >( you.gold ))
+ quant_drop = you.gold;
+
+ drop_gold( quant_drop );
+ return;
+ }
+
+ if (quant_drop < 0 || quant_drop > you.inv[item_dropped].quantity)
+ quant_drop = you.inv[item_dropped].quantity;
+
+ if (item_dropped == you.equip[EQ_LEFT_RING]
+ || item_dropped == you.equip[EQ_RIGHT_RING]
+ || item_dropped == you.equip[EQ_AMULET])
+ {
+ mpr("You will have to take that off first.");
+ return;
+ }
+
+ if (item_dropped == you.equip[EQ_WEAPON]
+ && you.inv[item_dropped].base_type == OBJ_WEAPONS
+ && item_cursed( you.inv[item_dropped] ))
+ {
+ mpr("That object is stuck to you!");
+ return;
+ }
+
+ for (i = EQ_CLOAK; i <= EQ_BODY_ARMOUR; i++)
+ {
+ if (item_dropped == you.equip[i] && you.equip[i] != -1)
+ {
+ if (!Options.easy_armour)
+ {
+ mpr("You will have to take that off first.");
+ }
+ else
+ {
+ // If we take off the item, cue up the item being dropped
+ if (takeoff_armour( item_dropped ))
+ {
+ start_delay( DELAY_DROP_ITEM, 1, item_dropped, 1 );
+ you.turn_is_over = 0; // turn happens later
+ }
+ }
+
+ // Regardless, we want to return here because either we're
+ // aborting the drop, or the drop is delayed until after
+ // the armour is removed. -- bwr
+ return;
+ }
+ }
+
+ // Unwield needs to be done before copy in order to clear things
+ // like temporary brands. -- bwr
+ if (item_dropped == you.equip[EQ_WEAPON])
+ {
+ unwield_item(item_dropped);
+ you.equip[EQ_WEAPON] = -1;
+ canned_msg( MSG_EMPTY_HANDED );
+ }
+
+ if (!copy_item_to_grid( you.inv[item_dropped],
+ you.x_pos, you.y_pos, quant_drop ))
+ {
+ mpr( "Too many items on this level, not dropping the item." );
+ return;
+ }
+
+ quant_name( you.inv[item_dropped], quant_drop, DESC_NOCAP_A, str_pass );
+ snprintf( info, INFO_SIZE, "You drop %s.", str_pass );
+ mpr(info);
+
+ dec_inv_item_quantity( item_dropped, quant_drop );
+ you.turn_is_over = 1;
+} // end drop()
+
+//---------------------------------------------------------------
+//
+// shift_monster
+//
+// Moves a monster to approximately (x,y) and returns true
+// if monster was moved.
+//
+//---------------------------------------------------------------
+static bool shift_monster( struct monsters *mon, int x, int y )
+{
+ bool found_move = false;
+
+ int i, j;
+ int tx, ty;
+ int nx = 0, ny = 0;
+
+ int count = 0;
+
+ if (x == 0 && y == 0)
+ {
+ // try and find a random floor space some distance away
+ for (i = 0; i < 50; i++)
+ {
+ tx = 5 + random2( GXM - 10 );
+ ty = 5 + random2( GYM - 10 );
+
+ int dist = grid_distance(x, y, tx, ty);
+ if (grd[tx][ty] == DNGN_FLOOR && dist > 10)
+ break;
+ }
+
+ if (i == 50)
+ return (false);
+ }
+
+ for (i = -1; i <= 1; i++)
+ {
+ for (j = -1; j <= 1; j++)
+ {
+ tx = x + i;
+ ty = y + j;
+
+ if (tx < 5 || tx > GXM - 5 || ty < 5 || ty > GXM - 5)
+ continue;
+
+ // won't drop on anything but vanilla floor right now
+ if (grd[tx][ty] != DNGN_FLOOR)
+ continue;
+
+ if (mgrd[tx][ty] != NON_MONSTER)
+ continue;
+
+ if (tx == you.x_pos && ty == you.y_pos)
+ continue;
+
+ count++;
+ if (one_chance_in(count))
+ {
+ nx = tx;
+ ny = ty;
+ found_move = true;
+ }
+ }
+ }
+
+ if (found_move)
+ {
+ const int mon_index = mgrd[mon->x][mon->y];
+ mgrd[mon->x][mon->y] = NON_MONSTER;
+ mgrd[nx][ny] = mon_index;
+ mon->x = nx;
+ mon->y = ny;
+ }
+
+ return (found_move);
+}
+
+//---------------------------------------------------------------
+//
+// update_corpses
+//
+// Update all of the corpses and food chunks on the floor. (The
+// elapsed time is a double because this is called when we re-
+// enter a level and a *long* time may have elapsed).
+//
+//---------------------------------------------------------------
+void update_corpses(double elapsedTime)
+{
+ int cx, cy;
+
+ if (elapsedTime <= 0.0)
+ return;
+
+ const long rot_time = (long) (elapsedTime / 20.0);
+
+ for (int c = 0; c < MAX_ITEMS; c++)
+ {
+ if (mitm[c].quantity < 1)
+ continue;
+
+ if (mitm[c].base_type != OBJ_CORPSES && mitm[c].base_type != OBJ_FOOD)
+ {
+ continue;
+ }
+
+ if (mitm[c].base_type == OBJ_CORPSES
+ && mitm[c].sub_type > CORPSE_SKELETON)
+ {
+ continue;
+ }
+
+ if (mitm[c].base_type == OBJ_FOOD && mitm[c].sub_type != FOOD_CHUNK)
+ {
+ continue;
+ }
+
+ if (rot_time >= mitm[c].special)
+ {
+ if (mitm[c].base_type == OBJ_FOOD)
+ {
+ destroy_item(c);
+ }
+ else
+ {
+ if (mitm[c].sub_type == CORPSE_SKELETON
+ || !mons_skeleton( mitm[c].plus ))
+ {
+ destroy_item(c);
+ }
+ else
+ {
+ mitm[c].sub_type = CORPSE_SKELETON;
+ mitm[c].special = 200;
+ mitm[c].colour = LIGHTGREY;
+ }
+ }
+ }
+ else
+ {
+ ASSERT(rot_time < 256);
+ mitm[c].special -= rot_time;
+ }
+ }
+
+
+ int fountain_checks = (int)(elapsedTime / 1000.0);
+ if (random2(1000) < (int)(elapsedTime) % 1000)
+ fountain_checks += 1;
+
+ // dry fountains may start flowing again
+ if (fountain_checks > 0)
+ {
+ for (cx=0; cx<GXM; cx++)
+ {
+ for (cy=0; cy<GYM; cy++)
+ {
+ if (grd[cx][cy] > DNGN_SPARKLING_FOUNTAIN
+ && grd[cx][cy] < DNGN_PERMADRY_FOUNTAIN)
+ {
+ for (int i=0; i<fountain_checks; i++)
+ {
+ if (one_chance_in(100))
+ {
+ if (grd[cx][cy] > DNGN_SPARKLING_FOUNTAIN)
+ grd[cx][cy]--;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static bool remove_enchant_levels( struct monsters *mon, int slot, int min,
+ int levels )
+{
+ const int new_level = mon->enchantment[slot] - levels;
+
+ if (new_level < min)
+ {
+ mons_del_ench( mon,
+ mon->enchantment[slot], mon->enchantment[slot], true );
+ return (true);
+ }
+ else
+ {
+ mon->enchantment[slot] = new_level;
+ }
+
+ return (false);
+}
+
+//---------------------------------------------------------------
+//
+// update_enchantments
+//
+// Update a monster's enchantments when the player returns
+// to the level.
+//
+// Management for enchantments... problems with this are the oddities
+// (monster dying from poison several thousands of turns later), and
+// game balance.
+//
+// Consider: Poison/Sticky Flame a monster at range and leave, monster
+// dies but can't leave level to get to player (implied game balance of
+// the delayed damage is that the monster could be a danger before
+// it dies). This could be fixed by keeping some monsters active
+// off level and allowing them to take stairs (a very serious change).
+//
+// Compare this to the current abuse where the player gets
+// effectively extended duration of these effects (although only
+// the actual effects only occur on level, the player can leave
+// and heal up without having the effect disappear).
+//
+// This is a simple compromise between the two... the enchantments
+// go away, but the effects don't happen off level. -- bwr
+//
+//---------------------------------------------------------------
+static void update_enchantments( struct monsters *mon, int levels )
+{
+ int i;
+
+ for (i = 0; i < NUM_MON_ENCHANTS; i++)
+ {
+ switch (mon->enchantment[i])
+ {
+ case ENCH_YOUR_POISON_I:
+ case ENCH_YOUR_POISON_II:
+ case ENCH_YOUR_POISON_III:
+ case ENCH_YOUR_POISON_IV:
+ remove_enchant_levels( mon, i, ENCH_YOUR_POISON_I, levels );
+ break;
+
+ case ENCH_YOUR_SHUGGOTH_I:
+ case ENCH_YOUR_SHUGGOTH_II:
+ case ENCH_YOUR_SHUGGOTH_III:
+ case ENCH_YOUR_SHUGGOTH_IV:
+ remove_enchant_levels( mon, i, ENCH_YOUR_SHUGGOTH_I, levels );
+ break;
+
+ case ENCH_YOUR_ROT_I:
+ case ENCH_YOUR_ROT_II:
+ case ENCH_YOUR_ROT_III:
+ case ENCH_YOUR_ROT_IV:
+ remove_enchant_levels( mon, i, ENCH_YOUR_ROT_I, levels );
+ break;
+
+ case ENCH_BACKLIGHT_I:
+ case ENCH_BACKLIGHT_II:
+ case ENCH_BACKLIGHT_III:
+ case ENCH_BACKLIGHT_IV:
+ remove_enchant_levels( mon, i, ENCH_BACKLIGHT_I, levels );
+ break;
+
+ case ENCH_YOUR_STICKY_FLAME_I:
+ case ENCH_YOUR_STICKY_FLAME_II:
+ case ENCH_YOUR_STICKY_FLAME_III:
+ case ENCH_YOUR_STICKY_FLAME_IV:
+ remove_enchant_levels( mon, i, ENCH_YOUR_STICKY_FLAME_I, levels );
+ break;
+
+ case ENCH_POISON_I:
+ case ENCH_POISON_II:
+ case ENCH_POISON_III:
+ case ENCH_POISON_IV:
+ remove_enchant_levels( mon, i, ENCH_POISON_I, levels );
+ break;
+
+ case ENCH_STICKY_FLAME_I:
+ case ENCH_STICKY_FLAME_II:
+ case ENCH_STICKY_FLAME_III:
+ case ENCH_STICKY_FLAME_IV:
+ remove_enchant_levels( mon, i, ENCH_STICKY_FLAME_I, levels );
+ break;
+
+ case ENCH_FRIEND_ABJ_I:
+ case ENCH_FRIEND_ABJ_II:
+ case ENCH_FRIEND_ABJ_III:
+ case ENCH_FRIEND_ABJ_IV:
+ case ENCH_FRIEND_ABJ_V:
+ case ENCH_FRIEND_ABJ_VI:
+ if (remove_enchant_levels( mon, i, ENCH_FRIEND_ABJ_I, levels ))
+ {
+ monster_die( mon, KILL_RESET, 0 );
+ }
+ break;
+
+ case ENCH_ABJ_I:
+ case ENCH_ABJ_II:
+ case ENCH_ABJ_III:
+ case ENCH_ABJ_IV:
+ case ENCH_ABJ_V:
+ case ENCH_ABJ_VI:
+ if (remove_enchant_levels( mon, i, ENCH_ABJ_I, levels ))
+ {
+ monster_die( mon, KILL_RESET, 0 );
+ }
+ break;
+
+
+ case ENCH_SHORT_LIVED:
+ monster_die( mon, KILL_RESET, 0 );
+ break;
+
+ case ENCH_TP_I:
+ case ENCH_TP_II:
+ case ENCH_TP_III:
+ case ENCH_TP_IV:
+ monster_teleport( mon, true );
+ break;
+
+ case ENCH_CONFUSION:
+ monster_blink( mon );
+ break;
+
+ case ENCH_GLOWING_SHAPESHIFTER:
+ case ENCH_SHAPESHIFTER:
+ case ENCH_CREATED_FRIENDLY:
+ case ENCH_SUBMERGED:
+ default:
+ // don't touch these
+ break;
+
+ case ENCH_SLOW:
+ case ENCH_HASTE:
+ case ENCH_FEAR:
+ case ENCH_INVIS:
+ case ENCH_CHARM:
+ case ENCH_SLEEP_WARY:
+ // delete enchantment (using function to get this done cleanly)
+ mons_del_ench(mon, mon->enchantment[i], mon->enchantment[i], true);
+ break;
+ }
+ }
+}
+
+
+//---------------------------------------------------------------
+//
+// update_level
+//
+// Update the level when the player returns to it.
+//
+//---------------------------------------------------------------
+void update_level( double elapsedTime )
+{
+ int m, i;
+ int turns = (int) (elapsedTime / 10.0);
+
+#if DEBUG_DIAGNOSTICS
+ int mons_total = 0;
+
+ snprintf( info, INFO_SIZE, "turns: %d", turns );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ update_corpses( elapsedTime );
+
+ for (m = 0; m < MAX_MONSTERS; m++)
+ {
+ struct monsters *mon = &menv[m];
+
+ if (mon->type == -1)
+ continue;
+
+#if DEBUG_DIAGNOSTICS
+ mons_total++;
+#endif
+
+ // following monsters don't get movement
+ if (mon->flags & MF_JUST_SUMMONED)
+ continue;
+
+ // XXX: Allow some spellcasting (like Healing and Teleport)? -- bwr
+ // const bool healthy = (mon->hit_points * 2 > mon->max_hit_points);
+
+ // This is the monster healing code, moved here from tag.cc:
+ if (monster_descriptor( mon->type, MDSC_REGENERATES )
+ || mon->type == MONS_PLAYER_GHOST)
+ {
+ heal_monster( mon, turns, false );
+ }
+ else
+ {
+ heal_monster( mon, (turns / 10), false );
+ }
+
+ if (turns >= 10)
+ update_enchantments( mon, turns / 10 );
+
+ // Don't move water or lava monsters around
+ if (monster_habitat( mon->type ) != DNGN_FLOOR)
+ continue;
+
+ // Let sleeping monsters lie
+ if (mon->behaviour == BEH_SLEEP)
+ continue;
+
+
+ const int range = (turns * mon->speed) / 10;
+ const int moves = (range > 50) ? 50 : range;
+
+ // const bool short_time = (range >= 5 + random2(10));
+ const bool long_time = (range >= (500 + roll_dice( 2, 500 )));
+
+ const bool ranged_attack = (mons_has_ranged_spell( mon )
+ || mons_has_ranged_attack( mon ));
+
+#if DEBUG_DIAGNOSTICS
+ // probably too annoying even for DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE,
+ "mon #%d: range %d; long %d; pos (%d,%d); targ %d(%d,%d); flags %d",
+ m, range, long_time, mon->x, mon->y,
+ mon->foe, mon->target_x, mon->target_y, mon->flags );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ if (range <= 0)
+ continue;
+
+ if (long_time
+ && (mon->behaviour == BEH_FLEE
+ || mon->behaviour == BEH_CORNERED
+ || testbits( mon->flags, MF_BATTY )
+ || ranged_attack
+ || coinflip()))
+ {
+ if (mon->behaviour != BEH_WANDER)
+ {
+ mon->behaviour = BEH_WANDER;
+ mon->foe = MHITNOT;
+ mon->target_x = 10 + random2( GXM - 10 );
+ mon->target_y = 10 + random2( GYM - 10 );
+ }
+ else
+ {
+ // monster will be sleeping after we move it
+ mon->behaviour = BEH_SLEEP;
+ }
+ }
+ else if (ranged_attack)
+ {
+ // if we're doing short time movement and the monster has a
+ // ranged attack (missile or spell), then the monster will
+ // flee to gain distance if its "too close", else it will
+ // just shift its position rather than charge the player. -- bwr
+ if (grid_distance(mon->x, mon->y, mon->target_x, mon->target_y) < 3)
+ {
+ mon->behaviour = BEH_FLEE;
+
+ // if the monster is on the target square, fleeing won't work
+ if (mon->x == mon->target_x && mon->y == mon->target_y)
+ {
+ if (you.x_pos != mon->x || you.y_pos != mon->y)
+ {
+ // flee from player's position if different
+ mon->target_x = you.x_pos;
+ mon->target_y = you.y_pos;
+ }
+ else
+ {
+ // randomize the target so we have a direction to flee
+ mon->target_x += (random2(3) - 1);
+ mon->target_y += (random2(3) - 1);
+ }
+ }
+
+#if DEBUG_DIAGNOSTICS
+ mpr( "backing off...", MSGCH_DIAGNOSTICS );
+#endif
+ }
+ else
+ {
+ shift_monster( mon, mon->x, mon->y );
+
+#if DEBUG_DIAGNOSTICS
+ snprintf(info, INFO_SIZE, "shifted to (%d,%d)", mon->x, mon->y);
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+ continue;
+ }
+ }
+
+ int pos_x = mon->x, pos_y = mon->y;
+
+ // dirt simple movement:
+ for (i = 0; i < moves; i++)
+ {
+ int mx = (pos_x > mon->target_x) ? -1 :
+ (pos_x < mon->target_x) ? 1
+ : 0;
+
+ int my = (pos_y > mon->target_y) ? -1 :
+ (pos_y < mon->target_y) ? 1
+ : 0;
+
+ if (mon->behaviour == BEH_FLEE)
+ {
+ mx *= -1;
+ my *= -1;
+ }
+
+ if (pos_x + mx < 0 || pos_x + mx >= GXM)
+ mx = 0;
+
+ if (pos_y + my < 0 || pos_y + my >= GXM)
+ my = 0;
+
+ if (mx == 0 && my == 0)
+ break;
+
+ if (grd[pos_x + mx][pos_y + my] < DNGN_FLOOR)
+ break;
+
+ pos_x += mx;
+ pos_y += my;
+ }
+
+ if (!shift_monster( mon, pos_x, pos_y ))
+ shift_monster( mon, mon->x, mon->y );
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "moved to (%d,%d)", mon->x, mon->y );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+ }
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "total monsters on level = %d", mons_total );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ for (i = 0; i < MAX_CLOUDS; i++)
+ delete_cloud( i );
+}
+
+
+//---------------------------------------------------------------
+//
+// handle_time
+//
+// Do various time related actions...
+// This function is called about every 20 turns.
+//
+//---------------------------------------------------------------
+void handle_time( long time_delta )
+{
+ int temp_rand; // probability determination {dlb}
+
+ // so as not to reduplicate f(x) calls {dlb}
+ unsigned char which_miscast = SPTYP_RANDOM;
+
+ bool summon_instead; // for branching within a single switch {dlb}
+ int which_beastie = MONS_PROGRAM_BUG; // error trapping {dlb}
+ unsigned char i; // loop variable {dlb}
+ bool new_rotting_item = false; //mv: becomes true when some new item becomes rotting
+
+ // BEGIN - Nasty things happen to people who spend too long in Hell:
+ if (player_in_hell() && coinflip())
+ {
+ temp_rand = random2(17);
+
+ mpr((temp_rand == 0) ? "\"You will not leave this place.\"" :
+ (temp_rand == 1) ? "\"Die, mortal!\"" :
+ (temp_rand == 2) ? "\"We do not forgive those who trespass against us!\"" :
+ (temp_rand == 3) ? "\"Trespassers are not welcome here!\"" :
+ (temp_rand == 4) ? "\"You do not belong in this place!\"" :
+ (temp_rand == 5) ? "\"Leave now, before it is too late!\"" :
+ (temp_rand == 6) ? "\"We have you now!\"" :
+ (temp_rand == 7) ? "You feel a terrible foreboding..." :
+ (temp_rand == 8) ? "You hear words spoken in a strange and terrible language..." :
+
+ (temp_rand == 9) ? ((you.species != SP_MUMMY)
+ ? "You smell brimstone." : "Brimstone rains from above.") :
+
+ (temp_rand == 10) ? "Something frightening happens." :
+ (temp_rand == 11) ? "You sense an ancient evil watching you..." :
+ (temp_rand == 12) ? "You feel lost and a long, long way from home..." :
+ (temp_rand == 13) ? "You suddenly feel all small and vulnerable." :
+ (temp_rand == 14) ? "A gut-wrenching scream fills the air!" :
+ (temp_rand == 15) ? "You shiver with fear." :
+ (temp_rand == 16) ? "You sense a hostile presence."
+ : "You hear diabolical laughter!", MSGCH_TALK);
+
+ temp_rand = random2(27);
+
+ if (temp_rand > 17) // 9 in 27 odds {dlb}
+ {
+ temp_rand = random2(8);
+
+ if (temp_rand > 3) // 4 in 8 odds {dlb}
+ which_miscast = SPTYP_NECROMANCY;
+ else if (temp_rand > 1) // 2 in 8 odds {dlb}
+ which_miscast = SPTYP_SUMMONING;
+ else if (temp_rand > 0) // 1 in 8 odds {dlb}
+ which_miscast = SPTYP_CONJURATION;
+ else // 1 in 8 odds {dlb}
+ which_miscast = SPTYP_ENCHANTMENT;
+
+ miscast_effect( which_miscast, 4 + random2(6), random2avg(97, 3),
+ 100, "the effects of Hell" );
+ }
+ else if (temp_rand > 7) // 10 in 27 odds {dlb}
+ {
+ // 60:40 miscast:summon split {dlb}
+ summon_instead = (random2(5) > 2);
+
+ switch (you.where_are_you)
+ {
+ case BRANCH_DIS:
+ if (summon_instead)
+ which_beastie = summon_any_demon(DEMON_GREATER);
+ else
+ which_miscast = SPTYP_EARTH;
+ break;
+ case BRANCH_GEHENNA:
+ if (summon_instead)
+ which_beastie = MONS_FIEND;
+ else
+ which_miscast = SPTYP_FIRE;
+ break;
+ case BRANCH_COCYTUS:
+ if (summon_instead)
+ which_beastie = MONS_ICE_FIEND;
+ else
+ which_miscast = SPTYP_ICE;
+ break;
+ case BRANCH_TARTARUS:
+ if (summon_instead)
+ which_beastie = MONS_SHADOW_FIEND;
+ else
+ which_miscast = SPTYP_NECROMANCY;
+ break;
+ default: // this is to silence gcc compiler warnings {dlb}
+ if (summon_instead)
+ which_beastie = MONS_FIEND;
+ else
+ which_miscast = SPTYP_NECROMANCY;
+ break;
+ }
+
+ if (summon_instead)
+ {
+ create_monster( which_beastie, 0, BEH_HOSTILE, you.x_pos,
+ you.y_pos, MHITYOU, 250 );
+ }
+ else
+ {
+ miscast_effect( which_miscast, 4 + random2(6),
+ random2avg(97, 3), 100, "the effects of Hell" );
+ }
+ }
+
+ // NB: no "else" - 8 in 27 odds that nothing happens through
+ // first chain {dlb}
+ // also note that the following is distinct from and in
+ // addition to the above chain:
+
+ // try to summon at least one and up to five random monsters {dlb}
+ if (one_chance_in(3))
+ {
+ create_monster( RANDOM_MONSTER, 0, BEH_HOSTILE,
+ you.x_pos, you.y_pos, MHITYOU, 250 );
+
+ for (i = 0; i < 4; i++)
+ {
+ if (one_chance_in(3))
+ {
+ create_monster( RANDOM_MONSTER, 0, BEH_HOSTILE,
+ you.x_pos, you.y_pos, MHITYOU, 250 );
+ }
+ }
+ }
+ }
+ // END - special Hellish things...
+
+ // Adjust the player's stats if s/he's diseased (or recovering).
+ if (!you.disease)
+ {
+ if (you.strength < you.max_strength && one_chance_in(100))
+ {
+ mpr("You feel your strength returning.", MSGCH_RECOVERY);
+ you.strength++;
+ you.redraw_strength = 1;
+ }
+
+ if (you.dex < you.max_dex && one_chance_in(100))
+ {
+ mpr("You feel your dexterity returning.", MSGCH_RECOVERY);
+ you.dex++;
+ you.redraw_dexterity = 1;
+ }
+
+ if (you.intel < you.max_intel && one_chance_in(100))
+ {
+ mpr("You feel your intelligence returning.", MSGCH_RECOVERY);
+ you.intel++;
+ you.redraw_intelligence = 1;
+ }
+ }
+ else
+ {
+ if (one_chance_in(30))
+ {
+ mpr("Your disease is taking its toll.", MSGCH_WARN);
+ lose_stat(STAT_RANDOM, 1);
+ }
+ }
+
+ // Adjust the player's stats if s/he has the deterioration mutation
+ if (you.mutation[MUT_DETERIORATION]
+ && random2(200) <= you.mutation[MUT_DETERIORATION] * 5 - 2)
+ {
+ lose_stat(STAT_RANDOM, 1);
+ }
+
+ int added_contamination = 0;
+
+ // Account for mutagenic radiation. Invis and haste will give the
+ // player about .1 points per turn, mutagenic randarts will give
+ // about 1.5 points on average, so they can corrupt the player
+ // quite quickly. Wielding one for a short battle is OK, which is
+ // as things should be. -- GDL
+ if (you.invis && random2(10) < 6)
+ added_contamination++;
+
+ if (you.haste && !you.berserker && random2(10) < 6)
+ added_contamination++;
+
+ // randarts are usually about 20x worse than running around invisible
+ // or hasted.. this seems OK.
+ added_contamination += random2(1 + scan_randarts(RAP_MUTAGENIC));
+
+ // we take off about .5 points per turn
+ if (!you.invis && !you.haste && coinflip())
+ added_contamination -= 1;
+
+ contaminate_player( added_contamination );
+
+ // only check for badness once every other turn
+ if (coinflip())
+ {
+ if (you.magic_contamination >= 5
+ /* && random2(150) <= you.magic_contamination */)
+ {
+ mpr("Your body shudders with the violent release of wild energies!", MSGCH_WARN);
+
+ // for particularly violent releases, make a little boom
+ if (you.magic_contamination > 25 && one_chance_in(3))
+ {
+ struct bolt boom;
+ boom.type = SYM_BURST;
+ boom.colour = BLACK;
+ boom.flavour = BEAM_RANDOM;
+ boom.target_x = you.x_pos;
+ boom.target_y = you.y_pos;
+ boom.damage = dice_def( 3, (you.magic_contamination / 2) );
+ boom.thrower = KILL_MISC;
+ boom.aux_source = "a magical explosion";
+ boom.beam_source = NON_MONSTER;
+ boom.isBeam = false;
+ boom.isTracer = false;
+ strcpy(boom.beam_name, "magical storm");
+
+ boom.ench_power = (you.magic_contamination * 5);
+ boom.ex_size = (you.magic_contamination / 15);
+ if (boom.ex_size > 9)
+ boom.ex_size = 9;
+
+ explosion(boom);
+ }
+
+ // we want to warp the player, not do good stuff!
+ if (one_chance_in(5))
+ mutate(100);
+ else
+ give_bad_mutation(coinflip());
+
+ // we're meaner now, what with explosions and whatnot, but
+ // we dial down the contamination a little faster if its actually
+ // mutating you. -- GDL
+ contaminate_player( -(random2(you.magic_contamination / 4) + 1) );
+ }
+ }
+
+ // Random chance to identify staff in hand based off of Spellcasting
+ // and an appropriate other spell skill... is 1/20 too fast?
+ if (you.equip[EQ_WEAPON] != -1
+ && you.inv[you.equip[EQ_WEAPON]].base_type == OBJ_STAVES
+ && item_not_ident( you.inv[you.equip[EQ_WEAPON]], ISFLAG_KNOW_TYPE )
+ && one_chance_in(20))
+ {
+ int total_skill = you.skills[SK_SPELLCASTING];
+
+ switch (you.inv[you.equip[EQ_WEAPON]].sub_type)
+ {
+ case STAFF_WIZARDRY:
+ case STAFF_ENERGY:
+ total_skill += you.skills[SK_SPELLCASTING];
+ break;
+ case STAFF_FIRE:
+ if (you.skills[SK_FIRE_MAGIC] > you.skills[SK_ICE_MAGIC])
+ total_skill += you.skills[SK_FIRE_MAGIC];
+ else
+ total_skill += you.skills[SK_ICE_MAGIC];
+ break;
+ case STAFF_COLD:
+ if (you.skills[SK_ICE_MAGIC] > you.skills[SK_FIRE_MAGIC])
+ total_skill += you.skills[SK_ICE_MAGIC];
+ else
+ total_skill += you.skills[SK_FIRE_MAGIC];
+ break;
+ case STAFF_AIR:
+ if (you.skills[SK_AIR_MAGIC] > you.skills[SK_EARTH_MAGIC])
+ total_skill += you.skills[SK_AIR_MAGIC];
+ else
+ total_skill += you.skills[SK_EARTH_MAGIC];
+ break;
+ case STAFF_EARTH:
+ if (you.skills[SK_EARTH_MAGIC] > you.skills[SK_AIR_MAGIC])
+ total_skill += you.skills[SK_EARTH_MAGIC];
+ else
+ total_skill += you.skills[SK_AIR_MAGIC];
+ break;
+ case STAFF_POISON:
+ total_skill += you.skills[SK_POISON_MAGIC];
+ break;
+ case STAFF_DEATH:
+ total_skill += you.skills[SK_NECROMANCY];
+ break;
+ case STAFF_CONJURATION:
+ total_skill += you.skills[SK_CONJURATIONS];
+ break;
+ case STAFF_ENCHANTMENT:
+ total_skill += you.skills[SK_ENCHANTMENTS];
+ break;
+ case STAFF_SUMMONING:
+ total_skill += you.skills[SK_SUMMONINGS];
+ break;
+ }
+
+ if (random2(100) < total_skill)
+ {
+ set_ident_flags( you.inv[you.equip[EQ_WEAPON]], ISFLAG_IDENT_MASK );
+
+ char str_pass[ ITEMNAME_SIZE ];
+ in_name(you.equip[EQ_WEAPON], DESC_NOCAP_A, str_pass);
+ snprintf( info, INFO_SIZE, "You are wielding %s.", str_pass );
+ mpr(info);
+ more();
+
+ you.wield_change = true;
+ }
+ }
+
+ // Check to see if an upset god wants to do something to the player
+ // jmf: moved huge thing to religion.cc
+ handle_god_time();
+
+ // If the player has the lost mutation forget portions of the map
+ if (you.mutation[MUT_LOST])
+ {
+ if (random2(100) <= you.mutation[MUT_LOST] * 5)
+ forget_map(5 + random2(you.mutation[MUT_LOST] * 10));
+ }
+
+ // Update all of the corpses and food chunks on the floor
+ update_corpses(time_delta);
+
+ // Update all of the corpses and food chunks in the player's
+ // inventory {should be moved elsewhere - dlb}
+
+
+ for (i = 0; i < ENDOFPACK; i++)
+ {
+ if (you.inv[i].quantity < 1)
+ continue;
+
+ if (you.inv[i].base_type != OBJ_CORPSES && you.inv[i].base_type != OBJ_FOOD)
+ continue;
+
+ if (you.inv[i].base_type == OBJ_CORPSES
+ && you.inv[i].sub_type > CORPSE_SKELETON)
+ {
+ continue;
+ }
+
+ if (you.inv[i].base_type == OBJ_FOOD && you.inv[i].sub_type != FOOD_CHUNK)
+ continue;
+
+ if ((time_delta / 20) >= you.inv[i].special)
+ {
+ if (you.inv[i].base_type == OBJ_FOOD)
+ {
+ if (you.equip[EQ_WEAPON] == i)
+ {
+ unwield_item(you.equip[EQ_WEAPON]);
+ you.equip[EQ_WEAPON] = -1;
+ you.wield_change = true;
+ }
+
+ mpr( "Your equipment suddenly weighs less.", MSGCH_ROTTEN_MEAT );
+ you.inv[i].quantity = 0;
+ burden_change();
+ continue;
+ }
+
+ if (you.inv[i].sub_type == CORPSE_SKELETON)
+ continue; // carried skeletons are not destroyed
+
+ if (!mons_skeleton( you.inv[i].plus ))
+ {
+ if (you.equip[EQ_WEAPON] == i)
+ {
+ unwield_item(you.equip[EQ_WEAPON]);
+ you.equip[EQ_WEAPON] = -1;
+ }
+
+ you.inv[i].quantity = 0;
+ burden_change();
+ continue;
+ }
+
+ you.inv[i].sub_type = 1;
+ you.inv[i].special = 0;
+ you.inv[i].colour = LIGHTGREY;
+ you.wield_change = true;
+ continue;
+ }
+
+ you.inv[i].special -= (time_delta / 20);
+
+ if (you.inv[i].special < 100 && (you.inv[i].special + (time_delta / 20)>=100))
+ {
+ new_rotting_item = true;
+ }
+ }
+
+ //mv: messages when chunks/corpses become rotten
+ if (new_rotting_item)
+ {
+ switch (you.species)
+ {
+ // XXX: should probably still notice?
+ case SP_MUMMY: // no smell
+ case SP_TROLL: // stupid, living in mess - doesn't care about it
+ break;
+
+ case SP_GHOUL: //likes it
+ temp_rand = random2(8);
+ mpr( ((temp_rand < 5) ? "You smell something rotten." :
+ (temp_rand == 5) ? "Smell of rotting flesh makes you more hungry." :
+ (temp_rand == 6) ? "You smell decay. Yum-yum."
+ : "Wow! There is something tasty in your inventory."),
+ MSGCH_ROTTEN_MEAT );
+ break;
+
+ case SP_KOBOLD: //mv: IMO these race aren't so "touchy"
+ case SP_OGRE:
+ case SP_MINOTAUR:
+ case SP_HILL_ORC:
+ temp_rand = random2(8);
+ mpr( ((temp_rand < 5) ? "You smell something rotten." :
+ (temp_rand == 5) ? "You smell rotting flesh." :
+ (temp_rand == 6) ? "You smell decay."
+ : "There is something rotten in your inventory."),
+ MSGCH_ROTTEN_MEAT );
+ break;
+
+ default:
+ temp_rand = random2(8);
+ mpr( ((temp_rand < 5) ? "You smell something rotten." :
+ (temp_rand == 5) ? "Smell of rotting flesh makes you sick." :
+ (temp_rand == 6) ? "You smell decay. Yuk..."
+ : "Ugh! There is something really disgusting in your inventory."),
+ MSGCH_ROTTEN_MEAT );
+ break;
+ }
+ }
+
+ // exercise armour *xor* stealth skill: {dlb}
+ if (!player_light_armour())
+ {
+ if (random2(1000) <= mass_item( you.inv[you.equip[EQ_BODY_ARMOUR]] ))
+ {
+ return;
+ }
+
+ if (one_chance_in(6)) // lowered random roll from 7 to 6 -- bwross
+ exercise(SK_ARMOUR, 1);
+ }
+ else // exercise stealth skill:
+ {
+ if (you.burden_state != BS_UNENCUMBERED || you.berserker)
+ return;
+
+ if (you.special_wield == SPWLD_SHADOW)
+ return;
+
+ if (you.equip[EQ_BODY_ARMOUR] != -1
+ && random2( mass_item( you.inv[you.equip[EQ_BODY_ARMOUR]] )) >= 100)
+ {
+ return;
+ }
+
+ if (one_chance_in(18))
+ exercise(SK_STEALTH, 1);
+ }
+
+ return;
+} // end handle_time()
+
+int autopickup_on = 1;
+
+static void autopickup(void)
+{
+ //David Loewenstern 6/99
+ int result, o, next;
+ bool did_pickup = false;
+
+ if (autopickup_on == 0 || Options.autopickups == 0L)
+ return;
+
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_AIR
+ && you.duration[DUR_TRANSFORMATION] > 0)
+ {
+ return;
+ }
+
+ if (player_is_levitating() && !wearing_amulet(AMU_CONTROLLED_FLIGHT))
+ return;
+
+ o = igrd[you.x_pos][you.y_pos];
+
+ while (o != NON_ITEM)
+ {
+ next = mitm[o].link;
+
+ if (Options.autopickups & (1L << mitm[o].base_type))
+ {
+ result = move_item_to_player( o, mitm[o].quantity);
+
+ if (result == 0)
+ {
+ mpr("You can't carry any more.");
+ break;
+ }
+ else if (result == -1)
+ {
+ mpr("Your pack is full.");
+ break;
+ }
+
+ did_pickup = true;
+ }
+
+ o = next;
+ }
+
+ // move_item_to_player should leave things linked. -- bwr
+ // relink_cell(you.x_pos, you.y_pos);
+
+ if (did_pickup)
+ {
+ you.turn_is_over = 1;
+ start_delay( DELAY_AUTOPICKUP, 1 );
+ }
+ }
+
+int inv_count(void)
+{
+ int count=0;
+
+ for(int i=0; i< ENDOFPACK; i++)
+ {
+ if (is_valid_item( you.inv[i] ))
+ count += 1;
+ }
+
+ return count;
+}
+
+#ifdef ALLOW_DESTROY_ITEM_COMMAND
+// Started with code from AX-crawl, although its modified to fix some
+// serious problems. -- bwr
+//
+// Issues to watch for here:
+// - no destroying things from the ground since that includes corpses
+// which might be animated by monsters (butchering takes a few turns).
+// This code provides a quicker way to get rid of a corpse, but
+// the player has to be able to lift it first... something that was
+// a valid preventative method before (although this allow the player
+// to get rid of the mass on the next action).
+//
+// - artefacts can be destroyed
+//
+// - equipment cannot be destroyed... not only is this the more accurate
+// than testing for curse status (to prevent easy removal of cursed items),
+// but the original code would leave all the equiped items properties
+// (including weight) which would cause a bit of a mess to state.
+//
+// - no item does anything for just carrying it... if that changes then
+// this code will have to deal with that.
+//
+// - Do we want the player to be able to remove items from the game?
+// This would make things considerably easier to keep weapons (esp
+// those of distortion) from falling into the hands of monsters.
+// Right now the player has to carry them to a safe area, or otherwise
+// ingeniously dispose of them... do we care about this gameplay aspect?
+//
+// - Prompt for number to destroy?
+//
+void cmd_destroy_item( void )
+{
+ int i;
+ char str_pass[ ITEMNAME_SIZE ];
+
+ // ask the item to destroy
+ int item = prompt_invent_item( "Destroy which item? ", -1, true, false );
+ if (item == PROMPT_ABORT)
+ return;
+
+ // Used to check for cursed... but that's not the real problem -- bwr
+ for (i = 0; i < NUM_EQUIP; i++)
+ {
+ if (you.equip[i] == item)
+ {
+ mesclr( true );
+ mpr( "You cannot destroy equipped items!" );
+ return;
+ }
+ }
+
+ // ask confirmation
+ // quant_name(you.inv[item], you.inv[item].quantity, DESC_NOCAP_A, str_pass );
+ item_name( you.inv[item], DESC_NOCAP_THE, str_pass );
+ snprintf( info, INFO_SIZE, "Destroy %s? ", str_pass );
+
+ if (yesno( info, true ))
+ {
+ //destroy it!!
+ snprintf( info, INFO_SIZE, "You destroy %s.", str_pass );
+ mpr( info );
+ dec_inv_item_quantity( item, you.inv[item].quantity );
+ burden_change();
+ }
+}
+#endif
diff --git a/trunk/source/items.h b/trunk/source/items.h
new file mode 100644
index 0000000000..10b1ee27c9
--- /dev/null
+++ b/trunk/source/items.h
@@ -0,0 +1,125 @@
+/*
+ * File: items.cc
+ * Summary: Misc (mostly) inventory related functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <2> 6/9/99 DML Autopickup
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef ITEMS_H
+#define ITEMS_H
+
+#include "externs.h"
+
+// used in acr.cc {dlb}:
+extern int autopickup_on;
+
+// used in initfile.cc {dlb}:
+extern long autopickups;
+
+bool is_valid_item( const item_def &item );
+
+bool dec_inv_item_quantity( int obj, int amount );
+bool dec_mitm_item_quantity( int obj, int amount );
+
+void inc_inv_item_quantity( int obj, int amount );
+void inc_mitm_item_quantity( int obj, int amount );
+
+void move_item_to_grid( int *const obj, int x, int y );
+void move_item_stack_to_grid( int x, int y, int targ_x, int targ_y );
+int move_item_to_player( int obj, int quant_got, bool quiet = false );
+bool items_stack( const item_def &item1, const item_def &item2 );
+
+void init_item( int item );
+
+// last updated 13mar2001 {gdl}
+/* ***********************************************************************
+ * called from: dungeon files
+ * *********************************************************************** */
+void link_items(void);
+
+// last updated 13mar2001 {gdl}
+/* ***********************************************************************
+ * called from: files
+ * *********************************************************************** */
+void fix_item_coordinates(void);
+
+// last updated: 19apr2001 {gdl}
+/* ***********************************************************************
+ * called from: dungeon
+ * *********************************************************************** */
+int cull_items(void);
+
+// last updated: 16oct2001 -- bwr
+int get_item_slot( int reserve = 50 );
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: beam - fight - files - food - items - misc - monstuff -
+ * religion - spells2 - spells3 - spells4
+ * *********************************************************************** */
+void unlink_item(int dest);
+void destroy_item(int dest);
+void destroy_item_stack( int x, int y );
+
+// last updated: 08jun2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void item_check(char keyin);
+
+
+// last updated: 08jun2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void pickup(void);
+
+
+// last updated 08jun2000 {dlb}
+/* ***********************************************************************
+ * called from: beam - items - transfor
+ * *********************************************************************** */
+bool copy_item_to_grid( const item_def &item, int x_plos, int y_plos,
+ int quant_drop = -1 ); // item.quantity by default
+
+// last updated Oct 15, 2000 -- bwr
+/* ***********************************************************************
+ * called from: spells4.cc
+ * *********************************************************************** */
+bool move_top_item( int src_x, int src_y, int dest_x, int dest_y );
+
+// last updated: 08jun2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void drop(void);
+
+
+// last updated: 08jun2000 {dlb}
+/* ***********************************************************************
+ * called from: files - items
+ * *********************************************************************** */
+void update_corpses(double elapsedTime);
+void update_level(double elapsedTime);
+
+
+// last updated: 08jun2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void handle_time( long time_delta );
+
+// last updated: 08jun2000 {dlb}
+/* ***********************************************************************
+ * called from: command food item_use shopping spl-book transfor
+ * *********************************************************************** */
+int inv_count(void);
+
+void cmd_destroy_item( void );
+
+#endif
diff --git a/trunk/source/lev-pand.cc b/trunk/source/lev-pand.cc
new file mode 100644
index 0000000000..a2fadad876
--- /dev/null
+++ b/trunk/source/lev-pand.cc
@@ -0,0 +1,166 @@
+/*
+ * File: lev-pand.cc
+ * Summary: Functions used in Pandemonium.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "lev-pand.h"
+
+#include "externs.h"
+
+#include "monplace.h"
+#include "mon-pick.h"
+#include "stuff.h"
+
+void init_pandemonium(void)
+{
+ int pc = 0;
+ struct monsters *monster = 0; // NULL
+
+ for (pc = 0; pc < MAX_MONSTERS; pc++)
+ {
+ monster = &menv[pc];
+
+ // Looks for unique demons and sets appropriate lists of demons.
+ // NB - also sets the level colours.
+ if (monster->type == MONS_MNOLEG)
+ {
+ env.mons_alloc[0] = MONS_ABOMINATION_SMALL;
+ env.mons_alloc[1] = MONS_ABOMINATION_SMALL;
+ env.mons_alloc[2] = MONS_ABOMINATION_SMALL;
+ env.mons_alloc[3] = MONS_ABOMINATION_LARGE;
+ env.mons_alloc[4] = MONS_NEQOXEC;
+ env.mons_alloc[5] = MONS_MIDGE;
+ env.mons_alloc[6] = MONS_NEQOXEC;
+ env.mons_alloc[7] = MONS_BLUE_DEATH;
+ env.mons_alloc[8] = MONS_BALRUG;
+ env.mons_alloc[9] = MONS_LEMURE;
+ return;
+ }
+
+ if (monster->type == MONS_LOM_LOBON)
+ {
+ env.mons_alloc[0] = MONS_HELLWING;
+ env.mons_alloc[1] = MONS_SMOKE_DEMON;
+ env.mons_alloc[2] = MONS_SMOKE_DEMON;
+ env.mons_alloc[3] = MONS_YNOXINUL;
+ env.mons_alloc[4] = MONS_GREEN_DEATH;
+ env.mons_alloc[5] = MONS_BLUE_DEATH;
+ env.mons_alloc[6] = MONS_SMOKE_DEMON;
+ env.mons_alloc[7] = MONS_HELLWING;
+ env.mons_alloc[8] = MONS_WHITE_IMP;
+ env.mons_alloc[9] = MONS_HELLWING;
+ return;
+ }
+
+ if (monster->type == MONS_CEREBOV)
+ {
+ env.mons_alloc[0] = MONS_EFREET;
+ env.mons_alloc[1] = MONS_ABOMINATION_SMALL;
+ env.mons_alloc[2] = MONS_ORANGE_DEMON;
+ env.mons_alloc[3] = MONS_ORANGE_DEMON;
+ env.mons_alloc[4] = MONS_NEQOXEC;
+ env.mons_alloc[5] = MONS_LEMURE;
+ env.mons_alloc[6] = MONS_ORANGE_DEMON;
+ env.mons_alloc[7] = MONS_YNOXINUL;
+ env.mons_alloc[8] = MONS_BALRUG;
+ env.mons_alloc[9] = MONS_BALRUG;
+ return;
+ }
+
+ if (monster->type == MONS_GLOORX_VLOQ)
+ {
+ env.mons_alloc[0] = MONS_SKELETON_SMALL;
+ env.mons_alloc[1] = MONS_SKELETON_SMALL;
+ env.mons_alloc[2] = MONS_SKELETON_LARGE;
+ env.mons_alloc[3] = MONS_WHITE_IMP;
+ env.mons_alloc[4] = MONS_CACODEMON;
+ env.mons_alloc[5] = MONS_HELLWING;
+ env.mons_alloc[6] = MONS_SMOKE_DEMON;
+ env.mons_alloc[7] = MONS_EXECUTIONER;
+ env.mons_alloc[8] = MONS_EXECUTIONER;
+ env.mons_alloc[9] = MONS_EXECUTIONER;
+ return;
+ }
+ }
+
+// colour of monster 9 is colour of floor, 8 is colour of rock
+// IIRC, BLACK is set to LIGHTGRAY
+
+ for (pc = 0; pc < 10; pc++)
+ {
+ switch (random2(17))
+ {
+ case 0: case 10: env.mons_alloc[pc] = MONS_WHITE_IMP; break;
+ case 1: case 11: env.mons_alloc[pc] = MONS_LEMURE; break;
+ case 2: case 12: env.mons_alloc[pc] = MONS_UFETUBUS; break;
+ case 3: case 13: env.mons_alloc[pc] = MONS_MANES; break;
+ case 4: case 14: env.mons_alloc[pc] = MONS_MIDGE; break;
+ case 5: env.mons_alloc[pc] = MONS_NEQOXEC; break;
+ case 6: env.mons_alloc[pc] = MONS_ORANGE_DEMON; break;
+ case 7: env.mons_alloc[pc] = MONS_HELLWING; break;
+ case 8: env.mons_alloc[pc] = MONS_SMOKE_DEMON; break;
+ case 9: env.mons_alloc[pc] = MONS_YNOXINUL; break;
+ case 15: env.mons_alloc[pc] = MONS_ABOMINATION_SMALL; break;
+ case 16: env.mons_alloc[pc] = MONS_ABOMINATION_LARGE; break;
+ }
+
+ if (one_chance_in(10))
+ env.mons_alloc[pc] = MONS_HELLION + random2(10);
+
+ if (one_chance_in(30))
+ env.mons_alloc[pc] = MONS_RED_DEVIL;
+
+ if (one_chance_in(30))
+ env.mons_alloc[pc] = MONS_IMP;
+
+ if (one_chance_in(20))
+ env.mons_alloc[pc] = MONS_DEMONIC_CRAWLER + random2(5);
+ }
+
+ if (one_chance_in(8))
+ env.mons_alloc[7] = MONS_EXECUTIONER + random2(5);
+
+ if (one_chance_in(5))
+ env.mons_alloc[8] = MONS_EXECUTIONER + random2(5);
+
+ if (one_chance_in(3))
+ env.mons_alloc[9] = MONS_EXECUTIONER + random2(5);
+
+ if (one_chance_in(10))
+ env.mons_alloc[7 + random2(3)] = MONS_FIEND;
+
+ if (one_chance_in(10))
+ env.mons_alloc[7 + random2(3)] = MONS_ICE_FIEND;
+
+ if (one_chance_in(10))
+ env.mons_alloc[7 + random2(3)] = MONS_SHADOW_FIEND;
+
+ if (one_chance_in(10))
+ env.mons_alloc[7 + random2(3)] = MONS_PIT_FIEND;
+
+ // set at least some specific monsters for the special levels - this
+ // can also be used to set some colours
+} // end init_pandemonium()
+
+void pandemonium_mons(void)
+{
+ // must leave allowance for monsters rare on pandemonium (eg wizards etc)
+ int pan_mons = env.mons_alloc[random2(10)];
+
+ if (one_chance_in(40))
+ {
+ do
+ {
+ pan_mons = random2(NUM_MONSTERS); // was random2(400) {dlb}
+ }
+ while (!mons_pan(pan_mons));
+ }
+ mons_place(pan_mons, BEH_HOSTILE, MHITNOT, false, 50,50,
+ LEVEL_PANDEMONIUM);
+} // end pandemonium_mons()
diff --git a/trunk/source/lev-pand.h b/trunk/source/lev-pand.h
new file mode 100644
index 0000000000..6868ad4bf1
--- /dev/null
+++ b/trunk/source/lev-pand.h
@@ -0,0 +1,30 @@
+/*
+ * File: lev-pand.h
+ * Summary: Functions used in Pandemonium.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef LEVPAND_H
+#define LEVPAND_H
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: abyss - misc
+ * *********************************************************************** */
+void init_pandemonium(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - misc
+ * *********************************************************************** */
+void pandemonium_mons(void);
+
+
+#endif
diff --git a/trunk/source/libemx.cc b/trunk/source/libemx.cc
new file mode 100644
index 0000000000..5634adbef8
--- /dev/null
+++ b/trunk/source/libemx.cc
@@ -0,0 +1,233 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <emx/syscalls.h>
+#include <sys/video.h>
+
+#include "libemx.h"
+
+
+static int cursor_start = 0, cursor_end = 0;
+static int gx = 0, gy = 0, gxx = 79, gyy = 24;
+static char buf[4096];
+
+
+
+
+void init_emx()
+{
+ v_init();
+ v_getctype(&cursor_start, &cursor_end);
+}
+
+
+
+
+void deinit_emx()
+{
+ // nothing to do
+}
+
+
+
+
+void _setcursortype(int curstype)
+{
+ if ( curstype == _NOCURSOR )
+ v_hidecursor();
+ else
+ v_ctype(cursor_start, cursor_end);
+}
+
+
+
+
+void clrscr()
+{
+ if ( (gx == 0) && (gy == 0) && (gxx == 79) && (gyy == 24) )
+ {
+ v_clear();
+ v_gotoxy(0, 0);
+ }
+ else
+ {
+ for (int i = gy; i <= gyy; ++i)
+ {
+ v_gotoxy(gx, i);
+ v_putn(' ', gxx - gx + 1);
+ }
+ v_gotoxy(gx, gy);
+ }
+}
+
+
+
+
+void gotoxy(int x, int y)
+{
+ v_gotoxy(x - 1 + gx, y - 1 + gy);
+}
+
+
+
+
+void textcolor(int c)
+{
+ v_attrib(c);
+}
+
+
+
+
+static void cprintf_aux(const char *s)
+{
+ char *ptr = buf;
+
+ while (*s)
+ {
+ if ( *s == '\n' )
+ {
+ *ptr = 0;
+ v_puts(buf);
+ int x, y;
+
+ v_getxy(&x, &y);
+ if ( y != 24 )
+ v_gotoxy(gx, y + 1);
+ else
+ v_putc('\n');
+
+ ptr = buf;
+ }
+ else if ( *s != '\r' )
+ *ptr++ = *s;
+
+ ++s;
+ }
+
+ *ptr = 0;
+ v_puts(buf);
+
+}
+
+void cprintf(const char *format, ...)
+{
+ va_list argp;
+ char buffer[4096]; // one could hope it's enough
+
+ va_start( argp, format );
+
+ vsprintf(buffer, format, argp);
+ cprintf_aux(buffer);
+
+ va_end(argp);
+}
+
+void puttext(int x, int y, int lx, int ly, unsigned const char *buf)
+{
+ puttext(x, y, lx, ly, (const char *) buf);
+}
+
+
+
+
+void puttext(int x, int y, int lx, int ly, const char *buf)
+{
+ int count = (lx - x + 1);
+
+ for (int i = y - 1; i < ly; ++i)
+ {
+ v_putline(buf + 2 * count * i, x - 1, i, count);
+ }
+}
+
+
+
+
+void gettext(int x, int y, int lx, int ly, unsigned char *buf)
+{
+ gettext(x, y, lx, ly, (char *) buf);
+}
+
+
+
+
+void gettext(int x, int y, int lx, int ly, char *buf)
+{
+ int count = (lx - x + 1);
+
+ for (int i = y - 1; i < ly; ++i)
+ {
+ v_getline(buf + 2 * count * i, x - 1, i, count);
+ }
+}
+
+
+
+
+void window(int x, int y, int lx, int ly)
+{
+ gx = x - 1;
+ gy = y - 1;
+ gxx = lx - 1;
+ gyy = ly - 1;
+}
+
+
+
+
+int wherex()
+{
+ int x, y;
+
+ v_getxy(&x, &y);
+
+ return x + 1 - gx;
+}
+
+
+
+
+int wherey()
+{
+ int x, y;
+
+ v_getxy(&x, &y);
+
+ return y + 1 - gy;
+}
+
+
+
+
+void putch(char c)
+{
+ v_putc(c);
+}
+
+
+
+
+int kbhit()
+{
+ return 0;
+}
+
+
+
+
+void delay(int ms)
+{
+ __sleep2(ms);
+}
+
+
+
+
+void textbackground(int c)
+{
+ if ( c != 0 )
+ {
+ fprintf(stderr, "bad background=%d", c);
+ exit(1);
+ }
+}
diff --git a/trunk/source/libemx.h b/trunk/source/libemx.h
new file mode 100644
index 0000000000..ac33612284
--- /dev/null
+++ b/trunk/source/libemx.h
@@ -0,0 +1,38 @@
+#ifndef LIBEMX_H
+#define LIBEMX_H
+#ifndef __LIBEMX_C__
+
+
+#include <stdlib.h>
+#include <conio.h>
+
+#define itoa _itoa
+
+
+#define _NORMALCURSOR 1
+#define _NOCURSOR 0
+
+
+void init_emx();
+void deinit_emx();
+void _setcursortype(int curstype);
+void clrscr();
+void gotoxy(int x, int y);
+void textcolor(int c);
+void cprintf (const char *format, ...);
+
+void puttext(int x, int y, int lx, int ly, const char *buf);
+void puttext(int x, int y, int lx, int ly, unsigned const char *buf);
+void gettext(int x, int y, int lx, int ly, char *buf);
+void gettext(int x, int y, int lx, int ly, unsigned char *buf);
+void window(int x, int y, int lx, int ly);
+int wherex();
+int wherey();
+void putch(char c);
+int kbhit();
+void delay(int ms);
+void textbackground(int c);
+
+
+#endif // __LIBEMX_C__
+#endif
diff --git a/trunk/source/liblinux.cc b/trunk/source/liblinux.cc
new file mode 100644
index 0000000000..01d8db3194
--- /dev/null
+++ b/trunk/source/liblinux.cc
@@ -0,0 +1,757 @@
+/*
+ * File: liblinux.cc
+ * Summary: Functions for linux, unix, and curses support
+ * Written by: ?
+ *
+ * Change History (most recent first):
+ *
+ * <6> 10/11/99 BCR Swapped 'v' and 'V' commands, fixed
+ * & for debug command.
+ * <5> 9/25/99 CDL linuxlib -> liblinux
+ * changes to fix "macro problem"
+ * keypad -> command lookup
+ * <4> 99/07/13 BWR added translate_keypad(), to try and
+ * translate keypad escape sequences into
+ * numeric char values.
+ * <3> 99/06/18 BCR moved CHARACTER_SET #define to AppHdr.h
+ * <2> 99/05/12 BWR Tchars, signals, solaris support
+ *
+ * <1> -/--/-- ? Created
+ *
+ */
+
+/* Some replacement routines missing in gcc
+ Some of these are inspired by/stolen from the Linux-conio package
+ by Mental EXPlotion. Hope you guys don't mind.
+ The colour exchange system is perhaps a little overkill, but I wanted
+ it to be general to support future changes.. The only thing not
+ supported properly is black on black (used by curses for "normal" mode)
+ and white on white (used by me for "bright black" (darkgray) on black
+
+ Jan 1998 Svante Gerhard <svante@algonet.se> */
+
+#include "AppHdr.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <ctype.h>
+#define _LIBLINUX_IMPLEMENTATION
+#include "liblinux.h"
+#include "defines.h"
+
+#include "enum.h"
+#include "externs.h"
+
+
+#if defined(USE_POSIX_TERMIOS)
+#include <termios.h>
+
+static struct termios def_term;
+static struct termios game_term;
+
+#elif defined(USE_TCHARS_IOCTL)
+#include <sys/ttold.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <errno.h>
+
+static struct ltchars def_term;
+static struct ltchars game_term;
+
+#endif
+
+#ifdef USE_UNIX_SIGNALS
+#include <signal.h>
+#endif
+
+// Its best if curses comes at the end (name conflicts with Solaris). -- bwr
+#ifndef CURSES_INCLUDE_FILE
+ #include <curses.h>
+#else
+ #include CURSES_INCLUDE_FILE
+#endif
+
+// Character set variable
+int character_set = CHARACTER_SET;
+
+// Globals holding current text/backg. colors
+short FG_COL = WHITE;
+short BG_COL = BLACK;
+
+// a lookup table to convert keypresses to command enums
+static int key_to_command_table[KEY_MAX];
+
+static unsigned int convert_to_curses_attr( int chattr )
+{
+ switch (chattr)
+ {
+ case CHATTR_STANDOUT: return (A_STANDOUT);
+ case CHATTR_BOLD: return (A_BOLD);
+ case CHATTR_BLINK: return (A_BLINK);
+ case CHATTR_UNDERLINE: return (A_UNDERLINE);
+ case CHATTR_REVERSE: return (A_REVERSE);
+ case CHATTR_DIM: return (A_DIM);
+ default: return (A_NORMAL);
+ }
+}
+
+static inline short macro_colour( short col )
+{
+ return (Options.colour[ col ]);
+}
+
+// Translate DOS colors to curses.
+static short translate_colour( short col )
+{
+ switch (col)
+ {
+ case BLACK:
+ return COLOR_BLACK;
+ break;
+ case BLUE:
+ return COLOR_BLUE;
+ break;
+ case GREEN:
+ return COLOR_GREEN;
+ break;
+ case CYAN:
+ return COLOR_CYAN;
+ break;
+ case RED:
+ return COLOR_RED;
+ break;
+ case MAGENTA:
+ return COLOR_MAGENTA;
+ break;
+ case BROWN:
+ return COLOR_YELLOW;
+ break;
+ case LIGHTGREY:
+ return COLOR_WHITE;
+ break;
+ case DARKGREY:
+ return COLOR_BLACK + COLFLAG_CURSES_BRIGHTEN;
+ break;
+ case LIGHTBLUE:
+ return COLOR_BLUE + COLFLAG_CURSES_BRIGHTEN;
+ break;
+ case LIGHTGREEN:
+ return COLOR_GREEN + COLFLAG_CURSES_BRIGHTEN;
+ break;
+ case LIGHTCYAN:
+ return COLOR_CYAN + COLFLAG_CURSES_BRIGHTEN;
+ break;
+ case LIGHTRED:
+ return COLOR_RED + COLFLAG_CURSES_BRIGHTEN;
+ break;
+ case LIGHTMAGENTA:
+ return COLOR_MAGENTA + COLFLAG_CURSES_BRIGHTEN;
+ break;
+ case YELLOW:
+ return COLOR_YELLOW + COLFLAG_CURSES_BRIGHTEN;
+ break;
+ case WHITE:
+ return COLOR_WHITE + COLFLAG_CURSES_BRIGHTEN;
+ break;
+ default:
+ return COLOR_GREEN;
+ break; //mainly for debugging
+ }
+}
+
+
+static void setup_colour_pairs( void )
+{
+
+ short i, j;
+
+ for (i = 0; i < 8; i++)
+ {
+ for (j = 0; j < 8; j++)
+ {
+ if (( i > 0 ) || ( j > 0 ))
+ init_pair(i * 8 + j, j, i);
+ }
+ }
+
+ init_pair(63, COLOR_BLACK, Options.background);
+} // end setup_colour_pairs()
+
+
+#if defined(USE_POSIX_TERMIOS)
+
+static void termio_init()
+{
+ tcgetattr(0, &def_term);
+ memcpy(&game_term, &def_term, sizeof(struct termios));
+
+ def_term.c_cc[VINTR] = (char) 3; // ctrl-C
+ game_term.c_cc[VINTR] = (char) 3; // ctrl-C
+
+ // Lets recover some control sequences
+ game_term.c_cc[VSTART] = (char) -1; // ctrl-Q
+ game_term.c_cc[VSTOP] = (char) -1; // ctrl-S
+ game_term.c_cc[VSUSP] = (char) -1; // ctrl-Y
+#ifdef VDSUSP
+ game_term.c_cc[VDSUSP] = (char) -1; // ctrl-Y
+#endif
+
+ tcsetattr(0, TCSAFLUSH, &game_term);
+}
+
+#elif defined(USE_TCHARS_IOCTL)
+
+static void termio_init()
+{
+ ioctl(0, TIOCGLTC, &def_term);
+ memcpy(&game_term, &def_term, sizeof(struct ltchars));
+
+ game_term.t_suspc = game_term.t_dsuspc = -1;
+ ioctl(0, TIOCSLTC, &game_term);
+}
+
+#endif
+
+void init_key_to_command()
+{
+ int i;
+
+ // initialize to "do nothing"
+ for (i = 0; i < KEY_MAX; i++)
+ {
+ key_to_command_table[i] = CMD_NO_CMD;
+ }
+
+ // lower case
+ key_to_command_table['a'] = CMD_USE_ABILITY;
+ key_to_command_table['b'] = CMD_MOVE_DOWN_LEFT;
+ key_to_command_table['c'] = CMD_CLOSE_DOOR;
+ key_to_command_table['d'] = CMD_DROP;
+ key_to_command_table['e'] = CMD_EAT;
+ key_to_command_table['f'] = CMD_FIRE;
+ key_to_command_table['g'] = CMD_PICKUP;
+ key_to_command_table['h'] = CMD_MOVE_LEFT;
+ key_to_command_table['i'] = CMD_DISPLAY_INVENTORY;
+ key_to_command_table['j'] = CMD_MOVE_DOWN;
+ key_to_command_table['k'] = CMD_MOVE_UP;
+ key_to_command_table['l'] = CMD_MOVE_RIGHT;
+ key_to_command_table['m'] = CMD_DISPLAY_SKILLS;
+ key_to_command_table['n'] = CMD_MOVE_DOWN_RIGHT;
+ key_to_command_table['o'] = CMD_OPEN_DOOR;
+ key_to_command_table['p'] = CMD_PRAY;
+ key_to_command_table['q'] = CMD_QUAFF;
+ key_to_command_table['r'] = CMD_READ;
+ key_to_command_table['s'] = CMD_SEARCH;
+ key_to_command_table['t'] = CMD_THROW;
+ key_to_command_table['u'] = CMD_MOVE_UP_RIGHT;
+ key_to_command_table['v'] = CMD_EXAMINE_OBJECT;
+ key_to_command_table['w'] = CMD_WIELD_WEAPON;
+ key_to_command_table['x'] = CMD_LOOK_AROUND;
+ key_to_command_table['y'] = CMD_MOVE_UP_LEFT;
+ key_to_command_table['z'] = CMD_ZAP_WAND;
+
+ // upper case
+ key_to_command_table['A'] = CMD_DISPLAY_MUTATIONS;
+ key_to_command_table['B'] = CMD_RUN_DOWN_LEFT;
+ key_to_command_table['C'] = CMD_EXPERIENCE_CHECK;
+ key_to_command_table['D'] = CMD_BUTCHER;
+ key_to_command_table['E'] = CMD_EVOKE;
+ key_to_command_table['F'] = CMD_NO_CMD;
+ key_to_command_table['G'] = CMD_NO_CMD;
+ key_to_command_table['H'] = CMD_RUN_LEFT;
+ key_to_command_table['I'] = CMD_OBSOLETE_INVOKE;
+ key_to_command_table['J'] = CMD_RUN_DOWN;
+ key_to_command_table['K'] = CMD_RUN_UP;
+ key_to_command_table['L'] = CMD_RUN_RIGHT;
+ key_to_command_table['M'] = CMD_MEMORISE_SPELL;
+ key_to_command_table['N'] = CMD_RUN_DOWN_RIGHT;
+ key_to_command_table['O'] = CMD_DISPLAY_OVERMAP;
+ key_to_command_table['P'] = CMD_WEAR_JEWELLERY;
+ key_to_command_table['Q'] = CMD_QUIT;
+ key_to_command_table['R'] = CMD_REMOVE_JEWELLERY;
+ key_to_command_table['S'] = CMD_SAVE_GAME;
+ key_to_command_table['T'] = CMD_REMOVE_ARMOUR;
+ key_to_command_table['U'] = CMD_RUN_UP_RIGHT;
+ key_to_command_table['V'] = CMD_GET_VERSION;
+ key_to_command_table['W'] = CMD_WEAR_ARMOUR;
+ key_to_command_table['X'] = CMD_DISPLAY_MAP;
+ key_to_command_table['Y'] = CMD_RUN_UP_LEFT;
+ key_to_command_table['Z'] = CMD_CAST_SPELL;
+
+ // control
+ key_to_command_table[ CONTROL('A') ] = CMD_TOGGLE_AUTOPICKUP;
+ key_to_command_table[ CONTROL('B') ] = CMD_OPEN_DOOR_DOWN_LEFT;
+ key_to_command_table[ CONTROL('C') ] = CMD_NO_CMD;
+
+#ifdef ALLOW_DESTROY_ITEM_COMMAND
+ key_to_command_table[ CONTROL('D') ] = CMD_DESTROY_ITEM;
+#else
+ key_to_command_table[ CONTROL('D') ] = CMD_NO_CMD;
+#endif
+
+ key_to_command_table[ CONTROL('E') ] = CMD_NO_CMD;
+ key_to_command_table[ CONTROL('F') ] = CMD_NO_CMD;
+ key_to_command_table[ CONTROL('G') ] = CMD_NO_CMD;
+ key_to_command_table[ CONTROL('H') ] = CMD_OPEN_DOOR_LEFT;
+ key_to_command_table[ CONTROL('I') ] = CMD_NO_CMD;
+ key_to_command_table[ CONTROL('J') ] = CMD_OPEN_DOOR_DOWN;
+ key_to_command_table[ CONTROL('K') ] = CMD_OPEN_DOOR_UP;
+ key_to_command_table[ CONTROL('L') ] = CMD_OPEN_DOOR_RIGHT;
+ key_to_command_table[ CONTROL('M') ] = CMD_NO_CMD;
+ key_to_command_table[ CONTROL('N') ] = CMD_OPEN_DOOR_DOWN_RIGHT;
+ key_to_command_table[ CONTROL('O') ] = CMD_NO_CMD;
+ key_to_command_table[ CONTROL('P') ] = CMD_REPLAY_MESSAGES;
+ key_to_command_table[ CONTROL('Q') ] = CMD_NO_CMD;
+ key_to_command_table[ CONTROL('R') ] = CMD_REDRAW_SCREEN;
+ key_to_command_table[ CONTROL('S') ] = CMD_NO_CMD;
+ key_to_command_table[ CONTROL('T') ] = CMD_NO_CMD;
+ key_to_command_table[ CONTROL('U') ] = CMD_OPEN_DOOR_UP_LEFT;
+ key_to_command_table[ CONTROL('V') ] = CMD_NO_CMD;
+ key_to_command_table[ CONTROL('W') ] = CMD_NO_CMD;
+ key_to_command_table[ CONTROL('X') ] = CMD_SAVE_GAME_NOW;
+ key_to_command_table[ CONTROL('Y') ] = CMD_OPEN_DOOR_UP_RIGHT;
+ key_to_command_table[ CONTROL('Z') ] = CMD_SUSPEND_GAME;
+
+ // other printables
+ key_to_command_table['.'] = CMD_MOVE_NOWHERE;
+ key_to_command_table['<'] = CMD_GO_UPSTAIRS;
+ key_to_command_table['>'] = CMD_GO_DOWNSTAIRS;
+ key_to_command_table['@'] = CMD_DISPLAY_CHARACTER_STATUS;
+ key_to_command_table[','] = CMD_PICKUP;
+ key_to_command_table[';'] = CMD_INSPECT_FLOOR;
+ key_to_command_table['!'] = CMD_SHOUT;
+ key_to_command_table['^'] = CMD_DISPLAY_RELIGION;
+ key_to_command_table['#'] = CMD_CHARACTER_DUMP;
+ key_to_command_table['='] = CMD_ADJUST_INVENTORY;
+ key_to_command_table['?'] = CMD_DISPLAY_COMMANDS;
+ key_to_command_table['`'] = CMD_MACRO_ADD;
+ key_to_command_table['~'] = CMD_MACRO_SAVE;
+ key_to_command_table['&'] = CMD_WIZARD;
+ key_to_command_table['"'] = CMD_LIST_JEWELLERY;
+
+
+ // I'm making this both, because I'm tried of changing it
+ // back to '[' (the character that represents armour on the map) -- bwr
+ key_to_command_table['['] = CMD_LIST_ARMOUR;
+ key_to_command_table[']'] = CMD_LIST_ARMOUR;
+
+ // This one also ended up backwards this time, so it's also going on
+ // both now -- should be ')'... the same character that's used to
+ // represent weapons.
+ key_to_command_table[')'] = CMD_LIST_WEAPONS;
+ key_to_command_table['('] = CMD_LIST_WEAPONS;
+
+ key_to_command_table['\\'] = CMD_DISPLAY_KNOWN_OBJECTS;
+ key_to_command_table['\''] = CMD_WEAPON_SWAP;
+
+ // digits
+ key_to_command_table['1'] = CMD_MOVE_DOWN_LEFT;
+ key_to_command_table['2'] = CMD_MOVE_DOWN;
+ key_to_command_table['3'] = CMD_MOVE_DOWN_RIGHT;
+ key_to_command_table['4'] = CMD_MOVE_LEFT;
+ key_to_command_table['5'] = CMD_REST;
+ key_to_command_table['6'] = CMD_MOVE_RIGHT;
+ key_to_command_table['7'] = CMD_MOVE_UP_LEFT;
+ key_to_command_table['8'] = CMD_MOVE_UP;
+ key_to_command_table['9'] = CMD_MOVE_UP_RIGHT;
+
+ // keypad
+ key_to_command_table[KEY_A1] = CMD_MOVE_UP_LEFT;
+ key_to_command_table[KEY_A3] = CMD_MOVE_UP_RIGHT;
+ key_to_command_table[KEY_C1] = CMD_MOVE_DOWN_LEFT;
+ key_to_command_table[KEY_C3] = CMD_MOVE_DOWN_RIGHT;
+
+ key_to_command_table[KEY_HOME] = CMD_MOVE_UP_LEFT;
+ key_to_command_table[KEY_PPAGE] = CMD_MOVE_UP_RIGHT;
+ key_to_command_table[KEY_END] = CMD_MOVE_DOWN_LEFT;
+ key_to_command_table[KEY_NPAGE] = CMD_MOVE_DOWN_RIGHT;
+
+ key_to_command_table[KEY_B2] = CMD_REST;
+
+ key_to_command_table[KEY_UP] = CMD_MOVE_UP;
+ key_to_command_table[KEY_DOWN] = CMD_MOVE_DOWN;
+ key_to_command_table[KEY_LEFT] = CMD_MOVE_LEFT;
+ key_to_command_table[KEY_RIGHT] = CMD_MOVE_RIGHT;
+
+
+ // other odd things
+ // key_to_command_table[ 263 ] = CMD_OPEN_DOOR_LEFT; // backspace
+
+ // these are invalid keys, but to help kludge running
+ // pass them through unmolested
+ key_to_command_table[128] = 128;
+ key_to_command_table['*'] = '*';
+ key_to_command_table['/'] = '/';
+}
+
+int key_to_command(int keyin)
+{
+ return (key_to_command_table[keyin]);
+}
+
+void lincurses_startup( void )
+{
+#if defined(USE_POSIX_TERMIOS) || defined(USE_TCHARS_IOCTL)
+ termio_init();
+#endif
+
+#ifdef USE_UNIX_SIGNALS
+#ifdef SIGQUIT
+ signal(SIGQUIT, SIG_IGN);
+#endif
+
+#ifdef SIGINT
+ signal(SIGINT, SIG_IGN);
+#endif
+#endif
+
+ //savetty();
+
+ initscr();
+ cbreak();
+ noecho();
+
+ nonl();
+ intrflush(stdscr, FALSE);
+ //cbreak();
+
+ meta(stdscr, TRUE);
+ start_color();
+ setup_colour_pairs();
+
+ init_key_to_command();
+
+#ifndef SOLARIS
+ // These can cause some display problems under Solaris
+ scrollok(stdscr, TRUE);
+#endif
+}
+
+
+void lincurses_shutdown()
+{
+#if defined(USE_POSIX_TERMIOS)
+ tcsetattr(0, TCSAFLUSH, &def_term);
+#elif defined(USE_TCHARS_IOCTL)
+ ioctl(0, TIOCSLTC, &def_term);
+#endif
+
+#ifdef USE_UNIX_SIGNALS
+#ifdef SIGQUIT
+ signal(SIGQUIT, SIG_DFL);
+#endif
+
+#ifdef SIGINT
+ signal(SIGINT, SIG_DFL);
+#endif
+#endif
+
+ // resetty();
+ endwin();
+}
+
+
+/* Convert value to string */
+int itoa(int value, char *strptr, int radix)
+{
+ unsigned int bitmask = 32768;
+ int ctr = 0;
+ int startflag = 0;
+
+ if (radix == 10)
+ {
+ sprintf(strptr, "%i", value);
+ }
+ if (radix == 2) /* int to "binary string" */
+ {
+ while (bitmask)
+ {
+ if (value & bitmask)
+ {
+ startflag = 1;
+ sprintf(strptr + ctr, "1");
+ }
+ else
+ {
+ if (startflag)
+ sprintf(strptr + ctr, "0");
+ }
+
+ bitmask = bitmask >> 1;
+ if (startflag)
+ ctr++;
+ }
+
+ if (!startflag) /* Special case if value == 0 */
+ sprintf((strptr + ctr++), "0");
+
+ strptr[ctr] = (char) NULL;
+ }
+ return (OK); /* Me? Fail? Nah. */
+}
+
+
+// Convert string to lowercase.
+char *strlwr(char *str)
+{
+ unsigned int i;
+
+ for (i = 0; i < strlen(str); i++)
+ str[i] = tolower(str[i]);
+
+ return (str);
+}
+
+
+int cprintf(const char *format,...)
+{
+ int i;
+ char buffer[2048]; // One full screen if no control seq...
+
+ va_list argp;
+
+ va_start(argp, format);
+ vsprintf(buffer, format, argp);
+ va_end(argp);
+ i = addstr(buffer);
+ refresh();
+ return (i);
+}
+
+
+int putch(unsigned char chr)
+{
+ if (chr == 0)
+ chr = ' ';
+
+ return (addch(chr));
+}
+
+
+char getche()
+{
+ char chr;
+
+ chr = getch();
+ addch(chr);
+ refresh();
+ return (chr);
+}
+
+
+int window(int x1, int y1, int x2, int y2)
+{
+ x1 = y1 = x2 = y2 = 0; /* Do something to them.. makes gcc happy :) */
+ return (refresh());
+}
+
+// These next four are front functions so that we can reduce
+// the amount of curses special code that occurs outside this
+// this file. This is good, since there are some issues with
+// name space collisions between curses macros and the standard
+// C++ string class. -- bwr
+void update_screen(void)
+{
+ refresh();
+}
+
+void clear_to_end_of_line(void)
+{
+ textcolor( LIGHTGREY );
+ textbackground( BLACK );
+ clrtoeol();
+}
+
+void clear_to_end_of_screen(void)
+{
+ textcolor( LIGHTGREY );
+ textbackground( BLACK );
+ clrtobot();
+}
+
+int get_number_of_lines_from_curses(void)
+{
+ return (LINES);
+}
+
+void get_input_line_from_curses( char *const buff, int len )
+{
+ echo();
+ wgetnstr( stdscr, buff, len );
+ noecho();
+}
+
+int clrscr()
+{
+ int retval;
+
+ textcolor( LIGHTGREY );
+ textbackground( BLACK );
+ retval = clear();
+ refresh();
+ return (retval);
+}
+
+
+void _setcursortype(int curstype)
+{
+ curs_set(curstype);
+}
+
+
+void textcolor(int col)
+{
+ short fg, bg;
+
+ FG_COL = col & 0x00ff;
+ fg = translate_colour( macro_colour( FG_COL ) );
+ bg = translate_colour( (BG_COL == BLACK) ? Options.background : BG_COL );
+
+ // calculate which curses flags we need...
+ unsigned int flags = 0;
+
+#ifdef USE_COLOUR_OPTS
+ if ((col & COLFLAG_FRIENDLY_MONSTER)
+ && Options.friend_brand != CHATTR_NORMAL)
+ {
+ flags |= convert_to_curses_attr( Options.friend_brand );
+
+ // If we can't do a dark grey friend brand, then we'll
+ // switch the colour to light grey.
+ if (Options.no_dark_brand
+ && fg == (COLOR_BLACK | COLFLAG_CURSES_BRIGHTEN)
+ && bg == 0)
+ {
+ fg = COLOR_WHITE;
+ }
+ }
+#endif
+
+ // curses typically uses A_BOLD to give bright foreground colour,
+ // but various termcaps may disagree
+ if (fg & COLFLAG_CURSES_BRIGHTEN)
+ flags |= A_BOLD;
+
+ // curses typically uses A_BLINK to give bright background colour,
+ // but various termcaps may disagree (in whole or in part)
+ if (bg & COLFLAG_CURSES_BRIGHTEN)
+ flags |= A_BLINK;
+
+ // Strip out all the bits above the raw 3-bit colour definition
+ fg &= 0x0007;
+ bg &= 0x0007;
+
+ // figure out which colour pair we want
+ const int pair = (fg == 0 && bg == 0) ? 63 : (bg * 8 + fg);
+
+ attrset( COLOR_PAIR(pair) | flags | character_set );
+}
+
+
+void textbackground(int col)
+{
+ short fg, bg;
+
+ BG_COL = col & 0x00ff;
+ fg = translate_colour( macro_colour( FG_COL ) );
+ bg = translate_colour( (BG_COL == BLACK) ? Options.background : BG_COL );
+
+ unsigned int flags = 0;
+
+#ifdef USE_COLOUR_OPTS
+ if ((col & COLFLAG_FRIENDLY_MONSTER)
+ && Options.friend_brand != CHATTR_NORMAL)
+ {
+ flags |= convert_to_curses_attr( Options.friend_brand );
+
+ // If we can't do a dark grey friend brand, then we'll
+ // switch the colour to light grey.
+ if (Options.no_dark_brand
+ && fg == (COLOR_BLACK | COLFLAG_CURSES_BRIGHTEN)
+ && bg == 0)
+ {
+ fg = COLOR_WHITE;
+ }
+ }
+#endif
+
+ // curses typically uses A_BOLD to give bright foreground colour,
+ // but various termcaps may disagree
+ if (fg & COLFLAG_CURSES_BRIGHTEN)
+ flags |= A_BOLD;
+
+ // curses typically uses A_BLINK to give bright background colour,
+ // but various termcaps may disagree
+ if (bg & COLFLAG_CURSES_BRIGHTEN)
+ flags |= A_BLINK;
+
+ // Strip out all the bits above the raw 3-bit colour definition
+ fg &= 0x0007;
+ bg &= 0x0007;
+
+ // figure out which colour pair we want
+ const int pair = (fg == 0 && bg == 0) ? 63 : (bg * 8 + fg);
+
+ attrset( COLOR_PAIR(pair) | flags | character_set );
+}
+
+
+int gotoxy(int x, int y)
+{
+ return (move(y - 1, x - 1));
+}
+
+
+int wherex()
+{
+ int x, y;
+
+ getyx(stdscr, y, x);
+ return (x + 1);
+}
+
+
+int wherey()
+{
+ int x, y;
+
+ getyx(stdscr, y, x);
+ return (y + 1);
+}
+
+
+int stricmp( const char *str1, const char *str2 )
+{
+ return (strcmp(str1, str2));
+}
+
+
+void delay( unsigned long time )
+{
+ usleep( time * 1000 );
+}
+
+
+/*
+ Note: kbhit now in macro.cc
+ */
+
+/* This is Juho Snellman's modified kbhit, to work with macros */
+int kbhit()
+{
+ int i;
+
+ nodelay(stdscr, TRUE);
+ timeout(0); // apparently some need this to guarantee non-blocking -- bwr
+ i = wgetch(stdscr);
+ nodelay(stdscr, FALSE);
+
+ if (i == -1)
+ i = 0;
+ else
+ ungetch(i);
+
+ return (i);
+}
diff --git a/trunk/source/liblinux.h b/trunk/source/liblinux.h
new file mode 100644
index 0000000000..a63b625f3a
--- /dev/null
+++ b/trunk/source/liblinux.h
@@ -0,0 +1,53 @@
+#ifndef LIBLINUX_H
+#define LIBLINUX_H
+
+
+// Some replacement routines missing in gcc
+
+#define _NORMALCURSOR 1
+#define _NOCURSOR 0
+#define O_BINARY O_RDWR
+
+char *strlwr(char *str);
+char getche(void);
+
+
+int clrscr(void);
+int cprintf(const char *format,...);
+int gotoxy(int x, int y);
+int itoa(int value, char *strptr, int radix);
+int kbhit(void);
+int key_to_command(int);
+int putch(unsigned char chr);
+int stricmp(const char *str1, const char *str2);
+int translate_keypad(int keyin);
+int wherex(void);
+int wherey(void);
+int window(int x1, int y1, int x2, int y2);
+void update_screen(void);
+void clear_to_end_of_line(void);
+void clear_to_end_of_screen(void);
+int get_number_of_lines_from_curses(void);
+void get_input_line_from_curses( char *const buff, int len );
+
+void _setcursortype(int curstype);
+void delay(unsigned long time);
+void init_key_to_command();
+void lincurses_shutdown(void);
+void lincurses_startup(void);
+void textbackground(int bg);
+void textcolor(int col);
+
+#ifndef _LIBLINUX_IMPLEMENTATION
+/* Some stuff from curses, to remove compiling warnings.. */
+extern "C"
+{
+ int getstr(char *);
+ int getch(void);
+ int noecho(void);
+ int echo(void);
+}
+#endif
+
+
+#endif
diff --git a/trunk/source/libmac.cc b/trunk/source/libmac.cc
new file mode 100644
index 0000000000..78a90d774f
--- /dev/null
+++ b/trunk/source/libmac.cc
@@ -0,0 +1,2114 @@
+/*
+ * File: libmac.cc
+ * Summary: Mac specific routines used by Crawl.
+ * Written by: Jesse Jones (jesjones@mindspring.com)
+ *
+ * Change History (most recent first):
+ *
+ * <5> 5/25/02 JDJ Rewrote to use Carbon Events and Mach-O.
+ * <4> 9/25/99 CDL linuxlib -> liblinux
+ *
+ * <3> 5/30/99 JDJ Quit only pops up save changes dialog if game_has_started is true.
+ * <2> 4/24/99 JDJ HandleMenu calls save_game instead of returning a 'S'
+ * character ('S' now prompts). kTermHeight is now initialized
+ * to NUMBER_OF_LINES.
+ * <2> 4/24/99 JDJ getstr only adds printable characters to the buffer.
+ * <1> 3/23/99 JDJ Created
+ */
+
+#include "AppHdr.h"
+#include "libmac.h"
+
+#if macintosh
+
+#include <cstdarg>
+#include <ctype.h>
+#include <string.h>
+#include <vector.h>
+
+#include <CarbonCore/StringCompare.h>
+#include <HIToolbox/CarbonEvents.h>
+#include <HIToolbox/Dialogs.h>
+
+#include "debug.h"
+#include "defines.h"
+#include "files.h"
+#include "MacString.h"
+#include "version.h"
+
+
+//-----------------------------------
+// Forward References
+//
+class CApplication;
+
+
+//-----------------------------------
+// Constants
+//
+const int kTermWidth = 80;
+const int kTermHeight = MAC_NUMBER_OF_LINES;
+
+const int kLeftArrowKey = 0x7B;
+const int kUpArrowKey = 0x7E;
+const int kRightArrowKey = 0x7C;
+const int kDownArrowKey = 0x7D;
+
+const int kNumPad0Key = 0x52;
+const int kNumPad1Key = 0x53;
+const int kNumPad2Key = 0x54;
+const int kNumPad3Key = 0x55;
+const int kNumPad4Key = 0x56;
+const int kNumPad5Key = 0x57;
+const int kNumPad6Key = 0x58;
+const int kNumPad7Key = 0x59;
+const int kNumPad8Key = 0x5B;
+const int kNumPad9Key = 0x5C;
+
+const int kNumPadMultKey = 0x43;
+const int kNumPadAddKey = 0x45;
+const int kNumPadSubKey = 0x4E;
+const int kNumPadDecimalKey = 0x41;
+const int kNumPadDivideKey = 0x4B;
+
+const char kEnterChar = 0x03;
+const short kEscapeKey = 0x35;
+const char kCheckMarkChar = 0x12;
+const char kNoMarkChar = 0x00;
+
+const short kSaveBtn = 1;
+const short kCancelBtn = 2;
+const short kDontSaveBtn = 3;
+
+const Rect kBigRect = {0, 0, 32000, 32000};
+
+const RGBColor kBlack = {0, 0, 0};
+const RGBColor kWhite = {65535, 65535, 65535};
+
+enum EAskSaveResult
+{
+ kSaveChanges = 1,
+ kCancelSave = 2,
+ kDontSave = 3
+};
+
+
+//-----------------------------------
+// Variables
+//
+static CApplication* sApp = NULL;
+static CTabHandle sColors = NULL;
+
+static bool sInDialog = false;
+
+extern bool game_has_started;
+
+
+// ========================================================================
+// Internal Functions
+// ========================================================================
+
+//---------------------------------------------------------------
+//
+// CreateSpec
+//
+//---------------------------------------------------------------
+static EventTypeSpec CreateSpec(UInt32 c, UInt32 k)
+{
+ EventTypeSpec spec;
+
+ spec.eventClass = c;
+ spec.eventKind = k;
+
+ return spec;
+}
+
+
+//---------------------------------------------------------------
+//
+// DrawChar
+//
+//---------------------------------------------------------------
+inline void DrawChar(short x, short y, char ch)
+{
+ MoveTo(x, y);
+ DrawText(&ch, 0, 1);
+}
+
+
+//---------------------------------------------------------------
+//
+// ThrowIf
+//
+//---------------------------------------------------------------
+static void ThrowIf(bool predicate, const std::string& text)
+{
+ if (predicate)
+ throw std::runtime_error(text);
+}
+
+
+//---------------------------------------------------------------
+//
+// ThrowIfOSErr
+//
+//---------------------------------------------------------------
+static void ThrowIfOSErr(OSErr err, const std::string& text)
+{
+ if (err != noErr)
+ {
+ char buffer[256];
+ sprintf(buffer, "%s (%d)", text.c_str(), err);
+
+ throw std::runtime_error(buffer);
+ }
+}
+
+
+//---------------------------------------------------------------
+//
+// FlashButton
+//
+//---------------------------------------------------------------
+static void FlashButton(DialogPtr dialog, short item)
+{
+ ASSERT(dialog != nil);
+ ASSERT(item >= 1 && item <= CountDITL(dialog));
+
+ ControlRef control;
+ (void) GetDialogItemAsControl(dialog, item, &control);
+
+ HiliteControl(control, 1);
+// QDAddRectToDirtyRegion(GetDialogPort(dialog), &kBigRect);
+ QDFlushPortBuffer(GetDialogPort(dialog), NULL);
+
+ unsigned long ticks;
+ Delay(8, &ticks);
+
+ HiliteControl(control, 0);
+// QDAddRectToDirtyRegion(GetDialogPort(dialog), &kBigRect);
+ QDFlushPortBuffer(GetDialogPort(dialog), NULL);
+}
+
+
+//---------------------------------------------------------------
+//
+// WarnUser
+//
+// Pops up an error dialog.
+//
+//---------------------------------------------------------------
+static void WarnUser(const char* message)
+{
+ int len = strlen(message);
+ if (len > 250)
+ len = 250;
+
+ Str255 text;
+ for (int i = 0; i < len; i++)
+ text[i + 1] = message[i];
+ text[0] = len;
+
+ AlertStdAlertParamRec params;
+ params.movable = true;
+ params.helpButton = false;
+ params.filterProc = NULL;
+ params.defaultText = (StringPtr) -1L; // use default (ie "OK")
+ params.cancelText = NULL;
+ params.otherText = NULL;
+ params.defaultButton = 1;
+ params.cancelButton = 0;
+ params.position = kWindowAlertPositionParentWindowScreen;
+
+ short item;
+ sInDialog = true;
+ OSErr err = StandardAlert(kAlertCautionAlert, text, "\p", &params, &item);
+ ASSERT(err == noErr); // seems kind of pointless to throw
+ sInDialog = false;
+}
+
+
+//---------------------------------------------------------------
+//
+// SaveChangesFilter
+//
+//---------------------------------------------------------------
+static pascal Boolean SaveChangesFilter(DialogPtr dptr, EventRecord* event, short* item)
+{
+ bool handled = false;
+
+ if (event->what == keyDown)
+ {
+ char ch = (char) toupper((char) (event->message & charCodeMask));
+ short key = (short) ((event->message & keyCodeMask) >> 8);
+
+ if (ch == 'S')
+ {
+ *item = 1;
+ handled = true;
+ }
+ else if (ch == 'D')
+ {
+ *item = 3;
+ handled = true;
+ }
+ else if (ch == '\r' || ch == kEnterChar)
+ {
+ *item = 1;
+ handled = true;
+ }
+ else if (key == kEscapeKey)
+ {
+ *item = 2;
+ handled = true;
+ }
+
+ if (handled)
+ FlashButton(dptr, *item);
+ }
+
+ return handled;
+}
+
+
+//---------------------------------------------------------------
+//
+// AskSaveChanges
+//
+//---------------------------------------------------------------
+static EAskSaveResult AskSaveChanges()
+{
+#if 1
+ static ModalFilterUPP filterProc = NewModalFilterUPP(SaveChangesFilter);
+
+ AlertStdAlertParamRec params;
+ params.movable = true;
+ params.helpButton = false;
+ params.filterProc = filterProc;
+ params.defaultText = "\pSave";
+ params.cancelText = "\pCancel";
+ params.otherText = "\pDon't Save";
+ params.defaultButton = kSaveBtn;
+ params.cancelButton = kCancelBtn;
+ params.position = kWindowAlertPositionParentWindowScreen;
+
+ short item = kSaveBtn;
+ sInDialog = true;
+ OSErr err = StandardAlert(kAlertStopAlert, "\pDo you want to save your game before quitting?", "\p", &params, &item);
+ ASSERT(err == noErr); // seems kind of pointless to throw
+ sInDialog = false;
+
+ EAskSaveResult result;
+ if (item == kSaveBtn)
+ result = kSaveChanges;
+ else if (item == kDontSaveBtn)
+ result = kDontSave;
+ else
+ result = kCancelSave;
+
+ return result;
+
+#else
+ NavDialogOptions options;
+ OSStatus err = NavGetDefaultDialogOptions(&options);
+ ASSERT(err == noErr); // seems kind of pointless to throw
+
+ NavAskSaveChangesResult reply = kSaveChanges;
+ if (err == noErr)
+ {
+ std::string name = "foobar";
+ UInt32 length = std::min(name.size(), sizeof(options.savedFileName) - 1);
+ BlockMoveData(name.c_str(), options.savedFileName + 1, length);
+ options.savedFileName[0] = length;
+
+ err = NavAskSaveChanges(&options,
+ action,
+ &reply,
+ NULL,
+ 0UL);
+ ASSERT(err == noErr); // seems kind of pointless to throw
+ }
+
+ return (EAskSaveResult) reply;
+#endif
+}
+
+
+//---------------------------------------------------------------
+//
+// ConvertColor
+//
+//---------------------------------------------------------------
+static RGBColor ConvertColor(int c)
+{
+ ASSERT(c >= 0);
+ ASSERT(c < 16);
+
+ RGBColor color;
+
+ if (c == BLACK)
+ color = (**sColors).ctTable[15].rgb; // QD likes black and white swapped from DOS indices
+
+ else if (c == WHITE)
+ color = (**sColors).ctTable[0].rgb;
+ else
+ color = (**sColors).ctTable[c].rgb;
+
+ return color;
+}
+
+#if __MWERKS__
+#pragma mark -
+#endif
+
+// ============================================================================
+// class CApplication
+// ============================================================================
+class CApplication {
+
+//-----------------------------------
+// Initialization/Destruction
+//
+public:
+ ~CApplication();
+ CApplication();
+
+//-----------------------------------
+// API
+//
+public:
+ void Quit();
+
+ char GetChar();
+ // Block until a key is pressed.
+
+ bool PeekChar();
+ // Return true if a key event is on the event queue.
+
+ void Clear();
+ void SetCursor(int x, int y);
+ Point GetCursor() const {return mCursor;}
+ void SetChar(unsigned char ch);
+ void Print(const char* buffer);
+ void ShowCursor(bool show) {mShowCursor = show;}
+
+ void SetForeColor(const RGBColor& color);
+ void SetBackColor(const RGBColor& color);
+
+ void SetFont(const unsigned char *name) {this->DoSetFont(name, mPointSize);}
+ void SetFontSize(int size) {this->DoSetFont(mFontName, size);}
+
+//-----------------------------------
+// Internal Types
+//
+private:
+ struct SCell {
+ unsigned char ch;
+ RGBColor color;
+
+ SCell()
+ {
+ ch = ' ';
+ color.red = color.green = color.blue = 65535;
+ }
+ };
+
+ typedef vector<SCell> Line;
+
+//-----------------------------------
+// Internal API
+//
+private:
+ void DoAbout();
+ void DoClearToEOL();
+ void DoDrawCell(const Rect& area, const SCell& cell);
+ OSStatus DoEnableCommand(MenuRef menuH, MenuCommand command, MenuItemIndex index);
+ OSStatus DoHandleCommand(MenuCommand command);
+ void DoInitMenus();
+ void DoInitWindows();
+ char DoMungeChar(char inChar, UInt32 inKey, UInt32 modifiers) const;
+ OSStatus DoOpenMenu(MenuRef menuH);
+ void DoReadPrefs();
+ void DoRender();
+ void DoScroll();
+ void DoSetChar(unsigned char ch);
+ void DoSetFont(const unsigned char* name, int size);
+ void DoWritePrefs();
+
+ static pascal OSStatus DoKeyDown(EventHandlerCallRef handler, EventRef event, void* refCon);
+ static pascal OSStatus DoMenuEvent(EventHandlerCallRef handler, EventRef event, void* refCon);
+ static pascal OSErr DoQuit(const AppleEvent* event, AppleEvent* reply, SInt32 refCon);
+ static pascal OSStatus DoWindowEvent(EventHandlerCallRef handler, EventRef event, void* refCon);
+
+//-----------------------------------
+// Member Data
+//
+private:
+ WindowRef mWindow;
+ vector<Line> mLines;
+ char mChar;
+
+ Point mCursor;
+ bool mShowCursor;
+
+ RGBColor mForeColor;
+ RGBColor mBackColor;
+
+ Str255 mFontName;
+ int mPointSize;
+ UInt32 mNumFonts;
+ MenuRef mFontMenu;
+
+ short mFontNum;
+ int mAscent;
+ int mCellHeight;
+ int mCellWidth;
+};
+
+//---------------------------------------------------------------
+//
+// CApplication::~CApplication
+//
+//---------------------------------------------------------------
+CApplication::~CApplication()
+{
+ this->DoWritePrefs();
+
+ DisposeWindow(mWindow);
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::CApplication
+//
+//---------------------------------------------------------------
+CApplication::CApplication()
+{
+ InitCursor();
+
+ mCursor.h = 0;
+ mCursor.v = 0;
+ mShowCursor = false;
+ mChar = 0;
+
+ mNumFonts = 0;
+ mFontName[0] = '\0';
+ mFontNum = -2;
+ mPointSize = 0;
+ mAscent = 0;
+ mCellHeight = 0;
+ mCellWidth = 0;
+ mFontMenu = NULL;
+
+ mForeColor = kWhite;
+ mBackColor = kBlack;
+
+ try
+ {
+ // install a handler for the quit apple event
+ OSStatus err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP(DoQuit), 0, false);
+ ThrowIfOSErr(err, "Couldn't install the quit handler!");
+
+ // install a custom key handler
+ std::vector<EventTypeSpec> specs;
+ specs.push_back(CreateSpec(kEventClassKeyboard, kEventRawKeyDown));
+ specs.push_back(CreateSpec(kEventClassKeyboard, kEventRawKeyRepeat));
+
+ err = InstallApplicationEventHandler(NewEventHandlerUPP(DoKeyDown), specs.size(), &specs[0], this, NULL);
+ ThrowIfOSErr(err, "Couldn't install the key handler!");
+
+ // create the window
+ this->DoInitWindows();
+
+ // init the menus
+ this->DoInitMenus();
+
+ // update some state
+ this->DoReadPrefs();
+
+ this->Clear();
+
+ // show the window
+ ShowWindow(mWindow);
+ }
+ catch (const std::exception& e)
+ {
+ WarnUser(e.what());
+ ExitToShell();
+ }
+ catch (...)
+ {
+ WarnUser("Couldn't initialize the application.");
+ ExitToShell();
+ }
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::Quit
+//
+//---------------------------------------------------------------
+void CApplication::Quit()
+{
+ if (game_has_started)
+ {
+ EAskSaveResult answer = AskSaveChanges();
+
+ if (answer == kSaveChanges)
+ {
+ save_game(true);
+ }
+ else if (answer == kDontSave)
+ {
+ deinit_mac();
+ ExitToShell();
+ }
+ }
+ else
+ {
+ deinit_mac();
+ ExitToShell();
+ }
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::Clear
+//
+//---------------------------------------------------------------
+void CApplication::Clear()
+{
+ mLines.resize(kTermHeight);
+
+ for (int y = 0; y < mLines.size(); ++y)
+ {
+ Line& line = mLines[y];
+ line.resize(kTermWidth);
+
+ for (int x = 0; x < line.size(); ++x)
+ {
+ SCell& cell = line[x];
+
+ cell.ch = ' ';
+ cell.color = kWhite;
+ }
+ }
+
+ mCursor.h = 0;
+ mCursor.v = 0;
+
+ (void) InvalWindowRect(mWindow, &kBigRect);
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::SetCursor
+//
+//---------------------------------------------------------------
+void CApplication::SetCursor(int x, int y)
+{
+ ASSERT(x >= 0);
+ ASSERT(x < kTermWidth);
+ ASSERT(y >= 0);
+ ASSERT(y < kTermHeight);
+
+ if (x != mCursor.h || y != mCursor.v)
+ {
+ if (mShowCursor)
+ {
+ Rect area;
+ area.top = mCursor.v * mCellHeight;
+ area.bottom = area.top + mCellHeight;
+ area.left = mCursor.h * mCellWidth;
+ area.right = area.left + mCellWidth;
+
+ (void) InvalWindowRect(mWindow, &area);
+ }
+
+ mCursor.h = x;
+ mCursor.v = y;
+
+ if (mShowCursor)
+ {
+ Rect area;
+ area.top = mCursor.v * mCellHeight;
+ area.bottom = area.top + mCellHeight;
+ area.left = mCursor.h * mCellWidth;
+ area.right = area.left + mCellWidth;
+
+ (void) InvalWindowRect(mWindow, &area);
+ }
+ }
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::SetChar
+//
+//---------------------------------------------------------------
+void CApplication::SetChar(unsigned char ch)
+{
+ ASSERT(ch != '\t');
+ ASSERT(mLines.size() == kTermHeight);
+
+ const int TABSIZE = 8;
+
+ int x = mCursor.h; // this is from the ncurses source
+ int y = mCursor.v;
+
+ switch (ch) {
+ case '\t':
+ x += (TABSIZE - (x % TABSIZE));
+
+ // Space-fill the tab on the bottom line so that we'll get the
+ // "correct" cursor position.
+ if (x < kTermWidth)
+ {
+ char blank = ' ';
+
+ while (mCursor.h < x)
+ this->DoSetChar(blank);
+ break;
+
+ }
+ else
+ {
+ this->DoClearToEOL();
+ if (++y >= kTermHeight)
+ {
+ x = kTermWidth - 1;
+ y--;
+ this->DoScroll();
+ x = 0;
+ }
+ else
+ x = 0;
+ }
+ break;
+
+#if 1
+ case '\n':
+ case '\r':
+ this->DoClearToEOL();
+ if (++y >= kTermHeight)
+ {
+ y--;
+ this->DoScroll();
+ }
+ x = 0;
+ break;
+
+#else
+ case '\n':
+ this->DoClearToEOL();
+ if (++y >= kTermHeight)
+ {
+ y--;
+ this->DoScroll();
+ }
+ /* FALLTHRU */
+
+ case '\r':
+ x = 0;
+ break;
+#endif
+
+ case '\b':
+ if (x == 0)
+ return;
+ mCursor.h--;
+ this->DoSetChar(' ');
+ x--;
+ break;
+
+ case 159:
+ case 176:
+ case 177:
+ case 220:
+ case 239:
+ case 240:
+ case 247:
+ case 249:
+ case 250:
+ case 206:
+ case 254:
+ this->DoSetChar(ch);
+ return;
+ break;
+
+ default:
+ if (ch == '\0')
+ ch = ' ';
+
+// ASSERT(ch >= ' ');
+// ASSERT(ch <= '~');
+
+ if (ch >= ' ' && ch <= '~')
+ this->DoSetChar(ch);
+ else
+ this->DoSetChar('À');
+ return;
+ }
+
+ mCursor.h = x;
+ mCursor.v = y;
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::Print
+//
+//---------------------------------------------------------------
+void CApplication::Print(const char* buffer)
+{
+ ASSERT(buffer != NULL);
+
+ const char* p = buffer;
+
+ while (*p != '\0')
+ {
+ char ch = *p++;
+
+ this->SetChar(ch);
+ }
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::SetForeColor
+//
+//---------------------------------------------------------------
+void CApplication::SetForeColor(const RGBColor & color)
+{
+ if (color.red != mForeColor.red || color.green != mForeColor.green || color.blue != mForeColor.blue)
+ {
+ mForeColor = color;
+
+ (void) InvalWindowRect(mWindow, &kBigRect);
+ }
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::SetBackColor
+//
+//---------------------------------------------------------------
+void CApplication::SetBackColor(const RGBColor & color)
+{
+ if (color.red != mBackColor.red || color.green != mBackColor.green || color.blue != mBackColor.blue)
+ {
+ mBackColor = color;
+
+ (void) InvalWindowRect(mWindow, &kBigRect);
+ }
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::GetChar
+//
+//---------------------------------------------------------------
+char CApplication::GetChar()
+{
+ mChar = 0;
+ RunApplicationEventLoop();
+
+ (void) InvalWindowRect(mWindow, &kBigRect);
+
+ return mChar;
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::PeekChar
+//
+//---------------------------------------------------------------
+bool CApplication::PeekChar()
+{
+ EventTypeSpec specs[2];
+ specs[0] = CreateSpec(kEventClassKeyboard, kEventRawKeyDown);
+ specs[1] = CreateSpec(kEventClassKeyboard, kEventRawKeyRepeat);
+
+ EventRef event = NULL;
+ OSStatus err = ReceiveNextEvent(2, specs, kEventDurationNoWait, false, &event);
+
+ return err == noErr;
+}
+
+#if __MWERKS__
+#pragma mark ~
+#endif
+
+//---------------------------------------------------------------
+//
+// CApplication::DoAbout
+//
+//---------------------------------------------------------------
+void CApplication::DoAbout()
+{
+ AlertStdAlertParamRec params;
+ params.movable = true;
+ params.helpButton = false;
+ params.filterProc = NULL;
+ params.defaultText = (StringPtr) -1L; // use default (ie "OK") VERSION
+ params.cancelText = NULL;
+ params.otherText = NULL;
+ params.defaultButton = 1;
+ params.cancelButton = 0;
+ params.position = kWindowAlertPositionParentWindowScreen;
+
+ short item;
+ sInDialog = true;
+ OSErr err = StandardAlert(kAlertNoteAlert, "\p Crawl " VERSION, "\p© 1997-2002 by Linley Henzell\nMac Port by Jesse Jones", &params, &item);
+ ASSERT(err == noErr); // seems kind of pointless to throw
+ sInDialog = false;
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::DoClearToEOL
+//
+//---------------------------------------------------------------
+void CApplication::DoClearToEOL()
+{
+ ASSERT(mCursor.h < kTermWidth);
+ ASSERT(mCursor.v < kTermHeight);
+
+ Line& line = mLines[mCursor.v];
+ for (int x = mCursor.h; x < kTermWidth; ++x)
+ {
+ SCell& cell = line[x];
+ cell.ch = ' ';
+ }
+
+ Rect area;
+ area.top = mCursor.v * mCellHeight;
+ area.bottom = area.top + mCellHeight;
+ area.left = mCursor.h * mCellWidth;
+ area.right = 16000;
+
+ (void) InvalWindowRect(mWindow, &kBigRect);
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::DoDrawCell
+//
+//---------------------------------------------------------------
+void CApplication::DoDrawCell(const Rect& area, const SCell& cell)
+{
+ RGBForeColor(&cell.color);
+
+ switch (cell.ch) {
+ case 159: // fountain
+ DrawChar(area.left, area.top + mAscent, '´');
+ break;
+
+ case 177: // wall
+ case 176:
+ PaintRect(&area);
+ break;
+
+ case 247: // water/lava
+ PaintRect(&area);
+ break;
+
+ case 249: // floor
+ case 250: // undiscovered trap?
+// FillRect(&area, &qd.gray);
+ DrawChar(area.left, area.top + mAscent, '.');
+ break;
+
+ case 206:
+ case 254: // door
+ {
+ Rect temp = area;
+ InsetRect(&temp, 2, 2);
+ PaintRect(&temp);
+ }
+ break;
+
+ case 220: // altar
+ DrawChar(area.left, area.top + mAscent, 'Æ');
+ break;
+
+ case 239: // staircase to hell
+ case 240: // branch staircase
+ DrawChar(area.left, area.top + mAscent, '²');
+ break;
+
+ default:
+ DrawChar(area.left, area.top + mAscent, cell.ch);
+ }
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::DoEnableCommand
+//
+//---------------------------------------------------------------
+OSStatus CApplication::DoEnableCommand(MenuRef menuH, MenuCommand command, MenuItemIndex index)
+{
+ OSStatus err = noErr;
+
+ if (command == 'Abut')
+ {
+ EnableMenuItem(menuH, index);
+ }
+ else if (command == 'Save')
+ {
+ if (game_has_started)
+ EnableMenuItem(menuH, index);
+ else
+ DisableMenuItem(menuH, index);
+ }
+ else if (command >= 'Size' && command <= 'Size'+128)
+ {
+ if (mPointSize == command - 'Size')
+ SetItemMark(menuH, index, kCheckMarkChar);
+ else
+ SetItemMark(menuH, index, kNoMarkChar);
+ }
+ else if (command >= 'Font' && command <= 'Font'+128)
+ {
+ Str255 name;
+ GetMenuItemText(menuH, index, name);
+
+ if (EqualString(mFontName, name, true, true))
+ SetItemMark(menuH, index, kCheckMarkChar);
+ else
+ SetItemMark(menuH, index, noMark);
+ }
+ else
+ err = eventNotHandledErr;
+
+ return err;
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::DoHandleCommand
+//
+//---------------------------------------------------------------
+OSStatus CApplication::DoHandleCommand(MenuCommand command)
+{
+ OSStatus err = noErr;
+
+ if (command == 'Abut')
+ {
+ this->DoAbout();
+ }
+ else if (command == 'Save')
+ {
+ save_game(false);
+ }
+ else if (command >= 'Size' && command <= 'Size'+128)
+ {
+ int size = command - 'Size';
+
+ this->SetFontSize(size);
+ }
+ else if (command >= 'Font' && command <= 'Font'+128)
+ {
+ int index = command - 'Font';
+
+ Str255 name;
+ GetMenuItemText(mFontMenu, index, name);
+
+ this->SetFont(name);
+ }
+ else if (command == kHICommandQuit)
+ {
+ this->Quit();
+ }
+ else
+ err = eventNotHandledErr;
+
+ return err;
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::DoInitMenus
+//
+//---------------------------------------------------------------
+void CApplication::DoInitMenus()
+{
+ const int kFileMenu = 257;
+ const int kFontMenu = 258;
+ const int kSizeMenu = 259;
+
+ // add the About menu item
+ MenuRef menuH = NewMenu(0, "\pð");
+
+ OSStatus err = InsertMenuItemTextWithCFString(menuH, MacString("About Crawl"), 0, kMenuItemAttrIgnoreMeta, 'Abut');
+ ThrowIfOSErr(err, "Couldn't add the about menu item!");
+
+ InsertMenu(menuH, 0);
+
+ // create the File menu
+ err = CreateNewMenu(kFileMenu, kMenuAttrAutoDisable, &menuH);
+ ThrowIfOSErr(err, "Couldn't create the file menu!");
+
+ err = SetMenuTitleWithCFString(menuH, MacString("File"));
+ ThrowIfOSErr(err, "Couldn't set the file menu name!");
+
+ InsertMenu(menuH, 0);
+
+ // add the File menu items
+ err = AppendMenuItemTextWithCFString(menuH, MacString("Save"), kMenuItemAttrIgnoreMeta, 'Save', NULL);
+ ThrowIfOSErr(err, "Couldn't add the save menu item!");
+
+ err = SetMenuItemCommandKey(menuH, 1, false, 'S');
+ ThrowIfOSErr(err, "Couldn't set the save menu item's command key!");
+
+ // create the Font menu
+ err = CreateNewMenu(kFontMenu, kMenuAttrAutoDisable, &mFontMenu);
+ ThrowIfOSErr(err, "Couldn't create the font menu!");
+
+ err = CreateStandardFontMenu(mFontMenu, 0, 0, kNilOptions, &mNumFonts);
+ ThrowIfOSErr(err, "Couldn't initialize the font menu!");
+
+ err = SetMenuTitleWithCFString(mFontMenu, MacString("Font"));
+ ThrowIfOSErr(err, "Couldn't set the font menu name!");
+
+ UInt16 numItems = CountMenuItems(mFontMenu);
+ for (UInt16 index = 1; index <= numItems; ++index)
+ {
+ // set the font for each menu item so we're WYSIWYG
+ Str255 fontName;
+ GetMenuItemText(mFontMenu, index, fontName);
+
+ short fontNum;
+ GetFNum(fontName, &fontNum);
+
+ SetMenuItemFontID(mFontMenu, index, fontNum);
+
+ // set the command id so we can process the items (CreateStandardFontMenu
+ // leaves all of these at 0)
+ err = SetMenuItemCommandID(mFontMenu, index, 'Font' + index);
+ ThrowIfOSErr(err, "Couldn't set the font menu item's command ids!");
+ }
+
+ InsertMenu(mFontMenu, 0);
+
+ // create the Size menu
+ err = CreateNewMenu(kSizeMenu, kMenuAttrAutoDisable, &menuH);
+ ThrowIfOSErr(err, "Couldn't create the size menu!");
+
+ err = SetMenuTitleWithCFString(menuH, MacString("Size"));
+ ThrowIfOSErr(err, "Couldn't set the size menu name!");
+
+ InsertMenu(menuH, 0);
+
+ // add the Size menu items
+ const char* items[] = {"9", "10", "12", "16", "18", "20", "32", "48", "64", NULL};
+ int sizes[] = {9, 10, 12, 16, 18, 20, 32, 48, 64};
+ for (int i = 0; items[i] != NULL; ++i)
+ {
+ err = AppendMenuItemTextWithCFString(menuH, MacString(items[i]), kMenuItemAttrIgnoreMeta, 'Size' + sizes[i], NULL);
+ ThrowIfOSErr(err, "Couldn't add a size menu item!");
+ }
+
+ // install a custom menu handler
+ std::vector<EventTypeSpec> specs;
+ specs.push_back(CreateSpec(kEventClassCommand, kEventCommandProcess));
+ specs.push_back(CreateSpec(kEventClassCommand, kEventCommandUpdateStatus));
+ specs.push_back(CreateSpec(kEventClassMenu, kEventMenuOpening));
+
+ err = InstallApplicationEventHandler(NewEventHandlerUPP(DoMenuEvent), specs.size(), &specs[0], this, NULL);
+ ThrowIfOSErr(err, "Couldn't install the menu handlers!");
+
+ // draw the new menubar
+ DrawMenuBar();
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::DoInitWindows
+//
+//---------------------------------------------------------------
+void CApplication::DoInitWindows()
+{
+ // create the window
+ Rect bounds = {32, 32, 64, 64}; // we position properly later
+
+ WindowAttributes attrs = kWindowCollapseBoxAttribute | kWindowStandardHandlerAttribute;
+ OSStatus err = CreateNewWindow(kDocumentWindowClass, attrs, &bounds, &mWindow);
+ ThrowIfOSErr(err, "Couldn't create the window!");
+
+ // install a custom window handler
+ std::vector<EventTypeSpec> specs;
+ specs.push_back(CreateSpec(kEventClassWindow, kEventWindowDrawContent));
+
+ err = InstallWindowEventHandler(mWindow, NewEventHandlerUPP(DoWindowEvent), specs.size(), &specs[0], this, NULL);
+ ThrowIfOSErr(err, "Couldn't install the window event handler!");
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::DoKeyDown [static]
+//
+//---------------------------------------------------------------
+pascal OSStatus CApplication::DoKeyDown(EventHandlerCallRef handler, EventRef event, void* refCon)
+{
+ OSStatus err = eventNotHandledErr;
+
+ if (!sInDialog)
+ {
+ CApplication* thisPtr = static_cast<CApplication*>(refCon);
+
+ try
+ {
+ char ch;
+ (void) GetEventParameter(event, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(ch), NULL, &ch);
+
+ UInt32 key;
+ (void) GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL, sizeof(key), NULL, &key);
+
+ UInt32 modifiers;
+ (void) GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(modifiers), NULL, &modifiers);
+
+ if ((modifiers & cmdKey) == 0)
+ thisPtr->mChar = thisPtr->DoMungeChar(ch, key, modifiers);
+
+ if (thisPtr->mChar != 0)
+ QuitApplicationEventLoop();
+
+ err = noErr;
+ }
+ catch (const std::exception& e)
+ {
+ DEBUGSTR((std::string("Couldn't complete the operation (") + e.what() + ").").c_str());
+ err = eventNotHandledErr;
+ }
+ catch (...)
+ {
+ DEBUGSTR("Couldn't complete the operation.");
+ err = eventNotHandledErr;
+ }
+ }
+
+ return err;
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::DoMenuEvent [static]
+//
+//---------------------------------------------------------------
+pascal OSStatus CApplication::DoMenuEvent(EventHandlerCallRef handler, EventRef event, void* refCon)
+{
+ OSStatus err = noErr;
+ CApplication* thisPtr = static_cast<CApplication*>(refCon);
+
+ UInt32 kind = GetEventKind(event);
+ try
+ {
+ HICommand command;
+
+ if (kind == kEventCommandUpdateStatus)
+ {
+ err = GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, sizeof(command), NULL, &command);
+ ThrowIfOSErr(err, "Couldn't get the direct object in DoMenuEvent");
+
+ err = thisPtr->DoEnableCommand(command.menu.menuRef, command.commandID, command.menu.menuItemIndex);
+ }
+ else if (kind == kEventCommandProcess)
+ {
+ err = GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, sizeof(command), NULL, &command);
+ ThrowIfOSErr(err, "Couldn't get the direct object in DoMenuEvent");
+
+ err = thisPtr->DoHandleCommand(command.commandID);
+ }
+ else if (kind == kEventMenuOpening)
+ {
+ Boolean firstTime;
+ err = GetEventParameter(event, kEventParamMenuFirstOpen, typeBoolean, NULL, sizeof(firstTime), NULL, &firstTime);
+ ThrowIfOSErr(err, "Couldn't get the first open flag in DoMenuEvent");
+
+ if (firstTime) // only call the callbacks the first time we open the menu (during this drag)
+ {
+ MenuRef menuH;
+ err = GetEventParameter(event, kEventParamDirectObject, typeMenuRef, NULL, sizeof(MenuRef), NULL, &menuH);
+ ThrowIfOSErr(err, "Couldn't get the direct object in DoMenuEvent");
+
+ err = thisPtr->DoOpenMenu(menuH);
+ }
+ }
+ else
+ err = eventNotHandledErr;
+ }
+ catch (const std::exception& e)
+ {
+ DEBUGSTR((std::string("Couldn't complete the operation (") + e.what() + ").").c_str());
+ err = eventNotHandledErr;
+ }
+ catch (...)
+ {
+ DEBUGSTR("Couldn't complete the operation.");
+ err = eventNotHandledErr;
+ }
+
+ if (kind == kEventCommandProcess)
+ HiliteMenu(0);
+
+ return err;
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::DoMungeChar
+//
+//---------------------------------------------------------------
+char CApplication::DoMungeChar(char ch, UInt32 key, UInt32 modifiers) const
+{
+ switch (key) {
+ case kNumPad1Key:
+ if (modifiers & shiftKey)
+ ch = 'B';
+ else if (modifiers & controlKey)
+ ch = 2;
+ else
+ ch = 'b';
+ break;
+
+ case kNumPad2Key:
+ case kDownArrowKey:
+ if (modifiers & shiftKey)
+ ch = 'J';
+ else if (modifiers & controlKey)
+ ch = 10;
+ else
+ ch = 'j';
+ break;
+
+ case kNumPad3Key:
+ if (modifiers & shiftKey)
+ ch = 'N';
+ else if (modifiers & controlKey)
+ ch = 14;
+ else
+ ch = 'n';
+ break;
+
+ case kNumPad4Key:
+ case kLeftArrowKey:
+ if (modifiers & shiftKey)
+ ch = 'H';
+ else if (modifiers & controlKey)
+ ch = 8;
+ else
+ ch = 'h';
+ break;
+
+ case kNumPad5Key:
+ if (modifiers & shiftKey)
+ ch = '5';
+ else
+ ch = '.';
+ break;
+
+ case kNumPad6Key:
+ case kRightArrowKey:
+ if (modifiers & shiftKey)
+ ch = 'L';
+ else if (modifiers & controlKey)
+ ch = 12;
+ else
+ ch = 'l';
+ break;
+
+ case kNumPad7Key:
+ if (modifiers & shiftKey)
+ ch = 'Y';
+ else if (modifiers & controlKey)
+ ch = 25;
+ else
+ ch = 'y';
+ break;
+
+ case kNumPad8Key:
+ case kUpArrowKey:
+ if (modifiers & shiftKey)
+ ch = 'K';
+ else if (modifiers & controlKey)
+ ch = 11;
+ else
+ ch = 'k';
+ break;
+
+ case kNumPad9Key:
+ if (modifiers & shiftKey)
+ ch = 'U';
+ else if (modifiers & controlKey)
+ ch = 21;
+ else
+ ch = 'u';
+ break;
+ }
+
+ return ch;
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::DoOpenMenu
+//
+//---------------------------------------------------------------
+OSStatus CApplication::DoOpenMenu(MenuRef menuH)
+{
+ // select the curret font
+
+ return noErr;
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::DoQuit [static]
+//
+//---------------------------------------------------------------
+pascal OSErr CApplication::DoQuit(const AppleEvent* event, AppleEvent* reply, SInt32 refCon)
+{
+ CApplication* thisPtr = reinterpret_cast<CApplication*>(refCon);
+ thisPtr->Quit();
+
+ return noErr;
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::DoReadPrefs
+//
+//---------------------------------------------------------------
+void CApplication::DoReadPrefs()
+{
+ MacString appID("Crawl4");
+
+ // window location
+ Rect bounds;
+
+ MacString name("window_x");
+ Boolean existsX = false;
+ bounds.left = CFPreferencesGetAppIntegerValue(name, appID, &existsX);
+
+ name = MacString("window_y");
+ Boolean existsY = false;
+ bounds.top = CFPreferencesGetAppIntegerValue(name, appID, &existsY);
+
+ if (existsX && existsY)
+ {
+ bounds.right = bounds.left + 32; // DoSetFont will reset the window dimensions
+ bounds.bottom = bounds.top + 32;
+
+ OSStatus err = SetWindowBounds(mWindow, kWindowStructureRgn, &bounds);
+ ASSERT(err == noErr);
+ }
+ else
+ {
+ OSStatus err = RepositionWindow(mWindow, NULL, kWindowCenterOnMainScreen);
+ ASSERT(err == noErr);
+ }
+
+ // mFontName
+ name = MacString("font_name");
+
+ CFTypeRef dataRef = CFPreferencesCopyAppValue(name, appID);
+ if (dataRef != NULL && CFGetTypeID(dataRef) == CFStringGetTypeID())
+ {
+ MacString data(static_cast<CFStringRef>(dataRef));
+
+ Str255 fontName;
+ data.CopyTo(fontName, sizeof(fontName));
+ CFRelease(dataRef);
+
+ // mPointSize
+ name = MacString("font_size");
+ CFIndex fontSize = CFPreferencesGetAppIntegerValue(name, appID, NULL);
+ if (fontSize > 0)
+ this->DoSetFont(fontName, fontSize);
+ else
+ this->DoSetFont(fontName, 12);
+ }
+ else
+ this->DoSetFont("\pMonaco", 12);
+
+ // make sure the window isn't off-screen
+ Rect area;
+ OSStatus err = GetWindowGreatestAreaDevice(mWindow, kWindowStructureRgn, NULL, &area);
+ if (err == noErr)
+ {
+ err = GetWindowBounds(mWindow, kWindowDragRgn, &bounds);
+ if (err == noErr)
+ {
+ SectRect(&area, &bounds, &bounds);
+
+ int pixels = (bounds.right - bounds.left)*(bounds.bottom - bounds.top);
+ if (pixels < 64) // only move the window if there are fewer than 64 draggable pixels
+ {
+ err = ConstrainWindowToScreen(mWindow, kWindowStructureRgn, kWindowConstrainStandardOptions, NULL, NULL);
+ ASSERT(err == noErr);
+ }
+ }
+ }
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::DoRender
+//
+//---------------------------------------------------------------
+void CApplication::DoRender()
+{
+ ASSERT(mLines.size() == kTermHeight);
+
+ SetPortWindowPort(mWindow);
+
+ TextFont(mFontNum);
+ TextSize(mPointSize);
+
+ RGBBackColor(&mBackColor);
+ EraseRect(&kBigRect);
+
+ Rect area;
+ for (int y = 0; y < mLines.size(); ++y)
+ {
+ area.top = y*mCellHeight;
+ area.bottom = area.top + mCellHeight;
+ area.left = 0;
+ area.right = area.left + mCellWidth;
+
+ const Line& line = mLines[y];
+ ASSERT(line.size() == kTermWidth);
+
+ for (int x = 0; x < line.size(); ++x)
+ {
+ const SCell& cell = line[x];
+
+ this->DoDrawCell(area, cell);
+
+ if (x == mCursor.h && y == mCursor.v && mShowCursor)
+ {
+ ::RGBForeColor(&kWhite);
+ ::MoveTo(area.left + 1, area.top + mAscent);
+ ::Line(area.right - area.left - 2, 0);
+ }
+
+ area.left += mCellWidth;
+ area.right += mCellWidth;
+ }
+ }
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::DoSetChar
+//
+//---------------------------------------------------------------
+void CApplication::DoSetChar(unsigned char ch)
+{
+ ASSERT(mCursor.h < kTermWidth);
+ ASSERT(mCursor.v < kTermHeight);
+ ASSERT(mCursor.h >= 0);
+ ASSERT(mCursor.v >= 0);
+
+ int x = mCursor.h;
+
+ Line& line = mLines[mCursor.v];
+ ASSERT(line.size() == kTermWidth);
+
+ SCell& cell = line[x++];
+ cell.ch = ch;
+ cell.color = mForeColor;
+
+ Rect area;
+ area.top = mCursor.v * mCellHeight;
+ area.bottom = area.top + mCellHeight;
+ area.left = mCursor.h * mCellWidth;
+ area.right = area.left + mCellWidth;
+
+ (void) InvalWindowRect(mWindow, &kBigRect);
+
+ if (x >= kTermWidth)
+ {
+ if (++mCursor.v >= kTermHeight)
+ {
+ mCursor.v = kTermHeight - 1;
+ mCursor.h = kTermWidth - 1;
+ this->DoScroll();
+ }
+ x = 0;
+ }
+
+ mCursor.h = x;
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::DoScroll
+//
+//---------------------------------------------------------------
+void CApplication::DoScroll()
+{
+ mLines.erase(mLines.begin());
+
+ mLines.push_back(Line());
+ mLines.back().resize(kTermWidth);
+
+ (void) InvalWindowRect(mWindow, &kBigRect);
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::DoSetFont
+//
+//---------------------------------------------------------------
+void CApplication::DoSetFont(const unsigned char* name, int size)
+{
+ ASSERT(name != NULL);
+ ASSERT(size > 0);
+
+ short fontNum;
+ GetFNum(name, &fontNum);
+
+ if (fontNum != mFontNum || size != mPointSize)
+ {
+ BlockMoveData(name, mFontName, name[0] + 1);
+
+ mFontNum = fontNum;
+ mPointSize = size;
+
+ SetPortWindowPort(mWindow);
+ TextFont(mFontNum);
+ TextSize(mPointSize);
+
+ FontInfo info;
+ GetFontInfo(&info);
+
+ mCellHeight = info.ascent + info.descent;
+ mAscent = info.ascent;
+
+ short width = StringWidth("\pMMMMM"); // widMax is usually much too wide so we'll compute this ourselves...
+ mCellWidth = width/5 + 1;
+
+ Rect bounds;
+ bounds.top = 0;
+ bounds.left = 0;
+ bounds.bottom = mCellHeight * kTermHeight;
+ bounds.right = mCellWidth * kTermWidth;
+ SizeWindow(mWindow, bounds.right, bounds.bottom, false);
+
+ (void) InvalWindowRect(mWindow, &kBigRect);
+ }
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::DoWindowEvent [static]
+//
+//---------------------------------------------------------------
+pascal OSStatus CApplication::DoWindowEvent(EventHandlerCallRef handler, EventRef event, void* refCon)
+{
+ OSStatus err = noErr;
+ CApplication* thisPtr = static_cast<CApplication*>(refCon);
+
+ try
+ {
+ WindowRef window = NULL;
+ (void) GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(window), NULL, &window);
+ ASSERT(window == thisPtr->mWindow);
+
+ UInt32 kind = GetEventKind(event);
+ switch (kind) {
+// case kEventWindowBoundsChanging:
+// thisPtr->DoConstrainWindow(event);
+// break;
+
+ case kEventWindowDrawContent:
+ thisPtr->DoRender();
+ break;
+
+// case kEventWindowGetIdealSize:
+// case kEventWindowGetMaximumSize:
+// {
+// ::Point maxSize = thisPtr->OnGetMaxSize();
+// SetEventParameter(event, kEventParamDimensions, &maxSize);
+// }
+// break;
+
+// case kEventWindowGetMinimumSize:
+// {
+// ::Point minSize = thisPtr->OnGetMinSize();
+// SetEventParameter(event, kEventParamDimensions, &minSize);
+// }
+// break;
+
+ default:
+ err = eventNotHandledErr;
+ }
+ }
+ catch (const std::exception& e)
+ {
+ DEBUGSTR((std::string("Couldn't complete the operation (") + e.what() + ").").c_str());
+ err = eventNotHandledErr;
+ }
+ catch (...)
+ {
+ DEBUGSTR("Couldn't complete the operation.");
+ err = eventNotHandledErr;
+ }
+
+ return err;
+}
+
+
+//---------------------------------------------------------------
+//
+// CApplication::DoWritePrefs , , mWindow->location
+//
+//---------------------------------------------------------------
+void CApplication::DoWritePrefs()
+{
+ MacString appID("Crawl4");
+
+ // mFontName
+ MacString name("font_name");
+ MacString data(mFontName);
+ CFPreferencesSetAppValue(name, data, appID);
+
+ // mPointSize
+ name = MacString("font_size");
+ data = MacString(mPointSize);
+ CFPreferencesSetAppValue(name, data, appID);
+
+ // window location
+ Rect bounds;
+ OSStatus err = GetWindowBounds(mWindow, kWindowStructureRgn, &bounds);
+ if (err == noErr)
+ {
+ name = MacString("window_x");
+ data = MacString(bounds.left);
+ CFPreferencesSetAppValue(name, data, appID);
+
+ name = MacString("window_y");
+ data = MacString(bounds.top);
+ CFPreferencesSetAppValue(name, data, appID);
+ }
+
+ // flush
+ VERIFY(CFPreferencesAppSynchronize(appID));
+}
+
+#if __MWERKS__
+#pragma mark -
+#endif
+
+// ========================================================================
+// Non-ANSI Functions
+// ========================================================================
+
+//---------------------------------------------------------------
+//
+// stricmp
+//
+// Case insensitive string comparison (code is from MSL which
+// is why it looks so dorky).
+//
+//---------------------------------------------------------------
+int stricmp(const char* lhs, const char* rhs)
+{
+ ASSERT(lhs != NULL);
+ ASSERT(rhs != NULL);
+
+ const unsigned char* p1 = (unsigned char*) lhs - 1;
+ const unsigned char* p2 = (unsigned char*) rhs - 1;
+ unsigned long c1, c2;
+
+ while ((c1 = tolower(*++p1)) == (c2 = tolower(*++p2)))
+ if (c1 == '\0')
+ return (0);
+
+ return c1 - c2;
+}
+
+
+//---------------------------------------------------------------
+//
+// strlwr
+//
+// In place conversion to lower case.
+//
+//---------------------------------------------------------------
+char* strlwr(char* str)
+{
+ ASSERT(str != NULL);
+
+ for (int i = 0; i < strlen(str); ++i)
+ str[i] = tolower(str[i]);
+
+ return str;
+}
+
+
+//---------------------------------------------------------------
+//
+// itoa
+//
+// Converts an integer to a string (after liblinux.cc).
+//
+//---------------------------------------------------------------
+void itoa(int value, char* buffer, int radix)
+{
+ ASSERT(buffer != NULL);
+ ASSERT(radix == 10 || radix == 2);
+
+ if (radix == 10)
+ sprintf(buffer, "%i", value);
+
+ if (radix == 2)
+ { /* int to "binary string" */
+ unsigned int bitmask = 32768;
+ int ctr = 0;
+ int startflag = 0;
+
+ while (bitmask)
+ {
+ if (value & bitmask)
+ {
+ startflag = 1;
+ sprintf(buffer + ctr, "1");
+
+ }
+ else
+ {
+ if (startflag)
+ sprintf(buffer + ctr, "0");
+ }
+
+ bitmask = bitmask >> 1;
+ if (startflag)
+ ctr++;
+ }
+
+ if (!startflag) /* Special case if value == 0 */
+ sprintf((buffer + ctr++), "0");
+ buffer[ctr] = (char) NULL;
+ }
+}
+
+#if __MWERKS__
+#pragma mark -
+#endif
+
+// ========================================================================
+// Curses(?) Functions
+// ========================================================================
+
+//---------------------------------------------------------------
+//
+// window
+//
+//---------------------------------------------------------------
+void window(int x, int y, int lx, int ly)
+{
+ ASSERT(lx == kTermWidth); // window size is hard-coded
+ ASSERT(ly == kTermHeight);
+
+ gotoxy(x, y);
+}
+
+
+//---------------------------------------------------------------
+//
+// clrscr
+//
+//---------------------------------------------------------------
+void clrscr()
+{
+ ASSERT(sApp != NULL);
+
+ sApp->Clear();
+}
+
+
+//---------------------------------------------------------------
+//
+// textcolor
+//
+//---------------------------------------------------------------
+void textcolor(int c)
+{
+ ASSERT(c >= 0);
+ ASSERT(c < 16);
+ ASSERT(sApp != NULL);
+
+ RGBColor color = ConvertColor(c);
+ sApp->SetForeColor(color);
+}
+
+
+//---------------------------------------------------------------
+//
+// textbackground
+//
+//---------------------------------------------------------------
+void textbackground(int c)
+{
+ ASSERT(c >= 0);
+ ASSERT(c < 16);
+ ASSERT(sApp != NULL);
+
+ RGBColor color = ConvertColor(c);
+ sApp->SetBackColor(color);
+}
+
+
+//---------------------------------------------------------------
+//
+// gotoxy
+//
+//---------------------------------------------------------------
+void gotoxy(int x, int y)
+{
+ ASSERT(x >= 1);
+ ASSERT(y >= 1);
+ ASSERT(sApp != NULL);
+
+ sApp->SetCursor(x - 1, y - 1);
+}
+
+
+//---------------------------------------------------------------
+//
+// wherex
+//
+//---------------------------------------------------------------
+int wherex()
+{
+ ASSERT(sApp != NULL);
+
+ Point pos = sApp->GetCursor();
+
+ return pos.h + 1;
+}
+
+
+//---------------------------------------------------------------
+//
+// wherey
+//
+//---------------------------------------------------------------
+int wherey()
+{
+ ASSERT(sApp != NULL);
+
+ Point pos = sApp->GetCursor();
+
+ return pos.v + 1;
+}
+
+
+//---------------------------------------------------------------
+//
+// putch
+//
+//---------------------------------------------------------------
+void putch(char ch)
+{
+ ASSERT(sApp != NULL);
+
+ char buffer[2];
+
+ buffer[0] = ch;
+ buffer[1] = '\0';
+
+ sApp->SetChar(ch);
+// sApp->Print(buffer);
+}
+
+
+//---------------------------------------------------------------
+//
+// cprintf
+//
+//---------------------------------------------------------------
+void cprintf(const char* format,...)
+{
+ ASSERT(sApp != NULL);
+
+ char buffer[2048];
+
+ va_list argp;
+
+ va_start(argp, format);
+ vsprintf(buffer, format, argp);
+ va_end(argp);
+
+ sApp->Print(buffer);
+}
+
+
+//---------------------------------------------------------------
+//
+// kbhit
+//
+//---------------------------------------------------------------
+int kbhit()
+{
+ return sApp->PeekChar();
+}
+
+
+//---------------------------------------------------------------
+//
+// getche
+//
+//---------------------------------------------------------------
+char getche()
+{
+ char ch = getch();
+
+ if (ch != '\r')
+ putch(ch);
+
+ return ch;
+}
+
+
+//---------------------------------------------------------------
+//
+// getstr
+//
+//---------------------------------------------------------------
+void getstr(char* buffer, int bufferSize)
+{
+ ASSERT(buffer != NULL);
+ ASSERT(bufferSize > 1);
+
+ int index = 0;
+
+ while (index < bufferSize - 1)
+ {
+ char ch = getche();
+
+ if (ch == '\r')
+ break;
+ else if (ch == '\b' && index > 0)
+ --index;
+ else if (isprint(ch))
+ buffer[index++] = ch;
+ }
+
+ buffer[index] = '\0';
+}
+
+
+//---------------------------------------------------------------
+//
+// _setcursortype
+//
+//---------------------------------------------------------------
+void _setcursortype(int curstype)
+{
+ ASSERT(curstype == _NORMALCURSOR || curstype == _NOCURSOR);
+ ASSERT(sApp != NULL);
+
+ sApp->ShowCursor(curstype == _NORMALCURSOR);
+}
+
+
+//---------------------------------------------------------------
+//
+// getch
+//
+//---------------------------------------------------------------
+int getch()
+{
+ ASSERT(sApp != NULL);
+
+ return sApp->GetChar();
+}
+
+#if __MWERKS__
+#pragma mark -
+#endif
+
+// ========================================================================
+// Misc Functions
+// ========================================================================
+
+//---------------------------------------------------------------
+//
+// delay
+//
+//---------------------------------------------------------------
+void delay(int ms)
+{
+ ASSERT(ms >= 0);
+
+ usleep(1000*ms);
+}
+
+
+//---------------------------------------------------------------
+//
+// init_mac
+//
+//---------------------------------------------------------------
+void init_mac()
+{
+ ASSERT(sApp == NULL);
+
+ // Read in the color table
+ sColors = GetCTable(256);
+ if (sColors == NULL)
+ {
+ WarnUser("Couldn't load the colour table!");
+ ExitToShell();
+ }
+
+ // Create the application object
+ sApp = new CApplication;
+}
+
+
+//---------------------------------------------------------------
+//
+// deinit_mac
+//
+//---------------------------------------------------------------
+void deinit_mac()
+{
+ delete sApp;
+ sApp = NULL;
+}
+
+
+#endif // macintosh
diff --git a/trunk/source/libmac.h b/trunk/source/libmac.h
new file mode 100644
index 0000000000..4f4dd992ef
--- /dev/null
+++ b/trunk/source/libmac.h
@@ -0,0 +1,91 @@
+/*
+ * File: libmac.h
+ * Summary: Mac specific routines used by Crawl.
+ * Written by: Jesse Jones
+ *
+ * Change History (most recent first):
+ *
+ * <2> 5/25/02 JDJ Updated for Mach-O targets
+ * <1> 3/23/99 JDJ Created
+ */
+
+#ifndef LIBMAC_H
+#define LIBMAC_H
+
+#if macintosh
+
+#ifdef _BSD_SIZE_T_ // $$$ is there a better way to test for OS X?
+ #define OSX 1
+#else
+ #define OS9 1
+#endif
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if OSX
+ #include <unistd.h>
+#endif
+
+#define MAC_NUMBER_OF_LINES 30
+
+// constants
+const int _NORMALCURSOR = 1;
+const int _NOCURSOR = 0;
+
+
+// non-ANSI functions
+int stricmp(const char* lhs, const char* rhs);
+char* strlwr(char* str);
+void itoa(int n, char* buffer, int radix);
+
+#if !OSX
+ inline int random()
+ {
+ return rand();
+ }
+
+ inline void srandom(unsigned int seed)
+ {
+ srand(seed);
+ }
+
+ int open(const char* path, int openFlags, int permissions);
+ int open(const char* path, int openFlags, int permissions, int mysteryFlags);
+ int close(int desc);
+ int read(int desc, void *buffer, unsigned int bytes);
+ int write(int desc, const void *buffer, unsigned int bytes);
+ int unlink(const char* path);
+#endif
+
+
+// curses(?) functions
+void clrscr();
+void gotoxy(int x, int y);
+void textcolor(int c);
+void cprintf(const char* format,...);
+
+void window(int x, int y, int lx, int ly);
+int wherex();
+int wherey();
+void putch(char c);
+int kbhit();
+
+char getche();
+int getch();
+void getstr(char* buffer, int bufferSize);
+
+void textbackground(int c);
+void _setcursortype(int curstype);
+
+
+// misc functions
+void delay(int ms);
+
+void init_mac();
+void deinit_mac();
+
+
+#endif // macintosh
+#endif // LIBMAC_H
diff --git a/trunk/source/libutil.cc b/trunk/source/libutil.cc
new file mode 100644
index 0000000000..9be12392a7
--- /dev/null
+++ b/trunk/source/libutil.cc
@@ -0,0 +1,93 @@
+/*
+ * File: libutil.cc
+ * Summary: Functions that may be missing from some systems
+ *
+ * Change History (most recent first):
+ *
+ * <1> 2001/Nov/01 BWR Created
+ *
+ */
+
+#include "AppHdr.h"
+#include <stdio.h>
+#include <ctype.h>
+
+void get_input_line( char *const buff, int len )
+{
+ buff[0] = '\0'; // just in case
+
+#if defined(LINUX)
+ get_input_line_from_curses( buff, len ); // inplemented in liblinux.cc
+#elif defined(MAC) || defined(WIN32CONSOLE)
+ getstr( buff, len ); // implemented in libmac.cc
+#else
+ fgets( buff, len, stdin ); // much safer than gets()
+#endif
+
+ buff[ len - 1 ] = '\0'; // just in case
+
+ // Removing white space from the end in order to get rid of any
+ // newlines or carriage returns that any of the above might have
+ // left there (ie fgets especially). -- bwr
+ const int end = strlen( buff );
+ int i;
+
+ for (i = end - 1; i >= 0; i++)
+ {
+ if (isspace( buff[i] ))
+ buff[i] = '\0';
+ else
+ break;
+ }
+}
+
+// The old school way of doing short delays via low level I/O sync.
+// Good for systems like old versions of Solaris that don't have usleep.
+#ifdef NEED_USLEEP
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/unistd.h>
+
+void usleep(unsigned long time)
+{
+ struct timeval timer;
+
+ timer.tv_sec = (time / 1000000L);
+ timer.tv_usec = (time % 1000000L);
+
+ select(0, NULL, NULL, NULL, &timer);
+}
+#endif
+
+// Not the greatest version of snprintf, but a functional one that's
+// a bit safer than raw sprintf(). Note that this doesn't do the
+// special behaviour for size == 0, largely because the return value
+// in that case varies depending on which standard is being used (SUSv2
+// returns an unspecified value < 1, whereas C99 allows str == NULL
+// and returns the number of characters that would have been written). -- bwr
+#ifdef NEED_SNPRINTF
+
+#include <stdarg.h>
+#include <string.h>
+
+int snprintf( char *str, size_t size, const char *format, ... )
+{
+ va_list argp;
+ va_start( argp, format );
+
+ char buff[ 10 * size ]; // hopefully enough
+
+ vsprintf( buff, format, argp );
+ strncpy( str, buff, size );
+ str[ size - 1 ] = '\0';
+
+ int ret = strlen( str );
+ if ((unsigned int) ret == size - 1 && strlen( buff ) >= size)
+ ret = -1;
+
+ va_end( argp );
+
+ return (ret);
+}
+#endif
diff --git a/trunk/source/libutil.h b/trunk/source/libutil.h
new file mode 100644
index 0000000000..73f8a849cf
--- /dev/null
+++ b/trunk/source/libutil.h
@@ -0,0 +1,24 @@
+/*
+ * File: libutil.h
+ * Summary: System indepentant functions
+ *
+ * Change History (most recent first):
+ *
+ * <1> 2001/Nov/01 BWR Created
+ *
+ */
+
+#ifndef LIBUTIL_H
+#define LIBUTIL_H
+
+void get_input_line( char *const buff, int len );
+
+#ifdef NEED_USLEEP
+void usleep( unsigned long time );
+#endif
+
+#ifdef NEED_SNPRINTF
+int snprintf( char *str, size_t size, const char *format, ... );
+#endif
+
+#endif
diff --git a/trunk/source/libw32c.cc b/trunk/source/libw32c.cc
new file mode 100644
index 0000000000..26edc304f5
--- /dev/null
+++ b/trunk/source/libw32c.cc
@@ -0,0 +1,753 @@
+/*
+ * File: libw32c.cc
+ * Summary: Functions for windows32 console mode support
+ * Written by: Gordon Lipford
+ *
+ * Change History (most recent first):
+ *
+ * <2> 8 Mar 2001 GDL Rewrite to use low level IO
+ * <1> 1 Mar 2000 GDL Created
+ *
+ */
+
+// WINDOWS INCLUDES GO HERE
+/*
+ * Exclude parts of WINDOWS.H that are not needed
+ */
+#define NOCOMM /* Comm driver APIs and definitions */
+#define NOLOGERROR /* LogError() and related definitions */
+#define NOPROFILER /* Profiler APIs */
+#define NOLFILEIO /* _l* file I/O routines */
+#define NOOPENFILE /* OpenFile and related definitions */
+#define NORESOURCE /* Resource management */
+#define NOATOM /* Atom management */
+#define NOLANGUAGE /* Character test routines */
+#define NOLSTRING /* lstr* string management routines */
+#define NODBCS /* Double-byte character set routines */
+#define NOKEYBOARDINFO /* Keyboard driver routines */
+#define NOCOLOR /* COLOR_* color values */
+#define NODRAWTEXT /* DrawText() and related definitions */
+#define NOSCALABLEFONT /* Truetype scalable font support */
+#define NOMETAFILE /* Metafile support */
+#define NOSYSTEMPARAMSINFO /* SystemParametersInfo() and SPI_* definitions */
+#define NODEFERWINDOWPOS /* DeferWindowPos and related definitions */
+#define NOKEYSTATES /* MK_* message key state flags */
+#define NOWH /* SetWindowsHook and related WH_* definitions */
+#define NOCLIPBOARD /* Clipboard APIs and definitions */
+#define NOICONS /* IDI_* icon IDs */
+#define NOMDI /* MDI support */
+#define NOCTLMGR /* Control management and controls */
+#define NOHELP /* Help support */
+
+/*
+ * Exclude parts of WINDOWS.H that are not needed (Win32)
+ */
+#define WIN32_LEAN_AND_MEAN
+#define NONLS /* All NLS defines and routines */
+#define NOSERVICE /* All Service Controller routines, SERVICE_ equates, etc. */
+#define NOKANJI /* Kanji support stuff. */
+#define NOMCX /* Modem Configuration Extensions */
+#define _X86_ /* target architecture */
+
+#include <excpt.h>
+#include <stdarg.h>
+#include <windef.h>
+#include <winbase.h>
+#include <wingdi.h>
+#include <winuser.h>
+#include <winnls.h>
+#include <wincon.h>
+
+// END -- WINDOWS INCLUDES
+
+#include <string.h>
+#ifdef __BCPLUSPLUS__
+#include <stdio.h>
+#endif
+#include "AppHdr.h"
+#include "version.h"
+#include "defines.h"
+#include "view.h"
+
+char oldTitle[80];
+
+static HANDLE inbuf = NULL;
+static HANDLE outbuf = NULL;
+static int current_color = -1;
+static bool current_cursor = _NOCURSOR;
+// dirty line (sx,ex,y)
+static int chsx=0, chex=0, chy=-1;
+// cursor position (start at 0,0 --> 1,1)
+static int cx=0, cy=0;
+
+//static FILE *foo = NULL; //DEBUG
+
+// and now, for the screen buffer
+static CHAR_INFO screen[80 * WIN_NUMBER_OF_LINES];
+static COORD screensize;
+#define SCREENINDEX(x,y) (x)+80*(y)
+static bool buffering = false;
+static const char *windowTitle = "Crawl " VERSION;
+
+// we can do straight translation of DOS color to win32 console color.
+#define WIN32COLOR(col) (WORD)(col)
+static void writeChar(char c);
+static void bFlush(void);
+static void _setcursortype_internal(int curstype);
+static void init_colors(void);
+static DWORD crawlColorData[16] =
+// BGR data, easier to put in registry
+{
+ 0x00000000, // BLACK
+ 0x00ff00cd, // BLUE
+ 0x0046b964, // GREEN
+ 0x00b4b400, // CYAN
+ 0x000085ff, // RED
+ 0x00ee82ee, // MAGENTA
+ 0x005a6fcd, // BROWN
+ 0x00c0c0c0, // LT GREY
+ 0x00808080, // DK GREY
+ 0x00ff8600, // LT BLUE
+ 0x0000ff85, // LT GREEN
+ 0x00ffff00, // LT CYAN
+ 0x000000ff, // LT RED
+ 0x00bf7091, // LT MAGENTA
+ 0x0000ffff, // YELLOW
+ 0x00ffffff // WHITE
+};
+
+//#define TIMING_INFO
+#ifdef TIMING_INFO
+
+#include <time.h>
+#include "message.h"
+
+// TIMING info
+static int ncalls[6] = { 0,0,0,0,0,0 };
+static double runavg[6] = { 0.0,0.0,0.0,0.0,0.0,0.0 };
+static int oob[6] = { 0,0,0,0,0,0 };
+static int dlen[6] = { 0,0,0,0,0,0 };
+static LARGE_INTEGER t1, t2;
+
+static void addcall(int i, LARGE_INTEGER &tm1, LARGE_INTEGER &tm2)
+{
+ double d = tm2.QuadPart - tm1.QuadPart;
+
+ runavg[i] = (runavg[i] * ncalls[i] + d) / (ncalls[i] + 1);
+ ncalls[i] ++;
+
+ // oob
+ if (ncalls[i] > 10)
+ {
+ if (d > 1.4*runavg[i])
+ oob[i] ++;
+ }
+}
+
+#define CLOCKIN {QueryPerformanceCounter(&t1);}
+#define CLOCKOUT(x) {QueryPerformanceCounter(&t2); \
+ addcall((x), t1, t2);}
+
+static char *descrip[] = {
+ "bflush:WriteConsoleOutput",
+ "_setCursorType:SetConsoleCursorInfo",
+ "gotoxy:SetConsoleCursorPosition",
+ "textcolor:SetConsoleTextAttribute",
+ "cprintf:WriteConsole",
+ "getch:ReadConsoleInput"
+};
+
+void print_timings(void)
+{
+ int i;
+ char s[100];
+
+ LARGE_INTEGER cps;
+ QueryPerformanceFrequency(&cps);
+
+ sprintf(s, "Avg (#/oob), CpS = %.1lf", cps.QuadPart);
+ mpr(s);
+ for(i=0; i<3; i++)
+ {
+ int dl = 0;
+ if (ncalls[i] > 0)
+ dl = dlen[i] / ncalls[i];
+ sprintf(s, "%-40s %.1f us (%d/%d), avg dlen = %d", descrip[i],
+ (1000000.0 * runavg[i]) / cps.QuadPart, ncalls[i], oob[i], dl);
+ mpr(s);
+ }
+}
+
+#else
+
+#define CLOCKIN
+#define CLOCKOUT(x)
+
+void print_timings()
+{ ; }
+
+#endif // TIMING INFO
+
+void writeChar(char c)
+{
+ bool noop = true;
+ PCHAR_INFO pci;
+
+ // check for CR: noop
+ if (c == 0x0D)
+ return;
+
+ // check for newline
+ if (c == 0x0A)
+ {
+ // must flush current buffer
+ bFlush();
+
+ // reposition
+ gotoxy(1, cy+2);
+
+ return;
+ }
+
+ int tc = WIN32COLOR(current_color);
+ pci = &screen[SCREENINDEX(cx,cy)];
+
+ // is this a no-op?
+ if (pci->Char.AsciiChar != c)
+ noop = false;
+ else if (pci->Attributes != tc && c != ' ')
+ noop = false;
+
+ if (!noop)
+ {
+ // write the info and update the dirty area
+ pci->Char.AsciiChar = c;
+ pci->Attributes = tc;
+
+ if (chy < 0)
+ chsx = cx;
+ chy = cy;
+ chex = cx;
+
+ // if we're not buffering, flush
+ if (!buffering)
+ bFlush();
+ }
+
+ // update x position
+ cx += 1;
+ if (cx >= 80) cx = 80;
+}
+
+void bFlush(void)
+{
+ COORD source;
+ SMALL_RECT target;
+
+ // see if we have a dirty area
+ if (chy < 0)
+ return;
+
+ // set up call
+ source.X = chsx;
+ source.Y = chy;
+
+ target.Left = chsx;
+ target.Top = chy;
+ target.Right = chex;
+ target.Bottom = chy;
+
+ CLOCKIN
+ WriteConsoleOutput(outbuf, screen, screensize, source, &target);
+ CLOCKOUT(0)
+
+ chy = -1;
+
+ // if cursor is not NOCURSOR, update screen
+ if (current_cursor != _NOCURSOR)
+ {
+ COORD xy;
+ xy.X = cx;
+ xy.Y = cy;
+ CLOCKIN
+ if (SetConsoleCursorPosition(outbuf, xy) == 0)
+ fputs("SetConsoleCursorPosition() failed!", stderr);
+ CLOCKOUT(2)
+ }
+}
+
+
+void setStringInput(bool value)
+{
+ DWORD inmodes, outmodes;
+ if (value == TRUE)
+ {
+ inmodes = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT;
+ outmodes = ENABLE_PROCESSED_OUTPUT;
+ }
+ else
+ {
+ inmodes = NULL;
+ outmodes = 0;
+ }
+
+ if ( SetConsoleMode( inbuf, inmodes ) == 0) {
+ fputs("Error initialising console input mode.", stderr);
+ exit(0);
+ }
+
+ if ( SetConsoleMode( outbuf, outmodes ) == 0) {
+ fputs("Error initialising console output mode.", stderr);
+ exit(0);
+ }
+
+ // now flush it
+ FlushConsoleInputBuffer( inbuf );
+}
+
+// this apparently only works for Win2K+ and ME+
+
+void init_colors(char *windowTitle)
+{
+ UNUSED( windowTitle );
+ int i;
+
+ // look up the Crawl shortcut
+
+ // if found, modify the colortable entries in the NT_CONSOLE_PROPS
+ // structure.
+
+ // if not found, quit.
+}
+
+void init_libw32c(void)
+{
+ inbuf = GetStdHandle( STD_INPUT_HANDLE );
+ outbuf = GetStdHandle( STD_OUTPUT_HANDLE );
+
+ if (inbuf == INVALID_HANDLE_VALUE || outbuf == INVALID_HANDLE_VALUE) {
+ fputs("Could not initialise libw32c console support.", stderr);
+ exit(0);
+ }
+
+ GetConsoleTitle( oldTitle, 78 );
+ SetConsoleTitle( "Crawl " VERSION );
+
+ init_colors(oldTitle);
+
+ // by default, set string input to false: use char-input only
+ setStringInput( false );
+ if (SetConsoleMode( outbuf, 0 ) == 0) {
+ fputs("Error initialising console output mode.", stderr);
+ exit(0);
+ }
+
+ // set up screen size
+ screensize.X = 80;
+ screensize.Y = get_number_of_lines();
+
+ // initialise text color
+ textcolor(DARKGREY);
+
+ // initialise cursor to NONE.
+ _setcursortype_internal(_NOCURSOR);
+
+ // buffering defaults to ON -- very important!
+ setBuffering(true);
+
+ //DEBUG
+ //foo = fopen("debug.txt", "w");
+}
+
+void deinit_libw32c(void)
+{
+ // don't do anything if we were never initted
+ if (inbuf == NULL || outbuf == NULL)
+ return;
+
+ // restore console attributes for normal function
+ setStringInput(true);
+
+ // set cursor and normal textcolor
+ _setcursortype_internal(_NORMALCURSOR);
+ textcolor(DARKGREY);
+
+ // finally, restore title
+ SetConsoleTitle( oldTitle );
+}
+
+// we don't take our cues from Crawl. Cursor is shown
+// only on input.
+void _setcursortype(int curstype)
+{
+ UNUSED( curstype );
+ ;
+}
+
+
+void _setcursortype_internal(int curstype)
+{
+ CONSOLE_CURSOR_INFO cci;
+
+ if (curstype == current_cursor)
+ return;
+
+ cci.dwSize = 5;
+ cci.bVisible = (bool)curstype;
+ current_cursor = curstype;
+ CLOCKIN
+ SetConsoleCursorInfo( outbuf, &cci );
+ CLOCKOUT(1)
+
+ // now, if we just changed from NOCURSOR to CURSOR,
+ // actually move screen cursor
+ if (current_cursor != _NOCURSOR)
+ gotoxy(cx+1, cy+1);
+}
+
+void clrscr(void)
+{
+ int x,y;
+ COORD source;
+ SMALL_RECT target;
+
+ const int num_lines = get_number_of_lines();
+
+ PCHAR_INFO pci = screen;
+
+ for(x=0; x<80; x++)
+ {
+ for(y=0; y<num_lines; y++)
+ {
+ pci->Char.AsciiChar = ' ';
+ pci->Attributes = 0;
+ pci++;
+ }
+ }
+
+ source.X = 0;
+ source.Y = 0;
+ target.Left = 0;
+ target.Top = 0;
+ target.Right = 79;
+ target.Bottom = num_lines - 1;
+
+ WriteConsoleOutput(outbuf, screen, screensize, source, &target);
+
+ // reset cursor to 1,1 for convenience
+ gotoxy(1,1);
+}
+
+void gotoxy(int x, int y)
+{
+ const int num_lines = get_number_of_lines();
+
+ // always flush on goto
+ bFlush();
+
+ // bounds check
+ if (x<1)
+ x=1;
+ if (x>80)
+ x=80;
+ if (y<1)
+ y=1;
+ if (y>num_lines)
+ y=num_lines;
+
+ // change current cursor
+ cx = x-1;
+ cy = y-1;
+
+ // if cursor is not NOCURSOR, update screen
+ if (current_cursor != _NOCURSOR)
+ {
+ COORD xy;
+ xy.X = cx;
+ xy.Y = cy;
+ CLOCKIN
+ if (SetConsoleCursorPosition(outbuf, xy) == 0)
+ fputs("SetConsoleCursorPosition() failed!", stderr);
+ CLOCKOUT(2)
+ }
+}
+
+void textcolor(int c)
+{
+ // change current color used to stamp chars
+ current_color = c;
+}
+
+static void cprintf_aux(const char *s)
+{
+ // early out -- not initted yet
+ if (outbuf == NULL)
+ {
+ printf(s);
+ return;
+ }
+
+ // turn buffering ON (temporarily)
+ bool oldValue = buffering;
+ setBuffering(true);
+
+ // loop through string
+ char *p = (char *)s;
+ while(*p)
+ {
+ if (p[0] == '%' && p[1] == '%')
+ {
+ p++;
+ continue;
+ }
+ writeChar(*p++);
+ }
+
+ // reset buffering
+ setBuffering(oldValue);
+
+ // flush string
+ bFlush();
+}
+
+void cprintf(const char *format, ...)
+{
+ va_list argp;
+ char buffer[4096]; // one could hope it's enough
+
+ va_start( argp, format );
+
+ vsprintf(buffer, format, argp);
+ cprintf_aux(buffer);
+
+ va_end(argp);
+}
+
+void window(int x, int y, int lx, int ly)
+{
+ // do nothing
+ UNUSED( x );
+ UNUSED( y );
+ UNUSED( lx );
+ UNUSED( ly );
+}
+
+int wherex(void)
+{
+ return cx+1;
+}
+
+int wherey(void)
+{
+ return cy+1;
+}
+
+void putch(char c)
+{
+ // special case: check for '0' char: map to space
+ if (c==0)
+ c = ' ';
+
+ writeChar(c);
+}
+
+// translate virtual keys
+
+static int vk_tr[4][9] = // virtual key, unmodified, shifted, control
+ {
+ { VK_END, VK_DOWN, VK_NEXT, VK_LEFT, VK_CLEAR, VK_RIGHT, VK_HOME, VK_UP, VK_PRIOR },
+ { 'b', 'j', 'n', 'h', '.', 'l', 'y', 'k', 'u' },
+ { '1', '2', '3', '4', '5', '6', '7', '8', '9' },
+ { 2, 10, 14, 8, 0, 12, 25, 11, 21 },
+ };
+
+int vk_translate( WORD VirtCode, CHAR c, DWORD cKeys)
+{
+ bool shftDown = false;
+ bool ctrlDown = false;
+
+ // DEBUG
+ //fprintf(foo, "Received code %d (%c) with modifiers: %d\n", VirtCode, c, cKeys);
+
+ // step 1 - we don't care about shift or control
+ if (VirtCode == VK_SHIFT || VirtCode == VK_CONTROL)
+ return 0;
+
+ // step 2 - translate the <Esc> key to 0x1b
+ if (VirtCode == VK_ESCAPE)
+ return 0x1b; // same as it ever was..
+
+ // step 3 - translate shifted or controlled numeric keypad keys
+ if (cKeys & SHIFT_PRESSED)
+ shftDown = true;
+ if (cKeys & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
+ {
+ ctrlDown = true; // control takes precedence over shift
+ shftDown = false;
+ }
+
+ // hack - translate ^P and ^Q since 16 and 17 are taken by CTRL and SHIFT
+ if ((VirtCode == 80 || VirtCode == 81) && ctrlDown)
+ return VirtCode & 0x003f; // shift back down
+
+ if (VirtCode == VK_DELETE && !ctrlDown) // assume keypad '.'
+ return '.';
+
+ // see if we're a vkey
+ int mkey;
+ for(mkey = 0; mkey<9; mkey++)
+ if (VirtCode == vk_tr[0][mkey]) break;
+
+ // step 4 - just return the damn key.
+ if (mkey == 9)
+ return (int)c;
+
+ // now translate the key. Dammit. This is !@#$(*& garbage.
+ if (shftDown)
+ return vk_tr[2][mkey];
+ // control key?
+ if (ctrlDown)
+ return vk_tr[3][mkey];
+ return vk_tr[1][mkey];
+}
+
+int getch(void)
+{
+ INPUT_RECORD ir;
+ DWORD nread;
+ int key = 0;
+ static int repeat_count = 0;
+ static int repeat_key = 0;
+
+ KEY_EVENT_RECORD *kr;
+
+ // handle key repeats
+ if (repeat_count > 0)
+ {
+ repeat_count -= 1;
+ return repeat_key;
+ }
+
+ bool oldValue = current_cursor;
+ _setcursortype_internal(_NORMALCURSOR);
+
+ while(1)
+ {
+ CLOCKIN
+ if (ReadConsoleInput( inbuf, &ir, 1, &nread) == 0)
+ fputs("Error in ReadConsoleInput()!", stderr);
+ CLOCKOUT(5)
+ if (nread > 0)
+ {
+ // ignore if it isn't a keyboard event.
+ if (ir.EventType == KEY_EVENT)
+ {
+ kr = &(ir.Event.KeyEvent);
+ // ignore if it is a 'key up' - we only want 'key down'
+ if (kr->bKeyDown == true)
+ {
+ key = vk_translate( kr->wVirtualKeyCode, kr->uChar.AsciiChar, kr->dwControlKeyState );
+ if (key > 0)
+ {
+ repeat_count = kr->wRepeatCount - 1;
+ repeat_key = key;
+ break;
+ }
+ }
+ }
+ }
+ }
+ // DEBUG
+ //fprintf(foo, "getch() returning %02x (%c)\n", key, key);
+
+ _setcursortype_internal(oldValue);
+
+ return key;
+}
+
+int getche(void)
+{
+ // turn buffering off temporarily
+ bool oldValue = buffering;
+ setBuffering(false);
+
+ int val = getch();
+
+ if (val != 0)
+ putch(val);
+
+ // restore buffering value
+ setBuffering(oldValue);
+
+ return val;
+}
+
+int kbhit()
+{
+ // do nothing. We could use PeekConsoleInput, I suppose..
+ return 0;
+}
+
+void delay(int ms)
+{
+ Sleep((DWORD)ms);
+}
+
+void textbackground(int c)
+{
+ // do nothing
+ UNUSED( c );
+}
+
+int getConsoleString(char *buf, int maxlen)
+{
+ DWORD nread;
+ // set console input to line mode
+ setStringInput( true );
+
+ // force cursor
+ bool oldValue = current_cursor;
+ _setcursortype_internal(_NORMALCURSOR);
+
+ // set actual screen color to current color
+ SetConsoleTextAttribute( outbuf, WIN32COLOR(current_color) );
+
+ if (ReadConsole( inbuf, buf, (DWORD)(maxlen-1), &nread, NULL) == 0)
+ fputs("Error in ReadConsole()!", stderr);
+
+ // terminate string, then strip CRLF, replace with \0
+ buf[maxlen-1] = '\0';
+ int i;
+ for (i=(nread<3 ? 0 : nread-3); i<nread; i++)
+ {
+ if (buf[i] == 0x0A || buf[i] == 0x0D)
+ {
+ buf[i] = '\0';
+ break;
+ }
+ }
+
+ // reset console mode - also flushes if player has typed in
+ // too long of a name so we don't get silly garbage on return.
+ setStringInput( false );
+
+ // restore old cursor
+ _setcursortype_internal(oldValue);
+
+ // return # of bytes read
+ return (int)nread;
+}
+
+bool setBuffering( bool value )
+{
+ bool oldValue = buffering;
+
+ if (value == false)
+ {
+ // must flush buffer
+ bFlush();
+ }
+ buffering = value;
+
+ return oldValue;
+}
diff --git a/trunk/source/libw32c.h b/trunk/source/libw32c.h
new file mode 100644
index 0000000000..6a7cde1dd3
--- /dev/null
+++ b/trunk/source/libw32c.h
@@ -0,0 +1,46 @@
+#ifndef LIBW32C_H
+#define LIBW32C_H
+
+#define WIN_NUMBER_OF_LINES 25
+
+#include <string>
+// I think the following definition is all we need from STD namespace..
+#ifdef __IBMCPP__ // Borland 5.01 doesn't seem to need this
+typedef std::basic_string<char> string;
+#endif
+
+#include <excpt.h>
+#include <stdarg.h>
+
+#define _NORMALCURSOR true
+#define _NOCURSOR false
+
+void init_libw32c(void);
+void deinit_libw32c(void);
+void _setcursortype(int curstype);
+void clrscr(void);
+void gotoxy(int x, int y);
+void textcolor(int c);
+void cprintf( const char *format, ... );
+// void cprintf(const char *s);
+void setStringInput(bool value);
+bool setBuffering(bool value);
+int getConsoleString(char *buf, int maxlen);
+void print_timings(void);
+
+void window(int x, int y, int lx, int ly);
+int wherex(void);
+int wherey(void);
+void putch(char c);
+int getch(void);
+int getche(void);
+int kbhit(void);
+void delay(int ms);
+void textbackground(int c);
+
+inline void srandom(unsigned int seed) { srand(seed); }
+inline int random() { return rand(); }
+
+#endif
+
+
diff --git a/trunk/source/machdr.h b/trunk/source/machdr.h
new file mode 100644
index 0000000000..5bad24eab7
--- /dev/null
+++ b/trunk/source/machdr.h
@@ -0,0 +1,185 @@
+/*
+ * File: MacHdr.h
+ * Summary: OS specific stuff for inclusion into AppHdr.h.
+ * Written by: Jesse Jones
+ *
+ * Copyright © 1999 Jesse Jones.
+ *
+ * Change History (most recent first):
+ *
+ * <1> 5/30/99 JDJ Created.
+ */
+#ifndef MACHDR_H
+#define MACHDR_H
+
+#pragma check_header_flags on
+
+
+// ===================================================================================
+// MSL Defines
+// ===================================================================================
+#include <ansi_parms.h>
+
+#ifndef __dest_os
+#define __dest_os __mac_os
+#endif
+
+#ifndef __MSL_LONGLONG_SUPPORT__
+#define __MSL_LONGLONG_SUPPORT__
+#endif
+
+#ifndef MSIPL_DEF_EXPLICIT
+#define MSIPL_DEF_EXPLICIT // prevent explicit from being defined away
+#endif
+
+#if __MWERKS__ >= 0x2000
+#define MSIPL_TEMPL_NEWSPEC 1 // enable null_template
+#endif
+
+
+// ===================================================================================
+// Universal headers
+// ===================================================================================
+#define OLDROUTINENAMES 0
+#define OLDROUTINELOCATIONS 0
+
+#define STRICT_WINDOWS 0
+#define STRICT_CONTROLS 0
+#define STRICT_LISTS 0
+#define STRICT_MENUS 0
+
+#define USE_OLD_INPUT_SPROCKET_LABELS 0
+#define USE_OLD_ISPNEED_STRUCT 0
+
+#if 1
+// #include <ADSP.h>
+// #include <AEObjects.h>
+// #include <AEPackObject.h>
+// #include <AERegistry.h>
+// #include <AEUserTermTypes.h>
+// #include <AIFF.h>
+#include <Aliases.h>
+#include <AppleEvents.h>
+// #include <AppleGuide.h>
+// #include <AppleScript.h>
+// #include <AppleTalk.h>
+// #include <ASDebugging.h>
+// #include <ASRegistry.h>
+#include <Balloons.h>
+// #include <CMApplication.h>
+// #include <CMComponent.h>
+// #include <CodeFragments.h>
+#include <ColorPicker.h>
+// #include <CommResources.h>
+// #include <Components.h>
+#include <ConditionalMacros.h>
+// #include <Connections.h>
+// #include <ConnectionTools.h>
+#include <Controls.h>
+// #include <ControlStrip.h>
+// #include <CRMSerialDevices.h>
+// #include <CTBUtilities.h>
+// #include <CursorCtl.h>
+// #include <CursorDevices.h>
+// #include <DatabaseAccess.h>
+// #include <DeskBus.h>
+#include <Devices.h>
+#include <Dialogs.h>
+// #include <Dictionary.h>
+// #include <DisAsmLookup.h>
+// #include <Disassembler.h>
+#include <DiskInit.h>
+// #include <Disks.h>
+#include <Displays.h>
+#include <Drag.h>
+// #include <Editions.h>
+// #include <ENET.h>
+// #include <EPPC.h>
+// #include <ErrMgr.h>
+#include <Errors.h>
+#include <Events.h>
+// #include <fenv.h>
+#include <Files.h>
+// #include <FileTransfers.h>
+// #include <FileTransferTools.h>
+// #include <FileTypesAndCreators.h>
+#include <Finder.h>
+// #include <FixMath.h>
+#include <Folders.h>
+#include <Fonts.h>
+// #include <fp.h>
+// #include <FragLoad.h>
+// #include <FSM.h>
+#include <Gestalt.h>
+// #include <HyperXCmd.h>
+// #include <Icons.h>
+// #include <ImageCodec.h>
+// #include <ImageCompression.h>
+// #include <IntlResources.h>
+// #include <Language.h>
+// #include <Lists.h>
+#include <LowMem.h>
+// #include <MachineExceptions.h>
+// #include <MacTCP.h>
+// #include <MediaHandlers.h>
+#include <Memory.h>
+#include <Menus.h>
+// #include <MIDI.h>
+#include <MixedMode.h>
+// #include <Movies.h>
+// #include <MoviesFormat.h>
+// #include <Notification.h>
+// #include <OSA.h>
+// #include <OSAComp.h>
+// #include <OSAGeneric.h>
+#include <OSUtils.h>
+#include <Packages.h>
+#include <Palettes.h>
+// #include <PictUtil.h>
+// #include <PictUtils.h>
+#include <PLStringFuncs.h>
+// #include <Power.h>
+// #include <PPCToolbox.h>
+#include <Printing.h>
+#include <Processes.h>
+#include <QDOffscreen.h>
+#include <Quickdraw.h>
+#include <QuickdrawText.h>
+// #include <QuickTimeComponents.h>
+#include <Resources.h>
+// #include <Retrace.h>
+// #include <ROMDefs.h>
+#include <Scrap.h>
+// #include <Script.h>
+// #include <SCSI.h>
+#include <SegLoad.h>
+// #include <Serial.h>
+// #include <ShutDown.h>
+// #include <Slots.h>
+// #include <Sound.h>
+// #include <SoundComponents.h>
+// #include <SoundInput.h>
+// #include <Speech.h>
+#include <StandardFile.h>
+// #include <Start.h>
+#include <Strings.h>
+// #include <Terminals.h>
+// #include <TerminalTools.h>
+#include <TextEdit.h>
+// #include <TextServices.h>
+#include <TextUtils.h>
+// #include <Threads.h>
+// #include <Timer.h>
+#include <ToolUtils.h>
+// #include <Translation.h>
+// #include <TranslationExtensions.h>
+#include <Traps.h>
+// #include <TSMTE.h>
+#include <Types.h>
+// #include <Unmangler.h>
+// #include <Video.h>
+#include <Windows.h>
+// #include <WorldScript.h>
+#endif // PRECOMPILE_SYSTEM_HEADERS
+
+#endif
diff --git a/trunk/source/macro.cc b/trunk/source/macro.cc
new file mode 100644
index 0000000000..4cd5c62ede
--- /dev/null
+++ b/trunk/source/macro.cc
@@ -0,0 +1,525 @@
+/*
+ * File: macro.cc
+ * Summary: Crude macro-capability
+ * Written by: Juho Snellman <jsnell@lyseo.edu.ouka.fi>
+ *
+ * Change History (most recent first):
+ *
+ * <3> 6/25/02 JS Completely rewritten
+ * <2> 6/13/99 BWR SysEnv.crawl_dir support
+ * <1> -/--/-- JS Created
+ */
+
+/*
+ * The macro-implementation works like this:
+ * - For generic game code, #define getch() getchm().
+ * - getchm() works by reading characters from an internal
+ * buffer. If none are available, new characters are read into
+ * the buffer with getch_mul().
+ * - getch_mul() reads at least one character, but will read more
+ * if available (determined using kbhit(), which should be defined
+ * in the platform specific libraries).
+ * - Before adding the characters read into the buffer, any macros
+ * in the sequence are replaced (see macro_add_buf_long for the
+ * details).
+ *
+ * (When the above text mentions characters, it actually means int).
+ */
+
+#include "AppHdr.h"
+
+#ifdef USE_MACROS
+#define MACRO_CC
+#include "macro.h"
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <map>
+#include <deque>
+
+#include <stdio.h> // for snprintf
+#include <ctype.h> // for tolower
+
+#include "externs.h"
+
+// for trim_string:
+#include "initfile.h"
+
+typedef std::deque<int> keyseq;
+typedef std::deque<int> keybuf;
+typedef std::map<keyseq,keyseq> macromap;
+
+static macromap Keymaps;
+static macromap Macros;
+
+static keybuf Buffer;
+
+/*
+ * Returns the name of the file that contains macros.
+ */
+static std::string get_macro_file()
+{
+ std::string s;
+
+ if (SysEnv.crawl_dir)
+ s = SysEnv.crawl_dir;
+
+ return (s + "macro.txt");
+}
+
+/*
+ * Takes as argument a string, and returns a sequence of keys described
+ * by the string. Most characters produce their own ASCII code. There
+ * are two special cases:
+ * \\ produces the ASCII code of a single \
+ * \{123} produces 123 (decimal)
+ */
+static keyseq parse_keyseq( std::string s )
+{
+ int state = 0;
+ keyseq v;
+ int num;
+
+ for (std::string::iterator i = s.begin(); i != s.end(); i++)
+ {
+ char c = *i;
+
+ switch (state)
+ {
+ case 0: // Normal state
+ if (c == '\\') {
+ state = 1;
+ } else {
+ v.push_back(c);
+ }
+ break;
+
+ case 1: // Last char is a '\'
+ if (c == '\\') {
+ state = 0;
+ v.push_back(c);
+ } else if (c == '{') {
+ state = 2;
+ num = 0;
+ }
+ // XXX Error handling
+ break;
+
+ case 2: // Inside \{}
+ if (c == '}') {
+ v.push_back(num);
+ state = 0;
+ } else if (c >= '0' && c <= '9') {
+ num = num * 10 + c - '0';
+ }
+ // XXX Error handling
+ break;
+ }
+ }
+
+ return (v);
+}
+
+/*
+ * Serializes a key sequence into a string of the format described
+ * above.
+ */
+static std::string vtostr( keyseq v )
+{
+ std::string s;
+
+ for (keyseq::iterator i = v.begin(); i != v.end(); i++)
+ {
+ if (*i < 32 || *i > 127) {
+ char buff[10];
+
+ snprintf( buff, sizeof(buff), "\\{%d}", *i );
+ s += std::string( buff );
+
+ // Removing the stringstream code because its highly
+ // non-portable. For starters, people and compilers
+ // are supposed to be using the <sstream> implementation
+ // (with the ostringstream class) not the old <strstream>
+ // version, but <sstream> is not as available as it should be.
+ //
+ // The strstream implementation isn't very standard
+ // either: some compilers require the "ends" marker,
+ // others don't (and potentially fatal errors can
+ // happen if you don't have it correct for the system...
+ // ie its hard to make portable). It also isn't a very
+ // good implementation to begin with.
+ //
+ // Everyone should have snprintf()... we supply a version
+ // in libutil.cc to make sure of that! -- bwr
+ //
+ // std::ostrstream ss;
+ // ss << "\\{" << *i << "}" << ends;
+ // s += ss.str();
+ } else if (*i == '\\') {
+ s += "\\\\";
+ } else {
+ s += *i;
+ }
+ }
+
+ return (s);
+}
+
+/*
+ * Add a macro (suprise, suprise).
+ */
+static void macro_add( macromap &mapref, keyseq key, keyseq action )
+{
+ mapref[key] = action;
+}
+
+/*
+ * Remove a macro.
+ */
+static void macro_del( macromap &mapref, keyseq key )
+{
+ mapref.erase( key );
+}
+
+
+/*
+ * Adds keypresses from a sequence into the internal keybuffer. Ignores
+ * macros.
+ */
+static void macro_buf_add( keyseq actions )
+{
+ for (keyseq::iterator i = actions.begin(); i != actions.end(); i++)
+ Buffer.push_back(*i);
+}
+
+/*
+ * Adds a single keypress into the internal keybuffer.
+ */
+static void macro_buf_add( int key )
+{
+ Buffer.push_back( key );
+}
+
+
+/*
+ * Adds keypresses from a sequence into the internal keybuffer. Does some
+ * O(N^2) analysis to the sequence to replace macros.
+ */
+static void macro_buf_add_long( keyseq actions )
+{
+ keyseq tmp;
+
+ // debug << "Adding: " << vtostr(actions) << endl;
+ // debug.flush();
+
+ // Check whether any subsequences of the sequence are macros.
+ // The matching starts from as early as possible, and is
+ // as long as possible given the first constraint. I.e from
+ // the sequence "abcdef" and macros "ab", "bcde" and "de"
+ // "ab" and "de" are recognized as macros.
+
+ while (actions.size() > 0)
+ {
+ tmp = actions;
+
+ while (tmp.size() > 0)
+ {
+ keyseq result = Keymaps[tmp];
+
+ // Found a macro. Add the expansion (action) of the
+ // macro into the buffer.
+ if (result.size() > 0) {
+ macro_buf_add( result );
+ break;
+ }
+
+ // Didn't find a macro. Remove a key from the end
+ // of the sequence, and try again.
+ tmp.pop_back();
+ }
+
+ if (tmp.size() == 0) {
+ // Didn't find a macro. Add the first keypress of the sequence
+ // into the buffer, remove it from the sequence, and try again.
+ macro_buf_add( actions.front() );
+ actions.pop_front();
+
+ } else {
+ // Found a macro, which has already been added above. Now just
+ // remove the macroed keys from the sequence.
+ for (unsigned int i = 0; i < tmp.size(); i++)
+ actions.pop_front();
+ }
+ }
+}
+
+/*
+ * Command macros are only applied from the immediate front of the
+ * buffer, and only when the game is expecting a command.
+ */
+static void macro_buf_apply_command_macro( void )
+{
+ keyseq tmp = Buffer;
+
+ // find the longest match from the start of the buffer and replace it
+ while (tmp.size() > 0)
+ {
+ keyseq result = Macros[tmp];
+
+ if (result.size() > 0)
+ {
+ // Found macro, remove match from front:
+ for (unsigned int i = 0; i < tmp.size(); i++)
+ Buffer.pop_front();
+
+ // Add macro to front:
+ for (keyseq::reverse_iterator k = result.rbegin(); k != result.rend(); k++)
+ Buffer.push_front(*k);
+
+ break;
+ }
+
+ tmp.pop_back();
+ }
+}
+
+/*
+ * Removes the earlies keypress from the keybuffer, and returns its
+ * value. If buffer was empty, returns -1;
+ */
+static int macro_buf_get( void )
+{
+ if (Buffer.size() == 0)
+ return (-1);
+
+ int key = Buffer.front();
+ Buffer.pop_front();
+
+ return (key);
+}
+
+/*
+ * Saves macros into the macrofile, overwriting the old one.
+ */
+void macro_save( void )
+{
+ std::ofstream f;
+ f.open( get_macro_file().c_str() );
+
+ f << "# WARNING: This file is entirely auto-generated." << std::endl
+ << std::endl << "# Key Mappings:" << std::endl;
+
+ for (macromap::iterator i = Keymaps.begin(); i != Keymaps.end(); i++)
+ {
+ // Need this check, since empty values are added into the
+ // macro struct for all used keyboard commands.
+ if ((*i).second.size() > 0)
+ {
+ f << "K:" << vtostr((*i).first) << std::endl
+ << "A:" << vtostr((*i).second) << std::endl << std::endl;
+ }
+ }
+
+ f << "# Command Macros:" << std::endl;
+
+ for (macromap::iterator i = Macros.begin(); i != Macros.end(); i++)
+ {
+ // Need this check, since empty values are added into the
+ // macro struct for all used keyboard commands.
+ if ((*i).second.size() > 0)
+ {
+ f << "M:" << vtostr((*i).first) << std::endl
+ << "A:" << vtostr((*i).second) << std::endl << std::endl;
+ }
+ }
+
+ f.close();
+}
+
+/*
+ * Reads as many keypresses as are available (waiting for at least one),
+ * and returns them as a single keyseq.
+ */
+static keyseq getch_mul( void )
+{
+ keyseq keys;
+ int a;
+
+ keys.push_back( a = getch() );
+
+ // The a == 0 test is legacy code that I don't dare to remove. I
+ // have a vague recollection of it being a kludge for conio support.
+ while ((kbhit() || a == 0)) {
+ keys.push_back( a = getch() );
+ }
+
+ return (keys);
+}
+
+/*
+ * Replacement for getch(). Returns keys from the key buffer if available.
+ * If not, adds some content to the buffer, and returns some of it.
+ */
+int getchm( void )
+{
+ int a;
+
+ // Got data from buffer.
+ if ((a = macro_buf_get()) != -1)
+ return (a);
+
+ // Read some keys...
+ keyseq keys = getch_mul();
+ // ... and add them into the buffer
+ macro_buf_add_long( keys );
+
+ return (macro_buf_get());
+}
+
+/*
+ * Replacement for getch(). Returns keys from the key buffer if available.
+ * If not, adds some content to the buffer, and returns some of it.
+ */
+int getch_with_command_macros( void )
+{
+ if (Buffer.size() == 0)
+ {
+ // Read some keys...
+ keyseq keys = getch_mul();
+ // ... and add them into the buffer (apply keymaps)
+ macro_buf_add_long( keys );
+ }
+
+ // Apply longest matching macro at front of buffer:
+ macro_buf_apply_command_macro();
+
+ return (macro_buf_get());
+}
+
+/*
+ * Flush the buffer. Later we'll probably want to give the player options
+ * as to when this happens (ex. always before command input, casting failed).
+ */
+void flush_input_buffer( int reason )
+{
+ if (Options.flush_input[ reason ])
+ Buffer.clear();
+}
+
+void macro_add_query( void )
+{
+ unsigned char input;
+ bool keymap = false;
+
+ mpr( "Command (m)acro or (k)eymap? ", MSGCH_PROMPT );
+ input = getch();
+ if (input == 0)
+ input = getch();
+
+ input = tolower( input );
+ if (input == 'k')
+ keymap = true;
+ else if (input == 'm')
+ keymap = false;
+ else
+ {
+ mpr( "Aborting." );
+ return;
+ }
+
+ // reference to the appropriate mapping
+ macromap &mapref = (keymap ? Keymaps : Macros);
+
+ snprintf( info, INFO_SIZE, "Input %s trigger key: ",
+ (keymap ? "keymap" : "macro") );
+
+ mpr( info, MSGCH_PROMPT );
+ keyseq key = getch_mul();
+
+ cprintf( "%s" EOL, (vtostr( key )).c_str() ); // echo key to screen
+
+ if (mapref[key].size() > 0)
+ {
+ snprintf( info, INFO_SIZE, "Current Action: %s",
+ (vtostr( mapref[key] )).c_str() );
+
+ mpr( info, MSGCH_WARN );
+ mpr( "Do you wish to (r)edefine, (c)lear, or (a)bort?", MSGCH_PROMPT );
+
+ input = getch();
+ if (input == 0)
+ input = getch();
+
+ input = tolower( input );
+ if (input == 'a' || input == ESCAPE)
+ {
+ mpr( "Aborting." );
+ return;
+ }
+ else if (input == 'c')
+ {
+ mpr( "Cleared." );
+ macro_del( mapref, key );
+ return;
+ }
+ }
+
+ mpr( "Input Macro Action: ", MSGCH_PROMPT );
+
+ // Using getch_mul() here isn't very useful... We'd like the
+ // flexibility to define multicharacter macros without having
+ // to resort to editing files and restarting the game. -- bwr
+ // keyseq act = getch_mul();
+
+ keyseq act;
+ char buff[4096];
+
+ get_input_line( buff, sizeof(buff) );
+
+ // convert c_str to keyseq
+ const int len = strlen( buff );
+ for (int i = 0; i < len; i++)
+ act.push_back( buff[i] );
+
+ macro_add( mapref, key, act );
+}
+
+
+/*
+ * Initializes the macros.
+ */
+int macro_init( void )
+{
+ std::string s;
+ std::ifstream f;
+ keyseq key, action;
+ bool keymap = false;
+
+ f.open( get_macro_file().c_str() );
+
+ while (f >> s)
+ {
+ trim_string(s); // remove white space from ends
+
+ if (s[0] == '#') {
+ continue; // skip comments
+
+ } else if (s.substr(0, 2) == "K:") {
+ key = parse_keyseq(s.substr(2));
+ keymap = true;
+
+ } else if (s.substr(0, 2) == "M:") {
+ key = parse_keyseq(s.substr(2));
+ keymap = false;
+
+ } else if (s.substr(0, 2) == "A:") {
+ action = parse_keyseq(s.substr(2));
+ macro_add( (keymap ? Keymaps : Macros), key, action );
+ }
+ }
+
+ return (0);
+}
+
+#endif
diff --git a/trunk/source/macro.h b/trunk/source/macro.h
new file mode 100644
index 0000000000..9266ae3c26
--- /dev/null
+++ b/trunk/source/macro.h
@@ -0,0 +1,40 @@
+/*
+ * File: macro.cc
+ * Summary: Crude macro-capability
+ * Written by: Juho Snellman <jsnell@lyseo.edu.ouka.fi>
+ *
+ * Change History (most recent first):
+ *
+ * <2> 6/25/02 JS Removed old cruft
+ * <1> -/--/-- JS Created
+ */
+
+#ifdef USE_MACROS
+
+#ifndef MACRO_H
+#define MACRO_H
+
+#ifndef MACRO_CC
+
+#undef getch
+#define getch() getchm()
+
+#endif
+
+int getchm(void); // keymaps applied (ie for prompts)
+int getch_with_command_macros(void); // keymaps and macros (ie for commands)
+
+void flush_input_buffer( int reason );
+
+void macro_add_query(void);
+int macro_init(void);
+void macro_save(void);
+
+#endif
+
+#else
+
+#define getch_with_command_macros() getch()
+#define flush_input_buffer(XXX) ;
+
+#endif
diff --git a/trunk/source/makefile b/trunk/source/makefile
new file mode 100644
index 0000000000..9e99a03c37
--- /dev/null
+++ b/trunk/source/makefile
@@ -0,0 +1,38 @@
+#Makefile chooser. Choose one:
+
+MAKEFILE = makefile.lnx
+#MAKEFILE = makefile.sgi
+#MAKEFILE = makefile.dos
+#MAKEFILE = makefile.emx
+#MAKEFILE = makefile.sol
+
+#jmf: number of concurrent jobs -- good value is (#_of_CPUs * 2) + 1
+# cuts build time a lot on multi-cpu machines
+OTHER=-j2
+
+all:
+ $(MAKE) $(OTHER) -f $(MAKEFILE) EXTRA_FLAGS='-O2 -fno-strength-reduce'
+
+noopt:
+ $(MAKE) $(OTHER) -f $(MAKEFILE)
+
+install:
+ $(MAKE) $(OTHER) -f $(MAKEFILE) install
+
+clean:
+ $(MAKE) $(OTHER) -f $(MAKEFILE) clean
+
+distclean:
+ $(MAKE) $(OTHER) -f $(MAKEFILE) distclean
+
+# WIZARD mode currently includes asserts, bounds checking, and item checking
+wizard:
+ $(MAKE) $(OTHER) -f $(MAKEFILE) debug EXTRA_FLAGS='-g -DWIZARD -DDEBUG -DDEBUG_ITEM_SCAN'
+
+# DEBUG mode includes WIZARD mode as well as copious debugging input
+debug:
+ $(MAKE) $(OTHER) -f $(MAKEFILE) debug EXTRA_FLAGS='-g -DFULLDEBUG -DWIZARD'
+
+# DO NOT DELETE THIS LINE -- $(MAKE) depend depends on it.
+
+
diff --git a/trunk/source/makefile.bor b/trunk/source/makefile.bor
new file mode 100644
index 0000000000..d90cf636d9
--- /dev/null
+++ b/trunk/source/makefile.bor
@@ -0,0 +1,53 @@
+#
+# Makefile for Borland C++ 5.5 free commandline tools
+#
+
+!include makefile.obj
+
+GAME = ..\crawl.exe
+
+all : $(GAME)
+
+.PHONY : clean
+.PHONY : debug
+.PHONY : noopt
+.PHONY : install
+.PHONY : wizard
+
+clean :
+ $(DEL) *.o
+
+debug :
+
+noopt :
+
+install :
+
+wizard :
+
+#
+# Borland C++ tools
+#
+CC = bcc32
+LINK = ilink32
+DEL = del
+
+#
+# windows defines, including windows version to make sure code runs on
+# all windows systems
+#
+WIN32DEFINES = WIN32CONSOLE;NEED_SPRINTF;WINVER=0x0400;_WIN32_WINNT=0x0400;__BCPLUSPLUS__
+
+#
+# Options
+#
+LINKOPTS = -Tpe -ap -c -x /V4.0
+CFLAGS = -I. -D$(WIN32DEFINES) -4 -a -k- -Oc -OS -Oi -Ov -H- -P -c
+NICEFLAGS = -w-8004
+DEBUGFLAGS = -v -y
+
+$(GAME) : $(OBJECTS) libw32c.o
+ $(LINK) $(LINKOPTS) c0x32.obj $?, $(GAME),, import32.lib cw32.lib
+
+.cc.o:
+ $(CC) $(CFLAGS) $(NICEFLAGS) -o$*.o $<
diff --git a/trunk/source/makefile.bsd b/trunk/source/makefile.bsd
new file mode 100644
index 0000000000..5f3a231285
--- /dev/null
+++ b/trunk/source/makefile.bsd
@@ -0,0 +1,62 @@
+# -*- Makefile -*- for Dungeon Crawl (linux)
+
+#APPNAME = crawl
+GAME = crawl
+
+# this file contains a list of the libraries.
+# it will make a variable called OBJECTS that contains all the libraries
+include makefile.obj
+
+OBJECTS += liblinux.o
+
+CXX = g++
+DELETE = rm -f
+COPY = cp
+OS_TYPE = BSD
+CFLAGS = -Wall -D$(OS_TYPE) $(EXTRA_FLAGS)
+LDFLAGS = -static -L/usr/lib
+MCHMOD = 711
+# INSTALLDIR = /usr/games
+INSTALLDIR = /tmp/CRAWLTEST/testdev
+LIB = -lncurses
+
+# Include for Linux
+INCLUDES = -I/usr/include/ncurses
+
+all: $(GAME)
+
+install: $(GAME)
+ $(COPY) $(GAME) ${INSTALLDIR}
+ chmod ${MCHMOD} ${INSTALLDIR}/$(GAME)
+
+clean:
+ $(DELETE) *.o
+
+distclean:
+ $(DELETE) *.o
+ $(DELETE) bones.*
+ $(DELETE) morgue.txt
+ $(DELETE) scores
+ $(DELETE) $(GAME)
+ $(DELETE) *.sav
+ $(DELETE) core
+ $(DELETE) *.0*
+ $(DELETE) *.lab
+
+
+$(GAME): $(OBJECTS)
+ ${CXX} ${LDFLAGS} $(INCLUDES) $(CFLAGS) $(OBJECTS) -o $(GAME) $(LIB)
+ strip $(GAME)
+ chmod ${MCHMOD} $(GAME)
+
+debug: $(OBJECTS)
+ ${CXX} ${LDFLAGS} $(INCLUDES) $(CFLAGS) $(OBJECTS) -o $(GAME) $(LIB)
+
+profile: $(OBJECTS)
+ ${CXX} -g -p ${LDFLAGS} $(INCLUDES) $(CFLAGS) $(OBJECTS) -o $(GAME) $(LIB)
+
+.cc.o:
+ ${CXX} ${CFLAGS} -c $< ${INCLUDE}
+
+.h.cc:
+ touch $@
diff --git a/trunk/source/makefile.dos b/trunk/source/makefile.dos
new file mode 100644
index 0000000000..869d6f8745
--- /dev/null
+++ b/trunk/source/makefile.dos
@@ -0,0 +1,53 @@
+# Make file for Dungeon Crawl (dos)
+
+# this file contains a list of the libraries.
+# it will make a variable called OBJECTS that contains all the libraries
+include makefile.obj
+
+# need .exe so make will find the right file
+APPNAME = crawl.exe
+CXX = gxx
+DELETE = del
+COPY = copy
+OS_TYPE = DOS
+CFLAGS = -D$(OS_TYPE) $(EXTRA_FLAGS)
+LDFLAGS = -Bc:/djgpp/contrib/pdcurs22/lib
+INSTALLDIR = c:\games\crawl
+# LIB = -lcurso -lpano
+
+all: $(APPNAME)
+
+install: $(APPNAME)
+ $(COPY) $(APPNAME) ${INSTALLDIR}
+
+clean:
+ $(DELETE) *.o
+
+distclean:
+ $(DELETE) *.o
+ $(DELETE) bones.*
+ $(DELETE) morgue.txt
+ $(DELETE) scores
+ $(DELETE) $(APPNAME)
+ $(DELETE) *.sav
+ $(DELETE) core
+ $(DELETE) *.0*
+ $(DELETE) *.lab
+
+$(APPNAME): $(OBJECTS)
+ ${CXX} ${LDFLAGS} $(INCLUDES) $(CFLAGS) $(OBJECTS) -o $(APPNAME) $(LIB)
+ strip $(APPNAME)
+
+debug: $(OBJECTS)
+ ${CXX} ${LDFLAGS} $(INCLUDES) $(CFLAGS) $(OBJECTS) -o $(APPNAME) $(LIB)
+
+profile: $(OBJECTS)
+ ${CXX} -g -p ${LDFLAGS} $(INCLUDES) $(CFLAGS) $(OBJECTS) -o $(APPNAME) $(LIB)
+
+.cc.o:
+ ${CXX} ${CFLAGS} -c $< ${INCLUDE}
+
+# I don't have touch for DOS, but if you do, you can put this back.
+#
+#.h.cc:
+# touch $@
diff --git a/trunk/source/makefile.emx b/trunk/source/makefile.emx
new file mode 100644
index 0000000000..13e99e47fe
--- /dev/null
+++ b/trunk/source/makefile.emx
@@ -0,0 +1,53 @@
+# Makefile for Dungeon Crawl (OS/2 EMX port)
+# 1998 (C) Alexey Guzeev, aga@russia.crosswinds.net
+# EMX is covered by GNU GPL
+# Dungeon Crawl is covered by Crawl GPL
+# OS/2 is a trademark of IBM Corp.
+# IBM is a trademark of IBM Corp.
+# :)
+
+# 1. make some directory, like \crawl
+# 2. make subdirectory for sources, \crawl\src
+# 3. put crawl sources in \crawl\src directory
+# 4. make directory \crawl\src current
+# 5. execute command 'dmake -B -r -f makefile.emx install'
+# 6. remove \crawl\src subdirectory with all contents
+# 7. delete \crawl\scoretable.exe - I don't know what it does :)
+# 8. run \crawl\crawl.exe & enjoy!
+
+
+CC = gcc
+CFLAGS = -Wall -O3 -MMD -Zmt -DUSE_EMX
+LIBS = -lvideo -lbsd
+AR = ar
+
+include makefile.obj
+
+OBJ = $(OBJECTS)
+
+
+all: crawl.exe scoretable.exe
+
+install: ..\crawl.exe ..\scoretable.exe
+
+crawl.a: $(OBJS)
+ $(AR) r crawl.a $(OBJS)
+
+..\crawl.exe: crawl.exe
+ +copy crawl.exe ..
+ emxbind -s ..\crawl.exe
+
+..\scoretable.exe: scoretable.exe
+ +copy scoretable.exe ..
+ emxbind -s ..\scoretable.exe
+clean:
+ +del *.o
+
+crawl.exe: crawl.a libemx.o
+ $(CC) -o crawl.exe crawl.a libemx.o $(LIBS)
+
+scoretable.exe: scoretab.o libemx.o
+ $(CC) -o scoretable.exe scoretab.o libemx.o $(LIBS)
+
+.cc.o:
+ $(CC) $(CFLAGS) -c $*.cc
diff --git a/trunk/source/makefile.lnx b/trunk/source/makefile.lnx
new file mode 100644
index 0000000000..2ebf926fcf
--- /dev/null
+++ b/trunk/source/makefile.lnx
@@ -0,0 +1,472 @@
+# -*- Makefile -*- for Dungeon Crawl (linux)
+
+#APPNAME = crawl
+GAME = crawl
+
+# this file contains a list of the libraries.
+# it will make a variable called OBJECTS that contains all the libraries
+include makefile.obj
+
+OBJECTS += liblinux.o
+
+# CXX = /usr/local/bin/g++
+CXX = g++
+DELETE = rm -f
+COPY = cp
+OS_TYPE = LINUX
+
+CFLAGS = -Wall -Wwrite-strings -Wstrict-prototypes \
+ -Wmissing-prototypes -Wmissing-declarations \
+ -g -D$(OS_TYPE) $(EXTRA_FLAGS)
+
+# LDFLAGS = -static
+MCHMOD = 2755
+# INSTALLDIR = /usr/games
+INSTALLDIR = /opt/crawl/bin
+LIB = -lncurses
+
+# Include for Linux
+INCLUDES = -I/usr/include/ncurses
+
+all: $(GAME)
+
+install: $(GAME)
+ $(COPY) $(GAME) ${INSTALLDIR}
+ chmod ${MCHMOD} ${INSTALLDIR}/$(GAME)
+
+clean:
+ $(DELETE) *.o
+
+distclean:
+ $(DELETE) *.o
+ $(DELETE) bones.*
+ $(DELETE) morgue.txt
+ $(DELETE) scores
+ $(DELETE) $(GAME)
+ $(DELETE) *.sav
+ $(DELETE) core
+ $(DELETE) *.0*
+ $(DELETE) *.lab
+
+
+$(GAME): $(OBJECTS)
+ ${CXX} ${LDFLAGS} $(INCLUDES) $(CFLAGS) $(OBJECTS) -o $(GAME) $(LIB)
+ chmod ${MCHMOD} $(GAME)
+
+debug: $(OBJECTS)
+ ${CXX} ${LDFLAGS} $(INCLUDES) $(CFLAGS) $(OBJECTS) -o $(GAME) $(LIB)
+
+profile: $(OBJECTS)
+ ${CXX} -g -p ${LDFLAGS} $(INCLUDES) $(CFLAGS) $(OBJECTS) -o $(GAME) $(LIB)
+
+.cc.o:
+ ${CXX} ${CFLAGS} -c $< ${INCLUDE}
+
+.h.cc:
+ touch $@
+
+# DO NOT DELETE
+
+abl-show.o: AppHdr.h libutil.h abl-show.h
+abl-show.o: externs.h
+abl-show.o: defines.h enum.h
+abl-show.o: FixAry.h FixVec.h debug.h message.h beam.h effects.h food.h
+abl-show.o: it_use2.h macro.h misc.h monplace.h player.h religion.h skills.h
+abl-show.o: skills2.h spl-cast.h spl-util.h direct.h spells1.h spells2.h
+abl-show.o: spells3.h spells4.h stuff.h transfor.h view.h liblinux.h
+abyss.o: AppHdr.h libutil.h abyss.h
+abyss.o: externs.h
+abyss.o: defines.h enum.h FixAry.h FixVec.h
+abyss.o: debug.h
+abyss.o: message.h cloud.h monplace.h dungeon.h items.h lev-pand.h randart.h
+abyss.o: stuff.h
+acr.o: AppHdr.h libutil.h
+acr.o: externs.h defines.h enum.h FixAry.h FixVec.h
+acr.o: debug.h message.h abl-show.h abyss.h chardump.h command.h delay.h
+acr.o: describe.h direct.h dungeon.h effects.h fight.h files.h food.h
+acr.o: hiscores.h initfile.h invent.h item_use.h it_use2.h it_use3.h
+acr.o: itemname.h items.h lev-pand.h macro.h misc.h monplace.h monstuff.h
+acr.o: mon-util.h mutation.h newgame.h ouch.h output.h overmap.h player.h
+acr.o: randart.h religion.h shopping.h skills.h skills2.h spells1.h spells3.h
+acr.o: spells4.h spl-book.h spl-cast.h spl-util.h stuff.h tags.h transfor.h
+acr.o: view.h wpn-misc.h
+beam.o: AppHdr.h libutil.h beam.h externs.h
+beam.o: defines.h enum.h
+beam.o: FixAry.h FixVec.h
+beam.o: debug.h
+beam.o: message.h
+beam.o: cloud.h effects.h
+beam.o: it_use2.h itemname.h items.h misc.h monplace.h monstuff.h mon-util.h
+beam.o: mstuff2.h ouch.h player.h religion.h skills.h spells1.h direct.h
+beam.o: spells3.h spells4.h stuff.h view.h
+chardump.o: AppHdr.h libutil.h chardump.h
+chardump.o: externs.h
+chardump.o: defines.h enum.h FixAry.h FixVec.h debug.h message.h describe.h
+chardump.o: itemname.h items.h macro.h mutation.h player.h religion.h
+chardump.o: shopping.h skills2.h spl-book.h spl-cast.h spl-util.h direct.h
+chardump.o: stuff.h version.h
+cloud.o: AppHdr.h libutil.h externs.h
+cloud.o: defines.h enum.h
+cloud.o: FixAry.h FixVec.h
+cloud.o: debug.h
+cloud.o: message.h cloud.h stuff.h
+command.o: AppHdr.h libutil.h command.h
+command.o: externs.h
+command.o: defines.h enum.h FixAry.h FixVec.h
+command.o: debug.h message.h abl-show.h invent.h itemname.h item_use.h
+command.o: items.h ouch.h spl-cast.h spl-util.h direct.h stuff.h version.h
+command.o: wpn-misc.h
+debug.o: AppHdr.h libutil.h debug.h
+debug.o: externs.h
+debug.o: defines.h enum.h
+debug.o: FixAry.h FixVec.h message.h direct.h dungeon.h invent.h itemname.h
+debug.o: items.h misc.h monplace.h monstuff.h mon-util.h mutation.h player.h
+debug.o: randart.h religion.h skills.h skills2.h spl-cast.h spl-util.h
+debug.o: stuff.h
+decks.o: AppHdr.h libutil.h decks.h
+decks.o: externs.h
+decks.o: defines.h enum.h FixAry.h FixVec.h
+decks.o: debug.h
+decks.o: message.h effects.h food.h it_use2.h items.h misc.h monplace.h
+decks.o: mutation.h ouch.h player.h religion.h spells1.h direct.h spells3.h
+decks.o: spl-cast.h stuff.h
+delay.o: AppHdr.h libutil.h externs.h
+delay.o: defines.h enum.h
+delay.o: FixAry.h FixVec.h
+delay.o: debug.h
+delay.o: message.h
+delay.o: delay.h food.h
+delay.o: items.h itemname.h item_use.h it_use2.h misc.h monstuff.h ouch.h
+delay.o: output.h player.h randart.h spl-util.h direct.h stuff.h
+describe.o: AppHdr.h libutil.h describe.h externs.h
+describe.o: defines.h
+describe.o: enum.h FixAry.h FixVec.h
+describe.o: debug.h
+describe.o: message.h
+describe.o: abl-show.h
+describe.o: fight.h itemname.h macro.h mon-util.h player.h randart.h
+describe.o: religion.h skills2.h stuff.h wpn-misc.h spl-util.h direct.h
+direct.o: AppHdr.h libutil.h direct.h externs.h
+direct.o: defines.h enum.h
+direct.o: FixAry.h FixVec.h
+direct.o: debug.h
+direct.o: message.h
+direct.o: describe.h itemname.h monstuff.h
+direct.o: mon-util.h player.h shopping.h stuff.h spells4.h view.h macro.h
+dungeon.o: AppHdr.h libutil.h abyss.h defines.h
+dungeon.o: enum.h externs.h FixAry.h FixVec.h debug.h message.h dungeon.h
+dungeon.o: itemname.h items.h maps.h mon-util.h mon-pick.h monplace.h
+dungeon.o: player.h randart.h spl-book.h stuff.h wpn-misc.h
+effects.o: AppHdr.h libutil.h effects.h externs.h
+effects.o: defines.h
+effects.o: enum.h FixAry.h FixVec.h
+effects.o: debug.h
+effects.o: message.h
+effects.o: beam.h direct.h dungeon.h itemname.h
+effects.o: items.h misc.h monplace.h monstuff.h mon-util.h mutation.h
+effects.o: newgame.h ouch.h player.h randart.h skills2.h spells3.h spells4.h
+effects.o: spl-book.h spl-util.h stuff.h view.h wpn-misc.h
+fight.o: AppHdr.h libutil.h fight.h externs.h
+fight.o: defines.h enum.h
+fight.o: FixAry.h FixVec.h
+fight.o: debug.h
+fight.o: message.h
+fight.o: beam.h cloud.h delay.h effects.h
+fight.o: food.h it_use2.h items.h itemname.h macro.h misc.h monplace.h
+fight.o: mon-pick.h monstuff.h mon-util.h mstuff2.h mutation.h ouch.h
+fight.o: player.h randart.h religion.h skills.h spells1.h direct.h spells3.h
+fight.o: spells4.h spl-cast.h stuff.h view.h wpn-misc.h
+files.o: AppHdr.h libutil.h files.h FixAry.h FixVec.h
+files.o: debug.h
+files.o: externs.h
+files.o: defines.h enum.h message.h cloud.h dungeon.h itemname.h items.h
+files.o: misc.h monstuff.h mon-util.h mstuff2.h player.h randart.h skills2.h
+files.o: stuff.h tags.h wpn-misc.h
+food.o: AppHdr.h libutil.h food.h
+food.o: externs.h
+food.o: defines.h enum.h
+food.o: FixAry.h FixVec.h debug.h message.h delay.h invent.h items.h
+food.o: itemname.h item_use.h it_use2.h macro.h misc.h mon-util.h mutation.h
+food.o: player.h religion.h skills2.h spells2.h stuff.h wpn-misc.h
+hiscores.o: AppHdr.h
+hiscores.o: libutil.h externs.h
+hiscores.o: defines.h enum.h FixAry.h FixVec.h debug.h message.h hiscores.h
+hiscores.o: itemname.h mon-util.h player.h religion.h stuff.h tags.h view.h
+hiscores.o: skills2.h
+initfile.o: AppHdr.h libutil.h initfile.h
+initfile.o: externs.h
+initfile.o: defines.h enum.h FixAry.h FixVec.h
+initfile.o: debug.h message.h player.h stuff.h items.h view.h
+insult.o: AppHdr.h libutil.h
+insult.o: externs.h
+insult.o: defines.h enum.h FixAry.h FixVec.h debug.h
+insult.o: message.h insult.h mon-util.h stuff.h
+invent.o: AppHdr.h libutil.h invent.h
+invent.o: externs.h
+invent.o: defines.h enum.h FixAry.h FixVec.h
+invent.o: debug.h
+invent.o: message.h itemname.h items.h macro.h player.h shopping.h stuff.h
+invent.o: view.h
+itemname.o: AppHdr.h libutil.h itemname.h externs.h
+itemname.o: defines.h
+itemname.o: enum.h FixAry.h FixVec.h
+itemname.o: debug.h
+itemname.o: message.h
+itemname.o: macro.h mon-util.h randart.h
+itemname.o: skills2.h stuff.h wpn-misc.h view.h
+items.o: AppHdr.h libutil.h items.h externs.h
+items.o: defines.h enum.h
+items.o: FixAry.h FixVec.h
+items.o: debug.h
+items.o: message.h
+items.o: beam.h cloud.h delay.h effects.h
+items.o: invent.h it_use2.h item_use.h itemname.h misc.h monplace.h
+items.o: monstuff.h mstuff2.h mon-util.h mutation.h player.h randart.h
+items.o: religion.h shopping.h skills.h spl-cast.h stuff.h
+item_use.o: AppHdr.h libutil.h item_use.h
+item_use.o: externs.h
+item_use.o: defines.h enum.h FixAry.h FixVec.h
+item_use.o: debug.h message.h beam.h delay.h describe.h direct.h effects.h
+item_use.o: fight.h food.h invent.h it_use2.h it_use3.h items.h itemname.h
+item_use.o: misc.h monplace.h monstuff.h mstuff2.h mon-util.h ouch.h player.h
+item_use.o: randart.h religion.h skills.h skills2.h spells1.h spells2.h
+item_use.o: spells3.h spl-book.h spl-cast.h stuff.h transfor.h view.h
+item_use.o: wpn-misc.h
+it_use2.o: AppHdr.h libutil.h it_use2.h externs.h
+it_use2.o: defines.h
+it_use2.o: enum.h FixAry.h FixVec.h
+it_use2.o: debug.h
+it_use2.o: message.h beam.h effects.h food.h itemname.h
+it_use2.o: misc.h mutation.h player.h randart.h religion.h skills2.h
+it_use2.o: spells2.h spl-cast.h stuff.h view.h
+it_use3.o: AppHdr.h libutil.h it_use3.h
+it_use3.o: externs.h
+it_use3.o: defines.h enum.h FixAry.h FixVec.h
+it_use3.o: debug.h
+it_use3.o: message.h beam.h decks.h direct.h effects.h fight.h food.h items.h
+it_use3.o: it_use2.h itemname.h misc.h monplace.h monstuff.h player.h
+it_use3.o: randart.h religion.h skills.h skills2.h spells1.h spells2.h
+it_use3.o: spl-book.h spl-cast.h spl-util.h stuff.h view.h wpn-misc.h
+lev-pand.o: AppHdr.h libutil.h lev-pand.h externs.h
+lev-pand.o: defines.h
+lev-pand.o: enum.h FixAry.h FixVec.h
+lev-pand.o: debug.h
+lev-pand.o: message.h monplace.h mon-pick.h stuff.h
+libemx.o: libemx.h
+liblinux.o: AppHdr.h libutil.h
+liblinux.o: liblinux.h defines.h enum.h externs.h
+liblinux.o: FixAry.h FixVec.h
+liblinux.o: debug.h message.h
+libutil.o: AppHdr.h libutil.h
+macro.o: AppHdr.h libutil.h macro.h
+macro.o: externs.h
+macro.o: defines.h enum.h FixAry.h FixVec.h debug.h
+macro.o: message.h initfile.h
+maps.o: AppHdr.h libutil.h maps.h FixVec.h
+maps.o: debug.h
+maps.o: enum.h monplace.h stuff.h externs.h
+maps.o: defines.h FixAry.h message.h
+message.o: AppHdr.h libutil.h message.h externs.h
+message.o: defines.h
+message.o: enum.h FixAry.h FixVec.h
+message.o: debug.h
+message.o: religion.h macro.h stuff.h view.h
+misc.o: AppHdr.h libutil.h misc.h externs.h
+misc.o: defines.h enum.h
+misc.o: FixAry.h FixVec.h
+misc.o: debug.h
+misc.o: message.h
+misc.o: cloud.h delay.h fight.h files.h food.h
+misc.o: it_use2.h items.h itemname.h lev-pand.h macro.h monplace.h mon-util.h
+misc.o: monstuff.h ouch.h player.h shopping.h skills.h skills2.h spells3.h
+misc.o: spl-cast.h stuff.h transfor.h view.h
+mon-pick.o: AppHdr.h libutil.h mon-pick.h externs.h
+mon-pick.o: defines.h
+mon-pick.o: enum.h FixAry.h FixVec.h
+mon-pick.o: debug.h
+mon-pick.o: message.h
+monplace.o: AppHdr.h libutil.h monplace.h enum.h FixVec.h
+monplace.o: debug.h
+monplace.o: externs.h
+monplace.o: defines.h
+monplace.o: FixAry.h message.h dungeon.h monstuff.h mon-pick.h mon-util.h
+monplace.o: misc.h player.h stuff.h spells4.h
+monspeak.o: AppHdr.h libutil.h monspeak.h externs.h
+monspeak.o: defines.h
+monspeak.o: enum.h FixAry.h FixVec.h
+monspeak.o: debug.h
+monspeak.o: message.h
+monspeak.o: beam.h fight.h insult.h itemname.h
+monspeak.o: misc.h monplace.h monstuff.h mon-util.h mstuff2.h player.h
+monspeak.o: spells2.h spells4.h stuff.h view.h
+monstuff.o: AppHdr.h libutil.h monstuff.h externs.h
+monstuff.o: defines.h
+monstuff.o: enum.h FixAry.h FixVec.h
+monstuff.o: debug.h
+monstuff.o: message.h
+monstuff.o: beam.h cloud.h dungeon.h fight.h
+monstuff.o: itemname.h items.h misc.h monplace.h monspeak.h mon-util.h
+monstuff.o: mstuff2.h player.h randart.h religion.h spl-cast.h spells2.h
+monstuff.o: spells4.h stuff.h view.h
+mon-util.o: AppHdr.h libutil.h mon-util.h externs.h
+mon-util.o: defines.h
+mon-util.o: enum.h FixAry.h FixVec.h
+mon-util.o: debug.h
+mon-util.o: message.h monstuff.h
+mon-util.o: itemname.h mstuff2.h player.h
+mon-util.o: randart.h stuff.h view.h mon-data.h mon-spll.h
+mstuff2.o: AppHdr.h libutil.h mstuff2.h externs.h
+mstuff2.o: defines.h
+mstuff2.o: enum.h FixAry.h FixVec.h
+mstuff2.o: debug.h
+mstuff2.o: message.h
+mstuff2.o: beam.h effects.h itemname.h items.h
+mstuff2.o: misc.h monplace.h monstuff.h mon-util.h player.h spells2.h
+mstuff2.o: spells4.h spl-cast.h stuff.h view.h wpn-misc.h
+mutation.o: AppHdr.h libutil.h mutation.h
+mutation.o: liblinux.h externs.h
+mutation.o: defines.h enum.h FixAry.h FixVec.h
+mutation.o: debug.h message.h effects.h macro.h ouch.h player.h skills2.h
+mutation.o: stuff.h transfor.h view.h
+newgame.o: AppHdr.h libutil.h newgame.h
+newgame.o: externs.h defines.h enum.h FixAry.h
+newgame.o: FixVec.h debug.h message.h abl-show.h dungeon.h files.h fight.h
+newgame.o: itemname.h items.h macro.h player.h randart.h skills.h skills2.h
+newgame.o: spl-util.h direct.h stuff.h version.h wpn-misc.h
+ouch.o: AppHdr.h libutil.h ouch.h
+ouch.o: externs.h defines.h
+ouch.o: enum.h FixAry.h FixVec.h debug.h message.h chardump.h delay.h files.h
+ouch.o: hiscores.h invent.h itemname.h items.h macro.h mon-util.h player.h
+ouch.o: randart.h religion.h shopping.h skills2.h spells4.h stuff.h view.h
+output.o: AppHdr.h libutil.h output.h
+output.o: externs.h
+output.o: defines.h enum.h FixAry.h FixVec.h
+output.o: debug.h
+output.o: message.h itemname.h ouch.h player.h
+overmap.o: AppHdr.h libutil.h overmap.h
+overmap.o: externs.h
+overmap.o: defines.h enum.h FixAry.h FixVec.h
+overmap.o: debug.h message.h files.h religion.h stuff.h view.h
+player.o: AppHdr.h libutil.h player.h externs.h
+player.o: defines.h enum.h
+player.o: FixAry.h FixVec.h
+player.o: debug.h
+player.o: message.h
+player.o: itemname.h macro.h
+player.o: misc.h mon-util.h mutation.h output.h randart.h religion.h
+player.o: skills2.h spl-util.h direct.h spells4.h stuff.h view.h wpn-misc.h
+randart.o: AppHdr.h libutil.h randart.h enum.h externs.h
+randart.o: defines.h
+randart.o: FixAry.h FixVec.h
+randart.o: debug.h
+randart.o: message.h
+randart.o: itemname.h stuff.h wpn-misc.h
+randart.o: unrand.h
+religion.o: AppHdr.h libutil.h religion.h enum.h
+religion.o: externs.h
+religion.o: defines.h FixAry.h FixVec.h debug.h
+religion.o: message.h abl-show.h beam.h decks.h describe.h dungeon.h
+religion.o: effects.h food.h it_use2.h itemname.h items.h misc.h monplace.h
+religion.o: mutation.h newgame.h ouch.h player.h shopping.h skills2.h
+religion.o: spells1.h direct.h spells2.h spells3.h spl-cast.h stuff.h
+shopping.o: AppHdr.h libutil.h shopping.h externs.h
+shopping.o: defines.h
+shopping.o: enum.h FixAry.h FixVec.h
+shopping.o: debug.h
+shopping.o: message.h
+shopping.o: describe.h invent.h items.h itemname.h
+shopping.o: macro.h player.h randart.h spl-book.h stuff.h
+skills2.o: AppHdr.h libutil.h skills2.h
+skills2.o: externs.h
+skills2.o: defines.h enum.h FixAry.h FixVec.h
+skills2.o: debug.h message.h fight.h player.h randart.h religion.h stuff.h
+skills2.o: wpn-misc.h view.h
+skills.o: AppHdr.h libutil.h skills.h
+skills.o: externs.h
+skills.o: defines.h enum.h
+skills.o: FixAry.h FixVec.h
+skills.o: debug.h
+skills.o: message.h macro.h player.h skills2.h stuff.h
+spells1.o: AppHdr.h libutil.h spells1.h externs.h
+spells1.o: defines.h
+spells1.o: enum.h FixAry.h FixVec.h
+spells1.o: debug.h
+spells1.o: message.h direct.h
+spells1.o: abyss.h beam.h
+spells1.o: cloud.h invent.h it_use2.h itemname.h misc.h monplace.h monstuff.h
+spells1.o: mon-util.h player.h skills2.h spells3.h spells4.h spl-util.h
+spells1.o: stuff.h view.h wpn-misc.h
+spells2.o: AppHdr.h libutil.h spells2.h
+spells2.o: externs.h
+spells2.o: defines.h enum.h
+spells2.o: FixAry.h FixVec.h debug.h message.h beam.h cloud.h direct.h
+spells2.o: effects.h itemname.h items.h misc.h monplace.h monstuff.h
+spells2.o: mon-util.h ouch.h player.h randart.h spells4.h spl-cast.h stuff.h
+spells2.o: view.h wpn-misc.h
+spells3.o: AppHdr.h libutil.h spells3.h
+spells3.o: externs.h
+spells3.o: defines.h enum.h
+spells3.o: FixAry.h FixVec.h debug.h message.h abyss.h beam.h cloud.h
+spells3.o: direct.h delay.h itemname.h items.h it_use2.h misc.h monplace.h
+spells3.o: mon-pick.h monstuff.h mon-util.h player.h randart.h spells1.h
+spells3.o: spl-cast.h spl-util.h stuff.h view.h wpn-misc.h
+spells4.o: AppHdr.h libutil.h
+spells4.o: externs.h
+spells4.o: defines.h enum.h FixAry.h FixVec.h
+spells4.o: debug.h message.h abyss.h beam.h cloud.h delay.h describe.h
+spells4.o: direct.h dungeon.h effects.h it_use2.h itemname.h items.h invent.h
+spells4.o: misc.h monplace.h monstuff.h mon-util.h mstuff2.h ouch.h player.h
+spells4.o: randart.h religion.h skills.h spells1.h spells4.h spl-cast.h
+spells4.o: spl-util.h stuff.h view.h
+spl-book.o: AppHdr.h libutil.h spl-book.h externs.h
+spl-book.o: defines.h
+spl-book.o: enum.h FixAry.h FixVec.h
+spl-book.o: debug.h
+spl-book.o: message.h
+spl-book.o: delay.h invent.h itemname.h items.h
+spl-book.o: it_use3.h player.h religion.h spl-cast.h spl-util.h direct.h
+spl-book.o: stuff.h
+spl-cast.o: AppHdr.h libutil.h spl-cast.h
+spl-cast.o: externs.h
+spl-cast.o: defines.h enum.h FixAry.h FixVec.h
+spl-cast.o: debug.h message.h beam.h cloud.h effects.h fight.h food.h
+spl-cast.o: it_use2.h itemname.h macro.h monplace.h monstuff.h mutation.h
+spl-cast.o: ouch.h player.h religion.h skills.h spells1.h direct.h spells2.h
+spl-cast.o: spells3.h spells4.h spl-book.h spl-util.h stuff.h transfor.h
+spl-cast.o: view.h
+spl-util.o: AppHdr.h libutil.h spl-util.h enum.h direct.h externs.h
+spl-util.o: defines.h
+spl-util.o: FixAry.h FixVec.h
+spl-util.o: debug.h
+spl-util.o: message.h
+spl-util.o: stuff.h
+spl-util.o: itemname.h macro.h monstuff.h player.h spl-book.h view.h
+spl-util.o: spl-data.h
+stuff.o: AppHdr.h libutil.h stuff.h externs.h
+stuff.o: defines.h enum.h
+stuff.o: FixAry.h FixVec.h
+stuff.o: debug.h
+stuff.o: message.h
+stuff.o: liblinux.h macro.h misc.h monstuff.h
+stuff.o: mon-util.h output.h skills2.h view.h
+tags.o: AppHdr.h
+tags.o: libutil.h abl-show.h enum.h externs.h defines.h FixAry.h FixVec.h
+tags.o: debug.h message.h files.h itemname.h monstuff.h mon-util.h randart.h
+tags.o: skills.h skills2.h stuff.h tags.h
+transfor.o: AppHdr.h libutil.h transfor.h FixVec.h
+transfor.o: debug.h
+transfor.o: externs.h
+transfor.o: defines.h enum.h
+transfor.o: FixAry.h message.h it_use2.h itemname.h items.h misc.h player.h
+transfor.o: skills2.h stuff.h
+view.o: AppHdr.h libutil.h view.h externs.h
+view.o: defines.h enum.h
+view.o: FixAry.h FixVec.h
+view.o: debug.h
+view.o: message.h insult.h macro.h monstuff.h
+view.o: mon-util.h overmap.h player.h skills2.h stuff.h spells4.h
+wpn-misc.o: AppHdr.h libutil.h wpn-misc.h externs.h
+wpn-misc.o: defines.h
+wpn-misc.o: enum.h FixAry.h FixVec.h
+wpn-misc.o: debug.h
+wpn-misc.o: message.h
diff --git a/trunk/source/makefile.osx b/trunk/source/makefile.osx
new file mode 100644
index 0000000000..9fa48a3b63
--- /dev/null
+++ b/trunk/source/makefile.osx
@@ -0,0 +1,67 @@
+# -*- Makefile -*- for Dungeon Crawl (OS X)
+
+#APPNAME = crawl
+GAME = crawl
+
+# this file contains a list of the libraries.
+# it will make a variable called OBJECTS that contains all the libraries
+include makefile.obj
+
+OBJECTS += liblinux.o
+
+CXX = g++
+DELETE = rm -f
+COPY = cp
+OS_TYPE = BSD
+
+CFLAGS = -D$(OS_TYPE) -DOSX $(EXTRA_FLAGS) -Wall -Werror \
+ -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes \
+ -Wmissing-declarations
+
+LDFLAGS = -L/sw/lib -L/usr/lib
+MCHMOD = 711
+# INSTALLDIR = /usr/games
+INSTALLDIR = /tmp/CRAWLTEST/testdev
+LIB = -lncurses -lstdc++
+
+# Include for Fink's version of curses
+INCLUDES = -I/sw/include
+
+all: $(GAME)
+
+install: $(GAME)
+ $(COPY) $(GAME) ${INSTALLDIR}
+ ${MCHMOD} ${INSTALLDIR}/$(GAME)
+
+clean:
+ $(DELETE) *.o
+
+distclean:
+ $(DELETE) *.o
+ $(DELETE) bones.*
+ $(DELETE) morgue.txt
+ $(DELETE) scores
+ $(DELETE) $(GAME)
+ $(DELETE) *.sav
+ $(DELETE) core
+ $(DELETE) *.0*
+ $(DELETE) *.lab
+
+
+$(GAME): $(OBJECTS)
+ ${CXX} ${LDFLAGS} $(INCLUDES) $(CFLAGS) $(OBJECTS) -o $(GAME) $(LIB)
+ strip $(GAME)
+ chmod ${MCHMOD} $(GAME)
+
+debug: $(OBJECTS)
+ ${CXX} ${LDFLAGS} $(INCLUDES) $(CFLAGS) $(OBJECTS) -o $(GAME) $(LIB)
+
+profile: $(OBJECTS)
+ ${CXX} -g -p ${LDFLAGS} $(INCLUDES) $(CFLAGS) $(OBJECTS) -o $(GAME) $(LIB)
+
+.cc.o:
+ ${CXX} ${CFLAGS} $(INCLUDES) -c $< ${INCLUDE}
+
+.h.cc:
+ touch $@
+
diff --git a/trunk/source/makefile.sgi b/trunk/source/makefile.sgi
new file mode 100644
index 0000000000..67815feaae
--- /dev/null
+++ b/trunk/source/makefile.sgi
@@ -0,0 +1,54 @@
+# Make file for Dungeon Crawl (irix)
+
+APPNAME = crawl
+
+# this file contains a list of the libraries.
+# it will make a variable called OBJECTS that contains all the libraries
+include makefile.obj
+
+CXX = CC
+DELETE = rm -f
+COPY = cp
+OS_TYPE = LINUX
+CFLAGS = -Wall -D$(OS_TYPE) $(EXTRA_FLAGS)
+LDFLAGS = -L/usr/lib
+MCHMOD = 711
+INSTALLDIR = /usr/games
+LIB = -lncurses
+
+# Include for Linux
+INCLUDES = -I/usr/include/ncurses
+
+all: $(APPNAME)
+
+%.o: %.cc
+ @echo hello
+ @${CXX} ${CFLAGS} -c $< ${INCLUDE}
+
+install: $(APPNAME)
+ $(COPY) $(APPNAME) ${INSTALLDIR}
+ chmod ${MCHMOD} ${INSTALLDIR}/$(APPNAME)
+
+clean:
+ $(DELETE) *.o
+
+distclean:
+ $(DELETE) *.o
+ $(DELETE) bones.*
+ $(DELETE) morgue.txt
+ $(DELETE) scores
+ $(DELETE) $(APPNAME)
+
+$(APPNAME): $(OBJECTS)
+ ${CXX} ${LDFLAGS} $(INCLUDES) $(CFLAGS) $(OBJECTS) -o $(APPNAME) $(LIB)
+ strip $(APPNAME)
+ chmod ${MCHMOD} $(APPNAME)
+
+debug: $(OBJECTS)
+ ${CXX} ${LDFLAGS} $(INCLUDES) $(CFLAGS) $(OBJECTS) -o $(APPNAME) $(LIB)
+
+profile: $(OBJECTS)
+ ${CXX} -g -p ${LDFLAGS} $(INCLUDES) $(CFLAGS) $(OBJECTS) -o $(APPNAME) $(LIB)
+
+.h.cc:
+ touch $@
diff --git a/trunk/source/makefile.sol b/trunk/source/makefile.sol
new file mode 100644
index 0000000000..3e8bcddc76
--- /dev/null
+++ b/trunk/source/makefile.sol
@@ -0,0 +1,3112 @@
+# Make file for Dungeon Crawl (solaris)
+
+APPNAME = crawl
+
+# this file contains a list of the libraries.
+# it will make a variable called OBJECTS that contains all the libraries
+include makefile.obj
+
+OBJECTS += liblinux.o
+
+CXX = g++
+DELETE = rm -f
+COPY = cp
+GROUP = games
+MOVE = mv
+OS_TYPE = SOLARIS
+
+CFLAGS = -Wall -Wwrite-strings -Wstrict-prototypes \
+ -Wmissing-prototypes -Wmissing-declarations \
+ -g -D$(OS_TYPE) $(EXTRA_FLAGS)
+
+LDFLAGS = -static
+MCHMOD = 2755
+INSTALLDIR = /opt/local/newcrawl/bin
+LIB = -lcurses
+
+all: $(APPNAME)
+
+install: $(APPNAME)
+ #strip $(APPNAME)
+ $(MOVE) ${INSTALLDIR}/${APPNAME} ${INSTALLDIR}/${APPNAME}.old
+ $(COPY) $(APPNAME) ${INSTALLDIR}
+ chgrp ${GROUP} ${INSTALLDIR}/${APPNAME}
+ chmod ${MCHMOD} ${INSTALLDIR}/$(APPNAME)
+
+clean:
+ $(DELETE) *.o
+
+distclean:
+ $(DELETE) *.o
+ $(DELETE) bones.*
+ $(DELETE) morgue.txt
+ $(DELETE) scores
+ $(DELETE) $(APPNAME)
+ $(DELETE) *.sav
+ $(DELETE) core
+ $(DELETE) *.0*
+ $(DELETE) *.lab
+
+
+$(APPNAME): $(OBJECTS)
+ ${CXX} ${LDFLAGS} $(INCLUDES) $(CFLAGS) $(OBJECTS) -o $(APPNAME) $(LIB)
+
+debug: $(OBJECTS)
+ ${CXX} ${LDFLAGS} $(INCLUDES) $(CFLAGS) $(OBJECTS) -o $(APPNAME) $(LIB)
+
+profile: $(OBJECTS)
+ ${CXX} -g -p ${LDFLAGS} $(INCLUDES) $(CFLAGS) $(OBJECTS) -o $(APPNAME) $(LIB)
+
+.cc.o:
+ ${CXX} ${CFLAGS} -c $< ${INCLUDE}
+
+.h.cc:
+ touch $@
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+
+abl-show.o: abl-show.h AppHdr.h beam.h debug.h defines.h direct.h effects.h
+abl-show.o: enum.h externs.h FixAry.h FixVec.h food.h it_use2.h liblinux.h
+abl-show.o: libutil.h message.h misc.h monplace.h player.h religion.h
+abl-show.o: skills2.h skills.h spells1.h spells2.h spells3.h spells4.h
+abl-show.o: spl-cast.h stuff.h transfor.h /usr/include/alloca.h
+abl-show.o: /usr/include/asm/errno.h /usr/include/assert.h
+abl-show.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+abl-show.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+abl-show.o: /usr/include/bits/fcntl.h /usr/include/bits/local_lim.h
+abl-show.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
+abl-show.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
+abl-show.o: /usr/include/bits/sched.h /usr/include/bits/select.h
+abl-show.o: /usr/include/bits/sigset.h /usr/include/bits/stat.h
+abl-show.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
+abl-show.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+abl-show.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+abl-show.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
+abl-show.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
+abl-show.o: /usr/include/fcntl.h /usr/include/features.h
+abl-show.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+abl-show.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+abl-show.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+abl-show.o: /usr/include/g++-3/iterator /usr/include/g++-3/queue
+abl-show.o: /usr/include/g++-3/std/bastring.cc
+abl-show.o: /usr/include/g++-3/std/bastring.h
+abl-show.o: /usr/include/g++-3/std/straits.h
+abl-show.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+abl-show.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+abl-show.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+abl-show.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+abl-show.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+abl-show.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+abl-show.o: /usr/include/g++-3/stl_uninitialized.h
+abl-show.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+abl-show.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+abl-show.o: /usr/include/_G_config.h /usr/include/gconv.h
+abl-show.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+abl-show.o: /usr/include/libio.h /usr/include/limits.h
+abl-show.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+abl-show.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+abl-show.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+abl-show.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+abl-show.o: /usr/include/sys/types.h /usr/include/time.h
+abl-show.o: /usr/include/unistd.h /usr/include/wchar.h /usr/include/xlocale.h
+abl-show.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+abl-show.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+abl-show.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+abl-show.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+abl-show.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+abl-show.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+abl-show.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+abl-show.o: view.h
+abyss.o: abyss.h AppHdr.h cloud.h debug.h defines.h dungeon.h enum.h
+abyss.o: externs.h FixAry.h FixVec.h items.h lev-pand.h liblinux.h libutil.h
+abyss.o: message.h monplace.h randart.h stuff.h /usr/include/alloca.h
+abyss.o: /usr/include/asm/errno.h /usr/include/assert.h
+abyss.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+abyss.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+abyss.o: /usr/include/bits/fcntl.h /usr/include/bits/local_lim.h
+abyss.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
+abyss.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
+abyss.o: /usr/include/bits/sched.h /usr/include/bits/select.h
+abyss.o: /usr/include/bits/sigset.h /usr/include/bits/stat.h
+abyss.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
+abyss.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+abyss.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+abyss.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
+abyss.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
+abyss.o: /usr/include/fcntl.h /usr/include/features.h
+abyss.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+abyss.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+abyss.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+abyss.o: /usr/include/g++-3/iterator /usr/include/g++-3/queue
+abyss.o: /usr/include/g++-3/std/bastring.cc /usr/include/g++-3/std/bastring.h
+abyss.o: /usr/include/g++-3/std/straits.h /usr/include/g++-3/stl_algobase.h
+abyss.o: /usr/include/g++-3/stl_alloc.h /usr/include/g++-3/stl_bvector.h
+abyss.o: /usr/include/g++-3/stl_config.h /usr/include/g++-3/stl_construct.h
+abyss.o: /usr/include/g++-3/stl_deque.h /usr/include/g++-3/stl_function.h
+abyss.o: /usr/include/g++-3/stl_heap.h /usr/include/g++-3/stl_iterator.h
+abyss.o: /usr/include/g++-3/stl_pair.h /usr/include/g++-3/stl_queue.h
+abyss.o: /usr/include/g++-3/stl_relops.h
+abyss.o: /usr/include/g++-3/stl_uninitialized.h
+abyss.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+abyss.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+abyss.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
+abyss.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/limits.h
+abyss.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+abyss.o: /usr/include/stdlib.h /usr/include/string.h /usr/include/sys/cdefs.h
+abyss.o: /usr/include/sys/select.h /usr/include/sys/stat.h
+abyss.o: /usr/include/sys/sysmacros.h /usr/include/sys/types.h
+abyss.o: /usr/include/time.h /usr/include/unistd.h /usr/include/wchar.h
+abyss.o: /usr/include/xlocale.h
+abyss.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+abyss.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+abyss.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+abyss.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+abyss.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+abyss.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+abyss.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+acr.o: abl-show.h abyss.h AppHdr.h chardump.h command.h debug.h defines.h
+acr.o: delay.h describe.h direct.h effects.h enum.h externs.h fight.h files.h
+acr.o: FixAry.h FixVec.h food.h hiscores.h initfile.h invent.h itemname.h
+acr.o: items.h item_use.h it_use2.h it_use3.h lev-pand.h liblinux.h libutil.h
+acr.o: message.h misc.h monplace.h monstuff.h mon-util.h mutation.h newgame.h
+acr.o: ouch.h output.h overmap.h player.h randart.h religion.h skills2.h
+acr.o: skills.h spells1.h spells3.h spells4.h spl-book.h spl-cast.h
+acr.o: spl-util.h stuff.h tags.h transfor.h /usr/include/alloca.h
+acr.o: /usr/include/asm/errno.h /usr/include/asm/sigcontext.h
+acr.o: /usr/include/assert.h /usr/include/bits/confname.h
+acr.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+acr.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+acr.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+acr.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+acr.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+acr.o: /usr/include/bits/select.h /usr/include/bits/sigaction.h
+acr.o: /usr/include/bits/sigcontext.h /usr/include/bits/siginfo.h
+acr.o: /usr/include/bits/signum.h /usr/include/bits/sigset.h
+acr.o: /usr/include/bits/sigstack.h /usr/include/bits/sigthread.h
+acr.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+acr.o: /usr/include/bits/time.h /usr/include/bits/types.h
+acr.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+acr.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+acr.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+acr.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+acr.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+acr.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+acr.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+acr.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+acr.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+acr.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+acr.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+acr.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+acr.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+acr.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+acr.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+acr.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+acr.o: /usr/include/g++-3/stl_uninitialized.h /usr/include/g++-3/stl_vector.h
+acr.o: /usr/include/g++-3/streambuf.h /usr/include/g++-3/string
+acr.o: /usr/include/g++-3/type_traits.h /usr/include/_G_config.h
+acr.o: /usr/include/gconv.h /usr/include/getopt.h /usr/include/gnu/stubs.h
+acr.o: /usr/include/libio.h /usr/include/limits.h /usr/include/linux/errno.h
+acr.o: /usr/include/linux/limits.h /usr/include/signal.h /usr/include/stdio.h
+acr.o: /usr/include/stdlib.h /usr/include/string.h /usr/include/sys/cdefs.h
+acr.o: /usr/include/sys/select.h /usr/include/sys/stat.h
+acr.o: /usr/include/sys/sysmacros.h /usr/include/sys/types.h
+acr.o: /usr/include/sys/ucontext.h /usr/include/time.h
+acr.o: /usr/include/ucontext.h /usr/include/unistd.h /usr/include/wchar.h
+acr.o: /usr/include/xlocale.h
+acr.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+acr.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/float.h
+acr.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+acr.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+acr.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+acr.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+acr.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+acr.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h view.h
+acr.o: wpn-misc.h
+beam.o: AppHdr.h beam.h cloud.h debug.h defines.h direct.h effects.h enum.h
+beam.o: externs.h fight.h FixAry.h FixVec.h itemname.h items.h it_use2.h
+beam.o: liblinux.h libutil.h message.h misc.h monplace.h monstuff.h
+beam.o: mon-util.h mstuff2.h ouch.h player.h religion.h skills.h spells1.h
+beam.o: spells3.h spells4.h stuff.h /usr/include/alloca.h
+beam.o: /usr/include/asm/errno.h /usr/include/assert.h
+beam.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+beam.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+beam.o: /usr/include/bits/fcntl.h /usr/include/bits/local_lim.h
+beam.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
+beam.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
+beam.o: /usr/include/bits/sched.h /usr/include/bits/select.h
+beam.o: /usr/include/bits/sigset.h /usr/include/bits/stat.h
+beam.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
+beam.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+beam.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+beam.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
+beam.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
+beam.o: /usr/include/fcntl.h /usr/include/features.h
+beam.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+beam.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+beam.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+beam.o: /usr/include/g++-3/iterator /usr/include/g++-3/queue
+beam.o: /usr/include/g++-3/std/bastring.cc /usr/include/g++-3/std/bastring.h
+beam.o: /usr/include/g++-3/std/straits.h /usr/include/g++-3/stl_algobase.h
+beam.o: /usr/include/g++-3/stl_alloc.h /usr/include/g++-3/stl_bvector.h
+beam.o: /usr/include/g++-3/stl_config.h /usr/include/g++-3/stl_construct.h
+beam.o: /usr/include/g++-3/stl_deque.h /usr/include/g++-3/stl_function.h
+beam.o: /usr/include/g++-3/stl_heap.h /usr/include/g++-3/stl_iterator.h
+beam.o: /usr/include/g++-3/stl_pair.h /usr/include/g++-3/stl_queue.h
+beam.o: /usr/include/g++-3/stl_relops.h
+beam.o: /usr/include/g++-3/stl_uninitialized.h
+beam.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+beam.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+beam.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
+beam.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/limits.h
+beam.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+beam.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+beam.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+beam.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+beam.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+beam.o: /usr/include/wchar.h /usr/include/xlocale.h
+beam.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+beam.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+beam.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+beam.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+beam.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+beam.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+beam.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h view.h
+chardump.o: AppHdr.h chardump.h debug.h defines.h describe.h enum.h externs.h
+chardump.o: FixAry.h FixVec.h itemname.h items.h liblinux.h libutil.h
+chardump.o: message.h mutation.h player.h religion.h shopping.h skills2.h
+chardump.o: spl-book.h spl-cast.h spl-util.h stuff.h /usr/include/alloca.h
+chardump.o: /usr/include/asm/errno.h /usr/include/assert.h
+chardump.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+chardump.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+chardump.o: /usr/include/bits/fcntl.h /usr/include/bits/local_lim.h
+chardump.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
+chardump.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
+chardump.o: /usr/include/bits/sched.h /usr/include/bits/select.h
+chardump.o: /usr/include/bits/sigset.h /usr/include/bits/stat.h
+chardump.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
+chardump.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+chardump.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+chardump.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
+chardump.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
+chardump.o: /usr/include/fcntl.h /usr/include/features.h
+chardump.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+chardump.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+chardump.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+chardump.o: /usr/include/g++-3/iterator /usr/include/g++-3/queue
+chardump.o: /usr/include/g++-3/std/bastring.cc
+chardump.o: /usr/include/g++-3/std/bastring.h
+chardump.o: /usr/include/g++-3/std/straits.h
+chardump.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+chardump.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+chardump.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+chardump.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+chardump.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+chardump.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+chardump.o: /usr/include/g++-3/stl_uninitialized.h
+chardump.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+chardump.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+chardump.o: /usr/include/_G_config.h /usr/include/gconv.h
+chardump.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+chardump.o: /usr/include/libio.h /usr/include/limits.h
+chardump.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+chardump.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+chardump.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+chardump.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+chardump.o: /usr/include/sys/types.h /usr/include/time.h
+chardump.o: /usr/include/unistd.h /usr/include/wchar.h /usr/include/xlocale.h
+chardump.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+chardump.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+chardump.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+chardump.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+chardump.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+chardump.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+chardump.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+chardump.o: version.h
+cloud.o: AppHdr.h cloud.h debug.h defines.h enum.h externs.h FixAry.h
+cloud.o: FixVec.h liblinux.h libutil.h message.h stuff.h
+cloud.o: /usr/include/alloca.h /usr/include/asm/errno.h /usr/include/assert.h
+cloud.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+cloud.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+cloud.o: /usr/include/bits/fcntl.h /usr/include/bits/local_lim.h
+cloud.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
+cloud.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
+cloud.o: /usr/include/bits/sched.h /usr/include/bits/select.h
+cloud.o: /usr/include/bits/sigset.h /usr/include/bits/stat.h
+cloud.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
+cloud.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+cloud.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+cloud.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
+cloud.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
+cloud.o: /usr/include/fcntl.h /usr/include/features.h
+cloud.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+cloud.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+cloud.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+cloud.o: /usr/include/g++-3/iterator /usr/include/g++-3/queue
+cloud.o: /usr/include/g++-3/std/bastring.cc /usr/include/g++-3/std/bastring.h
+cloud.o: /usr/include/g++-3/std/straits.h /usr/include/g++-3/stl_algobase.h
+cloud.o: /usr/include/g++-3/stl_alloc.h /usr/include/g++-3/stl_bvector.h
+cloud.o: /usr/include/g++-3/stl_config.h /usr/include/g++-3/stl_construct.h
+cloud.o: /usr/include/g++-3/stl_deque.h /usr/include/g++-3/stl_function.h
+cloud.o: /usr/include/g++-3/stl_heap.h /usr/include/g++-3/stl_iterator.h
+cloud.o: /usr/include/g++-3/stl_pair.h /usr/include/g++-3/stl_queue.h
+cloud.o: /usr/include/g++-3/stl_relops.h
+cloud.o: /usr/include/g++-3/stl_uninitialized.h
+cloud.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+cloud.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+cloud.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
+cloud.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/limits.h
+cloud.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+cloud.o: /usr/include/stdlib.h /usr/include/string.h /usr/include/sys/cdefs.h
+cloud.o: /usr/include/sys/select.h /usr/include/sys/stat.h
+cloud.o: /usr/include/sys/sysmacros.h /usr/include/sys/types.h
+cloud.o: /usr/include/time.h /usr/include/unistd.h /usr/include/wchar.h
+cloud.o: /usr/include/xlocale.h
+cloud.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+cloud.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+cloud.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+cloud.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+cloud.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+cloud.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+cloud.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+command.o: AppHdr.h command.h debug.h defines.h enum.h externs.h FixAry.h
+command.o: FixVec.h invent.h itemname.h items.h liblinux.h libutil.h
+command.o: message.h ouch.h spl-cast.h spl-util.h stuff.h
+command.o: /usr/include/alloca.h /usr/include/asm/errno.h
+command.o: /usr/include/assert.h /usr/include/bits/confname.h
+command.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+command.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+command.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+command.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+command.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+command.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+command.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+command.o: /usr/include/bits/time.h /usr/include/bits/types.h
+command.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+command.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+command.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+command.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+command.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+command.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+command.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+command.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+command.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+command.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+command.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+command.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+command.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+command.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+command.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+command.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+command.o: /usr/include/g++-3/stl_uninitialized.h
+command.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+command.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+command.o: /usr/include/_G_config.h /usr/include/gconv.h
+command.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+command.o: /usr/include/libio.h /usr/include/limits.h
+command.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+command.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+command.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+command.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+command.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+command.o: /usr/include/wchar.h /usr/include/xlocale.h
+command.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+command.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+command.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+command.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+command.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+command.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+command.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+command.o: version.h wpn-misc.h
+debug.o: AppHdr.h debug.h defines.h direct.h dungeon.h enum.h externs.h
+debug.o: FixAry.h FixVec.h invent.h itemname.h items.h liblinux.h libutil.h
+debug.o: message.h misc.h monplace.h mon-util.h mutation.h player.h randart.h
+debug.o: religion.h skills2.h skills.h spl-cast.h spl-util.h stuff.h
+debug.o: /usr/include/alloca.h /usr/include/asm/errno.h /usr/include/assert.h
+debug.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+debug.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+debug.o: /usr/include/bits/fcntl.h /usr/include/bits/local_lim.h
+debug.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
+debug.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
+debug.o: /usr/include/bits/sched.h /usr/include/bits/select.h
+debug.o: /usr/include/bits/sigset.h /usr/include/bits/stat.h
+debug.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
+debug.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+debug.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+debug.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
+debug.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
+debug.o: /usr/include/fcntl.h /usr/include/features.h
+debug.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+debug.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+debug.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+debug.o: /usr/include/g++-3/iterator /usr/include/g++-3/queue
+debug.o: /usr/include/g++-3/std/bastring.cc /usr/include/g++-3/std/bastring.h
+debug.o: /usr/include/g++-3/std/straits.h /usr/include/g++-3/stl_algobase.h
+debug.o: /usr/include/g++-3/stl_alloc.h /usr/include/g++-3/stl_bvector.h
+debug.o: /usr/include/g++-3/stl_config.h /usr/include/g++-3/stl_construct.h
+debug.o: /usr/include/g++-3/stl_deque.h /usr/include/g++-3/stl_function.h
+debug.o: /usr/include/g++-3/stl_heap.h /usr/include/g++-3/stl_iterator.h
+debug.o: /usr/include/g++-3/stl_pair.h /usr/include/g++-3/stl_queue.h
+debug.o: /usr/include/g++-3/stl_relops.h
+debug.o: /usr/include/g++-3/stl_uninitialized.h
+debug.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+debug.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+debug.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
+debug.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/limits.h
+debug.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+debug.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+debug.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+debug.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+debug.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+debug.o: /usr/include/wchar.h /usr/include/xlocale.h
+debug.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+debug.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+debug.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+debug.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+debug.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+debug.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+debug.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+decks.o: AppHdr.h debug.h decks.h defines.h direct.h effects.h enum.h
+decks.o: externs.h FixAry.h FixVec.h food.h items.h it_use2.h liblinux.h
+decks.o: libutil.h message.h misc.h monplace.h mutation.h ouch.h player.h
+decks.o: religion.h spells1.h spells3.h spl-cast.h stuff.h
+decks.o: /usr/include/alloca.h /usr/include/asm/errno.h /usr/include/assert.h
+decks.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+decks.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+decks.o: /usr/include/bits/fcntl.h /usr/include/bits/local_lim.h
+decks.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
+decks.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
+decks.o: /usr/include/bits/sched.h /usr/include/bits/select.h
+decks.o: /usr/include/bits/sigset.h /usr/include/bits/stat.h
+decks.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
+decks.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+decks.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+decks.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
+decks.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
+decks.o: /usr/include/fcntl.h /usr/include/features.h
+decks.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+decks.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+decks.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+decks.o: /usr/include/g++-3/iterator /usr/include/g++-3/queue
+decks.o: /usr/include/g++-3/std/bastring.cc /usr/include/g++-3/std/bastring.h
+decks.o: /usr/include/g++-3/std/straits.h /usr/include/g++-3/stl_algobase.h
+decks.o: /usr/include/g++-3/stl_alloc.h /usr/include/g++-3/stl_bvector.h
+decks.o: /usr/include/g++-3/stl_config.h /usr/include/g++-3/stl_construct.h
+decks.o: /usr/include/g++-3/stl_deque.h /usr/include/g++-3/stl_function.h
+decks.o: /usr/include/g++-3/stl_heap.h /usr/include/g++-3/stl_iterator.h
+decks.o: /usr/include/g++-3/stl_pair.h /usr/include/g++-3/stl_queue.h
+decks.o: /usr/include/g++-3/stl_relops.h
+decks.o: /usr/include/g++-3/stl_uninitialized.h
+decks.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+decks.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+decks.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
+decks.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/limits.h
+decks.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+decks.o: /usr/include/stdlib.h /usr/include/string.h /usr/include/sys/cdefs.h
+decks.o: /usr/include/sys/select.h /usr/include/sys/stat.h
+decks.o: /usr/include/sys/sysmacros.h /usr/include/sys/types.h
+decks.o: /usr/include/time.h /usr/include/unistd.h /usr/include/wchar.h
+decks.o: /usr/include/xlocale.h
+decks.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+decks.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+decks.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+decks.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+decks.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+decks.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+decks.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+delay.o: AppHdr.h debug.h defines.h delay.h enum.h externs.h fight.h FixAry.h
+delay.o: FixVec.h food.h itemname.h items.h item_use.h it_use2.h liblinux.h
+delay.o: libutil.h message.h misc.h monstuff.h ouch.h output.h player.h
+delay.o: randart.h stuff.h /usr/include/alloca.h /usr/include/asm/errno.h
+delay.o: /usr/include/assert.h /usr/include/bits/confname.h
+delay.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+delay.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+delay.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+delay.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+delay.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+delay.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+delay.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+delay.o: /usr/include/bits/time.h /usr/include/bits/types.h
+delay.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+delay.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+delay.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+delay.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+delay.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+delay.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+delay.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+delay.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+delay.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+delay.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+delay.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+delay.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+delay.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+delay.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+delay.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+delay.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+delay.o: /usr/include/g++-3/stl_uninitialized.h
+delay.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+delay.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+delay.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
+delay.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/limits.h
+delay.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+delay.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+delay.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+delay.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+delay.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+delay.o: /usr/include/wchar.h /usr/include/xlocale.h
+delay.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+delay.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+delay.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+delay.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+delay.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+delay.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+delay.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+describe.o: AppHdr.h debug.h defines.h describe.h enum.h externs.h fight.h
+describe.o: FixAry.h FixVec.h itemname.h liblinux.h libutil.h message.h
+describe.o: mon-util.h player.h randart.h religion.h skills2.h spl-util.h
+describe.o: stuff.h /usr/include/alloca.h /usr/include/asm/errno.h
+describe.o: /usr/include/assert.h /usr/include/bits/confname.h
+describe.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+describe.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+describe.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+describe.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+describe.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+describe.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+describe.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+describe.o: /usr/include/bits/time.h /usr/include/bits/types.h
+describe.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+describe.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+describe.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+describe.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+describe.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+describe.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+describe.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+describe.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+describe.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+describe.o: /usr/include/g++-3/std/bastring.h
+describe.o: /usr/include/g++-3/std/straits.h
+describe.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+describe.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+describe.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+describe.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+describe.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+describe.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+describe.o: /usr/include/g++-3/stl_uninitialized.h
+describe.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+describe.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+describe.o: /usr/include/_G_config.h /usr/include/gconv.h
+describe.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+describe.o: /usr/include/libio.h /usr/include/limits.h
+describe.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+describe.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+describe.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+describe.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+describe.o: /usr/include/sys/types.h /usr/include/time.h
+describe.o: /usr/include/unistd.h /usr/include/wchar.h /usr/include/xlocale.h
+describe.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+describe.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+describe.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+describe.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+describe.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+describe.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+describe.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+describe.o: wpn-misc.h
+direct.o: AppHdr.h debug.h defines.h describe.h direct.h enum.h externs.h
+direct.o: FixAry.h FixVec.h itemname.h liblinux.h libutil.h message.h
+direct.o: monstuff.h mon-util.h player.h shopping.h spells4.h stuff.h
+direct.o: /usr/include/alloca.h /usr/include/asm/errno.h
+direct.o: /usr/include/assert.h /usr/include/bits/confname.h
+direct.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+direct.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+direct.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+direct.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+direct.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+direct.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+direct.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+direct.o: /usr/include/bits/time.h /usr/include/bits/types.h
+direct.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+direct.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+direct.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+direct.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+direct.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+direct.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+direct.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+direct.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+direct.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+direct.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+direct.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+direct.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+direct.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+direct.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+direct.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+direct.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+direct.o: /usr/include/g++-3/stl_uninitialized.h
+direct.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+direct.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+direct.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
+direct.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/limits.h
+direct.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+direct.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+direct.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+direct.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+direct.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+direct.o: /usr/include/wchar.h /usr/include/xlocale.h
+direct.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+direct.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+direct.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+direct.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+direct.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+direct.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+direct.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h view.h
+dungeon.o: abyss.h AppHdr.h debug.h defines.h dungeon.h enum.h externs.h
+dungeon.o: FixAry.h FixVec.h itemname.h items.h liblinux.h libutil.h maps.h
+dungeon.o: message.h mon-pick.h monplace.h mon-util.h randart.h spl-book.h
+dungeon.o: stuff.h /usr/include/alloca.h /usr/include/asm/errno.h
+dungeon.o: /usr/include/assert.h /usr/include/bits/confname.h
+dungeon.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+dungeon.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+dungeon.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+dungeon.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+dungeon.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+dungeon.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+dungeon.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+dungeon.o: /usr/include/bits/time.h /usr/include/bits/types.h
+dungeon.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+dungeon.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+dungeon.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+dungeon.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+dungeon.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+dungeon.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+dungeon.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+dungeon.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+dungeon.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+dungeon.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+dungeon.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+dungeon.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+dungeon.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+dungeon.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+dungeon.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+dungeon.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+dungeon.o: /usr/include/g++-3/stl_uninitialized.h
+dungeon.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+dungeon.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+dungeon.o: /usr/include/_G_config.h /usr/include/gconv.h
+dungeon.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+dungeon.o: /usr/include/libio.h /usr/include/limits.h
+dungeon.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+dungeon.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+dungeon.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+dungeon.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+dungeon.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+dungeon.o: /usr/include/wchar.h /usr/include/xlocale.h
+dungeon.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+dungeon.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+dungeon.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+dungeon.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+dungeon.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+dungeon.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+dungeon.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+dungeon.o: wpn-misc.h
+effects.o: AppHdr.h beam.h debug.h defines.h direct.h dungeon.h effects.h
+effects.o: enum.h externs.h fight.h FixAry.h FixVec.h itemname.h items.h
+effects.o: liblinux.h libutil.h message.h misc.h monplace.h monstuff.h
+effects.o: mon-util.h mutation.h newgame.h ouch.h player.h skills2.h
+effects.o: spells3.h spl-book.h spl-util.h stuff.h /usr/include/alloca.h
+effects.o: /usr/include/asm/errno.h /usr/include/assert.h
+effects.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+effects.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+effects.o: /usr/include/bits/fcntl.h /usr/include/bits/local_lim.h
+effects.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
+effects.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
+effects.o: /usr/include/bits/sched.h /usr/include/bits/select.h
+effects.o: /usr/include/bits/sigset.h /usr/include/bits/stat.h
+effects.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
+effects.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+effects.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+effects.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
+effects.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
+effects.o: /usr/include/fcntl.h /usr/include/features.h
+effects.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+effects.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+effects.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+effects.o: /usr/include/g++-3/iterator /usr/include/g++-3/queue
+effects.o: /usr/include/g++-3/std/bastring.cc
+effects.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+effects.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+effects.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+effects.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+effects.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+effects.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+effects.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+effects.o: /usr/include/g++-3/stl_uninitialized.h
+effects.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+effects.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+effects.o: /usr/include/_G_config.h /usr/include/gconv.h
+effects.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+effects.o: /usr/include/libio.h /usr/include/limits.h
+effects.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+effects.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+effects.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+effects.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+effects.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+effects.o: /usr/include/wchar.h /usr/include/xlocale.h
+effects.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+effects.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+effects.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+effects.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+effects.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+effects.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+effects.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h view.h
+effects.o: wpn-misc.h
+fight.o: AppHdr.h beam.h cloud.h debug.h defines.h delay.h direct.h effects.h
+fight.o: enum.h externs.h fight.h FixAry.h FixVec.h food.h itemname.h items.h
+fight.o: it_use2.h liblinux.h libutil.h message.h misc.h mon-pick.h
+fight.o: monplace.h monstuff.h mon-util.h mstuff2.h mutation.h ouch.h
+fight.o: player.h randart.h religion.h skills.h spells1.h spells3.h spells4.h
+fight.o: spl-cast.h stuff.h /usr/include/alloca.h /usr/include/asm/errno.h
+fight.o: /usr/include/assert.h /usr/include/bits/confname.h
+fight.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+fight.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+fight.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+fight.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+fight.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+fight.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+fight.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+fight.o: /usr/include/bits/time.h /usr/include/bits/types.h
+fight.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+fight.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+fight.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+fight.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+fight.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+fight.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+fight.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+fight.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+fight.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+fight.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+fight.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+fight.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+fight.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+fight.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+fight.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+fight.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+fight.o: /usr/include/g++-3/stl_uninitialized.h
+fight.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+fight.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+fight.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
+fight.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/limits.h
+fight.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+fight.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+fight.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+fight.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+fight.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+fight.o: /usr/include/wchar.h /usr/include/xlocale.h
+fight.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+fight.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+fight.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+fight.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+fight.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+fight.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+fight.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h view.h
+fight.o: wpn-misc.h
+files.o: AppHdr.h cloud.h debug.h defines.h dungeon.h enum.h externs.h
+files.o: files.h FixAry.h FixVec.h itemname.h items.h liblinux.h libutil.h
+files.o: message.h misc.h monstuff.h mon-util.h mstuff2.h player.h randart.h
+files.o: skills2.h stuff.h tags.h /usr/include/alloca.h
+files.o: /usr/include/asm/errno.h /usr/include/assert.h
+files.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+files.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+files.o: /usr/include/bits/fcntl.h /usr/include/bits/local_lim.h
+files.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
+files.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
+files.o: /usr/include/bits/sched.h /usr/include/bits/select.h
+files.o: /usr/include/bits/sigset.h /usr/include/bits/stat.h
+files.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
+files.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+files.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+files.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
+files.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
+files.o: /usr/include/fcntl.h /usr/include/features.h
+files.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+files.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+files.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+files.o: /usr/include/g++-3/iterator /usr/include/g++-3/queue
+files.o: /usr/include/g++-3/std/bastring.cc /usr/include/g++-3/std/bastring.h
+files.o: /usr/include/g++-3/std/straits.h /usr/include/g++-3/stl_algobase.h
+files.o: /usr/include/g++-3/stl_alloc.h /usr/include/g++-3/stl_bvector.h
+files.o: /usr/include/g++-3/stl_config.h /usr/include/g++-3/stl_construct.h
+files.o: /usr/include/g++-3/stl_deque.h /usr/include/g++-3/stl_function.h
+files.o: /usr/include/g++-3/stl_heap.h /usr/include/g++-3/stl_iterator.h
+files.o: /usr/include/g++-3/stl_pair.h /usr/include/g++-3/stl_queue.h
+files.o: /usr/include/g++-3/stl_relops.h
+files.o: /usr/include/g++-3/stl_uninitialized.h
+files.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+files.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+files.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
+files.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/limits.h
+files.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+files.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+files.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+files.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+files.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+files.o: /usr/include/wchar.h /usr/include/xlocale.h
+files.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+files.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+files.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+files.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+files.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+files.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+files.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+files.o: wpn-misc.h
+food.o: AppHdr.h debug.h defines.h delay.h enum.h externs.h FixAry.h FixVec.h
+food.o: food.h invent.h itemname.h items.h item_use.h it_use2.h liblinux.h
+food.o: libutil.h message.h misc.h mon-util.h mutation.h player.h religion.h
+food.o: skills2.h spells2.h stuff.h /usr/include/alloca.h
+food.o: /usr/include/asm/errno.h /usr/include/assert.h
+food.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+food.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+food.o: /usr/include/bits/fcntl.h /usr/include/bits/local_lim.h
+food.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
+food.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
+food.o: /usr/include/bits/sched.h /usr/include/bits/select.h
+food.o: /usr/include/bits/sigset.h /usr/include/bits/stat.h
+food.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
+food.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+food.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+food.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
+food.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
+food.o: /usr/include/fcntl.h /usr/include/features.h
+food.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+food.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+food.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+food.o: /usr/include/g++-3/iterator /usr/include/g++-3/queue
+food.o: /usr/include/g++-3/std/bastring.cc /usr/include/g++-3/std/bastring.h
+food.o: /usr/include/g++-3/std/straits.h /usr/include/g++-3/stl_algobase.h
+food.o: /usr/include/g++-3/stl_alloc.h /usr/include/g++-3/stl_bvector.h
+food.o: /usr/include/g++-3/stl_config.h /usr/include/g++-3/stl_construct.h
+food.o: /usr/include/g++-3/stl_deque.h /usr/include/g++-3/stl_function.h
+food.o: /usr/include/g++-3/stl_heap.h /usr/include/g++-3/stl_iterator.h
+food.o: /usr/include/g++-3/stl_pair.h /usr/include/g++-3/stl_queue.h
+food.o: /usr/include/g++-3/stl_relops.h
+food.o: /usr/include/g++-3/stl_uninitialized.h
+food.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+food.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+food.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
+food.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/limits.h
+food.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+food.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+food.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+food.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+food.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+food.o: /usr/include/wchar.h /usr/include/xlocale.h
+food.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+food.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+food.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+food.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+food.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+food.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+food.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+food.o: wpn-misc.h
+hiscores.o: AppHdr.h debug.h defines.h enum.h externs.h FixAry.h FixVec.h
+hiscores.o: hiscores.h liblinux.h libutil.h message.h mon-util.h player.h
+hiscores.o: tags.h /usr/include/alloca.h /usr/include/asm/errno.h
+hiscores.o: /usr/include/assert.h /usr/include/bits/confname.h
+hiscores.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+hiscores.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+hiscores.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+hiscores.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+hiscores.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+hiscores.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+hiscores.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+hiscores.o: /usr/include/bits/time.h /usr/include/bits/types.h
+hiscores.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+hiscores.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+hiscores.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+hiscores.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+hiscores.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+hiscores.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+hiscores.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+hiscores.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+hiscores.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+hiscores.o: /usr/include/g++-3/std/bastring.h
+hiscores.o: /usr/include/g++-3/std/straits.h
+hiscores.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+hiscores.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+hiscores.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+hiscores.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+hiscores.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+hiscores.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+hiscores.o: /usr/include/g++-3/stl_uninitialized.h
+hiscores.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+hiscores.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+hiscores.o: /usr/include/_G_config.h /usr/include/gconv.h
+hiscores.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+hiscores.o: /usr/include/libio.h /usr/include/limits.h
+hiscores.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+hiscores.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+hiscores.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+hiscores.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+hiscores.o: /usr/include/sys/types.h /usr/include/time.h
+hiscores.o: /usr/include/unistd.h /usr/include/wchar.h /usr/include/xlocale.h
+hiscores.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+hiscores.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+hiscores.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+hiscores.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+hiscores.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+hiscores.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+hiscores.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+hiscores.o: view.h
+initfile.o: AppHdr.h debug.h defines.h enum.h externs.h FixAry.h FixVec.h
+initfile.o: initfile.h items.h liblinux.h libutil.h message.h
+initfile.o: /usr/include/alloca.h /usr/include/asm/errno.h
+initfile.o: /usr/include/assert.h /usr/include/bits/confname.h
+initfile.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+initfile.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+initfile.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+initfile.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+initfile.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+initfile.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+initfile.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+initfile.o: /usr/include/bits/time.h /usr/include/bits/types.h
+initfile.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+initfile.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+initfile.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+initfile.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+initfile.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+initfile.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+initfile.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+initfile.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+initfile.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+initfile.o: /usr/include/g++-3/std/bastring.h
+initfile.o: /usr/include/g++-3/std/straits.h
+initfile.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+initfile.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+initfile.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+initfile.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+initfile.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+initfile.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+initfile.o: /usr/include/g++-3/stl_uninitialized.h
+initfile.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+initfile.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+initfile.o: /usr/include/_G_config.h /usr/include/gconv.h
+initfile.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+initfile.o: /usr/include/libio.h /usr/include/limits.h
+initfile.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+initfile.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+initfile.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+initfile.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+initfile.o: /usr/include/sys/types.h /usr/include/time.h
+initfile.o: /usr/include/unistd.h /usr/include/wchar.h /usr/include/xlocale.h
+initfile.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+initfile.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+initfile.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+initfile.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+initfile.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+initfile.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+initfile.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+initfile.o: view.h
+insult.o: AppHdr.h debug.h defines.h enum.h externs.h FixAry.h FixVec.h
+insult.o: insult.h liblinux.h libutil.h message.h mon-util.h stuff.h
+insult.o: /usr/include/alloca.h /usr/include/asm/errno.h
+insult.o: /usr/include/assert.h /usr/include/bits/confname.h
+insult.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+insult.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+insult.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+insult.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+insult.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+insult.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+insult.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+insult.o: /usr/include/bits/time.h /usr/include/bits/types.h
+insult.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+insult.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+insult.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+insult.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+insult.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+insult.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+insult.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+insult.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+insult.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+insult.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+insult.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+insult.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+insult.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+insult.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+insult.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+insult.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+insult.o: /usr/include/g++-3/stl_uninitialized.h
+insult.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+insult.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+insult.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
+insult.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/limits.h
+insult.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+insult.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+insult.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+insult.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+insult.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+insult.o: /usr/include/wchar.h /usr/include/xlocale.h
+insult.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+insult.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+insult.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+insult.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+insult.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+insult.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+insult.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+invent.o: AppHdr.h debug.h defines.h enum.h externs.h FixAry.h FixVec.h
+invent.o: invent.h itemname.h items.h liblinux.h libutil.h message.h
+invent.o: shopping.h stuff.h /usr/include/alloca.h /usr/include/asm/errno.h
+invent.o: /usr/include/assert.h /usr/include/bits/confname.h
+invent.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+invent.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+invent.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+invent.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+invent.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+invent.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+invent.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+invent.o: /usr/include/bits/time.h /usr/include/bits/types.h
+invent.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+invent.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+invent.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+invent.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+invent.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+invent.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+invent.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+invent.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+invent.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+invent.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+invent.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+invent.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+invent.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+invent.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+invent.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+invent.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+invent.o: /usr/include/g++-3/stl_uninitialized.h
+invent.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+invent.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+invent.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
+invent.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/limits.h
+invent.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+invent.o: /usr/include/stdlib.h /usr/include/string.h
+invent.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+invent.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+invent.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+invent.o: /usr/include/wchar.h /usr/include/xlocale.h
+invent.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+invent.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+invent.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+invent.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+invent.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+invent.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+invent.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h view.h
+itemname.o: AppHdr.h debug.h defines.h enum.h externs.h FixAry.h FixVec.h
+itemname.o: itemname.h liblinux.h libutil.h message.h mon-util.h randart.h
+itemname.o: skills2.h stuff.h /usr/include/alloca.h /usr/include/asm/errno.h
+itemname.o: /usr/include/assert.h /usr/include/bits/confname.h
+itemname.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+itemname.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+itemname.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+itemname.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+itemname.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+itemname.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+itemname.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+itemname.o: /usr/include/bits/time.h /usr/include/bits/types.h
+itemname.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+itemname.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+itemname.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+itemname.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+itemname.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+itemname.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+itemname.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+itemname.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+itemname.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+itemname.o: /usr/include/g++-3/std/bastring.h
+itemname.o: /usr/include/g++-3/std/straits.h
+itemname.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+itemname.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+itemname.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+itemname.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+itemname.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+itemname.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+itemname.o: /usr/include/g++-3/stl_uninitialized.h
+itemname.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+itemname.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+itemname.o: /usr/include/_G_config.h /usr/include/gconv.h
+itemname.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+itemname.o: /usr/include/libio.h /usr/include/limits.h
+itemname.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+itemname.o: /usr/include/stdlib.h /usr/include/string.h
+itemname.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+itemname.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+itemname.o: /usr/include/sys/types.h /usr/include/time.h
+itemname.o: /usr/include/unistd.h /usr/include/wchar.h /usr/include/xlocale.h
+itemname.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+itemname.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+itemname.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+itemname.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+itemname.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+itemname.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+itemname.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+itemname.o: view.h wpn-misc.h
+items.o: AppHdr.h beam.h debug.h defines.h delay.h effects.h enum.h externs.h
+items.o: fight.h FixAry.h FixVec.h invent.h itemname.h items.h item_use.h
+items.o: it_use2.h liblinux.h libutil.h message.h misc.h monplace.h
+items.o: mon-util.h mutation.h player.h randart.h religion.h shopping.h
+items.o: skills.h spl-cast.h stuff.h /usr/include/alloca.h
+items.o: /usr/include/asm/errno.h /usr/include/assert.h
+items.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+items.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+items.o: /usr/include/bits/fcntl.h /usr/include/bits/local_lim.h
+items.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
+items.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
+items.o: /usr/include/bits/sched.h /usr/include/bits/select.h
+items.o: /usr/include/bits/sigset.h /usr/include/bits/stat.h
+items.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
+items.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+items.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+items.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
+items.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
+items.o: /usr/include/fcntl.h /usr/include/features.h
+items.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+items.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+items.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+items.o: /usr/include/g++-3/iterator /usr/include/g++-3/queue
+items.o: /usr/include/g++-3/std/bastring.cc /usr/include/g++-3/std/bastring.h
+items.o: /usr/include/g++-3/std/straits.h /usr/include/g++-3/stl_algobase.h
+items.o: /usr/include/g++-3/stl_alloc.h /usr/include/g++-3/stl_bvector.h
+items.o: /usr/include/g++-3/stl_config.h /usr/include/g++-3/stl_construct.h
+items.o: /usr/include/g++-3/stl_deque.h /usr/include/g++-3/stl_function.h
+items.o: /usr/include/g++-3/stl_heap.h /usr/include/g++-3/stl_iterator.h
+items.o: /usr/include/g++-3/stl_pair.h /usr/include/g++-3/stl_queue.h
+items.o: /usr/include/g++-3/stl_relops.h
+items.o: /usr/include/g++-3/stl_uninitialized.h
+items.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+items.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+items.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
+items.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/limits.h
+items.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+items.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+items.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+items.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+items.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+items.o: /usr/include/wchar.h /usr/include/xlocale.h
+items.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+items.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+items.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+items.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+items.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+items.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+items.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+item_use.o: AppHdr.h beam.h debug.h defines.h delay.h describe.h direct.h
+item_use.o: effects.h enum.h externs.h fight.h FixAry.h FixVec.h food.h
+item_use.o: invent.h itemname.h items.h item_use.h it_use2.h it_use3.h
+item_use.o: liblinux.h libutil.h message.h misc.h monplace.h monstuff.h
+item_use.o: mon-util.h mstuff2.h ouch.h player.h randart.h religion.h
+item_use.o: skills2.h skills.h spells1.h spells2.h spells3.h spl-book.h
+item_use.o: spl-cast.h stuff.h transfor.h /usr/include/alloca.h
+item_use.o: /usr/include/asm/errno.h /usr/include/assert.h
+item_use.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+item_use.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+item_use.o: /usr/include/bits/fcntl.h /usr/include/bits/local_lim.h
+item_use.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
+item_use.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
+item_use.o: /usr/include/bits/sched.h /usr/include/bits/select.h
+item_use.o: /usr/include/bits/sigset.h /usr/include/bits/stat.h
+item_use.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
+item_use.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+item_use.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+item_use.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
+item_use.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
+item_use.o: /usr/include/fcntl.h /usr/include/features.h
+item_use.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+item_use.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+item_use.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+item_use.o: /usr/include/g++-3/iterator /usr/include/g++-3/queue
+item_use.o: /usr/include/g++-3/std/bastring.cc
+item_use.o: /usr/include/g++-3/std/bastring.h
+item_use.o: /usr/include/g++-3/std/straits.h
+item_use.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+item_use.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+item_use.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+item_use.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+item_use.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+item_use.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+item_use.o: /usr/include/g++-3/stl_uninitialized.h
+item_use.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+item_use.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+item_use.o: /usr/include/_G_config.h /usr/include/gconv.h
+item_use.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+item_use.o: /usr/include/libio.h /usr/include/limits.h
+item_use.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+item_use.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+item_use.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+item_use.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+item_use.o: /usr/include/sys/types.h /usr/include/time.h
+item_use.o: /usr/include/unistd.h /usr/include/wchar.h /usr/include/xlocale.h
+item_use.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+item_use.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+item_use.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+item_use.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+item_use.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+item_use.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+item_use.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+item_use.o: view.h wpn-misc.h
+it_use2.o: AppHdr.h beam.h debug.h defines.h effects.h enum.h externs.h
+it_use2.o: FixAry.h FixVec.h food.h itemname.h it_use2.h liblinux.h libutil.h
+it_use2.o: message.h misc.h mutation.h player.h randart.h religion.h
+it_use2.o: skills2.h spells2.h spl-cast.h stuff.h /usr/include/alloca.h
+it_use2.o: /usr/include/asm/errno.h /usr/include/assert.h
+it_use2.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+it_use2.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+it_use2.o: /usr/include/bits/fcntl.h /usr/include/bits/local_lim.h
+it_use2.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
+it_use2.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
+it_use2.o: /usr/include/bits/sched.h /usr/include/bits/select.h
+it_use2.o: /usr/include/bits/sigset.h /usr/include/bits/stat.h
+it_use2.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
+it_use2.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+it_use2.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+it_use2.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
+it_use2.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
+it_use2.o: /usr/include/fcntl.h /usr/include/features.h
+it_use2.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+it_use2.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+it_use2.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+it_use2.o: /usr/include/g++-3/iterator /usr/include/g++-3/queue
+it_use2.o: /usr/include/g++-3/std/bastring.cc
+it_use2.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+it_use2.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+it_use2.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+it_use2.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+it_use2.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+it_use2.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+it_use2.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+it_use2.o: /usr/include/g++-3/stl_uninitialized.h
+it_use2.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+it_use2.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+it_use2.o: /usr/include/_G_config.h /usr/include/gconv.h
+it_use2.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+it_use2.o: /usr/include/libio.h /usr/include/limits.h
+it_use2.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+it_use2.o: /usr/include/stdlib.h /usr/include/string.h
+it_use2.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+it_use2.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+it_use2.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+it_use2.o: /usr/include/wchar.h /usr/include/xlocale.h
+it_use2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+it_use2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+it_use2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+it_use2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+it_use2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+it_use2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+it_use2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h view.h
+it_use3.o: AppHdr.h beam.h debug.h decks.h defines.h direct.h effects.h
+it_use3.o: enum.h externs.h fight.h FixAry.h FixVec.h itemname.h items.h
+it_use3.o: it_use2.h it_use3.h liblinux.h libutil.h message.h misc.h
+it_use3.o: monplace.h monstuff.h player.h randart.h skills2.h skills.h
+it_use3.o: spells1.h spells2.h spl-book.h spl-cast.h spl-util.h stuff.h
+it_use3.o: /usr/include/alloca.h /usr/include/asm/errno.h
+it_use3.o: /usr/include/assert.h /usr/include/bits/confname.h
+it_use3.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+it_use3.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+it_use3.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+it_use3.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+it_use3.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+it_use3.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+it_use3.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+it_use3.o: /usr/include/bits/time.h /usr/include/bits/types.h
+it_use3.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+it_use3.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+it_use3.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+it_use3.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+it_use3.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+it_use3.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+it_use3.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+it_use3.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+it_use3.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+it_use3.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+it_use3.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+it_use3.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+it_use3.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+it_use3.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+it_use3.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+it_use3.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+it_use3.o: /usr/include/g++-3/stl_uninitialized.h
+it_use3.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+it_use3.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+it_use3.o: /usr/include/_G_config.h /usr/include/gconv.h
+it_use3.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+it_use3.o: /usr/include/libio.h /usr/include/limits.h
+it_use3.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+it_use3.o: /usr/include/stdlib.h /usr/include/string.h
+it_use3.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+it_use3.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+it_use3.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+it_use3.o: /usr/include/wchar.h /usr/include/xlocale.h
+it_use3.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+it_use3.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+it_use3.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+it_use3.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+it_use3.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+it_use3.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+it_use3.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h view.h
+it_use3.o: wpn-misc.h
+lev-pand.o: AppHdr.h debug.h defines.h enum.h externs.h FixAry.h FixVec.h
+lev-pand.o: lev-pand.h liblinux.h libutil.h message.h mon-pick.h monplace.h
+lev-pand.o: stuff.h /usr/include/alloca.h /usr/include/asm/errno.h
+lev-pand.o: /usr/include/assert.h /usr/include/bits/confname.h
+lev-pand.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+lev-pand.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+lev-pand.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+lev-pand.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+lev-pand.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+lev-pand.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+lev-pand.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+lev-pand.o: /usr/include/bits/time.h /usr/include/bits/types.h
+lev-pand.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+lev-pand.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+lev-pand.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+lev-pand.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+lev-pand.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+lev-pand.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+lev-pand.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+lev-pand.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+lev-pand.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+lev-pand.o: /usr/include/g++-3/std/bastring.h
+lev-pand.o: /usr/include/g++-3/std/straits.h
+lev-pand.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+lev-pand.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+lev-pand.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+lev-pand.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+lev-pand.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+lev-pand.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+lev-pand.o: /usr/include/g++-3/stl_uninitialized.h
+lev-pand.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+lev-pand.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+lev-pand.o: /usr/include/_G_config.h /usr/include/gconv.h
+lev-pand.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+lev-pand.o: /usr/include/libio.h /usr/include/limits.h
+lev-pand.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+lev-pand.o: /usr/include/stdlib.h /usr/include/string.h
+lev-pand.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+lev-pand.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+lev-pand.o: /usr/include/sys/types.h /usr/include/time.h
+lev-pand.o: /usr/include/unistd.h /usr/include/wchar.h /usr/include/xlocale.h
+lev-pand.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+lev-pand.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+lev-pand.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+lev-pand.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+lev-pand.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+lev-pand.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+lev-pand.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+liblinux.o: AppHdr.h debug.h defines.h enum.h externs.h FixAry.h FixVec.h
+liblinux.o: liblinux.h libutil.h message.h /usr/include/alloca.h
+liblinux.o: /usr/include/asm/errno.h /usr/include/asm/sigcontext.h
+liblinux.o: /usr/include/assert.h /usr/include/bits/confname.h
+liblinux.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+liblinux.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+liblinux.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+liblinux.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+liblinux.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+liblinux.o: /usr/include/bits/select.h /usr/include/bits/sigaction.h
+liblinux.o: /usr/include/bits/sigcontext.h /usr/include/bits/siginfo.h
+liblinux.o: /usr/include/bits/signum.h /usr/include/bits/sigset.h
+liblinux.o: /usr/include/bits/sigstack.h /usr/include/bits/sigthread.h
+liblinux.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+liblinux.o: /usr/include/bits/termios.h /usr/include/bits/time.h
+liblinux.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+liblinux.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+liblinux.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
+liblinux.o: /usr/include/ctype.h /usr/include/curses.h /usr/include/endian.h
+liblinux.o: /usr/include/errno.h /usr/include/fcntl.h /usr/include/features.h
+liblinux.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+liblinux.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+liblinux.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+liblinux.o: /usr/include/g++-3/iterator /usr/include/g++-3/queue
+liblinux.o: /usr/include/g++-3/std/bastring.cc
+liblinux.o: /usr/include/g++-3/std/bastring.h
+liblinux.o: /usr/include/g++-3/std/straits.h
+liblinux.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+liblinux.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+liblinux.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+liblinux.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+liblinux.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+liblinux.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+liblinux.o: /usr/include/g++-3/stl_uninitialized.h
+liblinux.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+liblinux.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+liblinux.o: /usr/include/_G_config.h /usr/include/gconv.h
+liblinux.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+liblinux.o: /usr/include/libio.h /usr/include/limits.h
+liblinux.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+liblinux.o: /usr/include/ncurses/curses.h /usr/include/ncurses/ncurses_dll.h
+liblinux.o: /usr/include/ncurses/unctrl.h /usr/include/signal.h
+liblinux.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+liblinux.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+liblinux.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+liblinux.o: /usr/include/sys/ttydefaults.h /usr/include/sys/types.h
+liblinux.o: /usr/include/sys/ucontext.h /usr/include/termios.h
+liblinux.o: /usr/include/time.h /usr/include/ucontext.h /usr/include/unistd.h
+liblinux.o: /usr/include/wchar.h /usr/include/xlocale.h
+liblinux.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+liblinux.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+liblinux.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+liblinux.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+liblinux.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+liblinux.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+liblinux.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+libutil.o: AppHdr.h liblinux.h libutil.h /usr/include/alloca.h
+libutil.o: /usr/include/asm/errno.h /usr/include/assert.h
+libutil.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+libutil.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+libutil.o: /usr/include/bits/fcntl.h /usr/include/bits/posix_opt.h
+libutil.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+libutil.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+libutil.o: /usr/include/bits/stat.h /usr/include/bits/time.h
+libutil.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+libutil.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+libutil.o: /usr/include/bits/wordsize.h /usr/include/ctype.h
+libutil.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+libutil.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+libutil.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+libutil.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+libutil.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+libutil.o: /usr/include/g++-3/std/bastring.cc
+libutil.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+libutil.o: /usr/include/g++-3/stl_alloc.h /usr/include/g++-3/stl_config.h
+libutil.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_relops.h
+libutil.o: /usr/include/g++-3/streambuf.h /usr/include/g++-3/string
+libutil.o: /usr/include/_G_config.h /usr/include/gconv.h
+libutil.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+libutil.o: /usr/include/libio.h /usr/include/linux/errno.h
+libutil.o: /usr/include/stdlib.h /usr/include/string.h
+libutil.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+libutil.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+libutil.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+libutil.o: /usr/include/wchar.h /usr/include/xlocale.h
+libutil.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+libutil.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+libw32c.o: AppHdr.h defines.h liblinux.h libutil.h /usr/include/alloca.h
+libw32c.o: /usr/include/asm/errno.h /usr/include/assert.h
+libw32c.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+libw32c.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+libw32c.o: /usr/include/bits/fcntl.h /usr/include/bits/posix_opt.h
+libw32c.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+libw32c.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+libw32c.o: /usr/include/bits/stat.h /usr/include/bits/time.h
+libw32c.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+libw32c.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+libw32c.o: /usr/include/bits/wordsize.h /usr/include/ctype.h
+libw32c.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+libw32c.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+libw32c.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+libw32c.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+libw32c.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+libw32c.o: /usr/include/g++-3/std/bastring.cc
+libw32c.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+libw32c.o: /usr/include/g++-3/stl_alloc.h /usr/include/g++-3/stl_config.h
+libw32c.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_relops.h
+libw32c.o: /usr/include/g++-3/streambuf.h /usr/include/g++-3/string
+libw32c.o: /usr/include/_G_config.h /usr/include/gconv.h
+libw32c.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+libw32c.o: /usr/include/libio.h /usr/include/linux/errno.h
+libw32c.o: /usr/include/stdlib.h /usr/include/string.h
+libw32c.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+libw32c.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+libw32c.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+libw32c.o: /usr/include/wchar.h /usr/include/xlocale.h
+libw32c.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+libw32c.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h version.h
+macro.o: AppHdr.h debug.h defines.h enum.h externs.h FixAry.h FixVec.h
+macro.o: liblinux.h libmac.h libutil.h macro.h message.h
+macro.o: /usr/include/alloca.h /usr/include/asm/errno.h /usr/include/assert.h
+macro.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+macro.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+macro.o: /usr/include/bits/fcntl.h /usr/include/bits/local_lim.h
+macro.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
+macro.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
+macro.o: /usr/include/bits/sched.h /usr/include/bits/select.h
+macro.o: /usr/include/bits/sigset.h /usr/include/bits/stat.h
+macro.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
+macro.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+macro.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+macro.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
+macro.o: /usr/include/ctype.h /usr/include/curses.h /usr/include/endian.h
+macro.o: /usr/include/errno.h /usr/include/fcntl.h /usr/include/features.h
+macro.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+macro.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+macro.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+macro.o: /usr/include/g++-3/iterator /usr/include/g++-3/queue
+macro.o: /usr/include/g++-3/std/bastring.cc /usr/include/g++-3/std/bastring.h
+macro.o: /usr/include/g++-3/std/straits.h /usr/include/g++-3/stl_algobase.h
+macro.o: /usr/include/g++-3/stl_alloc.h /usr/include/g++-3/stl_bvector.h
+macro.o: /usr/include/g++-3/stl_config.h /usr/include/g++-3/stl_construct.h
+macro.o: /usr/include/g++-3/stl_deque.h /usr/include/g++-3/stl_function.h
+macro.o: /usr/include/g++-3/stl_heap.h /usr/include/g++-3/stl_iterator.h
+macro.o: /usr/include/g++-3/stl_pair.h /usr/include/g++-3/stl_queue.h
+macro.o: /usr/include/g++-3/stl_relops.h
+macro.o: /usr/include/g++-3/stl_uninitialized.h
+macro.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+macro.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+macro.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
+macro.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/limits.h
+macro.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+macro.o: /usr/include/ncurses/curses.h /usr/include/ncurses/ncurses_dll.h
+macro.o: /usr/include/ncurses/unctrl.h /usr/include/stdio.h
+macro.o: /usr/include/stdlib.h /usr/include/string.h /usr/include/sys/cdefs.h
+macro.o: /usr/include/sys/select.h /usr/include/sys/stat.h
+macro.o: /usr/include/sys/sysmacros.h /usr/include/sys/types.h
+macro.o: /usr/include/time.h /usr/include/unistd.h /usr/include/wchar.h
+macro.o: /usr/include/xlocale.h
+macro.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+macro.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+macro.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+macro.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+macro.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+macro.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+macro.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+maps.o: AppHdr.h debug.h enum.h FixVec.h liblinux.h libutil.h maps.h
+maps.o: monplace.h stuff.h /usr/include/alloca.h /usr/include/asm/errno.h
+maps.o: /usr/include/assert.h /usr/include/bits/confname.h
+maps.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+maps.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+maps.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
+maps.o: /usr/include/bits/sched.h /usr/include/bits/select.h
+maps.o: /usr/include/bits/sigset.h /usr/include/bits/stat.h
+maps.o: /usr/include/bits/time.h /usr/include/bits/types.h
+maps.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+maps.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+maps.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
+maps.o: /usr/include/fcntl.h /usr/include/features.h
+maps.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+maps.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+maps.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+maps.o: /usr/include/g++-3/iterator /usr/include/g++-3/std/bastring.cc
+maps.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+maps.o: /usr/include/g++-3/stl_alloc.h /usr/include/g++-3/stl_config.h
+maps.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_relops.h
+maps.o: /usr/include/g++-3/streambuf.h /usr/include/g++-3/string
+maps.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
+maps.o: /usr/include/gnu/stubs.h /usr/include/libio.h
+maps.o: /usr/include/linux/errno.h /usr/include/stdlib.h
+maps.o: /usr/include/string.h /usr/include/sys/cdefs.h
+maps.o: /usr/include/sys/select.h /usr/include/sys/stat.h
+maps.o: /usr/include/sys/sysmacros.h /usr/include/sys/types.h
+maps.o: /usr/include/time.h /usr/include/unistd.h /usr/include/wchar.h
+maps.o: /usr/include/xlocale.h
+maps.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+maps.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+message.o: AppHdr.h debug.h defines.h enum.h externs.h FixAry.h FixVec.h
+message.o: liblinux.h libutil.h message.h religion.h stuff.h
+message.o: /usr/include/alloca.h /usr/include/asm/errno.h
+message.o: /usr/include/assert.h /usr/include/bits/confname.h
+message.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+message.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+message.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+message.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+message.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+message.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+message.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+message.o: /usr/include/bits/time.h /usr/include/bits/types.h
+message.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+message.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+message.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+message.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+message.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+message.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+message.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+message.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+message.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+message.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+message.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+message.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+message.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+message.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+message.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+message.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+message.o: /usr/include/g++-3/stl_uninitialized.h
+message.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+message.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+message.o: /usr/include/_G_config.h /usr/include/gconv.h
+message.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+message.o: /usr/include/libio.h /usr/include/limits.h
+message.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+message.o: /usr/include/stdlib.h /usr/include/string.h
+message.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+message.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+message.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+message.o: /usr/include/wchar.h /usr/include/xlocale.h
+message.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+message.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+message.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+message.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+message.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+message.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+message.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h view.h
+misc.o: AppHdr.h cloud.h debug.h defines.h enum.h externs.h fight.h files.h
+misc.o: FixAry.h FixVec.h food.h items.h it_use2.h lev-pand.h liblinux.h
+misc.o: libutil.h message.h misc.h monplace.h monstuff.h mon-util.h ouch.h
+misc.o: player.h shopping.h skills2.h skills.h spells3.h spl-cast.h stuff.h
+misc.o: transfor.h /usr/include/alloca.h /usr/include/asm/errno.h
+misc.o: /usr/include/assert.h /usr/include/bits/confname.h
+misc.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+misc.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+misc.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+misc.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+misc.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+misc.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+misc.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+misc.o: /usr/include/bits/time.h /usr/include/bits/types.h
+misc.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+misc.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+misc.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+misc.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+misc.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+misc.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+misc.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+misc.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+misc.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+misc.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+misc.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+misc.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+misc.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+misc.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+misc.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+misc.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+misc.o: /usr/include/g++-3/stl_uninitialized.h
+misc.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+misc.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+misc.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
+misc.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/limits.h
+misc.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+misc.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+misc.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+misc.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+misc.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+misc.o: /usr/include/wchar.h /usr/include/xlocale.h
+misc.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+misc.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+misc.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+misc.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+misc.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+misc.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+misc.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h view.h
+mon-pick.o: AppHdr.h debug.h defines.h enum.h externs.h FixAry.h FixVec.h
+mon-pick.o: liblinux.h libutil.h message.h mon-pick.h /usr/include/alloca.h
+mon-pick.o: /usr/include/asm/errno.h /usr/include/assert.h
+mon-pick.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+mon-pick.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+mon-pick.o: /usr/include/bits/fcntl.h /usr/include/bits/local_lim.h
+mon-pick.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
+mon-pick.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
+mon-pick.o: /usr/include/bits/sched.h /usr/include/bits/select.h
+mon-pick.o: /usr/include/bits/sigset.h /usr/include/bits/stat.h
+mon-pick.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
+mon-pick.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+mon-pick.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+mon-pick.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
+mon-pick.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
+mon-pick.o: /usr/include/fcntl.h /usr/include/features.h
+mon-pick.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+mon-pick.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+mon-pick.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+mon-pick.o: /usr/include/g++-3/iterator /usr/include/g++-3/queue
+mon-pick.o: /usr/include/g++-3/std/bastring.cc
+mon-pick.o: /usr/include/g++-3/std/bastring.h
+mon-pick.o: /usr/include/g++-3/std/straits.h
+mon-pick.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+mon-pick.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+mon-pick.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+mon-pick.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+mon-pick.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+mon-pick.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+mon-pick.o: /usr/include/g++-3/stl_uninitialized.h
+mon-pick.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+mon-pick.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+mon-pick.o: /usr/include/_G_config.h /usr/include/gconv.h
+mon-pick.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+mon-pick.o: /usr/include/libio.h /usr/include/limits.h
+mon-pick.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+mon-pick.o: /usr/include/stdlib.h /usr/include/string.h
+mon-pick.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+mon-pick.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+mon-pick.o: /usr/include/sys/types.h /usr/include/time.h
+mon-pick.o: /usr/include/unistd.h /usr/include/wchar.h /usr/include/xlocale.h
+mon-pick.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+mon-pick.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+mon-pick.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+mon-pick.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+mon-pick.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+mon-pick.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+mon-pick.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+monplace.o: AppHdr.h debug.h defines.h dungeon.h enum.h externs.h FixAry.h
+monplace.o: FixVec.h liblinux.h libutil.h message.h misc.h mon-pick.h
+monplace.o: monplace.h monstuff.h mon-util.h player.h spells4.h stuff.h
+monplace.o: /usr/include/alloca.h /usr/include/asm/errno.h
+monplace.o: /usr/include/assert.h /usr/include/bits/confname.h
+monplace.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+monplace.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+monplace.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+monplace.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+monplace.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+monplace.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+monplace.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+monplace.o: /usr/include/bits/time.h /usr/include/bits/types.h
+monplace.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+monplace.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+monplace.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+monplace.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+monplace.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+monplace.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+monplace.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+monplace.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+monplace.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+monplace.o: /usr/include/g++-3/std/bastring.h
+monplace.o: /usr/include/g++-3/std/straits.h
+monplace.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+monplace.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+monplace.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+monplace.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+monplace.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+monplace.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+monplace.o: /usr/include/g++-3/stl_uninitialized.h
+monplace.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+monplace.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+monplace.o: /usr/include/_G_config.h /usr/include/gconv.h
+monplace.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+monplace.o: /usr/include/libio.h /usr/include/limits.h
+monplace.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+monplace.o: /usr/include/stdlib.h /usr/include/string.h
+monplace.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+monplace.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+monplace.o: /usr/include/sys/types.h /usr/include/time.h
+monplace.o: /usr/include/unistd.h /usr/include/wchar.h /usr/include/xlocale.h
+monplace.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+monplace.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+monplace.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+monplace.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+monplace.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+monplace.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+monplace.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+monspeak.o: AppHdr.h beam.h debug.h defines.h enum.h externs.h fight.h
+monspeak.o: FixAry.h FixVec.h insult.h itemname.h liblinux.h libutil.h
+monspeak.o: message.h misc.h monplace.h monspeak.h monstuff.h mon-util.h
+monspeak.o: mstuff2.h player.h spells2.h spells4.h stuff.h
+monspeak.o: /usr/include/alloca.h /usr/include/asm/errno.h
+monspeak.o: /usr/include/assert.h /usr/include/bits/confname.h
+monspeak.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+monspeak.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+monspeak.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+monspeak.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+monspeak.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+monspeak.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+monspeak.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+monspeak.o: /usr/include/bits/time.h /usr/include/bits/types.h
+monspeak.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+monspeak.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+monspeak.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+monspeak.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+monspeak.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+monspeak.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+monspeak.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+monspeak.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+monspeak.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+monspeak.o: /usr/include/g++-3/std/bastring.h
+monspeak.o: /usr/include/g++-3/std/straits.h
+monspeak.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+monspeak.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+monspeak.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+monspeak.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+monspeak.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+monspeak.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+monspeak.o: /usr/include/g++-3/stl_uninitialized.h
+monspeak.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+monspeak.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+monspeak.o: /usr/include/_G_config.h /usr/include/gconv.h
+monspeak.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+monspeak.o: /usr/include/libio.h /usr/include/limits.h
+monspeak.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+monspeak.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+monspeak.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+monspeak.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+monspeak.o: /usr/include/sys/types.h /usr/include/time.h
+monspeak.o: /usr/include/unistd.h /usr/include/wchar.h /usr/include/xlocale.h
+monspeak.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+monspeak.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+monspeak.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+monspeak.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+monspeak.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+monspeak.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+monspeak.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+monspeak.o: view.h
+monstuff.o: AppHdr.h beam.h cloud.h debug.h defines.h enum.h externs.h
+monstuff.o: fight.h FixAry.h FixVec.h itemname.h items.h liblinux.h libutil.h
+monstuff.o: message.h misc.h monplace.h monspeak.h monstuff.h mon-util.h
+monstuff.o: mstuff2.h player.h randart.h spells2.h spells4.h stuff.h
+monstuff.o: /usr/include/alloca.h /usr/include/asm/errno.h
+monstuff.o: /usr/include/assert.h /usr/include/bits/confname.h
+monstuff.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+monstuff.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+monstuff.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+monstuff.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+monstuff.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+monstuff.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+monstuff.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+monstuff.o: /usr/include/bits/time.h /usr/include/bits/types.h
+monstuff.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+monstuff.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+monstuff.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+monstuff.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+monstuff.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+monstuff.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+monstuff.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+monstuff.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+monstuff.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+monstuff.o: /usr/include/g++-3/std/bastring.h
+monstuff.o: /usr/include/g++-3/std/straits.h
+monstuff.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+monstuff.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+monstuff.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+monstuff.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+monstuff.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+monstuff.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+monstuff.o: /usr/include/g++-3/stl_uninitialized.h
+monstuff.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+monstuff.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+monstuff.o: /usr/include/_G_config.h /usr/include/gconv.h
+monstuff.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+monstuff.o: /usr/include/libio.h /usr/include/limits.h
+monstuff.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+monstuff.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+monstuff.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+monstuff.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+monstuff.o: /usr/include/sys/types.h /usr/include/time.h
+monstuff.o: /usr/include/unistd.h /usr/include/wchar.h /usr/include/xlocale.h
+monstuff.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+monstuff.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+monstuff.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+monstuff.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+monstuff.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+monstuff.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+monstuff.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+monstuff.o: view.h
+mon-util.o: AppHdr.h debug.h defines.h enum.h externs.h FixAry.h FixVec.h
+mon-util.o: itemname.h liblinux.h libutil.h message.h mon-data.h mon-spll.h
+mon-util.o: monstuff.h mon-util.h player.h randart.h stuff.h
+mon-util.o: /usr/include/alloca.h /usr/include/asm/errno.h
+mon-util.o: /usr/include/assert.h /usr/include/bits/confname.h
+mon-util.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+mon-util.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+mon-util.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+mon-util.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+mon-util.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+mon-util.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+mon-util.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+mon-util.o: /usr/include/bits/time.h /usr/include/bits/types.h
+mon-util.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+mon-util.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+mon-util.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+mon-util.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+mon-util.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+mon-util.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+mon-util.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+mon-util.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+mon-util.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+mon-util.o: /usr/include/g++-3/std/bastring.h
+mon-util.o: /usr/include/g++-3/std/straits.h
+mon-util.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+mon-util.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+mon-util.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+mon-util.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+mon-util.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+mon-util.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+mon-util.o: /usr/include/g++-3/stl_uninitialized.h
+mon-util.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+mon-util.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+mon-util.o: /usr/include/_G_config.h /usr/include/gconv.h
+mon-util.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+mon-util.o: /usr/include/libio.h /usr/include/limits.h
+mon-util.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+mon-util.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+mon-util.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+mon-util.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+mon-util.o: /usr/include/sys/types.h /usr/include/time.h
+mon-util.o: /usr/include/unistd.h /usr/include/wchar.h /usr/include/xlocale.h
+mon-util.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+mon-util.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+mon-util.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+mon-util.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+mon-util.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+mon-util.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+mon-util.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+mon-util.o: view.h
+mstuff2.o: AppHdr.h beam.h debug.h defines.h effects.h enum.h externs.h
+mstuff2.o: fight.h FixAry.h FixVec.h itemname.h items.h liblinux.h libutil.h
+mstuff2.o: message.h misc.h monplace.h monstuff.h mon-util.h mstuff2.h
+mstuff2.o: player.h spells2.h spells4.h spl-cast.h stuff.h
+mstuff2.o: /usr/include/alloca.h /usr/include/asm/errno.h
+mstuff2.o: /usr/include/assert.h /usr/include/bits/confname.h
+mstuff2.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+mstuff2.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+mstuff2.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+mstuff2.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+mstuff2.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+mstuff2.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+mstuff2.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+mstuff2.o: /usr/include/bits/time.h /usr/include/bits/types.h
+mstuff2.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+mstuff2.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+mstuff2.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+mstuff2.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+mstuff2.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+mstuff2.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+mstuff2.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+mstuff2.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+mstuff2.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+mstuff2.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+mstuff2.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+mstuff2.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+mstuff2.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+mstuff2.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+mstuff2.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+mstuff2.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+mstuff2.o: /usr/include/g++-3/stl_uninitialized.h
+mstuff2.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+mstuff2.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+mstuff2.o: /usr/include/_G_config.h /usr/include/gconv.h
+mstuff2.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+mstuff2.o: /usr/include/libio.h /usr/include/limits.h
+mstuff2.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+mstuff2.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+mstuff2.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+mstuff2.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+mstuff2.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+mstuff2.o: /usr/include/wchar.h /usr/include/xlocale.h
+mstuff2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+mstuff2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+mstuff2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+mstuff2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+mstuff2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+mstuff2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+mstuff2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h view.h
+mstuff2.o: wpn-misc.h
+mutation.o: AppHdr.h debug.h defines.h enum.h externs.h FixAry.h FixVec.h
+mutation.o: liblinux.h libutil.h message.h mutation.h player.h skills2.h
+mutation.o: stuff.h transfor.h /usr/include/alloca.h /usr/include/asm/errno.h
+mutation.o: /usr/include/assert.h /usr/include/bits/confname.h
+mutation.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+mutation.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+mutation.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+mutation.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+mutation.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+mutation.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+mutation.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+mutation.o: /usr/include/bits/time.h /usr/include/bits/types.h
+mutation.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+mutation.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+mutation.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+mutation.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+mutation.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+mutation.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+mutation.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+mutation.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+mutation.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+mutation.o: /usr/include/g++-3/std/bastring.h
+mutation.o: /usr/include/g++-3/std/straits.h
+mutation.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+mutation.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+mutation.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+mutation.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+mutation.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+mutation.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+mutation.o: /usr/include/g++-3/stl_uninitialized.h
+mutation.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+mutation.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+mutation.o: /usr/include/_G_config.h /usr/include/gconv.h
+mutation.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+mutation.o: /usr/include/libio.h /usr/include/limits.h
+mutation.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+mutation.o: /usr/include/stdlib.h /usr/include/string.h
+mutation.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+mutation.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+mutation.o: /usr/include/sys/types.h /usr/include/time.h
+mutation.o: /usr/include/unistd.h /usr/include/wchar.h /usr/include/xlocale.h
+mutation.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+mutation.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+mutation.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+mutation.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+mutation.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+mutation.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+mutation.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+mutation.o: view.h
+newgame.o: AppHdr.h debug.h defines.h enum.h externs.h fight.h files.h
+newgame.o: FixAry.h FixVec.h itemname.h items.h liblinux.h libutil.h
+newgame.o: message.h newgame.h player.h randart.h skills2.h skills.h stuff.h
+newgame.o: /usr/include/alloca.h /usr/include/asm/errno.h
+newgame.o: /usr/include/assert.h /usr/include/bits/confname.h
+newgame.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+newgame.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+newgame.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+newgame.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+newgame.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+newgame.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+newgame.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+newgame.o: /usr/include/bits/time.h /usr/include/bits/types.h
+newgame.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+newgame.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+newgame.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+newgame.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+newgame.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+newgame.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+newgame.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+newgame.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+newgame.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+newgame.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+newgame.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+newgame.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+newgame.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+newgame.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+newgame.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+newgame.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+newgame.o: /usr/include/g++-3/stl_uninitialized.h
+newgame.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+newgame.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+newgame.o: /usr/include/_G_config.h /usr/include/gconv.h
+newgame.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+newgame.o: /usr/include/libio.h /usr/include/limits.h
+newgame.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+newgame.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+newgame.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+newgame.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+newgame.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+newgame.o: /usr/include/wchar.h /usr/include/xlocale.h
+newgame.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+newgame.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+newgame.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+newgame.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+newgame.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+newgame.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+newgame.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+newgame.o: version.h wpn-misc.h
+ouch.o: AppHdr.h chardump.h debug.h defines.h delay.h enum.h externs.h
+ouch.o: files.h FixAry.h FixVec.h hiscores.h invent.h itemname.h items.h
+ouch.o: liblinux.h libutil.h message.h mon-util.h ouch.h player.h randart.h
+ouch.o: religion.h shopping.h skills2.h stuff.h /usr/include/alloca.h
+ouch.o: /usr/include/asm/errno.h /usr/include/assert.h
+ouch.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+ouch.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+ouch.o: /usr/include/bits/fcntl.h /usr/include/bits/local_lim.h
+ouch.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
+ouch.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
+ouch.o: /usr/include/bits/sched.h /usr/include/bits/select.h
+ouch.o: /usr/include/bits/sigset.h /usr/include/bits/stat.h
+ouch.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
+ouch.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+ouch.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+ouch.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
+ouch.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
+ouch.o: /usr/include/fcntl.h /usr/include/features.h
+ouch.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+ouch.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+ouch.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+ouch.o: /usr/include/g++-3/iterator /usr/include/g++-3/queue
+ouch.o: /usr/include/g++-3/std/bastring.cc /usr/include/g++-3/std/bastring.h
+ouch.o: /usr/include/g++-3/std/straits.h /usr/include/g++-3/stl_algobase.h
+ouch.o: /usr/include/g++-3/stl_alloc.h /usr/include/g++-3/stl_bvector.h
+ouch.o: /usr/include/g++-3/stl_config.h /usr/include/g++-3/stl_construct.h
+ouch.o: /usr/include/g++-3/stl_deque.h /usr/include/g++-3/stl_function.h
+ouch.o: /usr/include/g++-3/stl_heap.h /usr/include/g++-3/stl_iterator.h
+ouch.o: /usr/include/g++-3/stl_pair.h /usr/include/g++-3/stl_queue.h
+ouch.o: /usr/include/g++-3/stl_relops.h
+ouch.o: /usr/include/g++-3/stl_uninitialized.h
+ouch.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+ouch.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+ouch.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
+ouch.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/limits.h
+ouch.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+ouch.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+ouch.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+ouch.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+ouch.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+ouch.o: /usr/include/wchar.h /usr/include/xlocale.h
+ouch.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+ouch.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+ouch.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+ouch.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+ouch.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+ouch.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+ouch.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+output.o: AppHdr.h debug.h defines.h enum.h externs.h FixAry.h FixVec.h
+output.o: itemname.h liblinux.h libutil.h message.h ouch.h output.h player.h
+output.o: /usr/include/alloca.h /usr/include/asm/errno.h
+output.o: /usr/include/assert.h /usr/include/bits/confname.h
+output.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+output.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+output.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+output.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+output.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+output.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+output.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+output.o: /usr/include/bits/time.h /usr/include/bits/types.h
+output.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+output.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+output.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+output.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+output.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+output.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+output.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+output.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+output.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+output.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+output.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+output.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+output.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+output.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+output.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+output.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+output.o: /usr/include/g++-3/stl_uninitialized.h
+output.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+output.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+output.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
+output.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/limits.h
+output.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+output.o: /usr/include/stdlib.h /usr/include/string.h
+output.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+output.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+output.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+output.o: /usr/include/wchar.h /usr/include/xlocale.h
+output.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+output.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+output.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+output.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+output.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+output.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+output.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+overmap.o: AppHdr.h debug.h defines.h enum.h externs.h files.h FixAry.h
+overmap.o: FixVec.h liblinux.h libutil.h message.h overmap.h religion.h
+overmap.o: stuff.h /usr/include/alloca.h /usr/include/asm/errno.h
+overmap.o: /usr/include/assert.h /usr/include/bits/confname.h
+overmap.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+overmap.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+overmap.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+overmap.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+overmap.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+overmap.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+overmap.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+overmap.o: /usr/include/bits/time.h /usr/include/bits/types.h
+overmap.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+overmap.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+overmap.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+overmap.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+overmap.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+overmap.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+overmap.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+overmap.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+overmap.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+overmap.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+overmap.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+overmap.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+overmap.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+overmap.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+overmap.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+overmap.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+overmap.o: /usr/include/g++-3/stl_uninitialized.h
+overmap.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+overmap.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+overmap.o: /usr/include/_G_config.h /usr/include/gconv.h
+overmap.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+overmap.o: /usr/include/libio.h /usr/include/limits.h
+overmap.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+overmap.o: /usr/include/stdlib.h /usr/include/string.h
+overmap.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+overmap.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+overmap.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+overmap.o: /usr/include/wchar.h /usr/include/xlocale.h
+overmap.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+overmap.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+overmap.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+overmap.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+overmap.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+overmap.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+overmap.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h view.h
+player.o: AppHdr.h debug.h defines.h enum.h externs.h FixAry.h FixVec.h
+player.o: itemname.h liblinux.h libutil.h message.h misc.h mon-util.h
+player.o: mutation.h output.h player.h randart.h religion.h skills2.h
+player.o: spells4.h spl-util.h stuff.h /usr/include/alloca.h
+player.o: /usr/include/asm/errno.h /usr/include/assert.h
+player.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+player.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+player.o: /usr/include/bits/fcntl.h /usr/include/bits/huge_val.h
+player.o: /usr/include/bits/local_lim.h /usr/include/bits/mathcalls.h
+player.o: /usr/include/bits/mathdef.h /usr/include/bits/nan.h
+player.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
+player.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
+player.o: /usr/include/bits/sched.h /usr/include/bits/select.h
+player.o: /usr/include/bits/sigset.h /usr/include/bits/stat.h
+player.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
+player.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+player.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+player.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
+player.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
+player.o: /usr/include/fcntl.h /usr/include/features.h
+player.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+player.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+player.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+player.o: /usr/include/g++-3/iterator /usr/include/g++-3/queue
+player.o: /usr/include/g++-3/std/bastring.cc
+player.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+player.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+player.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+player.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+player.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+player.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+player.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+player.o: /usr/include/g++-3/stl_uninitialized.h
+player.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+player.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+player.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
+player.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/limits.h
+player.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+player.o: /usr/include/math.h /usr/include/stdio.h /usr/include/stdlib.h
+player.o: /usr/include/string.h /usr/include/sys/cdefs.h
+player.o: /usr/include/sys/select.h /usr/include/sys/stat.h
+player.o: /usr/include/sys/sysmacros.h /usr/include/sys/types.h
+player.o: /usr/include/time.h /usr/include/unistd.h /usr/include/wchar.h
+player.o: /usr/include/xlocale.h
+player.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+player.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+player.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+player.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+player.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+player.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+player.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h view.h
+player.o: wpn-misc.h
+randart.o: AppHdr.h debug.h defines.h enum.h externs.h FixAry.h FixVec.h
+randart.o: itemname.h liblinux.h libutil.h message.h randart.h stuff.h
+randart.o: unrand.h /usr/include/alloca.h /usr/include/asm/errno.h
+randart.o: /usr/include/assert.h /usr/include/bits/confname.h
+randart.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+randart.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+randart.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+randart.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+randart.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+randart.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+randart.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+randart.o: /usr/include/bits/time.h /usr/include/bits/types.h
+randart.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+randart.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+randart.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+randart.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+randart.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+randart.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+randart.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+randart.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+randart.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+randart.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+randart.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+randart.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+randart.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+randart.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+randart.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+randart.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+randart.o: /usr/include/g++-3/stl_uninitialized.h
+randart.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+randart.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+randart.o: /usr/include/_G_config.h /usr/include/gconv.h
+randart.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+randart.o: /usr/include/libio.h /usr/include/limits.h
+randart.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+randart.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+randart.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+randart.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+randart.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+randart.o: /usr/include/wchar.h /usr/include/xlocale.h
+randart.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+randart.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+randart.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+randart.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+randart.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+randart.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+randart.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+randart.o: wpn-misc.h
+religion.o: AppHdr.h beam.h debug.h decks.h defines.h describe.h direct.h
+religion.o: dungeon.h effects.h enum.h externs.h FixAry.h FixVec.h food.h
+religion.o: itemname.h items.h it_use2.h liblinux.h libutil.h message.h
+religion.o: misc.h monplace.h mutation.h newgame.h ouch.h player.h religion.h
+religion.o: shopping.h spells1.h spells2.h spells3.h spl-cast.h stuff.h
+religion.o: /usr/include/alloca.h /usr/include/asm/errno.h
+religion.o: /usr/include/assert.h /usr/include/bits/confname.h
+religion.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+religion.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+religion.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+religion.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+religion.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+religion.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+religion.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+religion.o: /usr/include/bits/time.h /usr/include/bits/types.h
+religion.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+religion.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+religion.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+religion.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+religion.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+religion.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+religion.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+religion.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+religion.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+religion.o: /usr/include/g++-3/std/bastring.h
+religion.o: /usr/include/g++-3/std/straits.h
+religion.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+religion.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+religion.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+religion.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+religion.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+religion.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+religion.o: /usr/include/g++-3/stl_uninitialized.h
+religion.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+religion.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+religion.o: /usr/include/_G_config.h /usr/include/gconv.h
+religion.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+religion.o: /usr/include/libio.h /usr/include/limits.h
+religion.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+religion.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+religion.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+religion.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+religion.o: /usr/include/sys/types.h /usr/include/time.h
+religion.o: /usr/include/unistd.h /usr/include/wchar.h /usr/include/xlocale.h
+religion.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+religion.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+religion.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+religion.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+religion.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+religion.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+religion.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+shopping.o: AppHdr.h debug.h defines.h describe.h enum.h externs.h FixAry.h
+shopping.o: FixVec.h invent.h itemname.h items.h liblinux.h libutil.h
+shopping.o: message.h player.h randart.h shopping.h spl-book.h stuff.h
+shopping.o: /usr/include/alloca.h /usr/include/asm/errno.h
+shopping.o: /usr/include/assert.h /usr/include/bits/confname.h
+shopping.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+shopping.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+shopping.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+shopping.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+shopping.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+shopping.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+shopping.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+shopping.o: /usr/include/bits/time.h /usr/include/bits/types.h
+shopping.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+shopping.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+shopping.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+shopping.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+shopping.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+shopping.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+shopping.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+shopping.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+shopping.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+shopping.o: /usr/include/g++-3/std/bastring.h
+shopping.o: /usr/include/g++-3/std/straits.h
+shopping.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+shopping.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+shopping.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+shopping.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+shopping.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+shopping.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+shopping.o: /usr/include/g++-3/stl_uninitialized.h
+shopping.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+shopping.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+shopping.o: /usr/include/_G_config.h /usr/include/gconv.h
+shopping.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+shopping.o: /usr/include/libio.h /usr/include/limits.h
+shopping.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+shopping.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+shopping.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+shopping.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+shopping.o: /usr/include/sys/types.h /usr/include/time.h
+shopping.o: /usr/include/unistd.h /usr/include/wchar.h /usr/include/xlocale.h
+shopping.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+shopping.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+shopping.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+shopping.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+shopping.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+shopping.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+shopping.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+skills2.o: AppHdr.h debug.h defines.h enum.h externs.h fight.h FixAry.h
+skills2.o: FixVec.h liblinux.h libutil.h message.h player.h randart.h
+skills2.o: skills2.h stuff.h /usr/include/alloca.h /usr/include/asm/errno.h
+skills2.o: /usr/include/assert.h /usr/include/bits/confname.h
+skills2.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+skills2.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+skills2.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+skills2.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+skills2.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+skills2.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+skills2.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+skills2.o: /usr/include/bits/time.h /usr/include/bits/types.h
+skills2.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+skills2.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+skills2.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+skills2.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+skills2.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+skills2.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+skills2.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+skills2.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+skills2.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+skills2.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+skills2.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+skills2.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+skills2.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+skills2.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+skills2.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+skills2.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+skills2.o: /usr/include/g++-3/stl_uninitialized.h
+skills2.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+skills2.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+skills2.o: /usr/include/_G_config.h /usr/include/gconv.h
+skills2.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+skills2.o: /usr/include/libio.h /usr/include/limits.h
+skills2.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+skills2.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+skills2.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+skills2.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+skills2.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+skills2.o: /usr/include/wchar.h /usr/include/xlocale.h
+skills2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+skills2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+skills2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+skills2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+skills2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+skills2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+skills2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h view.h
+skills2.o: wpn-misc.h
+skills.o: AppHdr.h debug.h defines.h enum.h externs.h FixAry.h FixVec.h
+skills.o: liblinux.h libutil.h message.h player.h skills2.h skills.h stuff.h
+skills.o: /usr/include/alloca.h /usr/include/asm/errno.h
+skills.o: /usr/include/assert.h /usr/include/bits/confname.h
+skills.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+skills.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+skills.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+skills.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+skills.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+skills.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+skills.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+skills.o: /usr/include/bits/time.h /usr/include/bits/types.h
+skills.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+skills.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+skills.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+skills.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+skills.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+skills.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+skills.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+skills.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+skills.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+skills.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+skills.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+skills.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+skills.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+skills.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+skills.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+skills.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+skills.o: /usr/include/g++-3/stl_uninitialized.h
+skills.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+skills.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+skills.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
+skills.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/limits.h
+skills.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+skills.o: /usr/include/stdlib.h /usr/include/string.h
+skills.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+skills.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+skills.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+skills.o: /usr/include/wchar.h /usr/include/xlocale.h
+skills.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+skills.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+skills.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+skills.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+skills.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+skills.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+skills.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+spells1.o: abyss.h AppHdr.h beam.h cloud.h debug.h defines.h direct.h enum.h
+spells1.o: externs.h fight.h FixAry.h FixVec.h invent.h itemname.h it_use2.h
+spells1.o: liblinux.h libutil.h message.h misc.h monplace.h monstuff.h
+spells1.o: mon-util.h player.h skills2.h spells1.h spells3.h spells4.h
+spells1.o: spl-util.h stuff.h /usr/include/alloca.h /usr/include/asm/errno.h
+spells1.o: /usr/include/assert.h /usr/include/bits/confname.h
+spells1.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+spells1.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+spells1.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+spells1.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+spells1.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+spells1.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+spells1.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+spells1.o: /usr/include/bits/time.h /usr/include/bits/types.h
+spells1.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+spells1.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+spells1.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+spells1.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+spells1.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+spells1.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+spells1.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+spells1.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+spells1.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+spells1.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+spells1.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+spells1.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+spells1.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+spells1.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+spells1.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+spells1.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+spells1.o: /usr/include/g++-3/stl_uninitialized.h
+spells1.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+spells1.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+spells1.o: /usr/include/_G_config.h /usr/include/gconv.h
+spells1.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+spells1.o: /usr/include/libio.h /usr/include/limits.h
+spells1.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+spells1.o: /usr/include/stdlib.h /usr/include/string.h
+spells1.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+spells1.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+spells1.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+spells1.o: /usr/include/wchar.h /usr/include/xlocale.h
+spells1.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+spells1.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+spells1.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+spells1.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+spells1.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+spells1.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+spells1.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h view.h
+spells1.o: wpn-misc.h
+spells2.o: AppHdr.h beam.h cloud.h debug.h defines.h direct.h effects.h
+spells2.o: enum.h externs.h fight.h FixAry.h FixVec.h itemname.h items.h
+spells2.o: liblinux.h libutil.h message.h misc.h monplace.h monstuff.h
+spells2.o: mon-util.h ouch.h player.h randart.h spells2.h spells4.h
+spells2.o: spl-cast.h stuff.h /usr/include/alloca.h /usr/include/asm/errno.h
+spells2.o: /usr/include/assert.h /usr/include/bits/confname.h
+spells2.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+spells2.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+spells2.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+spells2.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+spells2.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+spells2.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+spells2.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+spells2.o: /usr/include/bits/time.h /usr/include/bits/types.h
+spells2.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+spells2.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+spells2.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+spells2.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+spells2.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+spells2.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+spells2.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+spells2.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+spells2.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+spells2.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+spells2.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+spells2.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+spells2.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+spells2.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+spells2.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+spells2.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+spells2.o: /usr/include/g++-3/stl_uninitialized.h
+spells2.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+spells2.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+spells2.o: /usr/include/_G_config.h /usr/include/gconv.h
+spells2.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+spells2.o: /usr/include/libio.h /usr/include/limits.h
+spells2.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+spells2.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+spells2.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+spells2.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+spells2.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+spells2.o: /usr/include/wchar.h /usr/include/xlocale.h
+spells2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+spells2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+spells2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+spells2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+spells2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+spells2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+spells2.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h view.h
+spells2.o: wpn-misc.h
+spells3.o: abyss.h AppHdr.h beam.h cloud.h debug.h defines.h delay.h direct.h
+spells3.o: enum.h externs.h fight.h FixAry.h FixVec.h itemname.h items.h
+spells3.o: it_use2.h liblinux.h libutil.h message.h misc.h mon-pick.h
+spells3.o: monplace.h monstuff.h mon-util.h player.h randart.h spells1.h
+spells3.o: spells3.h spl-cast.h spl-util.h stuff.h /usr/include/alloca.h
+spells3.o: /usr/include/asm/errno.h /usr/include/assert.h
+spells3.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+spells3.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+spells3.o: /usr/include/bits/fcntl.h /usr/include/bits/local_lim.h
+spells3.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
+spells3.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
+spells3.o: /usr/include/bits/sched.h /usr/include/bits/select.h
+spells3.o: /usr/include/bits/sigset.h /usr/include/bits/stat.h
+spells3.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
+spells3.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+spells3.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+spells3.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
+spells3.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
+spells3.o: /usr/include/fcntl.h /usr/include/features.h
+spells3.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+spells3.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+spells3.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+spells3.o: /usr/include/g++-3/iterator /usr/include/g++-3/queue
+spells3.o: /usr/include/g++-3/std/bastring.cc
+spells3.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+spells3.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+spells3.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+spells3.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+spells3.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+spells3.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+spells3.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+spells3.o: /usr/include/g++-3/stl_uninitialized.h
+spells3.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+spells3.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+spells3.o: /usr/include/_G_config.h /usr/include/gconv.h
+spells3.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+spells3.o: /usr/include/libio.h /usr/include/limits.h
+spells3.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+spells3.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+spells3.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+spells3.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+spells3.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+spells3.o: /usr/include/wchar.h /usr/include/xlocale.h
+spells3.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+spells3.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+spells3.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+spells3.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+spells3.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+spells3.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+spells3.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h view.h
+spells3.o: wpn-misc.h
+spells4.o: abyss.h AppHdr.h beam.h cloud.h debug.h defines.h delay.h
+spells4.o: describe.h direct.h dungeon.h effects.h enum.h externs.h fight.h
+spells4.o: FixAry.h FixVec.h itemname.h items.h it_use2.h liblinux.h
+spells4.o: libutil.h message.h misc.h monplace.h monstuff.h mon-util.h
+spells4.o: mstuff2.h ouch.h player.h randart.h religion.h spells1.h spells4.h
+spells4.o: spl-cast.h spl-util.h stuff.h /usr/include/alloca.h
+spells4.o: /usr/include/asm/errno.h /usr/include/assert.h
+spells4.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+spells4.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+spells4.o: /usr/include/bits/fcntl.h /usr/include/bits/local_lim.h
+spells4.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
+spells4.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
+spells4.o: /usr/include/bits/sched.h /usr/include/bits/select.h
+spells4.o: /usr/include/bits/sigset.h /usr/include/bits/stat.h
+spells4.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
+spells4.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+spells4.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+spells4.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
+spells4.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
+spells4.o: /usr/include/fcntl.h /usr/include/features.h
+spells4.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+spells4.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+spells4.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+spells4.o: /usr/include/g++-3/iterator /usr/include/g++-3/queue
+spells4.o: /usr/include/g++-3/std/bastring.cc
+spells4.o: /usr/include/g++-3/std/bastring.h /usr/include/g++-3/std/straits.h
+spells4.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+spells4.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+spells4.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+spells4.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+spells4.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+spells4.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+spells4.o: /usr/include/g++-3/stl_uninitialized.h
+spells4.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+spells4.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+spells4.o: /usr/include/_G_config.h /usr/include/gconv.h
+spells4.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+spells4.o: /usr/include/libio.h /usr/include/limits.h
+spells4.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+spells4.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+spells4.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+spells4.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+spells4.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+spells4.o: /usr/include/wchar.h /usr/include/xlocale.h
+spells4.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+spells4.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+spells4.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+spells4.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+spells4.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+spells4.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+spells4.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h view.h
+spl-book.o: AppHdr.h debug.h defines.h delay.h enum.h externs.h FixAry.h
+spl-book.o: FixVec.h invent.h itemname.h items.h it_use3.h liblinux.h
+spl-book.o: libutil.h message.h player.h religion.h spl-book.h spl-cast.h
+spl-book.o: spl-util.h stuff.h /usr/include/alloca.h /usr/include/asm/errno.h
+spl-book.o: /usr/include/assert.h /usr/include/bits/confname.h
+spl-book.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+spl-book.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+spl-book.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+spl-book.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+spl-book.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+spl-book.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+spl-book.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+spl-book.o: /usr/include/bits/time.h /usr/include/bits/types.h
+spl-book.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+spl-book.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+spl-book.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+spl-book.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+spl-book.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+spl-book.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+spl-book.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+spl-book.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+spl-book.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+spl-book.o: /usr/include/g++-3/std/bastring.h
+spl-book.o: /usr/include/g++-3/std/straits.h
+spl-book.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+spl-book.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+spl-book.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+spl-book.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+spl-book.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+spl-book.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+spl-book.o: /usr/include/g++-3/stl_uninitialized.h
+spl-book.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+spl-book.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+spl-book.o: /usr/include/_G_config.h /usr/include/gconv.h
+spl-book.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+spl-book.o: /usr/include/libio.h /usr/include/limits.h
+spl-book.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+spl-book.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+spl-book.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+spl-book.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+spl-book.o: /usr/include/sys/types.h /usr/include/time.h
+spl-book.o: /usr/include/unistd.h /usr/include/wchar.h /usr/include/xlocale.h
+spl-book.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+spl-book.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+spl-book.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+spl-book.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+spl-book.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+spl-book.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+spl-book.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+spl-cast.o: AppHdr.h beam.h cloud.h debug.h defines.h direct.h effects.h
+spl-cast.o: enum.h externs.h fight.h FixAry.h FixVec.h food.h itemname.h
+spl-cast.o: it_use2.h liblinux.h libutil.h message.h monplace.h monstuff.h
+spl-cast.o: mutation.h ouch.h player.h religion.h skills.h spells1.h
+spl-cast.o: spells2.h spells3.h spells4.h spl-cast.h spl-util.h stuff.h
+spl-cast.o: transfor.h /usr/include/alloca.h /usr/include/asm/errno.h
+spl-cast.o: /usr/include/assert.h /usr/include/bits/confname.h
+spl-cast.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+spl-cast.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+spl-cast.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+spl-cast.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+spl-cast.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+spl-cast.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+spl-cast.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+spl-cast.o: /usr/include/bits/time.h /usr/include/bits/types.h
+spl-cast.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+spl-cast.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+spl-cast.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+spl-cast.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+spl-cast.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+spl-cast.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+spl-cast.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+spl-cast.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+spl-cast.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+spl-cast.o: /usr/include/g++-3/std/bastring.h
+spl-cast.o: /usr/include/g++-3/std/straits.h
+spl-cast.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+spl-cast.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+spl-cast.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+spl-cast.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+spl-cast.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+spl-cast.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+spl-cast.o: /usr/include/g++-3/stl_uninitialized.h
+spl-cast.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+spl-cast.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+spl-cast.o: /usr/include/_G_config.h /usr/include/gconv.h
+spl-cast.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+spl-cast.o: /usr/include/libio.h /usr/include/limits.h
+spl-cast.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+spl-cast.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+spl-cast.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+spl-cast.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+spl-cast.o: /usr/include/sys/types.h /usr/include/time.h
+spl-cast.o: /usr/include/unistd.h /usr/include/wchar.h /usr/include/xlocale.h
+spl-cast.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+spl-cast.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+spl-cast.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+spl-cast.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+spl-cast.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+spl-cast.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+spl-cast.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+spl-cast.o: view.h
+spl-util.o: AppHdr.h debug.h defines.h direct.h enum.h externs.h FixAry.h
+spl-util.o: FixVec.h itemname.h liblinux.h libutil.h message.h player.h
+spl-util.o: spl-book.h spl-data.h spl-util.h stuff.h /usr/include/alloca.h
+spl-util.o: /usr/include/asm/errno.h /usr/include/assert.h
+spl-util.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+spl-util.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+spl-util.o: /usr/include/bits/fcntl.h /usr/include/bits/local_lim.h
+spl-util.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
+spl-util.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
+spl-util.o: /usr/include/bits/sched.h /usr/include/bits/select.h
+spl-util.o: /usr/include/bits/sigset.h /usr/include/bits/stat.h
+spl-util.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
+spl-util.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+spl-util.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+spl-util.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
+spl-util.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
+spl-util.o: /usr/include/fcntl.h /usr/include/features.h
+spl-util.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+spl-util.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+spl-util.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+spl-util.o: /usr/include/g++-3/iterator /usr/include/g++-3/queue
+spl-util.o: /usr/include/g++-3/std/bastring.cc
+spl-util.o: /usr/include/g++-3/std/bastring.h
+spl-util.o: /usr/include/g++-3/std/straits.h
+spl-util.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+spl-util.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+spl-util.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+spl-util.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+spl-util.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+spl-util.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+spl-util.o: /usr/include/g++-3/stl_uninitialized.h
+spl-util.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+spl-util.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+spl-util.o: /usr/include/_G_config.h /usr/include/gconv.h
+spl-util.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+spl-util.o: /usr/include/libio.h /usr/include/limits.h
+spl-util.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+spl-util.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+spl-util.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+spl-util.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+spl-util.o: /usr/include/sys/types.h /usr/include/time.h
+spl-util.o: /usr/include/unistd.h /usr/include/wchar.h /usr/include/xlocale.h
+spl-util.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+spl-util.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+spl-util.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+spl-util.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+spl-util.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+spl-util.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+spl-util.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+spl-util.o: view.h
+stuff.o: AppHdr.h debug.h defines.h enum.h externs.h FixAry.h FixVec.h
+stuff.o: liblinux.h libutil.h message.h misc.h output.h skills2.h stuff.h
+stuff.o: /usr/include/alloca.h /usr/include/asm/errno.h /usr/include/assert.h
+stuff.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+stuff.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+stuff.o: /usr/include/bits/fcntl.h /usr/include/bits/local_lim.h
+stuff.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
+stuff.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
+stuff.o: /usr/include/bits/sched.h /usr/include/bits/select.h
+stuff.o: /usr/include/bits/sigset.h /usr/include/bits/stat.h
+stuff.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
+stuff.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+stuff.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+stuff.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
+stuff.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
+stuff.o: /usr/include/fcntl.h /usr/include/features.h
+stuff.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+stuff.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+stuff.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+stuff.o: /usr/include/g++-3/iterator /usr/include/g++-3/queue
+stuff.o: /usr/include/g++-3/std/bastring.cc /usr/include/g++-3/std/bastring.h
+stuff.o: /usr/include/g++-3/std/straits.h /usr/include/g++-3/stl_algobase.h
+stuff.o: /usr/include/g++-3/stl_alloc.h /usr/include/g++-3/stl_bvector.h
+stuff.o: /usr/include/g++-3/stl_config.h /usr/include/g++-3/stl_construct.h
+stuff.o: /usr/include/g++-3/stl_deque.h /usr/include/g++-3/stl_function.h
+stuff.o: /usr/include/g++-3/stl_heap.h /usr/include/g++-3/stl_iterator.h
+stuff.o: /usr/include/g++-3/stl_pair.h /usr/include/g++-3/stl_queue.h
+stuff.o: /usr/include/g++-3/stl_relops.h
+stuff.o: /usr/include/g++-3/stl_uninitialized.h
+stuff.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+stuff.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+stuff.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
+stuff.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/limits.h
+stuff.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+stuff.o: /usr/include/stdlib.h /usr/include/string.h /usr/include/sys/cdefs.h
+stuff.o: /usr/include/sys/select.h /usr/include/sys/stat.h
+stuff.o: /usr/include/sys/sysmacros.h /usr/include/sys/types.h
+stuff.o: /usr/include/time.h /usr/include/unistd.h /usr/include/wchar.h
+stuff.o: /usr/include/xlocale.h
+stuff.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+stuff.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+stuff.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+stuff.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+stuff.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+stuff.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+stuff.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h view.h
+tags.o: AppHdr.h debug.h defines.h enum.h externs.h files.h FixAry.h FixVec.h
+tags.o: itemname.h liblinux.h libutil.h message.h monstuff.h mon-util.h
+tags.o: randart.h skills.h stuff.h tags.h /usr/include/alloca.h
+tags.o: /usr/include/asm/errno.h /usr/include/assert.h
+tags.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+tags.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+tags.o: /usr/include/bits/fcntl.h /usr/include/bits/local_lim.h
+tags.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
+tags.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
+tags.o: /usr/include/bits/sched.h /usr/include/bits/select.h
+tags.o: /usr/include/bits/sigset.h /usr/include/bits/stat.h
+tags.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
+tags.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+tags.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+tags.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
+tags.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
+tags.o: /usr/include/fcntl.h /usr/include/features.h
+tags.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+tags.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+tags.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+tags.o: /usr/include/g++-3/iterator /usr/include/g++-3/queue
+tags.o: /usr/include/g++-3/std/bastring.cc /usr/include/g++-3/std/bastring.h
+tags.o: /usr/include/g++-3/std/straits.h /usr/include/g++-3/stl_algobase.h
+tags.o: /usr/include/g++-3/stl_alloc.h /usr/include/g++-3/stl_bvector.h
+tags.o: /usr/include/g++-3/stl_config.h /usr/include/g++-3/stl_construct.h
+tags.o: /usr/include/g++-3/stl_deque.h /usr/include/g++-3/stl_function.h
+tags.o: /usr/include/g++-3/stl_heap.h /usr/include/g++-3/stl_iterator.h
+tags.o: /usr/include/g++-3/stl_pair.h /usr/include/g++-3/stl_queue.h
+tags.o: /usr/include/g++-3/stl_relops.h
+tags.o: /usr/include/g++-3/stl_uninitialized.h
+tags.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+tags.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+tags.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
+tags.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/limits.h
+tags.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+tags.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
+tags.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+tags.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+tags.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
+tags.o: /usr/include/wchar.h /usr/include/xlocale.h
+tags.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+tags.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+tags.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+tags.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+tags.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+tags.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+tags.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+transfor.o: AppHdr.h debug.h defines.h enum.h externs.h FixAry.h FixVec.h
+transfor.o: itemname.h items.h it_use2.h liblinux.h libutil.h message.h
+transfor.o: misc.h player.h skills2.h stuff.h transfor.h
+transfor.o: /usr/include/alloca.h /usr/include/asm/errno.h
+transfor.o: /usr/include/assert.h /usr/include/bits/confname.h
+transfor.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
+transfor.o: /usr/include/bits/errno.h /usr/include/bits/fcntl.h
+transfor.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
+transfor.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
+transfor.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+transfor.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+transfor.o: /usr/include/bits/stat.h /usr/include/bits/stdio_lim.h
+transfor.o: /usr/include/bits/time.h /usr/include/bits/types.h
+transfor.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+transfor.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+transfor.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
+transfor.o: /usr/include/endian.h /usr/include/errno.h /usr/include/fcntl.h
+transfor.o: /usr/include/features.h /usr/include/g++-3/alloc.h
+transfor.o: /usr/include/g++-3/cassert /usr/include/g++-3/cctype
+transfor.o: /usr/include/g++-3/cstddef /usr/include/g++-3/cstring
+transfor.o: /usr/include/g++-3/iostream.h /usr/include/g++-3/iterator
+transfor.o: /usr/include/g++-3/queue /usr/include/g++-3/std/bastring.cc
+transfor.o: /usr/include/g++-3/std/bastring.h
+transfor.o: /usr/include/g++-3/std/straits.h
+transfor.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+transfor.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+transfor.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+transfor.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+transfor.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+transfor.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+transfor.o: /usr/include/g++-3/stl_uninitialized.h
+transfor.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+transfor.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+transfor.o: /usr/include/_G_config.h /usr/include/gconv.h
+transfor.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+transfor.o: /usr/include/libio.h /usr/include/limits.h
+transfor.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+transfor.o: /usr/include/stdlib.h /usr/include/string.h
+transfor.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+transfor.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+transfor.o: /usr/include/sys/types.h /usr/include/time.h
+transfor.o: /usr/include/unistd.h /usr/include/wchar.h /usr/include/xlocale.h
+transfor.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+transfor.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+transfor.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+transfor.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+transfor.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+transfor.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+transfor.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+view.o: AppHdr.h debug.h defines.h enum.h externs.h FixAry.h FixVec.h
+view.o: insult.h liblinux.h libutil.h message.h monstuff.h mon-util.h
+view.o: overmap.h player.h spells4.h stuff.h /usr/include/alloca.h
+view.o: /usr/include/asm/errno.h /usr/include/assert.h
+view.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+view.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+view.o: /usr/include/bits/fcntl.h /usr/include/bits/local_lim.h
+view.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
+view.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
+view.o: /usr/include/bits/sched.h /usr/include/bits/select.h
+view.o: /usr/include/bits/sigset.h /usr/include/bits/stat.h
+view.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
+view.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+view.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+view.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
+view.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
+view.o: /usr/include/fcntl.h /usr/include/features.h
+view.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+view.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+view.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+view.o: /usr/include/g++-3/iterator /usr/include/g++-3/queue
+view.o: /usr/include/g++-3/std/bastring.cc /usr/include/g++-3/std/bastring.h
+view.o: /usr/include/g++-3/std/straits.h /usr/include/g++-3/stl_algobase.h
+view.o: /usr/include/g++-3/stl_alloc.h /usr/include/g++-3/stl_bvector.h
+view.o: /usr/include/g++-3/stl_config.h /usr/include/g++-3/stl_construct.h
+view.o: /usr/include/g++-3/stl_deque.h /usr/include/g++-3/stl_function.h
+view.o: /usr/include/g++-3/stl_heap.h /usr/include/g++-3/stl_iterator.h
+view.o: /usr/include/g++-3/stl_pair.h /usr/include/g++-3/stl_queue.h
+view.o: /usr/include/g++-3/stl_relops.h
+view.o: /usr/include/g++-3/stl_uninitialized.h
+view.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+view.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+view.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
+view.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/limits.h
+view.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+view.o: /usr/include/stdlib.h /usr/include/string.h /usr/include/sys/cdefs.h
+view.o: /usr/include/sys/select.h /usr/include/sys/stat.h
+view.o: /usr/include/sys/sysmacros.h /usr/include/sys/types.h
+view.o: /usr/include/time.h /usr/include/unistd.h /usr/include/wchar.h
+view.o: /usr/include/xlocale.h
+view.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+view.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+view.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+view.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+view.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+view.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+view.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h view.h
+wpn-misc.o: AppHdr.h debug.h defines.h enum.h externs.h FixAry.h FixVec.h
+wpn-misc.o: liblinux.h libutil.h message.h /usr/include/alloca.h
+wpn-misc.o: /usr/include/asm/errno.h /usr/include/assert.h
+wpn-misc.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
+wpn-misc.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
+wpn-misc.o: /usr/include/bits/fcntl.h /usr/include/bits/local_lim.h
+wpn-misc.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
+wpn-misc.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
+wpn-misc.o: /usr/include/bits/sched.h /usr/include/bits/select.h
+wpn-misc.o: /usr/include/bits/sigset.h /usr/include/bits/stat.h
+wpn-misc.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
+wpn-misc.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
+wpn-misc.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
+wpn-misc.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
+wpn-misc.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
+wpn-misc.o: /usr/include/fcntl.h /usr/include/features.h
+wpn-misc.o: /usr/include/g++-3/alloc.h /usr/include/g++-3/cassert
+wpn-misc.o: /usr/include/g++-3/cctype /usr/include/g++-3/cstddef
+wpn-misc.o: /usr/include/g++-3/cstring /usr/include/g++-3/iostream.h
+wpn-misc.o: /usr/include/g++-3/iterator /usr/include/g++-3/queue
+wpn-misc.o: /usr/include/g++-3/std/bastring.cc
+wpn-misc.o: /usr/include/g++-3/std/bastring.h
+wpn-misc.o: /usr/include/g++-3/std/straits.h
+wpn-misc.o: /usr/include/g++-3/stl_algobase.h /usr/include/g++-3/stl_alloc.h
+wpn-misc.o: /usr/include/g++-3/stl_bvector.h /usr/include/g++-3/stl_config.h
+wpn-misc.o: /usr/include/g++-3/stl_construct.h /usr/include/g++-3/stl_deque.h
+wpn-misc.o: /usr/include/g++-3/stl_function.h /usr/include/g++-3/stl_heap.h
+wpn-misc.o: /usr/include/g++-3/stl_iterator.h /usr/include/g++-3/stl_pair.h
+wpn-misc.o: /usr/include/g++-3/stl_queue.h /usr/include/g++-3/stl_relops.h
+wpn-misc.o: /usr/include/g++-3/stl_uninitialized.h
+wpn-misc.o: /usr/include/g++-3/stl_vector.h /usr/include/g++-3/streambuf.h
+wpn-misc.o: /usr/include/g++-3/string /usr/include/g++-3/type_traits.h
+wpn-misc.o: /usr/include/_G_config.h /usr/include/gconv.h
+wpn-misc.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
+wpn-misc.o: /usr/include/libio.h /usr/include/limits.h
+wpn-misc.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
+wpn-misc.o: /usr/include/stdlib.h /usr/include/string.h
+wpn-misc.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
+wpn-misc.o: /usr/include/sys/stat.h /usr/include/sys/sysmacros.h
+wpn-misc.o: /usr/include/sys/types.h /usr/include/time.h
+wpn-misc.o: /usr/include/unistd.h /usr/include/wchar.h /usr/include/xlocale.h
+wpn-misc.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/exception
+wpn-misc.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
+wpn-misc.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new
+wpn-misc.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/new.h
+wpn-misc.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
+wpn-misc.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
+wpn-misc.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
+wpn-misc.o: wpn-misc.h
diff --git a/trunk/source/maps.cc b/trunk/source/maps.cc
new file mode 100644
index 0000000000..3e99b298e1
--- /dev/null
+++ b/trunk/source/maps.cc
@@ -0,0 +1,3641 @@
+/*
+ * File: maps.cc
+ * Summary: Functions used to create vaults.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <2> 5/20/99 BWR Added stone lining to Zot vault,
+ * this should prevent digging?
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "maps.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "enum.h"
+#include "monplace.h"
+#include "stuff.h"
+
+
+static char vault_1(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char vault_2(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char vault_3(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char vault_4(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char vault_5(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char vault_6(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char vault_7(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char vault_8(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char vault_9(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char vault_10(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+
+
+static char antaeus(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char asmodeus(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char beehive(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char box_level(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char castle_dis(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char elf_hall(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char ereshkigal(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char farm_and_country(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char fort_yaktaur(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char hall_of_Zot(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char hall_of_blades(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char gloorx_vloq(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+//static char mollusc(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char my_map(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char mnoleg(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char cerebov(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char orc_temple(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char lom_lobon(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char slime_pit(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char snake_pit(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char swamp(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char temple(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char tomb_1(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char tomb_2(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char tomb_3(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char vaults_vault(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char vestibule_map(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+
+
+static char minivault_1(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_2(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_3(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_4(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_5(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_6(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_7(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_8(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_9(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_10(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_11(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_12(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_13(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_14(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_15(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_16(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_17(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_18(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_19(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_20(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_21(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_22(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_23(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_24(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_25(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_26(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_27(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_28(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_29(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_30(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_31(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_32(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_33(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+
+//jmf: originals and slim wrappers to fit into don's non-switch
+static char minivault_34(char vgrid[81][81], FixedVector<int, 7>& mons_array, bool orientation);
+static char minivault_35(char vgrid[81][81], FixedVector<int, 7>& mons_array, bool orientation);
+static char minivault_34_a(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_34_b(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_35_a(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char minivault_35_b(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+
+static char rand_demon_1(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char rand_demon_2(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char rand_demon_3(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char rand_demon_4(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char rand_demon_5(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char rand_demon_6(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char rand_demon_7(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char rand_demon_8(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+static char rand_demon_9(char vgrid[81][81], FixedVector<int, 7>& mons_array);
+
+
+
+
+/* ******************** BEGIN PUBLIC FUNCTIONS ******************* */
+
+
+// remember (!!!) - if a member of the monster array isn't specified
+// within a vault subroutine, assume that it holds a random monster
+// -- only in cases of explicit monsters assignment have I listed
+// out random monster insertion {dlb}
+
+// make sure that vault_n, where n is a number, is a vault which can be put
+// anywhere, while other vault names are for specific level ranges, etc.
+char vault_main( char vgrid[81][81], FixedVector<int, 7>& mons_array, int vault_force, int many_many )
+{
+
+ int which_vault = 0;
+ unsigned char vx, vy;
+ char (*fnc_vault) (char[81][81], FixedVector<int, 7>&) = 0;
+
+// first, fill in entirely with walls and null-terminate {dlb}:
+ for (vx = 0; vx < 80; vx++)
+ {
+ for (vy = 0; vy < 80; vy++)
+ vgrid[vx][vy] = 'x';
+
+ vgrid[80][vx] = '\0';
+ vgrid[vx][80] = '\0';
+ }
+
+ // next, select an appropriate vault to place {dlb}:
+ for (;;)
+ {
+ which_vault = ( (vault_force == 100) ? random2(14) : vault_force );
+
+ // endless loops result if forced vault cannot pass these tests {dlb}:
+ if ( which_vault == 9 )
+ {
+ // if ( many_many > 23 || many_many > 12 )
+ if (many_many > 12)
+ break;
+ }
+ else if (which_vault == 11 || which_vault == 12)
+ {
+ if (many_many > 20)
+ break;
+ }
+ else
+ break;
+ }
+
+ // then, determine which drawing routine to use {dlb}:
+ fnc_vault = ( (which_vault == 0) ? vault_1 :
+ (which_vault == 1) ? vault_2 :
+ (which_vault == 2) ? vault_3 :
+ (which_vault == 3) ? vault_4 :
+ (which_vault == 4) ? vault_5 :
+ (which_vault == 5) ? vault_6 :
+ (which_vault == 6) ? vault_7 :
+ (which_vault == 7) ? vault_8 :
+ (which_vault == 8) ? vault_9 :
+ (which_vault == 9) ? ( (many_many > 23) ? my_map : orc_temple ) :
+ (which_vault == 10) ? vault_10 :
+ (which_vault == 11) ? farm_and_country :
+ (which_vault == 12) ? fort_yaktaur :
+ (which_vault == 13) ? box_level :
+
+ // the hell vaults:
+ (which_vault == 50) ? vestibule_map :
+ (which_vault == 51) ? castle_dis :
+ (which_vault == 52) ? asmodeus :
+ (which_vault == 53) ? antaeus :
+ (which_vault == 54) ? ereshkigal :
+
+ // the pandemonium big demonlord vaults:
+ (which_vault == 60) ? mnoleg : // was nemelex
+ (which_vault == 61) ? lom_lobon : // was sif muna
+ (which_vault == 62) ? cerebov : // was okawaru
+ (which_vault == 63) ? gloorx_vloq : // was kikubaaqudgha
+
+ //(which_vault == 64) ? mollusc :
+ (which_vault == 80) ? beehive :
+ (which_vault == 81) ? slime_pit :
+ (which_vault == 82) ? vaults_vault :
+ (which_vault == 83) ? hall_of_blades :
+ (which_vault == 84) ? hall_of_Zot :
+ (which_vault == 85) ? temple :
+ (which_vault == 86) ? snake_pit :
+ (which_vault == 87) ? elf_hall :
+ (which_vault == 88) ? tomb_1 :
+ (which_vault == 89) ? tomb_2 :
+ (which_vault == 90) ? tomb_3 :
+ (which_vault == 91) ? swamp :
+ (which_vault == 200) ? minivault_1 :
+ (which_vault == 201) ? minivault_2 :
+ (which_vault == 202) ? minivault_3 :
+ (which_vault == 203) ? minivault_4 :
+ (which_vault == 204) ? minivault_5 :
+ (which_vault == 205) ? ( (many_many > 15) ? minivault_6 : minivault_1 ) :
+ (which_vault == 206) ? ( (many_many > 10) ? minivault_7 : minivault_2 ) :
+ (which_vault == 207) ? ( (many_many > 15) ? minivault_8 : minivault_3 ) :
+ (which_vault == 208) ? ( (many_many > 15) ? minivault_9 : minivault_4 ) :
+ (which_vault == 209) ? minivault_10 :
+ (which_vault == 210) ? minivault_11 :
+ (which_vault == 211) ? minivault_12 :
+ (which_vault == 212) ? minivault_13 :
+ (which_vault == 213) ? minivault_14 :
+ (which_vault == 214) ? minivault_15 :
+ (which_vault == 215) ? minivault_16 :
+ (which_vault == 216) ? minivault_17 :
+ (which_vault == 217) ? minivault_18 :
+ (which_vault == 218) ? minivault_19 :
+ (which_vault == 219) ? minivault_20 :
+ (which_vault == 220) ? minivault_21 :
+ (which_vault == 221) ? minivault_22 :
+ (which_vault == 222) ? minivault_23 :
+ (which_vault == 223) ? minivault_24 :
+ (which_vault == 224) ? minivault_25 :
+ (which_vault == 225) ? minivault_26 :
+ (which_vault == 226) ? minivault_27 :
+ (which_vault == 227) ? minivault_28 :
+ (which_vault == 228) ? minivault_29 :
+ (which_vault == 229) ? minivault_30 :
+ (which_vault == 230) ? minivault_31 :
+ (which_vault == 231) ? minivault_32 :
+ (which_vault == 232) ? minivault_33 :
+ (which_vault == 233) ? minivault_34_a :
+ (which_vault == 234) ? minivault_34_b :
+ (which_vault == 235) ? minivault_35_a :
+ (which_vault == 236) ? minivault_35_b :
+ (which_vault == 300) ? rand_demon_1 :
+ (which_vault == 301) ? rand_demon_2 :
+ (which_vault == 302) ? rand_demon_3 :
+ (which_vault == 303) ? rand_demon_4 :
+ (which_vault == 304) ? rand_demon_5 :
+ (which_vault == 305) ? rand_demon_6 :
+ (which_vault == 306) ? rand_demon_7 :
+ (which_vault == 307) ? rand_demon_8 :
+ (which_vault == 308) ? rand_demon_9
+ : 0 ); // yep, NULL -- original behaviour {dlb}
+
+ // NB - a return value of zero is not handled well by dungeon.cc (but there it is) 10mar2000 {dlb}
+ return ( (fnc_vault == 0) ? 0 : fnc_vault(vgrid, mons_array) );
+} // end vault_main()
+
+/* ********************* END PUBLIC FUNCTIONS ******************** */
+
+/*
+ key:
+ x - DNGN_ROCK_WALL
+ X - DNGN_PERMAROCK_WALL -> should always be undiggable! -- bwr
+ c - DNGN_STONE_WALL
+ v - DNGN_METAL_WALL
+ b - DNGN_GREEN_CRYSTAL_WALL
+ a - DNGN_WAX_WALL
+ . - DNGN_FLOOR
+ + - DNGN_CLOSED_DOOR
+ = - DNGN_SECRET_DOOR
+ @ - entry point - must be on outside and on a particular side - see templates
+ w - water
+ l - lava
+ >< - extra stairs - you can leave level by these but will never be placed on them from another level
+ }{ - stairs 82/86 - You must be able to reach these from each other
+ )( - stairs 83/87
+ ][ - stairs 84/88
+ I - orcish idol (does nothing)
+ ^ - random trap
+
+ A - Vestibule gateway (opened by Horn). Can also be put on other levels for colour, where it won't do anything.
+ B - Altar. These are assigned specific types (eg of Zin etc) in dungeon.cc, in order.
+ C - Random Altar.
+ F - Typically a Granite Statue, but may be Orange or Silver (1 in 100)
+ G - Granite statue (does nothing)
+ H - orange crystal statue (attacks mind)
+ S - Silver statue (summons demons). Avoid using (rare).
+ T - Water fountain
+ U - Magic fountain
+ V - Permenantly dry fountain
+
+ Statues can't be walked over and are only destroyed by disintegration
+
+ $ - gold
+ % - normal item
+ * - higher level item (good)
+ | - acquirement-level item (almost guaranteed excellent)
+ O - place an appropriate rune here
+ P - maybe place a rune here (50%)
+ R - honeycomb (2/3) or royal jelly (1/3)
+ Z - the Orb of Zot
+
+ 0 - normal monster
+ 9 - +5 depth monster
+ 8 - (+2) * 2 depth monster (aargh!). Can get golden dragons and titans this way.
+ 1-7 - monster array monster
+ used to allocate specific monsters for a vault.
+ is filled with RANDOM_MONSTER if monster not specified
+
+ note that a lot of the vaults are in there mainly to add some interest to the
+ scenery, and are not the lethal treasure-fests you find in Angband
+ (not that there's anything wrong with that)
+
+ Guidelines for creating new vault maps:
+
+ Basically you can just let your creativity run wild. You do not have
+ to place all of the stairs unless the level is full screen, in which
+ case you must place all except the extra stairs (> and <). The <> stairs
+ can be put anywhere and in any quantities but do not have to be there. Any
+ of the other stairs which are not present in the vault will be randomly
+ placed outside it. Also generally try to avoid rooms with no exit.
+
+ You can use the templates below to build vaults, and remember to return the
+ same number (this number is used in builder2.cc to determine where on the map
+ the vault is located). The entry point '@' must be present (except
+ full-screen vaults where it must not) and be on the same side of the vault
+ as it is on the template, but can be anywhere along that side.
+
+ You'll have to tell me the level range in which you want the vault to appear,
+ so that I can code it into the vault management function. Unless you've
+ placed specific monster types this will probably be unnecessary.
+
+ I think that's all. Have fun!
+
+ ps - remember to add one to the monster array value when placing monsters
+ on each map (it is 1-7, not 0-6) {dlb}
+ */
+
+static char vault_1(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // my first vault
+ strcpy(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[6], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[7], "xxxxxxxxxxxx....x........x........x.................................xxxxxxxxxxxx");
+ strcpy(vgrid[8], "xxxxxxxxxx|=8...x........+........x......x....x1...x2...x2...x3...x...xxxxxxxxxx");
+ strcpy(vgrid[9], "xxxxxxxxxx|x....x........x........x....................................xxxxxxxxx");
+ strcpy(vgrid[10], "xxxxxxxxxxxxxxxx+xxx+xxxxxxxxxxxxxx..................................xxxxxxxxxxx");
+ strcpy(vgrid[11], "xxxxxxxxx.......x.................+...................................8xxxxxxxxx");
+ strcpy(vgrid[12], "xxxxxxxxx.......x.................x..................................xxxxxxxxxxx");
+ strcpy(vgrid[13], "xxxxxxxxx.......+........3........xx+xx................................xxxxxxxxx");
+ strcpy(vgrid[14], "xxxxxxxxx.......x.................x...x..x....x1...x2...x2...x3...x...xxxxxxxxxx");
+ strcpy(vgrid[15], "xxxxxxxxx.......x.................x...x.............................xxxxxxxxxxxx");
+ strcpy(vgrid[16], "xxxxxxxxxx+xxxxxxxxxxxxxxxxxxxxxxxx...xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[17], "xxxxxxxxx.........................x.S.x...xxxxxx..................|||||xxxxxxxxx");
+ strcpy(vgrid[18], "xxxxxxxxx....xxxxxxxxxxxxxxxxxx...x...x......xxxxxx..................||xxxxxxxxx");
+ strcpy(vgrid[19], "xxxxxxxxx....x...$$$$x****.999x...x...x.........xxxxxx.................xxxxxxxxx");
+ strcpy(vgrid[20], "xxxxxxxxx....+...$$$$x****....x...x...+............xxxxxx.........8....xxxxxxxxx");
+ strcpy(vgrid[21], "xxxxxxxxx....x...$$$$x****....+...x...x...............xxxxxx...........xxxxxxxxx");
+ strcpy(vgrid[22], "xxxxxxxxx....x...$$$$x****....x...x999x..................xxxxxx........xxxxxxxxx");
+ strcpy(vgrid[23], "xxxxxxxxx....xxxxxxxxxxxxxxxxxx...x...xxx...................xxxxxx.....xxxxxxxxx");
+ strcpy(vgrid[24], "xxxxxxxxx.........................x...xxxxxx...................xxxxxx..xxxxxxxxx");
+ strcpy(vgrid[25], "xxxxxxxxxxxxx+xxxxxxxx+xxxxxxx+xxxx...xxxxxx+xxxxxxxx+xxxxxxxx+xxxxxxx=xxxxxxxxx");
+ strcpy(vgrid[26], "xxxxxxxxx.........x.......x.......x...x.........x........x.............xxxxxxxxx");
+ strcpy(vgrid[27], "xxxxxxxxx.........x.......x.......x...x.........x........x.............xxxxxxxxx");
+ strcpy(vgrid[28], "xxxxxxxxx.........x.......x.......x...x.........x........x.............xxxxxxxxx");
+ strcpy(vgrid[29], "xxxxxxxxx....1....x...2...x...3...x...x....3....x....2...x......1......xxxxxxxxx");
+ strcpy(vgrid[30], "xxxxxxxxx.........x.......x.......x...x.........x........x.............xxxxxxxxx");
+ strcpy(vgrid[31], "xxxxxxxxx.........x.......x.......x...x.........x........x.............xxxxxxxxx");
+ strcpy(vgrid[32], "xxxxxxxxx.........x.......x.......x...x.........x........x.............xxxxxxxxx");
+ strcpy(vgrid[33], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[34], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[35], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ mons_array[0] = MONS_SHAPESHIFTER;
+ mons_array[1] = MONS_SHAPESHIFTER;
+ mons_array[2] = MONS_GLOWING_SHAPESHIFTER;
+
+ return MAP_NORTH;
+}
+
+
+static char vault_2(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // cell vault
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[6], "xxxxxxxxcccccccccccccccccccccccccccccccc");
+ strcpy(vgrid[7], "xxxxxxxxccw......^......w......^......wc");
+ strcpy(vgrid[8], "xxxxxxxxcc.ccccccccccccc.ccccccccccccc.c");
+ strcpy(vgrid[9], "xxxxxxxxcc.c....c.c....c.c....c.c....c.c");
+ strcpy(vgrid[10], "xxxxxxxxcc.c.8..+.c....c.c....+.c..9.c.c");
+ strcpy(vgrid[11], "xxxxxxxxcc.c....c.+..9.c.c.9..c.+....c.c");
+ strcpy(vgrid[12], "xxxxxxxxcc.c....c.c....c.c....c.c....c.c");
+ strcpy(vgrid[13], "xxxxxxxxcc.cccccc.cccccc.cccccc.cccccc.c");
+ strcpy(vgrid[14], "xxxxxxxxcc^c....c.c....c.c....c.c....c.c");
+ strcpy(vgrid[15], "xxxxxxxxcc.c....c.c....c.c....+.c....c.c");
+ strcpy(vgrid[16], "xxxxxxxxcc.c8...+.+..8.c.c.8..c.+....c.c");
+ strcpy(vgrid[17], "xxxxxxxxcc.c....c.c....c.c....c.c....c.c");
+ strcpy(vgrid[18], "xxxxxxxxcc.cccccc.cccccc.cccccc.cccccc.c");
+ strcpy(vgrid[19], "xxxxxxxxcc.c....c.c....c.c....c.c....c.c");
+ strcpy(vgrid[20], "xxxxxxxxcc.c....+.c....c.c.0..c.c....c.c");
+ strcpy(vgrid[21], "xxxxxxxxcc.c..9.c.+.8..c^c....+.+.0..c.c");
+ strcpy(vgrid[22], "xxxxxxxxcc.c....c.c....c.c....c.c....c.c");
+ strcpy(vgrid[23], "xxxxxxxxcc.cccccc.cccccc.cccccc.cccccc.c");
+ strcpy(vgrid[24], "xxxxxxxxcc.c....c.c....c.c....c.c....c.c");
+ strcpy(vgrid[25], "xxxxxxxxcc.c.0..+.+.0..c.c....+.+....c.c");
+ strcpy(vgrid[26], "xxxxxxxxcc.c....c.c....c.c.0..c.c.8..c.c");
+ strcpy(vgrid[27], "xxxxxxxxcc.cccccc.c....c.c....c.cccccc.c");
+ strcpy(vgrid[28], "xxxxxxxxcc.c....c.cccccc.cccccc.c....c^c");
+ strcpy(vgrid[29], "xxxxxxxxcc.c....c.c....c.c..9.+.+....c.c");
+ strcpy(vgrid[30], "xxxxxxxxcc.c.0..+.+....c.c9...c.c.0..c.c");
+ strcpy(vgrid[31], "xxxxxxxxcc.c....c.c.8..c.c....c.c....c.c");
+ strcpy(vgrid[32], "xxxxxxxxcc.cccccc^cccccc.cccccc^cccccc.c");
+ strcpy(vgrid[33], "xxxxxxxxccw.......Twwwwc.cwwwwT.......wc");
+ strcpy(vgrid[34], "xxxxxxxxcccccccccccccccc.ccccccccccccccc");
+ strcpy(vgrid[35], "xxxxxxxxxxxxxxxxxxxxxxxc@cxxxxxxxxxxxxxx");
+
+ return MAP_NORTHWEST;
+}
+
+
+static char vault_3(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // little maze vault
+ UNUSED( mons_array );
+
+ for (unsigned char i = 0; i < 81; i++)
+ strcpy(vgrid[i], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ strcat(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[6], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[7], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[8], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[9], "x900x..............x..........xxxxxxxxxx");
+ strcat(vgrid[10], "x999x.xxxxxxxxxxxx.x.xxxxxxxx.xxxxxxxxxx");
+ strcat(vgrid[11], "x000x.x............x.x......x.xxxxxxxxxx");
+ strcat(vgrid[12], "xx.xx.xxxxxxxxxxxxxx.x.xxxx.x.xxxxxxxxxx");
+ strcat(vgrid[13], "xx.x..............xx.x.88|x.x.xxxxxxxxxx");
+ strcat(vgrid[14], "xx.x.x.xxxxxxxxxx.xx.xxxxxx.x.xxxxxxxxxx");
+ strcat(vgrid[15], "xx.x.x.x........x...........x.xxxxxxxxxx");
+ strcat(vgrid[16], "xx.x.x.x.xxxxxx.xxxxxxxxxxxxx.xxxxxxxxxx");
+ strcat(vgrid[17], "xx.xxx.x.x$$$$x...............xxxxxxxxxx");
+ strcat(vgrid[18], "xx.....x.x$$$$x.xxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[19], "xxxxxxxx.x$$$$x...............xxxxxxxxxx");
+ strcat(vgrid[20], "x........x$$$$x.xxxxxxxxxxxxx.xxxxxxxxxx");
+ strcat(vgrid[21], "x.xxxxxx.xxxx.x.............x.xxxxxxxxxx");
+ strcat(vgrid[22], "x.xxxxxx.xxxx.xxxxxxxxxxxxx.x.xxxxxxxxxx");
+ strcat(vgrid[23], "x.x.......xxx.x...........x.x.xxxxxxxxxx");
+ strcat(vgrid[24], "x.x.xxxxx.....x.x.xxxxx...x.x.xxxxxxxxxx");
+ strcat(vgrid[25], "x.x.x999xxxxxxx.x.x***x...x.x.xxxxxxxxxx");
+ strcat(vgrid[26], "x.x.x889........x.x|||xxxxx.x.xxxxxxxxxx");
+ strcat(vgrid[27], "x.x.x899x.xxxxx.x.x***xxxxx.x.xxxxxxxxxx");
+ strcat(vgrid[28], "x.x.xxxxx.xxxxx.x.xx.xxxxxx.x.xxxxxxxxxx");
+ strcat(vgrid[29], "x.x..........xx.x.xx........x.xxxxxxxxxx");
+ strcat(vgrid[30], "x.xxxxxxx.xx.xx.x.xxxxx.xxxxx.xxxxxxxxxx");
+ strcat(vgrid[31], "x.xxx000x.xx.xx.x.x$$$x.xxxxx.xxxxxxxxxx");
+ strcat(vgrid[32], "x|||x000x.x$$$x.x.x$$$x%%x%%%.xxxxxxxxxx");
+ strcat(vgrid[33], "x|||x000..x$8$x.x.x$$$x%%x%8%xxxxxxxxxxx");
+ strcat(vgrid[34], "x|||xxxxxxx$$$x.x..$$$xxxx%%%xxxxxxxxxxx");
+ strcat(vgrid[35], "xxxxxxxxxxxxxxx@xxxxxxxxxxxxxxxxxxxxxxxx");
+
+ return MAP_NORTHEAST;
+}
+
+
+static char vault_4(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // thingy vault
+ UNUSED( mons_array );
+
+ for (unsigned char i = 0; i < 81; i++)
+ strcpy(vgrid[i], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ strcpy(vgrid[36], "xxxxxxxxxxxxxxxxxxxxxxxxx@xxxxxxxxxxxxxx");
+ strcpy(vgrid[37], "xxxxxxxxxxxxxxxxxxxxxxxxx^xxxxxxxxxxxxxx");
+ strcpy(vgrid[38], "xxxxxxxxxxxxxxxxxxxxxxxx...xxxxxxxxxxxxx");
+ strcpy(vgrid[39], "xxxxxxxxxxxxxxxxxxxxxxx.....xxxxxxxxxxxx");
+ strcpy(vgrid[40], "xxxxxxxxxxxxxxxxxxxxxxxx...xxxxxxxxxxxxx");
+ strcpy(vgrid[41], "xxxxxxxxxxxxxxxxxxxxxxxx...xxxxxxxxxxxxx");
+ strcpy(vgrid[42], "xxxxxxxxxxxxxxxxxxxxxxx.....xxxxxxxxxxxx");
+ strcpy(vgrid[43], "xxxxxxxxxxxxxxxxxxxxx.........xxxxxxxxxx");
+ strcpy(vgrid[44], "xxxxxxxxxxxxxxxxx......0...0......xxxxxx");
+ strcpy(vgrid[45], "xxxxxxxxxxxxxx.......................xxx");
+ strcpy(vgrid[46], "xxxxxxxxxxxxxx.........0...0.........xxx");
+ strcpy(vgrid[47], "xxxxxxxxxxxxx8......0.........0......8xx");
+ strcpy(vgrid[48], "xxxxxxxxxxxxxx.........0...0.........xxx");
+ strcpy(vgrid[49], "xxxxxxxxxxxxxx.......................xxx");
+ strcpy(vgrid[50], "xxxxxxxxxxxxxxx........0...0........xxxx");
+ strcpy(vgrid[51], "xxxxxxxxxxxxxxxxxxxx...........xxxxxxxxx");
+ strcpy(vgrid[52], "xxxxxxxxxxxxxxxxxxxxxxxx...xxxxxxxxxxxxx");
+ strcpy(vgrid[53], "xxxxxxxxxxxxxxxxxxxxxxxx...xxxxxxxxxxxxx");
+ strcpy(vgrid[54], "xxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxx");
+ strcpy(vgrid[55], "xxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxx");
+ strcpy(vgrid[56], "xxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxx");
+ strcpy(vgrid[57], "xxxxxxxxxxxxxxxxxxxxxxx.....xxxxxxxxxxxx");
+ strcpy(vgrid[58], "xxxxxxxxxxxxxxxxxx...............xxxxxxx");
+ strcpy(vgrid[59], "xxxxxxxxxxxxxxxx8.................8xxxxx");
+ strcpy(vgrid[60], "xxxxxxxxxxxxxxxxxxx.............xxxxxxxx");
+ strcpy(vgrid[61], "xxxxxxxxxxxxxxxxxxxxxxxx999xxxxxxxxxxxxx");
+ strcpy(vgrid[62], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[63], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[64], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[65], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[66], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[67], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[68], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[69], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ return MAP_SOUTHWEST;
+}
+
+static char vault_5(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // hourglass vault
+ UNUSED( mons_array );
+
+ for (unsigned char i = 0; i < 81; i++)
+ strcpy(vgrid[i], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ strcat(vgrid[36], "xxxxxxxxxxxxxx@xxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[37], "xxxxxx.................xxxxxxxxxxxxxxxxx");
+ strcat(vgrid[38], "xxxxx...................xxxxxxxxxxxxxxxx");
+ strcat(vgrid[39], "xxxxx...................xxxxxxxxxxxxxxxx");
+ strcat(vgrid[40], "xxxxxx.................xxxxxxxxxxxxxxxxx");
+ strcat(vgrid[41], "xxxxxx.................xxxxxxxxxxxxxxxxx");
+ strcat(vgrid[42], "xxxxxx.................xxxxxxxxxxxxxxxxx");
+ strcat(vgrid[43], "xxxxxxx...............xxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[44], "xxxxxxx...............xxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[45], "xxxxxxxx.............xxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[46], "xxxxxxxxx.....8.....xxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[47], "xxxxxxxxxx...999...xxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[48], "xxxxxxxxxxxx00000xxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[49], "xxxxxxxxxxxxx===xxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[50], "xxxxxxxxxxxx.....xxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[51], "xxxxxxxxxx.........xxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[52], "xxxxxxxxx...........xxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[53], "xxxxxxxx......|......xxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[54], "xxxxxxx...............xxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[55], "xxxxxxx...............xxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[56], "xxxxxx........$........xxxxxxxxxxxxxxxxx");
+ strcat(vgrid[57], "xxxxxx.......$$$.......xxxxxxxxxxxxxxxxx");
+ strcat(vgrid[58], "xxxxxx....$$$$$$$$$....xxxxxxxxxxxxxxxxx");
+ strcat(vgrid[59], "xxxxx$$$$$$$$$$$$$$$$$$$xxxxxxxxxxxxxxxx");
+ strcat(vgrid[60], "xxxxx$$$$$$$$$$$$$$$$$$$xxxxxxxxxxxxxxxx");
+ strcat(vgrid[61], "xxxxxx$$$$$$$$$$$$$$$$$xxxxxxxxxxxxxxxxx");
+ strcat(vgrid[62], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[63], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[64], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[65], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[66], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[67], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[68], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[69], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ return MAP_SOUTHEAST;
+}
+
+
+static char vault_6(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // a more Angbandy vault
+ UNUSED( mons_array );
+
+ for (unsigned char i = 0; i < 81; i++)
+ strcpy(vgrid[i], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ strcat(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[6], "ccccccccccccccccccccccccccccccccxxxxxxxx");
+ strcat(vgrid[7], "c*******cc..9...cc.+8c0c*c.c*c8cxxxxxxxx");
+ strcat(vgrid[8], "c******cc..cc..cc..cc0c.c.c.c8ccxxxxxxxx");
+ strcat(vgrid[9], "c*****cc..cc..cc..cc.c$c.c.c8c.cxxxxxxxx");
+ strcat(vgrid[10], "c****cc9.cc..cc8.cc|c.c|c.c*c0ccxxxxxxxx");
+ strcat(vgrid[11], "c***cc..cc..cc..cc.c.c.c.c.c.c$cxxxxxxxx");
+ strcat(vgrid[12], "c**cc..cc8.cc..cc.c*c.c.c.c.c.ccxxxxxxxx");
+ strcat(vgrid[13], "c+cc9.cc..cc..cc.c.c.c.c*c.c.c.cxxxxxxxx");
+ strcat(vgrid[14], "c^c..cc..cc..cc.c$c.c.c.c.c.c*ccxxxxxxxx");
+ strcat(vgrid[15], "c...cc..cc..cc.c.c.c9c$c.c.c.c9cxxxxxxxx");
+ strcat(vgrid[16], "c..cc..cc..cc$c.c.c*c.c.c.c9c9ccxxxxxxxx");
+ strcat(vgrid[17], "c.cc..cc..cc.c.c|c.c.c.c.c$c.c9cxxxxxxxx");
+ strcat(vgrid[18], "ccc..cc..cc.c.c.c.c.c.c.c.c.cc+cxxxxxxxx");
+ strcat(vgrid[19], "cc..cc..cc.c*c.c.c.c.c.c$c.cc..cxxxxxxxx");
+ strcat(vgrid[20], "c0.cc..cc.c.c.c.c8c.c*c.c.cc0.ccxxxxxxxx");
+ strcat(vgrid[21], "c.cc..cc*c.c.c.c.c$c.c.c.cc..cccxxxxxxxx");
+ strcat(vgrid[22], "c^c..cc.c.c9c.c.c.c.c.c.cc..cc.cxxxxxxxx");
+ strcat(vgrid[23], "c0..cc$c.c.c*c0c.c.c.c.cc..cc.0cxxxxxxxx");
+ strcat(vgrid[24], "c..cc.c.c9c.c.c.c$c.c.cc.9cc...cxxxxxxxx");
+ strcat(vgrid[25], "c.cc9c.c.c.c.c.c.c.c.cc..cc..c^cxxxxxxxx");
+ strcat(vgrid[26], "ccc.c.c$c.c.c.c.c.c$cc..cc..cc^cxxxxxxxx");
+ strcat(vgrid[27], "cc$c.c.c.c.c$c.c0c.cc..cc..cc..cxxxxxxxx");
+ strcat(vgrid[28], "c.c.c.c.c.c.c.c.c.cc9.cc..cc..ccxxxxxxxx");
+ strcat(vgrid[29], "cc.c8c.c.c$c.c.c.cc..cc..cc0.cccxxxxxxxx");
+ strcat(vgrid[30], "c.c$c.c$c0c.c.c.cc..cc..cc..cc$cxxxxxxxx");
+ strcat(vgrid[31], "cc.c.c.c.c.c*c.cc..cc..cc..cc$$cxxxxxxxx");
+ strcat(vgrid[32], "c.c.c.c.c.c.c.cc..cc0.cc..cc$$$cxxxxxxxx");
+ strcat(vgrid[33], "cc.c.c.c.c.c$cc..cc..cc..cc$$$$cxxxxxxxx");
+ strcat(vgrid[34], "c.c.c.c.c.c.cc.8.^..cc....+$$$$cxxxxxxxx");
+ strcat(vgrid[35], "cccc@cccccccccccccccccccccccccccxxxxxxxx");
+
+ return MAP_NORTHEAST;
+}
+
+static char vault_7(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // four-leaf vault
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[6], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[7], "xxxxxxxxxxxxx.........^..^.........xxxxx");
+ strcpy(vgrid[8], "xxxxxxxxxxxx...xxxxxxxx..xxxxxxxx...xxxx");
+ strcpy(vgrid[9], "xxxxxxxxxxx...xxxxxxxxx..xxxxxxxxx...xxx");
+ strcpy(vgrid[10], "xxxxxxxxxx...xx$*....xx..xx....$$xx...xx");
+ strcpy(vgrid[11], "xxxxxxxxx...xx$*$....xx..xx....$*$xx...x");
+ strcpy(vgrid[12], "xxxxxxxxx..xx*$*$....xx..xx....*$$$xx..x");
+ strcpy(vgrid[13], "xxxxxxxxx..xx$$$.00..xx..xx..00.*$*xx..x");
+ strcpy(vgrid[14], "xxxxxxxxx..xx....09..xx..xx..90....xx..x");
+ strcpy(vgrid[15], "xxxxxxxxx..xx......+xx....xx+......xx..x");
+ strcpy(vgrid[16], "xxxxxxxxx..xx......x^......^x......xx..x");
+ strcpy(vgrid[17], "xxxxxxxxx..xxxxxxxxx........xxxxxxxxx..x");
+ strcpy(vgrid[18], "xxxxxxxxx..xxxxxxxx..........xxxxxxxx..x");
+ strcpy(vgrid[19], "xxxxxxxxx..............TT..............x");
+ strcpy(vgrid[20], "xxxxxxxxx..............TT..............x");
+ strcpy(vgrid[21], "xxxxxxxxx..xxxxxxxx..........xxxxxxxx..x");
+ strcpy(vgrid[22], "xxxxxxxxx..xxxxxxxxx........xxxxxxxxx..x");
+ strcpy(vgrid[23], "xxxxxxxxx..xx......x^......^x......xx..x");
+ strcpy(vgrid[24], "xxxxxxxxx..xx......+xx....xx+......xx..x");
+ strcpy(vgrid[25], "xxxxxxxxx..xx....09..xx..xx..90....xx..x");
+ strcpy(vgrid[26], "xxxxxxxxx..xx$$*.00..xx..xx..00.*$$xx..x");
+ strcpy(vgrid[27], "xxxxxxxxx..xx*$*$....xx..xx....*$$*xx..x");
+ strcpy(vgrid[28], "xxxxxxxxx...xx*$*....xx..xx....$$$xx...x");
+ strcpy(vgrid[29], "xxxxxxxxxx...xx*$....xx..xx....*$xx...xx");
+ strcpy(vgrid[30], "xxxxxxxxxxx...xxxxxxxxx..xxxxxxxxx...xxx");
+ strcpy(vgrid[31], "xxxxxxxxxxxx...xxxxxxxx..xxxxxxxx...xxxx");
+ strcpy(vgrid[32], "xxxxxxxxxxxxx..^................^..xxxxx");
+ strcpy(vgrid[33], "xxxxxxxxxxxxxxxxxxxxxxx^^xxxxxxxxxxxxxxx");
+ strcpy(vgrid[34], "xxxxxxxxxxxxxxxxxxxxxxx++xxxxxxxxxxxxxxx");
+ strcpy(vgrid[35], "xxxxxxxxxxxxxxxxxxxxxxx@xxxxxxxxxxxxxxxx");
+
+ return MAP_NORTHWEST;
+}
+
+static char vault_8(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // cross vault
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[6], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[7], "xxxxxxxxxxxxxxxxxx............xxxxxxxxxx");
+ strcpy(vgrid[8], "xxxxxxxxxxxxxxx..................xxxxxxx");
+ strcpy(vgrid[9], "xxxxxxxxxxxxx......................xxxxx");
+ strcpy(vgrid[10], "xxxxxxxxxxxx..........w..w..........xxxx");
+ strcpy(vgrid[11], "xxxxxxxxxxx........wwww++wwww........xxx");
+ strcpy(vgrid[12], "xxxxxxxxxxx......wwwvvv^^vvvwww......xxx");
+ strcpy(vgrid[13], "xxxxxxxxxx......wwwwv.9..9.vwwww......xx");
+ strcpy(vgrid[14], "xxxxxxxxxx.....wwwwwv......vwwwww.....xx");
+ strcpy(vgrid[15], "xxxxxxxxxx....wwwwwvv......vvwwwww....xx");
+ strcpy(vgrid[16], "xxxxxxxxx....wwwwwvv........vvwwwww....x");
+ strcpy(vgrid[17], "xxxxxxxxx....wwvvvv....vv....vvvvww....x");
+ strcpy(vgrid[18], "xxxxxxxxx...wwwv......vvvv......vwww...x");
+ strcpy(vgrid[19], "xxxxxxxxx...wwwv....vv8vv8vv....vwww...x");
+ strcpy(vgrid[20], "xxxxxxxxx..wwwwv...vvvv||vvvv...vwwww..x");
+ strcpy(vgrid[21], "xxxxxxxxx^^wwwwv...vvvv||vvvv...vwwww^^x");
+ strcpy(vgrid[22], "xxxxxxxxx..wwwwv....vv8vv8vv....vwwww..x");
+ strcpy(vgrid[23], "xxxxxxxxx...wwwv......vvvv......vwww...x");
+ strcpy(vgrid[24], "xxxxxxxxx...wwwvvvv....vv....vvvvwww...x");
+ strcpy(vgrid[25], "xxxxxxxxx....wwwwwvv........vvwwwww....x");
+ strcpy(vgrid[26], "xxxxxxxxxx...wwwwwwvv......vvwwwwww...xx");
+ strcpy(vgrid[27], "xxxxxxxxxx....wwwwwwv......vwwwwww....xx");
+ strcpy(vgrid[28], "xxxxxxxxxx.....wwwwwv......vwwwww.....xx");
+ strcpy(vgrid[29], "xxxxxxxxxxx.....wwwwvvvvvvvvwwww.....xxx");
+ strcpy(vgrid[30], "xxxxxxxxxxx.......wwwwwwwwwwww.......xxx");
+ strcpy(vgrid[31], "xxxxxxxxxxxx.........wwwwww.........xxxx");
+ strcpy(vgrid[32], "xxxxxxxxxxxxx.........^..^.........xxxxx");
+ strcpy(vgrid[33], "xxxxxxxxxxxxxxx.......x++x.......xxxxxxx");
+ strcpy(vgrid[34], "xxxxxxxxxxxxxxxxxx...xx..xx...xxxxxxxxxx");
+ strcpy(vgrid[35], "xxxxxxxxxxxxxxxxxxxxxx..@.xxxxxxxxxxxxxx");
+
+ return MAP_NORTHWEST;
+}
+
+
+static char vault_9(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // another thingy vault
+ UNUSED( mons_array );
+
+ for (unsigned char i = 0; i < 81; i++)
+ strcpy(vgrid[i], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ strcat(vgrid[36], "xxxxxxxxxxxxxxx@xxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[37], "xxxxxxxxxxxxxxx^xxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[38], "xxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[39], "xx.....^...............^.....xxxxxxxxxxx");
+ strcat(vgrid[40], "x..bb..xxxxxxxxxxxxxxxxx..bb..xxxxxxxxxx");
+ strcat(vgrid[41], "x..b...xxxxxxxxxxxxxxxxx...b..xxxxxxxxxx");
+ strcat(vgrid[42], "x...b..xxxxbbbbbbbbbxxxx..b...xxxxxxxxxx");
+ strcat(vgrid[43], "x..bb..xxbbb.......bbbxx..bb..xxxxxxxxxx");
+ strcat(vgrid[44], "x......xxb....9.9....bxx......xxxxxxxxxx");
+ strcat(vgrid[45], "x..bb..xbb..%$$$$$%..bbx..bb..xxxxxxxxxx");
+ strcat(vgrid[46], "x...b..xb..0%$***$%0..bx..b...xxxxxxxxxx");
+ strcat(vgrid[47], "x..b...xb..0%$*H*$%0..bx...b..xxxxxxxxxx");
+ strcat(vgrid[48], "x...b..xb..0%$***$%0..bx..b...xxxxxxxxxx");
+ strcat(vgrid[49], "x..b...xb...%$$$$$%...bx...b..xxxxxxxxxx");
+ strcat(vgrid[50], "x...b..xbb.900000009.bbx..b...xxxxxxxxxx");
+ strcat(vgrid[51], "x..b...xxb...........bxx...b..xxxxxxxxxx");
+ strcat(vgrid[52], "x..bb..xxbbb..9.9..bbbxx..bb..xxxxxxxxxx");
+ strcat(vgrid[53], "x......xxxxbbbb.bbbbxxxx......xxxxxxxxxx");
+ strcat(vgrid[54], "x..bb..xxxxxxxb=bxxxxxxx..bb..xxxxxxxxxx");
+ strcat(vgrid[55], "x..b...xxxxxxxx=xxxxxxxx...b..xxxxxxxxxx");
+ strcat(vgrid[56], "x...b..xxxxxxxx^xxxxxxxx..b...xxxxxxxxxx");
+ strcat(vgrid[57], "x..b....xxxxxxx=xxxxxxx....b..xxxxxxxxxx");
+ strcat(vgrid[58], "x...b...^.............^...b...xxxxxxxxxx");
+ strcat(vgrid[59], "x..b....xxxxxxxxxxxxxxx....b..xxxxxxxxxx");
+ strcat(vgrid[60], "x..bb..xxxxxxxxxxxxxxxxx..bb..xxxxxxxxxx");
+ strcat(vgrid[61], "xx....xxxxxxxxxxxxxxxxxxx....xxxxxxxxxxx");
+ strcat(vgrid[62], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[63], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[64], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[65], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[66], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[67], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[68], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[69], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ return MAP_SOUTHEAST;
+}
+
+
+static char vault_10(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // impenetrable vault
+ UNUSED( mons_array );
+
+ for (unsigned char i = 0; i < 81; i++)
+ strcpy(vgrid[i], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ strcat(vgrid[36], "..............@................xxxxxxxxx");
+ strcat(vgrid[37], "...............................xxxxxxxxx");
+ strcat(vgrid[38], "...............................xxxxxxxxx");
+ strcat(vgrid[39], "...............................xxxxxxxxx");
+ strcat(vgrid[40], "...............................xxxxxxxxx");
+ strcat(vgrid[41], ".....cccccccccccccccc..........xxxxxxxxx");
+ strcat(vgrid[42], ".....c[^...........9cc.........xxxxxxxxx");
+ strcat(vgrid[43], ".....c^xxxxx=xxxxxx..cc........xxxxxxxxx");
+ strcat(vgrid[44], ".....c.x9..^^^...9xx..cc.......xxxxxxxxx");
+ strcat(vgrid[45], ".....c.x.xxx=xxxx..xx..cc......xxxxxxxxx");
+ strcat(vgrid[46], ".....c.x^x$$$$$$xx..xx.9c......xxxxxxxxx");
+ strcat(vgrid[47], ".....c.=^=$*|||*$xx..xx.c......xxxxxxxxx");
+ strcat(vgrid[48], ".....c.x^xx$*|||*$xx.9x.c......xxxxxxxxx");
+ strcat(vgrid[49], ".....c.x9.xx$*|||*$xx^x.c......xxxxxxxxx");
+ strcat(vgrid[50], ".....c.xx..xx$*|||*$=^=.c......xxxxxxxxx");
+ strcat(vgrid[51], ".....c9.xx..xx$$$$$$x^x.c......xxxxxxxxx");
+ strcat(vgrid[52], ".....cc..xx..xxxx=xxx.x.c......xxxxxxxxx");
+ strcat(vgrid[53], "......cc..xx9...^^^..9x.c......xxxxxxxxx");
+ strcat(vgrid[54], ".......cc..xxxxxx=xxxxx^c......xxxxxxxxx");
+ strcat(vgrid[55], "........cc9...........^]c......xxxxxxxxx");
+ strcat(vgrid[56], ".........cccccccccccccccc......xxxxxxxxx");
+ strcat(vgrid[57], "...............................xxxxxxxxx");
+ strcat(vgrid[58], "...............................xxxxxxxxx");
+ strcat(vgrid[59], "...............................xxxxxxxxx");
+ strcat(vgrid[60], "...............................xxxxxxxxx");
+ strcat(vgrid[61], "...............................xxxxxxxxx");
+ strcat(vgrid[62], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[63], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[64], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[65], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[66], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[67], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[68], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[69], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ return MAP_SOUTHEAST;
+}
+
+
+static char orc_temple(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+ for (unsigned char i = 0; i < 81; i++)
+ strcpy(vgrid[i], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ strcpy(vgrid[36], "xxxxxxxxxxxxxxxxxxxxxxx@xxxxxxxxxxxxxxxx");
+ strcpy(vgrid[37], "xxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxx");
+ strcpy(vgrid[38], "xxxxxxxxxxxxxxxxxxxxxx...xxxxxxxxxxxxxxx");
+ strcpy(vgrid[39], "xxxxxxxxxxxxxxxxxxxxxx4.4xxxxxxxxxxxxxxx");
+ strcpy(vgrid[40], "xxxxxxxxx**..........x414x..........**xx");
+ strcpy(vgrid[41], "xxxxxxxxx**..........x4.4x..........**xx");
+ strcpy(vgrid[42], "xxxxxxxxx............+...+....4.......xx");
+ strcpy(vgrid[43], "xxxxxxxxx....4..4....x...x............xx");
+ strcpy(vgrid[44], "xxxxxxxxx............x...x.......4....xx");
+ strcpy(vgrid[45], "xxxxxxxxx............xx.xx............xx");
+ strcpy(vgrid[46], "xxxxxxxxx...4......xxxx+xxxx......6...xx");
+ strcpy(vgrid[47], "xxxxxxxxx........xxx.......xxx........xx");
+ strcpy(vgrid[48], "xxxxxxxxxxx...xxxx..2.....2..xxxx...xxxx");
+ strcpy(vgrid[49], "xxxxxxxxxxxx+xxxx.............xxxx+xxxxx");
+ strcpy(vgrid[50], "xxxxxxxxxxx...xxx.............xxx...xxxx");
+ strcpy(vgrid[51], "xxxxxxxxx......x...............x......xx");
+ strcpy(vgrid[52], "xxxxxxxxx..4...x...2...I...2...x...5..xx");
+ strcpy(vgrid[53], "xxxxxxxxx......x...............x......xx");
+ strcpy(vgrid[54], "xxxxxxxxx...4..xx.............xx..5...xx");
+ strcpy(vgrid[55], "xxxxxxxxx$......x....2...2....x......$xx");
+ strcpy(vgrid[56], "xxxxxxxxx$6..5..xx.....3.....xx.5...7$xx");
+ strcpy(vgrid[57], "xxxxxxxxx$$$.....xxx.......xxx.....$$$xx");
+ strcpy(vgrid[58], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[59], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[60], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[61], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[62], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[63], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[64], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[65], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[66], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[67], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[68], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[69], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ mons_array[0] = MONS_ORC_WARLORD;
+ mons_array[1] = MONS_ORC_PRIEST;
+ mons_array[2] = MONS_ORC_HIGH_PRIEST;
+ mons_array[3] = MONS_ORC_WARRIOR;
+ mons_array[4] = MONS_ORC_WIZARD;
+ mons_array[5] = MONS_ORC_KNIGHT;
+ mons_array[6] = MONS_ORC_SORCERER;
+
+ return MAP_SOUTHWEST;
+}
+
+static char my_map(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // by Matthew Ludivico
+
+ for (unsigned char i = 0; i < 81; i++)
+ strcpy(vgrid[i], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ strcpy(vgrid[36], "xxxxxxxxxx.@.xxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[37], "xxxxxxxxxxx...xxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[38], "xxxxxxxxxxxx..........................xx");
+ strcpy(vgrid[39], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx..xx");
+ strcpy(vgrid[40], "xxxxxxxxx.^^..........................xx");
+ strcpy(vgrid[41], "xxxxxxxxxx.^^xx+xxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[42], "xxxxxxxxxxx.^...11....xxxxxxxx..xxxxxxxx");
+ strcpy(vgrid[43], "xxxxxxxxxxxx..x.1..6..xxx........xx..xxx");
+ strcpy(vgrid[44], "xxxxxxxxxxxxx.xxxxxxxxx...vvvvv...x...xx");
+ strcpy(vgrid[45], "xxxxxxxxx6..1...x.........+1..v.......xx");
+ strcpy(vgrid[46], "xxxxxxxxx..1....x.........vvvvv........x");
+ strcpy(vgrid[47], "xxxxxxxxx..5...xx......................x");
+ strcpy(vgrid[48], "xxxxxxxxxxxxxx^++...........vvvvvvv....x");
+ strcpy(vgrid[49], "xxxxxxxxxxxxxx^xx...xx=xx...vv$%$vvvvv.x");
+ strcpy(vgrid[50], "xxxxxxxxxxxxxx^x...xxv1vxx...vvv*2...v.x");
+ strcpy(vgrid[51], "xxxxxxxxxxxxxx^x..vvvv7.vvvv...vv.vv+v^x");
+ strcpy(vgrid[52], "xxxxxxxxx..xxx^..vvvb....bvvv...vvv^...x");
+ strcpy(vgrid[53], "xxxxxxxxx%%.xx..vvvvb....bvvvv.......xxx");
+ strcpy(vgrid[54], "xxxxxxxxxx.....vvbbb......bbbvv.....xxxx");
+ strcpy(vgrid[55], "xxxxxxxxxxx....vvb....66....bvvxxxxxxxxx");
+ strcpy(vgrid[56], "xxxxxxxxxxxxxxvvvb..llllll..bvvvxxxxxxxx");
+ strcpy(vgrid[57], "xxxxxxxxxvvvvvvvvb..ll45ll..bvvvvvvvvxxx");
+ strcpy(vgrid[58], "xxxxxxxxxccc***+== .l3.2.l..cccccccccxxx");
+ strcpy(vgrid[59], "xxxxxxxxxccc+cccbb....ll....c..$$$$+$*cx");
+ strcpy(vgrid[60], "xxxxxxxxxcc|||cbb...3llll2...cc%*%*c$|cx");
+ strcpy(vgrid[61], "xxxxxxxxxcccccccbbbbbbbbbbbccccccccccccx");
+ strcpy(vgrid[62], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[63], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[64], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[65], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[66], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[67], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[68], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[69], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ mons_array[0] = MONS_HELL_HOUND;
+ mons_array[1] = MONS_NECROMANCER;
+ mons_array[2] = MONS_WIZARD;
+ mons_array[3] = MONS_ORANGE_DEMON;
+ mons_array[4] = MONS_ROTTING_DEVIL;
+ mons_array[5] = MONS_HELL_KNIGHT;
+ mons_array[6] = MONS_GREAT_ORB_OF_EYES;
+
+ return MAP_SOUTHWEST;
+}
+
+static char farm_and_country(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // by Matthew Ludivico (mll6@lehigh.edu)
+
+ for (unsigned char i = 0; i < 81; i++)
+ strcpy(vgrid[i], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ strcpy(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[6], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[7], "xxxxxxxxxxxxxxxxx..........................................xxxxxxxx}.xxxxxxxxxxx");
+ strcpy(vgrid[8], "xxxxxxxxxxxxxxxxxxx............xxxxxx....xxx.......xx...........xxxx..]xxxxxxxxx");
+ strcpy(vgrid[9], "xxxxxxxxxxxxxxx***x...........xxx..xxx............xxxx...........xx..xxxxxxxxxxx");
+ strcpy(vgrid[10], "xxxxxxxxxxxxxxx|*$=...xx.xxxxxxx....xxxxxxxxxx......xx................xxxxxxxxxx");
+ strcpy(vgrid[11], "xxxxxxxxxxxxxxxxxxx....xxxxxxxx......3..xxx.................x..........xxxxxxxxx");
+ strcpy(vgrid[12], "xxxxxxxxxxxxxxxxxx......x........x......xx.........w...................xxxxxxxxx");
+ strcpy(vgrid[13], "xxxxxxxxxxx)......xx...xxx.....xxx......x........www3....3.............xxxxxxxxx");
+ strcpy(vgrid[14], "xxxxxxxxxxxx=xxxxxxxxxxx...xxxxxxxxx..xxx.....wwwww....%%%.............xxxxxxxxx");
+ strcpy(vgrid[15], "xxxxxxxxxx......xxx.......xx.xxxx.x...xxxxxxxwwwwwww..5%%%..........xx.xxxxxxxxx");
+ strcpy(vgrid[16], "xxxxxxxxx.........x..xxxxxxxx.....x........3wwwwwwwww..%%%........xxx..xxxxxxxxx");
+ strcpy(vgrid[17], "xxxxxxxxx....5...xx..x.xxxxx.....xxx........wwwwwwwww..%%%..........xx.xxxxxxxxx");
+ strcpy(vgrid[18], "xxxxxxxxxxx.....xxx..xx..xx........xxxxxxxxxwwwwwwwww..............xxx.xxxxxxxxx");
+ strcpy(vgrid[19], "xxxxxxxxxx........x..x...............xx..xxxxwwwwwwwwwwwwww............xxxxxxxxx");
+ strcpy(vgrid[20], "xxxxxxxxx.............................x.....xxwwwwww3wwwwww............xxxxxxxxx");
+ strcpy(vgrid[21], "xxxxxxxxxxx...x...........5.....7...............ww.......ww.....44....xxxxxxxxxx");
+ strcpy(vgrid[22], "xxxxxxxxxwxx..xx.....622...2.26...6.2...22.6...62..2..226ww.....44xx...xxxxxxxxx");
+ strcpy(vgrid[23], "xxxxxxxxxwwxxxx......2....2.22....2..2...2.2.......22...2ww....xxxx..xxxxxxxxxxx");
+ strcpy(vgrid[24], "xxxxxxxxxwwwwxxx......2...2.2.2...2.22..2.22...22.2.2..22ww.....xxx....xxxxxxxxx");
+ strcpy(vgrid[25], "xxxxxxxxxwwwwwx....4..2...2...........22...277..2..2.2.22ww...........xxxxxxxxxx");
+ strcpy(vgrid[26], "xxxxxxxxxwwwwwxx....42..2....22.4..2..2...2.4..2.22..22.2ww............xxxxxxxxx");
+ strcpy(vgrid[27], "xxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww.wwwwwwwwwwwww..2.........xxxxxxxxx");
+ strcpy(vgrid[28], "xxxxxxxxxwwwwwxx.....62....2.26...62.2.2..26...6...22..26..............xxxxxxxxx");
+ strcpy(vgrid[29], "xxxxxxxxxwwwww.........................................................xxxxxxxxx");
+ strcpy(vgrid[30], "xxxxxxxxxwwwwwxx....222.2.22..2.7.......7..............................xxxxxxxxx");
+ strcpy(vgrid[31], "xxxxxxxxxwwwww...........ccccccc+ccccccc...ccc......cc+ccc...xxxxx.....xxxxxxxxx");
+ strcpy(vgrid[32], "xxxxxxxxxwwwwwxx.........c$$*.c$$5$+.5.c...+5c......c%%%%c......xxx3...xxxxxxxxx");
+ strcpy(vgrid[33], "xxxxxxxxxwwwwwx....2.....c$.c+cccccc.%.c...ccc......c%%%%c....xxxxx....xxxxxxxxx");
+ strcpy(vgrid[34], "xxxxxxxxxwwwwwx..........c..c..........c............cccccc......xxx....xxxxxxxxx");
+ strcpy(vgrid[35], "xxxxxxxxxwwxxxxxxx.......ccccc+ccccccccc.........................xx....xxxxxxxxx");
+ strcpy(vgrid[36], "xxxxxxxxxwxx.....xxxx........c...c.................2...................xxxxxxxxx");
+ strcpy(vgrid[37], "xxxxxxxxxxx.........xxxx...........2....xxxx...........................xxxxxxxxx");
+ strcpy(vgrid[38], "xxxxxxxxx..............xxxx..........xxxx..x...........................xxxxxxxxx");
+ strcpy(vgrid[39], "xxxxxxxxx.................xxxxx++xxxxx.....xx............xx...x........xxxxxxxxx");
+ strcpy(vgrid[40], "xxxxxxxxx.....................c..c..........xxxxx..........xxxxx.......xxxxxxxxx");
+ strcpy(vgrid[41], "xxxxxxxxx.......cccc..........c..c...cccc......xxx...........x.........xxxxxxxxx");
+ strcpy(vgrid[42], "xxxxxxxxx.......c..c..........c++c...c..c........xxx.........x.........xxxxxxxxx");
+ strcpy(vgrid[43], "xxxxxxxxx.......c..c..........c..c...c..c..........xxx.................xxxxxxxxx");
+ strcpy(vgrid[44], "xxxxxxxxx....cccc++cccccccccccc++ccccc..ccccccc......xxx...............xxxxxxxxx");
+ strcpy(vgrid[45], "xxxxxxxxx....c..........1.....................c........xxx.............xxxxxxxxx");
+ strcpy(vgrid[46], "xxxxxxxxx.cccc.....w....w....%1.....w.....%...c..........xxx...........xxxxxxxxx");
+ strcpy(vgrid[47], "xxxxxxxxx.c1.+....www..www..%%%....www...%%%1.c...........xxxxxxxxx....xxxxxxxxx");
+ strcpy(vgrid[48], "xxxxxxxxx.cccc.....w....w....%......w.....%...c..................xxx...xxxxxxxxx");
+ strcpy(vgrid[49], "xxxxxxxxx....c.......5........................c....................xxxxxxxxxxxxx");
+ strcpy(vgrid[50], "xxxxxxxxx....ccc....%%%%%....cccccccccccccccccc........................xxxxxxxxx");
+ strcpy(vgrid[51], "xxxxxxxxx......cc...........cc.........................................xxxxxxxxx");
+ strcpy(vgrid[52], "xxxxxxxxx.......cccccc+cccccc..........................................xxxxxxxxx");
+ strcpy(vgrid[53], "xxxxxxxxx........cc.......cc...........................................xxxxxxxxx");
+ strcpy(vgrid[54], "xxxxxxxxx.........cc.....cc.....................cccccccccccccccccccccccxxxxxxxxx");
+ strcpy(vgrid[55], "xxxxxxxxx..........ccc+ccc......................c......vvv.............xxxxxxxxx");
+ strcpy(vgrid[56], "xxxxxxxxx..........ccc.c........................c......v5+...vvvvv.....xxxxxxxxx");
+ strcpy(vgrid[57], "xxxxxxxxx..........ccc.c........................c......vvv...v.5.v.....xxxxxxxxx");
+ strcpy(vgrid[58], "xxxxxxxxxccccccccccccc.ccc......................c............v..5v.....xxxxxxxxx");
+ strcpy(vgrid[59], "xxxxxxxxx..........c.....cccccccccccccccccccccccccccc..........vv+vv...xxxxxxxxx");
+ strcpy(vgrid[60], "xxxxxxxxx..........c............................+................5111..xxxxxxxxx");
+ strcpy(vgrid[61], "xxxxxxxxx..........c.{([.c......................+................5.....xxxxxxxxx");
+ strcpy(vgrid[62], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[63], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[64], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[65], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[66], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[67], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[68], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[69], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ mons_array[0] = MONS_DEATH_YAK;
+ mons_array[1] = MONS_PLANT;
+ mons_array[2] = MONS_GRIFFON;
+ mons_array[3] = MONS_KILLER_BEE;
+ mons_array[4] = MONS_OGRE;
+ mons_array[5] = MONS_OKLOB_PLANT;
+ mons_array[6] = MONS_WANDERING_MUSHROOM;
+
+ return MAP_ENCOMPASS;
+}
+
+
+static char fort_yaktaur(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // by Matthew Ludivico (mll6@lehigh.edu)
+
+ for (unsigned char i = 0; i < 81; i++)
+ strcpy(vgrid[i], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ strcat(vgrid[36], ".........@....wwwwwwwwwwwwwwwwwxxxxxxxxx");
+ strcat(vgrid[37], ".ccccc.......ww....wwww....wwwwxxxxxxxxx");
+ strcat(vgrid[38], ".c$c%c......ww.ccccccccc.......xxxxxxxxx");
+ strcat(vgrid[39], ".c+c+c......ww.c.%$....ccccccccxxxxxxxxx");
+ strcat(vgrid[40], ".c...+......ww.c*.115..c$$+|*|cxxxxxxxxx");
+ strcat(vgrid[41], ".c1..c.....ww..c...55+ccc+cxx=cxxxxxxxxx");
+ strcat(vgrid[42], ".ccccc.....ww..ccccccc....c|=*cxxxxxxxxx");
+ strcat(vgrid[43], "............ww.......c5...cxx=cxxxxxxxxx");
+ strcat(vgrid[44], "....6.ccccc.ww.w...2.+51..c|1.cxxxxxxxxx"); // last 1 here was 7
+ strcat(vgrid[45], "....63+...c..wwww..21+51..c2.2cxxxxxxxxx");
+ strcat(vgrid[46], "....6.ccccc..wwwwww..c5...cc+ccxxxxxxxxx");
+ strcat(vgrid[47], "............wwwwwww..c........cxxxxxxxxx");
+ strcat(vgrid[48], "............wwwwwww..ccccccccccxxxxxxxxx");
+ strcat(vgrid[49], "...........ww1w..www...........xxxxxxxxx");
+ strcat(vgrid[50], ".......566.www.....www.........xxxxxxxxx");
+ strcat(vgrid[51], ".........1ww....ccccc..........xxxxxxxxx");
+ strcat(vgrid[52], ".....566.w......+...c..........xxxxxxxxx");
+ strcat(vgrid[53], ".........www....ccccc..........xxxxxxxxx");
+ strcat(vgrid[54], "...........ww............wwwwwwxxxxxxxxx");
+ strcat(vgrid[55], ".......3....wwwww......www.....xxxxxxxxx");
+ strcat(vgrid[56], "......666.......ww...www.......xxxxxxxxx");
+ strcat(vgrid[57], ".....cc+cc.......wwwww.........xxxxxxxxx");
+ strcat(vgrid[58], ".....c...c.....................xxxxxxxxx");
+ strcat(vgrid[59], ".....ccccc.....................xxxxxxxxx");
+ strcat(vgrid[60], "...............................xxxxxxxxx");
+ strcat(vgrid[61], "...............................xxxxxxxxx");
+ strcat(vgrid[62], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[63], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[64], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[65], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[66], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[67], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[68], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[69], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ mons_array[0] = MONS_YAKTAUR;
+ mons_array[1] = MONS_DEATH_YAK;
+ mons_array[2] = MONS_MINOTAUR;
+ mons_array[3] = RANDOM_MONSTER;
+ mons_array[4] = MONS_YAK;
+ mons_array[5] = MONS_GNOLL;
+ mons_array[6] = RANDOM_MONSTER;
+
+ return MAP_SOUTHEAST;
+}
+
+
+static char box_level(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // by John Savard
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[6], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[7], "xxxxxxxxx.................xx.............x...................^.........xxxxxxxxx");
+ strcpy(vgrid[8], "xxxxxxxxx.................xx...xxxxxx....x.xxxxxxx.xxxxxxxxxxxxxxxxxxx.xxxxxxxxx");
+ strcpy(vgrid[9], "xxxxxxxxx.................xx...xx.0......x.x........x......x.........x.xxxxxxxxx");
+ strcpy(vgrid[10], "xxxxxxxxx..$..............xx...xx........x.x........x.....%x.x..*..xxx.xxxxxxxxx");
+ strcpy(vgrid[11], "xxxxxxxxx......................xx........x.x........x.xxxxxx.x.....x...xxxxxxxxx");
+ strcpy(vgrid[12], "xxxxxxxxx......................xx....%...x.x........x.x......xxxxxxx.x.xxxxxxxxx");
+ strcpy(vgrid[13], "xxxxxxxxx.................xx...xx........x.x........x.x.xxxxxx.......x.xxxxxxxxx");
+ strcpy(vgrid[14], "xxxxxxxxx.................xx...xx........x.x..{.....x.x..............x.xxxxxxxxx");
+ strcpy(vgrid[15], "xxxxxxxxx.............0...xx...xxxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxxxxxxxx.xxxxxxxxx");
+ strcpy(vgrid[16], "xxxxxxxxx.................xx...........................................xxxxxxxxx");
+ strcpy(vgrid[17], "xxxxxxxxxxxxxxxxxxxxxxxxxxxx...xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[18], "xxxxxxxxxxxxxxxxxxxxxxxxxxxx...xxx}x.........................>=........xxxxxxxxx");
+ strcpy(vgrid[19], "xxxxxxxxx..................x...xxx.x.xxx+xxxxxxxxxxxxxxxx+xxxxx........xxxxxxxxx");
+ strcpy(vgrid[20], "xxxxxxxxx..xxxxxxxxxxxxxx..x...xxx.x.x0...x..0..............0.x........xxxxxxxxx");
+ strcpy(vgrid[21], "xxxxxxxxx..x............x..x...xxx.x.x....x...................x........xxxxxxxxx");
+ strcpy(vgrid[22], "xxxxxxxxx....xxxxxxxxx..x..x...xxx.x.x....x...................x......8*xxxxxxxxx");
+ strcpy(vgrid[23], "xxxxxxxxx..x.x....0..x..x..x...xxx...x...%x...................x......*|xxxxxxxxx");
+ strcpy(vgrid[24], "xxxxxxxxx..x.x..........x..x...xxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[25], "xxxxxxxxx..x.x*......x..x..x..........x...........0...x...%............xxxxxxxxx");
+ strcpy(vgrid[26], "xxxxxxxxx..x.xxxxxxxxx..x..=..........x.xxxxxxxxxxxxx.x................xxxxxxxxx");
+ strcpy(vgrid[27], "xxxxxxxxx..x......0.....xxxxxxx.......x.x...x...x...x.x................xxxxxxxxx");
+ strcpy(vgrid[28], "xxxxxxxxx..xxxxxxxxxxxxxxxxxxxx..0....x...x.x.x.x.x.x.x......0.........xxxxxxxxx");
+ strcpy(vgrid[29], "xxxxxxxxx..........^.........xx.......x.x.x.x.x.x.x...+................xxxxxxxxx");
+ strcpy(vgrid[30], "xxxxxxxxxcccccccccccccccccc..xx.......x.x$x...x...xxxxx................xxxxxxxxx");
+ strcpy(vgrid[31], "xxxxxxxxxc...........9....c..xx.......x.x.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[32], "xxxxxxxxxc......c............xx.......x.x.x...x..0.....................xxxxxxxxx");
+ strcpy(vgrid[33], "xxxxxxxxxc.....|c............xx.......x.x.x.x.x........................xxxxxxxxx");
+ strcpy(vgrid[34], "xxxxxxxxxc...........9....c..xx.......x.x...x.x........................xxxxxxxxx");
+ strcpy(vgrid[35], "xxxxxxxxxcccccccccccccccccc..xx.......x.xxxxx.x........................xxxxxxxxx");
+ strcpy(vgrid[36], "xxxxxxxxx....................xx.......x.x.....=....................*...xxxxxxxxx");
+ strcpy(vgrid[37], "xxxxxxxxx....................xx.......x.x.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[38], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.......x.x.x...........................(xxxxxxxxx");
+ strcpy(vgrid[39], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxx.x$x..xxxx.xxxxxxxxxxxxxxxxxxxx.xxxxxxxxx");
+ strcpy(vgrid[40], "xxxxxxxxx...............................x.x..x.......................x.xxxxxxxxx");
+ strcpy(vgrid[41], "xxxxxxxxx..xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.x..x.xxxxxxxxxxxxx.........x.xxxxxxxxx");
+ strcpy(vgrid[42], "xxxxxxxxx.............)xxx................x..x.xxxxxxxxxxxxx.........x.xxxxxxxxx");
+ strcpy(vgrid[43], "xxxxxxxxx..............xxx.xxxxxxxxxxxxxxxx..x.xxxxxxxxxxxxx.........x.xxxxxxxxx");
+ strcpy(vgrid[44], "xxxxxxxxx..............xxx...................x.x...........xxxxx+xxxxx.xxxxxxxxx");
+ strcpy(vgrid[45], "xxxxxxxxx..............xxxxxxxxxxxxxxxxxxxxxxx.x..$........x.........x.xxxxxxxxx");
+ strcpy(vgrid[46], "xxxxxxxxx......9.......xxxxxxxxxxxxxxxxxxxxxxx.x...........x........%x.xxxxxxxxx");
+ strcpy(vgrid[47], "xxxxxxxxx..............xxxxxxxxxxxxxxxxxxxxxxx.x.0.........x0........x.xxxxxxxxx");
+ strcpy(vgrid[48], "xxxxxxxxx..............xxxxxxxxxxxxxxxxxxxxxxx.x.......$...x.........x.xxxxxxxxx");
+ strcpy(vgrid[49], "xxxxxxxxx..............xxxxxxxxxxxxxxxxxxxxxxx.x...........xxxxxxxxxxx.xxxxxxxxx");
+ strcpy(vgrid[50], "xxxxxxxxx..............xxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxx.x...........xxxxxxxxx");
+ strcpy(vgrid[51], "xxxxxxxxx..............xxxxxxxxxxxxxxxxxxxxxxx.............x...........xxxxxxxxx");
+ strcpy(vgrid[52], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx+xxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[53], "xxxxxxxxx..............................................................xxxxxxxxx");
+ strcpy(vgrid[54], "xxxxxxxxx.xxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxx.xxxxxxx=xxxxxx.xxxxxx.xxxxxxxxx");
+ strcpy(vgrid[55], "xxxxxxxxx.....xx.................xxxxxxxxxxx.......x........x.....x....xxxxxxxxx");
+ strcpy(vgrid[56], "xxxxxxxxx....0xx.................xxxxxxxxxxx.%.....x.0......x...0.x....xxxxxxxxx");
+ strcpy(vgrid[57], "xxxxxxxxx.....xx.9...............xxxxxxxxxxx.......x........x.%...x..$.xxxxxxxxx");
+ strcpy(vgrid[58], "xxxxxxxxx.....xx.................xxxxxxxxxxx.......x........x.....x....xxxxxxxxx");
+ strcpy(vgrid[59], "xxxxxxxxx.....xx.................xxxxxxxxxxx.......x........x.....x..0.xxxxxxxxx");
+ strcpy(vgrid[60], "xxxxxxxxx....0xx.................xxxxxxxxxxx.......x$.......x.....x....xxxxxxxxx");
+ strcpy(vgrid[61], "xxxxxxxxx]....xx................*xxxxxxxxxxx......[x........x.....x$...xxxxxxxxx");
+ strcpy(vgrid[62], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[63], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[64], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[65], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[66], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[67], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[68], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[69], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ return MAP_ENCOMPASS;
+}
+
+
+static char vestibule_map(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // this is the vestibule
+
+ strcpy(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[6], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxvvvvvvvxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[7], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx..v.....v..xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[8], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.....v.....v.....xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[9], "xxxxxxxxxxxxxxxxxxxxxxxxxxxx........v.....v........xxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[10], "xxxxxxxxxxxxxxxxxxxxxxxxxx..........v..A..v..........xxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[11], "xxxxxxxxxxxxxxxxxxxxxxxx............v.....v............xxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[12], "xxxxxxxxxxxxxxxxxxxxxxx.............v.....v.............xxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[13], "xxxxxxxxxxxxxxxxxxxxxx..............vvv+vvv..............xxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[14], "xxxxxxxxxxxxxxxxxxxxx.....................................xxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[15], "xxxxxxxxxxxxxxxxxxxx.......................................xxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[16], "xxxxxxxxxxxxxxxxxxx.........................................xxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[17], "xxxxxxxxxxxxxxxxxx...........................................xxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[18], "xxxxxxxxxxxxxxxxx.............................................xxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[19], "xxxxxxxxxxxxxxxx...............................................xxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[20], "xxxxxxxxxxxxxxx.................................................xxxxxxxxxxxxxxxx");
+ strcpy(vgrid[21], "xxxxxxxxxxxxxx...................................................xxxxxxxxxxxxxxx");
+ strcpy(vgrid[22], "xxxxxxxxxxxxx.....................................................xxxxxxxxxxxxxx");
+ strcpy(vgrid[23], "xxxxxxxxxxxxx.....................................................xxxxxxxxxxxxxx");
+ strcpy(vgrid[24], "xxxxxxxxxxxx.......................................................xxxxxxxxxxxxx");
+ strcpy(vgrid[25], "xxxxxxxxxxxx.......................................................xxxxxxxxxxxxx");
+ strcpy(vgrid[26], "xxxxxxxxxxx.........................................................xxxxxxxxxxxx");
+ strcpy(vgrid[27], "xxxxxxxxxxx............................{............................xxxxxxxxxxxx");
+ strcpy(vgrid[28], "xxxxxxxxxxx.........................................................xxxxxxxxxxxx");
+ strcpy(vgrid[29], "xxxxxxxxxx...l.l.....................................................xxxxxxxxxxx");
+ strcpy(vgrid[30], "xxxxxxxxxx..l.l.l.l..................................................xxxxxxxxxxx");
+ strcpy(vgrid[31], "xxxxxxxxxx.l.l.l.l.l.................................................xxxxxxxxxxx");
+ strcpy(vgrid[32], "xxxxxxxxx.l.l.l.l.l...................................................xxxxxxxxxx");
+ strcpy(vgrid[33], "xxxxxxxxxl.l.l.l.l.l..................................................xxxxxxxxxx");
+ strcpy(vgrid[34], "xxxxxxxxx.l.l.l.A.l.l.................}1].............................=Axxxxxxxx");
+ strcpy(vgrid[35], "xxxxxxxxxl.l.l.l.l.l.l.................)..............................xxxxxxxxxx");
+ strcpy(vgrid[36], "xxxxxxxxx.l.l.l.l.l.l.................................................xxxxxxxxxx");
+ strcpy(vgrid[37], "xxxxxxxxxx.l.l.l.l.l.l...............................................xxxxxxxxxxx");
+ strcpy(vgrid[38], "xxxxxxxxxx..l.l.l.l..................................................xxxxxxxxxxx");
+ strcpy(vgrid[39], "xxxxxxxxxx.....l.l...................................................xxxxxxxxxxx");
+ strcpy(vgrid[40], "xxxxxxxxxxx......................[...........(......................xxxxxxxxxxxx");
+ strcpy(vgrid[41], "xxxxxxxxxxx.........................................................xxxxxxxxxxxx");
+ strcpy(vgrid[42], "xxxxxxxxxxx.........................................................xxxxxxxxxxxx");
+ strcpy(vgrid[43], "xxxxxxxxxxxx.......................................................xxxxxxxxxxxxx");
+ strcpy(vgrid[44], "xxxxxxxxxxxx.......................................................xxxxxxxxxxxxx");
+ strcpy(vgrid[45], "xxxxxxxxxxxxx.....................................................xxxxxxxxxxxxxx");
+ strcpy(vgrid[46], "xxxxxxxxxxxxx.....................................................xxxxxxxxxxxxxx");
+ strcpy(vgrid[47], "xxxxxxxxxxxxxx...................................................xxxxxxxxxxxxxxx");
+ strcpy(vgrid[48], "xxxxxxxxxxxxxxx....................wwwww........................xxxxxxxxxxxxxxxx");
+ strcpy(vgrid[49], "xxxxxxxxxxxxxxxx..................wwwwwwww.....................xxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[50], "xxxxxxxxxxxxxxxxx..............wwwwwwwwwwwww..................xxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[51], "xxxxxxxxxxxxxxxxxx...........w..wwww..wwwww..w...............xxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[52], "xxxxxxxxxxxxxxxxxxx..........w...ww.....ww..wwwww...........xxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[53], "xxxxxxxxxxxxxxxxxxxx.........ww......ww....wwwwwwwww.......xxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[54], "xxxxxxxxxxxxxxxxxxxxx.........ww....wwww...wwwwwwwwww.....xxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[55], "xxxxxxxxxxxxxxxxxxxxxx.........ww....ww....wwwwwwwwwww...xxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[56], "xxxxxxxxxxxxxxxxxxxxxxx........wwww.......wwwwwwwwwwwwwwxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[57], "xxxxxxxxxxxxxxxxxxxxxxxx......wwwwwww....wwwwwwwwwwwwwwxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[58], "xxxxxxxxxxxxxxxxxxxxxxxxxx...wwwwwwwwwwAwwwwwwwwwwwwwxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[59], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[60], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[61], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[62], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[63], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[64], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[65], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[66], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[67], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[68], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[69], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ mons_array[0] = MONS_GERYON;
+ mons_array[1] = RANDOM_MONSTER;
+ mons_array[2] = RANDOM_MONSTER;
+ mons_array[3] = RANDOM_MONSTER;
+ mons_array[4] = RANDOM_MONSTER;
+ mons_array[5] = RANDOM_MONSTER;
+ mons_array[6] = RANDOM_MONSTER;
+
+ return MAP_ENCOMPASS;
+}
+
+
+static char castle_dis(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // Dispater's castle - rest of level filled up with plan_4 (irregular city)
+
+ strcpy(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[6], "xxxxxxxxvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvxxxxxxxx");
+ strcpy(vgrid[7], "xxxxxxxxv..............................................................vxxxxxxxx");
+ strcpy(vgrid[8], "xxxxxxxxv..vvvvvvvvv........................................vvvvvvvvv..vxxxxxxxx");
+ strcpy(vgrid[9], "xxxxxxxxv..v3.....|v........................................v|.....2v..vxxxxxxxx");
+ strcpy(vgrid[10], "xxxxxxxxv..v.vv+vvvv.v.v.v.v.v.v.v.v.v..v.v.v.v.v.v.v.v.v.v.vvvv+vv.v..vxxxxxxxx");
+ strcpy(vgrid[11], "xxxxxxxxv..v.v.....vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv.....v.v..vxxxxxxxx");
+ strcpy(vgrid[12], "xxxxxxxxv..v|v.....+$$v$$+$$v||vvvvvvvvvvvvvvvvv$$$$v4.4.v$$v.....v|v..vxxxxxxxx");
+ strcpy(vgrid[13], "xxxxxxxxv..vvvv+vvvv$$+$$v$$+||v...............v$$$$+.4.4+$$v+vv+vvvv..vxxxxxxxx");
+ strcpy(vgrid[14], "xxxxxxxxv....vv.vvvvvvvvvvvvvvvv.v..v..v..v..v.v$$$$v4.4.v$$+||v.vv5...vxxxxxxxx");
+ strcpy(vgrid[15], "xxxxxxxxv...vvv................v...............vvvvvvvvvvvvvvvvv.vvv...vxxxxxxxx");
+ strcpy(vgrid[16], "xxxxxxxxv...5vv................+...............+.................vv....vxxxxxxxx");
+ strcpy(vgrid[17], "xxxxxxxxv...vvv+vvvvvvvvvvvvvvvv.v..v..v..v..v.vvvvvvvvvvvvvvvvv.vvv...vxxxxxxxx");
+ strcpy(vgrid[18], "xxxxxxxxv....vv..v.+$$$$$v.....v...............vvvvvvvvvvvvvvvvv.vv5...vxxxxxxxx");
+ strcpy(vgrid[19], "xxxxxxxxv...vvv..v.v$$$$$v.....v...............vv|$|$|vv|$|$|$vv.vvv...vxxxxxxxx");
+ strcpy(vgrid[20], "xxxxxxxxv...5vv..v.vvvvvvv.....vvvvv.......vvvvvv$|$|$++$|$|$|vv.vv....vxxxxxxxx");
+ strcpy(vgrid[21], "xxxxxxxxv...vvv..v...............v.vvvv+vvvvvvvvvvvvvvvvvvvvv+vv.vvv...vxxxxxxxx");
+ strcpy(vgrid[22], "xxxxxxxxv....vvv+v..........vvvvv.4vvv...vvvvvvvvvvvvvvvvvvvv+vv.vv5...vxxxxxxxx");
+ strcpy(vgrid[23], "xxxxxxxxv...vvv..v.v..v..v....2vvv+vv5...5vvvvvvv.4.4.vv.4.4.4vv.vvv...vxxxxxxxx");
+ strcpy(vgrid[24], "xxxxxxxxv...5vv.................vv|vvv...vvvvv.++4.4.4++4.4.4.vv.vv....vxxxxxxxx");
+ strcpy(vgrid[25], "xxxxxxxxv...vvv.................1vOvv5...5vvvv.vvvvvvvvvvvvvvvvv.vvv...vxxxxxxxx");
+ strcpy(vgrid[26], "xxxxxxxxv....vv.................vv|vvv...vvvvv.vvvvvvvvvvvvvvvvv.vv5...vxxxxxxxx");
+ strcpy(vgrid[27], "xxxxxxxxv...vvv.v..v..v..v....3vvv+vv5...5vvvv...................vvv...vxxxxxxxx");
+ strcpy(vgrid[28], "xxxxxxxxv...5vv.............vvvvv.4vvv...vvvvvvvvvvvvvvvvvvvvvvv.vv....vxxxxxxxx");
+ strcpy(vgrid[29], "xxxxxxxxv..vvvv+vvvv.............v.vv5...5vvvvvvvvvvvvvvvvvvvvvv+vvvv..vxxxxxxxx");
+ strcpy(vgrid[30], "xxxxxxxxv..v|v.....vvvvvvvvvvvvvvvvvvv...vvvvvvvvvvvvvvvvvvvv.....v|v..vxxxxxxxx");
+ strcpy(vgrid[31], "xxxxxxxxv..v.v.....vvvvvvvvvvvvvvvvvvvv+vvvvvvvvvvvvvvvvvvvvv.....v.v..vxxxxxxxx");
+ strcpy(vgrid[32], "xxxxxxxxv..v.vv+vvvv5.............5.........5..............5vvvv+vv.v..vxxxxxxxx");
+ strcpy(vgrid[33], "xxxxxxxxv..v2.....|v........................................v|.....3v..vxxxxxxxx");
+ strcpy(vgrid[34], "xxxxxxxxv..vvvvvvvvv........................................vvvvvvvvv..vxxxxxxxx");
+ strcpy(vgrid[35], "xxxxxxxxv............................{.[.(.............................vxxxxxxxx");
+
+ mons_array[0] = MONS_DISPATER;
+ mons_array[1] = MONS_FIEND;
+ mons_array[2] = MONS_ICE_FIEND;
+ mons_array[3] = MONS_IRON_DEVIL;
+ mons_array[4] = MONS_METAL_GARGOYLE;
+ mons_array[5] = RANDOM_MONSTER;
+ mons_array[6] = RANDOM_MONSTER;
+
+ return MAP_NORTH_DIS;
+}
+
+
+static char asmodeus(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+
+ strcpy(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[6], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[7], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxx....xxxxxxxxxxxxxxx.xxxxxxxxxxxx");
+ strcpy(vgrid[8], "xxxxxxxxxxxxxxxxxxxxxxxxx............................xxxxxxxxxxxxxx..xxxxxxxxxxx");
+ strcpy(vgrid[9], "xxxxxxxxxxxxxxxxxxxxxxxxxx..............................xxxxxxxxxx....xxxxxxxxxx");
+ strcpy(vgrid[10], "xxxxxxxxxxxxxxxxxxxxx...xxx................................xxxxxx....xxxxxxxxxxx");
+ strcpy(vgrid[11], "xxxxxxxxxxxx.x.xxxxx.........................................xxx....xxxxxxxxxxxx");
+ strcpy(vgrid[12], "xxxxxxxxxxxx....xx.....................4......................xx...xxxxxxxxxxxxx");
+ strcpy(vgrid[13], "xxxxxxxxxxx......x......................llllllllllllll.........x..xxxxxxxxxxxxxx");
+ strcpy(vgrid[14], "xxxxxxxxxxx..xx..................lllllllllllllllllllllllll........xxxxxxxxxxxxxx");
+ strcpy(vgrid[15], "xxxxxxxxxx...xxx....0..........llllllllllllllllllllllllll........xx...xxxxxxxxxx");
+ strcpy(vgrid[16], "xxxxxxxxx....xxx.............llllllllllllllllllllllllllll..............xxxxxxxxx");
+ strcpy(vgrid[17], "xxxxxxxxxx....xx...........lllllllllllllllllllllllllllll...............xxxxxxxxx");
+ strcpy(vgrid[18], "xxxxxxxxxxxx..............llllllllllllllllllllllllllllll...2..xx...0...xxxxxxxxx");
+ strcpy(vgrid[19], "xxxxxxxxxxxxx...........lllllllllllllllllll.......llllll......xx......xxxxxxxxxx");
+ strcpy(vgrid[20], "xxxxxxxxxxxxxx.......llllllllllllllllll............llllll.............xxxxxxxxxx");
+ strcpy(vgrid[21], "xxxxxxxxxxxxxxx......lllllllll..........4.........4.lllllll..........xxxxxxxxxxx");
+ strcpy(vgrid[22], "xxxxxxxxxx...xx...ll3lllll......4...................llllllll......x.xxxxxxxxxxxx");
+ strcpy(vgrid[23], "xxxxxxxxx.......lllll.l................................llll.......xxxxxxxxxxxxxx");
+ strcpy(vgrid[24], "xxxxxxxxxx..4..llllll...cccccccc+c+c+c+c+c+c+c+c+c+c....lll......xxxxxxxxxxxxxxx");
+ strcpy(vgrid[25], "xxxxxxxxxxx..lllllll..4.c.....c....................c....llll.....xxxxxxxxxxxxxxx");
+ strcpy(vgrid[26], "xxxxxxxxxx...llllll.....c.V.V.+....0.....3.....0...c.....llll....x..xxxxxxxxxxxx");
+ strcpy(vgrid[27], "xxxxxxxxx...llllll...l..c.....c....................c....lllll........xxxxxxxxxxx");
+ strcpy(vgrid[28], "xxxxxxxxxx...lllll..ll..c..5..cccccccccccccccccccccc.4..llllll........xxxxxxxxxx");
+ strcpy(vgrid[29], "xxxxxxxxx...lllll..llll.c.....c...............c....c....lllllll.......xxxxxxxxxx");
+ strcpy(vgrid[30], "xxxxxxxxx...lllll..llll.c.V.V.c.......0.......c....c....lllllll.......xxxxxxxxxx");
+ strcpy(vgrid[31], "xxxxxxxxxx...lllll..lll.c.....+...............+....c...lllllll........xxxxxxxxxx");
+ strcpy(vgrid[32], "xxxxxxxxxxx..lllll...ll.cccccccccc....0.......c....c...llllllll........xxxxxxxxx");
+ strcpy(vgrid[33], "xxxxxxxxxx...lllll..4...c|$$||$$|c............c.0..c...llllllll........xxxxxxxxx");
+ strcpy(vgrid[34], "xxxxxxxxx...lllll.......c$$$$$$$$cccccccccccccc....c...lllllll.........xxxxxxxxx");
+ strcpy(vgrid[35], "xxxxxxxxx...lllll.......c$$|2|$$|c..0.........+....c...lllllll........xxxxxxxxxx");
+ strcpy(vgrid[36], "xxxxxxxxxx.lllllll......c|$$$$$$$c........9...c....c....llllllll.....xxxxxxxxxxx");
+ strcpy(vgrid[37], "xxxxxxxxxx.lllllll......c$|$|$$|$c+ccccccccccccccccc....lllllll......xxxxxxxxxxx");
+ strcpy(vgrid[38], "xxxxxxxxxx..llllll......cccccccc+c.....9.......c.........llllll......x.xxxxxxxxx");
+ strcpy(vgrid[39], "xxxxxxxxxx..lllllll.....c$$$$$$+3c.....8...3...c.....4...llllll........xxxxxxxxx");
+ strcpy(vgrid[40], "xxxxxxxxxx..llllllll....c$$$$$$c.c.....9.......c..ll....llllll.........xxxxxxxxx");
+ strcpy(vgrid[41], "xxxxxxxxxx...llllll..4..c$$2$$$c.ccccccccccccc+c.lll...lllllll...0....xxxxxxxxxx");
+ strcpy(vgrid[42], "xxxxxxxxxxx..llllll.....c$$$$$$c..+............c.ll...lllllll..........xxxxxxxxx");
+ strcpy(vgrid[43], "xxxxxxxxxxx..llllllll...ccccccccc+cccccccccccccc.....lllllll...........xxxxxxxxx");
+ strcpy(vgrid[44], "xxxxxxxxxxxx..llllllll.........cc..........cc........lllllll.......x..xxxxxxxxxx");
+ strcpy(vgrid[45], "xxxxxxxxxxxxx.llllllllll.......ccc.........cc......lllllllll.......xxxxxxxxxxxxx");
+ strcpy(vgrid[46], "xxxxxxxxxx....lllllllllll...4...cc.....2.2.cc....llllllllll.4.......xxxxxxxxxxxx");
+ strcpy(vgrid[47], "xxxxxxxxx....4.lllllllllllll....cccccccc+cccc..lllllllllll.....xx....xxxxxxxxxxx");
+ strcpy(vgrid[48], "xxxxxxxxxx.....llllllllllllll...cccccccc+cccc..llllllllll......xx....xxxxxxxxxxx");
+ strcpy(vgrid[49], "xxxxxxxxxxx.....lllllllllllllll..cc......cc...lllllllllll...........xxxxxxxxxxxx");
+ strcpy(vgrid[50], "xxxxxxxxxxx.....llllllllllllll...ccO1....cc.4..lllllllll...........xxxxxxxxxxxxx");
+ strcpy(vgrid[51], "xxxxxxxxxxxx.....lllllllllllll...cc......cc....lllllllll.......xx.xxxxxxxxxxxxxx");
+ strcpy(vgrid[52], "xxxxxxxxxxxx.......llllllllllll..cccccccccc...lllllllll........xxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[53], "xxxxxxxxx.........llllllllllllll.cccccccccc.lllllllllll.......xxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[54], "xxxxxxxxxx....0...llllllllllllll............lllllllll....0....xxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[55], "xxxxxxxxxx.......4.lllllllllllllll..4....lllllllll...........xxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[56], "xxxxxxxxxxx..........llllllllllllll....lllllll....4.....x........xxxxxxxxxxxxxxx");
+ strcpy(vgrid[57], "xxxxxxxxxxx...xx.........lllllllllllllllll...................xx{xxxxxxxxxxxxxxxx");
+ strcpy(vgrid[58], "xxxxxxxxxxxxx..xx................lllllll.....................xxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[59], "xxxxxxxxxxxxxxxxx.........xxx.................xxxxxx......xxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[60], "xxxxxxxxxxxxxxxxxxx....xxxxxxxx...xxx......xxxxxxxxxx.......xxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[61], "xxxxxxxxxxxxxxxxxxxx(xxxxxxxxxxxx[xxxxx...xxxxxxxxxxxxxx...xxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[62], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[63], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[64], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[65], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[66], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[67], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[68], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[69], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ mons_array[0] = MONS_ASMODEUS;
+ mons_array[1] = MONS_FIEND;
+ mons_array[2] = MONS_BALRUG;
+ mons_array[3] = MONS_MOLTEN_GARGOYLE;
+ mons_array[4] = MONS_SERPENT_OF_HELL;
+ mons_array[5] = RANDOM_MONSTER;
+ mons_array[6] = RANDOM_MONSTER;
+
+ return MAP_ENCOMPASS;
+}
+
+static char antaeus(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // bottom of Cocytus. This needs work
+
+ strcpy(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[6], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[7], "xxxxxxxxxxxxxxxxxxxxxxxxxxxx........................xxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[8], "xxxxxxxxxxxxxxxxxxxxxxxxxxx..........................xxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[9], "xxxxxxxxxxxxxxxxxxxxxxxxxx............................xxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[10], "xxxxxxxxxxxxxxxxxxxxxxxxx..............................xxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[11], "xxxxxxxxxxxxxxxxxxxxxxxx................................xxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[12], "xxxxxxxxxxxxxxxxxxxxxxx....cccccccccccc..cccccccccccc....xxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[13], "xxxxxxxxxxxxxxxxxxxxxx....ccccccccccccc2.ccccccccccccc....xxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[14], "xxxxxxxxxxxxxxxxxxxxx....cc..........................cc....xxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[15], "xxxxxxxxxxxxxxxxxxxx....cc............................cc....xxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[16], "xxxxxxxxxxxxxxxxxxx....cc...wwwwwwwwwwwwwwwwwwwwwwww...cc....xxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[17], "xxxxxxxxxxxxxxxxxx....cc...wwwwwwwwwwwwwwwwwwwwwwwwww...cc....xxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[18], "xxxxxxxxxxxxxxxxx....cc...wwwwwwwwwwwwwwwwwwwwwwwwwwww...cc....xxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[19], "xxxxxxxxxxxxxxxx....cc...ww.......3..........3.......ww...cc....xxxxxxxxxxxxxxxx");
+ strcpy(vgrid[20], "xxxxxxxxxxxxxxx....cc...ww............................ww...cc....xxxxxxxxxxxxxxx");
+ strcpy(vgrid[21], "xxxxxxxxxxxxxx....cc...ww....cccccccccccccccccccccc....ww...cc....xxxxxxxxxxxxxx");
+ strcpy(vgrid[22], "xxxxxxxxxxxxx....cc...ww....cccccccccccccccccccccccc....ww...cc....xxxxxxxxxxxxx");
+ strcpy(vgrid[23], "xxxxxxxxxxxx....cc...ww....cc......................cc....ww...cc....xxxxxxxxxxxx");
+ strcpy(vgrid[24], "xxxxxxxxxxx....cc...ww....cc...T................T...cc....ww...cc....xxxxxxxxxxx");
+ strcpy(vgrid[25], "xxxxxxxxxx....cc...ww....cc..........wwwwww..........cc....ww...cc....xxxxxxxxxx");
+ strcpy(vgrid[26], "xxxxxxxxx....cc...ww....cc.......wwwwwwwwwwwwww.......cc....ww...cc....xxxxxxxxx");
+ strcpy(vgrid[27], "xxxxxxxxx....cc...ww...cc.....wwwwwwwwwwwwwwwwwwww.....cc...ww...cc....xxxxxxxxx");
+ strcpy(vgrid[28], "xxxxxxxxx....cc..www..cc....wwwwwwwwwccccccwwwwwwwww....cc..www..cc....xxxxxxxxx");
+ strcpy(vgrid[29], "xxxxxxxxx....cc..www.cc....wwwwwwwwccc2O12cccwwwwwwww....cc.www..cc....xxxxxxxxx");
+ strcpy(vgrid[30], "xxxxxxxxx....cc..www.cc...wwwwwwwwcc2+....+2ccwwwwwwww...cc.www..cc....xxxxxxxxx");
+ strcpy(vgrid[31], "xxxxxxxxx....cc..www.cc...wwwwwwwwcc+cc++cc+ccwwwwwwww...cc.www..cc....xxxxxxxxx");
+ strcpy(vgrid[32], "xxxxxxxxx....cc..www..c..wwwwwwwwwc|||c..c$$$cwwwwwwwww..c..www..cc....xxxxxxxxx");
+ strcpy(vgrid[33], "xxxxxxxxx....cc..wwww.c.wwwwwwwwwwc|||c..c$$$cwwwwwwwwww.c.wwww..cc....xxxxxxxxx");
+ strcpy(vgrid[34], "xxxxxxxxx....cc..wwww.c.wwwwwwwwwwcc||c..c$$ccwwwwwwwwww.c.wwww..cc....xxxxxxxxx");
+ strcpy(vgrid[35], "xxxxxxxxx....cc..wwww.c.wwwwwwwwwwwcccc++ccccwwwwwwwwwww.c.wwww..cc....xxxxxxxxx");
+ strcpy(vgrid[36], "xxxxxxxxx....cc..www..c..wwwwwwwwwwwwww..wwwwwwwwwwwwww..c..www..cc....xxxxxxxxx");
+ strcpy(vgrid[37], "xxxxxxxxx....cc..www.cc...wwwwwwwwwwwwwwwwwwwwwwwwwwww...cc.www..cc....xxxxxxxxx");
+ strcpy(vgrid[38], "xxxxxxxxx....cc..www.cc....wwwwwwwwwwwwwwwwwwwwwwwwwww...cc.www..cc....xxxxxxxxx");
+ strcpy(vgrid[39], "xxxxxxxxx....cc..www.cc....wwwwwwwwwwwwwwwwwwwwwwwwww....cc.www..cc....xxxxxxxxx");
+ strcpy(vgrid[40], "xxxxxxxxx....cc..www..cc....wwwwwwwwwwwwwwwwwwwwwwww....cc..www..cc....xxxxxxxxx");
+ strcpy(vgrid[41], "xxxxxxxxx....cc...ww...cc.....wwwwwwwwwwwwwwwwwwww.....cc...ww...cc....xxxxxxxxx");
+ strcpy(vgrid[42], "xxxxxxxxx....cc...ww....cc.......wwwwwwwwwwwwww.......cc....ww...cc....xxxxxxxxx");
+ strcpy(vgrid[43], "xxxxxxxxxx....cc...ww....cc..........wwwwww..........cc....ww...cc....xxxxxxxxxx");
+ strcpy(vgrid[44], "xxxxxxxxxxx....cc...ww....cc...T................T...cc....ww...cc....xxxxxxxxxxx");
+ strcpy(vgrid[45], "xxxxxxxxxxxx....cc...ww....cc......................cc....ww...cc....xxxxxxxxxxxx");
+ strcpy(vgrid[46], "xxxxxxxxxxxxx....cc...ww....ccccccccccc..ccccccccccc....ww...cc....xxxxxxxxxxxxx");
+ strcpy(vgrid[47], "xxxxxxxxxxxxxx....cc...ww....cccccccccc2.cccccccccc....ww...cc....xxxxxxxxxxxxxx");
+ strcpy(vgrid[48], "xxxxxxxxxxxxxxx....cc...ww............................ww...cc....xxxxxxxxxxxxxxx");
+ strcpy(vgrid[49], "xxxxxxxxxxxxxxxx....cc...ww..........................ww...cc....xxxxxxxxxxxxxxxx");
+ strcpy(vgrid[50], "xxxxxxxxxxxxxxxxx....cc...wwwwwwwwwwwww..wwwwwwwwwwwww...cc....xxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[51], "xxxxxxxxxxxxxxxxxx....cc...wwwwwwwwwwww..wwwwwwwwwwww...cc....xxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[52], "xxxxxxxxxxxxxxxxxxx....cc...wwwwwwwwwww..wwwwwwwwwww...cc....xxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[53], "xxxxxxxxxxxxxxxxxxxx....cc............................cc....xxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[54], "xxxxxxxxxxxxxxxxxxxxx....cc..........................cc....xxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[55], "xxxxxxxxxxxxxxxxxxxxxx....cccccccccccccccccccccccccccc....xxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[56], "xxxxxxxxxxxxxxxxxxxxxxx....cccccccccccccccccccccccccc....xxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[57], "xxxxxxxxxxxxxxxxxxxxxxxx................................xxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[58], "xxxxxxxxxxxxxxxxxxxxxxxxx..............................xxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[59], "xxxxxxxxxxxxxxxxxxxxxxxxxx............................xxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[60], "xxxxxxxxxxxxxxxxxxxxxxxxxxx..........{.(.[...........xxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[61], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[62], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[63], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[64], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[65], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[66], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[67], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[68], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[69], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ mons_array[0] = MONS_ANTAEUS;
+ mons_array[1] = MONS_ICE_FIEND;
+ mons_array[2] = MONS_ICE_DRAGON;
+ mons_array[3] = RANDOM_MONSTER;
+ mons_array[4] = RANDOM_MONSTER;
+ mons_array[5] = RANDOM_MONSTER;
+ mons_array[6] = RANDOM_MONSTER;
+
+ return MAP_ENCOMPASS;
+}
+
+
+static char ereshkigal(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // Tartarus
+ // note that the tomb on the right isn't supposed to have any doors
+
+ strcpy(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[6], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[7], "xxxxxxxxx..............................................................xxxxxxxxx");
+ strcpy(vgrid[8], "xxxxxxxxx..............................................................xxxxxxxxx");
+ strcpy(vgrid[9], "xxxxxxxxx.................cccc..........ccc............................xxxxxxxxx");
+ strcpy(vgrid[10], "xxxxxxxxx.............ccccc..cccc.....ccc.cccc.........................xxxxxxxxx");
+ strcpy(vgrid[11], "xxxxxxxxx...........ccc.........ccccccc.....cc.........................xxxxxxxxx");
+ strcpy(vgrid[12], "xxxxxxxxx.........ccc.......2............V..cc.........................xxxxxxxxx");
+ strcpy(vgrid[13], "xxxxxxxxx........cc4........................cc...........xxxxxxxx......xxxxxxxxx");
+ strcpy(vgrid[14], "xxxxxxxxx........cc44xxx==xxx...............cc..........xx......xx.....xxxxxxxxx");
+ strcpy(vgrid[15], "xxxxxxxxx........ccxxx......xxx.......ccc++ccc.........xx........xx....xxxxxxxxx");
+ strcpy(vgrid[16], "xxxxxxxxx........cxx..........xxx.....ccc44ccc.........x..........x....xxxxxxxxx");
+ strcpy(vgrid[17], "xxxxxxxxx........cx............xx....cccc44cc.........xx..........xx...xxxxxxxxx");
+ strcpy(vgrid[18], "xxxxxxxxx.......ccx.G........G.xxx7ccc..c44c..........x.....|......x...xxxxxxxxx");
+ strcpy(vgrid[19], "xxxxxxxxx.......cxx............xxxcc..................x......7.....x...xxxxxxxxx");
+ strcpy(vgrid[20], "xxxxxxxxx......ccx..............xxc...................xx..........xx...xxxxxxxxx");
+ strcpy(vgrid[21], "xxxxxxxxx......ccx..G........G..xxc..x.........x.......x..........x....xxxxxxxxx");
+ strcpy(vgrid[22], "xxxxxxxxx......ccx..............xcc....................xx........xx....xxxxxxxxx");
+ strcpy(vgrid[23], "xxxxxxxxx.......cxx............xxc......................xx......xx.....xxxxxxxxx");
+ strcpy(vgrid[24], "xxxxxxxxx.......ccx.F........F.xcc.......................xxxxxxxx......xxxxxxxxx");
+ strcpy(vgrid[25], "xxxxxxxxx........cx............xc......................................xxxxxxxxx");
+ strcpy(vgrid[26], "xxxxxxxxx........cxx....17....xxc....x.........x.......................xxxxxxxxx");
+ strcpy(vgrid[27], "xxxxxxxxx........ccxxx......xxxcc......................................xxxxxxxxx");
+ strcpy(vgrid[28], "xxxxxxxxx........cccc=xxxxxx=cccc......................................xxxxxxxxx");
+ strcpy(vgrid[29], "xxxxxxxxx........cc||cccccccc||cc......................................xxxxxxxxx");
+ strcpy(vgrid[30], "xxxxxxxxx.........cc||||O|||||cc.......................................xxxxxxxxx");
+ strcpy(vgrid[31], "xxxxxxxxx..........cccccccccccc......x.........x............V..........xxxxxxxxx");
+ strcpy(vgrid[32], "xxxxxxxxx..............................................................xxxxxxxxx");
+ strcpy(vgrid[33], "xxxxxxxxx...........................................xxxxxxxxxxxxxxxx...xxxxxxxxx");
+ strcpy(vgrid[34], "xxxxxxxxx...........................................xxxxxxxxxxxxxxxx...xxxxxxxxx");
+ strcpy(vgrid[35], "xxxxxxxxx...........................................xx$$$$xxx|||||xx...xxxxxxxxx");
+ strcpy(vgrid[36], "xxxxxxxxx.......V........V...........x.........x....xx$$$$xxx|||||xx...xxxxxxxxx");
+ strcpy(vgrid[37], "xxxxxxxxx...........................................xxxxxxxxxxxxxxxx...xxxxxxxxx");
+ strcpy(vgrid[38], "xxxxxxxxx...........................................xxxxxxxxxxxxxxxx...xxxxxxxxx");
+ strcpy(vgrid[39], "xxxxxxxxx...........................................xx44444xx22222xx...xxxxxxxxx");
+ strcpy(vgrid[40], "xxxxxxxxx.......xxxxxxxxx+xxxxxxxxx.................xx44444xx22222xx...xxxxxxxxx");
+ strcpy(vgrid[41], "xxxxxxxxx.......x3.2..........3...x..x.........x..xxxxxxxxxxxxxxxxxx...xxxxxxxxx");
+ strcpy(vgrid[42], "xxxxxxxxx.......x.x.x.x.x.x.x.x.x.x.................xxxxxxxxxxxxxxxx...xxxxxxxxx");
+ strcpy(vgrid[43], "xxxxxxxxx.......x...2.3..4..5..4..x......................=.......xxx...xxxxxxxxx");
+ strcpy(vgrid[44], "xxxxxxxxx.......xx.x.x.x.x.x.x.x.xx......................=.......xxx...xxxxxxxxx");
+ strcpy(vgrid[45], "xxxxxxxxx.......x..65..3..6.6...5.x.................xxxxxxxxxxxxxxxx...xxxxxxxxx");
+ strcpy(vgrid[46], "xxxxxxxxx.......x.x.x.x.x.x.x.x.x.x..x.........x..xxxxxxxxxxxxxxxxxx...xxxxxxxxx");
+ strcpy(vgrid[47], "xxxxxxxxx.......x...4...3.....4...x.................xx.....xx555555x...xxxxxxxxx");
+ strcpy(vgrid[48], "xxxxxxxxx.......xx=xxxxx.x.xxxxxxxx.................xx.....xx555555x...xxxxxxxxx");
+ strcpy(vgrid[49], "xxxxxxxxx.......x$$$$$$x.25.x$$$||x.................xxxxxxxxxxxxxxxx...xxxxxxxxx");
+ strcpy(vgrid[50], "xxxxxxxxx.......x$x$$x$xx.x.x$x$x|x.................xxxxxxxxxxxxxxxx...xxxxxxxxx");
+ strcpy(vgrid[51], "xxxxxxxxx.......x||||||x.556=$$$||x..x.........x....xx$$xx56565xx$|x...xxxxxxxxx");
+ strcpy(vgrid[52], "xxxxxxxxx.......xxxxxxxxxxxxxxxxxxx.................xx$$xx65656xx|7x...xxxxxxxxx");
+ strcpy(vgrid[53], "xxxxxxxxx...........................................xxxxxxxxxxxxxxxx...xxxxxxxxx");
+ strcpy(vgrid[54], "xxxxxxxxx...........................................xxxxxxxxxxxxxxxx...xxxxxxxxx");
+ strcpy(vgrid[55], "xxxxxxxxx..............................................................xxxxxxxxx");
+ strcpy(vgrid[56], "xxxxxxxxx..............................................................xxxxxxxxx");
+ strcpy(vgrid[57], "xxxxxxxxx........(...........................................[.........xxxxxxxxx");
+ strcpy(vgrid[58], "xxxxxxxxx..............................................................xxxxxxxxx");
+ strcpy(vgrid[59], "xxxxxxxxx..............................................................xxxxxxxxx");
+ strcpy(vgrid[60], "xxxxxxxxx..............................{...............................xxxxxxxxx");
+ strcpy(vgrid[61], "xxxxxxxxx..............................................................xxxxxxxxx");
+ strcpy(vgrid[62], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[63], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[64], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[65], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[66], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[67], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[68], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[69], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ mons_array[0] = MONS_ERESHKIGAL;
+ mons_array[1] = MONS_NECROPHAGE;
+ mons_array[2] = MONS_WRAITH;
+ mons_array[3] = MONS_SHADOW;
+ mons_array[4] = MONS_ZOMBIE_SMALL;
+ mons_array[5] = MONS_SKELETON_SMALL;
+ mons_array[6] = MONS_SHADOW_FIEND;
+
+ return MAP_ENCOMPASS;
+}
+
+
+static char mnoleg(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+
+ for (unsigned char i = 0; i < 81; i++)
+ strcpy(vgrid[i], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ strcat(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[6], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[7], "x.................2............xxxxxxxxx");
+ strcat(vgrid[8], "x.....2........................xxxxxxxxx");
+ strcat(vgrid[9], "x..cccccccc...ccccccc..ccccccc.xxxxxxxxx");
+ strcat(vgrid[10], "x..ccccccccc.2.ccccccc..cccccc.xxxxxxxxx");
+ strcat(vgrid[11], "x..cccccccccc...ccccccc..ccccc.xxxxxxxxx");
+ strcat(vgrid[12], "x..ccccccccccc.1.ccccccc..cccc.xxxxxxxxx");
+ strcat(vgrid[13], "x2.cccccccccc.2..Occccccc2.ccc.xxxxxxxxx");
+ strcat(vgrid[14], "x..ccccccccc.....ccccccccc..cc.xxxxxxxxx");
+ strcat(vgrid[15], "x..cccccccc...c...ccccccccc..c.xxxxxxxxx");
+ strcat(vgrid[16], "x..ccccccc...ccc...ccccccccc...xxxxxxxxx");
+ strcat(vgrid[17], "x..cccccc...ccccc...ccccccccc..xxxxxxxxx");
+ strcat(vgrid[18], "x..ccccc...ccccccc...ccccccccc.xxxxxxxxx");
+ strcat(vgrid[19], "x..cccc...ccccccccc...ccccccc..xxxxxxxxx");
+ strcat(vgrid[20], "x..ccc.2.ccccccccccc.2.ccccc...xxxxxxxxx");
+ strcat(vgrid[21], "x..cc.....ccccccccccc...ccc....xxxxxxxxx");
+ strcat(vgrid[22], "x..c...c...ccccccccccc...c.2...xxxxxxxxx");
+ strcat(vgrid[23], "x.....ccc.2.ccccccccccc......c.xxxxxxxxx");
+ strcat(vgrid[24], "x....ccccc...ccccccccccc....cc.xxxxxxxxx");
+ strcat(vgrid[25], "x.2.ccccccc...ccccccccccc..ccc.xxxxxxxxx");
+ strcat(vgrid[26], "x.................2.......cccc.xxxxxxxxx");
+ strcat(vgrid[27], "x...c..ccccccc.ccccccc...ccccc.xxxxxxxxx");
+ strcat(vgrid[28], "x..ccc......2c.c2cccc...cccccc.xxxxxxxxx");
+ strcat(vgrid[29], "x.ccccc..ccc.c.c2ccc.2.ccccccc.xxxxxxxxx");
+ strcat(vgrid[30], "x.cccccc..cc.c.c.cc...cccccccc.xxxxxxxxx");
+ strcat(vgrid[31], "x.ccccccc..c.c.c.c...ccccccccc.xxxxxxxxx");
+ strcat(vgrid[32], "x.cccccccc...c.c....cccccccccc.xxxxxxxxx");
+ strcat(vgrid[33], "x.ccccccccc..c.c...ccccccccccc.xxxxxxxxx");
+ strcat(vgrid[34], "x..............................xxxxxxxxx");
+ strcat(vgrid[35], "xxxxxxxxxxxxxx@xxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ mons_array[0] = MONS_MNOLEG;
+ mons_array[1] = MONS_NEQOXEC;
+ mons_array[2] = RANDOM_MONSTER;
+ mons_array[3] = RANDOM_MONSTER;
+ mons_array[4] = RANDOM_MONSTER;
+ mons_array[5] = RANDOM_MONSTER;
+ mons_array[6] = RANDOM_MONSTER;
+
+ return MAP_NORTHEAST;
+}
+
+
+static char lom_lobon(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+
+ strcpy(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[6], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[7], "xxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwww.......wwwwwwwxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[8], "xxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwbbbwwwwwww.......wwwwwwwxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[9], "xxxxxxxxxxxxxxxxxxwwwwwwwwwwwwbbbbbbbbbbbwwwwww.........wwwwwwxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[10], "xxxxxxxxxxxxxxxwwwwwwwwwwwwbbbbwwwwwwwwwbbbbwwwwww.........wwwwwwxxxxxxxxxxxxxxx");
+ strcpy(vgrid[11], "xxxxxxxxxxxxxwwwwwwwbbbbbbbbwwwwwwwwwwwwwwwbbbwwwww...........wwwwwxxxxxxxxxxxxx");
+ strcpy(vgrid[12], "xxxxxxxxxxxxwwwwwbbbb......bbbwwwwwwwwwwww...bbwwwww.............wwwxxxxxxxxxxxx");
+ strcpy(vgrid[13], "xxxxxxxxxxxxwwwbbb...........bbbwwwwww........bbwwwww.............wwxxxxxxxxxxxx");
+ strcpy(vgrid[14], "xxxxxxxxxxxwwwbb...............bbwwww..........bwwwwww.............wwxxxxxxxxxxx");
+ strcpy(vgrid[15], "xxxxxxxxxxxwwbb........1O.......bbww...........bbwwww..............wwxxxxxxxxxxx");
+ strcpy(vgrid[16], "xxxxxxxxxxwwwb...................bw......2......bwww.....U....2.....wwxxxxxxxxxx");
+ strcpy(vgrid[17], "xxxxxxxxxxwwbb...................bb.............bww.................wwxxxxxxxxxx");
+ strcpy(vgrid[18], "xxxxxxxxxxwwbb..3................bbb............bbw..............4..wwxxxxxxxxxx");
+ strcpy(vgrid[19], "xxxxxxxxxwwbbb...................b.b............4....................wwxxxxxxxxx");
+ strcpy(vgrid[20], "xxxxxxxxxwwbwbb.................bb.......U......4..........U..........wxxxxxxxxx");
+ strcpy(vgrid[21], "xxxxxxxxxwwbwwbb...............bb..b............bbw..............4.....xxxxxxxxx");
+ strcpy(vgrid[22], "xxxxxxxxxwwbbwwbbb...........bbb..bb............bwww...................xxxxxxxxx");
+ strcpy(vgrid[23], "xxxxxxxxxwwwbwwwwb..b..2..bbbb....b.............bwww...................xxxxxxxxx");
+ strcpy(vgrid[24], "xxxxxxxxxxwwbwwww...bbbbbbb.......bw.....3.....bbwwww...U.....3.......xxxxxxxxxx");
+ strcpy(vgrid[25], "xxxxxxxxxxwwbbww.................bbww........wwbwwwww.................xxxxxxxxxx");
+ strcpy(vgrid[26], "xxxxxxxxxxwwwbbw................bbwwwww....wwwbbwwww..................xxxxxxxxxx");
+ strcpy(vgrid[27], "xxxxxxxxxxwwwwbb...4...U........bwwwwwwwwwwwwbbwww....................xxxxxxxxxx");
+ strcpy(vgrid[28], "xxxxxxxxxxxwwwwbbb...........bbbbbwwwwwwwwwbbbwww....................xxxxxxxxxxx");
+ strcpy(vgrid[29], "xxxxxxxxxxxwwwwwwbbbb.....bbbbwwwbbbbwwwbbbbwwww....................xxxxxxxxxxxx");
+ strcpy(vgrid[30], "xxxxxxxxxxxwwwwwwwwwbbbbbbbwwwwwwwwwbbbbbwwwww......4.....4........xxxxxxxxxxxxx");
+ strcpy(vgrid[31], "xxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww......................xxxxxxxxxxxxxx");
+ strcpy(vgrid[32], "xxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwww.......................xxxxxxxxxxxxxxxx");
+ strcpy(vgrid[33], "xxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwww........................xxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[34], "xxxxxxxxxxxxxxxxxxxxxxxxxwwwwwww......................xxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[35], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...@.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ mons_array[0] = MONS_LOM_LOBON;
+ mons_array[1] = MONS_GIANT_ORANGE_BRAIN;
+ mons_array[2] = MONS_RAKSHASA;
+ mons_array[3] = MONS_WIZARD;
+ mons_array[4] = RANDOM_MONSTER;
+ mons_array[5] = RANDOM_MONSTER;
+ mons_array[6] = RANDOM_MONSTER;
+
+ return MAP_NORTH;
+}
+
+
+static char cerebov(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // you might not want to teleport too much on this level -
+ // unless you can reliably teleport away again.
+
+ for (unsigned char i = 0; i < 81; i++)
+ strcpy(vgrid[i], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ strcat(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[6], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[7], "...............................xxxxxxxxx");
+ strcat(vgrid[8], ".............vvvvv.............xxxxxxxxx");
+ strcat(vgrid[9], ".............v$$$v.............xxxxxxxxx");
+ strcat(vgrid[10], ".............v|||v.............xxxxxxxxx");
+ strcat(vgrid[11], ".............v$$$v.............xxxxxxxxx");
+ strcat(vgrid[12], ".vvvvv...vvvvvvvvvvvvv...vvvvv.xxxxxxxxx");
+ strcat(vgrid[13], ".v|$|vvvvv...........vvvvv$|$v.xxxxxxxxx");
+ strcat(vgrid[14], ".v$|$v.....vvvvvvvvv.....v|$|v.xxxxxxxxx");
+ strcat(vgrid[15], ".v|$|v.vvvvvvvvOvvvvvvvv.v$|$v.xxxxxxxxx");
+ strcat(vgrid[16], ".vvvvv.vvvvvv..3..vvvvvv.vvvvv.xxxxxxxxx");
+ strcat(vgrid[17], "...v...vv.....vvv.....vv...v...xxxxxxxxx");
+ strcat(vgrid[18], "...v.vvvv....vv1vv....vvvv.v...xxxxxxxxx");
+ strcat(vgrid[19], "...v.vv......v...v......vv.v...xxxxxxxxx");
+ strcat(vgrid[20], "...v.vvvv.............vvvv.v...xxxxxxxxx");
+ strcat(vgrid[21], "...v...vv..2.......2..vv...v...xxxxxxxxx");
+ strcat(vgrid[22], ".vvvvv.vv..2.......2..vv.vvvvv.xxxxxxxxx");
+ strcat(vgrid[23], ".v|$|v.vv.............vv.v$|$v.xxxxxxxxx");
+ strcat(vgrid[24], ".v|$|v.vv...vv...vv...vv.v$|$v.xxxxxxxxx");
+ strcat(vgrid[25], ".v|$|v.vv...vv+++vv...vv.v$|$v.xxxxxxxxx");
+ strcat(vgrid[26], ".vvvvv.vvvvvvv...vvvvvvv.vvvvv.xxxxxxxxx");
+ strcat(vgrid[27], "....v..vvvvvvv...vvvvvvv..v....xxxxxxxxx");
+ strcat(vgrid[28], "....vv...................vv....xxxxxxxxx");
+ strcat(vgrid[29], ".....vv.vvvvv..2..vvvvv.vv.....xxxxxxxxx");
+ strcat(vgrid[30], "......vvv|||v.....v$$$vvv......xxxxxxxxx");
+ strcat(vgrid[31], "........v|$|vv...vv$|$v........xxxxxxxxx");
+ strcat(vgrid[32], "........v|||v.....v$$$v........xxxxxxxxx");
+ strcat(vgrid[33], "........vvvvv.....vvvvv........xxxxxxxxx");
+ strcat(vgrid[34], "...............................xxxxxxxxx");
+ strcat(vgrid[35], "...............@...............xxxxxxxxx");
+
+ mons_array[0] = MONS_CEREBOV;
+ mons_array[1] = MONS_BALRUG;
+ mons_array[2] = MONS_PIT_FIEND;
+ mons_array[3] = RANDOM_MONSTER;
+ mons_array[4] = RANDOM_MONSTER;
+ mons_array[5] = RANDOM_MONSTER;
+ mons_array[6] = RANDOM_MONSTER;
+
+ return MAP_NORTHEAST;
+}
+
+
+static char gloorx_vloq(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+
+ for (unsigned char i = 0; i < 81; i++)
+ strcpy(vgrid[i], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ strcpy(vgrid[36], "xxxxxxxxxxxxxxxxxxxxxxx@.xxxxxxxxxxxxxxx");
+ strcpy(vgrid[37], "xxxxxxxxx..............................x");
+ strcpy(vgrid[38], "xxxxxxxxx..............................x");
+ strcpy(vgrid[39], "xxxxxxxxx..............................x");
+ strcpy(vgrid[40], "xxxxxxxxx.x.x.x.x.x.x.x..x.x.x.x.x.x.x.x");
+ strcpy(vgrid[41], "xxxxxxxxx..............................x");
+ strcpy(vgrid[42], "xxxxxxxxx.x.xxxx=xxxxxxxxxxxx=xxxxxx.x.x");
+ strcpy(vgrid[43], "xxxxxxxxx...xx....................xx...x");
+ strcpy(vgrid[44], "xxxxxxxxx.x.x..ccccc..4..4..ccccc..x.x.x");
+ strcpy(vgrid[45], "xxxxxxxxx...x.cc.3............3.cc.x...x");
+ strcpy(vgrid[46], "xxxxxxxxx.x.x.c..ccccc.cc.ccccc..c.x.x.x");
+ strcpy(vgrid[47], "xxxxxxxxx...x.c.cc.....cc.....cc.c.x...x");
+ strcpy(vgrid[48], "xxxxxxxxx.x.x.c.c.2...cccc...2.c.c.x.x.x");
+ strcpy(vgrid[49], "xxxxxxxxx...x...c...ccc..ccc...c...=...x");
+ strcpy(vgrid[50], "xxxxxxxxx.x.x.3.....2..1O..2.....3.x.x.x");
+ strcpy(vgrid[51], "xxxxxxxxx...=...c...ccc..ccc...c...x...x");
+ strcpy(vgrid[52], "xxxxxxxxx.x.x.c.c.2...cccc...2.c.c.x.x.x");
+ strcpy(vgrid[53], "xxxxxxxxx...x.c.cc.....cc.....cc.c.x...x");
+ strcpy(vgrid[54], "xxxxxxxxx.x.x.c..ccccc.cc.ccccc..c.x.x.x");
+ strcpy(vgrid[55], "xxxxxxxxx...x.cc.3............3.cc.x...x");
+ strcpy(vgrid[56], "xxxxxxxxx.x.x..ccccc..4..4..ccccc..=.x.x");
+ strcpy(vgrid[57], "xxxxxxxxx...xx....................xx...x");
+ strcpy(vgrid[58], "xxxxxxxxx.x.xxxx=xxxx=xxxxxxxx=xxxxx.x.x");
+ strcpy(vgrid[59], "xxxxxxxxx..............................x");
+ strcpy(vgrid[60], "xxxxxxxxx.x.x.x.x.x.x.x..x.x.x.x.x.x.x.x");
+ strcpy(vgrid[61], "xxxxxxxxx..............................x");
+ strcpy(vgrid[62], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[63], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[64], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[65], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[66], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[67], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[68], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[69], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ mons_array[0] = MONS_GLOORX_VLOQ;
+ mons_array[1] = MONS_EXECUTIONER;
+ mons_array[2] = MONS_DEMONIC_CRAWLER;
+ mons_array[3] = MONS_SHADOW_DEMON;
+ mons_array[4] = RANDOM_MONSTER;
+ mons_array[5] = RANDOM_MONSTER;
+ mons_array[6] = RANDOM_MONSTER;
+
+ return MAP_SOUTHWEST;
+}
+
+
+static char beehive(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+
+ strcpy(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[6], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[7], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[8], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[9], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxaaaaaaaaaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[10], "xxxxxxxxxxxxxxxxxxxxxxaaaaaaaaaaaRaaaaaaaaaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[11], "xxxxxxxxxxxxxxxxxaaaaaaaaaaRa2aaR1RaaRa2aaaaaaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[12], "xxxxxxxxxxxxxxxxxxaaaaaaaaaaRa2a3R3aRaRaRaaaaaaaaaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[13], "xxxxxxxxxxxxxxxxxxxxxaaaaRaRaRaaa3aaa3aRa.a.aaaaaaaaaaaxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[14], "xxxxxxxxxxxxxxxxaaaaaaRa.aRa2a2a2a2aRaRa.a.a3aaaaaaaaaaaaaaxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[15], "xxxxxxxxxxxxx4aaaaaaaaa.aaRaRaa2aa2aaRaaa.aa3a33aaaaaaaaaa.44xxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[16], "xxxxxxxxxxx.4aaaaaaa.222a3a.aaaRaaa.aaa.R3aa3a3aaaaaaaa.....4xxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[17], "xxxxxxxxxx....aaaaaaa.aRa.a3aRaRa.a3a.a.a.a.aRa2aaaaaa....xxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[18], "xxxxxxxxxxx...aaaaaa3a3a.a.a.a3aRa2aRa3a.a.aRaRa.aaaaa...xxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[19], "xxxxxxxxxxxx...aa2aRa3a3a3aRa.a3a.a.a.a.a.a.a.a3a.aaa...xxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[20], "xxxxxxxxxxxx...aaa.a.a.a2a.aaa.aRaRa2a.a2a3a.a2aaaa..T..xxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[21], "xxxxxxxxxxx.....a2a.a2a.aRaaaaa3a.a.aaa3a3a3a3a.a.........xxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[22], "xxxxxxxxxxx.4...aaRRaa.a2a.a3a3a3a.aaa.a.aRa.a.aa..4.......xxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[23], "xxxxxxxxxx......a.a.aaa.a3a.a.a.a.aaa2a.a2a.a.aRaa.....4...xxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[24], "xxxxxxxxxx.....aa3a2aaa.a.a.a3a3a3a3aRaaa.a2a.a2aa........xxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[25], "xxxxxxxxxxx...aaaa.a2aRa.a.a2aaa.a.a.a.aaa.a.aaaa.....xxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[26], "xxxxxxxxxxxx..aaa.a.a.a.a.a.a.aaa2a.a3a2a.a2aaa.....xxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[27], "xxxxxxxxxxxxxx.aaaa3a.a2aRa.a.aaaRa.a.aa.a.aaa....xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[28], "xxxxxxxxxxxxxxx...aaaaRa.a3a3a.a.a.aaa.aa.aa....4xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[29], "xxxxxxxxxxxxx........aa.a2a.a.aaa2aa.aa.aaa....xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[30], "xxxxxxxxxxxxx....4.....a.a2a2a.a2a.a2a.......4.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[31], "xxxxxxxxxxx.............a.a.a.a.a.a.....4....xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[32], "xxxxxxxxxx..............4..a.a.a......4...xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[33], "xxxxxxxxxx.................a.a.........xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[34], "xxxxxxxxxxx........................xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[35], "xxxxxxxxxxx.....4...T............xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[36], "xxxxxxxxxxx.......................xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[37], "xxxxxxxxxxxx.........................xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[38], "xxxxxxxxxxxx.................T.........xxxxxxxx..xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[39], "xxxxxxxxxxxx.......4.....................xxxxxxx...xxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[40], "xxxxxxxxxxx..............xx...............xxxxxx....xxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[41], "xxxxxxxxxxx............xxxxx........4......xxxx..4....xxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[42], "xxxxxxxxxxx..T..........xxx................xxxxx...T.xxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[43], "xxxxxxxxxxx............xxx........T.........xxx........xxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[44], "xxxxxxxxxxx....4........xx....................x..........xxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[45], "xxxxxxxxxx...............x.x...xxx...............xx.xxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[46], "xxxxxxxxxx.........4...........xxx..................xxxxxxxxxxxxxxxxxxaaaaaxxxxx");
+ strcpy(vgrid[47], "xxxxxxxxx.....4.....................4......4...........4...xxxxxxxxxxaa5a5aaxxxx");
+ strcpy(vgrid[48], "xxxxxxxxx.................................................wwwwwwwwxxxa5*|*5axxxx");
+ strcpy(vgrid[49], "xxxxxxxxx............x...x...T.....xxxx.................wwwwwwwwwwwwxaa*|*aaxxxx");
+ strcpy(vgrid[50], "xxxxxxxxxx.........xx.............xxxxx................wwwwwwwwwwwwwwxaa5aaxxxxx");
+ strcpy(vgrid[51], "xxxxxxxxxxx.......x..................xxx....4..........wwwwwwwwwwwwwwwxa5axxxxxx");
+ strcpy(vgrid[52], "xxxxxxxxxxx.....xxx...4...........................xxxx.4wwwwwwwwwwwwwwwa=axxxxxx");
+ strcpy(vgrid[53], "xxxxxxxxxxxx..xxx.............xx....(.........xxxxxxxx....wwwwwwwwwwwwwwaaxxxxxx");
+ strcpy(vgrid[54], "xxxxxxxxxxxxxxxx.............xxxx..................xxxx......wwwwwwwwwwxxxxxxxxx");
+ strcpy(vgrid[55], "xxxxxxxxxxxxxxxxx....{..}..xxxxxx..]......xxx...........4.wwwwwwwwwwwwxxxxxxxxxx");
+ strcpy(vgrid[56], "xxxxxxxxxxxxxxxxxxxx........xxx........xxxxxx....4....wwwwwwwwwwwwwwxxxxxxxxxxxx");
+ strcpy(vgrid[57], "xxxxxxxxxxxxxxxxxxxxxxxxx..[.xxx........xxx)....wwwwwwwwwwwwwwwwwwxxxxxxxxxxxxxx");
+ strcpy(vgrid[58], "xxxxxxxxxxxxxxxxxxxxxxxxxxxx.........xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[59], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[60], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[61], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[62], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[63], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[64], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[65], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[66], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[67], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[68], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[69], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ mons_array[0] = MONS_QUEEN_BEE;
+ mons_array[1] = MONS_KILLER_BEE;
+ mons_array[2] = MONS_KILLER_BEE_LARVA;
+ mons_array[3] = MONS_PLANT;
+ mons_array[4] = MONS_YELLOW_WASP;
+ mons_array[5] = RANDOM_MONSTER;
+ mons_array[6] = RANDOM_MONSTER;
+
+ return MAP_ENCOMPASS;
+}
+
+
+static char vaults_vault(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // last level of the vaults -- dungeon.cc will change all these 'x's
+
+ strcpy(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[6], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[7], "xxxxxxxxx..............................................................xxxxxxxxx");
+ strcpy(vgrid[8], "xxxxxxxxx..............................................................xxxxxxxxx");
+ strcpy(vgrid[9], "xxxxxxxxx..xxxxxxxxxxxxxxxxxxxxxxxxxxx....xxxxxxxxxxxxxxxxxxxxxxxxxxx..xxxxxxxxx");
+ strcpy(vgrid[10], "xxxxxxxxx..x.........................x....xxxxxxxxxxxxxxxxxxxxxxxxxxx..xxxxxxxxx");
+ strcpy(vgrid[11], "xxxxxxxxx..x.xxxxxxxxxxx..xxxxxxxxxx.x....xxxxx.................xxxxx..xxxxxxxxx");
+ strcpy(vgrid[12], "xxxxxxxxx..x.x*.*.*.*.*x..x........x.x....xxx..........8..........xxx..xxxxxxxxx");
+ strcpy(vgrid[13], "xxxxxxxxx..x.x.*.*.*.*.x..x........x.x....xxx.....................xxx..xxxxxxxxx");
+ strcpy(vgrid[14], "xxxxxxxxx..x.x*.*.*.*.*x..x...||...x.x....xx......9........9.......xx..xxxxxxxxx");
+ strcpy(vgrid[15], "xxxxxxxxx..x.x.*.*.*.*.x..x...||...x.x....xx.......................xx..xxxxxxxxx");
+ strcpy(vgrid[16], "xxxxxxxxx..x.x*.*.*.*.*x..x...||...x.x....xx......xxxxxxxxxxx......xx..xxxxxxxxx");
+ strcpy(vgrid[17], "xxxxxxxxx..x.x.*.*.*.*.x..x........x.x....xx......x.........x......xx..xxxxxxxxx");
+ strcpy(vgrid[18], "xxxxxxxxx..x.x*.*.*.*.*+..+........x.x....xx....xxx..........xx....xx..xxxxxxxxx");
+ strcpy(vgrid[19], "xxxxxxxxx..x.x.*.*.*.*.xxxxxxxxxxxxx.x....xx.9..x....xxxxx....x..8.xx..xxxxxxxxx");
+ strcpy(vgrid[20], "xxxxxxxxx..x.xxxxxxxxxxx9998.........x....xx....x...xx$$$xx...x....xx..xxxxxxxxx");
+ strcpy(vgrid[21], "xxxxxxxxx..x...........899xxxxxxxxxx.x....xx....x..xx$***$xx..x....xx..xxxxxxxxx");
+ strcpy(vgrid[22], "xxxxxxxxx..x.xxxxxxxxxxx99x........x.x....xx....x..x$$*|*$$x..x....xx..xxxxxxxxx");
+ strcpy(vgrid[23], "xxxxxxxxx..x.x.....|...x88x.$$$$$$.x.x....xx..8.x..xx$***$xx..x....xx..xxxxxxxxx");
+ strcpy(vgrid[24], "xxxxxxxxx..x.x.|..|..|.x..x.$$$$$$.x.x....xx....x....x$$$xx...x..9.xx..xxxxxxxxx");
+ strcpy(vgrid[25], "xxxxxxxxx..x.x.........x..x.$$$$$$.x.x....xx....xxx..xxxxx..xxx....xx..xxxxxxxxx");
+ strcpy(vgrid[26], "xxxxxxxxx..x.x.|..|..|.x..x.$$$$$$.x.x....xx......x.........x......xx..xxxxxxxxx");
+ strcpy(vgrid[27], "xxxxxxxxx..x.x.........x..x.$$$$$$.x.x....xx......xxxxxxxxxxx......xx..xxxxxxxxx");
+ strcpy(vgrid[28], "xxxxxxxxx..x.x|..|..|..x..x.$$$$$$.x.x....xxx.....................xxx..xxxxxxxxx");
+ strcpy(vgrid[29], "xxxxxxxxx..x.x.........x..+........x.x....xxx......9.........9....xxx..xxxxxxxxx");
+ strcpy(vgrid[30], "xxxxxxxxx..x.xxxxxxxxx+x..xxxxxxxxxx.xx.11....xx................xxxxx..xxxxxxxxx");
+ strcpy(vgrid[31], "xxxxxxxxx..x...........x..x...........x1111...xxxxxxxxxxxxxxxxxxxxxxx..xxxxxxxxx");
+ strcpy(vgrid[32], "xxxxxxxxx..xxxxxxxxxxxxxxxxxxxxxxxxx..1....1..xxxxxxxxxxxxxxxxxxxxxxx..xxxxxxxxx");
+ strcpy(vgrid[33], "xxxxxxxxx..........................xx1..(}..1..........................xxxxxxxxx");
+ strcpy(vgrid[34], "xxxxxxxxx...........................11.[..{.11.........................xxxxxxxxx");
+ strcpy(vgrid[35], "xxxxxxxxx............................1..])..1..........................xxxxxxxxx");
+ strcpy(vgrid[36], "xxxxxxxxx.............................1....1...........................xxxxxxxxx");
+ strcpy(vgrid[37], "xxxxxxxxx..xxxxxxxxxxxxxxxxxxxxxxx.....1111..x.xxx.xxxxxxxxxxxxxxxxxx..xxxxxxxxx");
+ strcpy(vgrid[38], "xxxxxxxxx..xx.x.x.x.x.x.x.x.x.x.x.x.....11..........................x..xxxxxxxxx");
+ strcpy(vgrid[39], "xxxxxxxxx..x.x.x.x.x.x.x.x|x.x.x.x.x................................x..xxxxxxxxx");
+ strcpy(vgrid[40], "xxxxxxxxx..xx.x|x.x.x.x.x.x.x.x.x.x.x.....x.........................x..xxxxxxxxx");
+ strcpy(vgrid[41], "xxxxxxxxx..x.x.x.x.x.x.x.x9x.x.x.x.x.x..........8..........9........x..xxxxxxxxx");
+ strcpy(vgrid[42], "xxxxxxxxx..xx.x.x.x.x.x.x.x.x.x.x.x.xx....x..9......................x..xxxxxxxxx");
+ strcpy(vgrid[43], "xxxxxxxxx..x.x.x.x.x.x.x.x.x.x|x.x.x.x....x.........................x..xxxxxxxxx");
+ strcpy(vgrid[44], "xxxxxxxxx..xx.x8x.x.x|x.x.x.x.x.x.x.xx....x..............9...9......x..xxxxxxxxx");
+ strcpy(vgrid[45], "xxxxxxxxx..x.x.x.x.x9x.x.x.x.x.x.x.x.x...........8..................x..xxxxxxxxx");
+ strcpy(vgrid[46], "xxxxxxxxx..xx.x.x.x.x.x.x.x.x.x.x.x.xx....x..9......................x..xxxxxxxxx");
+ strcpy(vgrid[47], "xxxxxxxxx..x.x.x.x.x.x.x.x.x|x.x9x.x.x....x.........................x..xxxxxxxxx");
+ strcpy(vgrid[48], "xxxxxxxxx..xx.x.x.x.x.x.x.x.x.x.x.x.xx....x...................9.....x..xxxxxxxxx");
+ strcpy(vgrid[49], "xxxxxxxxx..x.x.x9x.x.x.x.x.x.x.x.x.x.x....x....9......8.............x..xxxxxxxxx");
+ strcpy(vgrid[50], "xxxxxxxxx..xx.x.x.x.x.x.x9x.x.x.x.x.xx....x.........................x..xxxxxxxxx");
+ strcpy(vgrid[51], "xxxxxxxxx..x.x.x.x.x.x.x.x.x.x.x.x.x.x....x.........................x..xxxxxxxxx");
+ strcpy(vgrid[52], "xxxxxxxxx..xx.x.x.x.x.x.x.x.x.x.x.x.xx....x.......9......9..........x..xxxxxxxxx");
+ strcpy(vgrid[53], "xxxxxxxxx..x.x.x.x.x.x.x.x.x.x8x.x.x.x....x.....................8...x..xxxxxxxxx");
+ strcpy(vgrid[54], "xxxxxxxxx..xx.x8x.x.x.x.x.x.x.x.x.x.xx....x.....................||.|x..xxxxxxxxx");
+ strcpy(vgrid[55], "xxxxxxxxx..x.x|x.x.x.x.x.x.x|x.x.x.x.x....x.....................|...x..xxxxxxxxx");
+ strcpy(vgrid[56], "xxxxxxxxx..xx.x.x.x.x.x.x8x.x.x.x.x.xx....x......8..................x..xxxxxxxxx");
+ strcpy(vgrid[57], "xxxxxxxxx..x.x.x.x.x.x.x.x.x.x.x.x.x.x....x..........8..8...8.....||x..xxxxxxxxx");
+ strcpy(vgrid[58], "xxxxxxxxx..xO.x.x.x.x.x.x.x.x.x.x|x.xx....x.....................|.||x..xxxxxxxxx");
+ strcpy(vgrid[59], "xxxxxxxxx..xxxxxxxxxxxxxxxxxxxxxxxxxxx....xxxxxxxxxxxxxxxxxxxxxxxxxxx..xxxxxxxxx");
+ strcpy(vgrid[60], "xxxxxxxxx..............................................................xxxxxxxxx");
+ strcpy(vgrid[61], "xxxxxxxxx..............................................................xxxxxxxxx");
+ strcpy(vgrid[62], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[63], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[64], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[65], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[66], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[67], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[68], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[69], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ mons_array[0] = MONS_VAULT_GUARD;
+ mons_array[1] = RANDOM_MONSTER;
+ mons_array[2] = RANDOM_MONSTER;
+ mons_array[3] = RANDOM_MONSTER;
+ mons_array[4] = RANDOM_MONSTER;
+ mons_array[5] = RANDOM_MONSTER;
+ mons_array[6] = RANDOM_MONSTER;
+
+ return MAP_ENCOMPASS;
+}
+
+
+static char snake_pit(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // Hey, this looks a bit like a face ...
+
+ for (unsigned char i = 0; i < 81; i++)
+ strcpy(vgrid[i], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ strcpy(vgrid[36], "xxxxxxxxxxxxxxxxxxxxxxx..@.xxxxxxxxxxxxx");
+ strcpy(vgrid[37], "xxxxxxxxxxxxxxxxxxx.............xxxxxxxx");
+ strcpy(vgrid[38], "xxxxxxxxxxxxxx....x.............x..xxxxx");
+ strcpy(vgrid[39], "xxxxxxxxxxxx....2.x.............x.2..xxx");
+ strcpy(vgrid[40], "xxxxxxxxxxx.....2.x....x.....x..x..3.xxx");
+ strcpy(vgrid[41], "xxxxxxxxxxx.....22x.............xx.2..xx");
+ strcpy(vgrid[42], "xxxxxxxxxxx.......xx..x........xx..3..xx");
+ strcpy(vgrid[43], "xxxxxxxxxx.....x23.xx....T...xxx.44...xx");
+ strcpy(vgrid[44], "xxxxxxxxxx......4.4.x.........x.333....x");
+ strcpy(vgrid[45], "xxxxxxxxxx......3.x4...x.......4x4.....x");
+ strcpy(vgrid[46], "xxxxxxxxxx.......3.......x.............x");
+ strcpy(vgrid[47], "xxxxxxxxxx..c......3.........x.......c.x");
+ strcpy(vgrid[48], "xxxxxxxxx...cc...................3..cc.x");
+ strcpy(vgrid[49], "xxxxxxxxx...cc..........4.4.........cc.x");
+ strcpy(vgrid[50], "xxxxxxxxx...cc...3...x........2.....cc.x");
+ strcpy(vgrid[51], "xxxxxxxxx...cc.........1...1.......cc..x");
+ strcpy(vgrid[52], "xxxxxxxxxx..cc.....1.....1.....1..ccc.xx");
+ strcpy(vgrid[53], "xxxxxxxxxx...ccc..................cc..xx");
+ strcpy(vgrid[54], "xxxxxxxxxx....cccc....3333333.....cc..xx");
+ strcpy(vgrid[55], "xxxxxxxxxx.....ccccccc...........cc...xx");
+ strcpy(vgrid[56], "xxxxxxxxxx........cccccccO...ccccc....xx");
+ strcpy(vgrid[57], "xxxxxxxxxxx........cccccccccccccc....xxx");
+ strcpy(vgrid[58], "xxxxxxxxxxx.........cccccccccccc.....xxx");
+ strcpy(vgrid[59], "xxxxxxxxxxxxx.......................xxxx");
+ strcpy(vgrid[60], "xxxxxxxxxxxxxxxx..................xxxxxx");
+ strcpy(vgrid[61], "xxxxxxxxxxxxxxxxxxxxx.......xxxxxxxxxxxx");
+ strcpy(vgrid[62], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[63], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[64], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[65], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[66], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[67], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[68], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[69], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ mons_array[0] = MONS_GREATER_NAGA;
+ mons_array[1] = MONS_NAGA;
+ mons_array[2] = MONS_NAGA_MAGE;
+ mons_array[3] = MONS_NAGA_WARRIOR;
+ mons_array[4] = RANDOM_MONSTER;
+ mons_array[5] = RANDOM_MONSTER;
+ mons_array[6] = RANDOM_MONSTER;
+
+ return MAP_SOUTHWEST;
+}
+
+
+static char elf_hall(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+
+ strcpy(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[6], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[7], "xxxxxxxxxxxxxxxxxxcccccccccccccccccxxxxx");
+ strcpy(vgrid[8], "xxxxxxxxxxxxxxxxxcc*|*|*|**|||||c$ccxxxx");
+ strcpy(vgrid[9], "xxxxxxxxxxxxxxxxcc*$*|*|*|*|||||c$$ccxxx");
+ strcpy(vgrid[10], "xxxxxxxxxxxxxxxcc*$|*$***$$|||||c|$$ccxx");
+ strcpy(vgrid[11], "xxxxxxxxxxxxxxcc*$*|**ccccccccccc$$$$ccx");
+ strcpy(vgrid[12], "xxxxxxxxxxxxxxc*|*$*$ccc.....2..c+$|$$cx");
+ strcpy(vgrid[13], "xxxxxxxxxxxxxxc$*$*ccc...........c$$$$cx");
+ strcpy(vgrid[14], "xxxxxxxxxxxxxxc||**cc...5.......4cc$|$cx");
+ strcpy(vgrid[15], "xxxxxxxxxxxxxxc*$$cc........3..ccccccccx");
+ strcpy(vgrid[16], "xxxxxxxxxxxxxxc$+ccc.....2....cc.....5cx");
+ strcpy(vgrid[17], "xxxxxxxxxxxxxxc$c....5.......cc.......cx");
+ strcpy(vgrid[18], "xxxxxxxxxxxxxxccc......5....cc..2....ccx");
+ strcpy(vgrid[19], "xxxxxxxxxxxxxxxxc..........cc.......ccxx");
+ strcpy(vgrid[20], "xxxxxxxxxxxxxxxcc..1..U..........4..ccxx");
+ strcpy(vgrid[21], "xxxxxxxxxxxxxxcc.....................ccx");
+ strcpy(vgrid[22], "xxxxxxxxxxxxxxc...........3...........cx");
+ strcpy(vgrid[23], "xxxxxxxxxxxxxxc.......2.......3.......cx");
+ strcpy(vgrid[24], "xxxxxxxxxxxxxxc..2................2..5cx");
+ strcpy(vgrid[25], "xxxxxxxxxxxxxxc......x.........x......cx");
+ strcpy(vgrid[26], "xxxxxxxxxxxxxxc.....xx.........xx.....cx");
+ strcpy(vgrid[27], "xxxxxxxxxxxxxxc2...xxx....1....xxx.4..cx");
+ strcpy(vgrid[28], "xxxxxxxxxxxxxxc..xxxx...........xxxx..cx");
+ strcpy(vgrid[29], "xxxxxxxxxxxxxxc.xxx.....cc.cc.....xxx.cx");
+ strcpy(vgrid[30], "xxxxxxxxxxxxxxc.x.....cccc.cccc.....x.cx");
+ strcpy(vgrid[31], "xxxxxxxxxxxxxxc.3...cccxxc.cxxccc.3...cx");
+ strcpy(vgrid[32], "xxxxxxxxxxxxxxc...cccxxxxc.cxxxxccc...cx");
+ strcpy(vgrid[33], "xxxxxxxxxxxxxxc.cccxxxxxxc.cxxxxxxccc.cx");
+ strcpy(vgrid[34], "xxxxxxxxxxxxxxcccxxxxxxxxc.cxxxxxxxxcccx");
+ strcpy(vgrid[35], "xxxxxxxxxxxxxxxxxxxxxxxxxx@xxxxxxxxxxxxx");
+
+ mons_array[0] = MONS_DEEP_ELF_HIGH_PRIEST;
+ mons_array[1] = MONS_DEEP_ELF_DEMONOLOGIST;
+ mons_array[2] = MONS_DEEP_ELF_ANNIHILATOR;
+ mons_array[3] = MONS_DEEP_ELF_SORCERER;
+ mons_array[4] = MONS_DEEP_ELF_DEATH_MAGE;
+ mons_array[5] = RANDOM_MONSTER;
+ mons_array[6] = RANDOM_MONSTER;
+
+ return MAP_NORTHWEST;
+}
+
+
+// Slime pit take is reduced pending an increase in difficulty
+// of this subdungeon. -- bwr
+static char slime_pit(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+
+ strcpy(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[6], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[7], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx....xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[8], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx..xxxx.........xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[9], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx....................xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[10], "xxxxxxxxxxxxxxxxxxxxxxxxxxxx......................xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[11], "xxxxxxxxxxxxxxxxxxxxxxxxxx..........................x.xxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[12], "xxxxxxxxxxxxxxxxxxxxxxxxxx............................xxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[13], "xxxxxxxxxxxxxxxxxxxxxxxxx.............................xxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[14], "xxxxxxxxxxxxxxxxxxxxxxxx.................................xxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[15], "xxxxxxxxxxxxxxxxxxxxxxxx..................................xxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[16], "xxxxxxxxxxxxxxxxxxxxxx....(................................xxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[17], "xxxxxxxxxxxxxxxxxxxxxx......................................xxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[18], "xxxxxxxxxxxxxxxxxxx..........................................xxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[19], "xxxxxxxxxxxxxxxxxxx..........................................xxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[20], "xxxxxxxxxxxxxxxxx............................................xxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[21], "xxxxxxxxxxxxxxxxx............................................xxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[22], "xxxxxxxxxxxxxx.....................ccc..ccc............]......xxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[23], "xxxxxxxxxxxxxxx...................cccc2ccccc...................xxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[24], "xxxxxxxxxxxxxx...................cc*cc..cc*cc....................xxxxxxxxxxxxxxx");
+ strcpy(vgrid[25], "xxxxxxxxxxxxxx..................cc***cc4c***cc..................xxxxxxxxxxxxxxxx");
+ strcpy(vgrid[26], "xxxxxxxxxxxxx..................cc*|*cc..cc*|*cc..................xxxxxxxxxxxxxxx");
+ strcpy(vgrid[27], "xxxxxxxxxxxxx.................cc*|P|*c4cc*|P|*cc.................xxxxxxxxxxxxxxx");
+ strcpy(vgrid[28], "xxxxxxxxxxxxx.................cc**|*cc..cc*|**cc....................xxxxxxxxxxxx");
+ strcpy(vgrid[29], "xxxxxxxxxxxx..................ccc**c|cc4c|c**ccc...................xxxxxxxxxxxxx");
+ strcpy(vgrid[30], "xxxxxxxxxxxx..................cccccccc..cccccccc....................xxxxxxxxxxxx");
+ strcpy(vgrid[31], "xxxxxxxxxxx...................c.4.c.4.1..4.c.4.c.....................xxxxxxxxxxx");
+ strcpy(vgrid[32], "xxxxxxxxxxx...................2.c.4.c..3.c.4.c.2.....................xxxxxxxxxxx");
+ strcpy(vgrid[33], "xxxxxxxxxxx..........)........cccccccc..cccccccc.....................xxxxxxxxxxx");
+ strcpy(vgrid[34], "xxxxxxxxxxx...................ccc**c|cc4c|c**ccc.....................xxxxxxxxxxx");
+ strcpy(vgrid[35], "xxxxxxxxxx....................cc**|*cc..cc*|**cc....................xxxxxxxxxxxx");
+ strcpy(vgrid[36], "xxxxxxxxxx....................cc*|P|*c4cc*|P|*cc....................xxxxxxxxxxxx");
+ strcpy(vgrid[37], "xxxxxxxxxx.....................cc*|*cc..cc*|*cc....................xxxxxxxxxxxxx");
+ strcpy(vgrid[38], "xxxxxxxxxxx.....................cc***cc4c***cc.....................xxxxxxxxxxxxx");
+ strcpy(vgrid[39], "xxxxxxxxxxxx.....................cc*cc..cc*cc......................xxxxxxxxxxxxx");
+ strcpy(vgrid[40], "xxxxxxxxxxxxx.....................cccc2ccccc......................xxxxxxxxxxxxxx");
+ strcpy(vgrid[41], "xxxxxxxxxxxxxx.....................ccc..ccc.......................xxxxxxxxxxxxxx");
+ strcpy(vgrid[42], "xxxxxxxxxxxxxx...........................................[.........xxxxxxxxxxxxx");
+ strcpy(vgrid[43], "xxxxxxxxxxxxx......................................................xxxxxxxxxxxxx");
+ strcpy(vgrid[44], "xxxxxxxxxxxxx..............................................xxxxx...xxxxxxxxxxxxx");
+ strcpy(vgrid[45], "xxxxxxxxxxxxxx...........................................xxxxxxxx.xxxxxxxxxxxxxx");
+ strcpy(vgrid[46], "xxxxxxxxxxxxxx..........................................xxxxxxxxx.xxxxxxxxxxxxxx");
+ strcpy(vgrid[47], "xxxxxxxxxxxxxxxx........................................xxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[48], "xxxxxxxxxxxxxxxx.........................................xxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[49], "xxxxxxxxxxxxxxxxxx.......................................xxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[50], "xxxxxxxxxxxxxxxxxxxx......................................xxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[51], "xxxxxxxxxxxxxxxxxxxx......................................xxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[52], "xxxxxxxxxxxxxxxxxxxxx.....................................xxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[53], "xxxxxxxxxxxxxxxxxxxxx.............................}......xxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[54], "xxxxxxxxxxxxxxxxxxxxxxx.................................xxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[55], "xxxxxxxxxxxxxxxxxxxxxxxx..............................xxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[56], "xxxxxxxxxxxxxxxxxxxxxxxxx..............................xxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[57], "xxxxxxxxxxxxxxxxxxxxxxxxxx............................xxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[58], "xxxxxxxxxxxxxxxxxxxxxxxxxxxx...........{........xxx..xxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[59], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx................xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[60], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.........xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[61], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[62], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[63], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[64], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[65], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[66], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[67], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[68], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[69], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ mons_array[0] = MONS_ROYAL_JELLY;
+ mons_array[1] = MONS_ACID_BLOB;
+ mons_array[2] = MONS_GREAT_ORB_OF_EYES;
+ mons_array[3] = RANDOM_MONSTER;
+ mons_array[4] = RANDOM_MONSTER;
+ mons_array[5] = RANDOM_MONSTER;
+ mons_array[6] = RANDOM_MONSTER;
+
+ return MAP_ENCOMPASS;
+
+}
+
+
+static char hall_of_blades(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+
+ strcpy(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[6], "xxxxxxxxccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccxxxxxxxx");
+ strcpy(vgrid[7], "xxxxxxxxccc....cccc.cccc.cccc.cccc.cccc.cccc.cccc.cccc.cccc.cccc.....cccxxxxxxxx");
+ strcpy(vgrid[8], "xxxxxxxxcc......cc...cc...cc...cc...cc...cc...cc...cc...cc...cc.......ccxxxxxxxx");
+ strcpy(vgrid[9], "xxxxxxxxc..............................................................cxxxxxxxx");
+ strcpy(vgrid[10], "xxxxxxxxc..........c..............c..............c..............c......cxxxxxxxx");
+ strcpy(vgrid[11], "xxxxxxxxc.........ccc............ccc............ccc............ccc.....cxxxxxxxx");
+ strcpy(vgrid[12], "xxxxxxxxc........ccccc..........ccccc..........ccccc..........ccccc....cxxxxxxxx");
+ strcpy(vgrid[13], "xxxxxxxxc.........ccc............ccc............ccc...........ccccc....cxxxxxxxx");
+ strcpy(vgrid[14], "xxxxxxxxc..........c..............c..............c.............ccc.....cxxxxxxxx");
+ strcpy(vgrid[15], "xxxxxxxxc......................................................ccc.....cxxxxxxxx");
+ strcpy(vgrid[16], "xxxxxxxxc.......................................................c......cxxxxxxxx");
+ strcpy(vgrid[17], "xxxxxxxxc..............................................................cxxxxxxxx");
+ strcpy(vgrid[18], "xxxxxxxxc..............................................................cxxxxxxxx");
+ strcpy(vgrid[19], "xxxxxxxxc..............................................................cxxxxxxxx");
+ strcpy(vgrid[20], "xxxxxxxxc..............................................................cxxxxxxxx");
+ strcpy(vgrid[21], "xxxxxxxxc..............................................................cxxxxxxxx");
+ strcpy(vgrid[22], "xxxxxxxxc..............................................................cxxxxxxxx");
+ strcpy(vgrid[23], "xxxxxxxxc.......................................................c......cxxxxxxxx");
+ strcpy(vgrid[24], "xxxxxxxxc......................................................ccc.....cxxxxxxxx");
+ strcpy(vgrid[25], "xxxxxxxxc..........c..............c..............c.............ccc.....cxxxxxxxx");
+ strcpy(vgrid[26], "xxxxxxxxc.........ccc............ccc............ccc...........ccccc....cxxxxxxxx");
+ strcpy(vgrid[27], "xxxxxxxxc........ccccc..........ccccc..........ccccc..........ccccc....cxxxxxxxx");
+ strcpy(vgrid[28], "xxxxxxxxc.........ccc............ccc............ccc............ccc.....cxxxxxxxx");
+ strcpy(vgrid[29], "xxxxxxxxc..........c..............c..............c..............c......cxxxxxxxx");
+ strcpy(vgrid[30], "xxxxxxxxc..............................................................cxxxxxxxx");
+ strcpy(vgrid[31], "xxxxxxxxc.......cc...cc...cc...cc...cc...cc...cc...cc...cc...cc.......ccxxxxxxxx");
+ strcpy(vgrid[32], "xxxxxxxxcc.....cccc.cccc.cccc.cccc.cccc.cccc.cccc.cccc.cccc.cccc.....cccxxxxxxxx");
+ strcpy(vgrid[33], "xxxxxxxxccc...ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccxxxxxxxx");
+ strcpy(vgrid[34], "xxxxxxxxcccc.............................cccccccccccccccccccccccccccccccxxxxxxxx");
+ strcpy(vgrid[35], "xxxxxxxxcccccccccccccccccccccccccccccc.@.cccccccccccccccccccccccccccccccxxxxxxxx");
+
+ mons_array[0] = MONS_DANCING_WEAPON;
+ mons_array[1] = RANDOM_MONSTER;
+ mons_array[2] = RANDOM_MONSTER;
+ mons_array[3] = RANDOM_MONSTER;
+ mons_array[4] = RANDOM_MONSTER;
+ mons_array[5] = RANDOM_MONSTER;
+ mons_array[6] = RANDOM_MONSTER;
+
+ return MAP_NORTH;
+}
+
+
+static char hall_of_Zot(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+
+ strcpy(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[6], "xxxxxxxxxxxxxxccccccccccccccccxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccxxxxxxxxxxxxx");
+ strcpy(vgrid[7], "xxxxxxxxxxxcccc..............ccccxxxxxxxxxxxxxxxxxcccc............ccccxxxxxxxxxx");
+ strcpy(vgrid[8], "xxxxxxxxxxcc....................cccxxxxxxxxxxxxxccc..................ccxxxxxxxxx");
+ strcpy(vgrid[9], "xxxxxxxxxcc...........3...........ccxxxxxxxxxxxcc...........3.........ccxxxxxxxx");
+ strcpy(vgrid[10], "xxxxxxxxxc..8......................cXXXXXXXXXXXc....................8..cxxxxxxxx");
+ strcpy(vgrid[11], "xxxxxxxxxc...................8.....XXX...1...XXX....8..................cxxxxxxxx");
+ strcpy(vgrid[12], "xxxxxxxxxcc........................XX..1...1..XX......................ccxxxxxxxx");
+ strcpy(vgrid[13], "xxxxxxxxxxcc.......................X1.........1X.....................ccxxxxxxxxx");
+ strcpy(vgrid[14], "xxxxxxxxxxxcc.....4....2..............1..Z..1............2....4.....ccxxxxxxxxxx");
+ strcpy(vgrid[15], "xxxxxxxxxxcc.......................X1.........1X.....................ccxxxxxxxxx");
+ strcpy(vgrid[16], "xxxxxxxxxcc........................XX..1...1..XX......................ccxxxxxxxx");
+ strcpy(vgrid[17], "xxxxxxxxxc...................8.....XXX...1...XXX....8..................cxxxxxxxx");
+ strcpy(vgrid[18], "xxxxxxxxxc...8.....................cXXXXXXXXXXXc...................8...cxxxxxxxx");
+ strcpy(vgrid[19], "xxxxxxxxxcc..........8............ccccccccccccccc..........8..........ccxxxxxxxx");
+ strcpy(vgrid[20], "xxxxxxxxxxcc....................ccccccccccccccccccc..................ccxxxxxxxxx");
+ strcpy(vgrid[21], "xxxxxxxxxxxcc................ccccccccccccccccccccccccc..............ccxxxxxxxxxx");
+ strcpy(vgrid[22], "xxxxxxxxxxxxccF111FcccccccccccccccccccccccccccccccccccccccccccF111Fccxxxxxxxxxxx");
+ strcpy(vgrid[23], "xxxxxxxxxxxcc................^^1.ccccccccccccccccc.1^^..............ccxxxxxxxxxx");
+ strcpy(vgrid[24], "xxxxxxxxxxcc.................cc1...ccccccccccccc...1cc...............ccxxxxxxxxx");
+ strcpy(vgrid[25], "xxxxxxxxxcc.............8.....ccc...ccccccccccc...ccc...8.............ccxxxxxxxx");
+ strcpy(vgrid[26], "xxxxxxxxxc....8................ccc...............ccc...........8...8...cxxxxxxxx");
+ strcpy(vgrid[27], "xxxxxxxxxc.......8.....8...8...cxcc.............ccxc...................cxxxxxxxx");
+ strcpy(vgrid[28], "xxxxxxxxxc.....................cxxc.............cxxc.......8...........cxxxxxxxx");
+ strcpy(vgrid[29], "xxxxxxxxxc.....................cxxcc.1...1...1.ccxxc............8....8.cxxxxxxxx");
+ strcpy(vgrid[30], "xxxxxxxxxc.......8....8.....8..cxxxc...........cxxxc....8..............cxxxxxxxx");
+ strcpy(vgrid[31], "xxxxxxxxxc.....................cxxcc...........ccxxc..........8........cxxxxxxxx");
+ strcpy(vgrid[32], "xxxxxxxxxcc...5...............ccxxc.............cxxcc..............8..ccxxxxxxxx");
+ strcpy(vgrid[33], "xxxxxxxxxxcc........8........ccxxcc.............ccxxcc....8....5.....ccxxxxxxxxx");
+ strcpy(vgrid[34], "xxxxxxxxxxxcc...............ccxxxc...............cxxxcc.............ccxxxxxxxxxx");
+ strcpy(vgrid[35], "xxxxxxxxxxxxcccccccccccccccccxxxxcccccccc@ccccccccxxxxcccccccccccccccxxxxxxxxxxx");
+
+ mons_array[0] = MONS_ORB_GUARDIAN;
+ mons_array[1] = MONS_KILLER_KLOWN;
+ mons_array[2] = MONS_ELECTRIC_GOLEM;
+ mons_array[3] = MONS_ORB_OF_FIRE;
+ mons_array[4] = MONS_ANCIENT_LICH;
+ mons_array[5] = RANDOM_MONSTER;
+ mons_array[6] = RANDOM_MONSTER;
+
+ return MAP_NORTH;
+}
+
+
+static char temple(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // this is the ecumenical temple level
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[6], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[7], "xxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[8], "xxxxxxxxxxxxxxxxxxxxxxxxxcc............<............cxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[9], "xxxxxxxxxxxxxxxxxxxxxxxxcc...........................cxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[10], "xxxxxxxxxxxxxxxxxxxxxxxcc.............................cxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[11], "xxxxxxxxxxxxxxxxxxxxxxcc...............................cxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[12], "xxxxxxxxxxxxxxxxxxxxxcc.................................cxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[13], "xxxxxxxxxxxxxxxxxxxxcc...................................cxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[14], "xxxxxxxxxxxxxxxxxxxcc.....................................cxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[15], "xxxxxxxxxxxxxxxxxxcc.......................................cxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[16], "xxxxxxxxxxxxxxxxxcc.........................................cxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[17], "xxxxxxxxxxxxxxxxcc...........................................cxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[18], "xxxxxxxxxxxxxxxcc.............................................cxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[19], "xxxxxxxxxxxxxxcc...............................................cxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[20], "xxxxxxxxxxxxxcc.................................................cxxxxxxxxxxxxxxx");
+ strcpy(vgrid[21], "xxxxxxxxxxxxcc...................................................cxxxxxxxxxxxxxx");
+ strcpy(vgrid[22], "xxxxxxxxxxxcc..........................B..........................cxxxxxxxxxxxxx");
+ strcpy(vgrid[23], "xxxxxxxxxxcc.......................................................cxxxxxxxxxxxx");
+ strcpy(vgrid[24], "xxxxxxxxxcc.....................B.............B.....................cxxxxxxxxxxx");
+ strcpy(vgrid[25], "xxxxxxxxcc...........................................................cxxxxxxxxxx");
+ strcpy(vgrid[26], "xxxxxxxxc.............................................................cxxxxxxxxx");
+ strcpy(vgrid[27], "xxxxxxxxc.............................................................cxxxxxxxxx");
+ strcpy(vgrid[28], "xxxxxxxxc.................B.........................B.................cxxxxxxxxx");
+ strcpy(vgrid[29], "xxxxxxxxc..............................T..............................cxxxxxxxxx");
+ strcpy(vgrid[30], "xxxxxxxxc.............................................................cxxxxxxxxx");
+ strcpy(vgrid[31], "xxxxxxxxc.............................................................cxxxxxxxxx");
+ strcpy(vgrid[32], "xxxxxxxxc.............................................................cxxxxxxxxx");
+ strcpy(vgrid[33], "xxxxxxxxc.............................................................cxxxxxxxxx");
+ strcpy(vgrid[34], "xxxxxxxxc.............................................................cxxxxxxxxx");
+ strcpy(vgrid[35], "xxxxxxxxc..............B...............................B..............cxxxxxxxxx");
+ strcpy(vgrid[36], "xxxxxxxxc(....................T.................T....................{cxxxxxxxxx");
+ strcpy(vgrid[37], "xxxxxxxxc.............................................................cxxxxxxxxx");
+ strcpy(vgrid[38], "xxxxxxxxc.............................................................cxxxxxxxxx");
+ strcpy(vgrid[39], "xxxxxxxxc.............................................................cxxxxxxxxx");
+ strcpy(vgrid[40], "xxxxxxxxc.............................................................cxxxxxxxxx");
+ strcpy(vgrid[41], "xxxxxxxxc.............................................................cxxxxxxxxx");
+ strcpy(vgrid[42], "xxxxxxxxc.............................................................cxxxxxxxxx");
+ strcpy(vgrid[43], "xxxxxxxxc................B...........................B................cxxxxxxxxx");
+ strcpy(vgrid[44], "xxxxxxxxcc...........................................................ccxxxxxxxxx");
+ strcpy(vgrid[45], "xxxxxxxxxcc............................T............................ccxxxxxxxxxx");
+ strcpy(vgrid[46], "xxxxxxxxxxcc.......................................................ccxxxxxxxxxxx");
+ strcpy(vgrid[47], "xxxxxxxxxxxcc.....................................................ccxxxxxxxxxxxx");
+ strcpy(vgrid[48], "xxxxxxxxxxxxcc...................................................ccxxxxxxxxxxxxx");
+ strcpy(vgrid[49], "xxxxxxxxxxxxxcc.................................................ccxxxxxxxxxxxxxx");
+ strcpy(vgrid[50], "xxxxxxxxxxxxxxcc...............B................B..............ccxxxxxxxxxxxxxxx");
+ strcpy(vgrid[51], "xxxxxxxxxxxxxxxcc.............................................ccxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[52], "xxxxxxxxxxxxxxxxcc.....................B.....................ccxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[53], "xxxxxxxxxxxxxxxxxcc.........................................ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[54], "xxxxxxxxxxxxxxxxxxcc.......................................ccxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[55], "xxxxxxxxxxxxxxxxxxxcc.....................................ccxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[56], "xxxxxxxxxxxxxxxxxxxxcc...................................ccxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[57], "xxxxxxxxxxxxxxxxxxxxxcc.................................ccxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[58], "xxxxxxxxxxxxxxxxxxxxxxcc...............................ccxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[59], "xxxxxxxxxxxxxxxxxxxxxxxcc.............................ccxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[60], "xxxxxxxxxxxxxxxxxxxxxxxxcc...........................ccxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[61], "xxxxxxxxxxxxxxxxxxxxxxxxxcc............[............ccxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[62], "xxxxxxxxxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[63], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[64], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[65], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[66], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[67], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[68], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[69], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ return MAP_ENCOMPASS;
+}
+
+
+static char tomb_1(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+
+ strcpy(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[6], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[7], "xxxxxxxxx(.............................[..............................{xxxxxxxxx");
+ strcpy(vgrid[8], "xxxxxxxxx..............................................................xxxxxxxxx");
+ strcpy(vgrid[9], "xxxxxxxxx..............................................................xxxxxxxxx");
+ strcpy(vgrid[10], "xxxxxxxxx..............................................................xxxxxxxxx");
+ strcpy(vgrid[11], "xxxxxxxxx..............................................................xxxxxxxxx");
+ strcpy(vgrid[12], "xxxxxxxxx..........ccccccccccccccccccccccccccccccccccccccccccc.........xxxxxxxxx");
+ strcpy(vgrid[13], "xxxxxxxxx..........ccccccccccccccccccccccccccccccccccccccccccc.........xxxxxxxxx");
+ strcpy(vgrid[14], "xxxxxxxxx..........cc..........................^............cc.........xxxxxxxxx");
+ strcpy(vgrid[15], "xxxxxxxxx..........cc.........^....................^........cc.........xxxxxxxxx");
+ strcpy(vgrid[16], "xxxxxxxxx..........cc..ccccccccccccccccccccccccccccccccccc..cc.........xxxxxxxxx");
+ strcpy(vgrid[17], "xxxxxxxxx..........cc..c....^....^..c................c.^)c..cc.........xxxxxxxxx");
+ strcpy(vgrid[18], "xxxxxxxxx..........cc..c..ccccccccc.c..3.............c.^.c..cc.........xxxxxxxxx");
+ strcpy(vgrid[19], "xxxxxxxxx..........cc..c..c222c111c.c...............5c..^c..cc.........xxxxxxxxx");
+ strcpy(vgrid[20], "xxxxxxxxx..........cc..c..c2c222c.^.c......2.........+cccc..cc.........xxxxxxxxx");
+ strcpy(vgrid[21], "xxxxxxxxx..........cc..c..ccccccccccc..........3......5..c.^cc.........xxxxxxxxx");
+ strcpy(vgrid[22], "xxxxxxxxx..........cc..c.................................c..cc.........xxxxxxxxx");
+ strcpy(vgrid[23], "xxxxxxxxx..........cc..c..........................3......c..cc.........xxxxxxxxx");
+ strcpy(vgrid[24], "xxxxxxxxx..........cc^.cccccccccccccc.......2............c..cc.........xxxxxxxxx");
+ strcpy(vgrid[25], "xxxxxxxxx..........cc..c............c....................c..cc.........xxxxxxxxx");
+ strcpy(vgrid[26], "xxxxxxxxx..........cc..c............c.................3..c..cc.........xxxxxxxxx");
+ strcpy(vgrid[27], "xxxxxxxxx..........cc..c..cccccccc..c..........2.........c^5cc.........xxxxxxxxx");
+ strcpy(vgrid[28], "xxxxxxxxx..........cc..c..c.^.c11c..c....................c..cc.........xxxxxxxxx");
+ strcpy(vgrid[29], "xxxxxxxxx..........cc..c..c.c.c11c..c...3................c..cc.........xxxxxxxxx");
+ strcpy(vgrid[30], "xxxxxxxxx..........cc..c..c^c.11cc..c..............2.....c..cc.........xxxxxxxxx");
+ strcpy(vgrid[31], "xxxxxxxxx..........cc..c..c.cccccc..c.......2............c..cc.........xxxxxxxxx");
+ strcpy(vgrid[32], "xxxxxxxxx..........cc..c..c..^..^...c.................2..c..cc.........xxxxxxxxx");
+ strcpy(vgrid[33], "xxxxxxxxx..........cc5^c..ccccccccccc....................c..cc.........xxxxxxxxx");
+ strcpy(vgrid[34], "xxxxxxxxx..........cc..c.................................c..cc.........xxxxxxxxx");
+ strcpy(vgrid[35], "xxxxxxxxx..........cc..c.................................c..cc.........xxxxxxxxx");
+ strcpy(vgrid[36], "xxxxxxxxx..........cc..cccccccccccccc..^.^..cccccccccccccc..cc.........xxxxxxxxx");
+ strcpy(vgrid[37], "xxxxxxxxx..........cc..c...........ccc+++++ccc........^..c.^cc.........xxxxxxxxx");
+ strcpy(vgrid[38], "xxxxxxxxx..........cc..c.^.....^...cc.2...2.cc......^....c..cc.........xxxxxxxxx");
+ strcpy(vgrid[39], "xxxxxxxxx..........cc..c..ccccccc..cc.F...F.cc..ccccccc..c..cc.........xxxxxxxxx");
+ strcpy(vgrid[40], "xxxxxxxxx..........cc..c..cc.322c..cc.......cc..c22..cc..c..cc.........xxxxxxxxx");
+ strcpy(vgrid[41], "xxxxxxxxx..........cc..c..c].c22c..cc.......cc..c22c.}c^.c..cc.........xxxxxxxxx");
+ strcpy(vgrid[42], "xxxxxxxxx..........cc..c..cccc..c.^cc.G...G.cc..c3.cccc..c..cc.........xxxxxxxxx");
+ strcpy(vgrid[43], "xxxxxxxxx..........cc..c.....^..c..cc.......cc.^c........c..cc.........xxxxxxxxx");
+ strcpy(vgrid[44], "xxxxxxxxx..........cc..c........c..cc.......cc..c....^...c..cc.........xxxxxxxxx");
+ strcpy(vgrid[45], "xxxxxxxxx..........cc^.cccccccccc..cc.G...G.cc..cccccccccc.^cc.........xxxxxxxxx");
+ strcpy(vgrid[46], "xxxxxxxxx..........cc......^.......cc.......cc..........^...cc.........xxxxxxxxx");
+ strcpy(vgrid[47], "xxxxxxxxx..........cc...........^..cc.......cc.....^........cc.........xxxxxxxxx");
+ strcpy(vgrid[48], "xxxxxxxxx..........cccccccccccccccccc.G...G.cccccccccccccccccc.........xxxxxxxxx");
+ strcpy(vgrid[49], "xxxxxxxxx..........cccccccccccccccccc.......cccccccccccccccccc.........xxxxxxxxx");
+ strcpy(vgrid[50], "xxxxxxxxx..............................................................xxxxxxxxx");
+ strcpy(vgrid[51], "xxxxxxxxx.............................G...G............................xxxxxxxxx");
+ strcpy(vgrid[52], "xxxxxxxxx...........................4.......4..........................xxxxxxxxx");
+ strcpy(vgrid[53], "xxxxxxxxx..............................................................xxxxxxxxx");
+ strcpy(vgrid[54], "xxxxxxxxx..............................................................xxxxxxxxx");
+ strcpy(vgrid[55], "xxxxxxxxx...........................4..V.V..4..........................xxxxxxxxx");
+ strcpy(vgrid[56], "xxxxxxxxx..............................................................xxxxxxxxx");
+ strcpy(vgrid[57], "xxxxxxxxx..............................................................xxxxxxxxx");
+ strcpy(vgrid[58], "xxxxxxxxx..............................................................xxxxxxxxx");
+ strcpy(vgrid[59], "xxxxxxxxx...........................4.......4..........................xxxxxxxxx");
+ strcpy(vgrid[60], "xxxxxxxxx..............................................................xxxxxxxxx");
+ strcpy(vgrid[61], "xxxxxxxxx..............................................................xxxxxxxxx");
+ strcpy(vgrid[62], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[63], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[64], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[65], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[66], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[67], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[68], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[69], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ mons_array[0] = MONS_MUMMY;
+ mons_array[1] = MONS_GUARDIAN_MUMMY;
+ mons_array[2] = MONS_MUMMY_PRIEST;
+ mons_array[3] = MONS_SPHINX;
+ mons_array[4] = MONS_GREATER_MUMMY;
+ mons_array[5] = RANDOM_MONSTER;
+ mons_array[6] = RANDOM_MONSTER;
+
+ return MAP_ENCOMPASS;
+}
+
+
+static char tomb_2(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+
+ strcpy(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[6], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[7], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[8], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[9], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[10], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[11], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[12], "xxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[13], "xxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[14], "xxxxxxxxxxxxxxxxxxxcc{...c......c.....3....c........c.......ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[15], "xxxxxxxxxxxxxxxxxxxcc....c.....^c^........^c......2^c.......ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[16], "xxxxxxxxxxxxxxxxxxxcc....c...2.^+..2.....2^+^..2....+.......ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[17], "xxxxxxxxxxxxxxxxxxxcc.3.^c^.....c^.........c^2.....^c^......ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[18], "xxxxxxxxxxxxxxxxxxxcc...^+^.....c..........c........c...2...ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[19], "xxxxxxxxxxxxxxxxxxxccccc+ccccccccccccccccccccccccccccccc....ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[20], "xxxxxxxxxxxxxxxxxxxcc..^.c.............................c....ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[21], "xxxxxxxxxxxxxxxxxxxcc....c.............................c..3.ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[22], "xxxxxxxxxxxxxxxxxxxcc....c..ccc4.................4ccc..c....ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[23], "xxxxxxxxxxxxxxxxxxxcc....c..ccc...................ccc..c..2.ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[24], "xxxxxxxxxxxxxxxxxxxcc....c..ccc.........1.........ccc..c)..}ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[25], "xxxxxxxxxxxxxxxxxxxcc.3..c..ccc.....2.......2.....ccc..cccccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[26], "xxxxxxxxxxxxxxxxxxxcc....c.............................c....ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[27], "xxxxxxxxxxxxxxxxxxxcc....c.............................c^2..ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[28], "xxxxxxxxxxxxxxxxxxxcc....c........c...........c........+....ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[29], "xxxxxxxxxxxxxxxxxxxcc]...c.............................c^2..ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[30], "xxxxxxxxxxxxxxxxxxxccccccc.....3........(........3.....c....ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[31], "xxxxxxxxxxxxxxxxxxxcc....c.............................c.^.^ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[32], "xxxxxxxxxxxxxxxxxxxcc...^c........c...........c........ccc+cccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[33], "xxxxxxxxxxxxxxxxxxxcc....+.............................c..^.ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[34], "xxxxxxxxxxxxxxxxxxxcc...^c.............................c....ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[35], "xxxxxxxxxxxxxxxxxxxcc....c..ccc.....2.......2.....ccc..c..2.ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[36], "xxxxxxxxxxxxxxxxxxxccccccc..ccc.........1.........ccc..c....ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[37], "xxxxxxxxxxxxxxxxxxxcc....c..ccc...................ccc..c....ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[38], "xxxxxxxxxxxxxxxxxxxcc...^+..ccc4.................4ccc..c2...ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[39], "xxxxxxxxxxxxxxxxxxxcc....c.............................c....ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[40], "xxxxxxxxxxxxxxxxxxxccccccc.............................c..2.ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[41], "xxxxxxxxxxxxxxxxxxxcc....c.............................ccc+cccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[42], "xxxxxxxxxxxxxxxxxxxcc....+cccc+ccccccccccccccc+ccccccccc.^.^ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[43], "xxxxxxxxxxxxxxxxxxxcc.1.^^.c.^..c............c^.......c.3...ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[44], "xxxxxxxxxxxxxxxxxxxcc...2..c.1..c.....1.1....c.....2..c.....ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[45], "xxxxxxxxxxxxxxxxxxxcc......c....c..1......1.^c..2.....c...2.ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[46], "xxxxxxxxxxxxxxxxxxxcc..3...c.1..c...1...1..1^+........c.....ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[47], "xxxxxxxxxxxxxxxxxxxcc......c....c[...........c.......3c.....ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[48], "xxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[49], "xxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[50], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[51], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[52], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[53], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[54], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[55], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[56], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[57], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[58], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[59], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[60], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[61], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[62], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[63], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[64], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[65], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[66], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[67], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[68], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[69], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ mons_array[0] = MONS_MUMMY;
+ mons_array[1] = MONS_GUARDIAN_MUMMY;
+ mons_array[2] = MONS_MUMMY_PRIEST;
+ mons_array[3] = MONS_GREATER_MUMMY;
+ mons_array[4] = RANDOM_MONSTER;
+ mons_array[5] = RANDOM_MONSTER;
+ mons_array[6] = RANDOM_MONSTER;
+
+ return MAP_ENCOMPASS;
+}
+
+
+static char tomb_3(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+
+ strcpy(vgrid[0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[1], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[2], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[3], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[4], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[5], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[6], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[7], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[8], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[9], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[10], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[11], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[12], "xxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[13], "xxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[14], "xxxxxxxxxxxxxxxxxxxccccccc.............................cccccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[15], "xxxxxxxxxxxxxxxxxxxcccc...............cccccc..............ccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[16], "xxxxxxxxxxxxxxxxxxxccc...............cccccccc..............cccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[17], "xxxxxxxxxxxxxxxxxxxccc.......4......ccccO4cccc......4......cccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[18], "xxxxxxxxxxxxxxxxxxxccc............cccc......cccc...........cccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[19], "xxxxxxxxxxxxxxxxxxxcc............cccc........cccc...........ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[20], "xxxxxxxxxxxxxxxxxxxcc............cccc........cccc...........ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[21], "xxxxxxxxxxxxxxxxxxxcc...........cccc..444444..cccc..........ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[22], "xxxxxxxxxxxxxxxxxxxcc.......................................ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[23], "xxxxxxxxxxxxxxxxxxxcc.......................................ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[24], "xxxxxxxxxxxxxxxxxxxcc.................222222................ccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[25], "xxxxxxxxxxxxxxxxxxxccc................223322...............cccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[26], "xxxxxxxxxxxxxxxxxxxccc...3............223322............3..cccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[27], "xxxxxxxxxxxxxxxxxxxcccc...............222222..............ccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[28], "xxxxxxxxxxxxxxxxxxxcccc....2..........................2...ccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[29], "xxxxxxxxxxxxxxxxxxxcccccc....2......................2....cccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[30], "xxxxxxxxxxxxxxxxxxxcccccccc............................cccccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[31], "xxxxxxxxxxxxxxxxxxxccccccccc+ccc..................ccc+ccccccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[32], "xxxxxxxxxxxxxxxxxxxcccccccc....cc................cc....cccccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[33], "xxxxxxxxxxxxxxxxxxxcccccc.......cc22222222222222cc......$cccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[34], "xxxxxxxxxxxxxxxxxxxcccc....^.....cc............cc..^.....$ccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[35], "xxxxxxxxxxxxxxxxxxxcccc.^.........cc..........cc.....^.^.$ccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[36], "xxxxxxxxxxxxxxxxxxxccc$...^...^..^.cc........cc..........$$cccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[37], "xxxxxxxxxxxxxxxxxxxccc$$$...........cc222222cc.^........$$$cccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[38], "xxxxxxxxxxxxxxxxxxxccc|$$$...........c......c.....^...$$$$$cccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[39], "xxxxxxxxxxxxxxxxxxxccc||$$$$...^.....c......c^......$$$$$$$cccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[40], "xxxxxxxxxxxxxxxxxxxccc|||||$$.....^..c......c......$$$$$$$$cccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[41], "xxxxxxxxxxxxxxxxxxxcccc|||||$........c......c...^.$$$$$$$$ccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[42], "xxxxxxxxxxxxxxxxxxxccccc||||$$..^....c......c.....$$$$$$$cccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[43], "xxxxxxxxxxxxxxxxxxxcccccc||||$.......c......c.....$$$$$$ccccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[44], "xxxxxxxxxxxxxxxxxxxccccccc|||$$....^.c......c.^.^$$$$$$cccccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[45], "xxxxxxxxxxxxxxxxxxxcccccccc|||$^....cc..{...cc...$$$$$ccccccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[46], "xxxxxxxxxxxxxxxxxxxccccccccc||$.....cc...(..cc..$$$$$cccccccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[47], "xxxxxxxxxxxxxxxxxxxcccccccccc|$...cccc..[...cccc$$$$ccccccccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[48], "xxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[49], "xxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[50], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[51], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[52], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[53], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[54], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[55], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[56], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[57], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[58], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[59], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[60], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[61], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[62], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[63], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[64], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[65], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[66], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[67], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[68], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcpy(vgrid[69], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ mons_array[0] = MONS_MUMMY;
+ mons_array[1] = MONS_GUARDIAN_MUMMY;
+ mons_array[2] = MONS_MUMMY_PRIEST;
+ mons_array[3] = MONS_GREATER_MUMMY;
+ mons_array[4] = RANDOM_MONSTER;
+ mons_array[5] = RANDOM_MONSTER;
+ mons_array[6] = RANDOM_MONSTER;
+
+ return MAP_ENCOMPASS;
+}
+
+
+
+static char swamp(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // NB - most of the 'x's here will be set to water in dungeon.cc
+
+ for (unsigned char i = 0; i < 81; i++)
+ strcpy(vgrid[i], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ strcat(vgrid[36], "xxxxxxxxxxx@xxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[37], "xxxxxxxxxxx2xxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[38], "xxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[39], "xxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[40], "xxxxxxxxxx2x.xxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[41], "xxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[42], "xxxxxxxxxcc.ccxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[43], "xxxxxxxxcc...ccxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[44], "xxxxxxxcc3.2..ccxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[45], "xxxxxxcc.1.3.2.ccxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[46], "xxxxxccc....1.1cccxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[47], "xxxxxcc.1.32....ccxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[48], "xxxxxcc...3..1.3ccxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[49], "xxxxxcc2.1.3..2.ccxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[50], "xxxxxccc33..1..cccxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[51], "xxxxxxcccc3O3ccccxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[52], "xxxxxxxcccccccccxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[53], "xxxxxxxxcccccccxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[54], "xxxxxxxxxxcccxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[55], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[56], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[57], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[58], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[59], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[60], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[61], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[62], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[63], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[64], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[65], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[66], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[67], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[68], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ strcat(vgrid[69], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ mons_array[0] = MONS_SWAMP_DRAGON;
+ mons_array[1] = MONS_SWAMP_DRAKE;
+ mons_array[2] = MONS_HYDRA;
+ mons_array[3] = RANDOM_MONSTER;
+ mons_array[4] = RANDOM_MONSTER;
+ mons_array[5] = RANDOM_MONSTER;
+ mons_array[6] = RANDOM_MONSTER;
+
+ return MAP_SOUTHEAST;
+}
+
+
+/*
+ NOTE: *Cannot* place 8,9 or 0 monsters in branch vaults which neither use the
+ normal mons_level function or are around level 35, or generation will crash.
+
+ Remember, minivaults are always sidewards
+*/
+
+static char minivault_1(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], "..xxxx=xxx..");
+ strcpy(vgrid[2], ".xx..x...xx.");
+ strcpy(vgrid[3], ".x....x...x.");
+ strcpy(vgrid[4], ".x...x....x.");
+ strcpy(vgrid[5], ".xx.x*x.x.=.");
+ strcpy(vgrid[6], ".=.x.x*x.xx.");
+ strcpy(vgrid[7], ".x....x...x.");
+ strcpy(vgrid[8], ".x...x....x.");
+ strcpy(vgrid[9], ".xx...x..xx.");
+ strcpy(vgrid[10], "..xxx=xxxx..");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+}
+
+
+static char minivault_2(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], "..xxxx.xxxx.");
+ strcpy(vgrid[2], "..xx.....xx.");
+ strcpy(vgrid[3], "..x.......x.");
+ strcpy(vgrid[4], "..x.......x.");
+ strcpy(vgrid[5], "......C.....");
+ strcpy(vgrid[6], "..x.......x.");
+ strcpy(vgrid[7], "..x.......x.");
+ strcpy(vgrid[8], "..xx.....xx.");
+ strcpy(vgrid[9], "..xxxx.xxxx.");
+ strcpy(vgrid[10], "............");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+}
+
+
+static char minivault_3(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], ".cccccccccc.");
+ strcpy(vgrid[2], ".cccccccccc.");
+ strcpy(vgrid[3], ".cBcBcBcBcc.");
+ strcpy(vgrid[4], ".G.c.c.c.Bc.");
+ strcpy(vgrid[5], ".........Bc.");
+ strcpy(vgrid[6], ".........Bc.");
+ strcpy(vgrid[7], ".G.c.c.c.Bc.");
+ strcpy(vgrid[8], ".cBcBcBcBcc.");
+ strcpy(vgrid[9], ".cccccccccc.");
+ strcpy(vgrid[10], ".cccccccccc.");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+}
+
+
+static char minivault_4(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], "....xwxx....");
+ strcpy(vgrid[2], "..xxxwwxwx..");
+ strcpy(vgrid[3], "..xwwwwwwx..");
+ strcpy(vgrid[4], ".xwwxwwxwxx.");
+ strcpy(vgrid[5], ".xwwwwwwwwx.");
+ strcpy(vgrid[6], ".xwwxwwwxww.");
+ strcpy(vgrid[7], ".xxwwwwwwxx.");
+ strcpy(vgrid[8], "..wwwwxwwx..");
+ strcpy(vgrid[9], "..xxxwwxxw..");
+ strcpy(vgrid[10], "....xxww....");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+}
+
+
+static char minivault_5(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], ".x.xxxxxxxx.");
+ strcpy(vgrid[2], ".x.x......x.");
+ strcpy(vgrid[3], ".x.x.xxxx.x.");
+ strcpy(vgrid[4], ".x.x.x**x.x.");
+ strcpy(vgrid[5], ".x.x.x**x.x.");
+ strcpy(vgrid[6], ".x.x.xx.x.x.");
+ strcpy(vgrid[7], ".x.x....x.x.");
+ strcpy(vgrid[8], ".x.xxxxxx.x.");
+ strcpy(vgrid[9], ".x........x.");
+ strcpy(vgrid[10], ".xxxxxxxxxx.");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+}
+
+
+static char minivault_6(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // Wizard's laboratory
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], ".ccccccc+cc.");
+ strcpy(vgrid[2], ".c........c.");
+ strcpy(vgrid[3], ".c........c.");
+ strcpy(vgrid[4], ".c..1.....c.");
+ strcpy(vgrid[5], ".c........c.");
+ strcpy(vgrid[6], ".cc+ccccccc.");
+ strcpy(vgrid[7], ".c***c3232c.");
+ strcpy(vgrid[8], ".c|**+2223c.");
+ strcpy(vgrid[9], ".c||*c3322c.");
+ strcpy(vgrid[10], ".cccccccccc.");
+ strcpy(vgrid[11], "............");
+
+ mons_array[0] = MONS_WIZARD;
+ mons_array[1] = MONS_ABOMINATION_SMALL;
+ mons_array[2] = MONS_ABOMINATION_LARGE;
+
+ return MAP_NORTH;
+
+}
+
+
+static char minivault_7(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // beehive minivault
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], "....aaaa....");
+ strcpy(vgrid[2], "..a2a2aaaa..");
+ strcpy(vgrid[3], "..aaRa3a2a..");
+ strcpy(vgrid[4], ".aa2aRa2aaa.");
+ strcpy(vgrid[5], ".a3aRa1aRa2.");
+ strcpy(vgrid[6], ".aa3aRaRa2a.");
+ strcpy(vgrid[7], ".aaa2a2a3aa.");
+ strcpy(vgrid[8], "..a3aRa2aa..");
+ strcpy(vgrid[9], "...aa2aa2a..");
+ strcpy(vgrid[10], "....aaaa....");
+ strcpy(vgrid[11], "............");
+
+ mons_array[0] = MONS_QUEEN_BEE;
+ mons_array[1] = MONS_KILLER_BEE;
+ mons_array[2] = MONS_KILLER_BEE_LARVA;
+
+ return MAP_NORTH;
+}
+
+
+static char minivault_8(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // lava pond
+
+ strcpy(vgrid[0], "x.x.x.x.x.x.");
+ strcpy(vgrid[1], ".c.c.c.c.c.x");
+ strcpy(vgrid[2], "x...l1l...c.");
+ strcpy(vgrid[3], ".c.llllll..x");
+ strcpy(vgrid[4], "x.lllllll1c.");
+ strcpy(vgrid[5], ".c.llFGll..x");
+ strcpy(vgrid[6], "x..llGFll.c.");
+ strcpy(vgrid[7], ".c1lllllll.x");
+ strcpy(vgrid[8], "x..llllll.c.");
+ strcpy(vgrid[9], ".c...l1l...x");
+ strcpy(vgrid[10], "x.c.c.c.c.c.");
+ strcpy(vgrid[11], ".x.x.x.x.x.x");
+
+ mons_array[0] = MONS_MOLTEN_GARGOYLE;
+
+ return MAP_NORTH;
+}
+
+
+static char minivault_9(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // evil zoo
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], ".==========.");
+ strcpy(vgrid[2], ".==========.");
+ strcpy(vgrid[3], ".==========.");
+ strcpy(vgrid[4], ".===8888===.");
+ strcpy(vgrid[5], ".===8998===.");
+ strcpy(vgrid[6], ".===8998===.");
+ strcpy(vgrid[7], ".===8888===.");
+ strcpy(vgrid[8], ".==========.");
+ strcpy(vgrid[9], ".==========.");
+ strcpy(vgrid[10], ".==========.");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+
+}
+
+
+static char minivault_10(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], ".xxxx..xxxx.");
+ strcpy(vgrid[2], ".x**x..x**x.");
+ strcpy(vgrid[3], ".x**+..+**x.");
+ strcpy(vgrid[4], ".xx+x..x+xx.");
+ strcpy(vgrid[5], "............");
+ strcpy(vgrid[6], "............");
+ strcpy(vgrid[7], ".xx+x..x+xx.");
+ strcpy(vgrid[8], ".x**+..+**x.");
+ strcpy(vgrid[9], ".x**x..x**x.");
+ strcpy(vgrid[10], ".xxxx..xxxx.");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+}
+
+
+static char minivault_11(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // multicoloured onion
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], ".+xxxxxxxx+.");
+ strcpy(vgrid[2], ".x........x.");
+ strcpy(vgrid[3], ".x.+cccc+.x.");
+ strcpy(vgrid[4], ".x.c....c.x.");
+ strcpy(vgrid[5], ".x.c.bb.c.x.");
+ strcpy(vgrid[6], ".x.c.bb.c.x.");
+ strcpy(vgrid[7], ".x.c....c.x.");
+ strcpy(vgrid[8], ".x.+cccc+.x.");
+ strcpy(vgrid[9], ".x........x.");
+ strcpy(vgrid[10], ".+xxxxxxxx+.");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+}
+
+
+static char minivault_12(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // closed box minivault
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], ".xxxxxxxxxx.");
+ strcpy(vgrid[2], ".x>9$9$9$<x.");
+ strcpy(vgrid[3], ".x.$9$9$.$x.");
+ strcpy(vgrid[4], ".x$.****$.x.");
+ strcpy(vgrid[5], ".x.$*||*.$x.");
+ strcpy(vgrid[6], ".x$.*||*$.x.");
+ strcpy(vgrid[7], ".x.$****.$x.");
+ strcpy(vgrid[8], ".x$9$9$9$.x.");
+ strcpy(vgrid[9], ".x<$9$9$9>x.");
+ strcpy(vgrid[10], ".xxxxxxxxxx.");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+}
+
+
+static char minivault_13(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // little trap spiral
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], ".xxxxxxxxxx.");
+ strcpy(vgrid[2], ".=.^x..=.9x.");
+ strcpy(vgrid[3], ".x.$=.^x..x.");
+ strcpy(vgrid[4], ".xxxxxxxx=x.");
+ strcpy(vgrid[5], ".x.8+|0x8.x.");
+ strcpy(vgrid[6], ".x8$x.|x..x.");
+ strcpy(vgrid[7], ".xx=xxxx=xx.");
+ strcpy(vgrid[8], ".x.9=^.x..x.");
+ strcpy(vgrid[9], ".x..x.^=9.x.");
+ strcpy(vgrid[10], ".xxxxxxxxxx.");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+}
+
+
+static char minivault_14(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // water cross
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], ".wwwww.wwww.");
+ strcpy(vgrid[2], ".wwwww.wwww.");
+ strcpy(vgrid[3], ".wwwww.wwww.");
+ strcpy(vgrid[4], ".wwwww.wwww.");
+ strcpy(vgrid[5], ".......wwww.");
+ strcpy(vgrid[6], ".wwww.......");
+ strcpy(vgrid[7], ".wwww.wwwww.");
+ strcpy(vgrid[8], ".wwww.wwwww.");
+ strcpy(vgrid[9], ".wwww.wwwww.");
+ strcpy(vgrid[10], ".wwww.wwwww.");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+}
+
+static char minivault_15(char vgrid[81][81], FixedVector<int, 7>& mons_array) /* lava pond */
+{
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], "............");
+ strcpy(vgrid[2], "....lll.....");
+ strcpy(vgrid[3], "...vvlvv....");
+ strcpy(vgrid[4], "..lv|*|vl...");
+ strcpy(vgrid[5], "..ll*S*ll...");
+ strcpy(vgrid[6], "..lv|*|vl...");
+ strcpy(vgrid[7], "...vvlvv....");
+ strcpy(vgrid[8], "....lll.....");
+ strcpy(vgrid[9], "............");
+ strcpy(vgrid[10], "............");
+ strcpy(vgrid[11], "............");
+
+ return 1;
+}
+
+
+static char minivault_16(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // lava pond
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], "............");
+ strcpy(vgrid[2], "............");
+ strcpy(vgrid[3], "............");
+ strcpy(vgrid[4], "............");
+ strcpy(vgrid[5], "............");
+ strcpy(vgrid[6], "......S.....");
+ strcpy(vgrid[7], "............");
+ strcpy(vgrid[8], "............");
+ strcpy(vgrid[9], "............");
+ strcpy(vgrid[10], "............");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+}
+
+
+static char minivault_17(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // lava pond
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], "............");
+ strcpy(vgrid[2], "............");
+ strcpy(vgrid[3], "............");
+ strcpy(vgrid[4], "............");
+ strcpy(vgrid[5], ".....F......");
+ strcpy(vgrid[6], "............");
+ strcpy(vgrid[7], "............");
+ strcpy(vgrid[8], "............");
+ strcpy(vgrid[9], "............");
+ strcpy(vgrid[10], "............");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+}
+
+
+static char minivault_18(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // lava pond
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], "............");
+ strcpy(vgrid[2], "............");
+ strcpy(vgrid[3], "............");
+ strcpy(vgrid[4], "............");
+ strcpy(vgrid[5], ".....H......");
+ strcpy(vgrid[6], "............");
+ strcpy(vgrid[7], "............");
+ strcpy(vgrid[8], "............");
+ strcpy(vgrid[9], "............");
+ strcpy(vgrid[10], "............");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+}
+
+
+static char minivault_19(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], ".xx......xx.");
+ strcpy(vgrid[2], ".xxx....xxx.");
+ strcpy(vgrid[3], "..xxx..xxx..");
+ strcpy(vgrid[4], "...xxxxxx...");
+ strcpy(vgrid[5], "....xxxx....");
+ strcpy(vgrid[6], "....xxxx....");
+ strcpy(vgrid[7], "...xxxxxx...");
+ strcpy(vgrid[8], "..xxx..xxx..");
+ strcpy(vgrid[9], ".xxx....xxx.");
+ strcpy(vgrid[10], ".xx......xx.");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+}
+
+
+static char minivault_20(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // lava pond
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], ".xxxx..xxxx.");
+ strcpy(vgrid[2], ".x........x.");
+ strcpy(vgrid[3], ".x..xxxx..x.");
+ strcpy(vgrid[4], ".x.x....x.x.");
+ strcpy(vgrid[5], "...x.x9.x...");
+ strcpy(vgrid[6], "...x.9x.x...");
+ strcpy(vgrid[7], ".x.x....x.x.");
+ strcpy(vgrid[8], ".x..xxxx..x.");
+ strcpy(vgrid[9], ".x........x.");
+ strcpy(vgrid[10], ".xxxx..xxxx.");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+}
+
+
+static char minivault_21(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], ".^xxxxxxxx^.");
+ strcpy(vgrid[2], ".x........x.");
+ strcpy(vgrid[3], ".x.cccccc.x.");
+ strcpy(vgrid[4], ".x.c|..<c.x.");
+ strcpy(vgrid[5], ".x.c.**.c.x.");
+ strcpy(vgrid[6], ".x.c.**.c.x.");
+ strcpy(vgrid[7], ".x.c>..|c.x.");
+ strcpy(vgrid[8], ".x.cccccc.x.");
+ strcpy(vgrid[9], ".x........x.");
+ strcpy(vgrid[10], ".^xxxxxxxx^.");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+
+}
+
+
+static char minivault_22(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], ".....xx.....");
+ strcpy(vgrid[2], "...xxxxxx...");
+ strcpy(vgrid[3], "..x^x..x^x..");
+ strcpy(vgrid[4], "..xx.xx.xx..");
+ strcpy(vgrid[5], ".xx.x$$x.xx.");
+ strcpy(vgrid[6], ".xx.x$$x.xx.");
+ strcpy(vgrid[7], "..xx.xx.xx..");
+ strcpy(vgrid[8], "..x^x..x^x..");
+ strcpy(vgrid[9], "...xxxxxx...");
+ strcpy(vgrid[10], ".....xx.....");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+
+}
+
+
+static char minivault_23(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "x.x.x.x.x.x.");
+ strcpy(vgrid[1], ".x.x.x.x.x.x");
+ strcpy(vgrid[2], "x.x.x.x.x.x.");
+ strcpy(vgrid[3], ".x.x.x.x.x.x");
+ strcpy(vgrid[4], "x.x.x.x.x.x.");
+ strcpy(vgrid[5], ".x.x.x.x.x.x");
+ strcpy(vgrid[6], "x.x.x.x.x.x.");
+ strcpy(vgrid[7], ".x.x.x.x.x.x");
+ strcpy(vgrid[8], "x.x.x.x.x.x.");
+ strcpy(vgrid[9], ".x.x.x.x.x.x");
+ strcpy(vgrid[10], "x.x.x.x.x.x.");
+ strcpy(vgrid[11], ".x.x.x.x.x.x");
+
+ return MAP_NORTH;
+
+}
+
+
+static char minivault_24(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], "....xxxx....");
+ strcpy(vgrid[2], "....xxxx....");
+ strcpy(vgrid[3], "....xxxx....");
+ strcpy(vgrid[4], ".xxxx.x.xxx.");
+ strcpy(vgrid[5], ".xxx.x.xxxx.");
+ strcpy(vgrid[6], ".xxxx.x.xxx.");
+ strcpy(vgrid[7], ".xxx.x.xxxx.");
+ strcpy(vgrid[8], "....xxxx....");
+ strcpy(vgrid[9], "....xxxx....");
+ strcpy(vgrid[10], "....xxxx....");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+
+}
+
+
+static char minivault_25(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], ".xx+xxxxxxx.");
+ strcpy(vgrid[2], ".x........x.");
+ strcpy(vgrid[3], ".x........+.");
+ strcpy(vgrid[4], ".x........x.");
+ strcpy(vgrid[5], ".x........x.");
+ strcpy(vgrid[6], ".x........x.");
+ strcpy(vgrid[7], ".x........x.");
+ strcpy(vgrid[8], ".+........x.");
+ strcpy(vgrid[9], ".x........x.");
+ strcpy(vgrid[10], ".xxxxxxx+xx.");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+
+}
+
+
+static char minivault_26(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "c..........c");
+ strcpy(vgrid[1], ".c...cc...c.");
+ strcpy(vgrid[2], "..c..cc..c..");
+ strcpy(vgrid[3], "...c....c...");
+ strcpy(vgrid[4], "....c..c....");
+ strcpy(vgrid[5], ".cc..cc..cc.");
+ strcpy(vgrid[6], ".cc..cc..cc.");
+ strcpy(vgrid[7], "....c..c....");
+ strcpy(vgrid[8], "...c....c...");
+ strcpy(vgrid[9], "..c..cc..c..");
+ strcpy(vgrid[10], ".c...cc...c.");
+ strcpy(vgrid[11], "c..........c");
+
+ return MAP_NORTH;
+
+}
+
+
+static char minivault_27(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], ".x.xxxxxxxx.");
+ strcpy(vgrid[2], ".x........x.");
+ strcpy(vgrid[3], ".xxxxxxxx.x.");
+ strcpy(vgrid[4], ".x........x.");
+ strcpy(vgrid[5], ".x.xxxxxxxx.");
+ strcpy(vgrid[6], ".x........x.");
+ strcpy(vgrid[7], ".xxxxxxxx.x.");
+ strcpy(vgrid[8], ".x........x.");
+ strcpy(vgrid[9], ".x.xxxxxxxx.");
+ strcpy(vgrid[10], "............");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+
+}
+
+
+static char minivault_28(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], ".xxxx.xxxx..");
+ strcpy(vgrid[2], ".x.......x..");
+ strcpy(vgrid[3], ".x..999..x..");
+ strcpy(vgrid[4], ".x.9...9.x..");
+ strcpy(vgrid[5], "...9.I.9....");
+ strcpy(vgrid[6], ".x.9...9.x..");
+ strcpy(vgrid[7], ".x..999..x..");
+ strcpy(vgrid[8], ".x.......x..");
+ strcpy(vgrid[9], ".xxxx.xxxx..");
+ strcpy(vgrid[10], "............");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+
+}
+
+
+static char minivault_29(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+
+ strcpy(vgrid[0], ".3......3...");
+ strcpy(vgrid[1], "...x.xx.x.2.");
+ strcpy(vgrid[2], ".xxx2xxxxx..");
+ strcpy(vgrid[3], ".xxxx42xxx2.");
+ strcpy(vgrid[4], ".2xx243432x3");
+ strcpy(vgrid[5], ".xx421424xx.");
+ strcpy(vgrid[6], "3xx423242x..");
+ strcpy(vgrid[7], ".x2x3243xxx.");
+ strcpy(vgrid[8], ".x2xx42422x.");
+ strcpy(vgrid[9], "..xxxxxxxx2.");
+ strcpy(vgrid[10], "...x2xxxx3..");
+ strcpy(vgrid[11], ".3.......33.");
+
+ mons_array[0] = MONS_QUEEN_ANT;
+ mons_array[1] = MONS_SOLDIER_ANT;
+ mons_array[2] = MONS_GIANT_ANT;
+ mons_array[3] = MONS_ANT_LARVA;
+
+ return MAP_NORTH;
+
+}
+
+
+static char minivault_30(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // lava pond
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], "............");
+ strcpy(vgrid[2], "............");
+ strcpy(vgrid[3], "............");
+ strcpy(vgrid[4], "............");
+ strcpy(vgrid[5], ".....T......");
+ strcpy(vgrid[6], "............");
+ strcpy(vgrid[7], "............");
+ strcpy(vgrid[8], "............");
+ strcpy(vgrid[9], "............");
+ strcpy(vgrid[10], "............");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+
+}
+
+
+static char minivault_31(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // lava pond
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], "............");
+ strcpy(vgrid[2], "............");
+ strcpy(vgrid[3], "............");
+ strcpy(vgrid[4], "............");
+ strcpy(vgrid[5], ".....T......");
+ strcpy(vgrid[6], "............");
+ strcpy(vgrid[7], "............");
+ strcpy(vgrid[8], "............");
+ strcpy(vgrid[9], "............");
+ strcpy(vgrid[10], "............");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+
+}
+
+
+static char minivault_32(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // lava pond
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], "............");
+ strcpy(vgrid[2], "............");
+ strcpy(vgrid[3], "............");
+ strcpy(vgrid[4], "............");
+ strcpy(vgrid[5], ".....U......");
+ strcpy(vgrid[6], "............");
+ strcpy(vgrid[7], "............");
+ strcpy(vgrid[8], "............");
+ strcpy(vgrid[9], "............");
+ strcpy(vgrid[10], "............");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+
+}
+
+
+static char minivault_33(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // lava pond
+ UNUSED( mons_array );
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], "............");
+ strcpy(vgrid[2], "............");
+ strcpy(vgrid[3], "............");
+ strcpy(vgrid[4], "............");
+ strcpy(vgrid[5], ".....V......");
+ strcpy(vgrid[6], "............");
+ strcpy(vgrid[7], "............");
+ strcpy(vgrid[8], "............");
+ strcpy(vgrid[9], "............");
+ strcpy(vgrid[10], "............");
+ strcpy(vgrid[11], "............");
+
+ return MAP_NORTH;
+
+}
+
+static char minivault_34(char vgrid[81][81], FixedVector<int, 7>& mons_array, bool orientation)
+{
+ //jmf: multi-god temple thing
+ UNUSED( mons_array );
+ int i, di;
+
+ if ( orientation )
+ {
+ i = 0;
+ di = +1;
+ }
+ else
+ {
+ i = 11;
+ di = -1;
+ }
+
+ for (int c=0; c <= 11; c++, i += di)
+ {
+ strcpy(vgrid[i], "............");
+ strcpy(vgrid[i], ".=xxxxxxxx=.");
+ strcpy(vgrid[i], ".x9......9x.");
+ strcpy(vgrid[i], ".xT......Tx.");
+ strcpy(vgrid[i], ".x..C..C..x.");
+ strcpy(vgrid[i], ".xT......Tx.");
+ strcpy(vgrid[i], ".xxxxxxxxxx.");
+ strcpy(vgrid[i], ".xxx$$$$xxx.");
+ strcpy(vgrid[i], ".xx8....8xx.");
+ strcpy(vgrid[i], "..xx....xx..");
+ strcpy(vgrid[i], "...xG..Gx...");
+ strcpy(vgrid[i], "............");
+ }
+
+ return MAP_NORTH;
+}
+
+static char minivault_34_a(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+ return minivault_34(vgrid, mons_array, true);
+}
+
+static char minivault_34_b(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+ return minivault_34(vgrid, mons_array, false);
+}
+
+static char minivault_35(char vgrid[81][81], FixedVector<int, 7>& mons_array, bool orientation)
+{
+ UNUSED( mons_array );
+ //jmf: another multi-god temple thing
+ int i, di;
+
+ if (orientation)
+ {
+ i = 0;
+ di = +1;
+ }
+ else
+ {
+ i = 11;
+ di = -1;
+ }
+
+ for (int c=0; c <= 11; c++, i += di)
+ {
+ strcpy(vgrid[i], "............");
+ strcpy(vgrid[i], "..vvvvvvvv..");
+ strcpy(vgrid[i], ".vv......vv.");
+ strcpy(vgrid[i], ".v..x..x..v.");
+ strcpy(vgrid[i], ".v.Cx..xC.v.");
+ strcpy(vgrid[i], ".v..x..x..v.");
+ strcpy(vgrid[i], ".vT8x..x8Tv.");
+ strcpy(vgrid[i], ".vvvx==xvvv.");
+ strcpy(vgrid[i], "...Gx99xG...");
+ strcpy(vgrid[i], "...+*99*+...");
+ strcpy(vgrid[i], "...GxxxxG...");
+ strcpy(vgrid[i], "............");
+ }
+
+ return MAP_NORTH;
+}
+
+static char minivault_35_a(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+ return minivault_35(vgrid, mons_array, true);
+}
+
+static char minivault_35_b(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+ return minivault_35(vgrid, mons_array, false);
+}
+
+
+static char rand_demon_1(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], ".xx.xx.x.xx.");
+ strcpy(vgrid[2], "..x.x..x.x..");
+ strcpy(vgrid[3], "..x.x..x.x..");
+ strcpy(vgrid[4], "..x.x..x.x..");
+ strcpy(vgrid[5], "..x.x..x.x..");
+ strcpy(vgrid[6], "..x.x1.x.x..");
+ strcpy(vgrid[7], "..x.x..x.x..");
+ strcpy(vgrid[8], "..x.x..x.x..");
+ strcpy(vgrid[9], "..x.x..x.x..");
+ strcpy(vgrid[10], ".xx.x.xx.xx.");
+ strcpy(vgrid[11], "............");
+
+ mons_array[0] = MONS_PANDEMONIUM_DEMON;
+ mons_array[1] = RANDOM_MONSTER;
+ mons_array[2] = RANDOM_MONSTER;
+ mons_array[3] = RANDOM_MONSTER;
+ mons_array[4] = RANDOM_MONSTER;
+ mons_array[5] = RANDOM_MONSTER;
+
+ return MAP_NORTH;
+}
+
+
+static char rand_demon_2(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], ".xxxxxxxx3x.");
+ strcpy(vgrid[2], ".3.....xx.x.");
+ strcpy(vgrid[3], ".xxxxxx4x.x.");
+ strcpy(vgrid[4], ".xx4x..xx.x.");
+ strcpy(vgrid[5], ".x.x.22.x.x.");
+ strcpy(vgrid[6], ".x.x.12.x.x.");
+ strcpy(vgrid[7], ".x.xx..x4xx.");
+ strcpy(vgrid[8], ".x.x4xxxxxx.");
+ strcpy(vgrid[9], ".x.xx.....3.");
+ strcpy(vgrid[10], ".x3xxxxxxxx.");
+ strcpy(vgrid[11], "............");
+
+ mons_array[0] = MONS_PANDEMONIUM_DEMON;
+ mons_array[1] = summon_any_demon(DEMON_GREATER);
+ mons_array[2] = summon_any_demon(DEMON_COMMON);
+ mons_array[3] = summon_any_demon(DEMON_COMMON);
+ mons_array[4] = RANDOM_MONSTER;
+ mons_array[5] = RANDOM_MONSTER;
+
+ return MAP_NORTH;
+}
+
+
+static char rand_demon_3(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], ".x.x.x3x.x..");
+ strcpy(vgrid[2], "..x.x3x3x.x.");
+ strcpy(vgrid[3], ".x.x.x2x.x..");
+ strcpy(vgrid[4], "..x3x2x2x3x.");
+ strcpy(vgrid[5], ".x3x2x1x2x3.");
+ strcpy(vgrid[6], "..x3x2x2x3x.");
+ strcpy(vgrid[7], ".x.x.x2x3x..");
+ strcpy(vgrid[8], "..x.x3x3x.x.");
+ strcpy(vgrid[9], ".x.x.x3x.x..");
+ strcpy(vgrid[10], "..x.x.x.x.x.");
+ strcpy(vgrid[11], "............");
+
+ mons_array[0] = MONS_PANDEMONIUM_DEMON;
+ mons_array[1] = summon_any_demon(DEMON_COMMON);
+ mons_array[2] = summon_any_demon(DEMON_COMMON);
+
+ return MAP_NORTH;
+}
+
+
+static char rand_demon_4(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+ //jmf: all 3s below were 1s -- may have been bug
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], ".xxxxxxxxx..");
+ strcpy(vgrid[2], ".x$=*=3=|x..");
+ strcpy(vgrid[3], ".xxxxxxx=x..");
+ strcpy(vgrid[4], ".x2=3=2x|x..");
+ strcpy(vgrid[5], ".x=xxxxx=x..");
+ strcpy(vgrid[6], ".x3=*x1=Px..");
+ strcpy(vgrid[7], ".x=x=xxxxx..");
+ strcpy(vgrid[8], ".x*x2=3=2=..");
+ strcpy(vgrid[9], ".xxxxxxxxx..");
+ strcpy(vgrid[10], "............");
+ strcpy(vgrid[11], "............");
+
+ mons_array[0] = MONS_PANDEMONIUM_DEMON;
+ mons_array[1] = summon_any_demon(random2(3));
+ mons_array[2] = summon_any_demon(random2(3));
+
+ return MAP_NORTH;
+
+}
+
+
+static char rand_demon_5(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{ // obviously possible to get stuck - too bad (should've come prepared)
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], "...xxxxxx...");
+ strcpy(vgrid[2], "..xx....xx..");
+ strcpy(vgrid[3], ".xx......xx.");
+ strcpy(vgrid[4], ".x..3232..x.");
+ strcpy(vgrid[5], ".x..2|P3..x.");
+ strcpy(vgrid[6], ".x..3P|2..x.");
+ strcpy(vgrid[7], ".x..2123..x.");
+ strcpy(vgrid[8], ".xx......xx.");
+ strcpy(vgrid[9], "..xx....xx..");
+ strcpy(vgrid[10], "...xxxxxx...");
+ strcpy(vgrid[11], "............");
+
+ mons_array[0] = MONS_PANDEMONIUM_DEMON;
+ mons_array[1] = summon_any_demon(random2(3));
+ mons_array[2] = summon_any_demon(random2(3));
+
+ return MAP_NORTH;
+
+}
+
+
+static char rand_demon_6(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], "............");
+ strcpy(vgrid[2], "......2.....");
+ strcpy(vgrid[3], "............");
+ strcpy(vgrid[4], ".3..........");
+ strcpy(vgrid[5], "..........2.");
+ strcpy(vgrid[6], ".....1......");
+ strcpy(vgrid[7], "............");
+ strcpy(vgrid[8], "............");
+ strcpy(vgrid[9], ".2.......3..");
+ strcpy(vgrid[10], "............");
+ strcpy(vgrid[11], "............");
+
+ mons_array[0] = MONS_PANDEMONIUM_DEMON;
+ mons_array[1] = summon_any_demon(random2(3));
+ mons_array[2] = summon_any_demon(random2(3));
+
+ return MAP_NORTH;
+
+}
+
+
+static char rand_demon_7(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], ".xxx....xxx.");
+ strcpy(vgrid[2], ".x|xx=xxx|x.");
+ strcpy(vgrid[3], ".xx=....=xx.");
+ strcpy(vgrid[4], "..x.x==x.x..");
+ strcpy(vgrid[5], "..x.=12=.=..");
+ strcpy(vgrid[6], "..=.=23=.x..");
+ strcpy(vgrid[7], "..x.x==x.x..");
+ strcpy(vgrid[8], ".xx=....=xx.");
+ strcpy(vgrid[9], ".x|xxx=xx|x.");
+ strcpy(vgrid[10], ".xxx....xxx.");
+ strcpy(vgrid[11], "............");
+
+ mons_array[0] = MONS_PANDEMONIUM_DEMON;
+ mons_array[1] = summon_any_demon(random2(3));
+ mons_array[2] = summon_any_demon(DEMON_GREATER);
+
+ return MAP_NORTH;
+
+}
+
+
+static char rand_demon_8(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], "....xxxxxxx.");
+ strcpy(vgrid[2], "..xxx....1x.");
+ strcpy(vgrid[3], ".xx..2....x.");
+ strcpy(vgrid[4], ".x........x.");
+ strcpy(vgrid[5], ".xx.......x.");
+ strcpy(vgrid[6], "..xx33..2.x.");
+ strcpy(vgrid[7], "....33...xx.");
+ strcpy(vgrid[8], ".....x...x..");
+ strcpy(vgrid[9], "..F..xx.xx..");
+ strcpy(vgrid[10], "......xxx...");
+ strcpy(vgrid[11], "............");
+
+ mons_array[0] = MONS_PANDEMONIUM_DEMON;
+ mons_array[1] = summon_any_demon(DEMON_GREATER);
+ mons_array[2] = summon_any_demon(random2(3));
+
+ return MAP_NORTH;
+
+}
+
+
+static char rand_demon_9(char vgrid[81][81], FixedVector<int, 7>& mons_array)
+{
+
+ strcpy(vgrid[0], "............");
+ strcpy(vgrid[1], ".xxxxxxxxxx.");
+ strcpy(vgrid[2], ".x2=3=3=3xx.");
+ strcpy(vgrid[3], ".x=xxxxxx2x.");
+ strcpy(vgrid[4], ".x3x^^^^x=x.");
+ strcpy(vgrid[5], ".x=x^P^^x2x.");
+ strcpy(vgrid[6], ".x3x^^1^x=x.");
+ strcpy(vgrid[7], ".x=x^^^^x3x.");
+ strcpy(vgrid[8], ".x2xxxx=x=x.");
+ strcpy(vgrid[9], ".xx2=2=3x3x.");
+ strcpy(vgrid[10], ".xxxxxxxx=x.");
+ strcpy(vgrid[11], "............");
+
+ mons_array[0] = MONS_PANDEMONIUM_DEMON;
+ mons_array[1] = summon_any_demon(random2(3));
+ mons_array[2] = summon_any_demon(DEMON_GREATER);
+
+ return MAP_NORTH;
+
+}
diff --git a/trunk/source/maps.h b/trunk/source/maps.h
new file mode 100644
index 0000000000..e2ce11af80
--- /dev/null
+++ b/trunk/source/maps.h
@@ -0,0 +1,25 @@
+/*
+ * File: maps.cc
+ * Summary: Functions used to create vaults.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef MAPS_H
+#define MAPS_H
+
+#include "FixVec.h"
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: dungeon
+ * *********************************************************************** */
+char vault_main(char vgrid[81][81], FixedVector<int, 7>& mons_array, int vault_force, int many_many);
+
+
+#endif
diff --git a/trunk/source/message.cc b/trunk/source/message.cc
new file mode 100644
index 0000000000..5f7ad30998
--- /dev/null
+++ b/trunk/source/message.cc
@@ -0,0 +1,526 @@
+/*
+ * File: message.cc
+ * Summary: Functions used to print messages.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <3> 5/20/99 BWR Extended screen lines support
+ * <2> 5/08/99 JDJ mpr takes a const char* instead of a char array.
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "message.h"
+#include "religion.h"
+
+#include <string.h>
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#include "externs.h"
+
+#include "macro.h"
+#include "stuff.h"
+#include "view.h"
+
+
+// circular buffer for keeping past messages
+message_item Store_Message[ NUM_STORED_MESSAGES ]; // buffer of old messages
+int Next_Message = 0; // end of messages
+
+char Message_Line = 0; // line of next (previous?) message
+
+static char god_message_altar_colour( char god )
+{
+ int rnd;
+
+ switch (god)
+ {
+ case GOD_SHINING_ONE:
+ return (YELLOW);
+
+ case GOD_ZIN:
+ return (WHITE);
+
+ case GOD_ELYVILON:
+ return (LIGHTBLUE); // really, LIGHTGREY but that's plain text
+
+ case GOD_OKAWARU:
+ return (CYAN);
+
+ case GOD_YREDELEMNUL:
+ return (coinflip() ? DARKGREY : RED);
+
+ case GOD_KIKUBAAQUDGHA:
+ return (DARKGREY);
+
+ case GOD_XOM:
+ return (random2(15) + 1);
+
+ case GOD_VEHUMET:
+ rnd = random2(3);
+ return ((rnd == 0) ? LIGHTMAGENTA :
+ (rnd == 1) ? LIGHTRED
+ : LIGHTBLUE);
+
+ case GOD_MAKHLEB:
+ rnd = random2(3);
+ return ((rnd == 0) ? RED :
+ (rnd == 1) ? LIGHTRED
+ : YELLOW);
+
+ case GOD_TROG:
+ return (RED);
+
+ case GOD_NEMELEX_XOBEH:
+ return (LIGHTMAGENTA);
+
+ case GOD_SIF_MUNA:
+ return (BLUE);
+
+ case GOD_NO_GOD:
+ default:
+ return(YELLOW);
+ }
+}
+
+#ifdef USE_COLOUR_MESSAGES
+
+// returns a colour or MSGCOL_MUTED
+static char channel_to_colour( int channel, int param )
+{
+ char ret;
+
+ switch (Options.channels[ channel ])
+ {
+ case MSGCOL_PLAIN:
+ // note that if the plain channel is muted, then we're protecting
+ // the player from having that spead to other other channels here.
+ // The intent of plain is to give non-coloured messages, not to
+ // supress them.
+ if (Options.channels[ MSGCH_PLAIN ] >= MSGCOL_DEFAULT)
+ ret = LIGHTGREY;
+ else
+ ret = Options.channels[ MSGCH_PLAIN ];
+ break;
+
+ case MSGCOL_DEFAULT:
+ case MSGCOL_ALTERNATE:
+ switch (channel)
+ {
+ case MSGCH_GOD:
+ ret = (Options.channels[ channel ] == MSGCOL_DEFAULT)
+ ? god_colour( param )
+ : god_message_altar_colour( param );
+ break;
+
+ case MSGCH_DURATION:
+ ret = LIGHTBLUE;
+ break;
+
+ case MSGCH_DANGER:
+ ret = RED;
+ break;
+
+ case MSGCH_WARN:
+ ret = LIGHTRED;
+ break;
+
+ case MSGCH_FOOD:
+ ret = YELLOW;
+ break;
+
+ case MSGCH_INTRINSIC_GAIN:
+ ret = GREEN;
+ break;
+
+ case MSGCH_RECOVERY:
+ ret = LIGHTGREEN;
+ break;
+
+ case MSGCH_TALK:
+ ret = WHITE;
+ break;
+
+ case MSGCH_MONSTER_SPELL:
+ case MSGCH_MONSTER_ENCHANT:
+ ret = LIGHTMAGENTA;
+ break;
+
+ case MSGCH_MONSTER_DAMAGE:
+ ret = ((param == MDAM_DEAD) ? RED :
+ (param >= MDAM_HORRIBLY_DAMAGED) ? LIGHTRED :
+ (param >= MDAM_MODERATELY_DAMAGED) ? YELLOW
+ : LIGHTGREY);
+ break;
+
+ case MSGCH_PROMPT:
+ ret = CYAN;
+ break;
+
+ case MSGCH_DIAGNOSTICS:
+ ret = DARKGREY; // makes is easier to ignore at times -- bwr
+ break;
+
+ case MSGCH_PLAIN:
+ case MSGCH_ROTTEN_MEAT:
+ case MSGCH_EQUIPMENT:
+ default:
+ ret = LIGHTGREY;
+ break;
+ }
+ break;
+
+ case MSGCOL_MUTED:
+ ret = MSGCOL_MUTED;
+ break;
+
+ default:
+ // Setting to a specific colour is handled here, special
+ // cases should be handled above.
+ if (channel == MSGCH_MONSTER_DAMAGE)
+ {
+ // a special case right now for monster damage (at least until
+ // the init system is improved)... selecting a specific
+ // colour here will result in only the death messages coloured
+ if (param == MDAM_DEAD)
+ ret = Options.channels[ channel ];
+ else if (Options.channels[ MSGCH_PLAIN ] >= MSGCOL_DEFAULT)
+ ret = LIGHTGREY;
+ else
+ ret = Options.channels[ MSGCH_PLAIN ];
+ }
+ else
+ ret = Options.channels[ channel ];
+ break;
+ }
+
+ return (ret);
+}
+
+#else // don't use colour messages
+
+static char channel_to_colour( int channel, int param )
+{
+ return (LIGHTGREY);
+}
+
+#endif
+
+void mpr(const char *inf, int channel, int param)
+{
+ char info2[80];
+
+ int colour = channel_to_colour( channel, param );
+ if (colour == MSGCOL_MUTED)
+ return;
+
+ you.running = 0;
+ flush_input_buffer( FLUSH_ON_MESSAGE );
+
+#ifdef DOS_TERM
+ window(1, 1, 80, 25);
+#endif
+
+ textcolor(LIGHTGREY);
+
+ const int num_lines = get_number_of_lines();
+
+ if (Message_Line == num_lines - 18) // ( Message_Line == 8 )
+ more();
+
+ gotoxy( (Options.delay_message_clear) ? 2 : 1, Message_Line + 18 );
+ strncpy(info2, inf, 78);
+ info2[78] = 0;
+
+ textcolor( colour );
+ cprintf(info2);
+ //
+ // reset colour
+ textcolor(LIGHTGREY);
+
+ Message_Line++;
+
+ if (Options.delay_message_clear
+ && channel != MSGCH_PROMPT
+ && Message_Line == num_lines - 18)
+ {
+ more();
+ }
+
+ // equipment lists just waste space in the message recall
+ if (channel != MSGCH_EQUIPMENT)
+ {
+ /* Put the message into Store_Message, and move the '---' line forward */
+ Store_Message[ Next_Message ].text = inf;
+ Store_Message[ Next_Message ].channel = channel;
+ Store_Message[ Next_Message ].param = param;
+ Next_Message++;
+
+ if (Next_Message >= NUM_STORED_MESSAGES)
+ Next_Message = 0;
+ }
+} // end mpr()
+
+bool any_messages(void)
+{
+ return (Message_Line > 0);
+}
+
+void mesclr( bool force )
+{
+ // if no messages, return.
+ if (!any_messages())
+ return;
+
+ if (!force && Options.delay_message_clear)
+ {
+ gotoxy( 1, Message_Line + 18 );
+ textcolor( channel_to_colour( MSGCH_PLAIN, 0 ) );
+ cprintf( ">" );
+ return;
+ }
+
+ // turn cursor off -- avoid 'cursor dance'
+ _setcursortype(_NOCURSOR);
+
+#ifdef DOS_TERM
+ window(1, 18, 78, 25);
+ clrscr();
+ window(1, 1, 80, 25);
+#endif
+
+#ifdef PLAIN_TERM
+ int startLine = 18;
+
+ gotoxy(1, startLine);
+
+#ifdef LINUX
+ clear_to_end_of_screen();
+#else
+
+ int numLines = get_number_of_lines() - startLine + 1;
+ for (int i = 0; i < numLines; i++)
+ {
+ cprintf( " " );
+
+ if (i < numLines - 1)
+ {
+ cprintf(EOL);
+ }
+ }
+#endif
+#endif
+
+ // turn cursor back on
+ _setcursortype(_NORMALCURSOR);
+
+ Message_Line = 0;
+} // end mseclr()
+
+void more(void)
+{
+ char keypress = 0;
+
+#ifdef PLAIN_TERM
+ gotoxy( 2, get_number_of_lines() );
+#endif
+
+#ifdef DOS_TERM
+ window(1, 18, 80, 25);
+ gotoxy(2, 7);
+#endif
+
+ textcolor(LIGHTGREY);
+
+#ifdef DOS
+ cprintf(EOL);
+#endif
+ cprintf("--more--");
+
+ do
+ {
+ keypress = getch();
+ }
+ while (keypress != ' ' && keypress != '\r' && keypress != '\n');
+
+ mesclr( (Message_Line >= get_number_of_lines() - 18) );
+} // end more()
+
+void replay_messages(void)
+{
+ int win_start_line = 0;
+ unsigned char keyin;
+
+ bool full_buffer = true;
+ int num_msgs = NUM_STORED_MESSAGES;
+ int first_message = Next_Message;
+
+ const int num_lines = get_number_of_lines();
+
+ if (Store_Message[ NUM_STORED_MESSAGES - 1 ].text.length() == 0)
+ {
+ full_buffer = false;
+ first_message = 0;
+ num_msgs = Next_Message;
+ }
+
+ int last_message = Next_Message - 1;
+ if (last_message < 0)
+ last_message += NUM_STORED_MESSAGES;
+
+#ifdef DOS_TERM
+ char buffer[4800];
+
+ window(1, 1, 80, 25);
+ gettext(1, 1, 80, 25, buffer);
+#endif
+
+ // track back a screen's worth of messages from the end
+ win_start_line = Next_Message - (num_lines - 2);
+ if (win_start_line < 0)
+ {
+ if (full_buffer)
+ win_start_line += NUM_STORED_MESSAGES;
+ else
+ win_start_line = 0;
+ }
+
+ for(;;)
+ {
+ // turn cursor off
+ _setcursortype(_NOCURSOR);
+
+ clrscr();
+
+ gotoxy(1, 1);
+
+ for (int i = 0; i < num_lines - 2; i++)
+ {
+ // calculate line in circular buffer
+ int line = win_start_line + i;
+ if (line >= NUM_STORED_MESSAGES)
+ line -= NUM_STORED_MESSAGES;
+
+ // avoid wrap-around
+ if (line == first_message && i != 0)
+ break;
+
+ int colour = channel_to_colour( Store_Message[ line ].channel,
+ Store_Message[ line ].param );
+ if (colour == MSGCOL_MUTED)
+ continue;
+
+ textcolor( colour );
+
+#if DEBUG_DIAGNOSTICS
+ cprintf( "%d: %s", line, Store_Message[ line ].text.c_str() );
+#else
+ cprintf( Store_Message[ line ].text.c_str() );
+#endif
+
+ cprintf(EOL);
+ textcolor(LIGHTGREY);
+ }
+
+ // print a footer -- note: relative co-ordinates start at 1
+ int rel_start;
+ if (!full_buffer)
+ {
+ if (Next_Message == 0) // no messages!
+ rel_start = 0;
+ else
+ rel_start = win_start_line + 1;
+ }
+ else if (win_start_line >= first_message)
+ rel_start = win_start_line - first_message + 1;
+ else
+ rel_start = (win_start_line + NUM_STORED_MESSAGES) - first_message + 1;
+
+ int rel_end = rel_start + (num_lines - 2) - 1;
+ if (rel_end > num_msgs)
+ rel_end = num_msgs;
+
+ cprintf( "-------------------------------------------------------------------------------" );
+ cprintf(EOL);
+ cprintf( "<< Lines %d-%d of %d >>", rel_start, rel_end, num_msgs );
+
+ // turn cursor back on
+ _setcursortype(_NORMALCURSOR);
+
+ keyin = get_ch();
+
+ if ((full_buffer && NUM_STORED_MESSAGES > num_lines - 2)
+ || (!full_buffer && Next_Message > num_lines - 2))
+ {
+ int new_line;
+ int end_mark;
+
+ if (keyin == 'k' || keyin == '8' || keyin == '-')
+ {
+ new_line = win_start_line - (num_lines - 2);
+
+ // end_mark is equivalent to Next_Message, but
+ // is always less than win_start_line.
+ end_mark = first_message;
+ if (end_mark > win_start_line)
+ end_mark -= NUM_STORED_MESSAGES;
+
+ ASSERT( end_mark <= win_start_line );
+
+ if (new_line <= end_mark)
+ new_line = end_mark; // hit top
+
+ // handle wrap-around
+ if (new_line < 0)
+ {
+ if (full_buffer)
+ new_line += NUM_STORED_MESSAGES;
+ else
+ new_line = 0;
+ }
+ }
+ else if (keyin == 'j' || keyin == '2' || keyin == '+')
+ {
+ new_line = win_start_line + (num_lines - 2);
+
+ // as above, but since we're adding we want
+ // this mark to always be greater.
+ end_mark = last_message;
+ if (end_mark < win_start_line)
+ end_mark += NUM_STORED_MESSAGES;
+
+ ASSERT( end_mark >= win_start_line );
+
+ // hit bottom
+ if (new_line >= end_mark - (num_lines - 2))
+ new_line = end_mark - (num_lines - 2) + 1;
+
+ if (new_line >= NUM_STORED_MESSAGES)
+ new_line -= NUM_STORED_MESSAGES;
+ }
+ else
+ break;
+
+ win_start_line = new_line;
+ }
+ else
+ {
+ if (keyin != 'k' && keyin != '8' && keyin != '-'
+ && keyin != 'j' && keyin != '2' && keyin != '+')
+ {
+ break;
+ }
+ }
+ }
+
+
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+#endif
+
+ return;
+} // end replay_messages()
diff --git a/trunk/source/message.h b/trunk/source/message.h
new file mode 100644
index 0000000000..c5fdc5a312
--- /dev/null
+++ b/trunk/source/message.h
@@ -0,0 +1,77 @@
+/*
+ * File: message.cc
+ * Summary: Functions used to print messages.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <2> 5/08/99 JDJ mpr takes a const char* instead of a char array.
+ * <1> -/--/-- LRH Created
+ */
+
+#ifndef MESSAGE_H
+#define MESSAGE_H
+
+#include <string>
+
+#include "externs.h"
+
+struct message_item {
+ int channel; // message channel
+ int param; // param for channel (god, enchantment)
+ std::string text; // text of message
+};
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - acr - command - direct - effects - item_use -
+ * misc - player - spell - spl-book - spells1 - spells2 -
+ * spells3
+ * *********************************************************************** */
+void mesclr( bool force = false );
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - bang - beam - decks - fight - files - it_use3 -
+ * item_use - items - message - misc - ouch - player -
+ * religion - spell - spells - spells2 - spells3
+ * *********************************************************************** */
+void more(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - acr - bang - beam - chardump - command - debug -
+ * decks - direct - effects - fight - files - food - it_use2 -
+ * it_use3 - item_use - items - macro - misc - monplace -
+ * monstuff - mstuff2 - mutation - ouch - overmap - player -
+ * religion - shopping - skills - spell - spl-book - spells -
+ * spells1 - spells2 - spells3 - spells4 - stuff - transfor -
+ * view
+ * *********************************************************************** */
+void mpr(const char *inf, int channel = MSGCH_PLAIN, int param = 0);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void replay_messages(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - it_use3 - items - religion
+ * *********************************************************************** */
+void set_colour(char set_message_colour);
+
+
+// last updated 18mar2001 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+bool any_messages(void);
+
+#endif
diff --git a/trunk/source/misc.cc b/trunk/source/misc.cc
new file mode 100644
index 0000000000..85ebb311b7
--- /dev/null
+++ b/trunk/source/misc.cc
@@ -0,0 +1,1767 @@
+/*
+ * File: misc.cc
+ * Summary: Misc functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <3> 11/14/99 cdl evade with random40(ev) vice random2(ev)
+ * <2> 5/20/99 BWR Multi-user support, new berserk code.
+ * <1> -/--/-- LRH Created
+ */
+
+
+#include "AppHdr.h"
+#include "misc.h"
+
+#include <string.h>
+#if !(defined(__IBMCPP__) || defined(__BCPLUSPLUS__))
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#include "externs.h"
+
+#include "cloud.h"
+#include "delay.h"
+#include "fight.h"
+#include "files.h"
+#include "food.h"
+#include "it_use2.h"
+#include "items.h"
+#include "itemname.h"
+#include "lev-pand.h"
+#include "macro.h"
+#include "monplace.h"
+#include "mon-util.h"
+#include "monstuff.h"
+#include "ouch.h"
+#include "player.h"
+#include "shopping.h"
+#include "skills.h"
+#include "skills2.h"
+#include "spells3.h"
+#include "spl-cast.h"
+#include "stuff.h"
+#include "transfor.h"
+#include "view.h"
+
+
+bool scramble(void);
+bool trap_item(char base_type, char sub_type, char beam_x, char beam_y);
+static void dart_trap(bool trap_known, int trapped, struct bolt &pbolt, bool poison);
+
+// void place_chunks(int mcls, unsigned char rot_status, unsigned char chx,
+// unsigned char chy, unsigned char ch_col)
+void turn_corpse_into_chunks( item_def &item )
+{
+ const int mons_class = item.plus;
+ const int max_chunks = mons_weight( mons_class ) / 150;
+
+ ASSERT( item.base_type == OBJ_CORPSES );
+
+ item.base_type = OBJ_FOOD;
+ item.sub_type = FOOD_CHUNK;
+ item.quantity = 1 + random2( max_chunks );
+
+ item.quantity = stepdown_value( item.quantity, 4, 4, 12, 12 );
+
+ // seems to me that this should come about only
+ // after the corpse has been butchered ... {dlb}
+ if (monster_descriptor( mons_class, MDSC_LEAVES_HIDE ) && !one_chance_in(3))
+ {
+ int o = get_item_slot( 100 + random2(200) );
+ if (o == NON_ITEM)
+ return;
+
+ mitm[o].quantity = 1;
+
+ // these values are common to all: {dlb}
+ mitm[o].base_type = OBJ_ARMOUR;
+ mitm[o].plus = 0;
+ mitm[o].plus2 = 0;
+ mitm[o].special = 0;
+ mitm[o].flags = 0;
+ mitm[o].colour = mons_colour( mons_class );
+
+ // these values cannot be set by a reasonable formula: {dlb}
+ switch (mons_class)
+ {
+ case MONS_DRAGON:
+ mitm[o].sub_type = ARM_DRAGON_HIDE;
+ break;
+ case MONS_TROLL:
+ mitm[o].sub_type = ARM_TROLL_HIDE;
+ break;
+ case MONS_ICE_DRAGON:
+ mitm[o].sub_type = ARM_ICE_DRAGON_HIDE;
+ break;
+ case MONS_STEAM_DRAGON:
+ mitm[o].sub_type = ARM_STEAM_DRAGON_HIDE;
+ break;
+ case MONS_MOTTLED_DRAGON:
+ mitm[o].sub_type = ARM_MOTTLED_DRAGON_HIDE;
+ break;
+ case MONS_STORM_DRAGON:
+ mitm[o].sub_type = ARM_STORM_DRAGON_HIDE;
+ break;
+ case MONS_GOLDEN_DRAGON:
+ mitm[o].sub_type = ARM_GOLD_DRAGON_HIDE;
+ break;
+ case MONS_SWAMP_DRAGON:
+ mitm[o].sub_type = ARM_SWAMP_DRAGON_HIDE;
+ break;
+ default:
+ // future implementation {dlb}
+ mitm[o].sub_type = ARM_ANIMAL_SKIN;
+ break;
+ }
+
+ move_item_to_grid( &o, item.x, item.y );
+ }
+} // end place_chunks()
+
+void search_around(void)
+{
+ char srx = 0;
+ char sry = 0;
+ int i;
+
+ // Never if doing something else... this prevents a slight asymetry
+ // where using autopickup was giving free searches in comparison to
+ // not using autopickup. -- bwr
+ if (you_are_delayed())
+ return;
+
+ for (srx = you.x_pos - 1; srx < you.x_pos + 2; srx++)
+ {
+ for (sry = you.y_pos - 1; sry < you.y_pos + 2; sry++)
+ {
+ // don't exclude own square; may be levitating
+ if (grd[srx][sry] == DNGN_SECRET_DOOR
+ && random2(17) <= 1 + you.skills[SK_TRAPS_DOORS])
+ {
+ grd[srx][sry] = DNGN_CLOSED_DOOR;
+ mpr("You found a secret door!");
+ exercise(SK_TRAPS_DOORS, ((coinflip())? 2 : 1));
+ }
+
+ if (grd[srx][sry] == DNGN_UNDISCOVERED_TRAP
+ && random2(17) <= 1 + you.skills[SK_TRAPS_DOORS])
+ {
+ i = trap_at_xy(srx, sry);
+
+ if (i != -1)
+ grd[srx][sry] = trap_category(env.trap[i].type);
+
+ mpr("You found a trap!");
+ }
+ }
+ }
+
+ return;
+} // end search_around()
+
+void in_a_cloud(void)
+{
+ int cl = env.cgrid[you.x_pos][you.y_pos];
+ int hurted = 0;
+ int resist;
+
+ if (you.duration[DUR_CONDENSATION_SHIELD] > 0)
+ {
+ mpr("Your icy shield dissipates!", MSGCH_DURATION);
+ you.duration[DUR_CONDENSATION_SHIELD] = 0;
+ you.redraw_armour_class = 1;
+ }
+
+ switch (env.cloud[cl].type)
+ {
+ case CLOUD_FIRE:
+ case CLOUD_FIRE_MON:
+ if (you.fire_shield)
+ return;
+
+ mpr("You are engulfed in roaring flames!");
+
+ resist = player_res_fire();
+
+ if (resist <= 0)
+ {
+ hurted += ((random2avg(23, 3) + 10) * you.time_taken) / 10;
+
+ if (resist < 0)
+ hurted += ((random2avg(14, 2) + 3) * you.time_taken) / 10;
+
+ hurted -= random2(player_AC());
+
+ if (hurted < 1)
+ hurted = 0;
+ else
+ ouch( hurted, cl, KILLED_BY_CLOUD, "flame" );
+ }
+ else
+ {
+ canned_msg(MSG_YOU_RESIST);
+ hurted += ((random2avg(23, 3) + 10) * you.time_taken) / 10;
+ hurted /= (1 + resist * resist);
+ ouch( hurted, cl, KILLED_BY_CLOUD, "flame" );
+ }
+ scrolls_burn(7, OBJ_SCROLLS);
+ break;
+
+ case CLOUD_STINK:
+ case CLOUD_STINK_MON:
+ // If you don't have to breathe, unaffected
+ mpr("You are engulfed in noxious fumes!");
+ if (player_res_poison())
+ break;
+
+ hurted += (random2(3) * you.time_taken) / 10;
+ if (hurted < 1)
+ hurted = 0;
+ else
+ ouch( (hurted * you.time_taken) / 10, cl, KILLED_BY_CLOUD,
+ "noxious fumes" );
+
+ if (1 + random2(27) >= you.experience_level)
+ {
+ mpr("You choke on the stench!");
+ confuse_player( (coinflip() ? 3 : 2) );
+ }
+ break;
+
+ case CLOUD_COLD:
+ case CLOUD_COLD_MON:
+ mpr("You are engulfed in freezing vapours!");
+
+ resist = player_res_cold();
+
+ if (resist <= 0)
+ {
+ hurted += ((random2avg(23, 3) + 10) * you.time_taken) / 10;
+
+ if (resist < 0)
+ hurted += ((random2avg(14, 2) + 3) * you.time_taken) / 10;
+
+ hurted -= random2(player_AC());
+ if (hurted < 0)
+ hurted = 0;
+
+ ouch( (hurted * you.time_taken) / 10, cl, KILLED_BY_CLOUD,
+ "freezing vapour" );
+ }
+ else
+ {
+ canned_msg(MSG_YOU_RESIST);
+ hurted += ((random2avg(23, 3) + 10) * you.time_taken) / 10;
+ hurted /= (1 + resist * resist);
+ ouch( hurted, cl, KILLED_BY_CLOUD, "freezing vapour" );
+ }
+ scrolls_burn(7, OBJ_POTIONS);
+ break;
+
+ case CLOUD_POISON:
+ case CLOUD_POISON_MON:
+ // If you don't have to breathe, unaffected
+ mpr("You are engulfed in poison gas!");
+ if (!player_res_poison())
+ {
+ ouch( (random2(10) * you.time_taken) / 10, cl, KILLED_BY_CLOUD,
+ "poison gas" );
+ poison_player(1);
+ }
+ break;
+
+ case CLOUD_GREY_SMOKE:
+ case CLOUD_BLUE_SMOKE:
+ case CLOUD_PURP_SMOKE:
+ case CLOUD_BLACK_SMOKE:
+ case CLOUD_GREY_SMOKE_MON:
+ case CLOUD_BLUE_SMOKE_MON:
+ case CLOUD_PURP_SMOKE_MON:
+ case CLOUD_BLACK_SMOKE_MON:
+ mpr("You are engulfed in a cloud of smoke!");
+ break;
+
+ case CLOUD_STEAM:
+ case CLOUD_STEAM_MON:
+ mpr("You are engulfed in a cloud of scalding steam!");
+ if (you.species == SP_PALE_DRACONIAN && you.experience_level > 5)
+ {
+ mpr("It doesn't seem to affect you.");
+ return;
+ }
+
+ if (!player_equip( EQ_BODY_ARMOUR, ARM_STEAM_DRAGON_ARMOUR ))
+ {
+ mpr("It doesn't seem to affect you.");
+ return;
+ }
+
+ hurted += (random2(6) * you.time_taken) / 10;
+ if (hurted < 0 || player_res_fire() > 0)
+ hurted = 0;
+
+ ouch( (hurted * you.time_taken) / 10, cl, KILLED_BY_CLOUD, "poison gas" );
+ break;
+
+ case CLOUD_MIASMA:
+ case CLOUD_MIASMA_MON:
+ mpr("You are engulfed in a dark miasma.");
+
+ if (player_prot_life() > random2(3))
+ return;
+
+ poison_player(1);
+
+ hurted += (random2avg(12, 3) * you.time_taken) / 10; // 3
+
+ if (hurted < 0)
+ hurted = 0;
+
+ ouch( hurted, cl, KILLED_BY_CLOUD, "foul pestilence" );
+ potion_effect(POT_SLOWING, 5);
+
+ if (you.hp_max > 4 && coinflip())
+ rot_hp(1);
+
+ break;
+ }
+
+ return;
+} // end in_a_cloud()
+
+
+void merfolk_start_swimming(void)
+{
+ FixedVector < char, 8 > removed;
+
+ if (you.attribute[ATTR_TRANSFORMATION] != TRAN_NONE)
+ untransform();
+
+ for (int i = EQ_WEAPON; i < EQ_RIGHT_RING; i++)
+ {
+ removed[i] = 0;
+ }
+
+ if (you.equip[EQ_BOOTS] != -1)
+ removed[EQ_BOOTS] = 1;
+
+ // Perhaps a bit to easy for the player, but we allow merfolk
+ // to slide out of heavy body armour freely when entering water,
+ // rather than handling emcumbered swimming. -- bwr
+ if (!player_light_armour())
+ {
+ // Can't slide out of just the body armour, cloak comes off -- bwr
+ if (you.equip[EQ_CLOAK])
+ removed[EQ_CLOAK] = 1;
+
+ removed[EQ_BODY_ARMOUR] = 1;
+ }
+
+ remove_equipment(removed);
+}
+
+void up_stairs(void)
+{
+ unsigned char stair_find = grd[you.x_pos][you.y_pos];
+ char old_where = you.where_are_you;
+ bool was_a_labyrinth = false;
+
+ if (stair_find == DNGN_ENTER_SHOP)
+ {
+ shop();
+ return;
+ }
+
+ // probably still need this check here (teleportation) -- bwr
+ if ((stair_find < DNGN_STONE_STAIRS_UP_I
+ || stair_find > DNGN_ROCK_STAIRS_UP)
+ && (stair_find < DNGN_RETURN_FROM_ORCISH_MINES || stair_find >= 150))
+ {
+ mpr("You can't go up here.");
+ return;
+ }
+
+ // Since the overloaded message set turn_is_over, I'm assuming that
+ // the overloaded character makes an attempt... so we're doing this
+ // check before that one. -- bwr
+ if (!player_is_levitating()
+ && you.conf
+ && (stair_find >= DNGN_STONE_STAIRS_UP_I
+ && stair_find <= DNGN_ROCK_STAIRS_UP)
+ && random2(100) > you.dex)
+ {
+ mpr("In your confused state, you trip and fall back down the stairs.");
+
+ ouch( roll_dice( 3 + you.burden_state, 5 ), 0,
+ KILLED_BY_FALLING_DOWN_STAIRS );
+
+ you.turn_is_over = 1;
+ return;
+ }
+
+ if (you.burden_state == BS_OVERLOADED)
+ {
+ mpr("You are carrying too much to climb upwards.");
+ you.turn_is_over = 1;
+ return;
+ }
+
+ if (you.your_level == 0
+ && !yesno("Are you sure you want to leave the Dungeon?", false))
+ {
+ mpr("Alright, then stay!");
+ return;
+ }
+
+ unsigned char old_level = you.your_level;
+
+ // Make sure we return to our main dungeon level... labyrinth entrances
+ // in the abyss or pandemonium a bit trouble (well the labyrinth does
+ // provide a way out of those places, its really not that bad I suppose)
+ if (you.level_type == LEVEL_LABYRINTH)
+ {
+ you.level_type = LEVEL_DUNGEON;
+ was_a_labyrinth = true;
+ }
+
+ you.your_level--;
+
+ int i = 0;
+
+ if (you.your_level < 0)
+ {
+ mpr("You have escaped!");
+
+ for (i = 0; i < ENDOFPACK; i++)
+ {
+ if (is_valid_item( you.inv[i] )
+ && you.inv[i].base_type == OBJ_ORBS)
+ {
+ ouch(-9999, 0, KILLED_BY_WINNING);
+ }
+ }
+
+ ouch(-9999, 0, KILLED_BY_LEAVING);
+ }
+
+ mpr("Entering...");
+ you.prev_targ = MHITNOT;
+ you.pet_target = MHITNOT;
+
+ if (player_in_branch( BRANCH_VESTIBULE_OF_HELL ))
+ {
+ mpr("Thank you for visiting Hell. Please come again soon.");
+ you.where_are_you = BRANCH_MAIN_DUNGEON;
+ you.your_level = you.hell_exit;
+ stair_find = DNGN_STONE_STAIRS_UP_I;
+ }
+
+ if (player_in_hell())
+ {
+ you.where_are_you = BRANCH_VESTIBULE_OF_HELL;
+ you.your_level = 27;
+ }
+
+ switch (stair_find)
+ {
+ case DNGN_RETURN_FROM_ORCISH_MINES:
+ case DNGN_RETURN_FROM_HIVE:
+ case DNGN_RETURN_FROM_LAIR:
+ case DNGN_RETURN_FROM_VAULTS:
+ case DNGN_RETURN_FROM_TEMPLE:
+ case DNGN_RETURN_FROM_ZOT:
+ mpr("Welcome back to the Dungeon!");
+ you.where_are_you = BRANCH_MAIN_DUNGEON;
+ break;
+ case DNGN_RETURN_FROM_SLIME_PITS:
+ case DNGN_RETURN_FROM_SNAKE_PIT:
+ case DNGN_RETURN_FROM_SWAMP:
+ mpr("Welcome back to the Lair of Beasts!");
+ you.where_are_you = BRANCH_LAIR;
+ break;
+ case DNGN_RETURN_FROM_CRYPT:
+ case DNGN_RETURN_FROM_HALL_OF_BLADES:
+ mpr("Welcome back to the Vaults!");
+ you.where_are_you = BRANCH_VAULTS;
+ break;
+ case DNGN_RETURN_FROM_TOMB:
+ mpr("Welcome back to the Crypt!");
+ you.where_are_you = BRANCH_CRYPT;
+ break;
+ case DNGN_RETURN_FROM_ELVEN_HALLS:
+ mpr("Welcome back to the Orcish Mines!");
+ you.where_are_you = BRANCH_ORCISH_MINES;
+ break;
+ }
+
+ unsigned char stair_taken = stair_find;
+
+ if (player_is_levitating())
+ {
+ if (you.duration[DUR_CONTROLLED_FLIGHT])
+ mpr("You fly upwards.");
+ else
+ mpr("You float upwards... And bob straight up to the ceiling!");
+ }
+ else
+ mpr("You climb upwards.");
+
+ load(stair_taken, LOAD_ENTER_LEVEL, was_a_labyrinth, old_level, old_where);
+
+ you.turn_is_over = 1;
+
+ save_game(false);
+
+ new_level();
+
+ viewwindow(1, true);
+
+
+ if (you.skills[SK_TRANSLOCATIONS] > 0 && !allow_control_teleport( true ))
+ mpr( "You sense a powerful magical force warping space.", MSGCH_WARN );
+} // end up_stairs()
+
+void down_stairs( bool remove_stairs, int old_level )
+{
+ int i;
+ char old_level_type = you.level_type;
+ bool was_a_labyrinth = false;
+ const unsigned char stair_find = grd[you.x_pos][you.y_pos];
+
+ //int old_level = you.your_level;
+ bool leave_abyss_pan = false;
+ char old_where = you.where_are_you;
+
+#ifdef SHUT_LABYRINTH
+ if (stair_find == DNGN_ENTER_LABYRINTH)
+ {
+ mpr("Sorry, this section of the dungeon is closed for fumigation.");
+ mpr("Try again next release.");
+ return;
+ }
+#endif
+
+ // probably still need this check here (teleportation) -- bwr
+ if ((stair_find < DNGN_ENTER_LABYRINTH
+ || stair_find > DNGN_ROCK_STAIRS_DOWN)
+ && stair_find != DNGN_ENTER_HELL
+ && ((stair_find < DNGN_ENTER_DIS
+ || stair_find > DNGN_TRANSIT_PANDEMONIUM)
+ && stair_find != DNGN_STONE_ARCH)
+ && !(stair_find >= DNGN_ENTER_ORCISH_MINES
+ && stair_find < DNGN_RETURN_FROM_ORCISH_MINES))
+ {
+ mpr( "You can't go down here!" );
+ return;
+ }
+
+ if (stair_find >= DNGN_ENTER_LABYRINTH
+ && stair_find <= DNGN_ROCK_STAIRS_DOWN
+ && player_in_branch( BRANCH_VESTIBULE_OF_HELL ))
+ {
+ mpr("A mysterious force prevents you from descending the staircase.");
+ return;
+ } /* down stairs in vestibule are one-way */
+
+ if (stair_find == DNGN_STONE_ARCH)
+ {
+ mpr("You can't go down here!");
+ return;
+ }
+
+ if (player_is_levitating() && !wearing_amulet(AMU_CONTROLLED_FLIGHT))
+ {
+ mpr("You're floating high up above the floor!");
+ return;
+ }
+
+ if (stair_find == DNGN_ENTER_ZOT)
+ {
+ int num_runes = 0;
+
+ for (i = 0; i < ENDOFPACK; i++)
+ {
+ if (is_valid_item( you.inv[i] )
+ && you.inv[i].base_type == OBJ_MISCELLANY
+ && you.inv[i].sub_type == MISC_RUNE_OF_ZOT)
+ {
+ num_runes += you.inv[i].quantity;
+ }
+ }
+
+ if (num_runes < NUMBER_OF_RUNES_NEEDED)
+ {
+ switch (NUMBER_OF_RUNES_NEEDED)
+ {
+ case 1:
+ mpr("You need a Rune to enter this place.");
+ break;
+
+ default:
+ snprintf( info, INFO_SIZE,
+ "You need at least %d Runes to enter this place.",
+ NUMBER_OF_RUNES_NEEDED );
+
+ mpr(info);
+ }
+ return;
+ }
+ }
+
+ if (you.level_type == LEVEL_PANDEMONIUM
+ && stair_find == DNGN_TRANSIT_PANDEMONIUM)
+ {
+ was_a_labyrinth = true;
+ }
+ else
+ {
+ if (you.level_type != LEVEL_DUNGEON)
+ was_a_labyrinth = true;
+
+ you.level_type = LEVEL_DUNGEON;
+ }
+
+ mpr("Entering...");
+ you.prev_targ = MHITNOT;
+ you.pet_target = MHITNOT;
+
+ if (stair_find == DNGN_ENTER_HELL)
+ {
+ you.where_are_you = BRANCH_VESTIBULE_OF_HELL;
+ you.hell_exit = you.your_level;
+
+ mpr("Welcome to Hell!");
+ mpr("Please enjoy your stay.");
+
+ more();
+
+ you.your_level = 26; // = 59;
+ }
+
+ if ((stair_find >= DNGN_ENTER_DIS
+ && stair_find <= DNGN_ENTER_TARTARUS)
+ || (stair_find >= DNGN_ENTER_ORCISH_MINES
+ && stair_find < DNGN_RETURN_FROM_ORCISH_MINES))
+ {
+ // no idea why such a huge switch and not 100-grd[][]
+ // planning ahead for re-organizaing grd[][] values - 13jan2000 {dlb}
+ strcpy( info, "Welcome to " );
+ switch (stair_find)
+ {
+ case DNGN_ENTER_DIS:
+ strcat(info, "the Iron City of Dis!");
+ you.where_are_you = BRANCH_DIS;
+ you.your_level = 26;
+ break;
+ case DNGN_ENTER_GEHENNA:
+ strcat(info, "Gehenna!");
+ you.where_are_you = BRANCH_GEHENNA;
+ you.your_level = 26;
+ break;
+ case DNGN_ENTER_COCYTUS:
+ strcat(info, "Cocytus!");
+ you.where_are_you = BRANCH_COCYTUS;
+ you.your_level = 26;
+ break;
+ case DNGN_ENTER_TARTARUS:
+ strcat(info, "Tartarus!");
+ you.where_are_you = BRANCH_TARTARUS;
+ you.your_level = 26;
+ break;
+ case DNGN_ENTER_ORCISH_MINES:
+ strcat(info, "the Orcish Mines!");
+ you.where_are_you = BRANCH_ORCISH_MINES;
+ break;
+ case DNGN_ENTER_HIVE:
+ strcpy(info, "You hear a buzzing sound coming from all directions.");
+ you.where_are_you = BRANCH_HIVE;
+ break;
+ case DNGN_ENTER_LAIR:
+ strcat(info, "the Lair of Beasts!");
+ you.where_are_you = BRANCH_LAIR;
+ break;
+ case DNGN_ENTER_SLIME_PITS:
+ strcat(info, "the Pits of Slime!");
+ you.where_are_you = BRANCH_SLIME_PITS;
+ break;
+ case DNGN_ENTER_VAULTS:
+ strcat(info, "the Vaults!");
+ you.where_are_you = BRANCH_VAULTS;
+ break;
+ case DNGN_ENTER_CRYPT:
+ strcat(info, "the Crypt!");
+ you.where_are_you = BRANCH_CRYPT;
+ break;
+ case DNGN_ENTER_HALL_OF_BLADES:
+ strcat(info, "the Hall of Blades!");
+ you.where_are_you = BRANCH_HALL_OF_BLADES;
+ break;
+ case DNGN_ENTER_ZOT:
+ strcat(info, "the Hall of Zot!");
+ you.where_are_you = BRANCH_HALL_OF_ZOT;
+ break;
+ case DNGN_ENTER_TEMPLE:
+ strcat(info, "the Ecumenical Temple!");
+ you.where_are_you = BRANCH_ECUMENICAL_TEMPLE;
+ break;
+ case DNGN_ENTER_SNAKE_PIT:
+ strcat(info, "the Snake Pit!");
+ you.where_are_you = BRANCH_SNAKE_PIT;
+ break;
+ case DNGN_ENTER_ELVEN_HALLS:
+ strcat(info, "the Elven Halls!");
+ you.where_are_you = BRANCH_ELVEN_HALLS;
+ break;
+ case DNGN_ENTER_TOMB:
+ strcat(info, "the Tomb!");
+ you.where_are_you = BRANCH_TOMB;
+ break;
+ case DNGN_ENTER_SWAMP:
+ strcat(info, "the Swamp!");
+ you.where_are_you = BRANCH_SWAMP;
+ break;
+ }
+
+ mpr(info);
+ }
+ else if (stair_find == DNGN_ENTER_LABYRINTH)
+ {
+ you.level_type = LEVEL_LABYRINTH;
+ grd[you.x_pos][you.y_pos] = DNGN_FLOOR;
+ }
+ else if (stair_find == DNGN_ENTER_ABYSS)
+ {
+ you.level_type = LEVEL_ABYSS;
+ }
+ else if (stair_find == DNGN_ENTER_PANDEMONIUM)
+ {
+ you.level_type = LEVEL_PANDEMONIUM;
+ }
+
+ if (you.level_type == LEVEL_LABYRINTH || you.level_type == LEVEL_ABYSS
+ || you.level_type == LEVEL_PANDEMONIUM)
+ {
+ char glorpstr[kFileNameSize];
+ char del_file[kFileNameSize];
+ int sysg;
+
+#ifdef SAVE_DIR_PATH
+ snprintf( glorpstr, sizeof(glorpstr),
+ SAVE_DIR_PATH "%s%d", you.your_name, (int) getuid() );
+#else
+ strncpy(glorpstr, you.your_name, kFileNameLen);
+
+ // glorpstr [strlen(glorpstr)] = 0;
+ // This is broken. Length is not valid yet! We have to check if we got
+ // a trailing NULL; if not, write one:
+ /* is name 6 chars or more? */
+ if (strlen(you.your_name) > kFileNameLen - 1)
+ glorpstr[kFileNameLen] = '\0';
+#endif
+
+ strcpy(del_file, glorpstr);
+ strcat(del_file, ".lab");
+
+#ifdef DOS
+ strupr(del_file);
+#endif
+ sysg = unlink(del_file);
+
+#if DEBUG_DIAGNOSTICS
+ strcpy( info, "Deleting: " );
+ strcat( info, del_file );
+ mpr( info, MSGCH_DIAGNOSTICS );
+ more();
+#endif
+ }
+
+ if (stair_find == DNGN_EXIT_ABYSS || stair_find == DNGN_EXIT_PANDEMONIUM)
+ {
+ leave_abyss_pan = true;
+ mpr("You pass through the gate, and find yourself at the top of a staircase.");
+ more();
+ }
+
+ if (!player_is_levitating()
+ && you.conf
+ && (stair_find >= DNGN_STONE_STAIRS_DOWN_I
+ && stair_find <= DNGN_ROCK_STAIRS_DOWN)
+ && random2(100) > you.dex)
+ {
+ mpr("In your confused state, you trip and fall down the stairs.");
+
+ // Nastier than when climbing stairs, but you'll aways get to
+ // your destination, -- bwr
+ ouch( roll_dice( 6 + you.burden_state, 10 ), 0,
+ KILLED_BY_FALLING_DOWN_STAIRS );
+ }
+
+ if (you.level_type == LEVEL_DUNGEON)
+ you.your_level++;
+
+ int stair_taken = stair_find;
+
+ //unsigned char save_old = 1;
+
+ if (you.level_type == LEVEL_LABYRINTH || you.level_type == LEVEL_ABYSS)
+ stair_taken = DNGN_FLOOR; //81;
+
+ if (you.level_type == LEVEL_PANDEMONIUM)
+ stair_taken = DNGN_TRANSIT_PANDEMONIUM;
+
+ if (remove_stairs)
+ grd[you.x_pos][you.y_pos] = DNGN_FLOOR;
+
+ switch (you.level_type)
+ {
+ case LEVEL_LABYRINTH:
+ mpr("You enter a dark and forbidding labyrinth.");
+ break;
+
+ case LEVEL_ABYSS:
+ mpr("You enter the Abyss!");
+ mpr("To return, you must find a gate leading back.");
+ break;
+
+ case LEVEL_PANDEMONIUM:
+ if (old_level_type == LEVEL_PANDEMONIUM)
+ mpr("You pass into a different region of Pandemonium.");
+ else
+ {
+ mpr("You enter the halls of Pandemonium!");
+ mpr("To return, you must find a gate leading back.");
+ }
+ break;
+
+ default:
+ mpr("You climb downwards.");
+ break;
+ }
+
+ load(stair_taken, LOAD_ENTER_LEVEL, was_a_labyrinth, old_level, old_where);
+
+ unsigned char pc = 0;
+ unsigned char pt = random2avg(28, 3);
+
+ switch (you.level_type)
+ {
+ case LEVEL_LABYRINTH:
+ you.your_level++;
+ break;
+
+ case LEVEL_ABYSS:
+ grd[you.x_pos][you.y_pos] = DNGN_FLOOR;
+
+ if (old_level_type != LEVEL_PANDEMONIUM)
+ you.your_level--; // Linley-suggested addition 17jan2000 {dlb}
+
+ init_pandemonium(); /* colours only */
+
+ if (player_in_hell())
+ {
+ you.where_are_you = BRANCH_MAIN_DUNGEON;
+ you.your_level = you.hell_exit - 1;
+ }
+ break;
+
+ case LEVEL_PANDEMONIUM:
+ if (old_level_type == LEVEL_PANDEMONIUM)
+ {
+ init_pandemonium();
+ for (pc = 0; pc < pt; pc++)
+ pandemonium_mons();
+ }
+ else
+ {
+ // Linley-suggested addition 17jan2000 {dlb}
+ if (old_level_type != LEVEL_ABYSS)
+ you.your_level--;
+
+ init_pandemonium();
+
+ for (pc = 0; pc < pt; pc++)
+ pandemonium_mons();
+
+ if (player_in_hell())
+ {
+ you.where_are_you = BRANCH_MAIN_DUNGEON;
+ you.hell_exit = 26;
+ you.your_level = 26;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ you.turn_is_over = 1;
+
+ save_game(false);
+
+ new_level();
+
+ viewwindow(1, true);
+
+ if (you.skills[SK_TRANSLOCATIONS] > 0 && !allow_control_teleport( true ))
+ mpr( "You sense a powerful magical force warping space.", MSGCH_WARN );
+} // end down_stairs()
+
+void new_level(void)
+{
+ int curr_subdungeon_level = you.your_level + 1;
+
+ textcolor(LIGHTGREY);
+
+ // maybe last part better expresssed as <= PIT {dlb}
+ if (player_in_hell() || player_in_branch( BRANCH_VESTIBULE_OF_HELL ))
+ curr_subdungeon_level = you.your_level - 26;
+
+ /* Remember, must add this to the death_string in ouch */
+ if (you.where_are_you >= BRANCH_ORCISH_MINES
+ && you.where_are_you <= BRANCH_SWAMP)
+ {
+ curr_subdungeon_level = you.your_level
+ - you.branch_stairs[you.where_are_you - 10];
+ }
+
+ gotoxy(46, 12);
+
+#if DEBUG_DIAGNOSTICS
+ cprintf( "(%d) ", you.your_level + 1 );
+#endif
+
+ env.floor_colour = LIGHTGREY;
+ env.rock_colour = BROWN;
+
+ if (you.level_type == LEVEL_PANDEMONIUM)
+ {
+ cprintf("- Pandemonium ");
+
+ env.floor_colour = (mcolour[env.mons_alloc[9]] == BLACK)
+ ? LIGHTGREY : mcolour[env.mons_alloc[9]];
+
+ env.rock_colour = (mcolour[env.mons_alloc[8]] == BLACK)
+ ? LIGHTGREY : mcolour[env.mons_alloc[8]];
+ }
+ else if (you.level_type == LEVEL_ABYSS)
+ {
+ cprintf("- The Abyss ");
+
+ env.floor_colour = (mcolour[env.mons_alloc[9]] == BLACK)
+ ? LIGHTGREY : mcolour[env.mons_alloc[9]];
+
+ env.rock_colour = (mcolour[env.mons_alloc[8]] == BLACK)
+ ? LIGHTGREY : mcolour[env.mons_alloc[8]];
+ }
+ else if (you.level_type == LEVEL_LABYRINTH)
+ {
+ cprintf("- a Labyrinth ");
+ }
+ else
+ {
+ // level_type == LEVEL_DUNGEON
+ if (!player_in_branch( BRANCH_VESTIBULE_OF_HELL ))
+ cprintf( "%d", curr_subdungeon_level );
+
+ switch (you.where_are_you)
+ {
+ case BRANCH_MAIN_DUNGEON:
+ cprintf(" of the Dungeon ");
+ break;
+ case BRANCH_DIS:
+ env.floor_colour = CYAN;
+ env.rock_colour = CYAN;
+ cprintf(" of Dis ");
+ break;
+ case BRANCH_GEHENNA:
+ env.floor_colour = DARKGREY;
+ env.rock_colour = RED;
+ cprintf(" of Gehenna ");
+ break;
+ case BRANCH_VESTIBULE_OF_HELL:
+ env.floor_colour = LIGHTGREY;
+ env.rock_colour = LIGHTGREY;
+ cprintf("- the Vestibule of Hell ");
+ break;
+ case BRANCH_COCYTUS:
+ env.floor_colour = LIGHTBLUE;
+ env.rock_colour = LIGHTCYAN;
+ cprintf(" of Cocytus ");
+ break;
+ case BRANCH_TARTARUS:
+ env.floor_colour = DARKGREY;
+ env.rock_colour = DARKGREY;
+ cprintf(" of Tartarus ");
+ break;
+ case BRANCH_INFERNO:
+ env.floor_colour = LIGHTRED;
+ env.rock_colour = RED;
+ cprintf(" of the Inferno ");
+ break;
+ case BRANCH_THE_PIT:
+ env.floor_colour = RED;
+ env.rock_colour = DARKGREY;
+ cprintf(" of the Pit ");
+ break;
+ case BRANCH_ORCISH_MINES:
+ env.floor_colour = BROWN;
+ env.rock_colour = BROWN;
+ cprintf(" of the Orcish Mines ");
+ break;
+ case BRANCH_HIVE:
+ env.floor_colour = YELLOW;
+ env.rock_colour = BROWN;
+ cprintf(" of the Hive ");
+ break;
+ case BRANCH_LAIR:
+ env.floor_colour = GREEN;
+ env.rock_colour = BROWN;
+ cprintf(" of the Lair ");
+ break;
+ case BRANCH_SLIME_PITS:
+ env.floor_colour = GREEN;
+ env.rock_colour = LIGHTGREEN;
+ cprintf(" of the Slime Pits ");
+ break;
+ case BRANCH_VAULTS:
+ env.floor_colour = LIGHTGREY;
+ env.rock_colour = BROWN;
+ cprintf(" of the Vaults ");
+ break;
+ case BRANCH_CRYPT:
+ env.floor_colour = LIGHTGREY;
+ env.rock_colour = LIGHTGREY;
+ cprintf(" of the Crypt ");
+ break;
+ case BRANCH_HALL_OF_BLADES:
+ env.floor_colour = LIGHTGREY;
+ env.rock_colour = LIGHTGREY;
+ cprintf(" of the Hall of Blades ");
+ break;
+
+ case BRANCH_HALL_OF_ZOT:
+ if (you.your_level - you.branch_stairs[7] <= 1)
+ {
+ env.floor_colour = LIGHTGREY;
+ env.rock_colour = LIGHTGREY;
+ }
+ else
+ {
+ switch (you.your_level - you.branch_stairs[7])
+ {
+ case 2:
+ env.rock_colour = LIGHTGREY;
+ env.floor_colour = BLUE;
+ break;
+ case 3:
+ env.rock_colour = BLUE;
+ env.floor_colour = LIGHTBLUE;
+ break;
+ case 4:
+ env.rock_colour = LIGHTBLUE;
+ env.floor_colour = MAGENTA;
+ break;
+ case 5:
+ env.rock_colour = MAGENTA;
+ env.floor_colour = LIGHTMAGENTA;
+ break;
+ }
+ }
+ cprintf(" of the Realm of Zot ");
+ break;
+
+ case BRANCH_ECUMENICAL_TEMPLE:
+ env.floor_colour = LIGHTGREY;
+ env.rock_colour = LIGHTGREY;
+ cprintf(" of the Temple ");
+ break;
+ case BRANCH_SNAKE_PIT:
+ env.floor_colour = LIGHTGREEN;
+ env.rock_colour = YELLOW;
+ cprintf(" of the Snake Pit ");
+ break;
+ case BRANCH_ELVEN_HALLS:
+ env.floor_colour = DARKGREY;
+ env.rock_colour = LIGHTGREY;
+ cprintf(" of the Elven Halls ");
+ break;
+ case BRANCH_TOMB:
+ env.floor_colour = YELLOW;
+ env.rock_colour = LIGHTGREY;
+ cprintf(" of the Tomb ");
+ break;
+ case BRANCH_SWAMP:
+ env.floor_colour = BROWN;
+ env.rock_colour = BROWN;
+ cprintf(" of the Swamp ");
+ break;
+ }
+ } // end else
+} // end new_level()
+
+static void dart_trap( bool trap_known, int trapped, struct bolt &pbolt,
+ bool poison )
+{
+ int damage_taken = 0;
+ int trap_hit, your_dodge;
+
+ if (random2(10) < 2 || (trap_known && !one_chance_in(4)))
+ {
+ snprintf( info, INFO_SIZE, "You avoid triggering a%s trap.",
+ pbolt.beam_name );
+ mpr(info);
+ return;
+ }
+
+ if (you.equip[EQ_SHIELD] != -1 && one_chance_in(3))
+ exercise( SK_SHIELDS, 1 );
+
+ snprintf( info, INFO_SIZE, "A%s shoots out and ", pbolt.beam_name );
+
+ if (random2( 50 + 10 * you.shield_blocks * you.shield_blocks )
+ < player_shield_class())
+ {
+ you.shield_blocks++;
+ strcat( info, "hits your shield." );
+ mpr(info);
+ goto out_of_trap;
+ }
+
+ // note that this uses full ( not random2limit(foo,40) ) player_evasion.
+ trap_hit = (20 + (you.your_level * 2)) * random2(200) / 100;
+
+ your_dodge = player_evasion() + random2(you.dex) / 3
+ - 2 + (you.duration[DUR_REPEL_MISSILES] * 10);
+
+ if (trap_hit >= your_dodge && you.duration[DUR_DEFLECT_MISSILES] == 0)
+ {
+ strcat( info, "hits you!" );
+ mpr(info);
+
+ if (poison && random2(100) < 50 - (3 * player_AC()) / 2
+ && !player_res_poison())
+ {
+ poison_player( 1 + random2(3) );
+ }
+
+ damage_taken = roll_dice( pbolt.damage );
+ damage_taken -= random2( player_AC() + 1 );
+
+ if (damage_taken > 0)
+ ouch( damage_taken, 0, KILLED_BY_TRAP, pbolt.beam_name );
+ }
+ else
+ {
+ strcat( info, "misses you." );
+ mpr(info);
+ }
+
+ if (player_light_armour() && coinflip())
+ exercise( SK_DODGING, 1 );
+
+ out_of_trap:
+
+ pbolt.target_x = you.x_pos;
+ pbolt.target_y = you.y_pos;
+
+ if (coinflip())
+ itrap( pbolt, trapped );
+} // end dart_trap()
+
+//
+// itrap takes location from target_x, target_y of bolt strcture.
+//
+
+void itrap( struct bolt &pbolt, int trapped )
+{
+ int base_type = OBJ_MISSILES;
+ int sub_type = MI_DART;
+
+ switch (env.trap[trapped].type)
+ {
+ case TRAP_DART:
+ base_type = OBJ_MISSILES;
+ sub_type = MI_DART;
+ break;
+ case TRAP_ARROW:
+ base_type = OBJ_MISSILES;
+ sub_type = MI_ARROW;
+ break;
+ case TRAP_BOLT:
+ base_type = OBJ_MISSILES;
+ sub_type = MI_BOLT;
+ break;
+ case TRAP_SPEAR:
+ base_type = OBJ_WEAPONS;
+ sub_type = WPN_SPEAR;
+ break;
+ case TRAP_AXE:
+ base_type = OBJ_WEAPONS;
+ sub_type = WPN_HAND_AXE;
+ break;
+ case TRAP_NEEDLE:
+ base_type = OBJ_MISSILES;
+ sub_type = MI_NEEDLE;
+ break;
+ default:
+ return;
+ }
+
+ trap_item( base_type, sub_type, pbolt.target_x, pbolt.target_y );
+
+ return;
+} // end itrap()
+
+void handle_traps(char trt, int i, bool trap_known)
+{
+ struct bolt beam;
+
+ switch (trt)
+ {
+ case TRAP_DART:
+ strcpy(beam.beam_name, " dart");
+ beam.damage = dice_def( 1, 4 + (you.your_level / 2) );
+ dart_trap(trap_known, i, beam, false);
+ break;
+
+ case TRAP_NEEDLE:
+ strcpy(beam.beam_name, " needle");
+ beam.damage = dice_def( 1, 0 );
+ dart_trap(trap_known, i, beam, true);
+ break;
+
+ case TRAP_ARROW:
+ strcpy(beam.beam_name, "n arrow");
+ beam.damage = dice_def( 1, 7 + you.your_level );
+ dart_trap(trap_known, i, beam, false);
+ break;
+
+ case TRAP_BOLT:
+ strcpy(beam.beam_name, " bolt");
+ beam.damage = dice_def( 1, 13 + you.your_level );
+ dart_trap(trap_known, i, beam, false);
+ break;
+
+ case TRAP_SPEAR:
+ strcpy(beam.beam_name, " spear");
+ beam.damage = dice_def( 1, 10 + you.your_level );
+ dart_trap(trap_known, i, beam, false);
+ break;
+
+ case TRAP_AXE:
+ strcpy(beam.beam_name, "n axe");
+ beam.damage = dice_def( 1, 15 + you.your_level );
+ dart_trap(trap_known, i, beam, false);
+ break;
+
+ case TRAP_TELEPORT:
+ mpr("You enter a teleport trap!");
+
+ if (scan_randarts(RAP_PREVENT_TELEPORTATION))
+ mpr("You feel a weird sense of stasis.");
+ else
+ you_teleport2( true );
+ break;
+
+ case TRAP_AMNESIA:
+ mpr("You feel momentarily disoriented.");
+ if (!wearing_amulet(AMU_CLARITY))
+ forget_map(random2avg(100, 2));
+ break;
+
+ case TRAP_BLADE:
+ if (trap_known && one_chance_in(3))
+ mpr("You avoid triggering a blade trap.");
+ else if (random2limit(player_evasion(), 40)
+ + (random2(you.dex) / 3) + (trap_known ? 3 : 0) > 8)
+ {
+ mpr("A huge blade swings just past you!");
+ }
+ else
+ {
+ mpr("A huge blade swings out and slices into you!");
+ ouch( (you.your_level * 2) + random2avg(29, 2)
+ - random2(1 + player_AC()), 0, KILLED_BY_TRAP, " blade" );
+ }
+ break;
+
+ case TRAP_ZOT:
+ default:
+ mpr((trap_known) ? "You enter the Zot trap."
+ : "Oh no! You have blundered into a Zot trap!");
+ miscast_effect( SPTYP_RANDOM, random2(30) + you.your_level,
+ 75 + random2(100), 3, "a Zot trap" );
+ break;
+ }
+} // end handle_traps()
+
+void disarm_trap( struct dist &disa )
+{
+ if (you.berserker)
+ {
+ canned_msg(MSG_TOO_BERSERK);
+ return;
+ }
+
+ int i, j;
+
+ for (i = 0; i < MAX_TRAPS; i++)
+ {
+ if (env.trap[i].x == you.x_pos + disa.dx
+ && env.trap[i].y == you.y_pos + disa.dy)
+ {
+ break;
+ }
+
+ if (i == MAX_TRAPS - 1)
+ {
+ mpr("Error - couldn't find that trap.");
+ return;
+ }
+ }
+
+ if (trap_category(env.trap[i].type) == DNGN_TRAP_MAGICAL)
+ {
+ mpr("You can't disarm that trap.");
+ return;
+ }
+
+ if (random2(you.skills[SK_TRAPS_DOORS] + 2) <= random2(you.your_level + 5))
+ {
+ mpr("You failed to disarm the trap.");
+
+ you.turn_is_over = 1;
+
+ if (random2(you.dex) > 5 + random2(5 + you.your_level))
+ exercise(SK_TRAPS_DOORS, 1 + random2(you.your_level / 5));
+ else
+ {
+ handle_traps(env.trap[i].type, i, false);
+
+ if (coinflip())
+ exercise(SK_TRAPS_DOORS, 1);
+ }
+
+ return;
+ }
+
+ mpr("You have disarmed the trap.");
+
+ struct bolt beam;
+
+ beam.target_x = you.x_pos + disa.dx;
+ beam.target_y = you.y_pos + disa.dy;
+
+ if (env.trap[i].type != TRAP_BLADE
+ && trap_category(env.trap[i].type) == DNGN_TRAP_MECHANICAL)
+ {
+ for (j = 0; j < 20; j++)
+ {
+ // places items (eg darts), which will automatically stack
+ itrap(beam, i);
+
+ if (j > 10 && one_chance_in(3))
+ break;
+ }
+ }
+
+ grd[you.x_pos + disa.dx][you.y_pos + disa.dy] = DNGN_FLOOR;
+ env.trap[i].type = TRAP_UNASSIGNED;
+ you.turn_is_over = 1;
+
+ // reduced from 5 + random2(5)
+ exercise(SK_TRAPS_DOORS, 1 + random2(5) + (you.your_level / 5));
+} // end disarm_trap()
+
+void manage_clouds(void)
+{
+ // amount which cloud dissipates - must be unsigned! {dlb}
+ unsigned int dissipate = 0;
+
+ for (unsigned char cc = 0; cc < MAX_CLOUDS; cc++)
+ {
+ if (env.cloud[cc].type == CLOUD_NONE) // no cloud -> next iteration
+ continue;
+
+ dissipate = you.time_taken;
+
+ // water -> flaming clouds:
+ // lava -> freezing clouds:
+ if ((env.cloud[cc].type == CLOUD_FIRE
+ || env.cloud[cc].type == CLOUD_FIRE_MON)
+ && grd[env.cloud[cc].x][env.cloud[cc].y] == DNGN_DEEP_WATER)
+ {
+ dissipate *= 4;
+ }
+ else if ((env.cloud[cc].type == CLOUD_COLD
+ || env.cloud[cc].type == CLOUD_COLD_MON)
+ && grd[env.cloud[cc].x][env.cloud[cc].y] == DNGN_LAVA)
+ {
+ dissipate *= 4;
+ }
+
+ // double the amount when slowed - must be applied last(!):
+ if (you.slow)
+ dissipate *= 2;
+
+ // apply calculated rate to the actual cloud:
+ env.cloud[cc].decay -= dissipate;
+
+ // check for total dissipatation and handle accordingly:
+ if (env.cloud[cc].decay < 1)
+ delete_cloud( cc );
+ }
+
+ return;
+} // end manage_clouds()
+
+void weird_writing(char stringy[40])
+{
+ int temp_rand = 0; // for probability determinations {dlb}
+
+ temp_rand = random2(15);
+
+ // you'll see why later on {dlb}
+ strcpy(stringy, (temp_rand == 0) ? "writhing" :
+ (temp_rand == 1) ? "bold" :
+ (temp_rand == 2) ? "faint" :
+ (temp_rand == 3) ? "spidery" :
+ (temp_rand == 4) ? "blocky" :
+ (temp_rand == 5) ? "angular" :
+ (temp_rand == 6) ? "shimmering" :
+ (temp_rand == 7) ? "glowing" : "");
+
+ if (temp_rand < 8)
+ strcat(stringy, " "); // see above for reasoning {dlb}
+
+ temp_rand = random2(14);
+
+ strcat(stringy, (temp_rand == 0) ? "yellow" :
+ (temp_rand == 1) ? "brown" :
+ (temp_rand == 2) ? "black" :
+ (temp_rand == 3) ? "purple" :
+ (temp_rand == 4) ? "orange" :
+ (temp_rand == 5) ? "lime-green" :
+ (temp_rand == 6) ? "blue" :
+ (temp_rand == 7) ? "grey" :
+ (temp_rand == 8) ? "silver" :
+ (temp_rand == 9) ? "gold" :
+ (temp_rand == 10) ? "umber" :
+ (temp_rand == 11) ? "charcoal" :
+ (temp_rand == 12) ? "pastel" :
+ (temp_rand == 13) ? "mauve"
+ : "colourless");
+
+ strcat(stringy, " ");
+
+ temp_rand = random2(14);
+
+ strcat(stringy, (temp_rand == 0) ? "writing" :
+ (temp_rand == 1) ? "scrawl" :
+ (temp_rand == 2) ? "sigils" :
+ (temp_rand == 3) ? "runes" :
+ (temp_rand == 4) ? "hieroglyphics" :
+ (temp_rand == 5) ? "scrawl" :
+ (temp_rand == 6) ? "print-out" :
+ (temp_rand == 7) ? "binary code" :
+ (temp_rand == 8) ? "glyphs" :
+ (temp_rand == 9) ? "symbols"
+ : "text");
+
+ return;
+} // end weird_writing()
+
+// must be a better name than 'place' for the first parameter {dlb}
+void fall_into_a_pool(bool place, unsigned char terrain)
+{
+ bool escape = false;
+ FixedVector< char, 2 > empty;
+
+ if (you.species == SP_MERFOLK && terrain == DNGN_DEEP_WATER)
+ {
+ // These can happen when we enter deep water directly -- bwr
+ merfolk_start_swimming();
+ return;
+ }
+
+ strcpy(info, "You fall into the ");
+
+ strcat(info, (terrain == DNGN_LAVA) ? "lava" :
+ (terrain == DNGN_DEEP_WATER) ? "water"
+ : "programming rift");
+
+ strcat(info, "!");
+ mpr(info);
+
+ more();
+ mesclr();
+
+ if (terrain == DNGN_LAVA)
+ {
+ const int resist = player_res_fire();
+
+ if (resist <= 0)
+ {
+ mpr( "The lava burns you to a cinder!" );
+ ouch( -9999, 0, KILLED_BY_LAVA );
+ }
+ else
+ {
+ // should boost # of bangs per damage in the future {dlb}
+ mpr( "The lava burns you!" );
+ ouch( (10 + random2avg(100, 2)) / resist, 0, KILLED_BY_LAVA );
+ }
+
+ if (you.duration[DUR_CONDENSATION_SHIELD] > 0)
+ {
+ mpr("Your icy shield dissipates!", MSGCH_DURATION);
+ you.duration[DUR_CONDENSATION_SHIELD] = 0;
+ you.redraw_armour_class = 1;
+ }
+ }
+
+ // a distinction between stepping and falling from you.levitation
+ // prevents stepping into a thin stream of lava to get to the other side.
+ if (scramble())
+ {
+ if (place)
+ {
+ if (empty_surrounds(you.x_pos, you.y_pos, DNGN_FLOOR, false, empty))
+ {
+ you.x_pos = empty[0];
+ you.y_pos = empty[1];
+ escape = true;
+ }
+ else
+ escape = false;
+ }
+ else
+ escape = true;
+ }
+ else
+ {
+ // that is, don't display following when fall from levitating
+ if (!place)
+ mpr("You try to escape, but your burden drags you down!");
+ }
+
+ if (escape)
+ {
+ mpr("You manage to scramble free!");
+
+ if (terrain == DNGN_LAVA)
+ scrolls_burn(10, OBJ_SCROLLS);
+
+ return;
+ }
+
+ mpr("You drown...");
+
+ if (terrain == DNGN_LAVA)
+ ouch(-9999, 0, KILLED_BY_LAVA);
+ else if (terrain == DNGN_DEEP_WATER)
+ ouch(-9999, 0, KILLED_BY_WATER);
+
+ // Okay, so you don't trigger a trap when you scramble onto it.
+ //I really can't be bothered right now.
+} // end fall_into_a_pool()
+
+bool scramble(void)
+{
+ int max_carry = carrying_capacity();
+
+ if ((max_carry / 2) + random2(max_carry / 2) <= you.burden)
+ return false;
+ else
+ return true;
+} // end scramble()
+
+void weird_colours(unsigned char coll, char wc[30])
+{
+ unsigned char coll_div16 = coll / 16; // conceivable max is then 16 {dlb}
+
+ // Must start with a consonant!
+ strcpy(wc, (coll_div16 == 0 || coll_div16 == 7) ? "brilliant" :
+ (coll_div16 == 1 || coll_div16 == 8) ? "pale" :
+ (coll_div16 == 2 || coll_div16 == 9) ? "mottled" :
+ (coll_div16 == 3 || coll_div16 == 10) ? "shimmering" :
+ (coll_div16 == 4 || coll_div16 == 11) ? "bright" :
+ (coll_div16 == 5 || coll_div16 == 12) ? "dark" :
+ (coll_div16 == 6 || coll_div16 == 13) ? "shining"
+ : "faint");
+
+ strcat(wc, " ");
+
+ while (coll > 17)
+ coll -= 10;
+
+ strcat(wc, (coll == 0) ? "red" :
+ (coll == 1) ? "purple" :
+ (coll == 2) ? "green" :
+ (coll == 3) ? "orange" :
+ (coll == 4) ? "magenta" :
+ (coll == 5) ? "black" :
+ (coll == 6) ? "grey" :
+ (coll == 7) ? "silver" :
+ (coll == 8) ? "gold" :
+ (coll == 9) ? "pink" :
+ (coll == 10) ? "yellow" :
+ (coll == 11) ? "white" :
+ (coll == 12) ? "brown" :
+ (coll == 13) ? "aubergine" :
+ (coll == 14) ? "ochre" :
+ (coll == 15) ? "leaf green" :
+ (coll == 16) ? "mauve" :
+ (coll == 17) ? "azure"
+ : "colourless");
+
+ return;
+} // end weird_colours()
+
+bool go_berserk(bool intentional)
+{
+ if (you.berserker)
+ {
+ if (intentional)
+ mpr("You're already berserk!");
+ // or else you won't notice -- no message here.
+ return false;
+ }
+
+ if (you.exhausted)
+ {
+ if (intentional)
+ mpr("You're too exhausted to go berserk.");
+ // or else they won't notice -- no message here
+ return false;
+ }
+
+ if (you.is_undead)
+ {
+ if (intentional)
+ mpr("You cannot raise a blood rage in your lifeless body.");
+ // or else you won't notice -- no message here
+ return false;
+ }
+
+ mpr("A red film seems to cover your vision as you go berserk!");
+ mpr("You feel yourself moving faster!");
+ mpr("You feel mighty!");
+
+ you.berserker += 20 + random2avg(19, 2);
+
+ calc_hp();
+ you.hp *= 15;
+ you.hp /= 10;
+
+ deflate_hp(you.hp_max, false);
+
+ if (!you.might)
+ modify_stat( STAT_STRENGTH, 5, true );
+
+ you.might += you.berserker;
+ haste_player( you.berserker );
+
+ if (you.berserk_penalty != NO_BERSERK_PENALTY)
+ you.berserk_penalty = 0;
+
+ return true;
+} // end go_berserk()
+
+bool trap_item(char base_type, char sub_type, char beam_x, char beam_y)
+{
+ item_def item;
+
+ item.base_type = base_type;
+ item.sub_type = sub_type;
+ item.plus = 0;
+ item.plus2 = 0;
+ item.flags = 0;
+ item.special = 0;
+ item.quantity = 1;
+ item.colour = LIGHTCYAN;
+
+ if (base_type == OBJ_MISSILES)
+ {
+ if (sub_type == MI_NEEDLE)
+ {
+ set_item_ego_type( item, OBJ_MISSILES, SPMSL_POISONED );
+ item.colour = WHITE;
+ }
+ else
+ {
+ set_item_ego_type( item, OBJ_MISSILES, SPMSL_NORMAL );
+ }
+ }
+ else
+ {
+ set_item_ego_type( item, OBJ_WEAPONS, SPWPN_NORMAL );
+ }
+
+ if (igrd[beam_x][beam_y] != NON_ITEM)
+ {
+ if (items_stack( item, mitm[ igrd[beam_x][beam_y] ] ))
+ {
+ inc_mitm_item_quantity( igrd[beam_x][beam_y], 1 );
+ return (false);
+ }
+
+ // don't want to go overboard here. Will only generate up to three
+ // separate trap items, or less if there are other items present.
+ if (mitm[ igrd[beam_x][beam_y] ].link != NON_ITEM)
+ {
+ if (mitm[ mitm[ igrd[beam_x][beam_y] ].link ].link != NON_ITEM)
+ return (false);
+ }
+ } // end of if igrd != NON_ITEM
+
+ return (!copy_item_to_grid( item, beam_x, beam_y, 1 ));
+} // end trap_item()
+
+// returns appropriate trap symbol for a given trap type {dlb}
+unsigned char trap_category(unsigned char trap_type)
+{
+ switch (trap_type)
+ {
+ case TRAP_TELEPORT:
+ case TRAP_AMNESIA:
+ case TRAP_ZOT:
+ return (DNGN_TRAP_MAGICAL);
+
+ case TRAP_DART:
+ case TRAP_ARROW:
+ case TRAP_SPEAR:
+ case TRAP_AXE:
+ case TRAP_BLADE:
+ case TRAP_BOLT:
+ case TRAP_NEEDLE:
+ default: // what *would* be the default? {dlb}
+ return (DNGN_TRAP_MECHANICAL);
+ }
+} // end trap_category()
+
+// returns index of the trap for a given (x,y) coordinate pair {dlb}
+int trap_at_xy(int which_x, int which_y)
+{
+
+ for (int which_trap = 0; which_trap < MAX_TRAPS; which_trap++)
+ {
+ if (env.trap[which_trap].x == which_x
+ && env.trap[which_trap].y == which_y)
+ {
+ return (which_trap);
+ }
+ }
+
+ // no idea how well this will be handled elsewhere: {dlb}
+ return (-1);
+} // end trap_at_xy()
diff --git a/trunk/source/misc.h b/trunk/source/misc.h
new file mode 100644
index 0000000000..6ff186a84d
--- /dev/null
+++ b/trunk/source/misc.h
@@ -0,0 +1,135 @@
+/*
+ * File: misc.cc
+ * Summary: Misc functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef MISC_H
+#define MISC_H
+
+
+#include "externs.h"
+
+// last updated 08jan2001 {gdl}
+/* ***********************************************************************
+ * called from: ability - decks - fight - it_use2 - spells1
+ * *********************************************************************** */
+bool go_berserk(bool intentional);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void search_around(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void manage_clouds(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void disarm_trap(struct dist &disa);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - effects - spells3
+ * *********************************************************************** */
+void down_stairs(bool remove_stairs, int old_level);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void fall_into_a_pool(bool place, unsigned char grype);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - misc
+ * *********************************************************************** */
+void handle_traps(char trt, int i, bool trap_known);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void in_a_cloud(void);
+
+// Created Sept 1, 2000 -- bwr
+/* ***********************************************************************
+ * called from: acr misc
+ * *********************************************************************** */
+void merfolk_start_swimming(void);
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: misc - mstuff2
+ * *********************************************************************** */
+void itrap(struct bolt &pbolt, int trapped);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - misc - player - stuff
+ * *********************************************************************** */
+void new_level(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: delay
+ * *********************************************************************** */
+void turn_corpse_into_chunks( item_def &item );
+
+
+// last updated 3jun2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - misc - mstuff2 - spells3
+ * *********************************************************************** */
+int trap_at_xy(int which_x, int which_y);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void up_stairs(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - effects
+ * *********************************************************************** */
+void weird_colours(unsigned char coll, char wc[30]);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: it_use3
+ * *********************************************************************** */
+void weird_writing(char stringy[40]);
+
+
+// last updated 3jun2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - misc - mstuff2 - spells2 - spells3
+ * *********************************************************************** */
+unsigned char trap_category(unsigned char trap_type);
+
+
+#endif
diff --git a/trunk/source/misc/header b/trunk/source/misc/header
new file mode 100644
index 0000000000..9f91952461
--- /dev/null
+++ b/trunk/source/misc/header
@@ -0,0 +1,10 @@
+/*
+ * File:
+ * Summary:
+ * Written by:
+ *
+ * Change History (most recent first):
+ *
+ * <1> --/--/-- --- Created
+ */
+
diff --git a/trunk/source/misc/pfix6.pl b/trunk/source/misc/pfix6.pl
new file mode 100644
index 0000000000..66bf29bef5
--- /dev/null
+++ b/trunk/source/misc/pfix6.pl
@@ -0,0 +1,312 @@
+#!/usr/bin/perl -w
+
+use Term::ReadKey;
+
+use Term::ANSIColor qw(:constants);
+#$Term::ANSIColor::AUTORESET = 1;
+
+use Getopt::Std;
+local( $opt_p, $opt_P );
+getopts( "p:P:" );
+
+$light_pattern = $opt_p || "";
+$heavy_pattern = $opt_P || "\\b";
+
+
+
+
+$infile = "enum.h";
+open( DATA, $infile ) || die "can't open $infile: $!\n";
+
+$category = "";
+
+
+while( <DATA> )
+{
+ chop;
+
+ s#/.*##; # strip comments
+ s#\*.*##; # strip comments
+ s/#.*//;
+ next unless /\S/; # skip empty lines
+ next unless /\w/; # skip special chars
+
+ if ( m/^enum\s+(\S+)/ )
+ {
+ $category = $1;
+ $data{ $category }{ i } = 0;
+ }
+ else
+ {
+ s/,//; # usually a comma
+
+ # possibly a number on the line
+ ( $term, undef, $i ) = split;
+ $string = $term;
+
+ if ( defined $i && $i =~ m/^\d+$/ )
+ {
+ $data{ $category }{ i } = $i;
+ }
+ else
+ {
+ $i = $data{ $category }{ i };
+ }
+
+ $data{ $category }{ array }{ $i } = $string;
+ $data{ $category }{ i }++;
+ }
+}
+
+
+$let = "0";
+foreach $cat ( sort keys %data )
+{
+ $letters{ $let } = $cat;
+ $let++;
+ $let = "A" if $let eq "10";
+ $let = "a" if $let eq "AA";
+}
+
+# @sort_lets = sort { ($b ge "a") <=> ($a ge "a") || $a cmp $b } keys %letters;
+@sort_lets = sort keys %letters;
+foreach $let ( @sort_lets )
+{
+ push @key, "$let - $letters{ $let }";
+}
+
+$klen = 0;
+foreach $k ( @key )
+{
+ $lk = length $k;
+ $klen = $lk if $lk > $klen;
+}
+
+$klen += 1;
+$klen = 20 if $klen > 20;
+
+@bkey = @key;
+foreach $k ( @bkey )
+{
+ if ( length $k < $klen )
+ {
+ $k .= " " x ($klen - length $k);
+ }
+ else
+ {
+ $k = substr( $k, 0, $klen - 1 );
+ $k .= " ";
+ }
+}
+
+$ntpl = int 80/$klen;
+while ( @bkey )
+{
+ push @kd, join "", @bkey[0..$ntpl-1], "\n";
+ splice @bkey, 0, $ntpl;
+}
+
+foreach $file ( @ARGV )
+{
+ open IN, $file or die "can't open $file: $!\n";
+
+ @buff = <IN>;
+ $numlines = @buff;
+
+ @save_buff = @buff;
+
+ @lines_changed = ();
+
+LINE:
+ for( $line = 0; $line < $numlines; $line++ )
+ {
+ if ( $light_pattern && $buff[ $line ] !~ m/$light_pattern/io )
+ {
+ next LINE;
+ }
+
+ $target = $buff[ $line ];
+ %poslist = ();
+
+ while ( $target =~ m/$heavy_pattern(\d+)\b/go )
+ {
+
+ $number = $1;
+ $pos = pos( $target ) - length $number;
+
+ $pre = $`;
+
+ next if $pre =~ m#//#;
+
+ next if $pre =~ m#[\-+*/%] ?$#;
+
+ # skip some unlikely numbers
+ # you[0]
+ next if $number eq "0" && $pre =~ m/you ?\[ ?$/;
+ # arithmetic
+ next if $number eq "1" && $pre =~ m/\D-$/;
+
+
+ $poslist{ $pos } = $number;
+ }
+
+ $longer = 0;
+ foreach $pos ( sort { $a <=> $b } keys %poslist )
+ {
+ $number = $poslist{ $pos };
+
+ $nl = length $number;
+
+ print "\n";
+ print YELLOW, @buff[ $line-8..$line-1];
+
+ #print "-" x ($pos+$longer);
+ #print "v" x $nl;
+ #print "-" x (60 - ($nl+$pos+$longer));
+ #print "\n";
+
+ # print $target;
+ print GREEN, substr( $target, 0, $pos+$longer );
+ print CYAN, substr( $target, $pos+$longer, $nl );
+ print GREEN, substr( $target, $pos+$longer+$nl );
+
+
+ #print "-" x ($pos+$longer);
+ #print "^" x $nl;
+ #print "-" x (60 - ($nl+$pos+$longer));
+ #print "\n";
+
+ print YELLOW, @buff[ $line+1..$line+8];
+
+ print "\n";
+ print RESET;
+ print @kd;
+
+ print "\n";
+ print GREEN, "$file ", BLUE, "$line ", YELLOW, "replace? ";
+ print RESET;
+
+ if ( ! $do_all )
+ {
+ ReadMode('cbreak');
+ $ans = ReadKey(0);
+ ReadMode('normal');
+
+ print $ans;
+ }
+ else
+ {
+ $ans = $do_all;
+ }
+
+ if ( defined $letters{ $ans } )
+ {
+ print "\n";
+
+ # get busy
+ $list = $letters{ $ans };
+ # $rep = ${$data{$list}}[ $number ];
+ $rep = $data{$list}{array}{ $number };
+
+ if ( $rep )
+ {
+ substr( $target, $pos+$longer, $nl ) = $rep;
+ $longer += length( $rep );
+ $longer -= $nl;
+
+ print RED, $target;
+ print RESET;
+
+ push @lines_changed, $line;
+ }
+ else
+ {
+ print BLINK, RED, "###### trouble! ######\n";
+ print RESET;
+ }
+ }
+ elsif ( $ans eq "#" )
+ {
+ $more = <STDIN>;
+ print $more;
+ chop $more;
+
+ $cmd = substr $more, 0, 1;
+ if ( $cmd eq "u" )
+ {
+ print "\n";
+ if ( @lines_changed )
+ {
+ $line_changed = pop @lines_changed;
+
+ $buff[ $line_changed ] = $save_buff[ $line_changed ];
+ $line = $line_changed;
+ redo LINE;
+ }
+ else
+ {
+ redo;
+ }
+ }
+ elsif ( $cmd eq "l" )
+ {
+ $newline = substr $more, 1;
+ $newline += 0;
+ $line = $newline if $newline;
+ redo LINE;
+ }
+ elsif ( $cmd eq "s" )
+ {
+ $saving = 1;
+ last LINE;
+ }
+ elsif ( $cmd eq "a" )
+ {
+ $do_all = substr $more, 1;
+ print "Really answer with $do_all? ";
+ $yn = <STDIN>;
+ if ( $yn !~ m/^yes$/ )
+ {
+ $do_all = "";
+ }
+ redo;
+ }
+ elsif ( $cmd eq "q" )
+ {
+ exit;
+ }
+ }
+ else
+ {
+ if ( $ans =~ m/\S/ )
+ {
+ redo;
+ }
+ }
+ }
+ $buff[ $line ] = $target;
+ }
+ close IN;
+
+ if ( @lines_changed )
+ {
+ $bak = "$file.bak";
+
+ if ( rename( $file, $bak ) )
+ {
+ $outfile = $file;
+ }
+ else
+ {
+ $outfile = "Z$file";
+ print "***** printing changes to $outfile *****\n";
+ }
+
+ open OUT, "> $outfile" or die "can't open $outfile: $!\n";
+ print OUT @buff;
+ close OUT;
+
+ }
+ exit if $saving;
+}
+
diff --git a/trunk/source/mon-data.h b/trunk/source/mon-data.h
new file mode 100644
index 0000000000..8580b8758b
--- /dev/null
+++ b/trunk/source/mon-data.h
@@ -0,0 +1,3838 @@
+#ifndef MONDATA_H
+#define MONDATA_H
+
+/*
+ This whole file was very generously condensed from its initial ugly form
+ by Wladimir van der Laan ($pellbinder).
+ */
+
+
+/* ******************************************************************
+
+ (see "mon-util.h" for the gory details)
+
+ - ordering does not matter, because seekmonster() searches the entire
+ array ... probably not to most efficient thing to do, but so it goes
+
+ - Here are the rows:
+ - row 1: monster id, display character, display colour, name
+ - row 2: monster flags
+ - row 3: mass, experience modifier, charclass, holiness, resist magic
+ - row 4: damage for each of four attacks
+ - row 5: hit dice, described by four parameters
+ - row 6: AC, evasion, speed, speed_inc, sec(spell), corpse_thingy,
+ zombie size, shouts, intel
+ - row 6: gmon_use class
+
+ - Some further explanations:
+
+ - colour: if BLACK, monster uses value of mons_sec
+ - name: if an empty string, name generated automagically (see moname)
+ - mass: if zero, the monster never leaves a corpse
+ - charclass: base monster "type" for a classed monsters
+ - holiness: holy - irritates some gods when killed, immunity from
+ holy wrath weapons
+ natural - baseline monster type
+ undead - immunity from draining, pain, torment; extra
+ damage from hoyl wrath/disruption; affected by
+ repel undead and holy word
+ demonic - similar to undead, but holy wrath does even
+ more damage and disruption and repel undead
+ effects are ignored -- *no* automatic hellfire
+ resistance
+
+
+ exp_mod
+ - the experience given for killing this monster is calculated something
+ like this:
+ experience = hp_max * HD * HD * exp_mod / 10
+ I think.
+
+
+ resist_magic
+ - If -3, = 3 (5?) * hit dice
+
+ damage [4]
+ - up to 4 different attacks
+
+ hp_dice [4]
+ - hit dice, min hp per HD, extra random hp per HD, fixed HP (unique mons)
+
+ speed
+ - less = slower. 5 = half, 20 = double speed.
+
+ speed_inc
+ - this is unnecessary and should be removed. 7 for all monsters.
+
+ corpse_thingy
+ - err, bad name. Describes effects of eating corpses.
+
+ zombie_size
+ - 0 = no zombie possibly, 1 = small zombie (z), 2 = large zombie (Z)
+
+ shouts
+ - various things monsters can do upon seeing you
+ #define S_RANDOM -1
+ #define S_SILENT 0
+ #define S_SHOUT 1 //1=shout
+ #define S_BARK 2 //2=bark
+ #define S_SHOUT2 3 //3=shout twice - eg 2-headed ogres
+ #define S_ROAR 4 //4=roar
+ #define S_SCREAM 5 //5=scream
+ #define S_BELLOW 6 //6=bellow (?)
+ #define S_SCREECH 7 //7=screech
+ #define S_BUZZ 8 //8=buzz
+ #define S_MOAN 9 //9=moan
+
+ intel explanation:
+ - How smart it is. So far, differences here have little effects except
+ for monster's chance of seeing you if stealthy, and really stupid monsters
+ will walk through clouds
+
+ gmon_use explanation:
+ 0 = uses nothing
+ 1 = opens doors
+ 2 = gets and can use its starting equipment
+ 3 = can use weapons/armour
+
+ */
+
+
+// monster 250: The Thing That Should Not Be(tm)
+// do not remove, or seekmonster will crash on unknown mc request
+// it is also a good prototype for new monstersst
+{
+ MONS_PROGRAM_BUG, 'B', LIGHTRED, "program bug",
+ M_NO_EXP_GAIN,
+ 0, 10, MONS_PROGRAM_BUG, MH_NATURAL, -3,
+ { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 },
+ 0, 0, 0, 0, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+// real monsters begin here {dlb}:
+{
+ MONS_GIANT_ANT, 'a', DARKGREY, "giant ant",
+ M_ED_POISON,
+ 700, 10, MONS_GIANT_ANT, MH_NATURAL, -3,
+ { 8, 0, 0, 0 },
+ { 3, 3, 5, 0 },
+ 4, 10, 12, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_INSECT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_GIANT_BAT, 'b', DARKGREY, "giant bat",
+ M_FLIES | M_SEE_INVIS | M_WARM_BLOOD,
+ 150, 4, MONS_GIANT_BAT, MH_NATURAL, -1,
+ { 1, 0, 0, 0 },
+ { 1, 2, 3, 0 },
+ 1, 14, 30, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_ANIMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_CENTAUR, 'c', BROWN, "centaur",
+ M_WARM_BLOOD,
+ 1500, 10, MONS_CENTAUR, MH_NATURAL, -3,
+ { 10, 0, 0, 0 },
+ { 4, 3, 5, 0 },
+ 3, 7, 15, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_RED_DEVIL, '4', RED, "red devil",
+ M_RES_POISON | M_RES_HELLFIRE | M_ED_COLD | M_FLIES,
+ 0, 10, MONS_RED_DEVIL, MH_DEMONIC, -7,
+ { 18, 0, 0, 0 },
+ { 5, 3, 5, 0 },
+ 10, 10, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_ETTIN, 'C', BROWN, "ettin",
+ M_WARM_BLOOD,
+ 0, 10, MONS_ETTIN, MH_NATURAL, -3,
+ { 18, 12, 0, 0 },
+ { 7, 3, 5, 0 },
+ 3, 4, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT2, I_NORMAL,
+ MONUSE_STARTING_EQUIPMENT
+}
+,
+
+{
+ MONS_FUNGUS, 'f', LIGHTGREY, "fungus",
+ M_NO_EXP_GAIN | M_RES_POISON,
+ 0, 10, MONS_FUNGUS, MH_PLANT, 5000,
+ { 0, 0, 0, 0 },
+ { 8, 3, 5, 0 },
+ 1, 0, 0, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_GOBLIN, 'g', LIGHTGREY, "goblin",
+ M_WARM_BLOOD,
+ 400, 10, MONS_GOBLIN, MH_NATURAL, -1,
+ { 4, 0, 0, 0 },
+ { 1, 2, 4, 0 },
+ 0, 12, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_HOUND, 'h', BROWN, "hound",
+ M_SEE_INVIS | M_WARM_BLOOD,
+ 300, 10, MONS_HOUND, MH_NATURAL, -3,
+ { 6, 0, 0, 0 },
+ { 3, 3, 5, 0 },
+ 2, 13, 15, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_BARK, I_ANIMAL,
+ MONUSE_NOTHING
+}
+,
+
+// note: these things regenerate
+{
+ MONS_IMP, '5', RED, "imp",
+ M_RES_POISON | M_RES_HELLFIRE | M_ED_COLD | M_FLIES | M_SEE_INVIS | M_SPEAKS,
+ 0, 13, MONS_IMP, MH_DEMONIC, -9,
+ { 4, 0, 0, 0 },
+ { 3, 3, 3, 0 },
+ 3, 14, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_JACKAL, 'j', YELLOW, "jackal",
+ M_WARM_BLOOD,
+ 200, 10, MONS_JACKAL, MH_NATURAL, -1,
+ { 3, 0, 0, 0 },
+ { 1, 3, 5, 0 },
+ 2, 12, 14, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_BARK, I_ANIMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_KILLER_BEE, 'k', YELLOW, "killer bee",
+ M_ED_POISON | M_FLIES,
+ 150, 11, MONS_KILLER_BEE, MH_NATURAL, -3,
+ { 10, 0, 0, 0 },
+ { 3, 3, 5, 0 },
+ 2, 18, 20, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_BUZZ, I_INSECT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_KILLER_BEE_LARVA, 'w', LIGHTGREY, "killer bee larva",
+ M_ED_POISON | M_NO_SKELETON,
+ 150, 5, MONS_KILLER_BEE_LARVA, MH_NATURAL, -3,
+ { 3, 0, 0, 0 },
+ { 1, 3, 5, 0 },
+ 1, 5, 5, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_MANTICORE, 'm', BROWN, "manticore",
+ M_WARM_BLOOD,
+ 1800, 10, MONS_MANTICORE, MH_NATURAL, -3,
+ { 14, 8, 8, 0 },
+ { 9, 3, 5, 0 },
+ 5, 7, 7, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SILENT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+// this thing doesn't have nr. 13 for nothing, has it? ($pellbinder)
+{
+ MONS_NECROPHAGE, 'n', DARKGREY, "necrophage",
+ M_RES_POISON | M_RES_COLD,
+ 500, 10, MONS_NECROPHAGE, MH_UNDEAD, -5,
+ { 8, 0, 0, 0 },
+ { 5, 3, 5, 0 },
+ 2, 10, 10, 7, MST_NO_SPELLS, CE_HCL, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_ORC, 'o', LIGHTRED, "orc",
+ M_WARM_BLOOD,
+ 600, 10, MONS_ORC, MH_NATURAL, -3,
+ { 5, 0, 0, 0 },
+ { 1, 4, 6, 0 },
+ 0, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+// XP modifier is 5 for these, because they really aren't all that
+// dangerous, but still come out at 200+ XP
+{
+ MONS_PHANTOM, 'p', BLUE, "phantom",
+ M_RES_POISON | M_RES_COLD,
+ 0, 5, MONS_PHANTOM, MH_UNDEAD, -4,
+ { 10, 0, 0, 0 },
+ { 7, 3, 5, 0 },
+ 3, 13, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_QUASIT, 'q', LIGHTGREY, "quasit",
+ M_RES_POISON | M_RES_FIRE | M_RES_COLD,
+ 0, 10, MONS_QUASIT, MH_DEMONIC, 50,
+ { 3, 2, 2, 0 },
+ { 3, 2, 6, 0 },
+ 5, 17, 15, 7, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_INSECT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_RAT, 'r', BROWN, "rat",
+ M_WARM_BLOOD,
+ 200, 10, MONS_RAT, MH_NATURAL, -1,
+ { 3, 0, 0, 0 },
+ { 1, 1, 3, 0 },
+ 1, 10, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_ANIMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_SCORPION, 's', DARKGREY, "scorpion",
+ M_ED_POISON,
+ 500, 10, MONS_SCORPION, MH_NATURAL, -3,
+ { 10, 0, 0, 0 },
+ { 3, 3, 5, 0 },
+ 5, 10, 10, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
+ MONUSE_NOTHING
+}
+,
+
+/* ******************************************************************
+// the tunneling worm is no more ...
+// not until it can be reimplemented safely {dlb}
+{
+ MONS_TUNNELING_WORM, 't', LIGHTRED, "tunneling worm",
+ M_RES_POISON,
+ 0, 10, 19, MH_NATURAL, 5000,
+ { 50, 0, 0, 0 },
+ { 10, 5, 5, 0 },
+ 3, 3, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_REPTILE,
+ MONUSE_NOTHING
+}
+,
+****************************************************************** */
+
+{
+ MONS_UGLY_THING, 'u', BROWN, "ugly thing",
+ M_WARM_BLOOD | M_AMPHIBIOUS,
+ 600, 10, MONS_UGLY_THING, MH_NATURAL, -3,
+ { 12, 0, 0, 0 },
+ { 8, 3, 5, 0 },
+ 3, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_FIRE_VORTEX, 'v', RED, "fire vortex",
+ M_RES_POISON | M_RES_FIRE | M_ED_COLD | M_RES_ELEC | M_LEVITATE | M_CONFUSED,
+ 0, 5, MONS_FIRE_VORTEX, MH_NONLIVING, 5000,
+ { 30, 0, 0, 0 },
+ { 3, 3, 5, 0 },
+ 0, 5, 15, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_WORM, 'w', LIGHTRED, "worm",
+ M_NO_SKELETON,
+ 350, 4, MONS_WORM, MH_NATURAL, -2,
+ { 12, 0, 0, 0 },
+ { 5, 3, 5, 0 },
+ 1, 5, 6, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_INSECT,
+ MONUSE_NOTHING
+}
+,
+
+// random
+{
+ MONS_ABOMINATION_SMALL, 'x', BLACK, "abomination",
+ M_NO_FLAGS,
+ 0, 10, MONS_ABOMINATION_SMALL, MH_DEMONIC, -5,
+ { 23, 0, 0, 0 },
+ { 6, 2, 5, 0 },
+ 0, 0, 0, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_YELLOW_WASP, 'y', YELLOW, "yellow wasp",
+ M_ED_POISON | M_FLIES,
+ 220, 12, MONS_YELLOW_WASP, MH_NATURAL, -3,
+ { 13, 0, 0, 0 },
+ { 4, 3, 5, 0 },
+ 5, 14, 15, 7, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_INSECT,
+ MONUSE_NOTHING
+}
+,
+
+// small zombie
+{
+ MONS_ZOMBIE_SMALL, 'z', BROWN, "",
+ M_RES_POISON | M_RES_COLD,
+ 0, 6, MONS_ZOMBIE_SMALL, MH_UNDEAD, -1,
+ { 10, 0, 0, 0 },
+ { 1, 5, 5, 0 },
+ 0, 4, 5, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_ANGEL, 'A', WHITE, "Angel",
+ M_RES_POISON | M_FLIES | M_RES_ELEC | M_SPELLCASTER,
+ 0, 10, MONS_ANGEL, MH_HOLY, -8,
+ { 20, 0, 0, 0 },
+ { 9, 3, 5, 0 },
+ 10, 10, 10, 7, MST_ANGEL, CE_NOCORPSE, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_GIANT_BEETLE, 'B', DARKGREY, "giant beetle",
+ M_ED_POISON,
+ 1000, 10, MONS_GIANT_BEETLE, MH_NATURAL, -3,
+ { 20, 0, 0, 0 },
+ { 5, 7, 6, 0 },
+ 10, 3, 5, 7, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_SILENT, I_INSECT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_CYCLOPS, 'C', BROWN, "cyclops",
+ M_WARM_BLOOD,
+ 2500, 10, MONS_CYCLOPS, MH_NATURAL, -3,
+ { 35, 0, 0, 0 },
+ { 9, 3, 5, 0 },
+ 5, 3, 7, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SHOUT, I_NORMAL,
+ MONUSE_STARTING_EQUIPMENT
+}
+,
+
+{
+ MONS_DRAGON, 'D', GREEN, "dragon",
+ M_RES_POISON | M_RES_FIRE | M_ED_COLD | M_FLIES, //jmf: warm blood?
+ 2200, 12, MONS_DRAGON, MH_NATURAL, -4,
+ { 20, 13, 13, 0 },
+ { 12, 5, 5, 0 },
+ 10, 8, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SILENT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+// These guys get understated because the experience code can't see
+// that they wield two weapons... I'm raising their xp modifier. -- bwr
+{
+ MONS_TWO_HEADED_OGRE, 'O', LIGHTRED, "two-headed ogre",
+ M_WARM_BLOOD,
+ 1500, 15, MONS_TWO_HEADED_OGRE, MH_NATURAL, -4,
+ { 17, 13, 0, 0 },
+ { 6, 3, 5, 0 },
+ 1, 4, 8, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT2, I_NORMAL,
+ MONUSE_STARTING_EQUIPMENT
+}
+,
+
+{
+ MONS_FIEND, '1', LIGHTRED, "Fiend", //jmf: was RED, like Balrog
+ M_RES_POISON | M_RES_HELLFIRE | M_ED_COLD | M_FLIES | M_SEE_INVIS,
+ 0, 18, MONS_FIEND, MH_DEMONIC, -12,
+ { 25, 15, 15, 0 },
+ { 18, 3, 5, 0 },
+ 15, 6, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_ROAR, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_GIANT_SPORE, 'G', GREEN, "giant spore",
+ M_RES_POISON | M_LEVITATE,
+ 0, 10, MONS_GIANT_SPORE, MH_NATURAL, -3,
+ { 1, 0, 0, 0 },
+ { 1, 0, 0, 1 },
+ 0, 10, 15, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_HOBGOBLIN, 'g', BROWN, "hobgoblin",
+ M_WARM_BLOOD,
+ 500, 10, MONS_HOBGOBLIN, MH_NATURAL, -1,
+ { 5, 0, 0, 0 },
+ { 1, 4, 5, 0 },
+ 2, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_ICE_BEAST, 'I', WHITE, "ice beast",
+ M_RES_POISON | M_ED_FIRE | M_RES_COLD,
+ 0, 12, MONS_ICE_BEAST, MH_NATURAL, -3,
+ { 5, 0, 0, 0 },
+ { 5, 3, 5, 0 },
+ 5, 10, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_ANIMAL_LIKE,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_JELLY, 'J', LIGHTRED, "jelly",
+ M_RES_POISON | M_SEE_INVIS | M_SPLITS | M_AMPHIBIOUS,
+ 0, 13, MONS_JELLY, MH_NATURAL, -3,
+ { 8, 0, 0, 0 },
+ { 3, 5, 5, 0 },
+ 0, 2, 9, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_EATS_ITEMS
+}
+,
+
+{
+ MONS_KOBOLD, 'K', BROWN, "kobold",
+ M_WARM_BLOOD,
+ 400, 10, MONS_KOBOLD, MH_NATURAL, -1,
+ { 4, 0, 0, 0 },
+ { 1, 2, 3, 0 },
+ 2, 12, 10, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_LICH, 'L', WHITE, "lich",
+ M_RES_POISON | M_RES_COLD | M_RES_ELEC | M_SPELLCASTER | M_ACTUAL_SPELLS | M_SEE_INVIS,
+ 0, 16, MONS_LICH, MH_UNDEAD, -11,
+ { 15, 0, 0, 0 },
+ { 20, 2, 4, 0 },
+ 10, 10, 10, 7, MST_LICH_I, CE_NOCORPSE, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_MUMMY, 'M', WHITE, "mummy",
+ M_RES_POISON | M_ED_FIRE | M_RES_COLD,
+ 0, 10, MONS_MUMMY, MH_UNDEAD, -5,
+ { 20, 0, 0, 0 },
+ { 3, 5, 3, 0 },
+ 3, 6, 6, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_ANIMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_GUARDIAN_NAGA, 'N', LIGHTGREEN, "guardian naga",
+ M_RES_POISON | M_SPELLCASTER | M_SEE_INVIS | M_ACTUAL_SPELLS | M_WARM_BLOOD,
+ 350, 10, MONS_GUARDIAN_NAGA, MH_NATURAL, -6,
+ { 19, 0, 0, 0 },
+ { 8, 3, 5, 0 },
+ 6, 14, 15, 7, MST_GUARDIAN_NAGA, CE_MUTAGEN_RANDOM, Z_SMALL, S_SHOUT, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_OGRE, 'O', BROWN, "ogre",
+ M_WARM_BLOOD,
+ 1300, 10, MONS_OGRE, MH_NATURAL, -3,
+ { 17, 0, 0, 0 },
+ { 5, 3, 5, 0 },
+ 1, 6, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_NORMAL,
+ MONUSE_STARTING_EQUIPMENT
+}
+,
+
+{
+ MONS_PLANT, 'P', GREEN, "plant",
+ M_NO_EXP_GAIN,
+ 0, 10, MONS_PLANT, MH_PLANT, 5000,
+ { 0, 0, 0, 0 },
+ { 10, 3, 5, 0 },
+ 10, 0, 0, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_QUEEN_BEE, 'Q', YELLOW, "queen bee",
+ M_ED_POISON | M_FLIES,
+ 200, 14, MONS_QUEEN_BEE, MH_NATURAL, -3,
+ { 20, 0, 0, 0 },
+ { 7, 3, 5, 0 },
+ 10, 10, 10, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_RAKSHASA, 'R', YELLOW, "rakshasa",
+ M_RES_POISON | M_SPELLCASTER | M_SEE_INVIS,
+ 0, 15, MONS_RAKSHASA, MH_NATURAL, -10,
+ { 20, 0, 0, 0 },
+ { 10, 3, 5, 0 },
+ 10, 14, 10, 7, MST_RAKSHASA, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_SNAKE, 'S', GREEN, "snake",
+ M_COLD_BLOOD | M_AMPHIBIOUS,
+ 200, 10, MONS_SNAKE, MH_NATURAL, -3,
+ { 5, 0, 0, 0 },
+ { 2, 3, 5, 0 },
+ 1, 15, 13, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_REPTILE,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_TROLL, 'T', BROWN, "troll",
+ M_WARM_BLOOD,
+ 1500, 10, MONS_TROLL, MH_NATURAL, -3,
+ { 20, 15, 15, 0 },
+ { 7, 3, 5, 0 },
+ 3, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_UNSEEN_HORROR, 'x', MAGENTA, "unseen horror",
+ M_LEVITATE | M_SEE_INVIS | M_RES_ELEC | M_INVIS,
+ 0, 12, MONS_UNSEEN_HORROR, MH_NATURAL, -3,
+ { 12, 0, 0, 0 },
+ { 7, 3, 5, 0 },
+ 5, 10, 30, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_ANIMAL_LIKE,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_VAMPIRE, 'V', RED, "vampire",
+ M_RES_POISON | M_RES_COLD | M_SPELLCASTER | M_SEE_INVIS,
+ 0, 11, MONS_VAMPIRE, MH_UNDEAD, -6,
+ { 22, 0, 0, 0 },
+ { 6, 3, 5, 0 },
+ 10, 10, 10, 7, MST_VAMPIRE, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_WRAITH, 'W', DARKGREY, "wraith",
+ M_RES_POISON | M_RES_COLD | M_LEVITATE | M_SEE_INVIS,
+ 0, 11, MONS_WRAITH, MH_UNDEAD, -7,
+ { 13, 0, 0, 0 },
+ { 6, 3, 5, 0 },
+ 10, 10, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+// Large abom: (the previous one was small)
+{
+ MONS_ABOMINATION_LARGE, 'X', BLACK, "abomination",
+ M_NO_FLAGS,
+ 0, 10, MONS_ABOMINATION_LARGE, MH_DEMONIC, -7,
+ { 40, 0, 0, 0 },
+ { 11, 2, 5, 0 },
+ 0, 0, 0, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_YAK, 'Y', BROWN, "yak",
+ M_WARM_BLOOD,
+ 1200, 10, MONS_YAK, MH_NATURAL, -3,
+ { 18, 0, 0, 0 },
+ { 7, 3, 5, 0 },
+ 4, 7, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_BELLOW, I_ANIMAL,
+ MONUSE_NOTHING
+}
+,
+
+// big zombie
+{
+ MONS_ZOMBIE_LARGE, 'Z', BROWN, "",
+ M_RES_POISON | M_RES_COLD,
+ 0, 6, MONS_ZOMBIE_LARGE, MH_UNDEAD, -1,
+ { 23, 0, 0, 0 },
+ { 6, 3, 5, 0 },
+ 8, 5, 5, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_ORC_WARRIOR, 'o', YELLOW, "orc warrior",
+ M_WARM_BLOOD,
+ 0, 10, MONS_ORC, MH_NATURAL, -3,
+ { 20, 0, 0, 0 },
+ { 4, 4, 6, 0 },
+ 0, 13, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_KOBOLD_DEMONOLOGIST, 'K', MAGENTA, "kobold demonologist",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD,
+ 0, 10, MONS_KOBOLD, MH_NATURAL, -5,
+ { 4, 0, 0, 0 },
+ { 4, 3, 5, 0 },
+ 2, 13, 10, 7, MST_KOBOLD_DEMONOLOGIST, CE_POISONOUS, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_ORC_WIZARD, 'o', MAGENTA, "orc wizard",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD,
+ 0, 10, MONS_ORC, MH_NATURAL, -5,
+ { 5, 0, 0, 0 },
+ { 3, 3, 4, 0 },
+ 1, 12, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_ORC_KNIGHT, 'o', LIGHTCYAN, "orc knight",
+ M_WARM_BLOOD,
+ 0, 10, MONS_ORC, MH_NATURAL, -3,
+ { 25, 0, 0, 0 },
+ { 9, 4, 7, 0 },
+ 2, 13, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+/* ******************************************************************
+// the tunneling worm is no more ...
+// not until it can be reimplemented safely {dlb}
+{
+ MONS_WORM_TAIL, '~', LIGHTRED, "worm tail",
+ M_NO_EXP_GAIN | M_RES_POISON,
+ 0, 10, 56, MH_NATURAL, 5000,
+ { 0, 0, 0, 0 },
+ { 10, 5, 5, 0 },
+ 3, 3, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+****************************************************************** */
+
+{
+ MONS_WYVERN, 'D', LIGHTRED, "wyvern",
+ M_NO_FLAGS, //jmf: warm blood?
+ 2000, 10, MONS_WYVERN, MH_NATURAL, -3,
+ { 20, 0, 0, 0 },
+ { 5, 3, 5, 0 },
+ 5, 10, 15, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_ANIMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_BIG_KOBOLD, 'K', RED, "big kobold",
+ M_WARM_BLOOD,
+ 0, 10, MONS_BIG_KOBOLD, MH_NATURAL, -3,
+ { 7, 0, 0, 0 },
+ { 5, 3, 5, 0 },
+ 3, 12, 10, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_GIANT_EYEBALL, 'G', WHITE, "giant eyeball",
+ M_NO_SKELETON | M_LEVITATE,
+ 400, 10, MONS_GIANT_EYEBALL, MH_NATURAL, -3,
+ { 0, 0, 0, 0 },
+ { 3, 3, 5, 0 },
+ 0, 1, 3, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_WIGHT, 'W', LIGHTGREY, "wight",
+ M_RES_POISON | M_RES_COLD,
+ 0, 10, MONS_WIGHT, MH_UNDEAD, -4,
+ { 8, 0, 0, 0 },
+ { 3, 3, 5, 0 },
+ 4, 10, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_OKLOB_PLANT, 'P', GREEN, "oklob plant",
+ M_RES_POISON,
+ 0, 10, MONS_OKLOB_PLANT, MH_PLANT, -3,
+ { 0, 0, 0, 0 },
+ { 10, 3, 5, 0 },
+ 10, 0, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_WOLF_SPIDER, 's', BROWN, "wolf spider",
+ M_ED_POISON,
+ 800, 10, MONS_WOLF_SPIDER, MH_NATURAL, -3,
+ { 20, 0, 0, 0 },
+ { 8, 3, 5, 0 },
+ 3, 10, 15, 7, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_SILENT, I_INSECT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_SHADOW, ' ', BLACK, "shadow",
+ M_RES_POISON | M_RES_COLD | M_SEE_INVIS,
+ 0, 10, MONS_SHADOW, MH_UNDEAD, -5,
+ { 5, 0, 0, 0 },
+ { 3, 3, 5, 0 },
+ 12, 10, 10, 7, BLACK, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_ANIMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_HUNGRY_GHOST, 'p', GREEN, "hungry ghost",
+ M_RES_POISON | M_RES_COLD | M_SEE_INVIS | M_FLIES,
+ 0, 10, MONS_HUNGRY_GHOST, MH_UNDEAD, -4,
+ { 5, 0, 0, 0 },
+ { 7, 3, 5, 0 },
+ 0, 17, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_EYE_OF_DRAINING, 'G', LIGHTGREY, "eye of draining",
+ M_NO_SKELETON | M_LEVITATE | M_SEE_INVIS,
+ 400, 10, MONS_EYE_OF_DRAINING, MH_NATURAL, 5000,
+ { 0, 0, 0, 0 },
+ { 7, 3, 5, 0 },
+ 3, 1, 5, 7, MST_NO_SPELLS, CE_MUTAGEN_RANDOM, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_BUTTERFLY, 'b', BLACK, "butterfly",
+ M_FLIES | M_ED_POISON | M_CONFUSED,
+ 150, 10, MONS_BUTTERFLY, MH_NATURAL, -3,
+ { 0, 0, 0, 0 },
+ { 1, 3, 5, 0 },
+ 0, 25, 25, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_INSECT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_WANDERING_MUSHROOM, 'f', BROWN, "wandering mushroom",
+ M_RES_POISON,
+ 0, 10, MONS_WANDERING_MUSHROOM, MH_PLANT, -3,
+ { 20, 0, 0, 0 },
+ { 8, 3, 5, 0 },
+ 5, 0, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_EFREET, 'E', RED, "efreet",
+ M_RES_POISON | M_RES_FIRE | M_ED_COLD | M_SPELLCASTER | M_LEVITATE,
+ 0, 12, MONS_EFREET, MH_DEMONIC, -3,
+ { 12, 0, 0, 0 },
+ { 7, 3, 5, 0 },
+ 10, 5, 10, 7, MST_EFREET, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_BRAIN_WORM, 'w', LIGHTMAGENTA, "brain worm",
+ M_SPELLCASTER,
+ 150, 10, MONS_BRAIN_WORM, MH_NATURAL, -3,
+ { 0, 0, 0, 0 },
+ { 5, 3, 3, 0 },
+ 1, 5, 10, 7, MST_BRAIN_WORM, CE_POISONOUS, Z_SMALL, S_SILENT, I_REPTILE,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_GIANT_ORANGE_BRAIN, 'G', LIGHTRED, "giant orange brain",
+ M_NO_SKELETON | M_SPELLCASTER | M_LEVITATE | M_SEE_INVIS,
+ 1000, 13, MONS_GIANT_ORANGE_BRAIN, MH_NATURAL, -8,
+ { 0, 0, 0, 0 },
+ { 10, 3, 5, 0 },
+ 2, 4, 10, 7, MST_GIANT_ORANGE_BRAIN, CE_MUTAGEN_RANDOM, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_BOULDER_BEETLE, 'B', LIGHTGREY, "boulder beetle",
+ M_ED_POISON,
+ 2500, 10, MONS_BOULDER_BEETLE, MH_NATURAL, -3,
+ { 35, 0, 0, 0 },
+ { 9, 3, 5, 0 },
+ 20, 2, 3, 7, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_SILENT, I_INSECT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_FLYING_SKULL, 'z', WHITE, "flying skull",
+ M_RES_POISON | M_RES_FIRE | M_RES_COLD | M_RES_ELEC | M_LEVITATE,
+ 0, 10, MONS_FLYING_SKULL, MH_UNDEAD, -3,
+ { 7, 0, 0, 0 },
+ { 2, 3, 5, 0 },
+ 10, 17, 15, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SCREAM, I_ANIMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_HELL_HOUND, 'h', DARKGREY, "hell hound",
+ M_RES_POISON | M_RES_HELLFIRE | M_ED_COLD | M_SEE_INVIS,
+ 0, 10, MONS_HELL_HOUND, MH_DEMONIC, -3,
+ { 13, 0, 0, 0 },
+ { 5, 3, 5, 0 },
+ 6, 13, 15, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_BARK, I_NORMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_MINOTAUR, 'm', LIGHTRED, "minotaur",
+ M_WARM_BLOOD,
+ 1500, 10, MONS_MINOTAUR, MH_NATURAL, -3,
+ { 35, 0, 0, 0 },
+ { 13, 3, 5, 0 },
+ 5, 7, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_BELLOW, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_ICE_DRAGON, 'D', WHITE, "ice dragon",
+ M_RES_POISON | M_ED_FIRE | M_RES_COLD | M_FLIES,
+ 2200, 10, MONS_ICE_DRAGON, MH_NATURAL, -3,
+ { 17, 17, 17, 0 },
+ { 12, 5, 5, 0 },
+ 10, 8, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SILENT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_SLIME_CREATURE, 'J', GREEN, "slime creature",
+ M_RES_POISON | M_AMPHIBIOUS,
+ 0, 5, MONS_SLIME_CREATURE, MH_NATURAL, -3,
+ { 22, 0, 0, 0 },
+ { 11, 3, 5, 0 },
+ 1, 4, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_FREEZING_WRAITH, 'W', LIGHTBLUE, "freezing wraith",
+ M_RES_POISON | M_ED_FIRE | M_RES_COLD | M_LEVITATE | M_SEE_INVIS,
+ 0, 10, MONS_FREEZING_WRAITH, MH_UNDEAD, -4,
+ { 19, 0, 0, 0 },
+ { 8, 3, 5, 0 },
+ 12, 10, 8, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+// fake R - conjured by the R's illusion spell.
+{
+ MONS_RAKSHASA_FAKE, 'R', YELLOW, "rakshasa",
+ M_RES_POISON,
+ 0, 10, MONS_RAKSHASA_FAKE, MH_NATURAL, 5000,
+ { 0, 0, 0, 0 },
+ { 1, 0, 0, 1 },
+ 0, 30, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_ROAR, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_GREAT_ORB_OF_EYES, 'G', LIGHTGREEN, "great orb of eyes",
+ M_NO_SKELETON | M_RES_POISON | M_SPELLCASTER | M_LEVITATE | M_SEE_INVIS,
+ 900, 13, MONS_GREAT_ORB_OF_EYES, MH_NATURAL, 5000,
+ { 20, 0, 0, 0 },
+ { 12, 3, 5, 0 },
+ 10, 3, 10, 7, MST_GREAT_ORB_OF_EYES, CE_MUTAGEN_RANDOM, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_HELLION, '3', BLACK, "hellion",
+ M_RES_POISON | M_RES_HELLFIRE | M_ED_COLD | M_SPELLCASTER | M_ON_FIRE,
+ 0, 11, MONS_HELLION, MH_DEMONIC, -7,
+ { 10, 0, 0, 0 },
+ { 7, 3, 5, 0 },
+ 5, 10, 13, 7, RED, CE_NOCORPSE, Z_NOZOMBIE, S_SCREAM, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_ROTTING_DEVIL, '4', GREEN, "rotting devil",
+ M_RES_POISON | M_RES_COLD,
+ 0, 10, MONS_ROTTING_DEVIL, MH_DEMONIC, -7,
+ { 8, 0, 0, 0 },
+ { 5, 3, 5, 0 },
+ 2, 10, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_TORMENTOR, '3', YELLOW, "tormentor",
+ M_RES_POISON | M_RES_FIRE | M_SPELLCASTER | M_FLIES | M_SPEAKS,
+ 0, 10, MONS_TORMENTOR, MH_DEMONIC, -6,
+ { 8, 8, 0, 0 },
+ { 7, 3, 5, 0 },
+ 12, 12, 13, 7, MST_TORMENTOR, CE_NOCORPSE, Z_NOZOMBIE, S_ROAR, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_REAPER, '2', LIGHTGREY, "reaper",
+ M_RES_POISON | M_RES_COLD | M_SEE_INVIS,
+ 0, 10, MONS_REAPER, MH_DEMONIC, 5000,
+ { 32, 0, 0, 0 },
+ { 8, 3, 5, 0 },
+ 15, 10, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ MONUSE_STARTING_EQUIPMENT
+}
+,
+
+{
+ MONS_SOUL_EATER, '2', DARKGREY, "soul eater",
+ M_RES_POISON | M_RES_COLD | M_LEVITATE | M_SEE_INVIS,
+ 0, 12, MONS_SOUL_EATER, MH_DEMONIC, -10,
+ { 25, 0, 0, 0 },
+ { 11, 3, 5, 0 },
+ 18, 10, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_HAIRY_DEVIL, '4', LIGHTRED, "hairy devil",
+ M_RES_POISON,
+ 0, 10, MONS_HAIRY_DEVIL, MH_DEMONIC, -4,
+ { 9, 9, 0, 0 },
+ { 6, 3, 5, 0 },
+ 7, 10, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_ICE_DEVIL, '2', WHITE, "ice devil",
+ M_RES_POISON | M_ED_FIRE | M_RES_COLD | M_SEE_INVIS,
+ 0, 11, MONS_ICE_DEVIL, MH_DEMONIC, -6,
+ { 16, 0, 0, 0 },
+ { 11, 3, 5, 0 },
+ 12, 10, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_BLUE_DEVIL, '3', BLUE, "blue devil",
+ M_RES_POISON | M_ED_FIRE | M_RES_COLD | M_FLIES,
+ 0, 10, MONS_BLUE_DEVIL, MH_DEMONIC, -5,
+ { 21, 0, 0, 0 },
+ { 7, 3, 5, 0 },
+ 14, 10, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+// random
+{
+ MONS_BEAST, '4', BROWN, "beast",
+ M_NO_FLAGS,
+ 0, 10, MONS_BEAST, MH_DEMONIC, -3,
+ { 12, 0, 0, 0 },
+ { 5, 3, 5, 0 },
+ 0, 0, 0, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_RANDOM, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_IRON_DEVIL, '3', CYAN, "iron devil",
+ M_RES_ELEC | M_RES_POISON | M_RES_HELLFIRE | M_RES_COLD,
+ 0, 10, MONS_IRON_DEVIL, MH_DEMONIC, -6,
+ { 14, 14, 0, 0 },
+ { 8, 3, 5, 0 },
+ 16, 8, 8, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SCREECH, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_GLOWING_SHAPESHIFTER, '@', RED, "glowing shapeshifter",
+ M_NO_FLAGS,
+ 600, 10, MONS_SHAPESHIFTER, MH_NATURAL, -6,
+ { 15, 0, 0, 0 },
+ { 10, 3, 5, 0 },
+ 0, 10, 10, 7, MST_NO_SPELLS, CE_MUTAGEN_RANDOM, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_SHAPESHIFTER, '@', LIGHTRED, "shapeshifter",
+ M_NO_FLAGS,
+ 600, 10, MONS_SHAPESHIFTER, MH_NATURAL, -6,
+ { 5, 0, 0, 0 },
+ { 7, 3, 5, 0 },
+ 0, 10, 10, 7, MST_NO_SPELLS, CE_MUTAGEN_RANDOM, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_GIANT_MITE, 's', LIGHTRED, "giant mite",
+ M_ED_POISON,
+ 350, 10, MONS_GIANT_MITE, MH_NATURAL, -1,
+ { 5, 0, 0, 0 },
+ { 2, 3, 5, 0 },
+ 1, 7, 10, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_STEAM_DRAGON, 'd', LIGHTGREY, "steam dragon",
+ M_SPELLCASTER | M_FLIES,
+ 1000, 10, MONS_STEAM_DRAGON, MH_NATURAL, -3,
+ { 12, 0, 0, 0 },
+ { 4, 5, 5, 0 },
+ 5, 10, 10, 7, MST_STEAM_DRAGON, CE_CLEAN, Z_BIG, S_SILENT, I_ANIMAL_LIKE,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_VERY_UGLY_THING, 'u', RED, "very ugly thing",
+ M_WARM_BLOOD | M_AMPHIBIOUS,
+ 750, 10, MONS_VERY_UGLY_THING, MH_NATURAL, -3,
+ { 17, 0, 0, 0 },
+ { 12, 3, 5, 0 },
+ 4, 8, 8, 7, MST_NO_SPELLS, CE_MUTAGEN_RANDOM, Z_BIG, S_SHOUT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_ORC_SORCERER, 'o', DARKGREY, "orc sorcerer",
+ M_RES_FIRE | M_SPELLCASTER | M_SEE_INVIS | M_SPEAKS | M_ACTUAL_SPELLS | M_WARM_BLOOD,
+ 600, 12, MONS_ORC, MH_NATURAL, -3,
+ { 7, 0, 0, 0 },
+ { 8, 2, 3, 0 },
+ 5, 12, 10, 7, MST_ORC_SORCERER, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_HIPPOGRIFF, 'H', BROWN, "hippogriff",
+ M_FLIES | M_WARM_BLOOD,
+ 1000, 10, MONS_HIPPOGRIFF, MH_NATURAL, -3,
+ { 10, 8, 8, 0 },
+ { 7, 3, 5, 0 },
+ 2, 7, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SCREECH, I_ANIMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_GRIFFON, 'H', YELLOW, "griffon",
+ M_FLIES | M_WARM_BLOOD,
+ 1800, 10, MONS_GRIFFON, MH_NATURAL, -3,
+ { 18, 10, 10, 0 },
+ { 12, 3, 5, 0 },
+ 4, 6, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SCREECH, I_ANIMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_HYDRA, 'D', LIGHTGREEN, "hydra",
+ M_RES_POISON | M_AMPHIBIOUS, // because it likes the swamp -- bwr
+ 1800, 11, MONS_HYDRA, MH_NATURAL, -3,
+ { 18, 0, 0, 0 },
+ { 13, 3, 5, 0 },
+ 0, 5, 10, 7, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_ROAR, I_REPTILE,
+ MONUSE_OPEN_DOORS
+}
+,
+
+// small skeleton
+{
+ MONS_SKELETON_SMALL, 'z', LIGHTGREY, "",
+ M_RES_POISON | M_RES_COLD,
+ 0, 10, MONS_SKELETON_SMALL, MH_UNDEAD, -1,
+ { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 },
+ 0, 0, 0, 0, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+// large skeleton
+{
+ MONS_SKELETON_LARGE, 'Z', LIGHTGREY, "",
+ M_RES_POISON | M_RES_COLD,
+ 0, 10, MONS_SKELETON_LARGE, MH_UNDEAD, -1,
+ { 0, 0, 0, 0 },
+ { 0, 0, 0, 0 },
+ 0, 0, 0, 0, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+
+{
+ MONS_HELL_KNIGHT, '@', RED, "hell knight",
+ M_RES_FIRE | M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD,
+ 550, 10, MONS_HUMAN, MH_NATURAL, -3,
+ { 13, 0, 0, 0 },
+ { 10, 3, 6, 0 },
+ 0, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_NECROMANCER, '@', DARKGREY, "necromancer",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD,
+ 550, 10, MONS_HUMAN, MH_NATURAL, -4,
+ { 6, 0, 0, 0 },
+ { 10, 2, 4, 0 },
+ 0, 13, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_WIZARD, '@', MAGENTA, "wizard",
+ M_RES_ELEC | M_SPELLCASTER | M_SPEAKS | M_ACTUAL_SPELLS | M_WARM_BLOOD,
+ 550, 10, MONS_HUMAN, MH_NATURAL, -4,
+ { 6, 0, 0, 0 },
+ { 10, 2, 4, 0 },
+ 0, 13, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_ORC_PRIEST, 'o', LIGHTGREEN, "orc priest",
+ M_SPELLCASTER | M_PRIEST | M_WARM_BLOOD,
+ 600, 10, MONS_ORC, MH_NATURAL, -4,
+ { 6, 0, 0, 0 },
+ { 3, 3, 4, 0 },
+ 1, 10, 10, 7, MST_ORC_PRIEST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_ORC_HIGH_PRIEST, 'o', GREEN, "orc high priest",
+ M_RES_HELLFIRE | M_SPELLCASTER | M_SEE_INVIS | M_SPEAKS | M_PRIEST | M_WARM_BLOOD,
+ 600, 10, MONS_ORC, MH_NATURAL, -4,
+ { 7, 0, 0, 0 },
+ { 11, 3, 4, 0 },
+ 1, 12, 10, 7, MST_ORC_HIGH_PRIEST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+// this is a dummy monster, used for corpses
+// mv:but it can be generated by polymorph spells and because IMO it's
+// logical polymorph target so complete monster statistics should exist.
+// Same thing for elf dummy monster.
+
+{
+ MONS_HUMAN, '@', LIGHTGRAY, "human",
+ M_WARM_BLOOD,
+ 550, 10, MONS_HUMAN, MH_NATURAL, -3,
+ { 10, 0, 0, 0 },
+ { 1, 3, 5, 0 },
+ 0, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_GNOLL, 'g', YELLOW, "gnoll",
+ M_WARM_BLOOD,
+ 750, 10, MONS_GNOLL, MH_NATURAL, -3,
+ { 9, 0, 0, 0 },
+ { 2, 4, 5, 0 },
+ 2, 9, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_CLAY_GOLEM, '8', BROWN, "clay golem",
+ M_RES_POISON | M_RES_FIRE | M_RES_COLD | M_RES_ELEC | M_SEE_INVIS,
+ 0, 10, MONS_CLAY_GOLEM, MH_NONLIVING, 5000,
+ { 11, 11, 0, 0 },
+ { 8, 7, 3, 0 },
+ 7, 5, 8, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_WOOD_GOLEM, '8', YELLOW, "wood golem",
+ M_RES_POISON | M_ED_FIRE | M_RES_COLD | M_RES_ELEC,
+ 0, 10, MONS_WOOD_GOLEM, MH_NONLIVING, 5000,
+ { 10, 0, 0, 0 },
+ { 6, 6, 3, 0 },
+ 5, 6, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_STONE_GOLEM, '8', LIGHTGREY, "stone golem",
+ M_RES_POISON | M_RES_FIRE | M_RES_COLD | M_RES_ELEC,
+ 0, 10, MONS_STONE_GOLEM, MH_NONLIVING, 5000,
+ { 28, 0, 0, 0 },
+ { 12, 7, 4, 0 },
+ 12, 4, 7, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_IRON_GOLEM, '8', CYAN, "iron golem",
+ M_RES_POISON | M_RES_FIRE | M_RES_COLD | M_RES_ELEC | M_SEE_INVIS,
+ 0, 10, MONS_IRON_GOLEM, MH_NONLIVING, 5000,
+ { 35, 0, 0, 0 },
+ { 15, 7, 4, 0 },
+ 15, 3, 7, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_CRYSTAL_GOLEM, '8', WHITE, "crystal golem",
+ M_RES_POISON | M_RES_FIRE | M_RES_COLD | M_RES_ELEC | M_SEE_INVIS,
+ 0, 10, MONS_CRYSTAL_GOLEM, MH_NONLIVING, 5000,
+ { 40, 0, 0, 0 },
+ { 13, 7, 4, 0 },
+ 22, 3, 7, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_TOENAIL_GOLEM, '8', LIGHTGREY, "toenail golem",
+ M_RES_POISON | M_RES_FIRE | M_RES_COLD | M_RES_ELEC,
+ 0, 10, MONS_TOENAIL_GOLEM, MH_NONLIVING, 5000,
+ { 13, 0, 0, 0 },
+ { 9, 5, 3, 0 },
+ 8, 5, 8, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_MOTTLED_DRAGON, 'd', LIGHTMAGENTA, "mottled dragon",
+ M_RES_POISON | M_RES_FIRE | M_SPELLCASTER | M_FLIES,
+ 1100, 10, MONS_MOTTLED_DRAGON, MH_NATURAL, -3,
+ { 15, 0, 0, 0 },
+ { 5, 3, 5, 0 },
+ 5, 10, 10, 7, MST_MOTTLED_DRAGON, CE_POISONOUS, Z_BIG, S_SILENT, I_ANIMAL_LIKE,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_EARTH_ELEMENTAL, '#', BROWN, "earth elemental",
+ M_RES_POISON | M_RES_FIRE | M_RES_COLD | M_RES_ELEC,
+ 0, 10, MONS_EARTH_ELEMENTAL, MH_NONLIVING, 5000,
+ { 40, 0, 0, 0 },
+ { 6, 5, 5, 0 },
+ 14, 4, 6, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_FIRE_ELEMENTAL, '#', YELLOW, "fire elemental",
+ M_RES_POISON | M_RES_HELLFIRE | M_ED_COLD | M_RES_ELEC | M_FLIES,
+ 0, 10, MONS_FIRE_ELEMENTAL, MH_NONLIVING, 5000,
+ { 5, 0, 0, 0 },
+ { 6, 3, 5, 0 },
+ 4, 12, 13, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_AIR_ELEMENTAL, 'v', LIGHTGREY, "air elemental",
+ M_RES_ELEC | M_RES_POISON | M_LEVITATE | M_SEE_INVIS | M_FLIES,
+ 0, 5, MONS_AIR_ELEMENTAL, MH_NONLIVING, 5000,
+ { 15, 0, 0, 0 },
+ { 6, 3, 5, 0 },
+ 2, 18, 25, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_OPEN_DOORS
+}
+,
+
+// water elementals are later (with the other water monsters)
+
+{
+ MONS_ICE_FIEND, '1', WHITE, "Ice Fiend",
+ M_RES_POISON | M_ED_FIRE | M_RES_COLD | M_SPELLCASTER | M_FLIES | M_SEE_INVIS | M_FROZEN,
+ 0, 10, MONS_ICE_FIEND, MH_DEMONIC, -12,
+ { 25, 25, 0, 0 },
+ { 18, 3, 5, 0 },
+ 15, 6, 10, 7, MST_ICE_FIEND, CE_CONTAMINATED, Z_NOZOMBIE, S_ROAR, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_SHADOW_FIEND, '1', DARKGREY, "Shadow Fiend",
+ M_RES_POISON | M_RES_COLD | M_RES_ELEC | M_SPELLCASTER | M_LEVITATE | M_SEE_INVIS,
+ 0, 10, MONS_SHADOW_FIEND, MH_DEMONIC, -13,
+ { 25, 15, 15, 0 },
+ { 18, 3, 5, 0 },
+ 15, 6, 10, 7, MST_SHADOW_FIEND, CE_CONTAMINATED, Z_NOZOMBIE, S_ROAR, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_BROWN_SNAKE, 'S', BROWN, "brown snake",
+ M_RES_POISON | M_COLD_BLOOD | M_AMPHIBIOUS,
+ 300, 10, MONS_BROWN_SNAKE, MH_NATURAL, -3,
+ { 10, 0, 0, 0 },
+ { 4, 3, 5, 0 },
+ 2, 15, 14, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_HISS, I_REPTILE,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_GIANT_LIZARD, 'l', GREEN, "giant lizard",
+ M_COLD_BLOOD,
+ 600, 10, MONS_GIANT_LIZARD, MH_NATURAL, -3,
+ { 20, 0, 0, 0 },
+ { 5, 3, 5, 0 },
+ 4, 10, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_REPTILE,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_SPECTRAL_WARRIOR, 'W', LIGHTGREEN, "spectral warrior",
+ M_RES_POISON | M_RES_COLD | M_LEVITATE | M_SEE_INVIS,
+ 0, 13, MONS_SPECTRAL_WARRIOR, MH_UNDEAD, -6,
+ { 18, 0, 0, 0 },
+ { 9, 3, 5, 0 },
+ 12, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_PULSATING_LUMP, 'J', RED, "pulsating lump",
+ M_RES_POISON | M_SEE_INVIS,
+ 0, 3, MONS_PULSATING_LUMP, MH_NATURAL, -3,
+ { 13, 0, 0, 0 },
+ { 10, 3, 5, 0 },
+ 2, 6, 5, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_STORM_DRAGON, 'D', LIGHTBLUE, "storm dragon",
+ M_RES_ELEC | M_RES_COLD | M_SPELLCASTER | M_FLIES,
+ 2800, 12, MONS_STORM_DRAGON, MH_NATURAL, -5,
+ { 25, 15, 15, 0 },
+ { 14, 5, 5, 0 },
+ 13, 10, 12, 7, MST_STORM_DRAGON, CE_CLEAN, Z_BIG, S_ROAR, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_YAKTAUR, 'c', LIGHTRED, "yaktaur",
+ M_WARM_BLOOD,
+ 2000, 10, MONS_YAKTAUR, MH_NATURAL, -3,
+ { 15, 0, 0, 0 },
+ { 8, 3, 5, 0 },
+ 4, 4, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_DEATH_YAK, 'Y', DARKGREY, "death yak",
+ M_WARM_BLOOD,
+ 1500, 10, MONS_DEATH_YAK, MH_NATURAL, -5,
+ { 30, 0, 0, 0 },
+ { 14, 3, 5, 0 },
+ 9, 5, 10, 7, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_BELLOW, I_ANIMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_ROCK_TROLL, 'T', LIGHTGREY, "rock troll",
+ M_WARM_BLOOD,
+ 2200, 11, MONS_ROCK_TROLL, MH_NATURAL, -4,
+ { 30, 20, 20, 0 },
+ { 11, 3, 5, 0 },
+ 13, 6, 8, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_STONE_GIANT, 'C', LIGHTGREY, "stone giant",
+ M_WARM_BLOOD,
+ 3000, 10, MONS_STONE_GIANT, MH_NATURAL, -4,
+ { 45, 0, 0, 0 },
+ { 16, 3, 5, 0 },
+ 12, 2, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_NORMAL,
+ MONUSE_STARTING_EQUIPMENT
+}
+,
+
+{
+ MONS_FLAYED_GHOST, 'p', RED, "flayed ghost",
+ M_RES_POISON | M_FLIES,
+ 0, 10, MONS_FLAYED_GHOST, MH_UNDEAD, -4,
+ { 30, 0, 0, 0 },
+ { 11, 3, 5, 0 },
+ 0, 14, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_BUMBLEBEE, 'k', RED, "bumblebee",
+ M_ED_POISON | M_FLIES,
+ 300, 10, MONS_BUMBLEBEE, MH_NATURAL, -3,
+ { 20, 0, 0, 0 },
+ { 7, 3, 5, 0 },
+ 4, 15, 10, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_BUZZ, I_INSECT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_REDBACK, 's', RED, "redback",
+ M_ED_POISON,
+ 1000, 14, MONS_REDBACK, MH_NATURAL, -3,
+ { 18, 0, 0, 0 },
+ { 6, 3, 5, 0 },
+ 2, 12, 15, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_INSUBSTANTIAL_WISP, 'p', LIGHTGREY, "insubstantial wisp",
+ M_RES_ELEC | M_RES_POISON | M_RES_FIRE | M_RES_COLD | M_LEVITATE,
+ 0, 17, MONS_INSUBSTANTIAL_WISP, MH_NONLIVING, 5000,
+ { 12, 0, 0, 0 },
+ { 6, 1, 2, 0 },
+ 20, 20, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_MOAN, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_VAPOUR, '#', LIGHTGREY, "vapour",
+ M_RES_ELEC | M_RES_POISON | M_SPELLCASTER | M_LEVITATE | M_SEE_INVIS | M_INVIS | M_CONFUSED,
+ 0, 21, MONS_VAPOUR, MH_NONLIVING, 5000,
+ { 0, 0, 0, 0 },
+ { 12, 2, 3, 0 },
+ 0, 12, 10, 7, MST_STORM_DRAGON, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_OGRE_MAGE, 'O', MAGENTA, "ogre-mage",
+ M_RES_ELEC | M_SPELLCASTER | M_ACTUAL_SPELLS | M_SEE_INVIS | M_WARM_BLOOD,
+ 0, 16, MONS_OGRE, MH_NATURAL, -6,
+ { 12, 0, 0, 0 },
+ { 10, 3, 5, 0 },
+ 1, 7, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_SPINY_WORM, 'w', DARKGREY, "spiny worm",
+ M_ED_POISON,
+ 1300, 13, MONS_SPINY_WORM, MH_NATURAL, -3,
+ { 32, 0, 0, 0 },
+ { 12, 3, 5, 0 },
+ 10, 6, 9, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+// these are named more explicitly when they attack, also when you use 'x'
+// to examine them.
+{
+ MONS_DANCING_WEAPON, '(', BLACK, "dancing weapon",
+ M_RES_POISON | M_RES_HELLFIRE | M_RES_COLD | M_RES_ELEC | M_LEVITATE,
+ 0, 10, MONS_DANCING_WEAPON, MH_NONLIVING, 5000,
+ { 30, 0, 0, 0 },
+ { 15, 0, 0, 15 },
+ 10, 20, 15, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_TITAN, 'C', MAGENTA, "titan",
+ M_RES_ELEC | M_SPELLCASTER | M_WARM_BLOOD | M_SEE_INVIS,
+ 3500, 12, MONS_TITAN, MH_NATURAL, -7,
+ { 55, 0, 0, 0 },
+ { 20, 3, 5, 0 },
+ 10, 3, 10, 7, MST_TITAN, CE_CLEAN, Z_BIG, S_SHOUT, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_GOLDEN_DRAGON, 'D', YELLOW, "golden dragon",
+ M_RES_ELEC | M_RES_POISON | M_RES_FIRE | M_RES_COLD | M_SPELLCASTER | M_FLIES | M_SEE_INVIS,
+ 3000, 17, MONS_GOLDEN_DRAGON, MH_NATURAL, -8,
+ { 40, 20, 20, 0 },
+ { 18, 4, 4, 0 },
+ 15, 7, 10, 7, MST_GOLDEN_DRAGON, CE_POISONOUS, Z_BIG, S_ROAR, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+// 147 - dummy monster, used for corpses etc.
+//mv: have to exist because it's (and should be) valid polymorph target.
+{
+ MONS_ELF, 'e', DARKGREY, "elf",
+ M_WARM_BLOOD,
+ 450, 10, MONS_ELF, MH_NATURAL, -3,
+ { 10, 0, 0, 0 },
+ { 3, 3, 3, 0 },
+ 0, 12, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SILENT, I_PLANT,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+
+// Used to be "lindworm" and a GREEN 'l'... I'm hoping that by
+// making it a 'd' and using an alternate spelling people will
+// more intuitively know that this isn't a regular lizard. -- bwr
+{
+ MONS_LINDWURM, 'd', LIGHTGREEN, "lindwurm",
+ M_NO_FLAGS,
+ 1000, 11, MONS_LINDWURM, MH_NATURAL, -3,
+ { 20, 10, 10, 0 },
+ { 9, 3, 5, 0 },
+ 8, 6, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_ROAR, I_REPTILE,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_ELEPHANT_SLUG, 'm', LIGHTGREY, "elephant slug",
+ M_ED_POISON | M_NO_SKELETON,
+ 1500, 10, MONS_ELEPHANT_SLUG, MH_NATURAL, -3,
+ { 40, 0, 0, 0 },
+ { 20, 5, 3, 0 },
+ 2, 1, 4, 10, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_SILENT, I_INSECT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_WAR_DOG, 'h', CYAN, "war dog",
+ M_SEE_INVIS | M_WARM_BLOOD,
+ 350, 10, MONS_WAR_DOG, MH_NATURAL, -3,
+ { 12, 0, 0, 0 },
+ { 4, 3, 5, 0 },
+ 4, 15, 17, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_BARK, I_ANIMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_GREY_RAT, 'r', LIGHTGREY, "grey rat",
+ M_WARM_BLOOD,
+ 250, 10, MONS_GREY_RAT, MH_NATURAL, -3,
+ { 5, 0, 0, 0 },
+ { 1, 3, 6, 0 },
+ 2, 12, 12, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SILENT, I_ANIMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_GREEN_RAT, 'r', LIGHTGREEN, "green rat",
+ M_WARM_BLOOD,
+ 250, 10, MONS_GREEN_RAT, MH_NATURAL, -3,
+ { 10, 0, 0, 0 },
+ { 2, 3, 5, 0 },
+ 5, 11, 10, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_ANIMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_ORANGE_RAT, 'r', LIGHTRED, "orange rat",
+ M_WARM_BLOOD,
+ 250, 10, MONS_ORANGE_RAT, MH_NATURAL, -3,
+ { 20, 0, 0, 0 },
+ { 3, 3, 5, 0 },
+ 7, 10, 12, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_ROAR, I_ANIMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_BLACK_SNAKE, 'S', DARKGREY, "black snake",
+ M_RES_POISON | M_COLD_BLOOD,
+ 500, 12, MONS_BLACK_SNAKE, MH_NATURAL, -3,
+ { 20, 0, 0, 0 },
+ { 7, 3, 5, 0 },
+ 4, 15, 18, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_HISS, I_REPTILE,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_SHEEP, 'Y', LIGHTGREY, "sheep",
+ M_WARM_BLOOD,
+ 1200, 10, MONS_SHEEP, MH_NATURAL, -3,
+ { 13, 0, 0, 0 },
+ { 3, 3, 5, 0 },
+ 2, 7, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_BELLOW, I_ANIMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_GHOUL, 'n', RED, "ghoul",
+ M_RES_POISON | M_RES_COLD,
+ 500, 12, MONS_GHOUL, MH_UNDEAD, -5,
+ { 9, 0, 0, 0 },
+ { 4, 3, 5, 0 },
+ 4, 10, 10, 7, MST_NO_SPELLS, CE_HCL, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_HOG, 'h', LIGHTRED, "hog",
+ M_WARM_BLOOD,
+ 700, 10, MONS_HOG, MH_NATURAL, -3,
+ { 14, 0, 0, 0 },
+ { 6, 3, 5, 0 },
+ 2, 9, 13, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_ANIMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_GIANT_MOSQUITO, 'y', DARKGREY, "giant mosquito",
+ M_ED_POISON | M_FLIES,
+ 100, 10, MONS_GIANT_MOSQUITO, MH_NATURAL, -3,
+ { 10, 0, 0, 0 },
+ { 1, 3, 5, 0 },
+ 0, 13, 12, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_WHINE, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_GIANT_CENTIPEDE, 's', GREEN, "giant centipede",
+ M_ED_POISON,
+ 350, 10, MONS_GIANT_CENTIPEDE, MH_NATURAL, -3,
+ { 2, 0, 0, 0 },
+ { 2, 3, 3, 0 },
+ 2, 14, 13, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
+ MONUSE_NOTHING
+}
+,
+
+
+
+{
+ MONS_IRON_TROLL, 'T', CYAN, "iron troll",
+ M_RES_FIRE | M_RES_COLD | M_WARM_BLOOD,
+ 2400, 10, MONS_IRON_TROLL, MH_NATURAL, -5,
+ { 35, 25, 25, 0 },
+ { 16, 3, 5, 0 },
+ 20, 4, 7, 7, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_ROAR, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_NAGA, 'N', GREEN, "naga",
+ M_RES_POISON | M_SPELLCASTER | M_SEE_INVIS | M_WARM_BLOOD,
+ 750, 10, MONS_NAGA, MH_NATURAL, -6,
+ { 6, 0, 0, 0 },
+ { 5, 3, 5, 0 },
+ 6, 10, 8, 7, MST_NAGA, CE_POISONOUS, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_FIRE_GIANT, 'C', RED, "fire giant",
+ M_RES_FIRE | M_SPELLCASTER | M_WARM_BLOOD | M_SEE_INVIS,
+ 2400, 11, MONS_FIRE_GIANT, MH_NATURAL, -4,
+ { 30, 0, 0, 0 },
+ { 16, 3, 6, 0 },
+ 8, 4, 10, 7, MST_EFREET, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_FROST_GIANT, 'C', LIGHTBLUE, "frost giant",
+ M_RES_COLD | M_SPELLCASTER | M_WARM_BLOOD | M_SEE_INVIS,
+ 2600, 11, MONS_FROST_GIANT, MH_NATURAL, -4,
+ { 35, 0, 0, 0 },
+ { 16, 4, 5, 0 },
+ 9, 3, 10, 7, MST_FROST_GIANT, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_FIREDRAKE, 'd', RED, "firedrake",
+ M_RES_FIRE | M_FLIES,
+ 900, 10, MONS_FIREDRAKE, MH_NATURAL, -3,
+ { 8, 0, 0, 0 },
+ { 6, 3, 5, 0 },
+ 3, 12, 12, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SILENT, I_ANIMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_SHADOW_DRAGON, 'D', DARKGREY, "shadow dragon",
+ M_RES_POISON | M_RES_COLD | M_SPELLCASTER | M_FLIES | M_SEE_INVIS,
+ 2000, 12, MONS_SHADOW_DRAGON, MH_NATURAL, -5,
+ { 20, 15, 15, 0 },
+ { 17, 5, 5, 0 },
+ 15, 10, 10, 7, MST_SHADOW_DRAGON, CE_CLEAN, Z_BIG, S_ROAR, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+{
+ MONS_YELLOW_SNAKE, 'S', YELLOW, "yellow snake",
+ M_RES_POISON | M_COLD_BLOOD,
+ 400, 10, MONS_YELLOW_SNAKE, MH_NATURAL, -3,
+ { 15, 0, 0, 0 },
+ { 6, 3, 5, 0 },
+ 4, 14, 13, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_HISS, I_REPTILE,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_GREY_SNAKE, 'S', LIGHTGREY, "grey snake",
+ M_COLD_BLOOD,
+ 600, 10, MONS_GREY_SNAKE, MH_NATURAL, -3,
+ { 30, 0, 0, 0 },
+ { 11, 3, 5, 0 },
+ 4, 16, 18, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_HISS, I_REPTILE,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_DEEP_TROLL, 'T', DARKGREY, "deep troll",
+ M_WARM_BLOOD | M_SEE_INVIS,
+ 1500, 12, MONS_DEEP_TROLL, MH_NATURAL, -3,
+ { 27, 20, 20, 0 },
+ { 10, 3, 5, 0 },
+ 6, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_GIANT_BLOWFLY, 'y', LIGHTGREY, "giant blowfly",
+ M_ED_POISON | M_FLIES,
+ 200, 10, MONS_GIANT_BLOWFLY, MH_NATURAL, -3,
+ { 13, 0, 0, 0 },
+ { 5, 3, 5, 0 },
+ 2, 15, 19, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_BUZZ, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_RED_WASP, 'y', RED, "red wasp",
+ M_ED_POISON | M_FLIES,
+ 400, 14, MONS_RED_WASP, MH_NATURAL, -3,
+ { 23, 0, 0, 0 },
+ { 8, 3, 5, 0 },
+ 7, 14, 15, 7, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_BUZZ, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_SWAMP_DRAGON, 'D', BROWN, "swamp dragon",
+ M_SPELLCASTER | M_FLIES | M_RES_POISON,
+ 1900, 11, MONS_SWAMP_DRAGON, MH_NATURAL, -3,
+ { 13, 9, 9, 0 },
+ { 9, 5, 5, 0 },
+ 7, 7, 10, 7, MST_SWAMP_DRAGON, CE_CONTAMINATED, Z_BIG, S_ROAR, I_ANIMAL_LIKE,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_SWAMP_DRAKE, 'd', BROWN, "swamp drake",
+ M_SPELLCASTER | M_FLIES | M_RES_POISON,
+ 900, 11, MONS_SWAMP_DRAKE, MH_NATURAL, -3,
+ { 11, 0, 0, 0 },
+ { 4, 5, 5, 0 },
+ 3, 11, 11, 7, MST_SWAMP_DRAKE, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_ANIMAL_LIKE,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_SOLDIER_ANT, 'a', LIGHTGREY, "soldier ant",
+ M_ED_POISON,
+ 900, 10, MONS_SOLDIER_ANT, MH_NATURAL, -3,
+ { 14, 0, 0, 0 },
+ { 6, 3, 5, 0 },
+ 8, 10, 10, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_HILL_GIANT, 'C', LIGHTRED, "hill giant",
+ M_WARM_BLOOD,
+ 1600, 10, MONS_HILL_GIANT, MH_NATURAL, -3,
+ { 30, 0, 0, 0 },
+ { 11, 3, 5, 0 },
+ 3, 4, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_QUEEN_ANT, 'Q', DARKGREY, "queen ant",
+ M_ED_POISON,
+ 1200, 10, MONS_QUEEN_ANT, MH_NATURAL, -3,
+ { 20, 0, 0, 0 },
+ { 13, 3, 5, 0 },
+ 14, 3, 7, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_ANT_LARVA, 'w', LIGHTGREY, "ant larva",
+ M_ED_POISON | M_NO_SKELETON,
+ 350, 5, MONS_ANT_LARVA, MH_NATURAL, -3,
+ { 5, 0, 0, 0 },
+ { 2, 3, 5, 0 },
+ 2, 6, 6, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
+ MONUSE_NOTHING
+}
+,
+
+
+{
+ MONS_GIANT_FROG, 'F', GREEN, "giant frog",
+ M_COLD_BLOOD | M_AMPHIBIOUS,
+ 500, 10, MONS_GIANT_FROG, MH_NATURAL, -3,
+ { 9, 0, 0, 0 },
+ { 4, 3, 5, 0 },
+ 0, 12, 15, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_CROAK, I_ANIMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_GIANT_BROWN_FROG, 'F', BROWN, "giant brown frog",
+ M_COLD_BLOOD | M_AMPHIBIOUS,
+ 890, 10, MONS_GIANT_BROWN_FROG, MH_NATURAL, -3,
+ { 14, 0, 0, 0 },
+ { 8, 3, 5, 0 },
+ 2, 11, 13, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_CROAK, I_ANIMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_SPINY_FROG, 'F', YELLOW, "spiny frog",
+ M_COLD_BLOOD | M_RES_POISON | M_AMPHIBIOUS,
+ 1000, 10, MONS_SPINY_FROG, MH_NATURAL, -3,
+ { 26, 0, 0, 0 },
+ { 7, 3, 5, 0 },
+ 6, 9, 12, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_CROAK, I_ANIMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_BLINK_FROG, 'F', LIGHTGREEN, "blink frog",
+ M_COLD_BLOOD | M_AMPHIBIOUS,
+ 800, 12, MONS_BLINK_FROG, MH_NATURAL, -5,
+ { 20, 0, 0, 0 },
+ { 6, 3, 5, 0 },
+ 3, 12, 14, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_CROAK, I_ANIMAL,
+ MONUSE_NOTHING
+}
+,
+{
+ MONS_GIANT_COCKROACH, 'a', BROWN, "giant cockroach",
+ M_NO_FLAGS,
+ 250, 10, MONS_GIANT_COCKROACH, MH_NATURAL, -1,
+ { 2, 0, 0, 0 },
+ { 1, 3, 4, 0 },
+ 3, 10, 12, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SILENT, I_INSECT,
+ MONUSE_NOTHING
+}
+,
+{
+ MONS_SMALL_SNAKE, 'S', LIGHTGREEN, "small snake",
+ M_COLD_BLOOD,
+ 100, 13, MONS_SMALL_SNAKE, MH_NATURAL, -1,
+ { 2, 0, 0, 0 },
+ { 1, 2, 3, 0 },
+ 0, 11, 12, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_REPTILE,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_WHITE_IMP, '5', WHITE, "white imp",
+ M_RES_COLD | M_SPELLCASTER | M_FLIES | M_SPEAKS,
+ 0, 10, MONS_WHITE_IMP, MH_DEMONIC, -3,
+ { 4, 0, 0, 0 },
+ { 2, 3, 5, 0 },
+ 4, 10, 10, 7, MST_WHITE_IMP, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_LEMURE, '5', YELLOW, "lemure",
+ M_RES_POISON,
+ 0, 10, MONS_LEMURE, MH_DEMONIC, -3,
+ { 12, 0, 0, 0 },
+ { 2, 3, 5, 0 },
+ 1, 12, 12, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_MOAN, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_UFETUBUS, '5', LIGHTCYAN, "ufetubus",
+ M_ED_FIRE | M_RES_COLD,
+ 0, 10, MONS_UFETUBUS, MH_DEMONIC, -3,
+ { 5, 5, 0, 0 },
+ { 1, 4, 6, 0 },
+ 2, 15, 15, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_MANES, '5', LIGHTRED, "manes",
+ M_RES_ELEC | M_RES_FIRE | M_RES_COLD | M_RES_POISON,
+ 0, 10, MONS_MANES, MH_DEMONIC, -3,
+ { 5, 3, 3, 0 },
+ { 3, 3, 5, 0 },
+ 2, 8, 8, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_MIDGE, '5', LIGHTGREEN, "midge",
+ M_RES_POISON | M_FLIES,
+ 0, 10, MONS_MIDGE, MH_DEMONIC, -3,
+ { 8, 0, 0, 0 },
+ { 2, 3, 5, 0 },
+ 4, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_NEQOXEC, '3', MAGENTA, "neqoxec",
+ M_RES_POISON | M_SPELLCASTER | M_LEVITATE,
+ 0, 12, MONS_NEQOXEC, MH_DEMONIC, -6,
+ { 15, 0, 0, 0 },
+ { 6, 3, 5, 0 },
+ 4, 12, 10, 7, MST_NEQOXEC, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_ORANGE_DEMON, '3', LIGHTRED, "orange demon",
+ M_NO_FLAGS,
+ 0, 12, MONS_ORANGE_DEMON, MH_DEMONIC, -6,
+ { 10, 5, 0, 0 },
+ { 8, 4, 5, 0 },
+ 3, 7, 7, 7, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SCREECH, I_NORMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_HELLWING, '3', LIGHTGREY, "hellwing",
+ M_RES_POISON | M_SPELLCASTER | M_FLIES,
+ 0, 12, MONS_HELLWING, MH_DEMONIC, -6,
+ { 17, 10, 0, 0 },
+ { 7, 4, 5, 0 },
+ 8, 10, 10, 7, MST_HELLWING, CE_CONTAMINATED, Z_NOZOMBIE, S_MOAN, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_SMOKE_DEMON, '4', LIGHTGREY, "smoke demon",
+ M_RES_POISON | M_RES_FIRE | M_SPELLCASTER | M_FLIES,
+ 0, 12, MONS_SMOKE_DEMON, MH_DEMONIC, -6,
+ { 8, 5, 5, 0 },
+ { 7, 3, 5, 0 },
+ 5, 9, 9, 7, MST_SMOKE_DEMON, CE_CONTAMINATED, Z_NOZOMBIE, S_ROAR, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_YNOXINUL, '3', CYAN, "ynoxinul",
+ M_RES_ELEC | M_RES_POISON | M_RES_COLD | M_SPELLCASTER | M_FLIES | M_SEE_INVIS,
+ 0, 12, MONS_YNOXINUL, MH_DEMONIC, -6,
+ { 12, 0, 0, 0 },
+ { 6, 3, 5, 0 },
+ 3, 10, 10, 7, MST_YNOXINUL, CE_CONTAMINATED, Z_NOZOMBIE, S_BELLOW, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_EXECUTIONER, '1', LIGHTGREY, "Executioner",
+ M_SPELLCASTER | M_RES_ELEC | M_RES_FIRE | M_RES_COLD | M_RES_POISON | M_SEE_INVIS,
+ 0, 14, MONS_EXECUTIONER, MH_DEMONIC, -9,
+ { 30, 10, 10, 0 },
+ { 12, 3, 5, 0 },
+ 10, 15, 20, 7, MST_HELL_KNIGHT_I, CE_CONTAMINATED, Z_NOZOMBIE, S_SCREAM, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_GREEN_DEATH, '1', GREEN, "Green Death",
+ M_RES_POISON | M_SPELLCASTER | M_SEE_INVIS,
+ 0, 14, MONS_GREEN_DEATH, MH_DEMONIC, -9,
+ { 32, 0, 0, 0 },
+ { 13, 3, 5, 0 },
+ 5, 7, 12, 7, MST_GREEN_DEATH, CE_POISONOUS, Z_NOZOMBIE, S_ROAR, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_BLUE_DEATH, '1', BLUE, "Blue Death",
+ M_RES_POISON | M_SPELLCASTER | M_ED_FIRE | M_RES_COLD | M_RES_ELEC | M_FLIES | M_SEE_INVIS,
+ 0, 14, MONS_BLUE_DEATH, MH_DEMONIC, -9,
+ { 20, 20, 0, 0 },
+ { 12, 3, 5, 0 },
+ 10, 10, 12, 7, MST_BLUE_DEATH, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_BALRUG, '1', RED, "Balrug",
+ M_RES_POISON | M_RES_HELLFIRE | M_ED_COLD | M_SPELLCASTER | M_FLIES | M_SEE_INVIS,
+ 0, 14, MONS_BALRUG, MH_DEMONIC, -9,
+ { 25, 0, 0, 0 },
+ { 14, 3, 5, 0 },
+ 5, 12, 12, 7, MST_BALRUG, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_CACODEMON, '1', YELLOW, "Cacodemon",
+ M_RES_POISON | M_RES_ELEC | M_SPELLCASTER | M_LEVITATE | M_SEE_INVIS,
+ 0, 14, MONS_CACODEMON, MH_DEMONIC, -9,
+ { 22, 0, 0, 0 },
+ { 13, 3, 5, 0 },
+ 11, 10, 10, 7, MST_CACODEMON, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+
+{
+ MONS_DEMONIC_CRAWLER, '3', DARKGREY, "demonic crawler",
+ M_RES_ELEC | M_RES_POISON | M_RES_COLD | M_RES_FIRE | M_SEE_INVIS,
+ 0, 12, MONS_DEMONIC_CRAWLER, MH_DEMONIC, -6,
+ { 13, 13, 13, 13 },
+ { 9, 3, 5, 0 },
+ 10, 6, 9, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SCREAM, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_SUN_DEMON, '2', YELLOW, "sun demon",
+ M_RES_ELEC | M_RES_POISON | M_ED_COLD | M_RES_HELLFIRE | M_SEE_INVIS | M_LEVITATE,
+ 0, 14, MONS_SUN_DEMON, MH_DEMONIC, -6,
+ { 30, 0, 0, 0 },
+ { 10, 3, 5, 0 },
+ 10, 12, 12, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_SHADOW_IMP, '5', DARKGREY, "shadow imp",
+ M_RES_COLD | M_SPELLCASTER | M_FLIES | M_RES_POISON | M_SPEAKS,
+ 0, 11, MONS_SHADOW_IMP, MH_DEMONIC, -3,
+ { 6, 0, 0, 0 },
+ { 2, 3, 5, 0 },
+ 3, 11, 10, 7, MST_SHADOW_IMP, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_SHADOW_DEMON, '3', DARKGREY, "shadow demon",
+ M_RES_POISON | M_RES_COLD | M_SEE_INVIS | M_INVIS,
+ 0, 12, MONS_SHADOW_DEMON, MH_DEMONIC, -7,
+ { 21, 0, 0, 0 },
+ { 6, 3, 5, 0 },
+ 7, 12, 11, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_CROAK, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_LOROCYPROCA, '2', BLUE, "Lorocyproca",
+ M_RES_POISON | M_RES_COLD | M_RES_FIRE | M_RES_ELEC | M_SEE_INVIS | M_INVIS,
+ 0, 12, MONS_LOROCYPROCA, MH_DEMONIC, -7,
+ { 25, 25, 0, 0 },
+ { 12, 3, 5, 0 },
+ 10, 12, 9, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_MOAN, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_SHADOW_WRAITH, 'W', BLUE, "shadow wraith",
+ M_RES_POISON | M_LEVITATE | M_SEE_INVIS | M_INVIS,
+ 0, 15, MONS_SHADOW_WRAITH, MH_UNDEAD, -8,
+ { 20, 0, 0, 0 },
+ { 10, 3, 5, 0 },
+ 7, 7, 10, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_MOAN, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_GIANT_AMOEBA, 'J', BLUE, "giant amoeba",
+ M_RES_POISON | M_NO_SKELETON | M_SEE_INVIS | M_AMPHIBIOUS,
+ 1000, 10, MONS_GIANT_AMOEBA, MH_NATURAL, -3,
+ { 25, 0, 0, 0 },
+ { 12, 3, 5, 0 },
+ 0, 4, 10, 10, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_GIANT_SLUG, 'm', GREEN, "giant slug",
+ M_NO_SKELETON | M_AMPHIBIOUS,
+ 700, 10, MONS_GIANT_SLUG, MH_NATURAL, -3,
+ { 23, 0, 0, 0 },
+ { 10, 5, 3, 0 },
+ 0, 2, 6, 10, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_SILENT, I_INSECT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_GIANT_SNAIL, 'm', LIGHTGREEN, "giant snail",
+ M_NO_SKELETON | M_AMPHIBIOUS,
+ 900, 10, MONS_GIANT_SNAIL, MH_NATURAL, -3,
+ { 18, 0, 0, 0 },
+ { 14, 5, 3, 0 },
+ 7, 2, 4, 10, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_SILENT, I_INSECT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_SPATIAL_VORTEX, 'v', BLACK, "spatial vortex",
+ M_RES_POISON | M_RES_FIRE | M_RES_COLD | M_RES_ELEC | M_LEVITATE | M_CONFUSED,
+ 0, 5, MONS_SPATIAL_VORTEX, MH_NONLIVING, 5000,
+ { 50, 0, 0, 0 },
+ { 6, 6, 6, 0 },
+ 0, 5, 15, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_PIT_FIEND, '1', BROWN, "Pit Fiend",
+ M_RES_POISON | M_RES_HELLFIRE | M_RES_COLD | M_FLIES | M_SEE_INVIS | M_RES_ELEC,
+ 0, 18, MONS_PIT_FIEND, MH_DEMONIC, -12,
+ { 28, 21, 21, 0 },
+ { 19, 4, 5, 0 },
+ 17, 5, 8, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_ROAR, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_BORING_BEETLE, 'B', BROWN, "boring beetle",
+ M_ED_POISON,
+ 1300, 10, MONS_BORING_BEETLE, MH_NATURAL, -3,
+ { 26, 0, 0, 0 },
+ { 8, 3, 5, 0 },
+ 13, 4, 6, 7, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_SILENT, I_INSECT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_GARGOYLE, 'g', DARKGREY, "gargoyle",
+ M_RES_POISON | M_RES_ELEC | M_FLIES,
+ 0, 12, MONS_GARGOYLE, MH_NONLIVING, -6,
+ { 10, 6, 6, 0 },
+ { 4, 3, 5, 0 },
+ 18, 6, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+// only appear in Dis castle
+{
+ MONS_METAL_GARGOYLE, 'g', CYAN, "metal gargoyle",
+ M_RES_POISON | M_RES_ELEC | M_FLIES,
+ 0, 12, MONS_METAL_GARGOYLE, MH_NONLIVING, -6,
+ { 19, 10, 10, 0 },
+ { 8, 3, 5, 0 },
+ 20, 4, 7, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+// only appear in Gehenna castle & one minivault
+{
+ MONS_MOLTEN_GARGOYLE, 'g', RED, "molten gargoyle",
+ M_RES_POISON | M_RES_ELEC | M_FLIES | M_RES_FIRE,
+ 0, 12, MONS_MOLTEN_GARGOYLE, MH_NONLIVING, -6,
+ { 12, 8, 8, 0 },
+ { 5, 3, 5, 0 },
+ 14, 7, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+
+// 250 can't exist
+
+
+{
+ MONS_MNOLEG, '&', LIGHTGREEN, "Mnoleg",
+ M_RES_ELEC | M_RES_POISON | M_RES_FIRE | M_SEE_INVIS | M_SPELLCASTER | M_SPEAKS,
+ 0, 25, MONS_MNOLEG, MH_DEMONIC, 5000,
+ { 23, 23, 0, 0 },
+ { 17, 0, 0, 199 },
+ 10, 13, 13, 7, MST_MNOLEG, CE_CONTAMINATED, Z_NOZOMBIE, S_BUZZ, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_LOM_LOBON, '&', LIGHTBLUE, "Lom Lobon",
+ M_RES_POISON | M_RES_FIRE | M_RES_COLD | M_RES_ELEC | M_LEVITATE | M_SEE_INVIS | M_SPELLCASTER | M_SPEAKS,
+ 0, 25, MONS_LOM_LOBON, MH_DEMONIC, 5000,
+ { 40, 0, 0, 0 },
+ { 19, 0, 0, 223 },
+ 10, 7, 8, 7, MST_LOM_LOBON, CE_CONTAMINATED, Z_NOZOMBIE, S_SCREAM, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_CEREBOV, '&', RED, "Cerebov",
+ M_RES_ELEC | M_RES_POISON | M_RES_HELLFIRE | M_SPELLCASTER | M_SEE_INVIS | M_SPEAKS,
+ 0, 25, MONS_CEREBOV, MH_DEMONIC, -6,
+ { 50, 0, 0, 0 },
+ { 21, 0, 0, 253 },
+ 15, 8, 10, 7, MST_CEREBOV, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_GLOORX_VLOQ, '&', DARKGREY, "Gloorx Vloq",
+ M_RES_POISON | M_RES_COLD | M_RES_ELEC | M_LEVITATE | M_SEE_INVIS | M_SPELLCASTER | M_SPEAKS,
+ 0, 25, MONS_GLOORX_VLOQ, MH_DEMONIC, -14,
+ { 20, 0, 0, 0 },
+ { 16, 0, 0, 234 },
+ 10, 10, 10, 7, MST_GLOORX_VLOQ, CE_CONTAMINATED, Z_NOZOMBIE, S_MOAN, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+/* ******************************************************************
+{MONS_MOLLUSC_LORD, 'U', GREEN, "The Mollusc Lord", M_RES_POISON,
+ 0, 25, 255, MH_DEMONIC, -3, {30,0,0,0},
+ {16,0,0,100}, 10, 10, 10, 7, 93, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_HIGH, 1},
+****************************************************************** */
+
+{
+ MONS_NAGA_MAGE, 'N', LIGHTRED, "naga mage",
+ M_RES_POISON | M_SPELLCASTER | M_ACTUAL_SPELLS | M_SEE_INVIS | M_WARM_BLOOD,
+ 750, 13, MONS_NAGA, MH_NATURAL, -6,
+ { 5, 0, 0, 0 },
+ { 7, 3, 5, 0 },
+ 6, 10, 8, 7, MST_NAGA_MAGE, CE_POISONOUS, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_NAGA_WARRIOR, 'N', BLUE, "naga warrior",
+ M_RES_POISON | M_SPELLCASTER | M_ACTUAL_SPELLS | M_SEE_INVIS | M_WARM_BLOOD,
+ 750, 12, MONS_NAGA, MH_NATURAL, -6,
+ { 11, 0, 0, 0 },
+ { 10, 5, 5, 0 },
+ 6, 10, 8, 7, MST_NAGA, CE_POISONOUS, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_ORC_WARLORD, 'o', RED, "orc warlord",
+ M_WARM_BLOOD,
+ 600, 15, MONS_ORC, MH_NATURAL, -3,
+ { 32, 0, 0, 0 },
+ { 15, 4, 7, 0 },
+ 3, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_DEEP_ELF_SOLDIER, 'e', CYAN, "deep elf soldier",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD,
+ 450, 10, MONS_ELF, MH_NATURAL, -6,
+ { 6, 0, 0, 0 },
+ { 3, 3, 3, 0 },
+ 0, 12, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_DEEP_ELF_FIGHTER, 'e', LIGHTBLUE, "deep elf fighter",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD,
+ 450, 10, MONS_ELF, MH_NATURAL, -6,
+ { 9, 0, 0, 0 },
+ { 6, 3, 3, 0 },
+ 0, 13, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_DEEP_ELF_KNIGHT, 'e', BLUE, "deep elf knight",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD,
+ 450, 10, MONS_ELF, MH_NATURAL, -6,
+ { 14, 0, 0, 0 },
+ { 11, 3, 3, 0 },
+ 0, 15, 11, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_DEEP_ELF_MAGE, 'e', LIGHTRED, "deep elf mage",
+ M_RES_ELEC | M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD,
+ 450, 10, MONS_ELF, MH_NATURAL, -6,
+ { 5, 0, 0, 0 },
+ { 4, 3, 3, 0 },
+ 0, 13, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_DEEP_ELF_SUMMONER, 'e', YELLOW, "deep elf summoner",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD,
+ 450, 10, MONS_ELF, MH_NATURAL, -6,
+ { 5, 0, 0, 0 },
+ { 6, 3, 3, 0 },
+ 0, 13, 10, 7, MST_DEEP_ELF_SUMMONER, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_DEEP_ELF_CONJURER, 'e', LIGHTGREEN, "deep elf conjurer",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_RES_ELEC | M_WARM_BLOOD,
+ 450, 10, MONS_ELF, MH_NATURAL, -6,
+ { 5, 0, 0, 0 },
+ { 6, 3, 3, 0 },
+ 0, 13, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_DEEP_ELF_PRIEST, 'e', LIGHTGREY, "deep elf priest",
+ M_SPELLCASTER | M_PRIEST | M_WARM_BLOOD,
+ 450, 10, MONS_ELF, MH_NATURAL, -6,
+ { 9, 0, 0, 0 },
+ { 5, 3, 3, 0 },
+ 0, 13, 10, 7, MST_DEEP_ELF_PRIEST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_DEEP_ELF_HIGH_PRIEST, 'e', DARKGREY, "deep elf high priest",
+ M_SPELLCASTER | M_SPEAKS | M_PRIEST | M_WARM_BLOOD | M_SEE_INVIS,
+ 450, 10, MONS_ELF, MH_NATURAL, -6,
+ { 14, 0, 0, 0 },
+ { 11, 3, 3, 0 },
+ 3, 13, 10, 7, MST_DEEP_ELF_HIGH_PRIEST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_DEEP_ELF_DEMONOLOGIST, 'e', MAGENTA, "deep elf demonologist",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD | M_SEE_INVIS,
+ 450, 10, MONS_ELF, MH_NATURAL, -6,
+ { 12, 0, 0, 0 },
+ { 12, 3, 3, 0 },
+ 0, 13, 10, 7, MST_DEEP_ELF_DEMONOLOGIST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_DEEP_ELF_ANNIHILATOR, 'e', GREEN, "deep elf annihilator",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD | M_RES_ELEC | M_SEE_INVIS,
+ 450, 10, MONS_ELF, MH_NATURAL, -6,
+ { 12, 0, 0, 0 },
+ { 15, 3, 3, 0 },
+ 0, 13, 10, 7, MST_DEEP_ELF_ANNIHILATOR, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_DEEP_ELF_SORCERER, 'e', RED, "deep elf sorcerer",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD | M_SEE_INVIS | M_SPEAKS,
+ 450, 10, MONS_ELF, MH_NATURAL, -6,
+ { 12, 0, 0, 0 },
+ { 14, 3, 3, 0 },
+ 0, 13, 10, 7, MST_DEEP_ELF_SORCERER, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_DEEP_ELF_DEATH_MAGE, 'e', WHITE, "deep elf death mage",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD | M_SEE_INVIS,
+ 450, 10, MONS_ELF, MH_NATURAL, -6,
+ { 12, 0, 0, 0 },
+ { 15, 3, 3, 0 },
+ 0, 13, 10, 7, MST_DEEP_ELF_DEATH_MAGE, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_BROWN_OOZE, 'J', BROWN, "brown ooze",
+ M_RES_POISON | M_NO_SKELETON | M_SEE_INVIS,
+ 0, 11, MONS_BROWN_OOZE, MH_NATURAL, -7,
+ { 25, 0, 0, 0 },
+ { 7, 3, 5, 0 },
+ 10, 1, 10, 7, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_EATS_ITEMS
+}
+,
+
+{
+ MONS_AZURE_JELLY, 'J', LIGHTBLUE, "azure jelly",
+ M_RES_POISON | M_RES_COLD | M_ED_FIRE | M_RES_ELEC | M_NO_SKELETON | M_SEE_INVIS,
+ 0, 11, MONS_AZURE_JELLY, MH_NATURAL, -4,
+ { 12, 12, 12, 12 },
+ { 15, 3, 5, 0 },
+ 5, 10, 12, 7, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_EATS_ITEMS
+}
+,
+
+{
+ MONS_DEATH_OOZE, 'J', DARKGREY, "death ooze",
+ M_RES_POISON | M_RES_COLD | M_NO_SKELETON | M_SEE_INVIS,
+ 0, 13, MONS_DEATH_OOZE, MH_UNDEAD, -8,
+ { 32, 32, 0, 0 },
+ { 11, 3, 3, 0 },
+ 2, 4, 12, 7, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_EATS_ITEMS
+}
+,
+
+{
+ MONS_ACID_BLOB, 'J', LIGHTGREEN, "acid blob",
+ M_RES_POISON | M_NO_SKELETON | M_SEE_INVIS,
+ 0, 12, MONS_ACID_BLOB, MH_NATURAL, -7,
+ { 42, 0, 0, 0 },
+ { 18, 3, 5, 0 },
+ 1, 3, 14, 7, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_EATS_ITEMS
+}
+,
+
+{
+ MONS_ROYAL_JELLY, 'J', YELLOW, "royal jelly",
+ M_RES_POISON | M_NO_SKELETON | M_SEE_INVIS,
+ 0, 20, MONS_ROYAL_JELLY, MH_NATURAL, -7,
+ { 50, 0, 0, 0 },
+ { 21, 0, 0, 111 },
+ 8, 4, 12, 7, MST_NO_SPELLS, CE_CLEAN, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_EATS_ITEMS
+}
+,
+
+{
+ MONS_TERENCE, '@', LIGHTCYAN, "Terence",
+ M_WARM_BLOOD| M_SPEAKS,
+ 0, 20, MONS_HUMAN, MH_NATURAL, -3,
+ { 3, 0, 0, 0 },
+ { 1, 0, 0, 14 },
+ 0, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_JESSICA, '@', LIGHTGREY, "Jessica",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD,
+ 0, 20, MONS_HUMAN, MH_NATURAL, -3,
+ { 4, 0, 0, 0 },
+ { 1, 0, 0, 10 },
+ 0, 10, 10, 7, MST_ORC_WIZARD_I, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_IJYB, 'g', BLUE, "Ijyb",
+ M_WARM_BLOOD | M_SPEAKS,
+ 0, 5, MONS_GOBLIN, MH_NATURAL, -3,
+ { 4, 0, 0, 0 },
+ { 3, 0, 0, 28 },
+ 2, 12, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_SIGMUND, '@', YELLOW, "Sigmund",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD,
+ 0, 20, MONS_HUMAN, MH_NATURAL, -3,
+ { 5, 0, 0, 0 },
+ { 3, 0, 0, 25 },
+ 0, 11, 10, 7, MST_ORC_WIZARD_II, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_BLORK_THE_ORC, 'o', BROWN, "Blork the orc",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD,
+ 0, 20, MONS_ORC, MH_NATURAL, -4,
+ { 7, 0, 0, 0 },
+ { 3, 0, 0, 32 },
+ 0, 9, 8, 7, MST_ORC_WIZARD_III, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_EDMUND, '@', RED, "Edmund",
+ M_WARM_BLOOD | M_SPEAKS,
+ 0, 20, MONS_HUMAN, MH_NATURAL, -4,
+ { 6, 0, 0, 0 },
+ { 4, 0, 0, 27 },
+ 0, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_PSYCHE, '@', LIGHTMAGENTA, "Psyche",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD,
+ 0, 20, MONS_HUMAN, MH_NATURAL, -4,
+ { 7, 0, 0, 0 },
+ { 5, 0, 0, 24 },
+ 0, 12, 13, 7, MST_ORC_WIZARD_III, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_EROLCHA, 'O', LIGHTBLUE, "Erolcha",
+ M_RES_ELEC | M_SPELLCASTER | M_ACTUAL_SPELLS | M_SEE_INVIS | M_WARM_BLOOD | M_SPEAKS,
+ 0, 20, MONS_OGRE, MH_NATURAL, -7,
+ { 20, 0, 0, 0 },
+ { 6, 0, 0, 45 },
+ 3, 7, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_DONALD, '@', BLUE, "Donald",
+ M_WARM_BLOOD | M_SPEAKS,
+ 0, 20, MONS_HUMAN, MH_NATURAL, -5,
+ { 8, 0, 0, 0 },
+ { 5, 0, 0, 33 },
+ 0, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_URUG, 'o', RED, "Urug",
+ M_WARM_BLOOD | M_SPEAKS,
+ 0, 20, MONS_ORC, MH_NATURAL, -5,
+ { 12, 0, 0, 0 },
+ { 6, 0, 0, 38 },
+ 0, 11, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_MICHAEL, '@', LIGHTGREY, "Michael",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD,
+ 0, 20, MONS_HUMAN, MH_NATURAL, -5,
+ { 9, 0, 0, 0 },
+ { 6, 0, 0, 36 },
+ 0, 10, 10, 7, MST_ORC_WIZARD_III, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_JOSEPH, '@', CYAN, "Joseph",
+ M_WARM_BLOOD | M_SPEAKS,
+ 0, 20, MONS_HUMAN, MH_NATURAL, -5,
+ { 9, 0, 0, 0 },
+ { 7, 0, 0, 42 },
+ 0, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_SNORG, 'T', GREEN, "Snorg",
+ M_WARM_BLOOD | M_SPEAKS,
+ 0, 20, MONS_TROLL, MH_NATURAL, -6,
+ { 20, 15, 15, 0 },
+ { 8, 0, 0, 45 },
+ 0, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_ERICA, '@', MAGENTA, "Erica",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD,
+ 0, 20, MONS_HUMAN, MH_NATURAL, -5,
+ { 10, 0, 0, 0 },
+ { 9, 0, 0, 43 },
+ 0, 11, 11, 7, MST_WIZARD_II, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_JOSEPHINE, '@', WHITE, "Josephine",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD,
+ 0, 20, MONS_HUMAN, MH_NATURAL, -5,
+ { 11, 0, 0, 0 },
+ { 9, 0, 0, 47 },
+ 0, 10, 10, 7, MST_NECROMANCER_I, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_HAROLD, '@', LIGHTGREEN, "Harold",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD,
+ 0, 20, MONS_HUMAN, MH_NATURAL, -5,
+ { 12, 0, 0, 0 },
+ { 9, 0, 0, 51 },
+ 0, 8, 10, 7, MST_HELL_KNIGHT_II, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_NORBERT, '@', BROWN, "Norbert",
+ M_WARM_BLOOD | M_SPEAKS,
+ 0, 20, MONS_HUMAN, MH_NATURAL, -5,
+ { 14, 0, 0, 0 },
+ { 10, 0, 0, 53 },
+ 0, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_JOZEF, '@', LIGHTMAGENTA, "Jozef",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD,
+ 0, 20, MONS_HUMAN, MH_NATURAL, -5,
+ { 14, 0, 0, 0 },
+ { 11, 0, 0, 60 },
+ 0, 9, 10, 7, MST_GUARDIAN_NAGA, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_AGNES, '@', LIGHTBLUE, "Agnes",
+ M_WARM_BLOOD | M_SPEAKS,
+ 0, 20, MONS_HUMAN, MH_NATURAL, -5,
+ { 11, 0, 0, 0 },
+ { 11, 0, 0, 64 },
+ 0, 10, 15, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_MAUD, '@', RED, "Maud",
+ M_WARM_BLOOD | M_SPEAKS,
+ 0, 20, MONS_HUMAN, MH_NATURAL, -5,
+ { 14, 0, 0, 0 },
+ { 13, 0, 0, 55 },
+ 0, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_LOUISE, '@', BLUE, "Louise",
+ M_SPELLCASTER | M_RES_ELEC | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD,
+ 0, 20, MONS_HUMAN, MH_NATURAL, -5,
+ { 12, 0, 0, 0 },
+ { 13, 0, 0, 52 },
+ 0, 10, 10, 7, MST_WIZARD_IV, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_FRANCIS, '@', YELLOW, "Francis",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD | M_SEE_INVIS,
+ 0, 20, MONS_HUMAN, MH_NATURAL, -5,
+ { 12, 0, 0, 0 },
+ { 14, 0, 0, 67 },
+ 0, 10, 10, 7, MST_ORC_HIGH_PRIEST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_FRANCES, '@', YELLOW, "Frances",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD | M_SEE_INVIS,
+ 0, 20, MONS_HUMAN, MH_NATURAL, -5,
+ { 11, 0, 0, 0 },
+ { 14, 0, 0, 70 },
+ 0, 10, 10, 7, MST_ORC_HIGH_PRIEST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_RUPERT, '@', RED, "Rupert",
+ M_SPELLCASTER | M_RES_ELEC | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD | M_SEE_INVIS,
+ 0, 20, MONS_HUMAN, MH_NATURAL, -5,
+ { 13, 0, 0, 0 },
+ { 16, 0, 0, 80 },
+ 0, 10, 10, 7, MST_WIZARD_IV, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_WAYNE, '@', YELLOW, "Wayne",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD | M_SEE_INVIS,
+ 0, 20, MONS_HUMAN, MH_NATURAL, -5,
+ { 14, 0, 0, 0 },
+ { 17, 0, 0, 78 },
+ 1, 10, 7, 7, MST_ORC_PRIEST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_DUANE, '@', YELLOW, "Duane",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD | M_SEE_INVIS,
+ 0, 20, MONS_HUMAN, MH_NATURAL, -5,
+ { 14, 0, 0, 0 },
+ { 18, 0, 0, 83 },
+ 0, 10, 10, 7, MST_ORC_WIZARD_I, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_XTAHUA, 'D', RED, "Xtahua",
+ M_SPEAKS | M_SEE_INVIS | M_RES_POISON | M_RES_FIRE | M_ED_COLD | M_FLIES,
+ 0, 20, MONS_DRAGON, MH_NATURAL, -7,
+ { 29, 17, 17, 0 },
+ { 19, 0, 0, 133 },
+ 15, 7, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_NORRIS, '@', LIGHTRED, "Norris",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD | M_SEE_INVIS,
+ 0, 20, MONS_HUMAN, MH_NATURAL, -5,
+ { 16, 0, 0, 0 },
+ { 20, 0, 0, 95 },
+ 1, 9, 9, 7, MST_HELL_KNIGHT_II, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_ADOLF, '@', DARKGREY, "Adolf",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD | M_SEE_INVIS,
+ 0, 20, MONS_HUMAN, MH_NATURAL, -5,
+ { 17, 0, 0, 0 },
+ { 21, 0, 0, 105 },
+ 0, 10, 10, 7, MST_LICH_IV, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_MARGERY, '@', RED, "Margery",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD | M_SEE_INVIS,
+ 0, 20, MONS_HUMAN, MH_NATURAL, -5,
+ { 18, 0, 0, 0 },
+ { 22, 0, 0, 119 },
+ 0, 10, 10, 7, MST_EFREET, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_BORIS, 'L', RED, "Boris",
+ M_RES_POISON | M_RES_COLD | M_RES_ELEC | M_SPELLCASTER | M_ACTUAL_SPELLS | M_SEE_INVIS | M_SPEAKS,
+ 0, 23, MONS_LICH, MH_UNDEAD, -11,
+ { 15, 0, 0, 0 },
+ { 22, 0, 0, 99 },
+ 12, 10, 10, 7, MST_LICH_IV, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ MONUSE_STARTING_EQUIPMENT
+}
+,
+
+
+{
+ MONS_GERYON, '&', GREEN, "Geryon",
+ M_SPELLCASTER | M_SEE_INVIS | M_SPEAKS,
+ 0, 25, MONS_GERYON, MH_DEMONIC, -6,
+ { 30, 0, 0, 0 },
+ { 15, 0, 0, 240 },
+ 15, 6, 10, 7, MST_GERYON, CE_CONTAMINATED, Z_NOZOMBIE, S_ROAR, I_NORMAL,
+ MONUSE_STARTING_EQUIPMENT
+}
+,
+
+{
+ MONS_DISPATER, '&', MAGENTA, "Dispater",
+ M_RES_ELEC | M_RES_POISON | M_RES_HELLFIRE | M_RES_COLD | M_SPELLCASTER | M_SEE_INVIS | M_SPEAKS,
+ 0, 25, MONS_DISPATER, MH_DEMONIC, -10,
+ { 15, 0, 0, 0 },
+ { 16, 0, 0, 222 },
+ 15, 3, 6, 7, MST_DISPATER, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_ASMODEUS, '&', LIGHTMAGENTA, "Asmodeus",
+ M_RES_ELEC | M_RES_POISON | M_RES_HELLFIRE | M_SPELLCASTER | M_FLIES | M_SEE_INVIS | M_SPEAKS,
+ 0, 25, MONS_ASMODEUS, MH_DEMONIC, -12,
+ { 20, 0, 0, 0 },
+ { 17, 0, 0, 245 },
+ 12, 7, 9, 7, MST_ASMODEUS, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+// Antaeus is now demonic so that he'll resist torment. -- bwr
+{
+ MONS_ANTAEUS, 'C', LIGHTCYAN, "Antaeus",
+ M_RES_ELEC | M_ED_FIRE | M_RES_COLD | M_SPELLCASTER | M_SPEAKS,
+ 0, 25, MONS_ANTAEUS, MH_DEMONIC, -9,
+ { 30, 0, 0, 0 },
+ { 22, 0, 0, 250 },
+ 10, 4, 7, 7, MST_ANTAEUS, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_ERESHKIGAL, '&', WHITE, "Ereshkigal",
+ M_RES_ELEC | M_RES_POISON | M_RES_COLD | M_SPELLCASTER | M_SEE_INVIS | M_SPEAKS,
+ 0, 25, MONS_ERESHKIGAL, MH_DEMONIC, -10,
+ { 20, 0, 0, 0 },
+ { 18, 0, 0, 238 },
+ 15, 6, 9, 7, MST_ERESHKIGAL, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_ANCIENT_LICH, 'L', DARKGREY, "ancient lich",
+ M_RES_POISON | M_RES_COLD | M_SPELLCASTER | M_ACTUAL_SPELLS | M_SEE_INVIS | M_RES_FIRE | M_RES_ELEC,
+ 0, 20, MONS_LICH, MH_UNDEAD, -14,
+ { 20, 0, 0, 0 },
+ { 27, 2, 4, 0 },
+ 20, 10, 12, 7, MST_LICH_I, CE_NOCORPSE, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+/* number is set in define_monster */
+
+{
+ MONS_OOZE, 'J', LIGHTGREY, "ooze",
+ M_RES_POISON | M_NO_SKELETON | M_SEE_INVIS,
+ 0, 5, MONS_OOZE, MH_NATURAL, -6,
+ { 5, 0, 0, 0 },
+ { 3, 3, 5, 0 },
+ 1, 3, 8, 7, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_VAULT_GUARD, '@', CYAN, "vault guard",
+ M_WARM_BLOOD | M_SEE_INVIS,
+ 0, 12, MONS_HUMAN, MH_NATURAL, -3,
+ { 20, 0, 0, 0 },
+ { 13, 3, 5, 0 },
+ 1, 13, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+/* These nasties are never randomly generated, only sometimes specially
+ placed in the Crypt. */
+{
+ MONS_CURSE_SKULL, 'z', DARKGREY, "curse skull",
+ M_RES_ELEC | M_RES_POISON | M_RES_HELLFIRE | M_RES_COLD | M_LEVITATE | M_SPELLCASTER | M_SEE_INVIS,
+ 0, 50, MONS_CURSE_SKULL, MH_UNDEAD, 5000,
+ { 0, 0, 0, 0 },
+ { 13, 0, 0, 66 },
+ 40, 3, 10, 7, MST_CURSE_SKULL, CE_NOCORPSE, Z_NOZOMBIE, S_MOAN, I_HIGH,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_VAMPIRE_KNIGHT, 'V', CYAN, "vampire knight",
+ M_RES_POISON | M_RES_COLD | M_SPELLCASTER | M_SEE_INVIS,
+ 0, 13, MONS_VAMPIRE, MH_UNDEAD, -6,
+ { 33, 0, 0, 0 },
+ { 11, 3, 7, 0 },
+ 10, 10, 10, 7, MST_VAMPIRE_KNIGHT, CE_NOCORPSE, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_VAMPIRE_MAGE, 'V', MAGENTA, "vampire mage",
+ M_RES_POISON | M_RES_COLD | M_SPELLCASTER | M_SEE_INVIS | M_FLIES,
+ 0, 15, MONS_VAMPIRE, MH_UNDEAD, -6,
+ { 22, 0, 0, 0 },
+ { 8, 3, 4, 0 },
+ 10, 10, 10, 7, MST_VAMPIRE_MAGE, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_SHINING_EYE, 'G', LIGHTMAGENTA, "shining eye",
+ M_NO_SKELETON | M_LEVITATE | M_SPELLCASTER | M_SEE_INVIS,
+ 0, 14, MONS_SHINING_EYE, MH_NATURAL, 5000,
+ { 0, 0, 0, 0 },
+ { 10, 3, 5, 0 },
+ 3, 1, 7, 7, MST_SHINING_EYE, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_ORB_GUARDIAN, 'X', MAGENTA, "Orb Guardian",
+ M_NO_SKELETON | M_SEE_INVIS,
+ 0, 20, MONS_ORB_GUARDIAN, MH_NATURAL, -6,
+ { 40, 0, 0, 0 },
+ { 15, 3, 5, 0 },
+ 13, 13, 14, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_DAEVA, 'A', YELLOW, "Daeva",
+ M_RES_POISON | M_LEVITATE | M_SPELLCASTER,
+ 0, 12, MONS_DAEVA, MH_HOLY, -8,
+ { 25, 0, 0, 0 },
+ { 12, 3, 5, 0 },
+ 10, 13, 13, 7, MST_DAEVA, CE_NOCORPSE, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+/* spectral thing - similar to zombies/skeletons */
+{
+ MONS_SPECTRAL_THING, 'W', GREEN, "",
+ M_RES_POISON | M_RES_COLD | M_LEVITATE | M_SEE_INVIS,
+ 0, 11, MONS_SPECTRAL_THING, MH_UNDEAD, 5000,
+ { 20, 0, 0, 0 },
+ { 8, 3, 5, 0 },
+ 8, 5, 7, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_GREATER_NAGA, 'N', RED, "greater naga",
+ M_RES_POISON | M_SPELLCASTER | M_ACTUAL_SPELLS | M_SEE_INVIS | M_WARM_BLOOD,
+ 750, 10, MONS_NAGA, MH_NATURAL, 5000,
+ { 18, 0, 0, 0 },
+ { 15, 3, 5, 0 },
+ 6, 10, 8, 7, MST_NAGA_MAGE, CE_POISONOUS, Z_SMALL, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_SKELETAL_DRAGON, 'D', LIGHTGREY, "skeletal dragon",
+ M_RES_POISON | M_RES_FIRE | M_RES_COLD | M_RES_ELEC | M_SEE_INVIS,
+ 0, 12, MONS_SKELETAL_DRAGON, MH_UNDEAD, -4,
+ { 30, 20, 20, 0 },
+ { 20, 8, 8, 0 },
+ 20, 4, 8, 7, MST_NO_SPELLS, CE_CLEAN, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_TENTACLED_MONSTROSITY, 'X', GREEN, "tentacled monstrosity",
+ M_RES_POISON | M_RES_FIRE | M_RES_COLD | M_RES_ELEC | M_SEE_INVIS | M_AMPHIBIOUS,
+ 0, 10, MONS_TENTACLED_MONSTROSITY, MH_NATURAL, -5,
+ { 22, 17, 13, 19 },
+ { 25, 3, 5, 0 },
+ 5, 5, 9, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_SPHINX, 'H', LIGHTGREY, "sphinx",
+ M_FLIES | M_SEE_INVIS | M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD,
+ 0, 10, MONS_SPHINX, MH_NATURAL, -3,
+ { 25, 12, 12, 0 },
+ { 16, 3, 5, 0 },
+ 5, 5, 13, 7, MST_SPHINX, CE_CLEAN, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_ROTTING_HULK, 'n', BROWN, "rotting hulk",
+ M_RES_POISON | M_RES_COLD,
+ 0, 12, MONS_ROTTING_HULK, MH_UNDEAD, -5,
+ { 25, 0, 0, 0 },
+ { 10, 3, 5, 0 },
+ 5, 7, 8, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_GUARDIAN_MUMMY, 'M', YELLOW, "guardian mummy",
+ M_RES_POISON | M_RES_COLD | M_SEE_INVIS,
+ 0, 13, MONS_GUARDIAN_MUMMY, MH_UNDEAD, -5,
+ { 30, 0, 0, 0 },
+ { 7, 5, 3, 0 },
+ 6, 9, 9, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_GREATER_MUMMY, 'M', DARKGREY, "greater mummy",
+ M_RES_POISON | M_RES_COLD | M_RES_ELEC | M_SPELLCASTER | M_ACTUAL_SPELLS | M_SEE_INVIS,
+ 0, 20, MONS_MUMMY, MH_UNDEAD, 5000,
+ { 35, 0, 0, 0 },
+ { 15, 5, 3, 100 },
+ 10, 6, 10, 7, MST_MUMMY, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_MUMMY_PRIEST, 'M', RED, "mummy priest",
+ M_RES_POISON | M_RES_COLD | M_RES_ELEC | M_SPELLCASTER | M_PRIEST | M_SEE_INVIS,
+ 0, 16, MONS_MUMMY, MH_UNDEAD, 5000,
+ { 30, 0, 0, 0 },
+ { 10, 5, 3, 0 },
+ 8, 7, 9, 7, MST_MUMMY, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_CENTAUR_WARRIOR, 'c', YELLOW, "centaur warrior",
+ M_WARM_BLOOD,
+ 1500, 12, MONS_CENTAUR, MH_NATURAL, -3,
+ { 16, 0, 0, 0 },
+ { 9, 3, 5, 0 },
+ 4, 8, 15, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_YAKTAUR_CAPTAIN, 'c', RED, "yaktaur captain",
+ M_WARM_BLOOD,
+ 2000, 10, MONS_YAKTAUR, MH_NATURAL, -3,
+ { 23, 0, 0, 0 },
+ { 14, 3, 5, 0 },
+ 5, 5, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_KILLER_KLOWN, '@', BLACK, "Killer Klown",
+ M_RES_FIRE | M_RES_COLD | M_RES_POISON | M_SEE_INVIS | M_SPEAKS | M_WARM_BLOOD,
+ 0, 15, MONS_KILLER_KLOWN, MH_NATURAL, 5000,
+ { 30, 0, 0, 0 },
+ { 20, 5, 5, 0 },
+ 10, 15, 15, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_ELECTRIC_GOLEM, '8', LIGHTCYAN, "electric golem",
+ M_SPELLCASTER | M_RES_ELEC | M_RES_POISON | M_RES_FIRE | M_RES_COLD | M_SEE_INVIS,
+ 0, 10, MONS_ELECTRIC_GOLEM, MH_NONLIVING, 5000,
+ { 12, 12, 12, 12 },
+ { 15, 7, 4, 0 },
+ 5, 20, 20, 7, MST_ELECTRIC_GOLEM, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_BALL_LIGHTNING, '*', LIGHTCYAN, "ball lightning",
+ M_FLIES | M_RES_ELEC | M_CONFUSED | M_SPELLCASTER,
+ 0, 20, MONS_BALL_LIGHTNING, MH_NONLIVING, 5000,
+ { 5, 0, 0, 0 },
+ { 12, 0, 0, 1 },
+ 0, 10, 20, 7, MST_STORM_DRAGON, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_PLANT,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_ORB_OF_FIRE, '*', RED, "orb of fire",
+ M_SPELLCASTER | M_FLIES | M_RES_ELEC | M_RES_FIRE | M_RES_COLD | M_RES_POISON | M_SEE_INVIS,
+ 0, 10, MONS_ORB_OF_FIRE, MH_NONLIVING, 5000,
+ { 0, 0, 0, 0 },
+ { 30, 0, 0, 150 },
+ 20, 20, 20, 7, MST_ORB_OF_FIRE, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_QUOKKA, 'r', LIGHTGREY, "quokka",
+ M_WARM_BLOOD,
+ 300, 10, MONS_QUOKKA, MH_NATURAL, -1,
+ { 5, 0, 0, 0 },
+ { 1, 3, 5, 0 },
+ 2, 13, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_NORMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_EYE_OF_DEVASTATION, 'G', YELLOW, "eye of devastation",
+ M_NO_SKELETON | M_LEVITATE | M_SPELLCASTER | M_SEE_INVIS,
+ 0, 11, MONS_EYE_OF_DEVASTATION, MH_NATURAL, 5000,
+ { 0, 0, 0, 0 },
+ { 10, 3, 5, 0 },
+ 12, 1, 7, 7, MST_EYE_OF_DEVASTATION, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_MOTH_OF_WRATH, 'y', BROWN, "moth of wrath",
+ M_FLIES,
+ 0, 10, MONS_MOTH_OF_WRATH, MH_NATURAL, -3,
+ { 25, 0, 0, 0 },
+ { 9, 3, 5, 0 },
+ 0, 10, 12, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_DEATH_COB, '%', YELLOW, "death cob",
+ M_RES_POISON | M_RES_COLD | M_SPEAKS,
+ 0, 10, MONS_DEATH_COB, MH_UNDEAD, -3,
+ { 20, 0, 0, 0 },
+ { 10, 4, 5, 0 },
+ 10, 15, 25, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_MOAN, I_NORMAL,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_CURSE_TOE, 'z', DARKGREY, "curse toe",
+ M_RES_ELEC | M_RES_POISON | M_RES_HELLFIRE | M_RES_COLD | M_LEVITATE | M_SPELLCASTER | M_SEE_INVIS,
+ 0, 60, MONS_CURSE_TOE, MH_UNDEAD, 5000,
+ { 0, 0, 0, 0 },
+ { 14, 0, 0, 77 },
+ 50, 1, 12, 7, MST_CURSE_SKULL, CE_NOCORPSE, Z_NOZOMBIE, S_MOAN, I_HIGH,
+ MONUSE_NOTHING
+}
+,
+
+{
+ // gold mimics are the only mimics that actually use their name -- bwr
+ MONS_GOLD_MIMIC, '$', YELLOW, "pile of gold coins",
+ M_NO_SKELETON | M_RES_POISON | M_RES_ELEC | M_RES_FIRE | M_RES_COLD,
+ 0, 13, MONS_GOLD_MIMIC, MH_NONLIVING, -3,
+ { 12, 12, 12, 0 },
+ { 8, 3, 5, 0 },
+ 5, 1, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_WEAPON_MIMIC, ')', BLACK, "mimic",
+ M_NO_SKELETON | M_RES_POISON | M_RES_ELEC | M_RES_FIRE | M_RES_COLD,
+ 0, 13, MONS_GOLD_MIMIC, MH_NONLIVING, -3,
+ { 17, 17, 17, 0 },
+ { 8, 3, 5, 0 },
+ 5, 1, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_ARMOUR_MIMIC, '[', BLACK, "mimic",
+ M_NO_SKELETON | M_RES_POISON | M_RES_ELEC | M_RES_FIRE | M_RES_COLD,
+ 0, 13, MONS_GOLD_MIMIC, MH_NONLIVING, -3,
+ { 12, 12, 12, 0 },
+ { 8, 3, 5, 0 },
+ 15, 1, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_SCROLL_MIMIC, '?', LIGHTGREY, "mimic",
+ M_NO_SKELETON | M_RES_POISON | M_RES_ELEC | M_RES_FIRE | M_RES_COLD,
+ 0, 13, MONS_GOLD_MIMIC, MH_NONLIVING, -3,
+ { 12, 12, 12, 0 },
+ { 8, 3, 5, 0 },
+ 5, 1, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_POTION_MIMIC, '!', BLACK, "mimic",
+ M_NO_SKELETON | M_RES_POISON | M_RES_ELEC | M_RES_FIRE | M_RES_COLD,
+ 0, 13, MONS_GOLD_MIMIC, MH_NONLIVING, -3,
+ { 12, 12, 12, 0 },
+ { 8, 3, 5, 0 },
+ 5, 1, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_HELL_HOG, 'h', RED, "hell-hog",
+ M_SPELLCASTER,
+ 0, 10, MONS_HELL_HOG, MH_DEMONIC, -3,
+ { 20, 0, 0, 0 },
+ { 11, 3, 5, 0 },
+ 2, 9, 14, 7, MST_HELL_HOG, CE_CLEAN, Z_NOZOMBIE, S_SILENT, I_ANIMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_SERPENT_OF_HELL, 'D', RED, "Serpent of Hell",
+ M_SPELLCASTER | M_RES_POISON | M_RES_HELLFIRE | M_FLIES | M_SEE_INVIS,
+ 0, 18, MONS_SERPENT_OF_HELL, MH_DEMONIC, -13,
+ { 35, 15, 15, 0 },
+ { 20, 4, 4, 0 },
+ 12, 9, 14, 7, MST_SERPENT_OF_HELL, CE_CLEAN, Z_NOZOMBIE, S_ROAR, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_BOGGART, 'g', DARKGREY, "boggart",
+ M_SPELLCASTER | M_ACTUAL_SPELLS | M_SEE_INVIS,
+ 0, 14, MONS_BOGGART, MH_NATURAL, -7,
+ { 5, 0, 0, 0 },
+ { 2, 3, 5, 0 },
+ 0, 12, 12, 7, MST_BOGGART, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+{
+ MONS_QUICKSILVER_DRAGON, 'D', LIGHTCYAN, "quicksilver dragon",
+ M_SPELLCASTER | M_FLIES | M_SEE_INVIS,
+ 0, 14, MONS_QUICKSILVER_DRAGON, MH_NATURAL, -7,
+ { 45, 0, 0, 0 },
+ { 16, 3, 5, 0 },
+ 10, 15, 15, 7, MST_QUICKSILVER_DRAGON, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_IRON_DRAGON, 'D', CYAN, "iron dragon",
+ M_SPELLCASTER | M_RES_POISON | M_RES_FIRE | M_RES_COLD | M_SEE_INVIS,
+ 0, 14, MONS_IRON_DRAGON, MH_NATURAL, -7,
+ { 25, 25, 25, 0 },
+ { 18, 5, 3, 0 },
+ 20, 6, 8, 7, MST_IRON_DRAGON, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_SKELETAL_WARRIOR, 'z', CYAN, "skeletal warrior",
+ M_SPELLCASTER | M_RES_POISON | M_RES_COLD | M_ACTUAL_SPELLS,
+ 0, 10, MONS_SKELETAL_WARRIOR, MH_UNDEAD, -7,
+ { 25, 0, 0, 0 },
+ { 10, 5, 3, 0 },
+ 15, 10, 10, 7, MST_SKELETAL_WARRIOR, CE_CONTAMINATED, Z_SMALL, S_SILENT, I_NORMAL,
+ MONUSE_WEAPONS_ARMOUR
+}
+,
+
+
+/* player ghost - only one per level. stats are stored in ghost struct */
+{
+ MONS_PLAYER_GHOST, 'p', DARKGREY, "",
+ M_RES_POISON | M_SPEAKS | M_SPELLCASTER | M_ACTUAL_SPELLS | M_FLIES,
+ 0, 15, MONS_PLAYER_GHOST, MH_UNDEAD, -5,
+ { 5, 0, 0, 0 },
+ { 4, 2, 3, 0 },
+ 1, 2, 10, 7, MST_GHOST, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+/* random demon in pan - only one per level. stats are stored in ghost struct */
+{
+ MONS_PANDEMONIUM_DEMON, '&', BLACK, "&",
+ M_SPELLCASTER | M_RES_POISON | M_SPEAKS,
+ 0, 14, MONS_PANDEMONIUM_DEMON, MH_DEMONIC, -5,
+ { 5, 0, 0, 0 },
+ { 4, 2, 3, 0 },
+ 1, 2, 10, 7, MST_GHOST, CE_CONTAMINATED, Z_NOZOMBIE, S_RANDOM, I_HIGH,
+ MONUSE_OPEN_DOORS
+}
+,
+
+// begin lava monsters {dlb}
+{
+ MONS_LAVA_WORM, 'w', RED, "lava worm",
+ M_RES_FIRE | M_ED_COLD,
+ 0, 10, MONS_LAVA_WORM, MH_NATURAL, -3,
+ { 15, 0, 0, 0 },
+ { 6, 3, 5, 0 },
+ 1, 10, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_SILENT, I_ANIMAL_LIKE,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_LAVA_FISH, ';', RED, "lava fish",
+ M_RES_FIRE | M_ED_COLD,
+ 0, 10, MONS_LAVA_FISH, MH_NATURAL, -3,
+ { 10, 0, 0, 0 },
+ { 4, 3, 5, 0 },
+ 4, 15, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_SILENT, I_ANIMAL_LIKE,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_LAVA_SNAKE, 'S', RED, "lava snake",
+ M_RES_FIRE | M_ED_COLD,
+ 0, 10, MONS_LAVA_SNAKE, MH_NATURAL, -3,
+ { 7, 0, 0, 0 },
+ { 3, 3, 5, 0 },
+ 2, 17, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_HISS, I_ANIMAL_LIKE,
+ MONUSE_NOTHING
+}
+,
+
+{ // mv: was another lava thing
+ MONS_SALAMANDER, 'S', LIGHTRED, "salamander",
+ M_RES_FIRE | M_ED_COLD | M_WARM_BLOOD,
+ 0, 10, MONS_SALAMANDER, MH_NATURAL, -3,
+ { 23, 0, 0, 0 },
+ { 14, 3, 5, 0 },
+ 5, 5, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_SILENT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR
+}
+
+,
+// end lava monsters {dlb}
+
+// begin water monsters {dlb}
+{
+ MONS_BIG_FISH, ';', LIGHTGREEN, "big fish",
+ M_COLD_BLOOD,
+ 0, 10, MONS_BIG_FISH, MH_NATURAL, -3,
+ { 8, 0, 0, 0 },
+ { 4, 3, 5, 0 },
+ 1, 12, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_SILENT, I_ANIMAL_LIKE,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_GIANT_GOLDFISH, ';', LIGHTRED, "giant goldfish",
+ M_COLD_BLOOD,
+ 0, 10, MONS_GIANT_GOLDFISH, MH_NATURAL, -3,
+ { 15, 0, 0, 0 },
+ { 7, 3, 5, 0 },
+ 5, 7, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_SILENT, I_ANIMAL_LIKE,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_ELECTRICAL_EEL, ';', LIGHTBLUE, "electrical eel",
+ M_RES_ELEC | M_COLD_BLOOD,
+ 0, 10, MONS_ELECTRICAL_EEL, MH_NATURAL, -3,
+ { 0, 0, 0, 0 },
+ { 3, 3, 5, 0 },
+ 1, 15, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_SILENT, I_ANIMAL_LIKE,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_JELLYFISH, 'J', CYAN, "jellyfish",
+ M_RES_POISON,
+ 0, 10, MONS_JELLYFISH, MH_NATURAL, -3,
+ { 1, 1, 0, 0 },
+ { 4, 3, 5, 0 },
+ 0, 5, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_WATER_ELEMENTAL, '{', LIGHTBLUE, "water elemental",
+ M_RES_POISON | M_ED_FIRE | M_FLIES | M_RES_ELEC,
+ 0, 10, MONS_WATER_ELEMENTAL, MH_NONLIVING, 5000,
+ { 25, 0, 0, 0 },
+ { 6, 5, 3, 0 },
+ 0, 7, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_OPEN_DOORS
+}
+,
+
+{
+ MONS_SWAMP_WORM, 'w', BROWN, "swamp worm",
+ M_AMPHIBIOUS,
+ 0, 10, MONS_SWAMP_WORM, MH_NATURAL, -3,
+ { 20, 0, 0, 0 },
+ { 5, 5, 5, 0 },
+ 3, 12, 12, 0, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+},
+// end water monsters {dlb}
+
+/* ************************************************************************
+Josh added the following, but they just won't work in the game just yet ...
+besides, four bear types !?!?! isn't that a *bit* excessive given the
+limited diversity of existing monster types?
+
+I'm still far from happy about the inclusion of "Shuggoths" -- I just do
+not think it fits into Crawl ... {dlb}
+************************************************************************ */
+ //jmf: it's never created anywhere yet, so you can save the punctuation.
+ // as to bears & wolves: the lair needs more variety.
+
+#if 0
+{
+ MONS_SHUGGOTH, 'A', LIGHTGREEN, "shuggoth",
+ M_NO_SKELETON | M_RES_ELEC | M_RES_POISON | M_RES_FIRE | M_RES_COLD | M_SEE_INVIS,
+ 1000, 10, MONS_SHUGGOTH, MH_DEMONIC, 300,
+ { 5, 5, 5, 0 },
+ { 10, 4, 4, 0 },
+ 10, 10, 20, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, -1, I_NORMAL,
+ MONUSE_NOTHING
+}
+,
+#endif
+
+{
+ MONS_WOLF, 'h', LIGHTGREY, "wolf",
+ M_WARM_BLOOD | M_SEE_INVIS, //jmf: until smell exists
+ 450, 10, MONS_WOLF, MH_NATURAL, -3,
+ { 8, 2, 2, 0 },
+ { 4, 3, 5, 0 },
+ 3, 15, 17, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_BARK, I_ANIMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_WARG, 'h', DARKGREY, "warg",
+ M_SEE_INVIS | M_RES_POISON | M_WARM_BLOOD,
+ 600, 12, MONS_WARG, MH_NATURAL, -6,
+ { 12, 3, 3, 0 },
+ { 4, 4, 5, 0 },
+ 4, 12, 13, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_BARK, I_ANIMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_BEAR, 'U', BROWN, "bear",
+ M_WARM_BLOOD,
+ 2000, 10, MONS_BEAR, MH_NATURAL, -3,
+ { 10, 6, 6, 0 },
+ { 7, 3, 3, 0 },
+ 4, 4, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_GROWL, I_ANIMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_GRIZZLY_BEAR, 'U', LIGHTGREY, "grizzly bear",
+ M_WARM_BLOOD,
+ 2500, 10, MONS_GRIZZLY_BEAR, MH_NATURAL, -3,
+ { 12, 8, 8, 0 },
+ { 7, 4, 4, 0 },
+ 5, 8, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_GROWL, I_ANIMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_POLAR_BEAR, 'U', WHITE, "polar bear",
+ M_RES_COLD | M_WARM_BLOOD | M_AMPHIBIOUS,
+ 2500, 10, MONS_POLAR_BEAR, MH_NATURAL, -3,
+ { 20, 5, 5, 0 }, //jmf: polar bears have very strong jaws & necks
+ { 7, 5, 3, 0 },
+ 7, 8, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_GROWL, I_ANIMAL,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_BLACK_BEAR, 'U', DARKGREY, "black bear",
+ M_WARM_BLOOD,
+ 1800, 10, MONS_BLACK_BEAR, MH_NATURAL, -3,
+ { 4, 4, 4, 0 },
+ { 6, 3, 3, 0 },
+ 2, 8, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_GROWL, I_ANIMAL,
+ MONUSE_NOTHING
+}
+,
+
+// small simulacrum
+{
+ MONS_SIMULACRUM_SMALL, 'z', WHITE, "",
+ M_RES_POISON | M_ED_FIRE | M_RES_COLD,
+ 0, 6, MONS_SIMULACRUM_SMALL, MH_UNDEAD, -1,
+ { 6, 0, 0, 0 },
+ { 2, 3, 5, 0 },
+ 10, 4, 7, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+// large simulacrum
+{
+ MONS_SIMULACRUM_LARGE, 'Z', WHITE, "",
+ M_RES_POISON | M_ED_FIRE | M_RES_COLD,
+ 0, 6, MONS_SIMULACRUM_LARGE, MH_UNDEAD, -1,
+ { 14, 0, 0, 0 },
+ { 5, 3, 5, 0 },
+ 10, 5, 7, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_GIANT_NEWT, 'l', LIGHTGREEN, "giant newt",
+ M_COLD_BLOOD | M_AMPHIBIOUS,
+ 150, 10, MONS_GIANT_NEWT, MH_NATURAL, -3,
+ { 3, 0, 0, 0 },
+ { 1, 1, 2, 0 },
+ 0, 15, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_REPTILE,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_GIANT_GECKO, 'l', YELLOW, "giant gecko",
+ M_COLD_BLOOD,
+ 250, 10, MONS_GIANT_GECKO, MH_NATURAL, -3,
+ { 5, 0, 0, 0 },
+ { 1, 3, 5, 0 },
+ 1, 14, 12, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_REPTILE,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_GIANT_IGUANA, 'l', BLUE, "giant iguana",
+ M_COLD_BLOOD,
+ 400, 10, MONS_GIANT_IGUANA, MH_NATURAL, -3,
+ { 15, 0, 0, 0 },
+ { 3, 3, 5, 0 },
+ 5, 9, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_HISS, I_REPTILE,
+ MONUSE_NOTHING
+}
+,
+
+{
+ // gila monsters colours: lightmagenta, magenta, lightred, red, yellow
+ MONS_GILA_MONSTER, 'l', BLACK, "gila monster",
+ M_COLD_BLOOD,
+ 500, 10, MONS_GILA_MONSTER, MH_NATURAL, -3,
+ { 20, 0, 0, 0 },
+ { 5, 4, 4, 0 },
+ 3, 12, 10, 7, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_HISS, I_REPTILE,
+ MONUSE_NOTHING
+}
+,
+
+{
+ MONS_KOMODO_DRAGON, 'l', BROWN, "komodo dragon",
+ M_COLD_BLOOD | M_AMPHIBIOUS,
+ 800, 10, MONS_KOMODO_DRAGON, MH_NATURAL, -3,
+ { 30, 0, 0, 0 },
+ { 8, 3, 5, 0 },
+ 7, 8, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_HISS, I_REPTILE,
+ MONUSE_NOTHING
+}
+,
+
+#endif
diff --git a/trunk/source/mon-pick.cc b/trunk/source/mon-pick.cc
new file mode 100644
index 0000000000..f4a3446230
--- /dev/null
+++ b/trunk/source/mon-pick.cc
@@ -0,0 +1,2727 @@
+/*
+ * File: mon-pick.cc
+ * Summary: Functions used to help determine which monsters should appear.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <2> 08-Mar-2000 DLB enumeration & clean-up
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "mon-pick.h"
+
+#include "externs.h"
+
+static int mons_cocytus_level(int mcls);
+static int mons_cocytus_rare(int mcls);
+static int mons_crypt_level(int mcls);
+static int mons_crypt_rare(int mcls);
+static int mons_dis_level(int mcls);
+static int mons_dis_rare(int mcls);
+static int mons_gehenna_level(int mcls);
+static int mons_gehenna_rare(int mcls);
+static int mons_hallblade_level(int mcls);
+static int mons_hallblade_rare(int mcls);
+static int mons_hallelf_level(int mcls);
+static int mons_hallelf_rare(int mcls);
+static int mons_hallzot_level(int mcls);
+static int mons_hallzot_rare(int mcls);
+static int mons_hive_level(int mcls);
+static int mons_hive_rare(int mcls);
+static int mons_lair_level(int mcls);
+static int mons_lair_rare(int mcls);
+static int mons_mineorc_level(int mcls);
+static int mons_mineorc_rare(int mcls);
+static int mons_pitslime_level(int mcls);
+static int mons_pitslime_rare(int mcls);
+static int mons_pitsnake_level(int mcls);
+static int mons_pitsnake_rare(int mcls);
+static int mons_standard_level(int mcls);
+static int mons_standard_rare(int mcls);
+static int mons_swamp_level(int mcls);
+static int mons_swamp_rare(int mcls);
+static int mons_tartarus_level(int mcls);
+static int mons_tartarus_rare(int mcls);
+static int mons_tomb_level(int mcls);
+static int mons_tomb_rare(int mcls);
+
+/* ******************* BEGIN EXTERNAL FUNCTIONS ******************* */
+int branch_depth(int branch)
+{
+ switch (branch)
+ {
+ case STAIRS_LAIR:
+ return 10;
+
+ case STAIRS_VAULTS:
+ return 8;
+
+ case STAIRS_ELVEN_HALLS:
+ return 7;
+
+ case STAIRS_SLIME_PITS:
+ return 6;
+
+ case STAIRS_CRYPT:
+ case STAIRS_HALL_OF_ZOT:
+ case STAIRS_SNAKE_PIT:
+ case STAIRS_SWAMP:
+ return 5;
+
+ case STAIRS_HIVE:
+ case STAIRS_ORCISH_MINES:
+ return 4;
+
+ case STAIRS_TOMB:
+ return 3;
+
+ case STAIRS_ECUMENICAL_TEMPLE:
+ case STAIRS_HALL_OF_BLADES:
+ return 1;
+
+ default:
+ return 0;
+ }
+} // end branch_depth()
+
+// NB - When adding new branches or levels above 50, you must
+// change pre-game deletion routine in new_game in newgame.cc
+
+int mons_level(int mcls)
+{
+ int monster_level = 0;
+ int (*fnc_level) (int) = 0;
+
+ if (you.level_type == LEVEL_ABYSS)
+ monster_level = ((mons_abyss(mcls)) ? 51 : 0);
+ else if (you.level_type == LEVEL_PANDEMONIUM)
+ monster_level = ((mons_pan(mcls)) ? 52 : 0);
+ else
+ {
+ fnc_level =
+ ((you.where_are_you == BRANCH_DIS) ? mons_dis_level :
+ (you.where_are_you == BRANCH_GEHENNA) ? mons_gehenna_level :
+ (you.where_are_you == BRANCH_COCYTUS) ? mons_cocytus_level :
+ (you.where_are_you == BRANCH_TARTARUS) ? mons_tartarus_level :
+ (you.where_are_you == BRANCH_ORCISH_MINES) ? mons_mineorc_level :
+ (you.where_are_you == BRANCH_HIVE) ? mons_hive_level :
+ (you.where_are_you == BRANCH_LAIR) ? mons_lair_level :
+ (you.where_are_you == BRANCH_SLIME_PITS) ? mons_pitslime_level :
+ (you.where_are_you == BRANCH_CRYPT) ? mons_crypt_level :
+ (you.where_are_you == BRANCH_HALL_OF_BLADES)?mons_hallblade_level :
+ (you.where_are_you == BRANCH_HALL_OF_ZOT) ? mons_hallzot_level :
+ (you.where_are_you == BRANCH_SNAKE_PIT) ? mons_pitsnake_level :
+ (you.where_are_you == BRANCH_ELVEN_HALLS) ? mons_hallelf_level :
+ (you.where_are_you == BRANCH_TOMB) ? mons_tomb_level :
+ (you.where_are_you == BRANCH_SWAMP) ? mons_swamp_level :
+ (you.where_are_you == BRANCH_VAULTS) ? mons_standard_level
+ : mons_standard_level);
+
+ monster_level = fnc_level(mcls);
+ }
+
+ return (monster_level);
+} // end mons_level()
+
+// higher values returned means the monster is "more common"
+// a return value of zero means the monster will never appear {dlb}
+int mons_rarity(int mcls)
+{
+ int monster_rarity = 0;
+ int (*fnc_rarity) (int) = 0;
+
+ // now, what about pandemonium ??? {dlb}
+ if (you.level_type == LEVEL_ABYSS)
+ return mons_rare_abyss(mcls);
+ else
+ {
+ fnc_rarity =
+ ((you.where_are_you == BRANCH_DIS) ? mons_dis_rare :
+ (you.where_are_you == BRANCH_GEHENNA) ? mons_gehenna_rare :
+ (you.where_are_you == BRANCH_COCYTUS) ? mons_cocytus_rare :
+ (you.where_are_you == BRANCH_TARTARUS) ? mons_tartarus_rare :
+ (you.where_are_you == BRANCH_ORCISH_MINES) ? mons_mineorc_rare :
+ (you.where_are_you == BRANCH_HIVE) ? mons_hive_rare :
+ (you.where_are_you == BRANCH_LAIR) ? mons_lair_rare :
+ (you.where_are_you == BRANCH_SLIME_PITS) ? mons_pitslime_rare :
+ (you.where_are_you == BRANCH_CRYPT) ? mons_crypt_rare :
+ (you.where_are_you == BRANCH_HALL_OF_BLADES)?mons_hallblade_rare :
+ (you.where_are_you == BRANCH_HALL_OF_ZOT) ? mons_hallzot_rare :
+ (you.where_are_you == BRANCH_SNAKE_PIT) ? mons_pitsnake_rare :
+ (you.where_are_you == BRANCH_ELVEN_HALLS) ? mons_hallelf_rare :
+ (you.where_are_you == BRANCH_TOMB) ? mons_tomb_rare :
+ (you.where_are_you == BRANCH_SWAMP) ? mons_swamp_rare :
+ (you.where_are_you == BRANCH_VAULTS) ? mons_standard_rare
+ : mons_standard_rare);
+
+ monster_rarity = fnc_rarity(mcls);
+ }
+
+ return (monster_rarity);
+} // end mons_rarity()
+
+bool mons_abyss(int mcls)
+{
+ switch (mcls)
+ {
+ case MONS_ABOMINATION_LARGE:
+ case MONS_ABOMINATION_SMALL:
+ case MONS_AIR_ELEMENTAL:
+ case MONS_ANCIENT_LICH:
+ case MONS_BALRUG:
+ case MONS_BLUE_DEATH:
+ case MONS_BLUE_DEVIL:
+ case MONS_BRAIN_WORM:
+ case MONS_CACODEMON:
+ case MONS_CLAY_GOLEM:
+ case MONS_CRYSTAL_GOLEM:
+ case MONS_DANCING_WEAPON:
+ case MONS_DEMONIC_CRAWLER:
+ case MONS_EARTH_ELEMENTAL:
+ case MONS_EFREET:
+ case MONS_EXECUTIONER:
+ case MONS_EYE_OF_DEVASTATION:
+ case MONS_EYE_OF_DRAINING:
+ case MONS_FIRE_ELEMENTAL:
+ case MONS_FLAYED_GHOST:
+ case MONS_FLYING_SKULL:
+ case MONS_FREEZING_WRAITH:
+ case MONS_FUNGUS:
+ case MONS_GIANT_EYEBALL:
+ case MONS_GIANT_ORANGE_BRAIN:
+ case MONS_GIANT_SPORE:
+ case MONS_GREAT_ORB_OF_EYES:
+ case MONS_GREEN_DEATH:
+ case MONS_GUARDIAN_NAGA:
+ case MONS_HAIRY_DEVIL:
+ case MONS_HELLION:
+ case MONS_HELLWING:
+ case MONS_HELL_HOUND:
+ case MONS_HELL_KNIGHT:
+ case MONS_HUNGRY_GHOST:
+ case MONS_ICE_BEAST:
+ case MONS_ICE_DEVIL:
+ case MONS_IMP:
+ case MONS_INSUBSTANTIAL_WISP:
+ case MONS_IRON_DEVIL:
+ case MONS_IRON_GOLEM:
+ case MONS_JELLY:
+ case MONS_SKELETON_LARGE:
+ case MONS_LEMURE:
+ case MONS_LICH:
+ case MONS_LOROCYPROCA:
+ case MONS_MANES:
+ case MONS_MIDGE:
+ case MONS_MUMMY:
+ case MONS_NAGA_MAGE:
+ case MONS_NAGA_WARRIOR:
+ case MONS_NECROMANCER:
+ case MONS_NECROPHAGE:
+ case MONS_NEQOXEC:
+ case MONS_ORANGE_DEMON:
+ case MONS_PHANTOM:
+ case MONS_PIT_FIEND:
+ case MONS_RAKSHASA:
+ case MONS_REAPER:
+ case MONS_RED_DEVIL:
+ case MONS_ROTTING_DEVIL:
+ case MONS_SHADOW:
+ case MONS_SHADOW_DEMON:
+ case MONS_SHADOW_IMP:
+ case MONS_SHINING_EYE:
+ case MONS_SKELETAL_DRAGON:
+ case MONS_SKELETAL_WARRIOR:
+ case MONS_SKELETON_SMALL:
+ case MONS_SMOKE_DEMON:
+ case MONS_SOUL_EATER:
+ case MONS_SPECTRAL_WARRIOR:
+ case MONS_SPINY_WORM:
+ case MONS_STONE_GOLEM:
+ case MONS_SUN_DEMON:
+ case MONS_TENTACLED_MONSTROSITY:
+ case MONS_TOENAIL_GOLEM:
+ case MONS_TORMENTOR:
+ case MONS_UFETUBUS:
+ case MONS_UGLY_THING:
+ case MONS_UNSEEN_HORROR:
+ case MONS_VAMPIRE:
+ case MONS_VAPOUR:
+ case MONS_VERY_UGLY_THING:
+ case MONS_WHITE_IMP:
+ case MONS_WIGHT:
+ case MONS_WIZARD:
+ case MONS_WOOD_GOLEM:
+ case MONS_WRAITH:
+ case MONS_YNOXINUL:
+ case MONS_ZOMBIE_LARGE:
+ case MONS_ZOMBIE_SMALL:
+ case MONS_SIMULACRUM_LARGE:
+ case MONS_SIMULACRUM_SMALL:
+ return true;
+ default:
+ return false;
+ }
+} // end mons_abyss()
+
+int mons_rare_abyss(int mcls)
+{
+ switch (mcls)
+ {
+ case MONS_ABOMINATION_LARGE:
+ case MONS_ABOMINATION_SMALL:
+ return 99;
+
+ case MONS_LEMURE:
+ case MONS_MANES:
+ case MONS_MIDGE:
+ case MONS_UFETUBUS:
+ case MONS_WHITE_IMP:
+ return 80;
+
+ case MONS_HELLWING:
+ case MONS_NEQOXEC:
+ case MONS_ORANGE_DEMON:
+ case MONS_SMOKE_DEMON:
+ case MONS_YNOXINUL:
+ return 50;
+
+ case MONS_SKELETON_LARGE:
+ case MONS_SKELETAL_WARRIOR:
+ case MONS_SKELETON_SMALL:
+ return 40;
+
+ case MONS_ZOMBIE_LARGE:
+ case MONS_ZOMBIE_SMALL:
+ return 35;
+
+ case MONS_SKELETAL_DRAGON:
+ return 20;
+
+ case MONS_EFREET:
+ return 18;
+
+ case MONS_RAKSHASA:
+ return 17;
+
+ case MONS_BRAIN_WORM:
+ return 16;
+
+ case MONS_FLYING_SKULL:
+ case MONS_FREEZING_WRAITH:
+ case MONS_GIANT_ORANGE_BRAIN:
+ case MONS_VERY_UGLY_THING:
+ case MONS_WRAITH:
+ return 15;
+
+ case MONS_EYE_OF_DRAINING:
+ case MONS_LICH:
+ return 14;
+
+ case MONS_INSUBSTANTIAL_WISP:
+ case MONS_UNSEEN_HORROR:
+ return 12;
+
+ case MONS_HELL_HOUND:
+ case MONS_HUNGRY_GHOST:
+ case MONS_SHADOW:
+ return 11;
+
+ case MONS_BALRUG:
+ case MONS_BLUE_DEATH:
+ case MONS_BLUE_DEVIL:
+ case MONS_CACODEMON:
+ case MONS_DEMONIC_CRAWLER:
+ case MONS_EXECUTIONER:
+ case MONS_GREEN_DEATH:
+ case MONS_GUARDIAN_NAGA:
+ case MONS_HAIRY_DEVIL:
+ case MONS_HELLION:
+ case MONS_ICE_DEVIL:
+ case MONS_IMP:
+ case MONS_LOROCYPROCA:
+ case MONS_MUMMY:
+ case MONS_NECROPHAGE:
+ case MONS_ROTTING_DEVIL:
+ case MONS_SHADOW_DEMON:
+ case MONS_SHADOW_IMP:
+ case MONS_SUN_DEMON:
+ case MONS_WIGHT:
+ return 10;
+
+ case MONS_ICE_BEAST:
+ case MONS_JELLY:
+ case MONS_TORMENTOR:
+ case MONS_VAMPIRE:
+ case MONS_VAPOUR:
+ case MONS_SIMULACRUM_LARGE:
+ case MONS_SIMULACRUM_SMALL:
+ return 9;
+
+ case MONS_FUNGUS:
+ case MONS_GIANT_EYEBALL:
+ case MONS_PHANTOM:
+ case MONS_REAPER:
+ return 8;
+
+ case MONS_SOUL_EATER:
+ return 7;
+
+ case MONS_IRON_DEVIL:
+ return 6;
+
+ case MONS_ANCIENT_LICH:
+ case MONS_CLAY_GOLEM:
+ case MONS_GREAT_ORB_OF_EYES:
+ case MONS_IRON_GOLEM:
+ case MONS_NAGA_MAGE:
+ case MONS_NAGA_WARRIOR:
+ case MONS_PIT_FIEND:
+ case MONS_RED_DEVIL:
+ case MONS_SHINING_EYE:
+ case MONS_SPECTRAL_WARRIOR:
+ case MONS_SPINY_WORM:
+ case MONS_STONE_GOLEM:
+ case MONS_TENTACLED_MONSTROSITY:
+ case MONS_WIZARD:
+ case MONS_WOOD_GOLEM:
+ return 5;
+
+ case MONS_AIR_ELEMENTAL:
+ case MONS_EARTH_ELEMENTAL:
+ case MONS_FIRE_ELEMENTAL:
+ case MONS_FLAYED_GHOST:
+ return 4;
+
+ case MONS_CRYSTAL_GOLEM:
+ case MONS_EYE_OF_DEVASTATION:
+ case MONS_HELL_KNIGHT:
+ case MONS_NECROMANCER:
+ case MONS_UGLY_THING:
+ return 3;
+
+ case MONS_DANCING_WEAPON:
+ case MONS_GIANT_SPORE:
+ return 2;
+
+ case MONS_TOENAIL_GOLEM:
+ return 1;
+
+ default:
+ return 0;
+ }
+} // end mons_rare_abyss()
+
+bool mons_pan(int mcls)
+{
+ switch (mcls)
+ {
+ // icky monsters
+ case MONS_BRAIN_WORM:
+ case MONS_FUNGUS:
+ case MONS_GIANT_ORANGE_BRAIN:
+ case MONS_JELLY:
+ case MONS_SLIME_CREATURE:
+ // undead
+ case MONS_FLAYED_GHOST:
+ case MONS_FLYING_SKULL:
+ case MONS_FREEZING_WRAITH:
+ case MONS_HUNGRY_GHOST:
+ case MONS_SKELETON_LARGE:
+ case MONS_LICH:
+ case MONS_MUMMY:
+ case MONS_NECROPHAGE:
+ case MONS_PHANTOM:
+ case MONS_SHADOW:
+ case MONS_SKELETON_SMALL:
+ case MONS_SPECTRAL_WARRIOR:
+ case MONS_VAMPIRE:
+ case MONS_WIGHT:
+ case MONS_WRAITH:
+ case MONS_ZOMBIE_LARGE:
+ case MONS_ZOMBIE_SMALL:
+ case MONS_SIMULACRUM_LARGE:
+ case MONS_SIMULACRUM_SMALL:
+ // "things"
+ case MONS_ABOMINATION_LARGE:
+ case MONS_ABOMINATION_SMALL:
+ case MONS_INSUBSTANTIAL_WISP:
+ case MONS_PULSATING_LUMP:
+ case MONS_UNSEEN_HORROR:
+ // eyes
+ case MONS_EYE_OF_DRAINING:
+ case MONS_GIANT_EYEBALL:
+ case MONS_GREAT_ORB_OF_EYES:
+ // malign beings
+ case MONS_EFREET:
+ case MONS_RAKSHASA:
+ //case MONS_RAKSHASA_FAKE: //jmf: FIXME: really create these?
+ // I'm guessing not -- bwr
+ // golems
+ case MONS_CLAY_GOLEM:
+ case MONS_CRYSTAL_GOLEM:
+ case MONS_IRON_GOLEM:
+ case MONS_STONE_GOLEM:
+ case MONS_TOENAIL_GOLEM:
+ case MONS_WOOD_GOLEM:
+ // dragon(s)
+ case MONS_MOTTLED_DRAGON:
+ // elementals
+ case MONS_AIR_ELEMENTAL:
+ case MONS_EARTH_ELEMENTAL:
+ case MONS_FIRE_ELEMENTAL:
+ // humanoids
+ case MONS_NECROMANCER:
+ case MONS_STONE_GIANT:
+ case MONS_WIZARD:
+ // demons
+ case MONS_BALRUG:
+ case MONS_BLUE_DEATH:
+ case MONS_CACODEMON:
+ case MONS_EXECUTIONER:
+ case MONS_GREEN_DEATH:
+ case MONS_HELLWING:
+ case MONS_LEMURE:
+ case MONS_MANES:
+ case MONS_MIDGE:
+ case MONS_NEQOXEC:
+ case MONS_ORANGE_DEMON:
+ case MONS_SMOKE_DEMON:
+ case MONS_UFETUBUS:
+ case MONS_WHITE_IMP:
+ case MONS_YNOXINUL:
+ return true;
+ default:
+ return false;
+ }
+} // end mons_pan()
+
+/* ******************** END EXTERNAL FUNCTIONS ******************** */
+
+static int mons_dis_level(int mcls)
+{
+ int mlev = 26;
+
+ switch (mcls)
+ {
+ case MONS_CLAY_GOLEM:
+ case MONS_IMP:
+ case MONS_NECROPHAGE:
+ case MONS_RED_DEVIL:
+ case MONS_SKELETAL_WARRIOR:
+ case MONS_ZOMBIE_LARGE:
+ mlev++;
+ break;
+
+ case MONS_HELL_HOUND:
+ case MONS_HELL_KNIGHT:
+ case MONS_SKELETON_LARGE:
+ case MONS_PHANTOM:
+ case MONS_ROTTING_DEVIL:
+ case MONS_SHADOW:
+ case MONS_SKELETON_SMALL:
+ case MONS_STONE_GOLEM:
+ case MONS_TORMENTOR:
+ case MONS_WIGHT:
+ case MONS_ZOMBIE_SMALL:
+ mlev += 2;
+ break;
+
+ case MONS_EFREET:
+ case MONS_FLYING_SKULL:
+ case MONS_HELLION:
+ case MONS_HELL_HOG:
+ case MONS_IRON_GOLEM:
+ case MONS_MUMMY:
+ mlev += 3;
+ break;
+
+ case MONS_FLAYED_GHOST:
+ case MONS_FREEZING_WRAITH:
+ case MONS_HAIRY_DEVIL:
+ case MONS_IRON_DEVIL:
+ case MONS_VAMPIRE:
+ case MONS_WRAITH:
+ mlev += 4;
+ break;
+
+ case MONS_BLUE_DEVIL:
+ case MONS_DANCING_WEAPON:
+ case MONS_ICE_DEVIL:
+ case MONS_ICE_DRAGON:
+ case MONS_LICH:
+ case MONS_REAPER:
+ case MONS_SOUL_EATER:
+ case MONS_SPECTRAL_WARRIOR:
+ mlev += 5;
+ break;
+
+ case MONS_ANCIENT_LICH:
+ case MONS_FIEND:
+ case MONS_IRON_DRAGON:
+ case MONS_SKELETAL_DRAGON:
+ mlev += 6;
+ break;
+
+ default:
+ return 0;
+ }
+
+ return (mlev);
+} // end mons_dis_level()
+
+static int mons_dis_rare(int mcls)
+{
+ switch (mcls)
+ {
+ case MONS_IMP:
+ case MONS_IRON_DEVIL:
+ case MONS_ZOMBIE_LARGE:
+ case MONS_ZOMBIE_SMALL:
+ return 99;
+
+ case MONS_REAPER:
+ return 77;
+
+ case MONS_TORMENTOR:
+ return 66;
+
+ case MONS_RED_DEVIL:
+ case MONS_SKELETAL_WARRIOR:
+ return 50;
+
+ case MONS_WRAITH:
+ return 48;
+
+ case MONS_SHADOW:
+ return 56;
+
+ case MONS_HELL_HOUND:
+ return 46;
+
+ case MONS_MUMMY:
+ case MONS_WIGHT:
+ return 45;
+
+ case MONS_HELLION:
+ case MONS_BLUE_DEVIL:
+ return 40;
+
+ case MONS_FLYING_SKULL:
+ return 35;
+
+ case MONS_FREEZING_WRAITH:
+ case MONS_ICE_DEVIL:
+ return 30;
+
+ case MONS_FLAYED_GHOST:
+ case MONS_SKELETON_LARGE:
+ case MONS_NECROPHAGE:
+ case MONS_SKELETON_SMALL:
+ return 25;
+
+ case MONS_HELL_HOG:
+ case MONS_SKELETAL_DRAGON:
+ return 20;
+
+ case MONS_VAMPIRE:
+ return 19;
+
+ case MONS_PHANTOM:
+ return 17;
+
+ case MONS_HAIRY_DEVIL:
+ return 15;
+
+ case MONS_CLAY_GOLEM:
+ case MONS_DANCING_WEAPON:
+ case MONS_EFREET:
+ case MONS_HELL_KNIGHT:
+ case MONS_IRON_GOLEM:
+ case MONS_LICH:
+ case MONS_ROTTING_DEVIL:
+ case MONS_SOUL_EATER:
+ case MONS_SPECTRAL_WARRIOR:
+ case MONS_STONE_GOLEM:
+ return 10;
+
+ case MONS_IRON_DRAGON:
+ return 5;
+
+ case MONS_ANCIENT_LICH:
+ case MONS_FIEND:
+ return 3;
+
+ default:
+ return 0;
+ }
+} // end mons_dis_rare()
+
+static int mons_gehenna_level(int mcls)
+{
+ int mlev = 26;
+
+ switch (mcls)
+ {
+ case MONS_CLAY_GOLEM:
+ case MONS_SKELETON_LARGE:
+ case MONS_RED_DEVIL:
+ case MONS_SKELETON_SMALL:
+ case MONS_ZOMBIE_LARGE:
+ case MONS_ZOMBIE_SMALL:
+ mlev++;
+ break;
+
+ case MONS_HELL_HOG:
+ case MONS_HELL_HOUND:
+ case MONS_IMP:
+ case MONS_NECROPHAGE:
+ case MONS_STONE_GOLEM:
+ mlev += 2;
+ break;
+
+ case MONS_FLYING_SKULL:
+ case MONS_IRON_GOLEM:
+ case MONS_MUMMY:
+ case MONS_PHANTOM:
+ case MONS_ROTTING_DEVIL:
+ case MONS_SHADOW:
+ case MONS_WIGHT:
+ mlev += 3;
+ break;
+
+ case MONS_HAIRY_DEVIL:
+ case MONS_HELL_KNIGHT:
+ case MONS_VAMPIRE:
+ case MONS_WRAITH:
+ mlev += 4;
+ break;
+
+ case MONS_EFREET:
+ case MONS_FLAYED_GHOST:
+ case MONS_HELLION:
+ case MONS_TORMENTOR:
+ mlev += 5;
+ break;
+
+ case MONS_ANCIENT_LICH:
+ case MONS_FIEND:
+ case MONS_LICH:
+ case MONS_PIT_FIEND:
+ case MONS_REAPER:
+ case MONS_SERPENT_OF_HELL:
+ case MONS_SKELETAL_DRAGON:
+ case MONS_SOUL_EATER:
+ case MONS_SPECTRAL_WARRIOR:
+ mlev += 6;
+ break;
+
+ default:
+ return 0;
+ }
+
+ return (mlev);
+} // end mons_gehenna_level()
+
+static int mons_gehenna_rare(int mcls)
+{
+ switch (mcls)
+ {
+ case MONS_SKELETON_LARGE:
+ case MONS_SKELETON_SMALL:
+ case MONS_ZOMBIE_LARGE:
+ case MONS_ZOMBIE_SMALL:
+ return 99;
+
+ case MONS_MUMMY:
+ return 70;
+
+ case MONS_SHADOW:
+ return 61;
+
+ case MONS_RED_DEVIL:
+ case MONS_WIGHT:
+ return 60;
+
+ case MONS_HELLION:
+ return 54;
+
+ case MONS_WRAITH:
+ return 53;
+
+ case MONS_NECROPHAGE:
+ case MONS_ROTTING_DEVIL:
+ return 50;
+
+ case MONS_VAMPIRE:
+ return 44;
+
+ case MONS_FLYING_SKULL:
+ case MONS_REAPER:
+ return 43;
+
+ case MONS_TORMENTOR:
+ return 42;
+
+ case MONS_HELL_HOUND:
+ return 41;
+
+ case MONS_FLAYED_GHOST:
+ case MONS_PHANTOM:
+ return 32;
+
+ case MONS_HELL_HOG:
+ case MONS_IMP:
+ case MONS_IRON_DEVIL:
+ return 30;
+
+ case MONS_LICH:
+ return 25;
+
+ case MONS_HELL_KNIGHT:
+ return 21;
+
+ case MONS_HAIRY_DEVIL:
+ case MONS_SPECTRAL_WARRIOR:
+ return 20;
+
+ case MONS_CLAY_GOLEM:
+ case MONS_SKELETAL_DRAGON:
+ return 10;
+
+ case MONS_STONE_GOLEM:
+ return 8;
+
+ case MONS_PIT_FIEND:
+ return 7;
+
+ case MONS_EFREET:
+ case MONS_FIEND:
+ case MONS_IRON_GOLEM:
+ case MONS_SOUL_EATER:
+ return 5;
+
+ case MONS_ANCIENT_LICH:
+ case MONS_SERPENT_OF_HELL:
+ return 4;
+
+ default:
+ return 0;
+ }
+} // end mons_gehenna_rare()
+
+static int mons_cocytus_level(int mcls)
+{
+ int mlev = 26;
+
+ switch (mcls)
+ {
+ case MONS_SKELETON_LARGE:
+ case MONS_NECROPHAGE:
+ case MONS_SKELETAL_WARRIOR:
+ case MONS_SKELETON_SMALL:
+ case MONS_ZOMBIE_LARGE:
+ case MONS_ZOMBIE_SMALL:
+ case MONS_SIMULACRUM_LARGE:
+ case MONS_SIMULACRUM_SMALL:
+ mlev++;
+ break;
+
+ case MONS_BLUE_DEVIL:
+ case MONS_ICE_BEAST:
+ case MONS_PHANTOM:
+ case MONS_SHADOW:
+ mlev += 2;
+ break;
+
+ case MONS_FLYING_SKULL:
+ case MONS_ROTTING_DEVIL:
+ case MONS_VAMPIRE:
+ case MONS_WIGHT:
+ mlev += 3;
+ break;
+
+ case MONS_FREEZING_WRAITH:
+ case MONS_HAIRY_DEVIL:
+ case MONS_HUNGRY_GHOST:
+ case MONS_MUMMY:
+ case MONS_SPECTRAL_WARRIOR:
+ case MONS_WRAITH:
+ mlev += 4;
+ break;
+
+ case MONS_ICE_DEVIL:
+ case MONS_ICE_DRAGON:
+ case MONS_TORMENTOR:
+ mlev += 5;
+ break;
+
+ case MONS_ANCIENT_LICH:
+ case MONS_LICH:
+ case MONS_REAPER:
+ case MONS_SKELETAL_DRAGON:
+ case MONS_SOUL_EATER:
+ mlev += 6;
+ break;
+
+ default:
+ return 0;
+ }
+
+ return (mlev);
+} // end mons_cocytus_level()
+
+static int mons_cocytus_rare(int mcls)
+{
+ switch (mcls)
+ {
+ case MONS_FREEZING_WRAITH:
+ return 87;
+
+ case MONS_ICE_BEAST:
+ case MONS_SKELETON_LARGE:
+ case MONS_SKELETON_SMALL:
+ case MONS_ZOMBIE_LARGE:
+ case MONS_ZOMBIE_SMALL:
+ return 85;
+
+ case MONS_BLUE_DEVIL:
+ case MONS_ICE_DEVIL:
+ return 76;
+
+ case MONS_FLYING_SKULL:
+ return 57;
+
+ case MONS_SHADOW:
+ return 56;
+
+ case MONS_SKELETAL_WARRIOR:
+ return 50;
+
+ case MONS_REAPER:
+ return 47;
+
+ case MONS_WIGHT:
+ case MONS_WRAITH:
+ return 45;
+
+ case MONS_ICE_DRAGON:
+ return 38;
+
+ case MONS_ROTTING_DEVIL:
+ case MONS_TORMENTOR:
+ return 37;
+
+ case MONS_MUMMY:
+ return 35;
+
+ case MONS_VAMPIRE:
+ return 34;
+
+ case MONS_HAIRY_DEVIL:
+ case MONS_HUNGRY_GHOST:
+ return 26;
+
+ case MONS_NECROPHAGE:
+ case MONS_PHANTOM:
+ return 25;
+
+ case MONS_SPECTRAL_WARRIOR:
+ return 20;
+
+ case MONS_SOUL_EATER:
+ return 19;
+
+ case MONS_LICH:
+ case MONS_SKELETAL_DRAGON:
+ case MONS_SIMULACRUM_LARGE:
+ case MONS_SIMULACRUM_SMALL:
+ return 12;
+
+ case MONS_ANCIENT_LICH:
+ return 5;
+
+ default:
+ return 0;
+ }
+} // end mons_cocytus_rare()
+
+static int mons_tartarus_level(int mcls)
+{
+ int mlev = 26;
+
+ switch (mcls)
+ {
+ case MONS_IMP:
+ case MONS_SKELETON_LARGE:
+ case MONS_RED_DEVIL:
+ case MONS_SHADOW_IMP:
+ case MONS_SKELETAL_WARRIOR:
+ case MONS_SKELETON_SMALL:
+ mlev++;
+ break;
+
+ case MONS_HELL_KNIGHT:
+ case MONS_NECROPHAGE:
+ case MONS_PHANTOM:
+ case MONS_WIGHT:
+ case MONS_ZOMBIE_LARGE:
+ case MONS_ZOMBIE_SMALL:
+ mlev += 2;
+ break;
+
+ case MONS_FREEZING_WRAITH:
+ case MONS_HELL_HOUND:
+ case MONS_NECROMANCER:
+ case MONS_SHADOW:
+ case MONS_SHADOW_DEMON:
+ case MONS_WRAITH:
+ mlev += 3;
+ break;
+
+ case MONS_BLUE_DEVIL:
+ case MONS_FLAYED_GHOST:
+ case MONS_HUNGRY_GHOST:
+ case MONS_ICE_DEVIL:
+ case MONS_MUMMY:
+ case MONS_SKELETAL_DRAGON:
+ case MONS_SPECTRAL_WARRIOR:
+ case MONS_TORMENTOR:
+ case MONS_SIMULACRUM_LARGE:
+ case MONS_SIMULACRUM_SMALL:
+ mlev += 4;
+ break;
+
+ case MONS_FLYING_SKULL:
+ case MONS_HELLION:
+ case MONS_REAPER:
+ case MONS_ROTTING_DEVIL:
+ case MONS_SHADOW_DRAGON:
+ case MONS_VAMPIRE:
+ mlev += 5;
+ break;
+
+ case MONS_ANCIENT_LICH:
+ case MONS_HAIRY_DEVIL:
+ case MONS_LICH:
+ case MONS_SOUL_EATER:
+ mlev += 6;
+ break;
+
+ default:
+ return 0;
+ }
+
+ return (mlev);
+} // end mons_tartarus_level()
+
+static int mons_tartarus_rare(int mcls)
+{
+ switch (mcls)
+ {
+ case MONS_SKELETON_LARGE:
+ case MONS_SHADOW_IMP:
+ case MONS_SKELETAL_WARRIOR:
+ case MONS_SKELETON_SMALL:
+ case MONS_ZOMBIE_LARGE:
+ case MONS_ZOMBIE_SMALL:
+ return 99;
+
+ case MONS_SHADOW:
+ return 92;
+
+ case MONS_REAPER:
+ return 73;
+
+ case MONS_NECROPHAGE:
+ return 72;
+
+ case MONS_WIGHT:
+ return 71;
+
+ case MONS_ROTTING_DEVIL:
+ return 62;
+
+ case MONS_FREEZING_WRAITH:
+ return 60;
+
+ case MONS_FLYING_SKULL:
+ return 53;
+
+ case MONS_HELL_HOUND:
+ case MONS_PHANTOM:
+ case MONS_WRAITH:
+ return 52;
+
+ case MONS_SHADOW_DEMON:
+ return 50;
+
+ case MONS_SPECTRAL_WARRIOR:
+ return 45;
+
+ case MONS_VAMPIRE:
+ return 44;
+
+ case MONS_HELLION:
+ case MONS_TORMENTOR:
+ return 42;
+
+ case MONS_SKELETAL_DRAGON:
+ return 40;
+
+ case MONS_SOUL_EATER:
+ return 35;
+
+ case MONS_ICE_DEVIL: // not really appropriate for a fiery hell
+ return 34;
+
+ case MONS_MUMMY:
+ return 33;
+
+ case MONS_BLUE_DEVIL:
+ case MONS_HUNGRY_GHOST:
+ return 32;
+
+ case MONS_FLAYED_GHOST:
+ case MONS_HAIRY_DEVIL:
+ return 30;
+
+ case MONS_LICH:
+ return 24;
+
+ case MONS_IMP:
+ case MONS_SHADOW_DRAGON:
+ return 20;
+
+ case MONS_RED_DEVIL:
+ return 13;
+
+ case MONS_HELL_KNIGHT:
+ return 14;
+
+ case MONS_NECROMANCER:
+ case MONS_SIMULACRUM_LARGE:
+ case MONS_SIMULACRUM_SMALL:
+ return 12;
+
+ case MONS_ANCIENT_LICH:
+ return 6;
+
+ default:
+ return 0;
+ }
+}
+
+static int mons_mineorc_level(int mcls)
+{
+ int mlev = you.branch_stairs[STAIRS_ORCISH_MINES] + 1;
+
+ switch (mcls)
+ {
+ case MONS_HOBGOBLIN:
+ case MONS_ORC_PRIEST:
+ case MONS_ORC_WARRIOR:
+ mlev++;
+ break;
+
+ case MONS_GNOLL:
+ case MONS_OGRE:
+ case MONS_WARG:
+ case MONS_ORC_KNIGHT:
+ case MONS_ORC_WIZARD:
+ mlev += 2;
+ break;
+
+ case MONS_CYCLOPS:
+ case MONS_IRON_TROLL:
+ case MONS_OGRE_MAGE:
+ case MONS_ORC_HIGH_PRIEST:
+ case MONS_ORC_SORCERER:
+ case MONS_ORC_WARLORD:
+ case MONS_ROCK_TROLL:
+ case MONS_STONE_GIANT:
+ case MONS_TROLL:
+ case MONS_TWO_HEADED_OGRE:
+ case MONS_ETTIN:
+ mlev += 3;
+ break;
+
+ case MONS_FUNGUS:
+ case MONS_GOBLIN:
+ case MONS_ORC:
+ default:
+ mlev += 0;
+ }
+
+ return (mlev);
+} // end mons_mineorc_level()
+
+static int mons_mineorc_rare(int mcls)
+{
+ switch (mcls)
+ {
+ case MONS_ORC:
+ return 300;
+
+ case MONS_GOBLIN:
+ case MONS_ORC_WARRIOR:
+ return 30;
+
+ case MONS_HOBGOBLIN:
+ case MONS_OGRE:
+ return 20;
+
+ case MONS_TROLL:
+ case MONS_WARG:
+ return 13;
+
+ case MONS_FUNGUS:
+ case MONS_ORC_KNIGHT:
+ case MONS_ORC_PRIEST:
+ case MONS_ORC_SORCERER:
+ case MONS_ORC_WIZARD:
+ return 10;
+
+ case MONS_ORC_WARLORD:
+ case MONS_ORC_HIGH_PRIEST:
+ case MONS_CYCLOPS:
+ case MONS_TWO_HEADED_OGRE:
+ return 5;
+
+ case MONS_ETTIN:
+ case MONS_IRON_TROLL:
+ case MONS_ROCK_TROLL:
+ case MONS_STONE_GIANT:
+ return 3;
+
+ case MONS_GNOLL:
+ return 2;
+
+ case MONS_OGRE_MAGE:
+ return 1;
+
+ default:
+ return 0;
+ }
+} // end mons_mineorc_rare()
+
+static int mons_hive_level(int mcls)
+{
+ int mlev = you.branch_stairs[STAIRS_HIVE] + 1;
+
+ switch (mcls)
+ {
+ case MONS_PLANT:
+ case MONS_KILLER_BEE:
+ mlev += 0;
+ break;
+
+ case MONS_KILLER_BEE_LARVA:
+ mlev += 2;
+ break;
+
+ default:
+ return 99;
+ }
+
+ return (mlev);
+} // end mons_hive_level()
+
+static int mons_hive_rare(int mcls)
+{
+ switch (mcls)
+ {
+ case MONS_KILLER_BEE:
+ return 300;
+
+ case MONS_PLANT:
+ return 100;
+
+ case MONS_KILLER_BEE_LARVA:
+ return 50;
+
+ default:
+ return 0;
+ }
+} // end mons_hive_rare()
+
+static int mons_lair_level(int mcls)
+{
+ int mlev = you.branch_stairs[STAIRS_LAIR] + 1;
+
+ switch (mcls)
+ {
+ case MONS_GIANT_GECKO:
+ case MONS_GIANT_BAT:
+ case MONS_JACKAL:
+ case MONS_GIANT_NEWT:
+ case MONS_RAT:
+ case MONS_QUOKKA:
+ mlev += 0;
+ break;
+
+ case MONS_GIANT_CENTIPEDE:
+ case MONS_GIANT_IGUANA:
+ mlev++;
+ break;
+
+ case MONS_GIANT_FROG:
+ case MONS_GILA_MONSTER:
+ case MONS_GREY_RAT:
+ case MONS_HOUND:
+ case MONS_BLACK_BEAR:
+ mlev += 2;
+ break;
+
+ case MONS_WORM:
+ case MONS_WOLF:
+ mlev += 3;
+ break;
+
+ case MONS_FUNGUS:
+ case MONS_GIANT_BROWN_FROG:
+ case MONS_GIANT_LIZARD:
+ case MONS_GIANT_MITE:
+ case MONS_GREEN_RAT:
+ case MONS_SCORPION:
+ case MONS_SNAKE:
+ mlev += 4;
+ break;
+
+ case MONS_BROWN_SNAKE:
+ case MONS_BUTTERFLY:
+ case MONS_GIANT_BEETLE:
+ case MONS_GIANT_SLUG:
+ case MONS_HIPPOGRIFF:
+ case MONS_PLANT:
+ case MONS_SPINY_FROG:
+ case MONS_WAR_DOG:
+ case MONS_YELLOW_WASP:
+ case MONS_BEAR:
+ mlev += 5;
+ break;
+
+ case MONS_BLINK_FROG:
+ case MONS_GIANT_SNAIL:
+ case MONS_GIANT_SPORE:
+ case MONS_KOMODO_DRAGON:
+ case MONS_ORANGE_RAT:
+ case MONS_SHEEP:
+ case MONS_STEAM_DRAGON:
+ case MONS_WOLF_SPIDER:
+ case MONS_YAK:
+ case MONS_GRIZZLY_BEAR:
+ mlev += 6;
+ break;
+
+ case MONS_BLACK_SNAKE:
+ case MONS_BRAIN_WORM:
+ case MONS_BUMBLEBEE:
+ case MONS_FIREDRAKE:
+ case MONS_HYDRA:
+ case MONS_OKLOB_PLANT:
+ case MONS_WYVERN:
+ mlev += 7;
+ break;
+
+ case MONS_ELEPHANT_SLUG:
+ case MONS_POLAR_BEAR:
+ case MONS_GRIFFON:
+ case MONS_LINDWURM:
+ case MONS_REDBACK:
+ case MONS_WANDERING_MUSHROOM:
+ mlev += 8;
+ break;
+
+ case MONS_BORING_BEETLE:
+ case MONS_BOULDER_BEETLE:
+ case MONS_DEATH_YAK:
+ case MONS_SPINY_WORM:
+ mlev += 9;
+ break;
+
+ default:
+ return 99;
+ }
+
+ return (mlev);
+} // end mons_lair_level()
+
+static int mons_lair_rare(int mcls)
+{
+ switch (mcls)
+ {
+ case MONS_RAT:
+ return 200;
+
+ case MONS_GIANT_BAT:
+ case MONS_GIANT_BROWN_FROG:
+ case MONS_GIANT_FROG:
+ case MONS_GREY_RAT:
+ case MONS_QUOKKA:
+ return 99;
+
+ case MONS_BROWN_SNAKE:
+ case MONS_GIANT_LIZARD:
+ return 90;
+
+ case MONS_PLANT:
+ case MONS_SNAKE:
+ return 80;
+
+ case MONS_SPINY_FROG:
+ return 75;
+
+ case MONS_JACKAL:
+ case MONS_GIANT_IGUANA:
+ case MONS_GILA_MONSTER:
+ return 70;
+
+ case MONS_GREEN_RAT:
+ return 64;
+
+ case MONS_HOUND:
+ return 60;
+
+ case MONS_GIANT_SNAIL:
+ return 56;
+
+ case MONS_GIANT_SLUG:
+ return 55;
+
+ case MONS_FUNGUS:
+ case MONS_GIANT_GECKO:
+ case MONS_GIANT_CENTIPEDE:
+ case MONS_HIPPOGRIFF:
+ case MONS_HYDRA:
+ case MONS_KOMODO_DRAGON:
+ case MONS_YAK:
+ return 50;
+
+ case MONS_BLACK_SNAKE:
+ return 47;
+
+ case MONS_BLINK_FROG:
+ return 45;
+
+ case MONS_SHEEP:
+ case MONS_FIREDRAKE:
+ return 36;
+
+ case MONS_WAR_DOG:
+ return 35;
+
+ case MONS_WORM:
+ case MONS_GIANT_MITE:
+ case MONS_GRIFFON:
+ case MONS_DEATH_YAK:
+ case MONS_ELEPHANT_SLUG:
+ return 30;
+
+ case MONS_BORING_BEETLE:
+ return 29;
+
+ case MONS_BOULDER_BEETLE:
+ case MONS_GIANT_NEWT:
+ case MONS_WOLF:
+ case MONS_WYVERN:
+ return 20;
+
+ case MONS_BLACK_BEAR:
+ case MONS_BEAR:
+ case MONS_GRIZZLY_BEAR:
+ case MONS_POLAR_BEAR:
+ return 15;
+
+ case MONS_GIANT_BEETLE:
+ case MONS_SCORPION:
+ case MONS_OKLOB_PLANT:
+ case MONS_STEAM_DRAGON:
+ case MONS_LINDWURM:
+ case MONS_ORANGE_RAT:
+ return 10;
+
+ case MONS_SPINY_WORM:
+ return 9;
+
+ case MONS_WANDERING_MUSHROOM:
+ case MONS_REDBACK:
+ return 8;
+
+ case MONS_BRAIN_WORM:
+ case MONS_BUMBLEBEE:
+ return 7;
+
+ case MONS_WOLF_SPIDER:
+ return 6;
+
+ case MONS_YELLOW_WASP:
+ case MONS_BUTTERFLY:
+ return 5;
+
+ case MONS_GIANT_SPORE:
+ return 2;
+
+ default:
+ return 0;
+ }
+} // end mons_lair_rare()
+
+static int mons_pitslime_level(int mcls)
+{
+ int mlev = you.branch_stairs[STAIRS_SLIME_PITS] + 1;
+
+
+ switch (mcls)
+ {
+ case MONS_JELLY:
+ case MONS_OOZE:
+ case MONS_ACID_BLOB:
+ case MONS_GIANT_SPORE:
+ case MONS_GIANT_EYEBALL:
+ mlev++;
+ break;
+
+ case MONS_BROWN_OOZE:
+ case MONS_SLIME_CREATURE:
+ case MONS_EYE_OF_DRAINING:
+ mlev += 2;
+ break;
+
+ case MONS_GIANT_AMOEBA:
+ case MONS_AZURE_JELLY:
+ case MONS_SHINING_EYE:
+ mlev += 3;
+ break;
+
+ case MONS_PULSATING_LUMP:
+ case MONS_GREAT_ORB_OF_EYES:
+ case MONS_EYE_OF_DEVASTATION:
+ mlev += 4;
+ break;
+
+ case MONS_DEATH_OOZE:
+ case MONS_TENTACLED_MONSTROSITY:
+ case MONS_GIANT_ORANGE_BRAIN:
+ mlev += 5;
+ break;
+
+ default:
+ mlev += 0;
+ break;
+ }
+
+ return (mlev);
+} // end mons_pitslime_level()
+
+static int mons_pitslime_rare(int mcls)
+{
+ switch (mcls)
+ {
+ case MONS_JELLY:
+ return 300;
+
+ case MONS_SLIME_CREATURE:
+ return 200;
+
+ case MONS_BROWN_OOZE:
+ return 150;
+
+ case MONS_GIANT_AMOEBA:
+ case MONS_ACID_BLOB:
+ return 100;
+
+ case MONS_OOZE:
+ case MONS_AZURE_JELLY:
+ case MONS_GIANT_SPORE:
+ case MONS_GIANT_EYEBALL:
+ case MONS_EYE_OF_DRAINING:
+ case MONS_SHINING_EYE:
+ return 50;
+
+ case MONS_DEATH_OOZE:
+ case MONS_GREAT_ORB_OF_EYES:
+ case MONS_EYE_OF_DEVASTATION:
+ return 30;
+
+ case MONS_PULSATING_LUMP:
+ case MONS_GIANT_ORANGE_BRAIN:
+ return 20;
+
+ case MONS_TENTACLED_MONSTROSITY:
+ return 2;
+
+ default:
+ return 0;
+ }
+} // end mons_pitslime_rare()
+
+static int mons_crypt_level(int mcls)
+{
+ int mlev = you.branch_stairs[STAIRS_CRYPT] + 1;
+
+ switch (mcls)
+ {
+ case MONS_ZOMBIE_SMALL:
+ mlev += 0;
+ break;
+
+ case MONS_PHANTOM:
+ case MONS_SKELETON_SMALL:
+ case MONS_SKELETON_LARGE:
+ case MONS_ZOMBIE_LARGE:
+ case MONS_WIGHT:
+ mlev++;
+ break;
+
+ case MONS_SHADOW:
+ case MONS_HUNGRY_GHOST:
+ case MONS_NECROPHAGE:
+ case MONS_SKELETAL_WARRIOR:
+ case MONS_SIMULACRUM_SMALL:
+ case MONS_SIMULACRUM_LARGE:
+ mlev += 2;
+ break;
+
+ case MONS_NECROMANCER:
+ case MONS_PULSATING_LUMP:
+ case MONS_FLAYED_GHOST:
+ case MONS_GHOUL:
+ case MONS_ROTTING_HULK:
+ case MONS_WRAITH:
+ case MONS_FLYING_SKULL:
+ mlev += 3;
+ break;
+
+ case MONS_SPECTRAL_WARRIOR:
+ case MONS_SHADOW_WRAITH:
+ case MONS_VAMPIRE_KNIGHT:
+ case MONS_VAMPIRE_MAGE:
+ case MONS_SKELETAL_DRAGON:
+ case MONS_ABOMINATION_SMALL:
+ case MONS_MUMMY:
+ case MONS_VAMPIRE:
+ case MONS_ABOMINATION_LARGE:
+ mlev += 4;
+ break;
+
+ case MONS_REAPER:
+ case MONS_ANCIENT_LICH:
+ case MONS_LICH:
+ mlev += 5;
+ break;
+
+ default:
+ mlev += 99;
+ }
+
+ return (mlev);
+} // end mons_crypt_level()
+
+static int mons_crypt_rare(int mcls)
+{
+ switch (mcls)
+ {
+ case MONS_ZOMBIE_SMALL:
+ case MONS_SKELETON_SMALL:
+ case MONS_SKELETON_LARGE:
+ return 410;
+
+ case MONS_ZOMBIE_LARGE:
+ return 300;
+
+ case MONS_SKELETAL_WARRIOR:
+ return 75;
+
+ case MONS_NECROPHAGE:
+ return 50;
+
+ case MONS_WIGHT:
+ return 35;
+
+ case MONS_WRAITH:
+ return 33;
+
+ case MONS_SHADOW:
+ return 30;
+
+ case MONS_NECROMANCER:
+ case MONS_GHOUL:
+ return 25;
+
+ case MONS_MUMMY:
+ case MONS_SKELETAL_DRAGON:
+ return 24;
+
+ case MONS_VAMPIRE:
+ case MONS_PHANTOM:
+ return 21;
+
+ case MONS_VAMPIRE_KNIGHT:
+ case MONS_VAMPIRE_MAGE:
+ return 20;
+
+ case MONS_ROTTING_HULK:
+ return 17;
+
+ case MONS_SPECTRAL_WARRIOR:
+ return 14;
+
+ case MONS_FLYING_SKULL:
+ case MONS_FLAYED_GHOST:
+ return 13;
+
+ case MONS_HUNGRY_GHOST:
+ return 12;
+
+ case MONS_SHADOW_WRAITH:
+ case MONS_SIMULACRUM_SMALL:
+ case MONS_SIMULACRUM_LARGE:
+ return 10;
+
+ case MONS_ANCIENT_LICH:
+ return 8;
+
+ case MONS_ABOMINATION_SMALL:
+ case MONS_LICH:
+ case MONS_REAPER:
+ return 5;
+
+ case MONS_ABOMINATION_LARGE:
+ return 4;
+
+ case MONS_PULSATING_LUMP:
+ return 3;
+
+ default:
+ return 0;
+ }
+} // end mons_crypt_rare()
+
+static int mons_pitsnake_level(int mcls)
+{
+ int mlev = you.branch_stairs[STAIRS_SNAKE_PIT] + 1;
+
+ switch (mcls)
+ {
+ case MONS_SMALL_SNAKE:
+ case MONS_SNAKE:
+ mlev++;
+ break;
+
+ case MONS_BROWN_SNAKE:
+ case MONS_BLACK_SNAKE:
+ case MONS_YELLOW_SNAKE:
+ case MONS_GREY_SNAKE:
+ case MONS_NAGA:
+ mlev += 2;
+ break;
+
+ case MONS_NAGA_WARRIOR:
+ case MONS_NAGA_MAGE:
+ mlev += 3;
+ break;
+
+ case MONS_GUARDIAN_NAGA:
+ mlev += 4;
+ break;
+
+ case MONS_GREATER_NAGA:
+ mlev += 5;
+ break;
+
+ default:
+ mlev += 99;
+ }
+
+ return (mlev);
+} // end mons_pitsnake_level()
+
+static int mons_pitsnake_rare(int mcls)
+{
+ switch (mcls)
+ {
+ case MONS_SNAKE:
+ case MONS_BROWN_SNAKE:
+ return 99;
+
+ case MONS_BLACK_SNAKE:
+ return 72;
+
+ case MONS_NAGA:
+ return 53;
+
+ case MONS_NAGA_WARRIOR:
+ case MONS_NAGA_MAGE:
+ return 34;
+
+ case MONS_YELLOW_SNAKE:
+ case MONS_GREY_SNAKE:
+ return 32;
+
+ case MONS_GREATER_NAGA:
+ case MONS_GUARDIAN_NAGA:
+ case MONS_SMALL_SNAKE:
+ return 15;
+
+ default:
+ return 0;
+ }
+} // end mons_pitsnake_rare()
+
+static int mons_hallelf_level(int mcls)
+{
+ int mlev = you.branch_stairs[STAIRS_ELVEN_HALLS] + 1;
+
+ switch (mcls)
+ {
+ case MONS_DEEP_ELF_SOLDIER:
+ case MONS_DEEP_ELF_FIGHTER:
+ case MONS_ORC:
+ case MONS_ORC_WARRIOR:
+ mlev++;
+ break;
+
+ case MONS_ORC_WIZARD:
+ case MONS_DEEP_ELF_MAGE:
+ case MONS_DEEP_ELF_SUMMONER:
+ mlev += 2;
+ break;
+
+ case MONS_FUNGUS:
+ case MONS_DEEP_ELF_CONJURER:
+ case MONS_SHAPESHIFTER:
+ case MONS_ORC_KNIGHT:
+ mlev += 3;
+ break;
+
+ case MONS_ORC_SORCERER:
+ case MONS_DEEP_ELF_PRIEST:
+ case MONS_GLOWING_SHAPESHIFTER:
+ case MONS_DEEP_ELF_KNIGHT:
+ mlev += 4;
+ break;
+
+ case MONS_ORC_PRIEST:
+ case MONS_ORC_HIGH_PRIEST:
+ mlev += 5;
+ break;
+
+ case MONS_DEEP_ELF_HIGH_PRIEST:
+ case MONS_DEEP_ELF_DEMONOLOGIST:
+ case MONS_DEEP_ELF_ANNIHILATOR:
+ case MONS_DEEP_ELF_SORCERER:
+ case MONS_DEEP_ELF_DEATH_MAGE:
+ mlev += 7;
+ break;
+
+ default:
+ mlev += 99;
+ break;
+ }
+
+ return (mlev);
+} // end mons_hallelf_level()
+
+static int mons_hallelf_rare(int mcls)
+{
+ switch (mcls)
+ {
+ case MONS_FUNGUS:
+ return 300;
+
+ case MONS_DEEP_ELF_SOLDIER:
+ case MONS_DEEP_ELF_FIGHTER:
+ case MONS_DEEP_ELF_MAGE:
+ return 100;
+
+ case MONS_DEEP_ELF_KNIGHT:
+ return 80;
+
+ case MONS_DEEP_ELF_SUMMONER:
+ return 72;
+
+ case MONS_DEEP_ELF_CONJURER:
+ return 63;
+
+ case MONS_DEEP_ELF_PRIEST:
+ return 44;
+
+ case MONS_SHAPESHIFTER:
+ return 25;
+
+ case MONS_ORC:
+ return 20;
+
+ case MONS_DEEP_ELF_DEMONOLOGIST:
+ case MONS_DEEP_ELF_SORCERER:
+ return 17;
+
+ case MONS_DEEP_ELF_ANNIHILATOR:
+ case MONS_DEEP_ELF_DEATH_MAGE:
+ case MONS_ORC_WIZARD:
+ return 13;
+
+ case MONS_ORC_WARRIOR:
+ return 11;
+
+ case MONS_DEEP_ELF_HIGH_PRIEST:
+ case MONS_ORC_SORCERER:
+ case MONS_GLOWING_SHAPESHIFTER:
+ return 10;
+
+ case MONS_ORC_KNIGHT:
+ case MONS_ORC_PRIEST:
+ case MONS_ORC_HIGH_PRIEST:
+ return 5;
+
+ default:
+ return 0;
+ }
+} // end mons_hallelf_rare()
+
+static int mons_tomb_level(int mcls)
+{
+ int mlev = you.branch_stairs[STAIRS_CRYPT] + 1;
+
+ switch (mcls)
+ {
+ case MONS_ZOMBIE_SMALL:
+ mlev += 0;
+ break;
+
+ case MONS_MUMMY:
+ case MONS_ZOMBIE_LARGE:
+ case MONS_SKELETON_SMALL:
+ case MONS_SKELETON_LARGE:
+ mlev++;
+ break;
+
+ case MONS_GUARDIAN_MUMMY:
+ case MONS_FLYING_SKULL:
+ case MONS_SIMULACRUM_SMALL:
+ case MONS_SIMULACRUM_LARGE:
+ mlev += 2;
+ break;
+
+ case MONS_LICH:
+ case MONS_ANCIENT_LICH:
+ case MONS_MUMMY_PRIEST:
+ mlev += 3;
+ break;
+
+ default:
+ mlev += 99;
+ }
+
+ return (mlev);
+} // end mons_tomb_level()
+
+static int mons_tomb_rare(int mcls)
+{
+ switch (mcls)
+ {
+ case MONS_MUMMY:
+ return 300;
+
+ case MONS_GUARDIAN_MUMMY:
+ return 202;
+
+ case MONS_MUMMY_PRIEST:
+ return 40;
+
+ case MONS_FLYING_SKULL:
+ return 33;
+
+ case MONS_ZOMBIE_LARGE:
+ case MONS_SKELETON_SMALL:
+ case MONS_SKELETON_LARGE:
+ return 21;
+
+ case MONS_ZOMBIE_SMALL:
+ return 20;
+
+ case MONS_SIMULACRUM_SMALL:
+ case MONS_SIMULACRUM_LARGE:
+ return 10;
+
+ case MONS_LICH:
+ return 4;
+
+ case MONS_ANCIENT_LICH:
+ return 2;
+
+ default:
+ return 0;
+ }
+} // end mons_tomb_rare()
+
+static int mons_swamp_level(int mcls)
+{
+ int mlev = you.branch_stairs[STAIRS_SWAMP] + 1;
+
+ switch (mcls)
+ {
+ case MONS_GIANT_BAT:
+ case MONS_GIANT_BLOWFLY:
+ case MONS_GIANT_FROG:
+ case MONS_GIANT_AMOEBA:
+ case MONS_GIANT_SLUG:
+ case MONS_GIANT_NEWT:
+ case MONS_GIANT_GECKO:
+ case MONS_RAT:
+ case MONS_SWAMP_DRAKE:
+ case MONS_WORM:
+ mlev++;
+ break;
+
+ case MONS_GIANT_BROWN_FROG:
+ case MONS_FUNGUS:
+ case MONS_NECROPHAGE:
+ case MONS_PLANT:
+ case MONS_SNAKE:
+ case MONS_BUTTERFLY:
+ case MONS_GIANT_LIZARD:
+ case MONS_GIANT_MOSQUITO:
+ case MONS_GIANT_SNAIL:
+ case MONS_HYDRA:
+ mlev += 2;
+ break;
+
+ case MONS_BROWN_SNAKE:
+ case MONS_HUNGRY_GHOST:
+ case MONS_INSUBSTANTIAL_WISP:
+ case MONS_JELLY:
+ case MONS_KOMODO_DRAGON:
+ case MONS_PHANTOM:
+ case MONS_RED_WASP:
+ case MONS_SPINY_FROG:
+ case MONS_SWAMP_DRAGON:
+ case MONS_UGLY_THING:
+ mlev += 3;
+ break;
+
+ case MONS_BLINK_FROG:
+ case MONS_SLIME_CREATURE:
+ case MONS_VERY_UGLY_THING:
+ case MONS_VAPOUR:
+ case MONS_TENTACLED_MONSTROSITY:
+ mlev += 4;
+ break;
+
+ default:
+ mlev += 99;
+ }
+
+ return (mlev);
+} // end mons_swamp_level()
+
+static int mons_swamp_rare(int mcls)
+{
+ switch (mcls)
+ {
+ case MONS_GIANT_MOSQUITO:
+ return 250;
+
+ case MONS_PLANT:
+ return 200;
+
+ case MONS_GIANT_FROG:
+ return 150;
+
+ case MONS_GIANT_BLOWFLY:
+ return 100;
+
+ case MONS_GIANT_BAT:
+ case MONS_FUNGUS:
+ return 99;
+
+ case MONS_GIANT_BROWN_FROG:
+ return 90;
+
+ case MONS_SWAMP_DRAKE:
+ return 80;
+
+ case MONS_HYDRA:
+ return 70;
+
+ case MONS_RAT:
+ return 61;
+
+ case MONS_SLIME_CREATURE:
+ return 54;
+
+ case MONS_SNAKE:
+ return 52;
+
+ case MONS_INSUBSTANTIAL_WISP:
+ return 43;
+
+ case MONS_BROWN_SNAKE:
+ return 33;
+
+ case MONS_RED_WASP:
+ case MONS_SWAMP_DRAGON:
+ case MONS_SPINY_FROG:
+ return 30;
+
+ case MONS_JELLY:
+ case MONS_BUTTERFLY:
+ case MONS_GIANT_LIZARD:
+ return 25;
+
+ case MONS_WORM:
+ return 20;
+
+ case MONS_KOMODO_DRAGON:
+ case MONS_VERY_UGLY_THING:
+ case MONS_VAPOUR:
+ return 15;
+
+ case MONS_PHANTOM:
+ case MONS_UGLY_THING:
+ case MONS_HUNGRY_GHOST:
+ return 13;
+
+ case MONS_NECROPHAGE:
+ return 12;
+
+ case MONS_BLINK_FROG:
+ case MONS_GIANT_AMOEBA:
+ case MONS_GIANT_GECKO:
+ case MONS_GIANT_NEWT:
+ case MONS_GIANT_SLUG:
+ case MONS_GIANT_SNAIL:
+ return 10;
+
+ case MONS_TENTACLED_MONSTROSITY:
+ return 5;
+
+ default:
+ return 0;
+ }
+} // end mons_swamp_rare()
+
+static int mons_hallblade_level(int mcls)
+{
+ if (mcls == MONS_DANCING_WEAPON)
+ return (you.branch_stairs[STAIRS_HALL_OF_BLADES] + 1);
+ else
+ return 0;
+} // end mons_hallblade_level
+
+static int mons_hallblade_rare(int mcls)
+{
+ return ((mcls == MONS_DANCING_WEAPON) ? 1000 : 0);
+} // end mons_hallblade_rare()
+
+// New branch must be added in:
+// - new_game stair location
+// - down/up stairs (to and back) misc.cc
+// - new_level (2 places) (misc.cc)
+// - item_check items.cc
+// - look_around (direct.cc)
+// - ouch ouch.cc (death message)
+// - and here...
+
+static int mons_hallzot_level(int mcls)
+{
+ int mlev = you.branch_stairs[STAIRS_HALL_OF_ZOT];
+
+ switch (mcls)
+ {
+ case MONS_GOLDEN_DRAGON:
+ case MONS_GUARDIAN_MUMMY:
+ mlev += 6;
+ break;
+ case MONS_KILLER_KLOWN:
+ case MONS_SHADOW_DRAGON:
+ case MONS_SKELETAL_DRAGON:
+ case MONS_STORM_DRAGON:
+ mlev += 5;
+ break;
+ case MONS_DEATH_COB:
+ case MONS_DRAGON:
+ case MONS_ICE_DRAGON:
+ mlev += 4;
+ break;
+ case MONS_DEEP_ELF_ANNIHILATOR:
+ case MONS_DEEP_ELF_DEATH_MAGE:
+ case MONS_DEEP_ELF_DEMONOLOGIST:
+ case MONS_DEEP_ELF_HIGH_PRIEST:
+ case MONS_DEEP_ELF_SORCERER:
+ case MONS_TENTACLED_MONSTROSITY:
+ mlev += 3;
+ break;
+ case MONS_MOTH_OF_WRATH:
+ mlev += 2;
+ break;
+ case MONS_ORB_OF_FIRE:
+ case MONS_ELECTRIC_GOLEM:
+ mlev += 1;
+ break;
+ default:
+ mlev += 99; // I think this won't be a problem {dlb}
+ break;
+ }
+
+ return (mlev);
+} // end mons_hallzot_level()
+
+static int mons_hallzot_rare(int mcls)
+{
+ switch (mcls)
+ {
+ case MONS_MOTH_OF_WRATH:
+ return 88;
+ case MONS_STORM_DRAGON:
+ case MONS_TENTACLED_MONSTROSITY:
+ return 50;
+ case MONS_GOLDEN_DRAGON:
+ return 42;
+ case MONS_DEATH_COB:
+ case MONS_DRAGON:
+ case MONS_ICE_DRAGON:
+ case MONS_SKELETAL_DRAGON:
+ return 40;
+ case MONS_SHADOW_DRAGON:
+ return 30;
+ case MONS_DEEP_ELF_ANNIHILATOR:
+ case MONS_DEEP_ELF_DEATH_MAGE:
+ case MONS_DEEP_ELF_DEMONOLOGIST:
+ case MONS_DEEP_ELF_HIGH_PRIEST:
+ case MONS_DEEP_ELF_SORCERER:
+ return 29;
+ case MONS_GUARDIAN_MUMMY:
+ case MONS_ELECTRIC_GOLEM:
+ return 20;
+ case MONS_KILLER_KLOWN:
+ case MONS_ORB_OF_FIRE:
+ return 15;
+ default:
+ return 0;
+ }
+} // end mons_hallzot_rare()
+
+static int mons_standard_level(int mcls)
+{
+ switch (mcls)
+ {
+ case MONS_GOBLIN:
+ case MONS_GIANT_NEWT:
+ return 1;
+
+ case MONS_GIANT_COCKROACH:
+ case MONS_OOZE:
+ case MONS_SMALL_SNAKE:
+ return 2;
+
+ case MONS_GIANT_BAT:
+ case MONS_KOBOLD:
+ case MONS_RAT:
+ return 4;
+
+ case MONS_GIANT_GECKO:
+ case MONS_GIANT_MITE:
+ case MONS_GNOLL:
+ case MONS_HOBGOBLIN:
+ case MONS_JACKAL:
+ case MONS_KILLER_BEE_LARVA:
+ return 5;
+
+ case MONS_WORM:
+ case MONS_SNAKE:
+ case MONS_QUOKKA:
+ return 6;
+
+ case MONS_ORC:
+ return 7;
+
+ case MONS_FUNGUS:
+ case MONS_GIANT_ANT:
+ case MONS_GIANT_EYEBALL:
+ case MONS_HOUND:
+ case MONS_GIANT_IGUANA:
+ case MONS_OGRE:
+ case MONS_ORC_WIZARD:
+ case MONS_PHANTOM:
+ case MONS_SCORPION:
+ return 8;
+
+ case MONS_BROWN_SNAKE:
+ case MONS_CENTAUR:
+ case MONS_ICE_BEAST:
+ case MONS_IMP:
+ case MONS_JELLY:
+ case MONS_NECROPHAGE:
+ case MONS_QUASIT:
+ case MONS_ZOMBIE_SMALL:
+ return 9;
+
+ case MONS_DEEP_ELF_SOLDIER:
+ case MONS_GIANT_BEETLE:
+ case MONS_GIANT_FROG:
+ case MONS_GIANT_SPORE:
+ case MONS_MUMMY:
+ case MONS_ORC_WARRIOR:
+ case MONS_STEAM_DRAGON:
+ case MONS_WIGHT:
+ return 10;
+
+ case MONS_GIANT_LIZARD:
+ case MONS_HIPPOGRIFF:
+ case MONS_HUNGRY_GHOST:
+ case MONS_KILLER_BEE:
+ case MONS_SHADOW:
+ case MONS_YELLOW_WASP:
+ return 11;
+
+ case MONS_EYE_OF_DRAINING:
+ case MONS_GILA_MONSTER:
+ case MONS_MANTICORE:
+ case MONS_PLANT:
+ case MONS_UNSEEN_HORROR:
+ case MONS_WYVERN:
+ return 12;
+
+ case MONS_BIG_KOBOLD:
+ case MONS_GIANT_BROWN_FROG:
+ case MONS_GIANT_CENTIPEDE:
+ case MONS_OKLOB_PLANT:
+ case MONS_TROLL:
+ case MONS_TWO_HEADED_OGRE:
+ case MONS_WOOD_GOLEM:
+ case MONS_YAK:
+ return 13;
+
+ case MONS_HILL_GIANT:
+ case MONS_KOMODO_DRAGON:
+ case MONS_SOLDIER_ANT:
+ case MONS_WOLF_SPIDER:
+ case MONS_WRAITH:
+ return 14;
+
+ case MONS_ARMOUR_MIMIC:
+ case MONS_BRAIN_WORM:
+ case MONS_CYCLOPS:
+ case MONS_EFREET:
+ case MONS_ETTIN:
+ case MONS_EYE_OF_DEVASTATION:
+ case MONS_GOLD_MIMIC:
+ case MONS_HYDRA:
+ case MONS_MOTTLED_DRAGON:
+ case MONS_ORC_PRIEST:
+ case MONS_POTION_MIMIC:
+ case MONS_SCROLL_MIMIC:
+ case MONS_SKELETAL_WARRIOR:
+ case MONS_WEAPON_MIMIC:
+ return 15;
+
+ case MONS_BLINK_FROG:
+ case MONS_BUTTERFLY:
+ case MONS_GIANT_BLOWFLY:
+ case MONS_GUARDIAN_NAGA:
+ case MONS_RAKSHASA:
+ case MONS_SLIME_CREATURE:
+ case MONS_STONE_GOLEM:
+ case MONS_VAMPIRE:
+ case MONS_WANDERING_MUSHROOM:
+ case MONS_ZOMBIE_LARGE:
+ return 16;
+
+ case MONS_BOGGART:
+ case MONS_CENTAUR_WARRIOR:
+ case MONS_CLAY_GOLEM:
+ case MONS_GRIFFON:
+ case MONS_SHAPESHIFTER:
+ case MONS_UGLY_THING:
+ case MONS_WIZARD:
+ case MONS_SIMULACRUM_SMALL:
+ case MONS_SIMULACRUM_LARGE:
+ return 17;
+
+ case MONS_DRAGON:
+ case MONS_GARGOYLE:
+ case MONS_GIANT_AMOEBA:
+ case MONS_KOBOLD_DEMONOLOGIST:
+ return 18;
+
+ case MONS_GIANT_SLUG:
+ case MONS_IRON_GOLEM:
+ case MONS_OGRE_MAGE:
+ case MONS_ROCK_TROLL:
+ case MONS_TOENAIL_GOLEM:
+ case MONS_YAKTAUR:
+ return 19;
+
+ case MONS_AIR_ELEMENTAL:
+ case MONS_DEEP_ELF_FIGHTER:
+ case MONS_DEEP_ELF_KNIGHT:
+ case MONS_DEEP_ELF_MAGE:
+ case MONS_DEEP_ELF_SUMMONER:
+ case MONS_EARTH_ELEMENTAL:
+ case MONS_FIRE_ELEMENTAL:
+ case MONS_GIANT_ORANGE_BRAIN:
+ case MONS_GIANT_SNAIL:
+ case MONS_GREAT_ORB_OF_EYES:
+ case MONS_ICE_DRAGON:
+ case MONS_SKELETON_LARGE:
+ case MONS_NAGA_MAGE:
+ case MONS_NAGA_WARRIOR:
+ case MONS_NECROMANCER:
+ case MONS_ORC_KNIGHT:
+ case MONS_QUEEN_BEE:
+ case MONS_RED_WASP:
+ case MONS_SHADOW_WRAITH:
+ case MONS_SKELETON_SMALL:
+ case MONS_SPINY_WORM:
+ case MONS_VERY_UGLY_THING:
+ return 20;
+
+ case MONS_BOULDER_BEETLE:
+ case MONS_ORC_HIGH_PRIEST:
+ case MONS_PULSATING_LUMP:
+ return 21;
+
+ case MONS_BORING_BEETLE:
+ case MONS_CRYSTAL_GOLEM:
+ case MONS_FLAYED_GHOST:
+ case MONS_FREEZING_WRAITH:
+ case MONS_REDBACK:
+ case MONS_SPHINX:
+ case MONS_VAPOUR:
+ return 22;
+
+ case MONS_ORC_SORCERER:
+ case MONS_SHINING_EYE:
+ return 23;
+
+ case MONS_BUMBLEBEE:
+ case MONS_ORC_WARLORD:
+ case MONS_IRON_TROLL:
+ case MONS_YAKTAUR_CAPTAIN:
+ return 24;
+
+ case MONS_DANCING_WEAPON:
+ case MONS_DEEP_TROLL:
+ case MONS_FIRE_GIANT:
+ case MONS_FROST_GIANT:
+ case MONS_HELL_KNIGHT:
+ case MONS_INSUBSTANTIAL_WISP:
+ case MONS_LICH:
+ case MONS_STONE_GIANT:
+ return 25;
+
+ case MONS_DEEP_ELF_CONJURER:
+ case MONS_SPECTRAL_WARRIOR:
+ case MONS_STORM_DRAGON:
+ return 26;
+
+ case MONS_DEEP_ELF_PRIEST:
+ case MONS_GLOWING_SHAPESHIFTER:
+ case MONS_TENTACLED_MONSTROSITY:
+ return 27;
+
+ case MONS_ANCIENT_LICH:
+ case MONS_DEEP_ELF_ANNIHILATOR:
+ case MONS_DEEP_ELF_DEATH_MAGE:
+ case MONS_DEEP_ELF_DEMONOLOGIST:
+ case MONS_DEEP_ELF_HIGH_PRIEST:
+ case MONS_DEEP_ELF_SORCERER:
+ case MONS_GOLDEN_DRAGON:
+ case MONS_IRON_DRAGON:
+ case MONS_QUICKSILVER_DRAGON:
+ case MONS_SHADOW_DRAGON:
+ case MONS_SKELETAL_DRAGON:
+ case MONS_TITAN:
+ return 30;
+
+ case MONS_BIG_FISH:
+ case MONS_ELECTRICAL_EEL:
+ case MONS_GIANT_GOLDFISH:
+ case MONS_JELLYFISH:
+ case MONS_LAVA_FISH:
+ case MONS_LAVA_SNAKE:
+ case MONS_LAVA_WORM:
+ case MONS_SWAMP_WORM:
+ case MONS_WATER_ELEMENTAL:
+ return 500;
+
+ default:
+ return 99;
+ }
+} // end mons_standard_level()
+
+static int mons_standard_rare(int mcls)
+{
+ switch (mcls)
+ {
+// "another lava thing" has no stats! (GDL)
+// case MONS_ANOTHER_LAVA_THING:
+ case MONS_BIG_FISH:
+ case MONS_ELECTRICAL_EEL:
+ case MONS_GIANT_GOLDFISH:
+ case MONS_JELLYFISH:
+ case MONS_LAVA_FISH:
+ case MONS_LAVA_SNAKE:
+ case MONS_LAVA_WORM:
+ case MONS_SWAMP_WORM:
+ case MONS_WATER_ELEMENTAL:
+ case MONS_SALAMANDER:
+ return 500;
+
+ case MONS_GIANT_BAT:
+ case MONS_GIANT_FROG:
+ case MONS_GOBLIN:
+ case MONS_HILL_GIANT:
+ case MONS_HOBGOBLIN:
+ case MONS_IMP:
+ case MONS_KOBOLD:
+ case MONS_SKELETON_LARGE:
+ case MONS_ORC:
+ case MONS_RAT:
+ case MONS_RED_DEVIL:
+ case MONS_SKELETON_SMALL:
+ case MONS_UGLY_THING:
+ case MONS_ZOMBIE_LARGE:
+ case MONS_ZOMBIE_SMALL:
+ return 99;
+
+ case MONS_CENTAUR_WARRIOR:
+ case MONS_GIANT_ANT:
+ case MONS_SNAKE:
+ return 80;
+
+ case MONS_FLYING_SKULL:
+ case MONS_SLIME_CREATURE:
+ return 75;
+
+ case MONS_HELL_HOUND:
+ return 71;
+
+ case MONS_CENTAUR:
+ case MONS_CYCLOPS:
+ case MONS_GIANT_BROWN_FROG:
+ case MONS_HELLION:
+ case MONS_HOUND:
+ case MONS_OGRE:
+ case MONS_ORC_WARRIOR:
+ case MONS_TROLL:
+ case MONS_YAK:
+ case MONS_YAKTAUR_CAPTAIN:
+ return 70;
+
+ case MONS_JELLY:
+ case MONS_ORC_KNIGHT:
+ case MONS_ROTTING_DEVIL:
+ return 60;
+
+ case MONS_SHAPESHIFTER:
+ return 59;
+
+ case MONS_STONE_GIANT:
+ return 53;
+
+ case MONS_BIG_KOBOLD:
+ case MONS_GIANT_BEETLE:
+ case MONS_GIANT_BLOWFLY:
+ case MONS_GIANT_COCKROACH:
+ case MONS_GIANT_GECKO:
+ case MONS_GIANT_IGUANA:
+ case MONS_GIANT_NEWT:
+ case MONS_HIPPOGRIFF:
+ case MONS_HYDRA:
+ case MONS_ICE_BEAST:
+ case MONS_KILLER_BEE:
+ case MONS_ORC_WIZARD:
+ case MONS_QUOKKA:
+ case MONS_SCORPION:
+ case MONS_TORMENTOR:
+ case MONS_UNSEEN_HORROR:
+ case MONS_WORM:
+ return 50;
+
+ case MONS_ROCK_TROLL:
+ return 48;
+
+ case MONS_MANTICORE:
+ case MONS_OGRE_MAGE:
+ return 45;
+
+ case MONS_HUNGRY_GHOST:
+ case MONS_SHADOW:
+ return 41;
+
+ case MONS_GIANT_CENTIPEDE:
+ case MONS_GIANT_EYEBALL:
+ case MONS_GIANT_SPORE:
+ case MONS_GRIFFON:
+ case MONS_HAIRY_DEVIL:
+ case MONS_JACKAL:
+ case MONS_MOTTLED_DRAGON:
+ case MONS_PHANTOM:
+ case MONS_REAPER:
+ case MONS_TWO_HEADED_OGRE:
+ case MONS_WIGHT:
+ case MONS_WRAITH:
+ case MONS_WYVERN:
+ case MONS_YAKTAUR:
+ return 40;
+
+ case MONS_WOLF_SPIDER:
+ return 36;
+
+ case MONS_FREEZING_WRAITH:
+ case MONS_GIANT_AMOEBA:
+ case MONS_GILA_MONSTER:
+ case MONS_GLOWING_SHAPESHIFTER:
+ case MONS_SOLDIER_ANT:
+ return 35;
+
+ case MONS_BOULDER_BEETLE:
+ return 34;
+
+ case MONS_EYE_OF_DRAINING:
+ return 33;
+
+ case MONS_GIANT_SLUG:
+ return 32;
+
+ case MONS_ARMOUR_MIMIC:
+ case MONS_BROWN_SNAKE:
+ case MONS_DRAGON:
+ case MONS_ETTIN:
+ case MONS_FIRE_VORTEX:
+ case MONS_GIANT_LIZARD:
+ case MONS_GIANT_MITE:
+ case MONS_GNOLL:
+ case MONS_GOLD_MIMIC:
+ case MONS_KOMODO_DRAGON:
+ case MONS_MUMMY:
+ case MONS_NECROPHAGE:
+ case MONS_POTION_MIMIC:
+ case MONS_SCROLL_MIMIC:
+ case MONS_SKELETAL_WARRIOR:
+ case MONS_SMALL_SNAKE:
+ case MONS_SOUL_EATER:
+ case MONS_SPINY_WORM:
+ case MONS_VAMPIRE:
+ case MONS_WEAPON_MIMIC:
+ case MONS_YELLOW_WASP:
+ return 30;
+
+ case MONS_FLAYED_GHOST:
+ return 29;
+
+ case MONS_BRAIN_WORM:
+ return 26;
+
+ case MONS_BOGGART:
+ case MONS_DEEP_ELF_FIGHTER:
+ case MONS_DEEP_ELF_KNIGHT:
+ case MONS_DEEP_TROLL:
+ case MONS_FIRE_GIANT:
+ case MONS_FROST_GIANT:
+ case MONS_GREAT_ORB_OF_EYES:
+ case MONS_IRON_TROLL:
+ case MONS_OOZE:
+ case MONS_ORC_PRIEST:
+ case MONS_PLANT:
+ case MONS_RED_WASP:
+ case MONS_SIMULACRUM_SMALL:
+ case MONS_SIMULACRUM_LARGE:
+ return 25;
+
+ case MONS_BUTTERFLY:
+ case MONS_FUNGUS:
+ case MONS_GIANT_SNAIL:
+ case MONS_ICE_DRAGON:
+ case MONS_INSUBSTANTIAL_WISP:
+ case MONS_RAKSHASA:
+ case MONS_REDBACK:
+ case MONS_SHADOW_DRAGON:
+ case MONS_SPECTRAL_WARRIOR:
+ case MONS_SPHINX:
+ case MONS_STEAM_DRAGON:
+ case MONS_STORM_DRAGON:
+ case MONS_VERY_UGLY_THING:
+ case MONS_WIZARD:
+ return 20;
+
+ case MONS_BORING_BEETLE:
+ case MONS_LICH:
+ case MONS_TENTACLED_MONSTROSITY:
+ return 17;
+
+ case MONS_BLINK_FROG:
+ case MONS_CLAY_GOLEM:
+ case MONS_EFREET:
+ case MONS_EYE_OF_DEVASTATION:
+ case MONS_NECROMANCER:
+ case MONS_WOOD_GOLEM:
+ return 15;
+
+ case MONS_KOBOLD_DEMONOLOGIST:
+ return 13;
+
+ case MONS_BUMBLEBEE:
+ case MONS_ORC_HIGH_PRIEST:
+ return 12;
+
+ case MONS_DEEP_ELF_SOLDIER:
+ case MONS_GIANT_ORANGE_BRAIN:
+ case MONS_HELL_KNIGHT:
+ case MONS_IRON_GOLEM:
+ case MONS_OKLOB_PLANT:
+ case MONS_ORC_SORCERER:
+ case MONS_SHADOW_WRAITH:
+ case MONS_STONE_GOLEM:
+ case MONS_TITAN:
+ case MONS_WANDERING_MUSHROOM:
+ return 10;
+
+ case MONS_GOLDEN_DRAGON:
+ case MONS_ORC_WARLORD:
+ return 7;
+
+ case MONS_GARGOYLE:
+ return 6;
+
+ case MONS_CRYSTAL_GOLEM:
+ case MONS_DANCING_WEAPON:
+ case MONS_DEEP_ELF_HIGH_PRIEST:
+ case MONS_DEEP_ELF_MAGE:
+ case MONS_DEEP_ELF_SUMMONER:
+ case MONS_IRON_DRAGON:
+ case MONS_NAGA_MAGE:
+ case MONS_NAGA_WARRIOR:
+ case MONS_SKELETAL_DRAGON:
+ case MONS_QUICKSILVER_DRAGON:
+ case MONS_VAPOUR:
+ return 5;
+
+ case MONS_AIR_ELEMENTAL:
+ case MONS_DEEP_ELF_CONJURER:
+ case MONS_EARTH_ELEMENTAL:
+ case MONS_FIRE_ELEMENTAL:
+ return 4;
+
+ case MONS_ANCIENT_LICH:
+ case MONS_DEEP_ELF_ANNIHILATOR:
+ case MONS_DEEP_ELF_DEATH_MAGE:
+ case MONS_DEEP_ELF_DEMONOLOGIST:
+ case MONS_DEEP_ELF_PRIEST:
+ case MONS_DEEP_ELF_SORCERER:
+ case MONS_GUARDIAN_NAGA:
+ return 3;
+
+ case MONS_PULSATING_LUMP:
+ case MONS_SHINING_EYE:
+ case MONS_TOENAIL_GOLEM:
+ return 2;
+
+ default:
+ return 0;
+ }
+} // end mons_standard_rare()
diff --git a/trunk/source/mon-pick.h b/trunk/source/mon-pick.h
new file mode 100644
index 0000000000..79312e6043
--- /dev/null
+++ b/trunk/source/mon-pick.h
@@ -0,0 +1,58 @@
+/*
+ * File: mon-pick.h
+ * Summary: Functions used to help determine which monsters should appear.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef MONPICK_H
+#define MONPICK_H
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: dungeon - fight
+ * *********************************************************************** */
+int mons_rarity(int mcls);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: dungeon
+ * *********************************************************************** */
+int mons_level(int mcls);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: dungeon - mon-pick
+ * *********************************************************************** */
+bool mons_abyss(int mcls);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: dungeon - mon-pick
+ * *********************************************************************** */
+int mons_rare_abyss(int mcls);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: dungeon - spells3
+ * *********************************************************************** */
+int branch_depth(int branch);
+
+
+// last updated 10jun2000 {dlb}
+/* ***********************************************************************
+ * called from: levels - mon-pick
+ * *********************************************************************** */
+bool mons_pan(int mcls);
+
+
+#endif
diff --git a/trunk/source/mon-spll.h b/trunk/source/mon-spll.h
new file mode 100644
index 0000000000..4799b4e2db
--- /dev/null
+++ b/trunk/source/mon-spll.h
@@ -0,0 +1,734 @@
+#ifndef MON_SPLL_H
+#define MON_SPLL_H
+
+
+/* *********************************************************************
+
+ this will do as long as ( 0 >= (template/sec numbers) <= 255 )
+
+ !!!NOTE!!! for simplicity, these templates assume that most monsters
+ capable of casting more powerful summonings can also cast Abjuration.
+
+ Template Format:
+
+ { WHICH TEMPLATE,
+ bolt spell,
+ enchantment,
+ self-enchantment, // 50% tried after others fail
+ misc(1) spell,
+ misc(2) spell, // MS_DIG must be here to work!
+ emergency spell // only when fleeing
+ }
+
+ see: mon-util::mons_spell_list() and
+ monstuff::handle_spell() for usage details.
+
+********************************************************************* */
+
+
+ { MST_ORC_WIZARD_I,
+ MS_MMISSILE,
+ MS_SLOW,
+ MS_HASTE,
+ MS_MMISSILE,
+ MS_BLINK,
+ MS_BLINK },
+
+ { MST_ORC_WIZARD_II,
+ MS_FLAME,
+ MS_CONFUSE,
+ MS_INVIS,
+ MS_MMISSILE,
+ MS_NO_SPELL,
+ MS_CONFUSE },
+
+ { MST_ORC_WIZARD_III,
+ MS_FROST,
+ MS_CANTRIP,
+ MS_HASTE,
+ MS_FLAME,
+ MS_MMISSILE,
+ MS_INVIS },
+
+ { MST_GUARDIAN_NAGA,
+ MS_TELEPORT_OTHER,
+ MS_TELEPORT_OTHER,
+ MS_HEAL,
+ MS_VENOM_BOLT,
+ MS_SLOW,
+ MS_HEAL },
+
+ { MST_LICH_I,
+ MS_COLD_BOLT,
+ MS_PARALYSIS,
+ MS_SUMMON_DEMON_GREATER,
+ MS_ANIMATE_DEAD,
+ MS_IRON_BOLT,
+ MS_TELEPORT },
+
+ { MST_LICH_II,
+ MS_FIRE_BOLT,
+ MS_CONFUSE,
+ MS_HASTE,
+ MS_NEGATIVE_BOLT,
+ MS_SUMMON_DEMON_GREATER,
+ MS_BANISHMENT },
+
+ { MST_LICH_III,
+ MS_NEGATIVE_BOLT,
+ MS_ANIMATE_DEAD,
+ MS_SUMMON_UNDEAD,
+ MS_FROST,
+ MS_CRYSTAL_SPEAR,
+ MS_SUMMON_UNDEAD },
+
+ { MST_LICH_IV,
+ MS_ORB_ENERGY,
+ MS_COLD_BOLT,
+ MS_INVIS,
+ MS_ANIMATE_DEAD,
+ MS_IRON_BOLT,
+ MS_INVIS },
+
+ { MST_BURNING_DEVIL,
+ MS_HELLFIRE_BURST,
+ MS_HELLFIRE_BURST,
+ MS_NO_SPELL,
+ MS_HELLFIRE_BURST,
+ MS_HELLFIRE_BURST,
+ MS_HELLFIRE_BURST },
+
+ { MST_VAMPIRE,
+ MS_VAMPIRE_SUMMON,
+ MS_CONFUSE,
+ MS_INVIS,
+ MS_NO_SPELL,
+ MS_VAMPIRE_SUMMON,
+ MS_VAMPIRE_SUMMON },
+
+ { MST_VAMPIRE_KNIGHT,
+ MS_VAMPIRE_SUMMON,
+ MS_PARALYSIS,
+ MS_HASTE,
+ MS_INVIS,
+ MS_VAMPIRE_SUMMON,
+ MS_HEAL },
+
+ { MST_VAMPIRE_MAGE,
+ MS_NEGATIVE_BOLT,
+ MS_SUMMON_UNDEAD,
+ MS_INVIS,
+ MS_ANIMATE_DEAD,
+ MS_ANIMATE_DEAD,
+ MS_TELEPORT },
+
+ { MST_EFREET,
+ MS_FIRE_BOLT,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_FIREBALL,
+ MS_NO_SPELL,
+ MS_NO_SPELL },
+
+ { MST_BRAIN_WORM,
+ MS_BRAIN_FEED,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_BRAIN_FEED,
+ MS_NO_SPELL,
+ MS_NO_SPELL },
+
+ { MST_GIANT_ORANGE_BRAIN,
+ MS_BRAIN_FEED,
+ MS_MUTATION,
+ MS_LEVEL_SUMMON,
+ MS_CONFUSE,
+ MS_BLINK,
+ MS_TELEPORT },
+
+ { MST_RAKSHASA,
+ MS_FAKE_RAKSHASA_SUMMON,
+ MS_BLINK,
+ MS_INVIS,
+ MS_FAKE_RAKSHASA_SUMMON,
+ MS_BLINK,
+ MS_TELEPORT },
+
+ { MST_GREAT_ORB_OF_EYES,
+ MS_PARALYSIS,
+ MS_DISINTEGRATE,
+ MS_NO_SPELL,
+ MS_SLOW,
+ MS_CONFUSE,
+ MS_TELEPORT_OTHER },
+
+ { MST_ORC_SORCERER,
+ MS_FIRE_BOLT,
+ MS_NEGATIVE_BOLT,
+ MS_SUMMON_DEMON,
+ MS_PARALYSIS,
+ MS_ANIMATE_DEAD,
+ MS_TELEPORT },
+
+ { MST_STEAM_DRAGON,
+ MS_STEAM_BALL,
+ MS_STEAM_BALL,
+ MS_NO_SPELL,
+ MS_STEAM_BALL,
+ MS_STEAM_BALL,
+ MS_NO_SPELL },
+
+ { MST_HELL_KNIGHT_I,
+ MS_NO_SPELL,
+ MS_PAIN,
+ MS_HASTE,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_HASTE },
+
+ { MST_HELL_KNIGHT_II,
+ MS_NO_SPELL,
+ MS_FIRE_BOLT,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_BLINK },
+
+ { MST_NECROMANCER_I,
+ MS_COLD_BOLT,
+ MS_NEGATIVE_BOLT,
+ MS_NO_SPELL,
+ MS_ANIMATE_DEAD,
+ MS_ANIMATE_DEAD,
+ MS_TELEPORT },
+
+ { MST_NECROMANCER_II,
+ MS_FIRE_BOLT,
+ MS_PAIN,
+ MS_INVIS,
+ MS_ANIMATE_DEAD,
+ MS_ANIMATE_DEAD,
+ MS_BLINK },
+
+ { MST_WIZARD_I,
+ MS_MMISSILE,
+ MS_PARALYSIS,
+ MS_HASTE,
+ MS_LIGHTNING_BOLT,
+ MS_CONFUSE,
+ MS_TELEPORT },
+
+ { MST_WIZARD_II,
+ MS_VENOM_BOLT,
+ MS_ORB_ENERGY,
+ MS_INVIS,
+ MS_CONFUSE,
+ MS_SLOW,
+ MS_TELEPORT },
+
+ { MST_WIZARD_III,
+ MS_PARALYSIS,
+ MS_CRYSTAL_SPEAR,
+ MS_BLINK,
+ MS_FIRE_BOLT,
+ MS_COLD_BOLT,
+ MS_HEAL },
+
+ { MST_WIZARD_IV,
+ MS_STONE_ARROW,
+ MS_STING,
+ MS_BLINK,
+ MS_LIGHTNING_BOLT,
+ MS_BANISHMENT,
+ MS_HEAL },
+
+ { MST_WIZARD_V,
+ MS_PARALYSIS,
+ MS_FLAME,
+ MS_INVIS,
+ MS_TELEPORT_OTHER,
+ MS_FIREBALL,
+ MS_TELEPORT_OTHER },
+
+ { MST_ORC_PRIEST,
+ MS_PAIN,
+ MS_NO_SPELL,
+ MS_CANTRIP,
+ MS_SMITE,
+ MS_NO_SPELL,
+ MS_HEAL },
+
+ { MST_ORC_HIGH_PRIEST,
+ MS_PAIN,
+ MS_SUMMON_DEMON,
+ MS_SUMMON_DEMON,
+ MS_SMITE,
+ MS_ANIMATE_DEAD,
+ MS_HEAL },
+
+ { MST_MOTTLED_DRAGON,
+ MS_STICKY_FLAME,
+ MS_STICKY_FLAME,
+ MS_NO_SPELL,
+ MS_STICKY_FLAME,
+ MS_STICKY_FLAME,
+ MS_NO_SPELL },
+
+ { MST_ICE_FIEND,
+ MS_COLD_BOLT,
+ MS_COLD_BOLT,
+ MS_NO_SPELL,
+ MS_TORMENT,
+ MS_NO_SPELL,
+ MS_SUMMON_DEMON },
+
+ { MST_SHADOW_FIEND,
+ MS_COLD_BOLT,
+ MS_NEGATIVE_BOLT,
+ MS_NO_SPELL,
+ MS_TORMENT,
+ MS_NO_SPELL,
+ MS_SUMMON_DEMON },
+
+ { MST_TORMENTOR,
+ MS_PAIN,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_PAIN,
+ MS_NO_SPELL,
+ MS_TORMENT },
+
+ { MST_STORM_DRAGON,
+ MS_LIGHTNING_BOLT,
+ MS_LIGHTNING_BOLT,
+ MS_NO_SPELL,
+ MS_LIGHTNING_BOLT,
+ MS_LIGHTNING_BOLT,
+ MS_NO_SPELL },
+
+ { MST_WHITE_IMP,
+ MS_FROST,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_NO_SPELL },
+
+ { MST_YNOXINUL,
+ MS_NO_SPELL,
+ MS_IRON_BOLT,
+ MS_SUMMON_UFETUBUS,
+ MS_NO_SPELL,
+ MS_SUMMON_UFETUBUS,
+ MS_NO_SPELL },
+
+ { MST_NEQOXEC,
+ MS_MUTATION,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_BRAIN_FEED,
+ MS_SUMMON_DEMON_LESSER,
+ MS_NO_SPELL },
+
+ { MST_HELLWING,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_TELEPORT_OTHER,
+ MS_ANIMATE_DEAD,
+ MS_TELEPORT },
+
+ { MST_SMOKE_DEMON,
+ MS_STICKY_FLAME,
+ MS_STEAM_BALL,
+ MS_NO_SPELL,
+ MS_SMITE,
+ MS_NO_SPELL,
+ MS_NO_SPELL },
+
+ { MST_CACODEMON,
+ MS_SUMMON_DEMON_LESSER,
+ MS_SUMMON_DEMON_LESSER,
+ MS_SUMMON_DEMON_LESSER,
+ MS_MUTATION,
+ MS_DIG,
+ MS_SUMMON_DEMON },
+
+ { MST_GREEN_DEATH,
+ MS_POISON_BLAST,
+ MS_POISON_BLAST,
+ MS_NO_SPELL,
+ MS_VENOM_BOLT,
+ MS_SUMMON_DEMON_LESSER,
+ MS_BLINK },
+
+ { MST_BALRUG,
+ MS_FIRE_BOLT,
+ MS_FIREBALL,
+ MS_NO_SPELL,
+ MS_STICKY_FLAME,
+ MS_SMITE,
+ MS_TELEPORT },
+
+ { MST_BLUE_DEATH,
+ MS_LIGHTNING_BOLT,
+ MS_COLD_BOLT,
+ MS_NO_SPELL,
+ MS_SUMMON_DEMON_LESSER,
+ MS_LEVEL_SUMMON,
+ MS_TELEPORT_OTHER },
+
+ { MST_GERYON,
+ MS_SUMMON_BEAST,
+ MS_SUMMON_BEAST,
+ MS_NO_SPELL,
+ MS_SUMMON_BEAST,
+ MS_NO_SPELL,
+ MS_SUMMON_BEAST },
+
+ { MST_DISPATER,
+ MS_SUMMON_DEMON_GREATER,
+ MS_IRON_BOLT,
+ MS_SUMMON_DEMON,
+ MS_LIGHTNING_BOLT,
+ MS_HELLFIRE,
+ MS_SUMMON_DEMON_GREATER },
+
+ { MST_ASMODEUS,
+ MS_FIRE_BOLT,
+ MS_HELLFIRE,
+ MS_SUMMON_DEMON,
+ MS_SUMMON_DEMON_GREATER,
+ MS_NEGATIVE_BOLT,
+ MS_TELEPORT },
+
+ { MST_ERESHKIGAL,
+ MS_NEGATIVE_BOLT,
+ MS_COLD_BOLT,
+ MS_SUMMON_DEMON,
+ MS_PAIN,
+ MS_PARALYSIS,
+ MS_HEAL },
+
+ { MST_ANTAEUS,
+ MS_COLD_BOLT,
+ MS_LIGHTNING_BOLT,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_NO_SPELL },
+
+ { MST_MNOLEG,
+ MS_SUMMON_DEMON,
+ MS_SMITE,
+ MS_INVIS,
+ MS_MUTATION,
+ MS_LEVEL_SUMMON,
+ MS_TELEPORT },
+
+ { MST_LOM_LOBON,
+ MS_LIGHTNING_BOLT,
+ MS_COLD_BOLT,
+ MS_HEAL,
+ MS_SUMMON_DEMON,
+ MS_TELEPORT,
+ MS_TELEPORT },
+
+ { MST_CEREBOV,
+ MS_FIRE_BOLT,
+ MS_IRON_BOLT,
+ MS_NO_SPELL,
+ MS_FIREBALL,
+ MS_SUMMON_DEMON_LESSER,
+ MS_NO_SPELL },
+
+ { MST_GLOORX_VLOQ,
+ MS_POISON_BLAST,
+ MS_SLOW,
+ MS_SUMMON_DEMON,
+ MS_NEGATIVE_BOLT,
+ MS_SUMMON_DEMON,
+ MS_NO_SPELL },
+
+ { MST_TITAN,
+ MS_LIGHTNING_BOLT,
+ MS_NO_SPELL,
+ MS_HEAL,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_HEAL },
+
+ { MST_GOLDEN_DRAGON,
+ MS_FIRE_BOLT,
+ MS_COLD_BOLT,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_POISON_BLAST,
+ MS_NO_SPELL },
+
+ { MST_DEEP_ELF_SUMMONER,
+ MS_BLINK,
+ MS_SUMMON_DEMON_LESSER,
+ MS_SUMMON_UFETUBUS,
+ MS_VAMPIRE_SUMMON,
+ MS_SUMMON_DEMON,
+ MS_TELEPORT },
+
+ { MST_DEEP_ELF_CONJURER_I,
+ MS_FIRE_BOLT,
+ MS_COLD_BOLT,
+ MS_CANTRIP,
+ MS_LIGHTNING_BOLT,
+ MS_STICKY_FLAME,
+ MS_TELEPORT },
+
+ { MST_DEEP_ELF_CONJURER_II,
+ MS_STICKY_FLAME,
+ MS_ORB_ENERGY,
+ MS_INVIS,
+ MS_STONE_ARROW,
+ MS_NEGATIVE_BOLT,
+ MS_TELEPORT },
+
+ { MST_DEEP_ELF_PRIEST,
+ MS_PAIN,
+ MS_CANTRIP,
+ MS_HEAL,
+ MS_SMITE,
+ MS_ANIMATE_DEAD,
+ MS_HEAL },
+
+ { MST_DEEP_ELF_HIGH_PRIEST,
+ MS_SUMMON_DEMON,
+ MS_HELLFIRE_BURST,
+ MS_HEAL,
+ MS_SMITE,
+ MS_ANIMATE_DEAD,
+ MS_HEAL },
+
+ { MST_DEEP_ELF_DEMONOLOGIST,
+ MS_SUMMON_DEMON,
+ MS_BANISHMENT,
+ MS_SUMMON_DEMON,
+ MS_SUMMON_DEMON_GREATER,
+ MS_SUMMON_DEMON_LESSER,
+ MS_TELEPORT },
+
+ { MST_DEEP_ELF_ANNIHILATOR,
+ MS_LIGHTNING_BOLT,
+ MS_CRYSTAL_SPEAR,
+ MS_BLINK,
+ MS_IRON_BOLT,
+ MS_POISON_BLAST,
+ MS_TELEPORT },
+
+ { MST_DEEP_ELF_SORCERER,
+ MS_NEGATIVE_BOLT,
+ MS_BANISHMENT,
+ MS_HASTE,
+ MS_SUMMON_DEMON,
+ MS_HELLFIRE,
+ MS_TELEPORT },
+
+ { MST_DEEP_ELF_DEATH_MAGE,
+ MS_NEGATIVE_BOLT,
+ MS_NEGATIVE_BOLT,
+ MS_HEAL,
+ MS_ANIMATE_DEAD,
+ MS_ANIMATE_DEAD,
+ MS_TELEPORT },
+
+ { MST_KOBOLD_DEMONOLOGIST,
+ MS_SUMMON_DEMON_LESSER,
+ MS_SUMMON_DEMON,
+ MS_CANTRIP,
+ MS_SUMMON_DEMON_LESSER,
+ MS_SUMMON_DEMON,
+ MS_CANTRIP }, // this should be cute -- bwr
+
+ { MST_NAGA,
+ MS_POISON_SPLASH,
+ MS_POISON_SPLASH,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_NO_SPELL },
+
+ { MST_NAGA_MAGE,
+ MS_VENOM_BOLT,
+ MS_ORB_ENERGY,
+ MS_HASTE,
+ MS_VENOM_BOLT,
+ MS_TELEPORT_OTHER,
+ MS_TELEPORT },
+
+ { MST_CURSE_SKULL,
+ MS_SUMMON_UNDEAD,
+ MS_SUMMON_UNDEAD,
+ MS_NO_SPELL,
+ MS_TORMENT,
+ MS_SUMMON_UNDEAD,
+ MS_NO_SPELL },
+
+ { MST_SHINING_EYE,
+ MS_MUTATION,
+ MS_MUTATION,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_NO_SPELL },
+
+ { MST_FROST_GIANT,
+ MS_COLD_BOLT,
+ MS_COLD_BOLT,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_NO_SPELL },
+
+ { MST_ANGEL,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_HEAL,
+ MS_NO_SPELL,
+ MS_HEAL,
+ MS_HEAL },
+
+ { MST_DAEVA,
+ MS_SMITE,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_SMITE,
+ MS_SMITE,
+ MS_NO_SPELL },
+
+ { MST_SHADOW_DRAGON,
+ MS_NEGATIVE_BOLT,
+ MS_NEGATIVE_BOLT,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_NEGATIVE_BOLT,
+ MS_NO_SPELL },
+
+ { MST_SPHINX,
+ MS_CONFUSE,
+ MS_PARALYSIS,
+ MS_HEAL,
+ MS_SMITE,
+ MS_SLOW,
+ MS_HEAL },
+
+ { MST_MUMMY,
+ MS_SUMMON_DEMON,
+ MS_SMITE,
+ MS_NO_SPELL,
+ MS_TORMENT,
+ MS_SUMMON_UNDEAD,
+ MS_SUMMON_UNDEAD },
+
+ { MST_ELECTRIC_GOLEM,
+ MS_LIGHTNING_BOLT,
+ MS_LIGHTNING_BOLT,
+ MS_BLINK,
+ MS_LIGHTNING_BOLT,
+ MS_LIGHTNING_BOLT,
+ MS_BLINK },
+
+ { MST_ORB_OF_FIRE,
+ MS_FIRE_BOLT,
+ MS_FIRE_BOLT,
+ MS_NO_SPELL,
+ MS_MUTATION,
+ MS_FIREBALL,
+ MS_FIREBALL },
+
+ { MST_SHADOW_IMP,
+ MS_PAIN,
+ MS_NO_SPELL,
+ MS_ANIMATE_DEAD,
+ MS_ANIMATE_DEAD,
+ MS_NO_SPELL,
+ MS_NO_SPELL },
+
+ { MST_GHOST, // actual spells taken from struct (see mon-util.cc),
+ MS_NO_SPELL, // this line: splist[x] = ghost.values[x + 14] -- dlb
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_NO_SPELL },
+
+ { MST_HELL_HOG,
+ MS_STICKY_FLAME,
+ MS_STICKY_FLAME,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_NO_SPELL },
+
+ { MST_SWAMP_DRAGON,
+ MS_POISON_BLAST,
+ MS_POISON_BLAST,
+ MS_NO_SPELL,
+ MS_POISON_BLAST,
+ MS_POISON_BLAST,
+ MS_NO_SPELL },
+
+ { MST_SWAMP_DRAKE,
+ MS_MARSH_GAS,
+ MS_MARSH_GAS,
+ MS_NO_SPELL,
+ MS_MARSH_GAS,
+ MS_MARSH_GAS,
+ MS_NO_SPELL },
+
+ { MST_SERPENT_OF_HELL,
+ MS_HELLFIRE,
+ MS_HELLFIRE,
+ MS_NO_SPELL,
+ MS_HELLFIRE,
+ MS_HELLFIRE,
+ MS_NO_SPELL },
+
+ { MST_BOGGART,
+ MS_CONFUSE,
+ MS_SLOW,
+ MS_INVIS,
+ MS_BLINK,
+ MS_LEVEL_SUMMON,
+ MS_LEVEL_SUMMON },
+
+ { MST_EYE_OF_DEVASTATION,
+ MS_ENERGY_BOLT,
+ MS_ENERGY_BOLT,
+ MS_NO_SPELL,
+ MS_ENERGY_BOLT,
+ MS_ENERGY_BOLT,
+ MS_NO_SPELL },
+
+ { MST_QUICKSILVER_DRAGON,
+ MS_QUICKSILVER_BOLT,
+ MS_QUICKSILVER_BOLT,
+ MS_NO_SPELL,
+ MS_QUICKSILVER_BOLT,
+ MS_QUICKSILVER_BOLT,
+ MS_NO_SPELL },
+
+ { MST_IRON_DRAGON,
+ MS_METAL_SPLINTERS,
+ MS_METAL_SPLINTERS,
+ MS_NO_SPELL,
+ MS_METAL_SPLINTERS,
+ MS_METAL_SPLINTERS,
+ MS_NO_SPELL },
+
+ { MST_SKELETAL_WARRIOR,
+ MS_ANIMATE_DEAD,
+ MS_NO_SPELL,
+ MS_ANIMATE_DEAD,
+ MS_NO_SPELL,
+ MS_NO_SPELL,
+ MS_NO_SPELL },
+
+
+#endif
diff --git a/trunk/source/mon-util.cc b/trunk/source/mon-util.cc
new file mode 100644
index 0000000000..491400c8d6
--- /dev/null
+++ b/trunk/source/mon-util.cc
@@ -0,0 +1,1983 @@
+/*
+ * File: mon-util.cc
+ * Summary: Misc monster related functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <2> 11/04/99 cdl added a break to spell selection
+ * for kobold Summoners
+ * print just "[Ii]t" for invisible undead
+ * renamed params to monam()
+ * <1> -/--/-- LRH Created
+ */
+
+// $pellbinder: (c) D.G.S.E 1998
+// some routines snatched from former monsstat.cc
+
+#include "AppHdr.h"
+#include "mon-util.h"
+#include "monstuff.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "externs.h"
+
+#include "debug.h"
+#include "itemname.h"
+#include "mstuff2.h"
+#include "player.h"
+#include "randart.h"
+#include "stuff.h"
+#include "view.h"
+
+//jmf: moved from inside function
+static FixedVector < int, NUM_MONSTERS > mon_entry;
+
+// really important extern -- screen redraws suck w/o it {dlb}
+FixedVector < unsigned short, 1000 > mcolour;
+
+static struct monsterentry mondata[] = {
+#include "mon-data.h"
+};
+
+#define MONDATASIZE (sizeof(mondata)/sizeof(struct monsterentry))
+
+static int mspell_list[][7] = {
+#include "mon-spll.h"
+};
+
+#if DEBUG_DIAGNOSTICS
+static const char *monster_spell_name[] = {
+ "Magic Missile",
+ "Throw Flame",
+ "Throw Frost",
+ "Paralysis",
+ "Slow",
+ "Haste",
+ "Confuse",
+ "Venom Bolt",
+ "Fire Bolt",
+ "Cold Bolt",
+ "Lightning Bolt",
+ "Invisibility",
+ "Fireball",
+ "Heal",
+ "Teleport",
+ "Teleport Other",
+ "Blink",
+ "Crystal Spear",
+ "Dig",
+ "Negative Bolt",
+ "Hellfire Burst",
+ "Vampire Summon",
+ "Orb Energy",
+ "Brain Feed",
+ "Level Summon",
+ "Fake Rakshasa Summon",
+ "Steam Ball",
+ "Summon Demon",
+ "Animate Dead",
+ "Pain",
+ "Smite",
+ "Sticky Flame",
+ "Poison Blast",
+ "Summon Demon Lesser",
+ "Summon Ufetubus",
+ "Purple Blast",
+ "Summon Beast",
+ "Energy Bolt",
+ "Sting",
+ "Iron Bolt",
+ "Stone Arrow",
+ "Poison Splash",
+ "Summon Undead",
+ "Mutation",
+ "Cantrip",
+ "Disintegrate",
+ "Marsh Gas",
+ "Quicksilver Bolt",
+ "Torment",
+ "Hellfire",
+ "Metal Splinters",
+ "Summon Demon Greater",
+ "Banishment",
+};
+#endif
+
+static int mons_exp_mod(int mclass);
+static monsterentry *seekmonster(int *p_monsterid);
+
+// macro that saves some typing, nothing more
+#define smc seekmonster(&mc)
+
+/* ******************** BEGIN PUBLIC FUNCTIONS ******************** */
+void mons_init(FixedVector < unsigned short, 1000 > &colour)
+{
+ unsigned int x; // must be unsigned to match size_t {dlb}
+
+ for (x = 0; x < MONDATASIZE; x++)
+ colour[mondata[x].mc] = mondata[x].colour;
+
+ //unsigned int x = 0; // must be unsigned to match size_t {dlb}
+
+ // first, fill static array with dummy values {dlb};
+ for (x = 0; x < NUM_MONSTERS; x++)
+ mon_entry[x] = -1;
+
+ // next, fill static array with location of entry in mondata[] {dlb}:
+ for (x = 0; x < MONDATASIZE; x++)
+ mon_entry[mondata[x].mc] = x;
+
+ // finally, monsters yet with dummy entries point to TTTSNB(tm) {dlb}:
+ for (x = 0; x < NUM_MONSTERS; x++)
+ {
+ if (mon_entry[x] == -1)
+ mon_entry[x] = mon_entry[MONS_PROGRAM_BUG];
+ }
+ //return (monsterentry *) 0; // return value should not matter here {dlb}
+} // end mons_init()
+
+
+int mons_flag(int mc, int bf)
+{
+ return ((smc->bitfields & bf) != 0);
+} // end mons_flag()
+
+static int scan_mon_inv_randarts( struct monsters *mon, int ra_prop )
+{
+ int ret = 0;
+
+ if (mons_itemuse( mon->type ) >= MONUSE_STARTING_EQUIPMENT)
+ {
+ const int weapon = mon->inv[MSLOT_WEAPON];
+ const int second = mon->inv[MSLOT_MISSILE]; // ettins/two-head oges
+ const int armour = mon->inv[MSLOT_ARMOUR];
+
+ if (weapon != NON_ITEM && mitm[weapon].base_type == OBJ_WEAPONS
+ && is_random_artefact( mitm[weapon] ))
+ {
+ ret += randart_wpn_property( mitm[weapon], ra_prop );
+ }
+
+ if (second != NON_ITEM && mitm[second].base_type == OBJ_WEAPONS
+ && is_random_artefact( mitm[second] ))
+ {
+ ret += randart_wpn_property( mitm[second], ra_prop );
+ }
+
+ if (armour != NON_ITEM && mitm[armour].base_type == OBJ_ARMOUR
+ && is_random_artefact( mitm[armour] ))
+ {
+ ret += randart_wpn_property( mitm[armour], ra_prop );
+ }
+ }
+
+ return (ret);
+}
+
+
+int mons_holiness(int mc)
+{
+ return (smc->holiness);
+} // end mons_holiness()
+
+bool mons_is_mimic( int mc )
+{
+ return (mons_charclass( mc ) == MONS_GOLD_MIMIC);
+}
+
+bool mons_is_demon( int mc )
+{
+ const int show_char = mons_char( mc );
+
+ // Not every demonic monster is a demon (ie hell hog, hell hound)
+ if (mons_holiness( mc ) == MH_DEMONIC
+ && (isdigit( show_char ) || show_char == '&'))
+ {
+ return (true);
+ }
+
+ return (false);
+}
+
+// Used for elven Glamour ability. -- bwr
+bool mons_is_humanoid( int mc )
+{
+ switch (mons_char( mc))
+ {
+ case 'o': // orcs
+ case 'e': // elvens (deep)
+ case 'c': // centaurs
+ case 'C': // giants
+ case 'O': // ogres
+ case 'K': // kobolds
+ case 'N': // nagas
+ case '@': // adventuring humans
+ case 'T': // trolls
+ return (true);
+
+ case 'g': // goblines, hobgoblins, gnolls, boggarts -- but not gargoyles
+ if (mc != MONS_GARGOYLE
+ && mc != MONS_METAL_GARGOYLE
+ && mc != MONS_MOLTEN_GARGOYLE)
+ {
+ return (true);
+ }
+
+ default:
+ break;
+ }
+
+ return (false);
+}
+
+int mons_zombie_size(int mc)
+{
+ return (smc->zombie_size);
+} // end mons_zombie_size()
+
+
+int mons_weight(int mc)
+{
+ return (smc->weight);
+} // end mons_weight()
+
+
+int mons_corpse_thingy(int mc)
+{
+ return (smc->corpse_thingy);
+} // end mons_corpse_thingy()
+
+
+int mons_charclass(int mc)
+{
+ return (smc->charclass);
+} // end mons_charclass()
+
+
+char mons_shouts(int mc)
+{
+ int u = smc->shouts;
+
+ if (u == -1)
+ u = random2(12);
+
+ return (u);
+} // end mons_shouts()
+
+bool mons_is_unique( int mc )
+{
+ if (mc <= MONS_PROGRAM_BUG
+ || (mc >= MONS_NAGA_MAGE && mc <= MONS_ROYAL_JELLY)
+ || (mc >= MONS_ANCIENT_LICH
+ && (mc != MONS_PLAYER_GHOST && mc != MONS_PANDEMONIUM_DEMON)))
+ {
+ return (false);
+ }
+
+ return (true);
+}
+
+char mons_see_invis( struct monsters *mon )
+{
+ if (mon->type == MONS_PLAYER_GHOST || mon->type == MONS_PANDEMONIUM_DEMON)
+ return (ghost.values[ GVAL_SEE_INVIS ]);
+ else if (((seekmonster(&mon->type))->bitfields & M_SEE_INVIS) != 0)
+ return (1);
+ else if (scan_mon_inv_randarts( mon, RAP_EYESIGHT ) > 0)
+ return (1);
+
+ return (0);
+} // end mons_see_invis()
+
+
+// This does NOT do line of sight! It checks the targ's visibility
+// with respect to mon's perception, but doesn't do walls or range.
+bool mons_monster_visible( struct monsters *mon, struct monsters *targ )
+{
+ if (mons_has_ench(targ, ENCH_SUBMERGED)
+ || (mons_has_ench(targ, ENCH_INVIS) && !mons_see_invis(mon)))
+ {
+ return (false);
+ }
+
+ return (true);
+}
+
+// This does NOT do line of sight! It checks the player's visibility
+// with respect to mon's perception, but doesn't do walls or range.
+bool mons_player_visible( struct monsters *mon )
+{
+ if (you.invis)
+ {
+ if (player_in_water())
+ return (true);
+
+ if (mons_see_invis( mon ))
+ return (true);
+
+ return (false);
+ }
+
+ return (true);
+}
+
+unsigned char mons_char(int mc)
+{
+ return (unsigned char) smc->showchar;
+} // end mons_char()
+
+
+char mons_itemuse(int mc)
+{
+ return (smc->gmon_use);
+} // end mons_itemuse()
+
+unsigned char mons_colour(int mc)
+{
+ return (smc->colour);
+} // end mons_colour()
+
+
+int mons_damage(int mc, int rt)
+{
+ ASSERT(rt >= 0);
+ ASSERT(rt <= 3);
+
+ if (rt < 0 || rt > 3) // make it fool-proof
+ return (0);
+
+ if (rt == 0 && (mc == MONS_PLAYER_GHOST || mc == MONS_PANDEMONIUM_DEMON))
+ return (ghost.values[ GVAL_DAMAGE ]);
+
+ return (smc->damage[rt]);
+} // end mons_damage()
+
+int mons_resist_magic( struct monsters *mon )
+{
+ int u = (seekmonster(&mon->type))->resist_magic;
+
+ // negative values get multiplied with mhd
+ if (u < 0)
+ u = mon->hit_dice * (-u * 2);
+
+ u += scan_mon_inv_randarts( mon, RAP_MAGIC );
+
+ // ego armour resistance
+ const int armour = mon->inv[MSLOT_ARMOUR];
+
+ if (armour != NON_ITEM
+ && get_armour_ego_type( mitm[armour] ) == SPARM_MAGIC_RESISTANCE )
+ {
+ u += 30;
+ }
+
+ return (u);
+} // end mon_resist_magic()
+
+
+// Returns true if the monster made its save against hostile
+// enchantments/some other magics.
+bool check_mons_resist_magic( struct monsters *monster, int pow )
+{
+ int mrs = mons_resist_magic(monster);
+
+ if (mrs == 5000)
+ return (true);
+
+ // Evil, evil hack to make weak one hd monsters easier for first
+ // level characters who have resistable 1st level spells. Six is
+ // a very special value because mrs = hd * 2 * 3 for most monsters,
+ // and the weak, low level monsters have been adjusted so that the
+ // "3" is typically a 1. There are some notable one hd monsters
+ // that shouldn't fall under this, so we do < 6, instead of <= 6...
+ // or checking monster->hit_dice. The goal here is to make the
+ // first level easier for these classes and give them a better
+ // shot at getting to level two or three and spells that can help
+ // them out (or building a level or two of their base skill so they
+ // aren't resisted as often). -- bwr
+ if (mrs < 6 && coinflip())
+ return (false);
+
+ pow = stepdown_value( pow, 30, 40, 100, 120 );
+
+ const int mrchance = (100 + mrs) - pow;
+ const int mrch2 = random2(100) + random2(101);
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE,
+ "Power: %d, monster's MR: %d, target: %d, roll: %d",
+ pow, mrs, mrchance, mrch2 );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ return ((mrch2 < mrchance) ? true : false);
+} // end check_mons_resist_magic()
+
+
+int mons_res_elec( struct monsters *mon )
+{
+ int mc = mon->type;
+
+ if (mc == MONS_PLAYER_GHOST || mc == MONS_PANDEMONIUM_DEMON)
+ return (ghost.values[ GVAL_RES_ELEC ]);
+
+ /* this is a variable, not a player_xx() function, so can be above 1 */
+ int u = 0, f = (seekmonster(&mc))->bitfields;
+
+ // of course it makes no sense setting them both :)
+ if (f & M_RES_ELEC)
+ u++; //if(f&M_ED_ELEC) u--;
+
+ // don't bother checking equipment if the monster can't use it
+ if (mons_itemuse(mc) >= MONUSE_STARTING_EQUIPMENT)
+ {
+ u += scan_mon_inv_randarts( mon, RAP_ELECTRICITY );
+
+ // no ego armour, but storm dragon.
+ const int armour = mon->inv[MSLOT_ARMOUR];
+ if (armour != NON_ITEM && mitm[armour].base_type == OBJ_ARMOUR
+ && mitm[armour].sub_type == ARM_STORM_DRAGON_ARMOUR)
+ {
+ u += 1;
+ }
+ }
+
+ return (u);
+} // end mons_res_elec()
+
+
+int mons_res_poison( struct monsters *mon )
+{
+ int mc = mon->type;
+
+ int u = 0, f = (seekmonster(&mc))->bitfields;
+
+ if (f & M_RES_POISON)
+ u++;
+
+ if (f & M_ED_POISON)
+ u--;
+
+ if (mons_itemuse(mc) >= MONUSE_STARTING_EQUIPMENT)
+ {
+ u += scan_mon_inv_randarts( mon, RAP_POISON );
+
+ const int armour = mon->inv[MSLOT_ARMOUR];
+ if (armour != NON_ITEM && mitm[armour].base_type == OBJ_ARMOUR)
+ {
+ // intrinsic armour abilities
+ switch (mitm[armour].sub_type)
+ {
+ case ARM_SWAMP_DRAGON_ARMOUR: u += 1; break;
+ case ARM_GOLD_DRAGON_ARMOUR: u += 1; break;
+ default: break;
+ }
+
+ // ego armour resistance
+ if (get_armour_ego_type( mitm[armour] ) == SPARM_POISON_RESISTANCE)
+ u += 1;
+ }
+ }
+
+ return (u);
+} // end mons_res_poison()
+
+
+int mons_res_fire( struct monsters *mon )
+{
+ int mc = mon->type;
+
+ if (mc == MONS_PLAYER_GHOST || mc == MONS_PANDEMONIUM_DEMON)
+ return (ghost.values[ GVAL_RES_FIRE ]);
+
+ int u = 0, f = (seekmonster(&mc))->bitfields;
+
+ // no Big Prize (tm) here either if you set all three flags. It's a pity uh?
+ //
+ // Note that natural monster resistance is two levels, this is duplicate
+ // the fact that having this flag used to be a lot better than armour
+ // for monsters (it used to make them immune in a lot of cases) -- bwr
+ if (f & M_RES_HELLFIRE)
+ u += 3;
+ else if (f & M_RES_FIRE)
+ u += 2;
+ else if (f & M_ED_FIRE)
+ u--;
+
+ if (mons_itemuse(mc) >= MONUSE_STARTING_EQUIPMENT)
+ {
+ u += scan_mon_inv_randarts( mon, RAP_POISON );
+
+ const int armour = mon->inv[MSLOT_ARMOUR];
+ if (armour != NON_ITEM && mitm[armour].base_type == OBJ_ARMOUR)
+ {
+ // intrinsic armour abilities
+ switch (mitm[armour].sub_type)
+ {
+ case ARM_DRAGON_ARMOUR: u += 2; break;
+ case ARM_GOLD_DRAGON_ARMOUR: u += 1; break;
+ case ARM_ICE_DRAGON_ARMOUR: u -= 1; break;
+ default: break;
+ }
+
+ // check ego resistance
+ const int ego = get_armour_ego_type( mitm[armour] );
+ if (ego == SPARM_FIRE_RESISTANCE || ego == SPARM_RESISTANCE)
+ u += 1;
+ }
+ }
+
+ return (u);
+} // end mons_res_fire()
+
+
+int mons_res_cold( struct monsters *mon )
+{
+ int mc = mon->type;
+
+ if (mc == MONS_PLAYER_GHOST || mc == MONS_PANDEMONIUM_DEMON)
+ return (ghost.values[ GVAL_RES_COLD ]);
+
+ int u = 0, f = (seekmonster(&mc))->bitfields;
+
+ // Note that natural monster resistance is two levels, this is duplicate
+ // the fact that having this flag used to be a lot better than armour
+ // for monsters (it used to make them immune in a lot of cases) -- bwr
+ if (f & M_RES_COLD)
+ u += 2;
+ else if (f & M_ED_COLD)
+ u--;
+
+ if (mons_itemuse(mc) >= MONUSE_STARTING_EQUIPMENT)
+ {
+ u += scan_mon_inv_randarts( mon, RAP_POISON );
+
+ const int armour = mon->inv[MSLOT_ARMOUR];
+ if (armour != NON_ITEM && mitm[armour].base_type == OBJ_ARMOUR)
+ {
+ // intrinsic armour abilities
+ switch (mitm[armour].sub_type)
+ {
+ case ARM_ICE_DRAGON_ARMOUR: u += 2; break;
+ case ARM_GOLD_DRAGON_ARMOUR: u += 1; break;
+ case ARM_DRAGON_ARMOUR: u -= 1; break;
+ default: break;
+ }
+
+ // check ego resistance
+ const int ego = get_armour_ego_type( mitm[armour] );
+ if (ego == SPARM_COLD_RESISTANCE || ego == SPARM_RESISTANCE)
+ u += 1;
+ }
+ }
+
+ return (u);
+} // end mons_res_cold()
+
+int mons_res_negative_energy( struct monsters *mon )
+{
+ int mc = mon->type;
+
+ if (mons_holiness( mon->type ) == MH_UNDEAD
+ || mons_holiness( mon->type ) == MH_DEMONIC
+ || mons_holiness( mon->type ) == MH_NONLIVING
+ || mons_holiness( mon->type ) == MH_PLANT
+ || mon->type == MONS_SHADOW_DRAGON)
+ {
+ return (3); // to match the value for players
+ }
+
+ int u = 0;
+
+ if (mons_itemuse(mc) >= MONUSE_STARTING_EQUIPMENT)
+ {
+ u += scan_mon_inv_randarts( mon, RAP_NEGATIVE_ENERGY );
+
+ const int armour = mon->inv[MSLOT_ARMOUR];
+ if (armour != NON_ITEM && mitm[armour].base_type == OBJ_ARMOUR)
+ {
+ // check for ego resistance
+ if (get_armour_ego_type( mitm[armour] ) == SPARM_POSITIVE_ENERGY)
+ u += 1;
+ }
+ }
+
+ return (u);
+} // end mons_res_negative_energy()
+
+int mons_skeleton(int mc)
+{
+ if (mons_zombie_size(mc) == 0
+ || mons_weight(mc) == 0 || ((smc->bitfields & M_NO_SKELETON) != 0))
+ {
+ return (0);
+ }
+
+ return (1);
+} // end mons_skeleton()
+
+char mons_class_flies(int mc)
+{
+ if (mc == MONS_PANDEMONIUM_DEMON)
+ return (ghost.values[ GVAL_DEMONLORD_FLY ]);
+
+ int f = smc->bitfields;
+
+ if (f & M_FLIES)
+ return (1);
+
+ if (f & M_LEVITATE)
+ return (2);
+
+ return (0);
+}
+
+char mons_flies( struct monsters *mon )
+{
+ char ret = mons_class_flies( mon->type );
+
+ return (ret ? ret : (scan_mon_inv_randarts(mon, RAP_LEVITATE) > 0) ? 2 : 0);
+} // end mons_flies()
+
+
+// this nice routine we keep in exactly the way it was
+int hit_points(int hit_dice, int min_hp, int rand_hp)
+{
+ int hrolled = 0;
+
+ for (int hroll = 0; hroll < hit_dice; hroll++)
+ {
+ hrolled += random2(1 + rand_hp);
+ hrolled += min_hp;
+ }
+
+ return (hrolled);
+} // end hit_points()
+
+// This function returns the standard number of hit dice for a type
+// of monster, not a pacticular monsters current hit dice. -- bwr
+int mons_type_hit_dice( int type )
+{
+ struct monsterentry *mon_class = seekmonster( &type );
+
+ if (mon_class)
+ return (mon_class->hpdice[0]);
+
+ return (0);
+}
+
+
+int exper_value( struct monsters *monster )
+{
+ long x_val = 0;
+
+ // these three are the original arguments:
+ const int mclass = monster->type;
+ const int mHD = monster->hit_dice;
+ const int maxhp = monster->max_hit_points;
+
+ // these are some values we care about:
+ const int speed = mons_speed(mclass);
+ const int modifier = mons_exp_mod(mclass);
+ const int item_usage = mons_itemuse(mclass);
+
+ // XXX: shapeshifters can qualify here, even though they can't cast:
+ const bool spellcaster = mons_flag( mclass, M_SPELLCASTER );
+
+ // early out for no XP monsters
+ if (mons_flag(mclass, M_NO_EXP_GAIN))
+ return (0);
+
+ // These undead take damage to maxhp, so we use only HD. -- bwr
+ if (mclass == MONS_ZOMBIE_SMALL
+ || mclass == MONS_ZOMBIE_LARGE
+ || mclass == MONS_SIMULACRUM_SMALL
+ || mclass == MONS_SIMULACRUM_LARGE
+ || mclass == MONS_SKELETON_SMALL
+ || mclass == MONS_SKELETON_LARGE)
+ {
+ x_val = (16 + mHD * 4) * (mHD * mHD) / 10;
+ }
+ else
+ {
+ x_val = (16 + maxhp) * (mHD * mHD) / 10;
+ }
+
+
+ // Let's calculate a simple difficulty modifier -- bwr
+ int diff = 0;
+
+ // Let's look for big spells:
+ if (spellcaster)
+ {
+ const int msecc = ((mclass == MONS_HELLION) ? MST_BURNING_DEVIL :
+ (mclass == MONS_PANDEMONIUM_DEMON) ? MST_GHOST
+ : monster->number);
+
+ int hspell_pass[6] = { MS_NO_SPELL, MS_NO_SPELL, MS_NO_SPELL,
+ MS_NO_SPELL, MS_NO_SPELL, MS_NO_SPELL };
+
+ mons_spell_list( msecc, hspell_pass );
+
+ for (int i = 0; i < 6; i++)
+ {
+ switch (hspell_pass[i])
+ {
+ case MS_PARALYSIS:
+ case MS_SMITE:
+ case MS_HELLFIRE_BURST:
+ case MS_HELLFIRE:
+ case MS_TORMENT:
+ case MS_IRON_BOLT:
+ diff += 25;
+ break;
+
+ case MS_LIGHTNING_BOLT:
+ case MS_NEGATIVE_BOLT:
+ case MS_VENOM_BOLT:
+ case MS_STICKY_FLAME:
+ case MS_DISINTEGRATE:
+ case MS_SUMMON_DEMON_GREATER:
+ case MS_BANISHMENT:
+ case MS_CRYSTAL_SPEAR:
+ case MS_TELEPORT:
+ case MS_TELEPORT_OTHER:
+ diff += 10;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ // let's look at regeneration
+ if (monster_descriptor( mclass, MDSC_REGENERATES ))
+ diff += 15;
+
+ // Monsters at normal or fast speed with big melee damage
+ if (speed >= 10)
+ {
+ int max_melee = 0;
+ for (int i = 0; i < 4; i++)
+ max_melee += mons_damage( mclass, i );
+
+ if (max_melee > 30)
+ diff += (max_melee / ((speed == 10) ? 2 : 1));
+ }
+
+ // Monsters who can use equipment (even if only the equipment
+ // they are given) can be considerably enhanced because of
+ // the way weapons work for monsters. -- bwr
+ if (item_usage == MONUSE_STARTING_EQUIPMENT
+ || item_usage == MONUSE_WEAPONS_ARMOUR)
+ {
+ diff += 30;
+ }
+
+ // Set a reasonable range on the difficulty modifier...
+ // Currently 70% - 200% -- bwr
+ if (diff > 100)
+ diff = 100;
+ else if (diff < -30)
+ diff = -30;
+
+ // Apply difficulty
+ x_val *= (100 + diff);
+ x_val /= 100;
+
+ // Basic speed modification
+ if (speed > 0)
+ {
+ x_val *= speed;
+ x_val /= 10;
+ }
+
+ // Slow monsters without spells and items often have big HD which
+ // cause the experience value to be overly large... this tries
+ // to reduce the inappropriate amount of XP that results. -- bwr
+ if (speed < 10 && !spellcaster && item_usage < MONUSE_STARTING_EQUIPMENT)
+ {
+ x_val /= 2;
+ }
+
+ // Apply the modifier in the monster's definition
+ if (modifier > 0)
+ {
+ x_val *= modifier;
+ x_val /= 10;
+ }
+
+ // Reductions for big values. -- bwr
+ if (x_val > 100)
+ x_val = 100 + ((x_val - 100) * 3) / 4;
+ if (x_val > 1000)
+ x_val = 1000 + (x_val - 1000) / 2;
+
+ // guarantee the value is within limits
+ if (x_val <= 0)
+ x_val = 1;
+ else if (x_val > 15000)
+ x_val = 15000;
+
+ return (x_val);
+} // end exper_value()
+
+
+// this needs to be rewritten a la the monsterseek rewrite {dlb}:
+void mons_spell_list( unsigned char sec, int splist[6] )
+{
+ unsigned int x;
+
+ for (x = 0; x < NUM_MSTYPES; x++)
+ {
+ if (mspell_list[x][0] == sec)
+ break;
+ }
+
+ if (x >= NUM_MSTYPES)
+ return;
+
+ // I *KNOW* this can easily be done in a loop
+ splist[0] = mspell_list[x][1]; // bolt spell
+ splist[1] = mspell_list[x][2]; // enchantment
+ splist[2] = mspell_list[x][3]; // self_ench
+ splist[3] = mspell_list[x][4]; // misc
+ splist[4] = mspell_list[x][5]; // misc2
+ splist[5] = mspell_list[x][6]; // emergency
+
+ if (sec == MST_GHOST) /* ghost */
+ {
+ for (x = 0; x < 6; x++)
+ splist[x] = ghost.values[ GVAL_SPELL_1 + x ];
+ }
+} // end mons_spell_list()
+
+#if DEBUG_DIAGNOSTICS
+const char *mons_spell_name( int spell )
+{
+ if (spell == MS_NO_SPELL || spell >= NUM_MONSTER_SPELLS || spell < 0)
+ return ("No spell");
+
+ return (monster_spell_name[ spell ]);
+}
+#endif
+
+// generate a shiny new and unscarred monster
+void define_monster(int k)
+{
+ int temp_rand = 0; // probability determination {dlb}
+ int m2_class = menv[k].type;
+ int m2_HD, m2_hp, m2_hp_max, m2_AC, m2_ev, m2_speed;
+ int m2_sec = menv[k].number;
+ struct monsterentry *m = seekmonster(&m2_class);
+
+ m2_HD = m->hpdice[0];
+
+ // misc
+ m2_AC = m->AC;
+ m2_ev = m->ev;
+
+ // speed
+ m2_speed = m->speed;
+
+ // some monsters are randomized:
+ // did I get them all? // I don't think so {dlb}
+ if (mons_is_mimic( m2_class ))
+ m2_sec = get_mimic_colour( &menv[k] );
+ else
+ {
+ switch (m2_class)
+ {
+ case MONS_ABOMINATION_SMALL:
+ m2_HD = 4 + random2(4);
+ m2_AC = 3 + random2(7);
+ m2_ev = 7 + random2(6);
+ m2_speed = 7 + random2avg(9, 2);
+
+ if (m2_sec == 250)
+ m2_sec = random_colour();
+ break;
+
+ case MONS_ZOMBIE_SMALL:
+ m2_HD = (coinflip() ? 1 : 2);
+ break;
+
+ case MONS_ZOMBIE_LARGE:
+ m2_HD = 3 + random2(5);
+ break;
+
+ case MONS_ABOMINATION_LARGE:
+ m2_HD = 8 + random2(4);
+ m2_AC = 5 + random2avg(9, 2);
+ m2_ev = 3 + random2(5);
+ m2_speed = 6 + random2avg(7, 2);
+
+ if (m2_sec == 250)
+ m2_sec = random_colour();
+ break;
+
+ case MONS_BEAST:
+ m2_HD = 4 + random2(4);
+ m2_AC = 2 + random2(5);
+ m2_ev = 7 + random2(5);
+ m2_speed = 8 + random2(5);
+ break;
+
+ case MONS_HYDRA:
+ m2_sec = 4 + random2(5);
+ break;
+
+ case MONS_DEEP_ELF_FIGHTER:
+ case MONS_DEEP_ELF_KNIGHT:
+ case MONS_DEEP_ELF_SOLDIER:
+ case MONS_ORC_WIZARD:
+ m2_sec = MST_ORC_WIZARD_I + random2(3);
+ break;
+
+ case MONS_LICH:
+ case MONS_ANCIENT_LICH:
+ m2_sec = MST_LICH_I + random2(4);
+ break;
+
+ case MONS_HELL_KNIGHT:
+ m2_sec = (coinflip() ? MST_HELL_KNIGHT_I : MST_HELL_KNIGHT_II);
+ break;
+
+ case MONS_NECROMANCER:
+ m2_sec = (coinflip() ? MST_NECROMANCER_I : MST_NECROMANCER_II);
+ break;
+
+ case MONS_WIZARD:
+ case MONS_OGRE_MAGE:
+ case MONS_EROLCHA:
+ case MONS_DEEP_ELF_MAGE:
+ m2_sec = MST_WIZARD_I + random2(5);
+ break;
+
+ case MONS_DEEP_ELF_CONJURER:
+ m2_sec = (coinflip()? MST_DEEP_ELF_CONJURER_I : MST_DEEP_ELF_CONJURER_II);
+ break;
+
+ case MONS_BUTTERFLY:
+ case MONS_SPATIAL_VORTEX:
+ case MONS_KILLER_KLOWN:
+ m2_sec = random_colour();
+ break;
+
+ case MONS_GILA_MONSTER:
+ temp_rand = random2(7);
+
+ m2_sec = (temp_rand >= 5 ? LIGHTRED : // 2/7
+ temp_rand >= 3 ? LIGHTMAGENTA : // 2/7
+ temp_rand == 2 ? RED : // 1/7
+ temp_rand == 1 ? MAGENTA // 1/7
+ : YELLOW); // 1/7
+ break;
+
+ case MONS_HUMAN:
+ case MONS_ELF:
+ // these are supposed to only be created by polymorph
+ m2_HD += random2(10);
+ m2_AC += random2(5);
+ m2_ev += random2(5);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // some calculations
+ m2_hp = hit_points(m2_HD, m->hpdice[1], m->hpdice[2]);
+ m2_hp += m->hpdice[3];
+ m2_hp_max = m2_hp;
+
+ if (m2_sec == 250)
+ m2_sec = m->sec;
+
+ // so let it be written, so let it be done
+ menv[k].hit_dice = m2_HD;
+ menv[k].hit_points = m2_hp;
+ menv[k].max_hit_points = m2_hp_max;
+ menv[k].armour_class = m2_AC;
+ menv[k].evasion = m2_ev;
+ menv[k].speed = m2_speed;
+ menv[k].speed_increment = 70;
+ menv[k].number = m2_sec;
+ menv[k].flags = 0;
+
+ // reset monster enchantments
+ for (int i = 0; i < NUM_MON_ENCHANTS; i++)
+ menv[k].enchantment[i] = ENCH_NONE;
+} // end define_monster()
+
+
+/* ------------------------- monam/moname ------------------------- */
+const char *ptr_monam( struct monsters *mon, char desc )
+{
+ // We give an item type description for mimics now, note that
+ // since gold mimics only have one description (to match the
+ // examine code in direct.cc), we won't bother going through
+ // this for them. -- bwr
+ if (mons_is_mimic( mon->type ) && mon->type != MONS_GOLD_MIMIC)
+ {
+ static char mimic_name_buff[ ITEMNAME_SIZE ];
+
+ item_def item;
+ get_mimic_item( mon, item );
+ item_name( item, desc, mimic_name_buff );
+
+ return (mimic_name_buff);
+ }
+
+ return (monam( mon->number, mon->type, player_monster_visible( mon ),
+ desc, mon->inv[MSLOT_WEAPON] ));
+}
+
+const char *monam( int mons_num, int mons, bool vis, char desc, int mons_wpn )
+{
+ static char gmo_n[ ITEMNAME_SIZE ];
+ char gmo_n2[ ITEMNAME_SIZE ] = "";
+
+ gmo_n[0] = '\0';
+
+ // If you can't see the critter, let moname() print [Ii]t.
+ if (!vis)
+ {
+ moname( mons, vis, desc, gmo_n );
+ return (gmo_n);
+ }
+
+ // These need their description level handled here instead of
+ // in monam().
+ if (mons == MONS_SPECTRAL_THING)
+ {
+ switch (desc)
+ {
+ case DESC_CAP_THE:
+ strcpy(gmo_n, "The");
+ break;
+ case DESC_NOCAP_THE:
+ strcpy(gmo_n, "the");
+ break;
+ case DESC_CAP_A:
+ strcpy(gmo_n, "A");
+ break;
+ case DESC_NOCAP_A:
+ strcpy(gmo_n, "a");
+ break;
+ case DESC_PLAIN: /* do nothing */ ;
+ break;
+ //default: DEBUGSTR("bad desc flag");
+ }
+ }
+
+ switch (mons)
+ {
+ case MONS_ZOMBIE_SMALL:
+ case MONS_ZOMBIE_LARGE:
+ moname(mons_num, vis, desc, gmo_n);
+ strcat(gmo_n, " zombie");
+ break;
+
+ case MONS_SKELETON_SMALL:
+ case MONS_SKELETON_LARGE:
+ moname(mons_num, vis, desc, gmo_n);
+ strcat(gmo_n, " skeleton");
+ break;
+
+ case MONS_SIMULACRUM_SMALL:
+ case MONS_SIMULACRUM_LARGE:
+ moname(mons_num, vis, desc, gmo_n);
+ strcat(gmo_n, " simulacrum");
+ break;
+
+ case MONS_SPECTRAL_THING:
+ strcat(gmo_n, " spectral ");
+ moname(mons_num, vis, DESC_PLAIN, gmo_n2);
+ strcat(gmo_n, gmo_n2);
+ break;
+
+ case MONS_DANCING_WEAPON:
+ // safety check -- if we don't have/know the weapon use default name
+ if (mons_wpn == NON_ITEM)
+ moname( mons, vis, desc, gmo_n );
+ else
+ {
+ item_def item = mitm[mons_wpn];
+ unset_ident_flags( item, ISFLAG_KNOW_CURSE | ISFLAG_KNOW_PLUSES );
+ item_name( item, desc, gmo_n );
+ }
+ break;
+
+ case MONS_PLAYER_GHOST:
+ strcpy(gmo_n, ghost.name);
+ strcat(gmo_n, "'s ghost");
+ break;
+
+ case MONS_PANDEMONIUM_DEMON:
+ strcpy(gmo_n, ghost.name);
+ break;
+
+ default:
+ moname(mons, vis, desc, gmo_n);
+ break;
+ }
+
+ return (gmo_n);
+} // end monam()
+
+void moname(int mons_num, bool vis, char descrip, char glog[ ITEMNAME_SIZE ])
+{
+ glog[0] = '\0';
+
+ char gmon_name[ ITEMNAME_SIZE ] = "";
+ strcpy( gmon_name, seekmonster( &mons_num )->name );
+
+ if (!vis)
+ {
+ switch (descrip)
+ {
+ case DESC_CAP_THE:
+ case DESC_CAP_A:
+ strcpy(glog, "It");
+ break;
+ case DESC_NOCAP_THE:
+ case DESC_NOCAP_A:
+ case DESC_PLAIN:
+ strcpy(glog, "it");
+ break;
+ }
+
+ strcpy(gmon_name, glog);
+ return;
+ }
+
+ if (!mons_is_unique( mons_num ))
+ {
+ switch (descrip)
+ {
+ case DESC_CAP_THE:
+ strcpy(glog, "The ");
+ break;
+ case DESC_NOCAP_THE:
+ strcpy(glog, "the ");
+ break;
+ case DESC_CAP_A:
+ strcpy(glog, "A");
+ break;
+ case DESC_NOCAP_A:
+ strcpy(glog, "a");
+ break;
+ case DESC_PLAIN:
+ break;
+ // default: DEBUGSTR("bad monster descrip flag");
+ }
+
+ if (descrip == DESC_CAP_A || descrip == DESC_NOCAP_A)
+ {
+ switch (toupper(gmon_name[0]))
+ {
+ case 'A':
+ case 'E':
+ case 'I':
+ case 'O':
+ case 'U':
+ strcat(glog, "n ");
+ break;
+
+ default:
+ strcat(glog, " ");
+ break;
+ }
+ }
+ }
+
+ strcat(glog, gmon_name);
+} // end moname()
+
+/* ********************* END PUBLIC FUNCTIONS ********************* */
+
+// see mons_init for initialization of mon_entry array.
+static struct monsterentry *seekmonster(int *p_monsterid)
+{
+ ASSERT(p_monsterid != 0);
+
+ int me = mon_entry[(*p_monsterid)];
+
+ if (me >= 0) // PARANOIA
+ return (&mondata[mon_entry[(*p_monsterid)]]);
+ else
+ return (NULL);
+} // end seekmonster()
+
+static int mons_exp_mod(int mc)
+{
+ return (smc->exp_mod);
+} // end mons_exp_mod()
+
+
+int mons_speed(int mc)
+{
+ return (smc->speed);
+} // end mons_speed()
+
+
+int mons_intel(int mc) //jmf: "fixed" to work with new I_ types
+{
+ switch (smc->intel)
+ {
+ case I_PLANT:
+ return (I_PLANT);
+ case I_INSECT:
+ case I_REPTILE:
+ return (I_INSECT);
+ case I_ANIMAL:
+ case I_ANIMAL_LIKE:
+ return (I_ANIMAL);
+ case I_NORMAL:
+ return (I_NORMAL);
+ case I_HIGH:
+ return (I_HIGH);
+ default:
+ return (I_NORMAL);
+ }
+} // ens mons_intel()
+
+
+int mons_intel_type(int mc) //jmf: new, used by my spells
+{
+ return (smc->intel);
+} // end mons_intel_type()
+
+int mons_power(int mc)
+{
+ // for now, just return monster hit dice.
+ return (smc->hpdice[0]);
+}
+
+bool mons_aligned(int m1, int m2)
+{
+ bool fr1, fr2;
+ struct monsters *mon1, *mon2;
+
+ if (m1 == MHITNOT || m2 == MHITNOT)
+ return (true);
+
+ if (m1 == MHITYOU)
+ fr1 = true;
+ else
+ {
+ mon1 = &menv[m1];
+ fr1 = (mon1->attitude == ATT_FRIENDLY) || mons_has_ench(mon1, ENCH_CHARM);
+ }
+
+ if (m2 == MHITYOU)
+ fr2 = true;
+ else
+ {
+ mon2 = &menv[m2];
+ fr2 = (mon2->attitude == ATT_FRIENDLY) || mons_has_ench(mon2, ENCH_CHARM);
+ }
+
+ return (fr1 == fr2);
+}
+
+bool mons_friendly(struct monsters *m)
+{
+ return (m->attitude == ATT_FRIENDLY || mons_has_ench(m, ENCH_CHARM));
+}
+
+/* ******************************************************************
+
+// In the name of England, I declare this function wasteful! {dlb}
+
+static monsterentry *seekmonster( int mc )
+{
+
+ ASSERT(mc >= 0);
+
+ int x = 0;
+
+ while (x < mondatasize)
+ {
+ if (mondata[x].mc == mc)
+ return &mondata[x];
+
+ x++;
+ }
+
+ ASSERT(false);
+
+ return seekmonster(MONS_PROGRAM_BUG); // see the disasters coming if there is no 250?
+
+} // end seekmonster()
+****************************************************************** */
+
+
+/* ******************************************************************
+
+// only used once, and internal to this file, to boot {dlb}:
+
+// These are easy to implement here. The difficult (dull!) work of converting
+// the data structures is finally finished now!
+inline char *mons_name( int mc )
+{
+
+ return smc->name;
+
+} // end mons_name()
+****************************************************************** */
+
+/*****************************************************************
+
+ Used to determine whether or not a monster should fire a beam (MUST be
+ called _after_ fire_tracer() for meaningful result.
+
+*/
+
+bool mons_should_fire(struct bolt &beam)
+{
+ // use of foeRatio:
+ // the higher this number, the more monsters
+ // will _avoid_ collateral damage to their friends.
+ // setting this to zero will in fact have all
+ // monsters ignore their friends when considering
+ // collateral damage.
+
+ // quick check - did we in fact get any foes?
+ if (beam.foe_count == 0)
+ return (false);
+
+ // if we either hit no friends, or monster too dumb to care
+ if (beam.fr_count == 0 || !beam.smartMonster)
+ return (true);
+
+ // only fire if they do acceptably low collateral damage
+ // the default for this is 50%; in other words, don't
+ // hit a foe unless you hit 2 or fewer friends.
+ if (beam.foe_power >= (beam.foeRatio * beam.fr_power) / 100)
+ return (true);
+
+ return (false);
+}
+
+int mons_has_ench(struct monsters *mon, unsigned int ench, unsigned int ench2)
+{
+ // silliness
+ if (ench == ENCH_NONE)
+ return (ench);
+
+ if (ench2 == ENCH_NONE)
+ ench2 = ench;
+
+ for (int p = 0; p < NUM_MON_ENCHANTS; p++)
+ {
+ if (mon->enchantment[p] >= ench && mon->enchantment[p] <= ench2)
+ return (mon->enchantment[p]);
+ }
+
+ return (ENCH_NONE);
+}
+
+// Returning the deleted enchantment is important! See abjuration. -- bwr
+int mons_del_ench( struct monsters *mon, unsigned int ench, unsigned int ench2,
+ bool quiet )
+{
+ unsigned int p;
+ int ret_val = ENCH_NONE;
+
+ // silliness
+ if (ench == ENCH_NONE)
+ return (ENCH_NONE);
+
+ if (ench2 == ENCH_NONE)
+ ench2 = ench;
+
+ for (p = 0; p < NUM_MON_ENCHANTS; p++)
+ {
+ if (mon->enchantment[p] >= ench && mon->enchantment[p] <= ench2)
+ break;
+ }
+
+ if (p == NUM_MON_ENCHANTS)
+ return (ENCH_NONE);
+
+ ret_val = mon->enchantment[p];
+ mon->enchantment[p] = ENCH_NONE;
+
+ // check for slow/haste
+ if (ench == ENCH_HASTE)
+ {
+ if (mon->speed >= 100)
+ mon->speed = 100 + ((mon->speed - 100) / 2);
+ else
+ mon->speed /= 2;
+ }
+
+ if (ench == ENCH_SLOW)
+ {
+ if (mon->speed >= 100)
+ mon->speed = 100 + ((mon->speed - 100) * 2);
+ else
+ mon->speed *= 2;
+ }
+
+ if (ench == ENCH_FEAR)
+ {
+ if (!quiet)
+ simple_monster_message(mon, " seems to regain its courage.");
+
+ // reevaluate behaviour
+ behaviour_event(mon, ME_EVAL);
+ }
+
+ if (ench == ENCH_CONFUSION)
+ {
+ if (!quiet)
+ simple_monster_message(mon, " seems less confused.");
+
+ // reevaluate behaviour
+ behaviour_event(mon, ME_EVAL);
+ }
+
+ if (ench == ENCH_INVIS)
+ {
+ // invisible monsters stay invisible
+ if (mons_flag(mon->type, M_INVIS))
+ {
+ mon->enchantment[p] = ENCH_INVIS;
+ }
+ else if (mons_near(mon) && !player_see_invis()
+ && !mons_has_ench( mon, ENCH_SUBMERGED ))
+ {
+ if (!quiet)
+ {
+ strcpy( info, ptr_monam( mon, DESC_CAP_A ) );
+ strcat( info, " appears!" );
+ mpr( info );
+ }
+ }
+ }
+
+ if (ench == ENCH_CHARM)
+ {
+ if (!quiet)
+ simple_monster_message(mon, " is no longer charmed.");
+
+ // reevaluate behaviour
+ behaviour_event(mon, ME_EVAL);
+ }
+
+ if (ench == ENCH_BACKLIGHT_I)
+ {
+ if (!quiet)
+ simple_monster_message(mon, " stops glowing.");
+ }
+
+ if (ench == ENCH_STICKY_FLAME_I || ench == ENCH_YOUR_STICKY_FLAME_I)
+ {
+ if (!quiet)
+ simple_monster_message(mon, " stops burning.");
+ }
+
+ if (ench == ENCH_POISON_I || ench == ENCH_YOUR_POISON_I)
+ {
+ if (!quiet)
+ simple_monster_message(mon, " looks more healthy.");
+ }
+
+ if (ench == ENCH_YOUR_ROT_I)
+ {
+ if (!quiet)
+ simple_monster_message(mon, " is no longer rotting.");
+ }
+
+ return (ret_val);
+}
+
+bool mons_add_ench(struct monsters *mon, unsigned int ench)
+{
+ // silliness
+ if (ench == ENCH_NONE)
+ return (false);
+
+ int newspot = -1;
+
+ // don't double-add
+ for (int p = 0; p < NUM_MON_ENCHANTS; p++)
+ {
+ if (mon->enchantment[p] == ench)
+ return (true);
+
+ if (mon->enchantment[p] == ENCH_NONE && newspot < 0)
+ newspot = p;
+ }
+
+ if (newspot < 0)
+ return (false);
+
+ mon->enchantment[newspot] = ench;
+// if ench == ENCH_FEAR //mv: withou this fear & repel undead spell doesn't work
+
+
+ // check for slow/haste
+ if (ench == ENCH_HASTE)
+ {
+ if (mon->speed >= 100)
+ mon->speed = 100 + ((mon->speed - 100) * 2);
+ else
+ mon->speed *= 2;
+ }
+
+ if (ench == ENCH_SLOW)
+ {
+ if (mon->speed >= 100)
+ mon->speed = 100 + ((mon->speed - 100) / 2);
+ else
+ mon->speed /= 2;
+ }
+
+ return (true);
+}
+
+// used to determine whether or not a monster should always
+// fire this spell if selected. If not, we should use a
+// tracer.
+
+// note - this function assumes that the monster is "nearby"
+// its target!
+
+bool ms_requires_tracer(int monspell)
+{
+ bool requires = false;
+
+ switch(monspell)
+ {
+ case MS_BANISHMENT:
+ case MS_COLD_BOLT:
+ case MS_CONFUSE:
+ case MS_CRYSTAL_SPEAR:
+ case MS_DISINTEGRATE:
+ case MS_ENERGY_BOLT:
+ case MS_FIRE_BOLT:
+ case MS_FIREBALL:
+ case MS_FLAME:
+ case MS_FROST:
+ case MS_HELLFIRE:
+ case MS_IRON_BOLT:
+ case MS_LIGHTNING_BOLT:
+ case MS_MARSH_GAS:
+ case MS_METAL_SPLINTERS:
+ case MS_MMISSILE:
+ case MS_NEGATIVE_BOLT:
+ case MS_ORB_ENERGY:
+ case MS_PAIN:
+ case MS_PARALYSIS:
+ case MS_POISON_BLAST:
+ case MS_POISON_SPLASH:
+ case MS_QUICKSILVER_BOLT:
+ case MS_SLOW:
+ case MS_STEAM_BALL:
+ case MS_STICKY_FLAME:
+ case MS_STING:
+ case MS_STONE_ARROW:
+ case MS_TELEPORT_OTHER:
+ case MS_VENOM_BOLT:
+ requires = true;
+ break;
+
+ // self-niceties and direct effects
+ case MS_ANIMATE_DEAD:
+ case MS_BLINK:
+ case MS_BRAIN_FEED:
+ case MS_DIG:
+ case MS_FAKE_RAKSHASA_SUMMON:
+ case MS_HASTE:
+ case MS_HEAL:
+ case MS_HELLFIRE_BURST:
+ case MS_INVIS:
+ case MS_LEVEL_SUMMON:
+ case MS_MUTATION:
+ case MS_SMITE:
+ case MS_SUMMON_BEAST:
+ case MS_SUMMON_DEMON_LESSER:
+ case MS_SUMMON_DEMON:
+ case MS_SUMMON_DEMON_GREATER:
+ case MS_SUMMON_UFETUBUS:
+ case MS_TELEPORT:
+ case MS_TORMENT:
+ case MS_VAMPIRE_SUMMON:
+ case MS_CANTRIP:
+
+ // meaningless, but sure, why not?
+ case MS_NO_SPELL:
+ break;
+
+ default:
+ break;
+
+ }
+
+ return (requires);
+}
+
+// returns true if the spell is something you wouldn't want done if
+// you had a friendly target.. only returns a meaningful value for
+// non-beam spells
+
+bool ms_direct_nasty(int monspell)
+{
+ bool nasty = true;
+
+ switch(monspell)
+ {
+ // self-niceties/summonings
+ case MS_ANIMATE_DEAD:
+ case MS_BLINK:
+ case MS_DIG:
+ case MS_FAKE_RAKSHASA_SUMMON:
+ case MS_HASTE:
+ case MS_HEAL:
+ case MS_INVIS:
+ case MS_LEVEL_SUMMON:
+ case MS_SUMMON_BEAST:
+ case MS_SUMMON_DEMON_LESSER:
+ case MS_SUMMON_DEMON:
+ case MS_SUMMON_DEMON_GREATER:
+ case MS_SUMMON_UFETUBUS:
+ case MS_TELEPORT:
+ case MS_VAMPIRE_SUMMON:
+ nasty = false;
+ break;
+
+ case MS_BRAIN_FEED:
+ case MS_HELLFIRE_BURST:
+ case MS_MUTATION:
+ case MS_SMITE:
+ case MS_TORMENT:
+
+ // meaningless, but sure, why not?
+ case MS_NO_SPELL:
+ break;
+
+ default:
+ break;
+
+ }
+
+ return (nasty);
+}
+
+// Spells a monster may want to cast if fleeing from the player, and
+// the player is not in sight.
+bool ms_useful_fleeing_out_of_sight( struct monsters *mon, int monspell )
+{
+ if (ms_waste_of_time( mon, monspell ))
+ return (false);
+
+ switch (monspell)
+ {
+ case MS_HASTE:
+ case MS_INVIS:
+ case MS_HEAL:
+ case MS_ANIMATE_DEAD:
+ return (true);
+
+ case MS_VAMPIRE_SUMMON:
+ case MS_SUMMON_UFETUBUS:
+ case MS_FAKE_RAKSHASA_SUMMON:
+ case MS_LEVEL_SUMMON:
+ case MS_SUMMON_DEMON:
+ case MS_SUMMON_DEMON_LESSER:
+ case MS_SUMMON_BEAST:
+ case MS_SUMMON_UNDEAD:
+ case MS_SUMMON_DEMON_GREATER:
+ if (one_chance_in(10)) // only summon friends some of the time
+ return (true);
+ break;
+
+ default:
+ break;
+ }
+
+ return (false);
+}
+
+bool ms_low_hitpoint_cast( struct monsters *mon, int monspell )
+{
+ bool ret = false;
+
+ bool targ_adj = false;
+
+ if (mon->foe == MHITYOU || mon->foe == MHITNOT)
+ {
+ if (adjacent(you.x_pos, you.y_pos, mon->x, mon->y))
+ targ_adj = true;
+ }
+ else if (adjacent( menv[mon->foe].x, menv[mon->foe].y, mon->x, mon->y ))
+ {
+ targ_adj = true;
+ }
+
+ switch (monspell)
+ {
+ case MS_TELEPORT:
+ case MS_TELEPORT_OTHER:
+ case MS_HEAL:
+ ret = true;
+ break;
+
+ case MS_BLINK:
+ if (targ_adj)
+ ret = true;
+ break;
+
+ case MS_VAMPIRE_SUMMON:
+ case MS_SUMMON_UFETUBUS:
+ case MS_FAKE_RAKSHASA_SUMMON:
+ if (!targ_adj)
+ ret = true;
+ break;
+ }
+
+ return (ret);
+}
+
+// Checks to see if a particular spell is worth casting in the first place.
+bool ms_waste_of_time( struct monsters *mon, int monspell )
+{
+ bool ret = false;
+ int intel, est_magic_resist, power, diff;
+ struct monsters *targ;
+
+
+ // Eventually, we'll probably want to be able to have monsters
+ // learn which of their elemental bolts were resisted and have those
+ // handled here as well. -- bwr
+ switch (monspell)
+ {
+ case MS_HASTE:
+ if (mons_has_ench( mon, ENCH_HASTE ))
+ ret = true;
+ break;
+
+ case MS_INVIS:
+ if (mons_has_ench( mon, ENCH_INVIS ))
+ ret = true;
+ break;
+
+ case MS_HEAL:
+ if (mon->hit_points > mon->max_hit_points / 2)
+ ret = true;
+ break;
+
+ case MS_TELEPORT:
+ // Monsters aren't smart enough to know when to cancel teleport.
+ if (mons_has_ench( mon, ENCH_TP_I, ENCH_TP_IV ))
+ ret = true;
+ break;
+
+ case MS_TELEPORT_OTHER:
+ // Monsters aren't smart enough to know when to cancel teleport.
+ if (mon->foe == MHITYOU)
+ {
+ if (you.duration[DUR_TELEPORT])
+ return (true);
+ }
+ else if (mon->foe != MHITNOT)
+ {
+ if (mons_has_ench( &menv[mon->foe], ENCH_TP_I, ENCH_TP_IV))
+ return (true);
+ }
+ // intentional fall-through
+
+ case MS_SLOW:
+ case MS_CONFUSE:
+ case MS_PAIN:
+ case MS_BANISHMENT:
+ case MS_DISINTEGRATE:
+ case MS_PARALYSIS:
+ // occasionally we don't estimate... just fire and see:
+ if (one_chance_in(5))
+ return (false);
+
+ // Only intelligent monsters estimate.
+ intel = mons_intel( mon->type );
+ if (intel != I_NORMAL && intel != I_HIGH)
+ return (false);
+
+ // We'll estimate the target's resistance to magic, by first getting
+ // the actual value and then randomizing it.
+ est_magic_resist = (mon->foe == MHITNOT) ? 10000 : 0;
+
+ if (mon->foe != MHITNOT)
+ {
+ if (mon->foe == MHITYOU)
+ est_magic_resist = player_res_magic();
+ else
+ {
+ targ = &menv[ mon->foe ];
+ est_magic_resist = mons_resist_magic( targ );
+ }
+
+ // now randomize (normal intels less accurate than high):
+ if (intel == I_NORMAL)
+ est_magic_resist += random2(80) - 40;
+ else
+ est_magic_resist += random2(30) - 15;
+ }
+
+ power = 12 * mon->hit_dice * (monspell == MS_PAIN ? 2 : 1);
+ power = stepdown_value( power, 30, 40, 100, 120 );
+
+ // Determine the amount of chance allowed by the benefit from
+ // the spell. The estimated difficulty is the probability
+ // of rolling over 100 + diff on 2d100. -- bwr
+ diff = (monspell == MS_PAIN
+ || monspell == MS_SLOW
+ || monspell == MS_CONFUSE) ? 0 : 50;
+
+ if (est_magic_resist - power > diff)
+ ret = true;
+
+ break;
+
+ default:
+ break;
+ }
+
+ return (ret);
+}
+
+static bool ms_ranged_spell( int monspell )
+{
+ switch (monspell)
+ {
+ case MS_HASTE:
+ case MS_HEAL:
+ case MS_TELEPORT:
+ case MS_INVIS:
+ case MS_BLINK:
+ return (false);
+
+ default:
+ break;
+ }
+
+ return (true);
+}
+
+bool mons_has_ranged_spell( struct monsters *mon )
+{
+ const int mclass = mon->type;
+
+ if (mons_flag( mclass, M_SPELLCASTER ))
+ {
+ const int msecc = ((mclass == MONS_HELLION) ? MST_BURNING_DEVIL :
+ (mclass == MONS_PANDEMONIUM_DEMON) ? MST_GHOST
+ : mon->number);
+
+ int hspell_pass[6] = { MS_NO_SPELL, MS_NO_SPELL, MS_NO_SPELL,
+ MS_NO_SPELL, MS_NO_SPELL, MS_NO_SPELL };
+
+ mons_spell_list( msecc, hspell_pass );
+
+ for (int i = 0; i < 6; i++)
+ {
+ if (ms_ranged_spell( hspell_pass[i] ))
+ return (true);
+ }
+ }
+
+ return (false);
+}
+
+bool mons_has_ranged_attack( struct monsters *mon )
+{
+ const int weapon = mon->inv[MSLOT_WEAPON];
+ const int ammo = mon->inv[MSLOT_MISSILE];
+
+ const int lnchClass = (weapon != NON_ITEM) ? mitm[weapon].base_type : -1;
+ const int lnchType = (weapon != NON_ITEM) ? mitm[weapon].sub_type : 0;
+
+ const int ammoClass = (ammo != NON_ITEM) ? mitm[ammo].base_type : -1;
+ const int ammoType = (ammo != NON_ITEM) ? mitm[ammo].sub_type : 0;
+
+ bool launched = false;
+ bool thrown = false;
+
+ throw_type( lnchClass, lnchType, ammoClass, ammoType, launched, thrown );
+
+ if (launched || thrown)
+ return (true);
+
+ return (false);
+}
+
+
+// use of variant:
+// 0 : She is tap dancing.
+// 1 : It seems she is tap dancing. (lower case pronoun)
+// 2 : Her sword explodes! (upper case possessive)
+// 3 : It sticks to her sword! (lower case possessive)
+// ... as needed
+
+const char *mons_pronoun(int mon_type, int variant)
+{
+ int gender = GENDER_NEUTER;
+
+ if (mons_is_unique( mon_type ))
+ {
+ switch(mon_type)
+ {
+ case MONS_JESSICA:
+ case MONS_PSYCHE:
+ case MONS_JOSEPHINE:
+ case MONS_AGNES:
+ case MONS_MAUD:
+ case MONS_LOUISE:
+ case MONS_FRANCES:
+ case MONS_MARGERY:
+ case MONS_EROLCHA:
+ case MONS_ERICA:
+ gender = GENDER_FEMALE;
+ break;
+ default:
+ gender = GENDER_MALE;
+ break;
+ }
+ }
+
+ switch(variant)
+ {
+ case PRONOUN_CAP:
+ return ((gender == 0) ? "It" :
+ (gender == 1) ? "He" : "She");
+
+ case PRONOUN_NOCAP:
+ return ((gender == 0) ? "it" :
+ (gender == 1) ? "he" : "she");
+
+ case PRONOUN_CAP_POSSESSIVE:
+ return ((gender == 0) ? "Its" :
+ (gender == 1) ? "His" : "Her");
+
+ case PRONOUN_NOCAP_POSSESSIVE:
+ return ((gender == 0) ? "its" :
+ (gender == 1) ? "his" : "her");
+
+ case PRONOUN_REFLEXIVE: // awkward at start of sentence, always lower
+ return ((gender == 0) ? "itself" :
+ (gender == 1) ? "himself" : "herself");
+ }
+
+ return ("");
+}
diff --git a/trunk/source/mon-util.h b/trunk/source/mon-util.h
new file mode 100644
index 0000000000..86291fd1e9
--- /dev/null
+++ b/trunk/source/mon-util.h
@@ -0,0 +1,460 @@
+/*
+ * File: mon-util.h
+ * Summary: Misc monster related functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef MONUTIL_H
+#define MONUTIL_H
+
+#include "externs.h"
+
+// ($pellbinder) (c) D.G.S.E. 1998
+
+// ****remember***** must make an hardcopy of this sometime
+
+#if defined(macintosh) || defined(__IBMCPP__) || defined(SOLARIS) || defined(__BCPLUSPLUS__) || defined(BSD)
+#define PACKED
+#else
+#define PACKED __attribute__ ((packed))
+#endif
+
+// leaves no skeleton? ("blob" monsters?)
+// if weight=0 or zombie_size=0, this is always true
+#define M_NO_FLAGS 0 // clear
+#define M_NO_SKELETON (1<<0)
+// resistances
+#define M_RES_ELEC (1<<1)
+#define M_RES_POISON (1<<2)
+#define M_RES_FIRE (1<<3)
+#define M_RES_HELLFIRE (1<<4)
+#define M_RES_COLD (1<<5)
+// invisible
+#define M_INVIS (1<<6) // is created with invis enchantment set, and never runs out
+// vulnerabilities
+//#define M_ED_ELEC (1<<6) // never used
+#define M_ED_POISON (1<<7) // ??? - - This flag is now (2.50) set for insects (LRH)
+#define M_ED_FIRE (1<<8)
+#define M_ED_COLD (1<<9)
+#define M_SPELLCASTER (1<<10) // any non-physical-attack powers
+#define M_FLIES (1<<11) // will crash to ground if paralysed (wings)
+#define M_LEVITATE (1<<12) // not if this is set
+#define M_SEE_INVIS (1<<13)
+// killing this beast only gives 10 experience (makes sense for plants/fungi)
+#define M_NO_EXP_GAIN (1<<14) // must do this manually
+#define M_SPEAKS (1<<15)
+//jmf: M_SPELLCASTER was taken ... :-b
+#define M_ACTUAL_SPELLS (1<<16) // monster is a wizard
+#define M_PRIEST (1<<17) // monster is a priest of Brian's Orc God (BOG)
+#define M_COLD_BLOOD (1<<18)
+#define M_WARM_BLOOD (1<<19)
+#define M_CONFUSED (1<<20) // monster is perma-confused
+#define M_SPLITS (1<<21) // monster is perma-confused
+#define M_AMPHIBIOUS (1<<22) // monster can swim in water
+
+//jmf: it'd be nice if these next two were implimented ...
+#define M_ON_FIRE (1<<29) // flag for Hellion-like colour shift
+#define M_FROZEN (1<<30) // flag for ice-like colour shift
+
+
+// zombie size
+#define Z_NOZOMBIE 0 // no zombie (and no skeleton)
+#define Z_SMALL 1
+#define Z_BIG 2
+// Note - this should be set to 0 for classed monsters, eg orc wizard
+
+// shout
+#define S_RANDOM -1
+#define S_SILENT 0
+#define S_SHOUT 1 //1=shout
+#define S_BARK 2 //2=bark
+#define S_SHOUT2 3 //3=shout twice
+#define S_ROAR 4 //4=roar
+#define S_SCREAM 5 //5=scream
+#define S_BELLOW 6 //6=bellow (?)
+#define S_SCREECH 7 //7=screech
+#define S_BUZZ 8 //8=buzz
+#define S_MOAN 9 //9=moan
+#define S_WHINE 10 //10=irritating whine (mosquito)
+#define S_CROAK 11 //11=frog croak
+#define S_GROWL 12 //jmf: for bears
+#define S_HISS 13 //bwr: for snakes and lizards
+
+// ai
+// So far this only affects a) chance to see stealthy player and b) chance to
+// walk through damaging clouds (LRH)
+//jmf: now has relevence to mind-affecting spells, maybe soon behaviour
+#define I_PLANT 0
+#define I_INSECT 1
+#define I_ANIMAL 2
+#define I_NORMAL 3
+#define I_HIGH 4
+#define I_ANIMAL_LIKE 5
+#define I_REPTILE 6
+
+
+struct monsterentry
+{
+ short mc PACKED; // monster number
+
+ unsigned char showchar PACKED, colour PACKED;
+ const char *name /*[32]*/PACKED; //longest is 23 till now (31 is max alowed here)
+
+ int bitfields PACKED;
+ short weight PACKED;
+ // experience is calculated like this:
+ // ((((max_hp / 7) + 1) * (mHD * mHD) + 1) * exp_mod) / 10
+ // ^^^^^^ see below at hpdice
+ // Note that this may make draining attacks less attractive (LRH)
+ char exp_mod PACKED;
+
+ unsigned short charclass PACKED; //
+
+ char holiness PACKED; // -1=holy,0=normal,1=undead,2=very very evil
+
+ short resist_magic PACKED; // (positive is ??)
+ // max damage in a turn is total of these four?
+
+ unsigned char damage[4] PACKED;
+
+// hpdice[4]: [0]=HD [1]=min_hp [2]=rand_hp [3]=add_hp
+// min hp = [0]*[1]+[3] & max hp = [0]*([1]+[2])+[3])
+// example: the Iron Golem, hpdice={15,7,4,0}
+// 15*7 < hp < 15*(7+4),
+// 105 < hp < 165
+// hp will be around 135 each time. (assuming an good random number generator)
+// !!!!!!! The system is exactly the same as before, only the way of writing changed !!!!
+ unsigned char hpdice[4] PACKED; // until we have monsters with 32767 hp,this is easily possible
+
+ char AC PACKED; // armour class
+
+ char ev PACKED; // evasion
+
+ char speed PACKED, speed_inc PACKED; // duh!
+
+ short sec PACKED; // not used (250) most o/t time
+
+ // eating the corpse: 1=clean,2=might be contaminated,3=poison,4=very bad
+ char corpse_thingy PACKED;
+ // 0=no zombie, 1=small zombie (z) 107, 2=_BIG_ zombie (Z) 108
+ char zombie_size PACKED;
+ // 0-12: see above, -1=random one of (0-7)
+ char shouts PACKED;
+ // AI things?
+ char intel PACKED; // 0=none, 1=worst...4=best
+
+ char gmon_use PACKED;
+}; // mondata[] - again, no idea why this was externed {dlb}
+
+
+// wow. this struct is only about 48 bytes, (excluding the name)
+
+
+// last updated 10jun2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void mons_init( FixedVector<unsigned short, 1000>& colour );
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: bang - beam - debug - direct - effects - fight - item_use -
+ * monstuff - mstuff2 - ouch - spells1 - spells2 - spells3 -
+ * spells4
+ * *********************************************************************** */
+// mons_wpn only important for dancing weapons -- bwr
+const char *monam(int mons_num, int mons, bool vis, char desc, int mons_wpn = NON_ITEM);
+
+// these front for monam
+const char *ptr_monam( struct monsters *mon, char desc );
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: beam - direct - fight - monstuff - mstuff2 - spells4 - view
+ * *********************************************************************** */
+char mons_class_flies( int mc );
+char mons_flies( struct monsters *mon );
+
+
+// last updated XXmay2000 {dlb}
+/* ***********************************************************************
+ * called from: dungeon - monstuff
+ * *********************************************************************** */
+char mons_itemuse(int mc);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: beam - fight - monstuff - view
+ * *********************************************************************** */
+char mons_see_invis( struct monsters *mon );
+
+bool mons_monster_visible( struct monsters *mon, struct monsters *targ );
+bool mons_player_visible( struct monsters *mon );
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: view
+ * *********************************************************************** */
+char mons_shouts(int mclass);
+
+bool mons_is_unique(int mclass);
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: describe - fight
+ * *********************************************************************** */
+// int exper_value(int mclass, int mHD, int maxhp);
+int exper_value( struct monsters *monster );
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: dungeon - mon-util
+ * *********************************************************************** */
+int hit_points(int hit_dice, int min_hp, int rand_hp);
+
+int mons_type_hit_dice( int type );
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: beam - effects
+ * *********************************************************************** */
+int mons_resist_magic( struct monsters *mon );
+int mons_resist_turn_undead( struct monsters *mon );
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: fight - monstuff
+ * *********************************************************************** */
+int mons_damage(int mc, int rt);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: dungeon - fight - monstuff - spells4
+ * *********************************************************************** */
+int mons_charclass(int mcls);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: food - spells4
+ * *********************************************************************** */
+int mons_corpse_thingy(int mclass);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: dungeon - fight - monstuff - mon-util
+ * *********************************************************************** */
+int mons_flag(int mc, int bf);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: beam - effects - fight - monstuff - mstuff2 - spells2 -
+ * spells3 - spells4
+ * *********************************************************************** */
+int mons_holiness(int mclass);
+
+bool mons_is_mimic( int mc );
+bool mons_is_demon( int mc );
+bool mons_is_humanoid( int mc );
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: monstuff - spells4 - view
+ * *********************************************************************** */
+int mons_intel(int mclass);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: spells4
+ * *********************************************************************** */
+int mons_intel_type(int mclass); //jmf: added 20mar2000
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: beam - fight - monstuff
+ * *********************************************************************** */
+int mons_res_cold( struct monsters *mon );
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: beam - fight - spells4
+ * *********************************************************************** */
+int mons_res_elec( struct monsters *mon );
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: beam - fight - monstuff
+ * *********************************************************************** */
+int mons_res_fire( struct monsters *mon );
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: beam - monstuff - spells4
+ * *********************************************************************** */
+int mons_res_poison( struct monsters *mon );
+
+int mons_res_negative_energy( struct monsters *mon );
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: dungeon - items - spells2 - spells4
+ * *********************************************************************** */
+int mons_skeleton(int mcls);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: describe - fight - items - misc - monstuff - mon-util -
+ * player - spells2 - spells3
+ * *********************************************************************** */
+int mons_weight(int mclass);
+
+
+// last updated 08may2001 {gdl}
+/* ***********************************************************************
+ * called from: monplace mon-util
+ * *********************************************************************** */
+int mons_speed(int mclass);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: dungeon - mon-util - spells2
+ * *********************************************************************** */
+int mons_zombie_size(int mclass);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: bang - beam - monstuff - mstuff2 - spells4 - view
+ * *********************************************************************** */
+// unsigned char mons_category(int which_mons);
+
+
+// last updated 07jan2001 (gdl)
+/* ***********************************************************************
+ * called from: beam
+ * *********************************************************************** */
+int mons_power(int mclass);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: spells2 - view
+ * *********************************************************************** */
+unsigned char mons_char(int mc);
+
+
+// last updated 10jun2000 {dlb}
+/* ***********************************************************************
+ * called from: dungeon - fight - misc
+ * *********************************************************************** */
+unsigned char mons_colour(int mc);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: dungeon - fight
+ * *********************************************************************** */
+void define_monster(int mid);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: debug - itemname - mon-util
+ * *********************************************************************** */
+void moname(int mcl, bool vis, char descrip, char glog[ ITEMNAME_SIZE ]);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: monstuff
+ * *********************************************************************** */
+void mons_spell_list(unsigned char sec, int splist[6]);
+
+#if DEBUG_DIAGNOSTICS
+// last updated 25sep2001 {dlb}
+/* ***********************************************************************
+ * called from: describe
+ * *********************************************************************** */
+const char *mons_spell_name( int spell );
+#endif
+
+// last updated 4jan2001 (gdl)
+/* ***********************************************************************
+ * called from: monstuff
+ * *********************************************************************** */
+bool mons_should_fire(struct bolt &beam);
+
+
+// last updated 23mar2001 (gdl)
+/* ***********************************************************************
+ * called from: monstuff
+ * *********************************************************************** */
+bool ms_direct_nasty(int monspell);
+
+// last updated 14jan2001 (gdl)
+/* ***********************************************************************
+ * called from: monstuff
+ * *********************************************************************** */
+bool ms_requires_tracer(int mons_spell);
+
+bool ms_useful_fleeing_out_of_sight( struct monsters *mon, int monspell );
+bool ms_waste_of_time( struct monsters *mon, int monspell );
+bool ms_low_hitpoint_cast( struct monsters *mon, int monspell );
+
+bool mons_has_ranged_spell( struct monsters *mon );
+bool mons_has_ranged_attack( struct monsters *mon );
+
+// last updated 06mar2001 (gdl)
+/* ***********************************************************************
+ * called from:
+ * *********************************************************************** */
+const char *mons_pronoun(int mon_type, int variant);
+
+// last updated 14mar2001 (gdl)
+/* ***********************************************************************
+ * called from: monstuff
+ * *********************************************************************** */
+bool mons_aligned(int m1, int m2);
+
+// last updated 14mar2001 (gdl)
+/* ***********************************************************************
+ * called from: monstuff acr
+ * *********************************************************************** */
+bool mons_friendly(struct monsters *m);
+
+
+int mons_has_ench( struct monsters *mon, unsigned int ench,
+ unsigned int ench2 = ENCH_NONE );
+
+int mons_del_ench( struct monsters *mon, unsigned int ench,
+ unsigned int ench2 = ENCH_NONE, bool quiet = false );
+
+bool mons_add_ench( struct monsters *mon, unsigned int ench );
+
+
+bool check_mons_resist_magic( struct monsters *monster, int pow );
+
+#endif
diff --git a/trunk/source/monplace.cc b/trunk/source/monplace.cc
new file mode 100644
index 0000000000..6c9505cd47
--- /dev/null
+++ b/trunk/source/monplace.cc
@@ -0,0 +1,1300 @@
+/*
+ * File: monplace.cc
+ * Summary: Functions used when placing monsters in the dungeon.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "monplace.h"
+
+#include "externs.h"
+#include "dungeon.h"
+#include "monstuff.h"
+#include "mon-pick.h"
+#include "mon-util.h"
+#include "misc.h"
+#include "player.h"
+#include "stuff.h"
+#include "spells4.h"
+
+// NEW place_monster -- note that power should be set to:
+// 51 for abyss
+// 52 for pandemonium
+// x otherwise
+
+// proximity is the same as for mons_place:
+// 0 is no restrictions
+// 1 attempts to place near player
+// 2 attempts to avoid player LOS
+
+#define BIG_BAND 20
+
+static int band_member(int band, int power);
+static int choose_band( int mon_type, int power, int &band_size );
+static int place_monster_aux(int mon_type, char behaviour, int target,
+ int px, int py, int power, int extra, bool first_band_member);
+
+bool place_monster(int &id, int mon_type, int power, char behaviour,
+ int target, bool summoned, int px, int py, bool allow_bands,
+ int proximity, int extra)
+{
+ int band_size = 0;
+ int band_monsters[BIG_BAND]; // band monster types
+ int lev_mons = power; // final 'power'
+ int count;
+ int i;
+
+ // set initial id to -1 (unsuccessful create)
+ id = -1;
+
+ // (1) early out (summoned to occupied grid)
+ if (summoned && mgrd[px][py] != NON_MONSTER)
+ return (false);
+
+ // (2) take care of random monsters
+ if (mon_type == RANDOM_MONSTER
+ && player_in_branch( BRANCH_HALL_OF_BLADES ))
+ {
+ mon_type = MONS_DANCING_WEAPON;
+ }
+
+ if (mon_type == RANDOM_MONSTER)
+ {
+ if (player_in_branch( BRANCH_MAIN_DUNGEON )
+ && lev_mons != 51 && one_chance_in(4))
+ {
+ lev_mons = random2(power);
+ }
+
+ if (player_in_branch( BRANCH_MAIN_DUNGEON ) && lev_mons < 28)
+ {
+ // potentially nasty surprise, but very rare
+ if (one_chance_in(5000))
+ lev_mons = random2(27);
+
+ // slightly out of depth monsters are more common:
+ if (one_chance_in(50))
+ lev_mons += random2(6);
+
+ if (lev_mons > 27)
+ lev_mons = 27;
+ }
+
+ /* Abyss or Pandemonium. Almost never called from Pan;
+ probably only if a rand demon gets summon anything spell */
+ if (lev_mons == 51
+ || you.level_type == LEVEL_PANDEMONIUM
+ || you.level_type == LEVEL_ABYSS)
+ {
+ do
+ {
+ count = 0;
+
+ do
+ {
+ // was: random2(400) {dlb}
+ mon_type = random2(NUM_MONSTERS);
+ count++;
+ }
+ while (mons_abyss(mon_type) == 0 && count < 2000);
+
+ if (count == 2000)
+ return (false);
+ }
+ while (random2avg(100, 2) > mons_rare_abyss(mon_type)
+ && !one_chance_in(100));
+ }
+ else
+ {
+ int level, diff, chance;
+
+ if (lev_mons > 30)
+ lev_mons = 30;
+
+ for (i = 0; i < 10000; i++)
+ {
+ int count = 0;
+
+ do
+ {
+ mon_type = random2(NUM_MONSTERS);
+ count++;
+ }
+ while (mons_rarity(mon_type) == 0 && count < 2000);
+
+ if (count == 2000)
+ return (false);
+
+ level = mons_level( mon_type );
+ diff = level - lev_mons;
+ chance = mons_rarity( mon_type ) - (diff * diff);
+
+ if ((lev_mons >= level - 5 && lev_mons <= level + 5)
+ && random2avg(100, 2) <= chance)
+ {
+ break;
+ }
+ }
+
+ if (i == 10000)
+ return (false);
+ }
+ }
+
+ // (3) decide on banding (good lord!)
+ band_size = 1;
+ band_monsters[0] = mon_type;
+
+ if (allow_bands)
+ {
+ int band = choose_band(mon_type, power, band_size);
+ band_size ++;
+
+ for (i = 1; i < band_size; i++)
+ band_monsters[i] = band_member( band, power );
+ }
+
+ // Monsters that can't move shouldn't be taking the stairs -- bwr
+ if (proximity == PROX_NEAR_STAIRS && mons_speed( mon_type ) == 0)
+ proximity = PROX_AWAY_FROM_PLAYER;
+
+ // (4) for first monster, choose location. This is pretty intensive.
+ bool proxOK;
+ bool close_to_player;
+
+ // player shoved out of the way?
+ bool shoved = false;
+ unsigned char stair_gfx = 0;
+ int pval = 0;
+
+ if (!summoned)
+ {
+ int tries = 0;
+ // try to pick px, py that is
+ // a) not occupied
+ // b) compatible
+ // c) in the 'correct' proximity to the player
+ unsigned char grid_wanted = monster_habitat(mon_type);
+ while(true)
+ {
+ tries ++;
+ // give up on stair placement?
+ if (proximity == PROX_NEAR_STAIRS)
+ {
+ if (tries > 320)
+ {
+ proximity = PROX_AWAY_FROM_PLAYER;
+ tries = 0;
+ }
+ }
+ else if (tries > 60)
+ return (false);
+
+ px = 5 + random2(GXM - 10);
+ py = 5 + random2(GYM - 10);
+
+ // occupied?
+ if (mgrd[px][py] != NON_MONSTER
+ || (px == you.x_pos && py == you.y_pos))
+ {
+ continue;
+ }
+
+ // compatible - floor?
+ if (grid_wanted == DNGN_FLOOR && grd[px][py] < DNGN_FLOOR)
+ continue;
+
+ // compatible - others (must match, except for deep water monsters
+ // generated in shallow water)
+ if ((grid_wanted != DNGN_FLOOR && grd[px][py] != grid_wanted)
+ && (grid_wanted != DNGN_DEEP_WATER || grd[px][py] != DNGN_SHALLOW_WATER))
+ {
+ continue;
+ }
+
+ // don't generate monsters on top of teleport traps
+ // (how did they get there?)
+ int trap = trap_at_xy(px, py);
+ if (trap >= 0)
+ {
+ if (env.trap[trap].type == TRAP_TELEPORT)
+ continue;
+ }
+
+ // check proximity to player
+ proxOK = true;
+
+ switch (proximity)
+ {
+ case PROX_ANYWHERE:
+ if (grid_distance( you.x_pos, you.y_pos, px, py ) < 2 + random2(3))
+ {
+ proxOK = false;
+ }
+ break;
+
+ case PROX_CLOSE_TO_PLAYER:
+ case PROX_AWAY_FROM_PLAYER:
+ close_to_player = (distance(you.x_pos, you.y_pos, px, py) < 64);
+
+ if ((proximity == PROX_CLOSE_TO_PLAYER && !close_to_player)
+ || (proximity == PROX_AWAY_FROM_PLAYER && close_to_player))
+ {
+ proxOK = false;
+ }
+ break;
+
+ case PROX_NEAR_STAIRS:
+ pval = near_stairs(px, py, 1, stair_gfx);
+ if (pval == 2)
+ {
+ // 0 speed monsters can't shove player out of their way.
+ if (mons_speed(mon_type) == 0)
+ {
+ proxOK = false;
+ break;
+ }
+ // swap the monster and the player spots, unless the
+ // monster was generated in lava or deep water.
+ if (grd[px][py] == DNGN_LAVA || grd[px][py] == DNGN_DEEP_WATER)
+ {
+ proxOK = false;
+ break;
+ }
+ shoved = true;
+ int tpx = px;
+ int tpy = py;
+ px = you.x_pos;
+ py = you.y_pos;
+ you.x_pos = tpx;
+ you.y_pos = tpy;
+ }
+
+ proxOK = (pval > 0);
+ break;
+ default:
+ break;
+ }
+
+ if (!proxOK)
+ continue;
+
+ // cool.. passes all tests
+ break;
+ } // end while.. place first monster
+ }
+
+ id = place_monster_aux( mon_type, behaviour, target, px, py, lev_mons,
+ extra, true );
+
+ // now, forget about banding if the first placement failed, or there's too
+ // many monsters already, or we successfully placed by stairs
+ if (id < 0 || id+30 > MAX_MONSTERS)
+ return false;
+
+ // message to player from stairwell/gate appearance?
+ if (see_grid(px, py) && proximity == PROX_NEAR_STAIRS)
+ {
+ info[0] = '\0';
+
+ if (player_monster_visible( &menv[id] ))
+ strcpy(info, ptr_monam( &menv[id], DESC_CAP_A ));
+ else if (shoved)
+ strcpy(info, "Something");
+
+ if (shoved)
+ {
+ strcat(info, " shoves you out of the ");
+ strcat(info, (stair_gfx == '>' || stair_gfx == '<') ? "stairwell!"
+ : "gateway!");
+ mpr(info);
+ }
+ else if (info[0] != '\0')
+ {
+ strcat(info, (stair_gfx == '>') ? " comes up the stairs." :
+ (stair_gfx == '<') ? " comes down the stairs."
+ : " comes through the gate.");
+ mpr(info);
+ }
+
+ // special case: must update the view for monsters created in player LOS
+ viewwindow(1, false);
+ }
+
+ // monsters placed by stairs don't bring the whole band up/down/through
+ // with them
+ if (proximity == PROX_NEAR_STAIRS)
+ return (true);
+
+ // (5) for each band monster, loop call to place_monster_aux().
+ for(i = 1; i < band_size; i++)
+ {
+ place_monster_aux( band_monsters[i], behaviour, target, px, py,
+ lev_mons, extra, false );
+ }
+
+ // placement of first monster, at least, was a success.
+ return (true);
+}
+
+static int place_monster_aux( int mon_type, char behaviour, int target,
+ int px, int py, int power, int extra,
+ bool first_band_member )
+{
+ int id, i;
+ char grid_wanted;
+ int fx=0, fy=0; // final x,y
+
+ // gotta be able to pick an ID
+ for (id = 0; id < MAX_MONSTERS; id++)
+ {
+ if (menv[id].type == -1)
+ break;
+ }
+
+ if (id == MAX_MONSTERS)
+ return -1;
+
+ // scrap monster inventory
+ for (i = 0; i < NUM_MONSTER_SLOTS; i++)
+ menv[id].inv[i] = NON_ITEM;
+
+ // scrap monster enchantments
+ for (i = 0; i < NUM_MON_ENCHANTS; i++)
+ menv[id].enchantment[i] = ENCH_NONE;
+
+ // setup habitat and placement
+ if (first_band_member)
+ {
+ fx = px;
+ fy = py;
+ }
+ else
+ {
+ grid_wanted = monster_habitat(mon_type);
+
+ // we'll try 1000 times for a good spot
+ for (i = 0; i < 1000; i++)
+ {
+ fx = px + random2(7) - 3;
+ fy = py + random2(7) - 3;
+
+ // occupied?
+ if (mgrd[fx][fy] != NON_MONSTER)
+ continue;
+
+ // compatible - floor?
+ if (grid_wanted == DNGN_FLOOR && grd[fx][fy] < DNGN_FLOOR)
+ continue;
+
+ // compatible - others (must match, except for deep water monsters
+ // generated in shallow water)
+ if ((grid_wanted != DNGN_FLOOR && grd[fx][fy] != grid_wanted)
+ && (grid_wanted != DNGN_DEEP_WATER || grd[fx][fy] != DNGN_SHALLOW_WATER))
+ continue;
+
+ // don't generate monsters on top of teleport traps
+ // (how do they get there?)
+ int trap = trap_at_xy(fx, fy);
+ if (trap >= 0)
+ if (env.trap[trap].type == TRAP_TELEPORT)
+ continue;
+
+ // cool.. passes all tests
+ break;
+ }
+
+ // did we really try 1000 times?
+ if (i == 1000)
+ return (-1);
+ }
+
+ // now, actually create the monster (wheeee!)
+ menv[id].type = mon_type;
+ menv[id].number = 250;
+
+ menv[id].x = fx;
+ menv[id].y = fy;
+
+ // link monster into monster grid
+ mgrd[fx][fy] = id;
+
+ // generate a brand shiny new monster, or zombie
+ if (mon_type == MONS_ZOMBIE_SMALL
+ || mon_type == MONS_ZOMBIE_LARGE
+ || mon_type == MONS_SIMULACRUM_SMALL
+ || mon_type == MONS_SIMULACRUM_LARGE
+ || mon_type == MONS_SKELETON_SMALL
+ || mon_type == MONS_SKELETON_LARGE
+ || mon_type == MONS_SPECTRAL_THING)
+ {
+ define_zombie( id, extra, mon_type, power );
+ }
+ else
+ {
+ define_monster(id);
+ }
+
+ // The return of Boris is now handled in monster_die()...
+ // not setting this for Boris here allows for multiple Borises
+ // in the dungeon at the same time. -- bwr
+ if (mon_type >= MONS_TERENCE && mon_type <= MONS_BORIS)
+ you.unique_creatures[mon_type - 280] = 1;
+
+ if (extra != 250)
+ menv[id].number = extra;
+
+ if (mons_flag(mon_type, M_INVIS))
+ mons_add_ench(&menv[id], ENCH_INVIS);
+
+ if (mons_flag(mon_type, M_CONFUSED))
+ mons_add_ench(&menv[id], ENCH_CONFUSION);
+
+ if (mon_type == MONS_SHAPESHIFTER)
+ mons_add_ench(&menv[id], ENCH_SHAPESHIFTER);
+
+ if (mon_type == MONS_GLOWING_SHAPESHIFTER)
+ mons_add_ench(&menv[id], ENCH_GLOWING_SHAPESHIFTER);
+
+ if (mon_type == MONS_GIANT_BAT || mon_type == MONS_UNSEEN_HORROR
+ || mon_type == MONS_GIANT_BLOWFLY)
+ {
+ menv[id].flags |= MF_BATTY;
+ }
+
+ if ((mon_type == MONS_BIG_FISH
+ || mon_type == MONS_GIANT_GOLDFISH
+ || mon_type == MONS_ELECTRICAL_EEL
+ || mon_type == MONS_JELLYFISH
+ || mon_type == MONS_WATER_ELEMENTAL
+ || mon_type == MONS_SWAMP_WORM)
+ && grd[fx][fy] == DNGN_DEEP_WATER
+ && !one_chance_in(5))
+ {
+ mons_add_ench( &menv[id], ENCH_SUBMERGED );
+ }
+
+ if ((mon_type == MONS_LAVA_WORM
+ || mon_type == MONS_LAVA_FISH
+ || mon_type == MONS_LAVA_SNAKE
+ || mon_type == MONS_SALAMANDER)
+ && grd[fx][fy] == DNGN_LAVA
+ && !one_chance_in(5))
+ {
+ mons_add_ench( &menv[id], ENCH_SUBMERGED );
+ }
+
+ menv[id].flags |= MF_JUST_SUMMONED;
+
+ if (mon_type == MONS_DANCING_WEAPON && extra != 1) // ie not from spell
+ {
+ give_item( id, power );
+
+ if (menv[id].inv[MSLOT_WEAPON] != NON_ITEM)
+ menv[id].number = mitm[ menv[id].inv[MSLOT_WEAPON] ].colour;
+ }
+ else if (mons_itemuse(mon_type) >= MONUSE_STARTING_EQUIPMENT)
+ {
+ give_item( id, power );
+
+ // Give these monsters a second weapon -- bwr
+ if (mon_type == MONS_TWO_HEADED_OGRE || mon_type == MONS_ETTIN)
+ {
+ give_item( id, power );
+ }
+ }
+
+
+ // give manticores 8 to 16 spike volleys.
+ // they're not spellcasters so this doesn't screw anything up.
+ if (mon_type == MONS_MANTICORE)
+ menv[id].number = 8 + random2(9);
+
+ // set attitude, behaviour and target
+ menv[id].attitude = ATT_HOSTILE;
+ menv[id].behaviour = behaviour;
+ menv[id].foe_memory = 0;
+
+ // setting attitude will always make the
+ // monster wander.. if you want sleeping
+ // hostiles, use BEH_SLEEP since the default
+ // attitude is hostile.
+ if (behaviour > NUM_BEHAVIOURS)
+ {
+ if (behaviour == BEH_FRIENDLY || behaviour == BEH_GOD_GIFT)
+ menv[id].attitude = ATT_FRIENDLY;
+
+ menv[id].behaviour = BEH_WANDER;
+ }
+
+ menv[id].foe = target;
+
+ return (id);
+} // end place_monster_aux()
+
+
+static int choose_band( int mon_type, int power, int &band_size )
+{
+ // init
+ band_size = 0;
+ int band = BAND_NO_BAND;
+
+ switch (mon_type)
+ {
+ case MONS_ORC:
+ if (coinflip())
+ break;
+ // intentional fall-through {dlb}
+ case MONS_ORC_WARRIOR:
+ band = BAND_ORCS; // orcs
+ band_size = 2 + random2(3);
+ break;
+
+ case MONS_BIG_KOBOLD:
+ if (power > 3)
+ {
+ band = BAND_KOBOLDS;
+ band_size = 2 + random2(6);
+ }
+ break;
+
+ case MONS_ORC_WARLORD:
+ band_size = 5 + random2(5); // warlords have large bands
+ // intentional fall through
+ case MONS_ORC_KNIGHT:
+ band = BAND_ORC_KNIGHT; // orcs + knight
+ band_size += 3 + random2(4);
+ break;
+
+ case MONS_KILLER_BEE:
+ band = BAND_KILLER_BEES; // killer bees
+ band_size = 2 + random2(4);
+ break;
+
+ case MONS_FLYING_SKULL:
+ band = BAND_FLYING_SKULLS; // flying skulls
+ band_size = 2 + random2(4);
+ break;
+ case MONS_SLIME_CREATURE:
+ band = BAND_SLIME_CREATURES; // slime creatures
+ band_size = 2 + random2(4);
+ break;
+ case MONS_YAK:
+ band = BAND_YAKS; // yaks
+ band_size = 2 + random2(4);
+ break;
+ case MONS_UGLY_THING:
+ band = BAND_UGLY_THINGS; // ugly things
+ band_size = 2 + random2(4);
+ break;
+ case MONS_HELL_HOUND:
+ band = BAND_HELL_HOUNDS; // hell hound
+ band_size = 2 + random2(3);
+ break;
+ case MONS_JACKAL:
+ band = BAND_JACKALS; // jackal
+ band_size = 1 + random2(3);
+ break;
+ case MONS_HELL_KNIGHT:
+ case MONS_MARGERY:
+ band = BAND_HELL_KNIGHTS; // hell knight
+ band_size = 4 + random2(4);
+ break;
+ case MONS_JOSEPHINE:
+ case MONS_NECROMANCER:
+ case MONS_VAMPIRE_MAGE:
+ band = BAND_NECROMANCER; // necromancer
+ band_size = 4 + random2(4);
+ break;
+ case MONS_ORC_HIGH_PRIEST:
+ band = BAND_ORC_HIGH_PRIEST; // orc high priest
+ band_size = 4 + random2(4);
+ break;
+ case MONS_GNOLL:
+ band = BAND_GNOLLS; // gnoll
+ band_size = ((coinflip())? 3 : 2);
+ break;
+ case MONS_BUMBLEBEE:
+ band = BAND_BUMBLEBEES; // bumble bees
+ band_size = 2 + random2(4);
+ break;
+ case MONS_CENTAUR:
+ case MONS_CENTAUR_WARRIOR:
+ if (power > 9 && one_chance_in(3))
+ {
+ band = BAND_CENTAURS; // centaurs
+ band_size = 2 + random2(4);
+ }
+ break;
+
+ case MONS_YAKTAUR:
+ case MONS_YAKTAUR_CAPTAIN:
+ if (coinflip())
+ {
+ band = BAND_YAKTAURS; // yaktaurs
+ band_size = 2 + random2(3);
+ }
+ break;
+
+ case MONS_DEATH_YAK:
+ band = BAND_DEATH_YAKS; // death yaks
+ band_size = 2 + random2(4);
+ break;
+ case MONS_INSUBSTANTIAL_WISP:
+ band = BAND_INSUBSTANTIAL_WISPS; // wisps
+ band_size = 4 + random2(5);
+ break;
+ case MONS_OGRE_MAGE:
+ band = BAND_OGRE_MAGE; // ogre mage
+ band_size = 4 + random2(4);
+ break;
+ case MONS_BALRUG:
+ band = BAND_BALRUG; // RED gr demon
+ band_size = 2 + random2(3);
+ break;
+ case MONS_CACODEMON:
+ band = BAND_CACODEMON; // BROWN gr demon
+ band_size = 1 + random2(3);
+ break;
+
+ case MONS_EXECUTIONER:
+ if (coinflip())
+ {
+ band = BAND_EXECUTIONER; // DARKGREY gr demon
+ band_size = 1 + random2(3);
+ }
+ break;
+
+ case MONS_HELLWING:
+ if (coinflip())
+ {
+ band = BAND_HELLWING; // LIGHTGREY gr demon
+ band_size = 1 + random2(4);
+ }
+ break;
+
+ case MONS_DEEP_ELF_FIGHTER:
+ if (coinflip())
+ {
+ band = BAND_DEEP_ELF_FIGHTER; // deep elf warrior
+ band_size = 3 + random2(4);
+ }
+ break;
+
+ case MONS_DEEP_ELF_KNIGHT:
+ if (coinflip())
+ {
+ band = BAND_DEEP_ELF_KNIGHT; // deep elf knight
+ band_size = 3 + random2(4);
+ }
+ break;
+
+ case MONS_DEEP_ELF_HIGH_PRIEST:
+ if (coinflip())
+ {
+ band = BAND_DEEP_ELF_HIGH_PRIEST; // deep elf high priest
+ band_size = 3 + random2(4);
+ }
+ break;
+
+ case MONS_KOBOLD_DEMONOLOGIST:
+ if (coinflip())
+ {
+ band = BAND_KOBOLD_DEMONOLOGIST; // kobold demonologist
+ band_size = 3 + random2(6);
+ }
+ break;
+
+ case MONS_NAGA_MAGE:
+ case MONS_NAGA_WARRIOR:
+ band = BAND_NAGAS; // Nagas
+ band_size = 3 + random2(4);
+ break;
+ case MONS_WAR_DOG:
+ band = BAND_WAR_DOGS; // war dogs
+ band_size = 2 + random2(4);
+ break;
+ case MONS_GREY_RAT:
+ band = BAND_GREY_RATS; // grey rats
+ band_size = 4 + random2(6);
+ break;
+ case MONS_GREEN_RAT:
+ band = BAND_GREEN_RATS; // green rats
+ band_size = 4 + random2(6);
+ break;
+ case MONS_ORANGE_RAT:
+ band = BAND_ORANGE_RATS; // orange rats
+ band_size = 3 + random2(4);
+ break;
+ case MONS_SHEEP:
+ band = BAND_SHEEP; // sheep
+ band_size = 3 + random2(5);
+ break;
+ case MONS_GHOUL:
+ band = BAND_GHOULS; // ghoul
+ band_size = 2 + random2(3);
+ break;
+ case MONS_HOG:
+ band = BAND_HOGS; // hog
+ band_size = 1 + random2(3);
+ break;
+ case MONS_GIANT_MOSQUITO:
+ band = BAND_GIANT_MOSQUITOES; // mosquito
+ band_size = 1 + random2(3);
+ break;
+ case MONS_DEEP_TROLL:
+ band = BAND_DEEP_TROLLS; // deep troll
+ band_size = 3 + random2(3);
+ break;
+ case MONS_HELL_HOG:
+ band = BAND_HELL_HOGS; // hell-hog
+ band_size = 1 + random2(3);
+ break;
+ case MONS_BOGGART:
+ band = BAND_BOGGARTS; // boggart
+ band_size = 2 + random2(3);
+ break;
+ case MONS_BLINK_FROG:
+ band = BAND_BLINK_FROGS; // blink frog
+ band_size = 2 + random2(3);
+ break;
+ case MONS_SKELETAL_WARRIOR:
+ band = BAND_SKELETAL_WARRIORS; // skeletal warrior
+ band_size = 2 + random2(3);
+ break;
+ } // end switch
+
+ if (band != BAND_NO_BAND && band_size == 0)
+ band = BAND_NO_BAND;
+
+ if (band_size >= BIG_BAND)
+ band_size = BIG_BAND-1;
+
+ return (band);
+}
+
+static int band_member(int band, int power)
+{
+ int mon_type = -1;
+ int temp_rand;
+
+ if (band == BAND_NO_BAND)
+ return -1;
+
+ switch (band)
+ {
+ case BAND_KOBOLDS:
+ mon_type = MONS_KOBOLD;
+ break;
+
+ case BAND_ORC_KNIGHT:
+ case BAND_ORC_HIGH_PRIEST:
+ temp_rand = random2(30);
+ mon_type = ((temp_rand > 17) ? MONS_ORC : // 12 in 30
+ (temp_rand > 8) ? MONS_ORC_WARRIOR : // 9 in 30
+ (temp_rand > 6) ? MONS_WARG : // 2 in 30
+ (temp_rand > 4) ? MONS_ORC_WIZARD : // 2 in 30
+ (temp_rand > 2) ? MONS_ORC_PRIEST : // 2 in 30
+ (temp_rand > 1) ? MONS_OGRE : // 1 in 30
+ (temp_rand > 0) ? MONS_TROLL // 1 in 30
+ : MONS_ORC_SORCERER); // 1 in 30
+ break;
+
+ case BAND_KILLER_BEES:
+ mon_type = MONS_KILLER_BEE;
+ break;
+
+ case BAND_FLYING_SKULLS:
+ mon_type = MONS_FLYING_SKULL;
+ break;
+
+ case BAND_SLIME_CREATURES:
+ mon_type = MONS_SLIME_CREATURE;
+ break;
+
+ case BAND_YAKS:
+ mon_type = MONS_YAK;
+ break;
+
+ case BAND_UGLY_THINGS:
+ mon_type = ((power > 21 && one_chance_in(4)) ?
+ MONS_VERY_UGLY_THING : MONS_UGLY_THING);
+ break;
+
+ case BAND_HELL_HOUNDS:
+ mon_type = MONS_HELL_HOUND;
+ break;
+
+ case BAND_JACKALS:
+ mon_type = MONS_JACKAL;
+ break;
+
+ case BAND_GNOLLS:
+ mon_type = MONS_GNOLL;
+ break;
+
+ case BAND_BUMBLEBEES:
+ mon_type = MONS_BUMBLEBEE;
+ break;
+
+ case BAND_CENTAURS:
+ mon_type = MONS_CENTAUR;
+ break;
+
+ case BAND_YAKTAURS:
+ mon_type = MONS_YAKTAUR;
+ break;
+
+ case BAND_INSUBSTANTIAL_WISPS:
+ mon_type = MONS_INSUBSTANTIAL_WISP;
+ break;
+
+ case BAND_DEATH_YAKS:
+ mon_type = MONS_DEATH_YAK;
+ break;
+
+ case BAND_NECROMANCER: // necromancer
+ temp_rand = random2(13);
+ mon_type = ((temp_rand > 9) ? MONS_ZOMBIE_SMALL : // 3 in 13
+ (temp_rand > 6) ? MONS_ZOMBIE_LARGE : // 3 in 13
+ (temp_rand > 3) ? MONS_SKELETON_SMALL : // 3 in 13
+ (temp_rand > 0) ? MONS_SKELETON_LARGE // 3 in 13
+ : MONS_NECROPHAGE); // 1 in 13
+ break;
+
+ case BAND_BALRUG:
+ mon_type = (coinflip()? MONS_NEQOXEC : MONS_ORANGE_DEMON);
+ break;
+
+ case BAND_CACODEMON:
+ mon_type = MONS_LEMURE;
+ break;
+
+ case BAND_EXECUTIONER:
+ mon_type = (coinflip() ? MONS_ABOMINATION_SMALL : MONS_ABOMINATION_LARGE);
+ break;
+
+ case BAND_HELLWING:
+ mon_type = (coinflip() ? MONS_HELLWING : MONS_SMOKE_DEMON);
+ break;
+
+ case BAND_DEEP_ELF_FIGHTER: // deep elf fighter
+ temp_rand = random2(11);
+ mon_type = ((temp_rand > 4) ? MONS_DEEP_ELF_SOLDIER : // 6 in 11
+ (temp_rand == 4) ? MONS_DEEP_ELF_FIGHTER : // 1 in 11
+ (temp_rand == 3) ? MONS_DEEP_ELF_KNIGHT : // 1 in 11
+ (temp_rand == 2) ? MONS_DEEP_ELF_CONJURER :// 1 in 11
+ (temp_rand == 1) ? MONS_DEEP_ELF_MAGE // 1 in 11
+ : MONS_DEEP_ELF_PRIEST); // 1 in 11
+ break;
+
+ case BAND_ORCS:
+ mon_type = MONS_ORC;
+ if (one_chance_in(5))
+ mon_type = MONS_ORC_WIZARD;
+ if (one_chance_in(7))
+ mon_type = MONS_ORC_PRIEST;
+ break;
+
+ case BAND_HELL_KNIGHTS:
+ mon_type = MONS_HELL_KNIGHT;
+ if (one_chance_in(4))
+ mon_type = MONS_NECROMANCER;
+ break;
+
+ //case 12 is orc high priest
+
+ case BAND_OGRE_MAGE:
+ mon_type = MONS_OGRE;
+ if (one_chance_in(3))
+ mon_type = MONS_TWO_HEADED_OGRE;
+ break; // ogre mage
+
+ // comment does not match value (30, TWO_HEADED_OGRE) prior to
+ // enum replacement [!!!] 14jan2000 {dlb}
+
+ case BAND_DEEP_ELF_KNIGHT: // deep elf knight
+ temp_rand = random2(208);
+ mon_type =
+ ((temp_rand > 159) ? MONS_DEEP_ELF_SOLDIER : // 23.08%
+ (temp_rand > 111) ? MONS_DEEP_ELF_FIGHTER : // 23.08%
+ (temp_rand > 79) ? MONS_DEEP_ELF_KNIGHT : // 15.38%
+ (temp_rand > 51) ? MONS_DEEP_ELF_MAGE : // 13.46%
+ (temp_rand > 35) ? MONS_DEEP_ELF_PRIEST : // 7.69%
+ (temp_rand > 19) ? MONS_DEEP_ELF_CONJURER : // 7.69%
+ (temp_rand > 3) ? MONS_DEEP_ELF_SUMMONER : // 7.69%
+ (temp_rand == 3) ? MONS_DEEP_ELF_DEMONOLOGIST :// 0.48%
+ (temp_rand == 2) ? MONS_DEEP_ELF_ANNIHILATOR : // 0.48%
+ (temp_rand == 1) ? MONS_DEEP_ELF_SORCERER // 0.48%
+ : MONS_DEEP_ELF_DEATH_MAGE); // 0.48%
+ break;
+
+ case BAND_DEEP_ELF_HIGH_PRIEST: // deep elf high priest
+ temp_rand = random2(16);
+ mon_type =
+ ((temp_rand > 12) ? MONS_DEEP_ELF_SOLDIER : // 3 in 16
+ (temp_rand > 9) ? MONS_DEEP_ELF_FIGHTER : // 3 in 16
+ (temp_rand > 6) ? MONS_DEEP_ELF_PRIEST : // 3 in 16
+ (temp_rand == 6) ? MONS_DEEP_ELF_MAGE : // 1 in 16
+ (temp_rand == 5) ? MONS_DEEP_ELF_SUMMONER : // 1 in 16
+ (temp_rand == 4) ? MONS_DEEP_ELF_CONJURER : // 1 in 16
+ (temp_rand == 3) ? MONS_DEEP_ELF_DEMONOLOGIST :// 1 in 16
+ (temp_rand == 2) ? MONS_DEEP_ELF_ANNIHILATOR : // 1 in 16
+ (temp_rand == 1) ? MONS_DEEP_ELF_SORCERER // 1 in 16
+ : MONS_DEEP_ELF_DEATH_MAGE); // 1 in 16
+ break;
+
+ case BAND_KOBOLD_DEMONOLOGIST:
+ temp_rand = random2(13);
+ mon_type = ((temp_rand > 4) ? MONS_KOBOLD : // 8 in 13
+ (temp_rand > 0) ? MONS_BIG_KOBOLD // 4 in 13
+ : MONS_KOBOLD_DEMONOLOGIST);// 1 in 13
+ break;
+
+ case BAND_NAGAS:
+ mon_type = MONS_NAGA;
+ break;
+ case BAND_WAR_DOGS:
+ mon_type = MONS_WAR_DOG;
+ break;
+ case BAND_GREY_RATS:
+ mon_type = MONS_GREY_RAT;
+ break;
+ case BAND_GREEN_RATS:
+ mon_type = MONS_GREEN_RAT;
+ break;
+ case BAND_ORANGE_RATS:
+ mon_type = MONS_ORANGE_RAT;
+ break;
+ case BAND_SHEEP:
+ mon_type = MONS_SHEEP;
+ break;
+ case BAND_GHOULS:
+ mon_type = (coinflip() ? MONS_GHOUL : MONS_NECROPHAGE);
+ break;
+ case BAND_DEEP_TROLLS:
+ mon_type = MONS_DEEP_TROLL;
+ break;
+ case BAND_HOGS:
+ mon_type = MONS_HOG;
+ break;
+ case BAND_HELL_HOGS:
+ mon_type = MONS_HELL_HOG;
+ break;
+ case BAND_GIANT_MOSQUITOES:
+ mon_type = MONS_GIANT_MOSQUITO;
+ break;
+ case BAND_BOGGARTS:
+ mon_type = MONS_BOGGART;
+ break;
+ case BAND_BLINK_FROGS:
+ mon_type = MONS_BLINK_FROG;
+ break;
+ case BAND_SKELETAL_WARRIORS:
+ mon_type = MONS_SKELETAL_WARRIOR;
+ break;
+ }
+
+ return (mon_type);
+}
+
+// PUBLIC FUNCTION -- mons_place().
+
+int mons_place( int mon_type, char behaviour, int target, bool summoned,
+ int px, int py, int level_type, int proximity, int extra )
+{
+ int mon_count = 0;
+ int temp_rand; // probabilty determination {dlb}
+ bool permit_bands = false;
+
+ for (int il = 0; il < MAX_MONSTERS; il++)
+ {
+ if (menv[il].type != -1)
+ mon_count++;
+ }
+
+ if (mon_type == WANDERING_MONSTER)
+ {
+ if (mon_count > 150)
+ return (-1);
+
+ mon_type = RANDOM_MONSTER;
+ }
+
+ // all monsters have been assigned? {dlb}
+ if (mon_count > MAX_MONSTERS - 2)
+ return (-1);
+
+ // this gives a slight challenge to the player as they ascend the
+ // dungeon with the Orb
+ if (you.char_direction == DIR_ASCENDING && mon_type == RANDOM_MONSTER
+ && you.level_type == LEVEL_DUNGEON)
+ {
+ temp_rand = random2(276);
+
+ mon_type = ((temp_rand > 184) ? MONS_WHITE_IMP + random2(15) : // 33.33%
+ (temp_rand > 104) ? MONS_HELLION + random2(10) : // 28.99%
+ (temp_rand > 78) ? MONS_HELL_HOUND : // 9.06%
+ (temp_rand > 54) ? MONS_ABOMINATION_LARGE : // 8.70%
+ (temp_rand > 33) ? MONS_ABOMINATION_SMALL : // 7.61%
+ (temp_rand > 13) ? MONS_RED_DEVIL // 7.25%
+ : MONS_PIT_FIEND); // 5.07%
+ }
+
+ if (mon_type == RANDOM_MONSTER || level_type == LEVEL_PANDEMONIUM)
+ permit_bands = true;
+
+ int mid = -1;
+
+ // translate level_type
+ int power;
+
+ switch (level_type)
+ {
+ case LEVEL_PANDEMONIUM:
+ power = 52; // sigh..
+ break;
+ case LEVEL_ABYSS:
+ power = 51;
+ break;
+ case LEVEL_DUNGEON: // intentional fallthrough
+ default:
+ power = you.your_level;
+ break;
+ }
+
+ if (place_monster( mid, mon_type, power, behaviour, target, summoned,
+ px, py, permit_bands, proximity, extra ) == false)
+ {
+ return (-1);
+ }
+
+ if (mid != -1)
+ {
+ struct monsters *const creation = &menv[mid];
+
+ // look at special cases: CHARMED, FRIENDLY, HOSTILE, GOD_GIFT
+ // alert summoned being to player's presence
+ if (behaviour > NUM_BEHAVIOURS)
+ {
+ if (behaviour == BEH_FRIENDLY || behaviour == BEH_GOD_GIFT)
+ creation->flags |= MF_CREATED_FRIENDLY;
+
+ if (behaviour == BEH_GOD_GIFT)
+ creation->flags |= MF_GOD_GIFT;
+
+ if (behaviour == BEH_CHARMED)
+ {
+ creation->attitude = ATT_HOSTILE;
+ mons_add_ench(creation, ENCH_CHARM);
+ }
+
+ // make summoned being aware of player's presence
+ behaviour_event(creation, ME_ALERT, MHITYOU);
+ }
+ }
+
+ return (mid);
+} // end mons_place()
+
+
+int create_monster( int cls, int dur, int beha, int cr_x, int cr_y,
+ int hitting, int zsec )
+{
+ int summd = -1;
+ FixedVector < char, 2 > empty;
+
+ unsigned char spcw = ((cls == RANDOM_MONSTER) ? DNGN_FLOOR
+ : monster_habitat( cls ));
+
+ empty[0] = 0;
+ empty[1] = 0;
+
+ // Might be better if we chose a space and tried to match the monster
+ // to it in the case of RANDOM_MONSTER, that way if the target square
+ // is surrounded by water of lava this function would work. -- bwr
+ if (empty_surrounds( cr_x, cr_y, spcw, true, empty ))
+ {
+ summd = mons_place( cls, beha, hitting, true, empty[0], empty[1],
+ you.level_type, 0, zsec );
+ }
+
+ // determine whether creating a monster is successful (summd != -1) {dlb}:
+ // then handle the outcome {dlb}:
+ if (summd == -1)
+ {
+ if (see_grid( cr_x, cr_y ))
+ mpr("You see a puff of smoke.");
+ }
+ else
+ {
+ struct monsters *const creation = &menv[summd];
+
+ // dur should always be ENCH_ABJ_xx
+ if (dur >= ENCH_ABJ_I && dur <= ENCH_ABJ_VI)
+ mons_add_ench(creation, dur );
+
+ // look at special cases: CHARMED, FRIENDLY, HOSTILE, GOD_GIFT
+ // alert summoned being to player's presence
+ if (beha > NUM_BEHAVIOURS)
+ {
+ if (beha == BEH_FRIENDLY || beha == BEH_GOD_GIFT)
+ creation->flags |= MF_CREATED_FRIENDLY;
+
+ if (beha == BEH_GOD_GIFT)
+ creation->flags |= MF_GOD_GIFT;
+
+ if (beha == BEH_CHARMED)
+ {
+ creation->attitude = ATT_HOSTILE;
+ mons_add_ench(creation, ENCH_CHARM);
+ }
+
+ // make summoned being aware of player's presence
+ behaviour_event(creation, ME_ALERT, MHITYOU);
+ }
+
+ if (creation->type == MONS_RAKSHASA_FAKE && !one_chance_in(3))
+ mons_add_ench(creation, ENCH_INVIS);
+ }
+
+ // the return value is either -1 (failure of some sort)
+ // or the index of the monster placed (if I read things right) {dlb}
+ return (summd);
+} // end create_monster()
+
+
+bool empty_surrounds(int emx, int emy, unsigned char spc_wanted,
+ bool allow_centre, FixedVector < char, 2 > &empty)
+{
+ bool success;
+ // assume all player summoning originates from player x,y
+ bool playerSummon = (emx == you.x_pos && emy == you.y_pos);
+
+ int xpos[25]; // good x pos
+ int ypos[25]; // good y pos
+ int good_count = 0;
+ int count_x, count_y;
+
+ char minx = -2;
+ char maxx = 2;
+ char miny = -2;
+ char maxy = 2;
+
+ for (count_x = minx; count_x <= maxx; count_x++)
+ {
+ for (count_y = miny; count_y <= maxy; count_y++)
+ {
+ success = false;
+
+ if (!allow_centre && count_x == 0 && count_y == 0)
+ continue;
+
+ int tx = emx + count_x;
+ int ty = emy + count_y;
+
+ if (tx == you.x_pos && ty == you.y_pos)
+ continue;
+
+ if (mgrd[tx][ty] != NON_MONSTER)
+ continue;
+
+ // players won't summon out of LOS
+ if (!see_grid(tx, ty) && playerSummon)
+ continue;
+
+ if (grd[tx][ty] == spc_wanted)
+ success = true;
+
+ // those seeking ground can stand in shallow water or better
+ if (spc_wanted == DNGN_FLOOR && grd[tx][ty] >= DNGN_SHALLOW_WATER)
+ success = true;
+
+ // water monsters can be created in shallow as well as deep water
+ if (spc_wanted == DNGN_DEEP_WATER && grd[tx][ty] == DNGN_SHALLOW_WATER)
+ success = true;
+
+ if (success)
+ {
+ // add point to list of good points
+ xpos[good_count] = tx;
+ ypos[good_count] = ty;
+ good_count ++;
+ }
+ } // end "for count_y"
+ } // end "for count_x"
+
+ if (good_count > 0)
+ {
+ int pick = random2(good_count);
+ empty[0] = xpos[pick];
+ empty[1] = ypos[pick];
+ }
+
+ return (good_count > 0);
+} // end empty_surrounds()
+
+int summon_any_demon(char demon_class)
+{
+ int summoned; // error trapping {dlb}
+ int temp_rand; // probability determination {dlb}
+
+ switch (demon_class)
+ {
+ case DEMON_LESSER:
+ temp_rand = random2(60);
+ summoned = ((temp_rand > 49) ? MONS_IMP : // 10 in 60
+ (temp_rand > 40) ? MONS_WHITE_IMP : // 9 in 60
+ (temp_rand > 31) ? MONS_LEMURE : // 9 in 60
+ (temp_rand > 22) ? MONS_UFETUBUS : // 9 in 60
+ (temp_rand > 13) ? MONS_MANES : // 9 in 60
+ (temp_rand > 4) ? MONS_MIDGE // 9 in 60
+ : MONS_SHADOW_IMP); // 5 in 60
+ break;
+
+ case DEMON_COMMON:
+ temp_rand = random2(3948);
+ summoned = ((temp_rand > 3367) ? MONS_NEQOXEC : // 14.69%
+ (temp_rand > 2787) ? MONS_ORANGE_DEMON : // 14.69%
+ (temp_rand > 2207) ? MONS_HELLWING : // 14.69%
+ (temp_rand > 1627) ? MONS_SMOKE_DEMON : // 14.69%
+ (temp_rand > 1047) ? MONS_YNOXINUL : // 14.69%
+ (temp_rand > 889) ? MONS_RED_DEVIL : // 4.00%
+ (temp_rand > 810) ? MONS_HELLION : // 2.00%
+ (temp_rand > 731) ? MONS_ROTTING_DEVIL : // 2.00%
+ (temp_rand > 652) ? MONS_TORMENTOR : // 2.00%
+ (temp_rand > 573) ? MONS_REAPER : // 2.00%
+ (temp_rand > 494) ? MONS_SOUL_EATER : // 2.00%
+ (temp_rand > 415) ? MONS_HAIRY_DEVIL : // 2.00%
+ (temp_rand > 336) ? MONS_ICE_DEVIL : // 2.00%
+ (temp_rand > 257) ? MONS_BLUE_DEVIL : // 2.00%
+ (temp_rand > 178) ? MONS_BEAST : // 2.00%
+ (temp_rand > 99) ? MONS_IRON_DEVIL : // 2.00%
+ (temp_rand > 49) ? MONS_SUN_DEMON // 1.26%
+ : MONS_SHADOW_IMP); // 1.26%
+ break;
+
+ case DEMON_GREATER:
+ temp_rand = random2(1000);
+ summoned = ((temp_rand > 868) ? MONS_CACODEMON : // 13.1%
+ (temp_rand > 737) ? MONS_BALRUG : // 13.1%
+ (temp_rand > 606) ? MONS_BLUE_DEATH : // 13.1%
+ (temp_rand > 475) ? MONS_GREEN_DEATH : // 13.1%
+ (temp_rand > 344) ? MONS_EXECUTIONER : // 13.1%
+ (temp_rand > 244) ? MONS_FIEND : // 10.0%
+ (temp_rand > 154) ? MONS_ICE_FIEND : // 9.0%
+ (temp_rand > 73) ? MONS_SHADOW_FIEND // 8.1%
+ : MONS_PIT_FIEND); // 7.4%
+ break;
+
+ default:
+ summoned = MONS_GIANT_ANT; // this was the original behaviour {dlb}
+ break;
+ }
+
+ return summoned;
+} // end summon_any_demon()
diff --git a/trunk/source/monplace.h b/trunk/source/monplace.h
new file mode 100644
index 0000000000..fc1595ee1e
--- /dev/null
+++ b/trunk/source/monplace.h
@@ -0,0 +1,79 @@
+/*
+ * File: monsplace.cc
+ * Summary: Functions used when placing monsters in the dungeon.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef MONPLACE_H
+#define MONPLACE_H
+
+#include "enum.h"
+#include "FixVec.h"
+
+// last updated 13mar2001 {gdl}
+/* ***********************************************************************
+ * called from: acr - lev-pand - monplace - dungeon
+ *
+ * Usage:
+ * mon_type WANDERING_MONSTER, RANDOM_MONSTER, or monster type
+ * behaviour standard behaviours (BEH_ENSLAVED, etc)
+ * target MHITYOU, MHITNOT, or monster id
+ * extra various things like skeleton/zombie types, colours, etc
+ * summoned monster is summoned?
+ * px placement x
+ * py placement y
+ * level_type LEVEL_DUNGEON, LEVEL_ABYSS, LEVEL_PANDEMONIUM.
+ * LEVEL_DUNGEON will generate appropriate power monsters
+ * proximity 0 = no extra restrictions on monster placement
+ * 1 = try to place the monster near the player
+ * 2 = don't place the monster near the player
+ * 3 = place the monster near stairs (regardless of player pos)
+ * *********************************************************************** */
+int mons_place( int mon_type, char behaviour, int target, bool summoned,
+ int px, int py, int level_type = LEVEL_DUNGEON,
+ int proximity = PROX_ANYWHERE, int extra = 250 );
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - debug - decks - effects - fight - it_use3 - item_use -
+ * items - monstuff - mstuff2 - religion - spell - spells -
+ * spells2 - spells3 - spells4
+ * *********************************************************************** */
+int create_monster( int cls, int dur, int beha, int cr_x, int cr_y,
+ int hitting, int zsec );
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: misc - monplace - spells3
+ * *********************************************************************** */
+bool empty_surrounds( int emx, int emy, unsigned char spc_wanted,
+ bool allow_centre, FixedVector<char, 2>& empty );
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - acr - items - maps - mstuff2 - spell - spells
+ * *********************************************************************** */
+int summon_any_demon( char demon_class );
+
+
+// last update 13mar2001 {gdl}
+/* ***********************************************************************
+ * called from: dungeon monplace
+ *
+ * This isn't really meant to be a public function. It is a low level
+ * monster placement function used by dungeon building routines and
+ * mons_place(). If you need to put a monster somewhere, use mons_place().
+ * Summoned creatures can be created with create_monster().
+ * *********************************************************************** */
+bool place_monster( int &id, int mon_type, int power, char behaviour,
+ int target, bool summoned, int px, int py, bool allow_bands,
+ int proximity = PROX_ANYWHERE, int extra = 250 );
+
+#endif // MONPLACE_H
diff --git a/trunk/source/monspeak.cc b/trunk/source/monspeak.cc
new file mode 100644
index 0000000000..09b348867d
--- /dev/null
+++ b/trunk/source/monspeak.cc
@@ -0,0 +1,2325 @@
+/*
+ * File: monspeak.cc
+ * Summary: Functions to handle speaking monsters
+ *
+ * Change History (most recent first):
+ *
+ * <1> 01/09/00 BWR Created
+ */
+
+#include "AppHdr.h"
+#include "monspeak.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#include "externs.h"
+
+#include "beam.h"
+#include "debug.h"
+#include "fight.h"
+#include "insult.h"
+#include "itemname.h"
+#include "misc.h"
+#include "monplace.h"
+#include "monstuff.h"
+#include "mon-util.h"
+#include "mstuff2.h"
+#include "player.h"
+#include "spells2.h"
+#include "spells4.h"
+#include "stuff.h"
+#include "view.h"
+
+// returns true if something is said
+bool mons_speaks(struct monsters *monster)
+{
+ int temp_rand; // probability determination
+
+ // This function is a little bit of a problem for the message channels
+ // since some of the messages it generates are "fake" warning to
+ // scare the player. In order to accomidate this intent, we're
+ // falsely categorizing various things in the function as spells and
+ // danger warning... everything else just goes into the talk channel -- bwr
+ int msg_type = MSGCH_TALK;
+
+ const char *m_name = ptr_monam(monster, DESC_CAP_THE);
+ strcpy(info, m_name);
+
+ if (mons_has_ench(monster, ENCH_INVIS))
+ return false;
+ // invisible monster tries to remain unnoticed
+
+ //mv: if it's also invisible, program never gets here
+ if (silenced(monster->x, monster->y))
+ {
+ if (!one_chance_in(3))
+ return false; // while silenced, don't bother so often
+
+ if (mons_has_ench(monster, ENCH_CONFUSION))
+ {
+ temp_rand = random2(10);
+ strcat(info, (temp_rand < 4) ? " gestures wildly." :
+ (temp_rand == 4) ? " looks confused." :
+ (temp_rand == 5) ? " grins evilly." :
+ (temp_rand == 6) ? " smiles happily." :
+ (temp_rand == 7) ? " cries."
+ : " says something but you don't hear anything.");
+ }
+ else if (monster->behaviour == BEH_FLEE)
+ {
+ temp_rand = random2(10);
+ strcat(info,
+ (temp_rand < 3) ? " glances furtively about." :
+ (temp_rand == 3) ? " opens its mouth, as if shouting." :
+ (temp_rand == 4) ? " looks around." :
+ (temp_rand == 5) ? " appears indecisive." :
+ (temp_rand == 6) ? " ponders the situation."
+ : " seems to says something.");
+ }
+ // disregard charmed critters.. they're not too expressive
+ else if (monster->attitude == ATT_FRIENDLY)
+ {
+ temp_rand = random2(10);
+ strcat(info, (temp_rand < 3) ? " gives you a thumbs up." :
+ (temp_rand == 3) ? " looks at you." :
+ (temp_rand == 4) ? " waves at you." :
+ (temp_rand == 5) ? " smiles happily.":
+ (temp_rand == 6) ? " winks at you."
+ : " says something you can't hear.");
+ }
+ else
+ {
+ temp_rand = random2(10);
+ strcat(info, (temp_rand < 3) ? " gestures." :
+ (temp_rand == 3) ? " gestures obscenely." :
+ (temp_rand == 4) ? " grins." :
+ (temp_rand == 5) ? " looks angry." :
+ (temp_rand == 6) ? " seems to be listening."
+ : " says something but you don't hear anything.");
+ } //end switch silenced monster's behaviour
+
+ mpr(info, MSGCH_TALK);
+ return true;
+ } // end silenced monster
+
+ // charmed monsters aren't too expressive
+ if (mons_has_ench(monster, ENCH_CHARM))
+ return false;
+
+ if (mons_has_ench(monster, ENCH_CONFUSION))
+ {
+ if (mons_holiness( monster->type ) == MH_DEMONIC
+ && monster->type != MONS_IMP)
+ {
+ return (false);
+ }
+
+ if (mons_friendly(monster))
+ {
+ switch (random2(18)) // speaks for friendly confused monsters
+ {
+ case 0:
+ strcat(info, " prays for help.");
+ break;
+ case 1:
+ strcat(info, " screams, \"Help!\"");
+ break;
+ case 2:
+ strcat(info, " shouts, \"I'm losing control!\"");
+ break;
+ case 3:
+ strcat(info, " shouts, \"What's happening?\"");
+ break;
+ case 4:
+ case 5:
+ strcat(info, " gestures wildly.");
+ break;
+ case 6:
+ strcat(info, " cries.");
+ break;
+ case 7:
+ strcat(info, " shouts, \"Yeah!\"");
+ break;
+ case 8:
+ strcat(info, " sings.");
+ break;
+ case 9:
+ strcat(info, " laughs crazily.");
+ break;
+ case 10:
+ strcat(info, " ponders the situation.");
+ break;
+ case 11:
+ strcat(info, " grins madly.");
+ break;
+ case 12:
+ strcat(info, " looks very confused.");
+ break;
+ case 13:
+ strcat(info, " mumbles something.");
+ break;
+ case 14:
+ strcat(info, " giggles crazily.");
+ break;
+ case 15:
+ strcat(info, " screams, \"");
+ strcat(info, you.your_name);
+ strcat(info, "! Help!\"");
+ break;
+ case 16:
+ strcat(info, " screams, \"");
+ strcat(info, you.your_name);
+ strcat(info, "! What's going on?\"");
+ break;
+ case 17:
+ strcat(info, " says, \"");
+ strcat(info, you.your_name);
+ strcat(info, ", I'm little bit confused.\"");
+ break;
+ }
+ }
+ else
+ {
+ switch (random2(23)) // speaks for unfriendly confused monsters
+ {
+ case 0:
+ strcat(info, " yells, \"Get them off of me!\"");
+ break;
+ case 1:
+ strcat(info, " screams, \"I will kill you anyway!\"");
+ break;
+ case 2:
+ strcat(info, " shouts, \"What's happening?\"");
+ break;
+ case 3:
+ case 4:
+ case 5:
+ strcat(info, " gestures wildly.");
+ break;
+ case 6:
+ strcat(info, " cries.");
+ break;
+ case 7:
+ strcat(info, " shouts, \"NO!\"");
+ break;
+ case 8:
+ strcat(info, " shouts, \"YES!\"");
+ break;
+ case 9:
+ strcat(info, " laughs crazily.");
+ break;
+ case 10:
+ strcat(info, " ponders the situation.");
+ break;
+ case 11:
+ strcat(info, " grins madly.");
+ break;
+ case 12:
+ strcat(info, " looks very confused.");
+ break;
+ case 13:
+ strcat(info, " mumbles something.");
+ break;
+ case 14:
+ strcat(info, " says, \"I'm little bit confused.\"");
+ break;
+ case 15:
+ strcat(info, " asks, \"Where am I?\"");
+ break;
+ case 16:
+ strcat(info, " shakes.");
+ break;
+ case 17:
+ strcat(info, " asks, \"Who are you?\"");
+ break;
+ case 18:
+ strcat(info, " asks, \"What the hell are we doing here? Mmm, I see...\"");
+ break;
+ case 19:
+ strcat(info, " cries, \"My head! MY HEAD!!!\"");
+ break;
+ case 20:
+ strcat(info, " says, \"Why is everything spinning?\"");
+ break;
+ case 21:
+ strcat(info, " screams, \"NO! I can't bear up that noise!\"");
+ break;
+ case 22:
+ strcat(info, " is trying to cover his eyes.");
+ break;
+ }
+ }
+
+ }
+ else if (monster->behaviour == BEH_FLEE)
+ {
+ if (mons_holiness( monster->type ) == MH_DEMONIC
+ && monster->type != MONS_IMP)
+ {
+ return (false);
+ }
+
+ if (mons_friendly(monster))
+ {
+ switch (random2(11))
+ {
+ case 0:
+ snprintf( info, INFO_SIZE, "%s %s, \"WAIT FOR ME!\"", m_name,
+ coinflip() ? "shouts" : "yells");
+ strcat(info, you.your_name);
+ strcat(info, ", could you help me?\"");
+ break;
+ case 1:
+ strcat(info, " screams, \"Help!\"");
+ break;
+ case 2:
+ strcat(info, " shouts, \"Cover me!\"");
+ break;
+ case 3:
+ strcat(info, " screams, \"");
+ strcat(info, you.your_name);
+ strcat(info, "! Help me!\"");
+ break;
+ case 4:
+ case 5:
+ case 6:
+ strcat(info, " tries to hide somewhere.");
+ break;
+ case 7:
+ strcat(info, " prays for help.");
+ break;
+ case 8:
+ strcat(info, " looks at you beseechingly.");
+ break;
+ case 9:
+ strcat(info, " shouts, \"Protect me!\"");
+ break;
+ case 10:
+ strcat(info, " cries, \"Don't forget your friends!\"");
+ break;
+ }
+ }
+ else
+ {
+ switch (random2(20)) // speaks for unfriendly fleeing monsters
+ {
+ case 0:
+ snprintf( info, INFO_SIZE, "%s %s, \"Help!\"", m_name, coinflip()? "yells" : "wails");
+ break;
+ case 1:
+ snprintf( info, INFO_SIZE, "%s %s, \"Help!\"", m_name,
+ coinflip() ? "cries" : "screams"); break;
+ case 2:
+ snprintf( info, INFO_SIZE, "%s %s, \"Why can't we all just get along?\"",
+ m_name, coinflip() ? "begs" : "pleads");
+ break;
+ case 3:
+ snprintf( info, INFO_SIZE, "%s %s trips in trying to escape.", m_name,
+ coinflip() ? "nearly" : "almost");
+ break;
+ case 4:
+ snprintf( info, INFO_SIZE, "%s %s, \"Of all the rotten luck!\"", m_name,
+ coinflip() ? "mutters" : "mumbles");
+ break;
+ case 5:
+ snprintf( info, INFO_SIZE, "%s %s, \"Oh dear! Oh dear!\"", m_name,
+ coinflip() ? "moans" : "wails");
+ case 6:
+ snprintf( info, INFO_SIZE, "%s %s, \"Damn and blast!\"", m_name,
+ coinflip() ? "mutters" : "mumbles");
+ break;
+ case 7:
+ strcat(info, " prays for help.");
+ break;
+ case 8:
+ strcat(info, " shouts, \"No! I'll never do that again!\"");
+ break;
+ case 9:
+ snprintf( info, INFO_SIZE, "%s %s", m_name,
+ coinflip() ? "begs for mercy." : "cries, \"Mercy!\"");
+ break;
+ case 10:
+ snprintf( info, INFO_SIZE, "%s %s, \"%s!\"", m_name,
+ coinflip() ? "blubbers" : "cries",
+ coinflip() ? "Mommeee" : "Daddeee");
+ break;
+ case 11:
+ snprintf( info, INFO_SIZE, "%s %s, \"Please don't kill me!\"", m_name,
+ coinflip() ? "begs" : "pleads");
+ break;
+ case 12:
+ snprintf( info, INFO_SIZE, "%s %s, \"Please don't hurt me!\"", m_name,
+ coinflip() ? "begs" : "pleads");
+ break;
+ case 13:
+ snprintf( info, INFO_SIZE, "%s %s, \"Please, I have a lot of children...\"",
+ m_name, coinflip() ? "begs" : "pleads");
+ break;
+ case 14:
+ strcat(info, " tries to recover lost courage.");
+ break;
+ case 15:
+ case 16:
+ case 17:
+ strcat(info, " gives up.");
+ break;
+ case 19:
+ snprintf( info, INFO_SIZE, "%s looks really %s.", m_name,
+ coinflip() ? "scared stiff" : "rattled");
+ break;
+ }
+ }
+ }
+ else if (mons_friendly(monster))
+ {
+ if (mons_holiness( monster->type ) == MH_DEMONIC
+ && monster->type != MONS_IMP)
+ {
+ return (false);
+ }
+
+ // friendly imps are too common so they speak very very rarely
+ if ((monster->type == MONS_IMP) && (random2(10)))
+ return (false);
+
+ switch (random2(18))
+ {
+ case 0:
+ strcat(info, " yells, \"Run! I'll cover you!\"");
+ break;
+ case 1:
+ strcat(info, " shouts, \"Die, monster!\"");
+ break;
+ case 2:
+ strcat(info, " says, \"It's nice to have friends.\"");
+ break;
+
+ case 3:
+ strcat(info, " looks at you.");
+ break;
+ case 4:
+ strcat(info, " smiles at you.");
+ break;
+ case 5:
+ strcat(info, " says, \"");
+ strcat(info, you.your_name);
+ strcat(info, ", you are my only friend.\"");
+ break;
+ case 6:
+ strcat(info, " says, \"");
+ strcat(info, you.your_name);
+ strcat(info, ", I like you.\"");
+ break;
+
+ case 7:
+ strcat(info, " waves at you.");
+ break;
+ case 8:
+ strcat(info, " says, \"Be careful!\"");
+ break;
+ case 9:
+ strcat(info, " says, \"Don't worry. I'm here with you.\"");
+ break;
+ case 10:
+ strcat(info, " smiles happily.");
+ break;
+ case 11:
+ strcat(info, " shouts, \"No mercy! Kill them all!");
+ break;
+ case 12:
+ strcat(info, " winks at you.");
+ break;
+ case 13:
+ strcat(info, " says, \"Me and you. It sounds cool.\"");
+ break;
+ case 14:
+ strcat(info, " says, \"I'll never leave you.\"");
+ break;
+ case 15:
+ strcat(info, " says, \"I would die for you.\"");
+ break;
+ case 16:
+ strcat(info, " shouts, \"Beware of monsters!\"");
+ break;
+ case 17:
+ strcat(info, " looks friendly.");
+ break;
+ }
+ }
+ else
+ {
+ switch (monster->type)
+ {
+ case MONS_TERENCE: // fighter who likes to kill
+ switch (random2(15))
+ {
+ case 0:
+ strcat(info, " screams, \"I'm going to kill you! \"");
+ break;
+ case 1:
+ strcat(info, " shouts, \"Now you die.\"");
+ break;
+ case 2:
+ strcat(info, " says, \"Rest in peace.\"");
+ break;
+ case 3:
+ snprintf( info, INFO_SIZE, "%s shouts, \"%s!!!\"",
+ m_name, coinflip() ? "ATTACK" : "DIE");
+ break;
+ case 4:
+ strcat(info, " says, \"How do you enjoy it?\"");
+ break;
+ case 5:
+ strcat(info, " shouts, \"Get ready for death!\"");
+ break;
+ case 6:
+ strcat(info, " says, \"You are history.\"");
+ break;
+ case 7:
+ strcat(info, " says, \"Do you want it fast or slow?.\"");
+ break;
+ case 8:
+ strcat(info, " says, \"Did you write a testament? You should...\"");
+ break;
+ case 9:
+ strcat(info, " says, \"Time to say good-bye...\"");
+ break;
+ case 10:
+ snprintf( info, INFO_SIZE, "%s says, \"Don't try to defend, it's %s.\"",
+ m_name, coinflip() ? "pointless" : "senseless");
+ break;
+ case 11:
+ strcat(info, " bares his teeth.");
+ break;
+ case 12:
+ snprintf( info, INFO_SIZE, "%s says, \"I'll show you few %s.\"",
+ m_name, coinflip() ? "tricks" : "ploys.");
+ break;
+ case 13:
+ strcat(info, " screams, \"I want your blood.\"");
+ break;
+ case 14:
+ strcat(info, " looks scornfully at you.");
+ break;
+ }
+ break; // end Terence
+
+ case MONS_EDMUND: // mercenaries guarding dungeon
+ case MONS_LOUISE:
+ case MONS_FRANCES:
+ case MONS_DUANE:
+ case MONS_ADOLF:
+ switch (random2(17))
+ {
+ case 0:
+ strcat(info, " screams, \"I'm going to kill you! Now!\"");
+ break;
+ case 1:
+ strcat(info,
+ " shouts, \"Return immediately or I'll kill you!\"");
+ break;
+ case 2:
+ strcat(info,
+ " says, \"Now you've reached the end of your journey!\"");
+ break;
+ case 3:
+ strcat(info,
+ " screams, \"One false step and I'll kill you!\"");
+ break;
+ case 4:
+ strcat(info, " says, \"Drop everything you've found here and return home.\"");
+ break;
+ case 5:
+ strcat(info, " shouts, \"You will never get the Orb.\"");
+ break;
+ case 6:
+ strcat(info, " looks very unfriendly.");
+ break;
+ case 7:
+ strcat(info, " looks very cold.");
+ break;
+ case 8:
+ strcat(info, " shouts, \"It's the end of the party!\"");
+ break;
+ case 9:
+ strcat(info, " says, \"Return every stolen item!\"");
+ break;
+ case 10:
+ strcat(info, " says, \"No trespassing is allowed here.\"");
+ break;
+ case 11:
+ strcat(info, " grins evilly.");
+ break;
+ case 12:
+ strcat(info, " screams, \"You must be punished!\"");
+ break;
+ case 13:
+ strcat(info, " says, \"It's nothing personal...\"");
+ break;
+ case 14:
+ strcat(info, " says, \"A dead adventurer is good adventurer.\"");
+ break;
+ case 15:
+ strcat(info, " says, \"Coming here was your last mistake.\"");
+ break;
+ case 16:
+ strcat(info, " shouts, \"Intruder!\"");
+ break;
+ }
+ break; // end Edmund & Co
+
+ case MONS_JOSEPH:
+ switch (random2(16))
+ {
+ case 0:
+ strcat(info, " smiles happily.");
+ break;
+ case 1:
+ strcat(info, " says, \"I'm happy to see you. And I'll be happy to kill you.\"");
+ break;
+ case 2:
+ strcat(info, " says, \"I've waited for this moment for such a long time.\"");
+ break;
+ case 3:
+ strcat(info,
+ " says, \"It's nothing personal but I have kill you.\"");
+ break;
+ case 5:
+ strcat(info, " says, \"You will never get the Orb, sorry.\"");
+ break;
+ case 9:
+ strcat(info, " shouts, \"I love to fight! I love killing!\"");
+ break;
+ case 10:
+ strcat(info,
+ " says, \"I'm here to kill trespassers. I like my job.\"");
+ break;
+ case 11:
+ strcat(info, " tries to grin evilly.");
+ break;
+ case 12:
+ strcat(info,
+ " says, \"You must be punished! Or... I want to punish you!\"");
+ break;
+ case 13:
+ strcat(info,
+ " sighs, \"Being guard is usually so boring...\"");
+ break;
+ case 14:
+ strcat(info, " shouts, \"At last some action!\"");
+ break;
+ case 15:
+ strcat(info, " shouts, \"Wow!\"");
+ break;
+ }
+ break; // end Joseph
+
+ case MONS_ORC_HIGH_PRIEST: // priest, servants of dark ancient god
+ case MONS_DEEP_ELF_HIGH_PRIEST:
+ switch (random2(9))
+ {
+ case 0:
+ case 1:
+ strcat(info, " prays.");
+ msg_type = MSGCH_MONSTER_SPELL;
+ break;
+
+ case 2:
+ strcat(info, " mumbles some strange prayers.");
+ msg_type = MSGCH_MONSTER_SPELL;
+ break;
+
+ case 3:
+ strcat(info,
+ " shouts, \"You are a heretic and must be destroyed.\"");
+ break;
+ case 4:
+ strcat(info, " says, \"All sinners must die.\"");
+ break;
+
+ case 5:
+ strcat(info, " looks excited.");
+ break;
+ case 6:
+ strcat(info, " says, \"You will make a fine sacrifice.\"");
+ break;
+ case 7:
+ strcat(info, " starts to sing a prayer.");
+ break;
+ case 8:
+ strcat(info, " shouts, \"You must be punished.\"");
+ break;
+ }
+ break; // end priests
+
+ case MONS_ORC_SORCERER: // hateful wizards, using strange powers
+ case MONS_DEEP_ELF_SORCERER:
+ case MONS_WIZARD:
+ switch (random2(19))
+ {
+ case 0:
+ case 1:
+ case 2:
+ strcat(info, " wildly gestures.");
+ mpr( info, MSGCH_MONSTER_SPELL );
+ if (coinflip())
+ canned_msg( MSG_NOTHING_HAPPENS );
+ else
+ canned_msg( MSG_YOU_RESIST );
+ return (true);
+
+ case 3:
+ case 4:
+ case 5:
+ strcat(info, " mumbles some strange words.");
+ mpr( info, MSGCH_MONSTER_SPELL );
+ if (coinflip())
+ canned_msg( MSG_NOTHING_HAPPENS );
+ else
+ canned_msg( MSG_YOU_RESIST );
+ return (true);
+
+ case 6:
+ strcat(info, " shouts, \"You can't withstand my power!\"");
+ break;
+
+ case 7:
+ strcat(info, " shouts, \"You are history.\"");
+ break;
+
+ case 8:
+ simple_monster_message( monster, " casts a spell.",
+ MSGCH_MONSTER_SPELL );
+
+ strcat(info, " becomes transparent for a moment.");
+ msg_type = MSGCH_MONSTER_ENCHANT;
+ break;
+
+ case 9:
+ strcat(info, " throws some strange powder towards you.");
+ msg_type = MSGCH_MONSTER_SPELL;
+ break;
+
+ case 10:
+ simple_monster_message( monster, " casts a spell.",
+ MSGCH_MONSTER_SPELL );
+
+ strcat(info, " glows brightly for a moment.");
+ msg_type = MSGCH_MONSTER_ENCHANT;
+ break;
+
+ case 11:
+ strcat(info, " says, \"argatax netranoch dertex\"");
+ msg_type = MSGCH_MONSTER_SPELL;
+ break;
+
+ case 12:
+ strcat(info, " says, \"dogrw nutew berg\"");
+ msg_type = MSGCH_MONSTER_SPELL;
+ break;
+
+ case 13:
+ strcat(info, " shouts, \"Entram moth deg ulag!\"");
+ msg_type = MSGCH_MONSTER_SPELL;
+ break;
+
+ case 14:
+ strcat(info, " casts a spell.");
+ mpr(info, MSGCH_MONSTER_SPELL);
+
+ strcpy(info, m_name);
+ strcat(info, " becomes larger for a moment.");
+ msg_type = MSGCH_MONSTER_ENCHANT;
+ break;
+
+ case 15:
+ strcat(info, " casts a spell.");
+ mpr(info, MSGCH_MONSTER_SPELL);
+
+ strcpy(info, m_name);
+ strcat(info, "'s fingertips starts to glow.");
+ msg_type = MSGCH_MONSTER_ENCHANT;
+ break;
+
+ case 16:
+ strcat(info, "'s eyes starts to glow.");
+ msg_type = MSGCH_MONSTER_SPELL;
+ break;
+
+ case 17:
+ strcat(info, " tries to paralyze you with his gaze.");
+ msg_type = MSGCH_MONSTER_SPELL;
+ break;
+
+ case 18:
+ strcat(info, " casts a spell.");
+ mpr(info, MSGCH_MONSTER_SPELL);
+ canned_msg( MSG_YOU_RESIST );
+ return (true);
+ }
+ break; // end wizards
+
+ case MONS_JESSICA: // sorceress disturbed by player
+ switch (random2(10))
+ {
+ case 0:
+ strcat(info, " grins evilly.");
+ break;
+ case 1:
+ strcat(info, " says, \"I'm really upset.\"");
+ break;
+ case 2:
+ strcat(info, " shouts, \"I don't like beings like you.\"");
+ break;
+ case 3:
+ strcat(info,
+ " shouts, \"Stop bothering me, or I'll kill you!\"");
+ break;
+ case 4:
+ strcat(info, " very coldly says, \"I hate your company.\"");
+ break;
+ case 5:
+ strcat(info, " mumbles something strange.");
+ msg_type = MSGCH_MONSTER_SPELL;
+ break;
+ case 6:
+ strcat(info, " looks very angry.");
+ break;
+ case 7:
+ strcat(info,
+ " shouts, \"You're disturbing me. I'll have kill you.\"");
+ break;
+ case 8:
+ strcat(info, " screams, \"You are a ghastly nuisance!\"");
+ break;
+ case 9:
+ strcat(info, " gestures wildly.");
+ msg_type = MSGCH_MONSTER_SPELL;
+ break;
+ }
+ break; // end Jessica
+
+ case MONS_SIGMUND: // mad old wizard
+ switch (random2(19))
+ {
+ case 0:
+ case 1:
+ case 2:
+ strcat(info, " laughs crazily.");
+ break;
+ case 3:
+ strcat(info, " says, \"Don't worry, I'll kill you fast.\"");
+ break;
+ case 4:
+ strcat(info, " grinds his teeth.");
+ break;
+ case 5:
+ strcat(info, " asks, \"Do you like me?\"");
+ break;
+ case 6:
+ strcat(info, " screams, \"Die, monster!\"");
+ break;
+ case 7:
+ strcat(info, " says, \"You will soon forget everything.\"");
+ break;
+ case 8:
+ strcat(info, " screams, \"You will never... NEVER!\"");
+ break;
+
+ case 9:
+ simple_monster_message( monster, " casts a spell.",
+ MSGCH_MONSTER_SPELL );
+
+ strcat(info, "'s eyes starts to glow with a red light. ");
+ msg_type = MSGCH_MONSTER_ENCHANT;
+ break;
+
+ case 10:
+ strcat(info, " says, \"Look in to my eyes.\"");
+ break;
+ case 11:
+ strcat(info, " says, \"I'm your fate.\"");
+ break;
+
+ case 12:
+ simple_monster_message( monster, " casts a spell.",
+ MSGCH_MONSTER_SPELL );
+
+ strcat(info, " is suddenly surrounded by pale blue light.");
+ msg_type = MSGCH_MONSTER_ENCHANT;
+ break;
+
+ case 13:
+ strcat(info, " tries to bite you.");
+ break;
+
+ case 14:
+ simple_monster_message( monster, " casts a spell.",
+ MSGCH_MONSTER_SPELL );
+
+ strcat(info, " is suddenly surrounded by pale green light.");
+ msg_type = MSGCH_MONSTER_ENCHANT;
+ break;
+
+ case 15:
+ strcat(info, " screams, \"I am the angel of Death!\"");
+ break;
+ case 16:
+ strcat(info, " screams, \"Only death can liberate you!\"");
+ break;
+ case 17:
+ strcat(info, " whispers, \"You'll know eternity soon...\"");
+ break;
+ case 18:
+ strcat(info, " screams, \"Don't try to resist!\"");
+ break;
+ }
+ break; // end Sigmund
+
+ case MONS_IMP: // small demon
+ case MONS_WHITE_IMP:
+ case MONS_SHADOW_IMP:
+ if (one_chance_in(3))
+ {
+ imp_taunt( monster );
+ return (true);
+ }
+ else
+ {
+ switch (random2(11))
+ {
+ case 0:
+ strcat(info, " laughs crazily.");
+ break;
+ case 1:
+ strcat(info, " grins evilly.");
+ break;
+ case 2:
+ strcat(info, " breathes a bit of smoke at you.");
+ break;
+ case 3:
+ strcat(info, " lashes with his tail.");
+ break;
+ case 4:
+ strcat(info, " grinds his teeth.");
+ break;
+ case 5:
+ strcat(info, " sputters.");
+ break;
+ case 6:
+ strcat(info, " breathes some steam toward you.");
+ break;
+ case 7:
+ strcat(info, " spits at you.");
+ break;
+ case 8:
+ strcat(info, " disappears for a moment.");
+ break;
+ case 9:
+ strcat(info, " summons a swarm of flies.");
+ break;
+ case 10:
+ strcat(info, " picks up some beetle and eats it.");
+ break;
+ }
+ }
+ break; // end imp
+
+ case MONS_TORMENTOR: // cruel devil
+ if (one_chance_in(10))
+ {
+ demon_taunt( monster );
+ return (true);
+ }
+ else
+ {
+ switch (random2(18))
+ {
+ case 0:
+ strcat(info, " laughs crazily.");
+ break;
+ case 1:
+ strcat(info, " grins evilly.");
+ break;
+ case 2:
+ strcat(info, " says, \"I am all your nightmares come true.\"");
+ break;
+ case 3:
+ strcat(info, " says, \"I will show you what pain is.\"");
+ break;
+ case 4:
+ strcat(info, " shouts, \"I'll tear you apart.\"");
+ break;
+ case 5:
+ strcat(info,
+ " says, \"You will wish to die when I get to you.\"");
+ break;
+ case 6:
+ strcat(info, " says, \"I will drown you in your own blood.\"");
+ break;
+ case 7:
+ strcat(info,
+ " screams, \"You will die horribly!\"");
+ break;
+ case 8:
+ strcat(info, " says, \"I will eat your liver.\"");
+ break;
+ case 9:
+ strcat(info, " grins madly.");
+ break;
+ case 10:
+ strcat(info, " shouts, \"Prepare for my thousand needles of pain!\"");
+ break;
+ case 11:
+ strcat(info,
+ " says, \"I know thousand and one way to kill you.\"");
+ break;
+ case 12:
+ strcat(info,
+ " says, \"I'll show you my torture chamber!\"");
+ break;
+ case 13:
+ case 14:
+ strcat(info,
+ " says, \"I'll crush your bones, one by one.\"");
+ break;
+ case 15:
+ strcat(info, " says, \"I know your fate. It's pain.\"");
+ break;
+ case 16:
+ strcat(info, " says, \"Get ready! Throes await you.\"");
+ break;
+ case 17:
+ strcat(info, " grins malevolently.");
+ break;
+ }
+ }
+ break; // end tormentor
+
+ case MONS_PANDEMONIUM_DEMON: // named demons
+ case MONS_GERYON:
+ case MONS_ASMODEUS:
+ case MONS_DISPATER:
+ case MONS_ANTAEUS:
+ case MONS_ERESHKIGAL:
+ case MONS_MNOLEG:
+ case MONS_LOM_LOBON:
+ case MONS_CEREBOV:
+ case MONS_GLOORX_VLOQ:
+ demon_taunt( monster );
+ return (true);
+
+ case MONS_PLAYER_GHOST: // ghost of unsuccesful player
+ switch (random2(24))
+ {
+ case 0:
+ strcat(info, " laughs crazily.");
+ break;
+
+ case 1:
+ strcat(info, " grins evilly.");
+ break;
+
+ case 2:
+ strcat(info, " shouts, \"You will never get the ORB!\"");
+ break;
+
+ case 3: // mv: ghosts are usually wailing, aren't ?
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ strcat(info, " wails.");
+ break;
+
+ case 12:
+ strcat(info, " stares at you.");
+ mpr(info, MSGCH_MONSTER_SPELL);
+ mpr("You feel cold.", MSGCH_WARN);
+ return (true);
+
+ case 13:
+ strcat(info, " screams, \"You will join me soon!\"");
+ break;
+ case 14:
+ strcat(info, " wails, \"To die, to sleep, no more.\"");
+ break; //Hamlet
+ case 15:
+ strcat(info,
+ " screams, \"You must not succeed where I failed.\"");
+ break;
+ case 16:
+ strcat(info,
+ " screams, \"I'll kill anyone who wants the ORB.\"");
+ break;
+ case 17:
+ strcat(info, " whispers, \"Meet emptiness of death!\"");
+ break;
+ case 18:
+ strcat(info, " whispers, \"Death is liberation.\"");
+ break;
+ case 19:
+ strcat(info,
+ " whispers, \"Everlasting silence awaits you.\"");
+ break;
+ case 20:
+ strcat(info,
+ " screams, \"Don't try to defend. You have no chance!\"");
+ break;
+ case 21:
+ strcat(info,
+ " whispers, \"Death doesn't hurt. What you feel is life.\"");
+ break;
+ case 22:
+ strcat(info, " whispers, \"The ORB doesn't exist.\"");
+ break;
+ case 23:
+ strcat(info, " wails, \"Death is your only future.\"");
+ break;
+ }
+ break; // end players ghost
+
+ case MONS_PSYCHE: // insane girl
+ switch (random2(20))
+ {
+ case 0:
+ strcat(info, " smiles happily.");
+ break;
+ case 1:
+ strcat(info, " giggles crazily.");
+ break;
+ case 2:
+ strcat(info, " cries.");
+ break;
+ case 3:
+ strcat(info, " stares at you for a moment.");
+ break;
+ case 4:
+ strcat(info, " sings.");
+ break;
+ case 5:
+ strcat(info,
+ " says, \"Please, could you die a little faster?\"");
+ break;
+ case 6:
+ strcat(info,
+ " says, \"I'm bad girl. But I can't do anything about it.\"");
+ break;
+ case 7:
+ strcat(info,
+ " screams, \"YOU ARE VIOLATING AREA SECURITY!\"");
+ break;
+ case 8:
+ strcat(info, " cries, \"I hate blood and violence.\"");
+ break;
+ case 9:
+ strcat(info,
+ " screams, \"Peace! Flowers! Freedom! Dead adventurers!\"");
+ break;
+ case 10:
+ strcat(info,
+ " says, \"I'm so lonely. Only corpses are my friends.\"");
+ break;
+ case 11:
+ strcat(info, " cries, \"You've killed my pet.\"");
+ break;
+ case 12:
+ strcat(info,
+ " cries, \"You want to steal my orb collection?!\"");
+ break;
+ case 13:
+ strcat(info, " sings some strange song.");
+ break;
+ case 14:
+ strcat(info, " bursts in tears.");
+ break;
+ case 15:
+ strcat(info, " sucks her thumb.");
+ break;
+ case 16:
+ strcat(info,
+ " whispers, \"Hold me, thrill me, kiss me, kill me.\"");
+ break; //(c) U2 ?
+ case 17:
+ strcat(info, " says, \"I'll kill you and take you home.\"");
+ break;
+ case 18:
+ strcat(info,
+ " shouts, \"Well, maybe I'm nutty, but who cares?\"");
+ break;
+ case 19:
+ strcat(info,
+ " shouts, \"I hope that you are sorry for that.\"");
+ break;
+ }
+ break; // end Psyche
+
+ case MONS_DONALD: // adventurers hating competition
+ case MONS_WAYNE:
+ switch (random2(11))
+ {
+ case 0:
+ strcat(info, " screams, \"Return home!\"");
+ break;
+ case 1:
+ strcat(info, " screams, \"The Orb is mine!\"");
+ break;
+ case 2:
+ strcat(info, " screams, \"Give me all your treasure!\"");
+ break;
+ case 3:
+ strcat(info, " screams, \"You will never get the Orb!\"");
+ break;
+ case 4:
+ strcat(info, " screams, \"I was here first!\"");
+ break;
+ case 5:
+ strcat(info, " frowns.\"");
+ break;
+ case 6:
+ strcat(info, " looks very upset.");
+ break;
+ case 7:
+ strcat(info, " screams, \"Get away or die!\"");
+ break;
+ case 8:
+ strcat(info, " screams, \"Die!\"");
+ break;
+ case 9:
+ strcat(info, " screams, \"First you have to pass me!\"");
+ break;
+ case 10:
+ strcat(info, " screams, \"I hate you!\"");
+ break;
+ }
+ break; // end Donald
+
+ case MONS_MICHAEL: // spellcaster who wanted to be alone
+ switch (random2(11))
+ {
+ case 0:
+ strcat(info, " looks very angry.");
+ break;
+ case 1:
+ strcat(info, " frowns.");
+ break;
+ case 2:
+ strcat(info, " screams, \"I want to be alone!\"");
+ break;
+ case 3:
+ strcat(info, " says, \"You are really nuisance.\"");
+ break;
+ case 4:
+ strcat(info,
+ " screams, \"I wanted to be alone. And you...\"");
+ break;
+ case 5:
+ strcat(info, " screams, \"Get away! Or better yet, die!\"");
+ break;
+ case 6:
+ strcat(info, " mumbles some strange words.");
+ msg_type = MSGCH_MONSTER_SPELL;
+ break;
+
+ case 7:
+ strcat(info, " points at you.");
+ mpr(info, MSGCH_MONSTER_SPELL);
+ canned_msg(MSG_YOU_RESIST);
+ return (true);
+
+ case 8:
+ strcat(info, " shakes with wrath.");
+ break;
+ case 9:
+ strcat(info, " drinks a potion.");
+ break;
+ case 10:
+ strcat(info, " gestures wildly.");
+ msg_type = MSGCH_MONSTER_SPELL;
+ break;
+ }
+ break; // end Michael
+
+ case MONS_ERICA: // wild tempered adventuress
+ switch (random2(12))
+ {
+ case 0:
+ strcat(info, " screams, \"Die!\"");
+ break;
+ case 1:
+ strcat(info, " screams, \"Do you want it fast or slow?\"");
+ break;
+ case 2:
+ strcat(info, " looks angry.");
+ break;
+ case 3:
+ strcat(info, " drinks a potion.");
+ break;
+ case 4:
+ strcat(info, " says, \"I'm so much better than you.\"");
+ break;
+ case 5:
+ strcat(info,
+ " says, \"Fast and perfect. Such is my way of killing.\"");
+ break;
+ case 6:
+ strcat(info, " screams, \"Hurry! Death awaits!\"");
+ break;
+ case 7:
+ strcat(info, " laughs wildly.");
+ break;
+ case 8:
+ strcat(info, " screams, \"I'll never tell where it is!\"");
+ break;
+ case 9:
+ strcat(info, " screams, \"You'll never get it!\"");
+ break;
+ case 10:
+ strcat(info, " screams, \"Coming here was suicide!\"");
+ break;
+ case 11:
+ strcat(info,
+ " says, \"I love to fight, but killing is better.\"");
+ break;
+ }
+ break; // end Erica
+
+ case MONS_JOSEPHINE: // ugly old witch looking for somone to kill
+ switch (random2(13))
+ {
+ case 0:
+ case 1:
+ case 2:
+ strcat(info, " grins evilly.");
+ break;
+ case 3:
+ case 4:
+ strcat(info, " screams, \"I will kill you!\"");
+ break;
+ case 5:
+ strcat(info, " grinds her teeth.");
+ break;
+ case 6:
+ strcat(info, " grins malevolently.");
+ break;
+ case 7:
+ strcat(info, " laughs insanely.");
+ break;
+ case 8:
+ strcat(info, " screams, \"Die!\"");
+ break;
+ case 9:
+ strcat(info,
+ " screams, \"I have something special for you!\"");
+ break;
+ case 10:
+ strcat(info,
+ " screams, \"I'll use your head as decoration in my hut!\"");
+ break;
+ case 11:
+ strcat(info, " says, \"I'll make a rug of your skin.\"");
+ break;
+ case 12:
+ strcat(info, " says, \"How about some decapitation?\"");
+ break;
+ }
+ break; // end Josephine
+
+ case MONS_HAROLD: // middle aged man, hired to kill you. He is in a hurry.
+ switch (random2(11))
+ {
+ case 0:
+ strcat(info, " looks nervous.");
+ break;
+ case 1:
+ strcat(info, " screams, \"Hurry up!\"");
+ break;
+ case 2:
+ strcat(info, " screams, \"Could you die faster?\"");
+ break;
+ case 3:
+ strcat(info,
+ " says, \"Stand still. I'm trying to kill you.\"");
+ break;
+ case 4:
+ strcat(info, " screams, \"Die!\"");
+ break;
+ case 5:
+ strcat(info, " says, \"I hope you die soon!\"");
+ break;
+ case 6:
+ strcat(info,
+ " says, \"Only few hits and it's over.\".");
+ break;
+ case 7:
+ strcat(info, " says, \"You know, I'm in a hurry.\"");
+ break;
+ case 8:
+ strcat(info, " screams, \"I'll finish you soon!\"");
+ break;
+ case 9:
+ strcat(info, " screams, \"Don't delay it.\"");
+ break;
+ case 11:
+ strcat(info, " says, \"Mine is not to reason why. Mine's to do, yours to die.\"" );
+ }
+ break; // end Harold
+
+ // skilled warrior looking for some fame. More deads = more fame
+ case MONS_NORBERT:
+ switch (random2(13))
+ {
+ case 0:
+ strcat(info, " smiles happily.");
+ break;
+ case 1:
+ strcat(info, " screams, \"Die, monster!\"");
+ break;
+ case 2:
+ strcat(info, " screams, \"I'm a hero!\"");
+ break;
+ case 3:
+ strcat(info, " shouts, \"YES! Another notch!\"");
+ break;
+ case 4:
+ strcat(info, " says, \"A pity your head will make such an ugly trophy.\"");
+ break;
+ case 5:
+ strcat(info,
+ " screams, \"Pray, because you'll die soon!\"");
+ break;
+ case 6:
+ strcat(info,
+ " asks \"Did you write a will? You should.\".");
+ break;
+ case 7:
+ strcat(info,
+ " says, \"I love killing ugly monsters like you.\"");
+ break;
+ case 8:
+ strcat(info, " screams, \"Blood and destruction!\"");
+ break;
+ case 9:
+ strcat(info, " says, \"You know, it's honour to die by my hand.\"");
+ break;
+ case 10:
+ strcat(info, " shouts, \"Your time has come!\"");
+ break;
+ case 11:
+ strcat(info,
+ " says, \"I'm sorry but you don't have a chance.\"");
+ break;
+ case 12:
+ strcat(info,
+ " says, \"Another dead monster... It must be my lucky day!\"");
+ break;
+ }
+ break; // end Norbert
+
+ case MONS_JOZEF: // bounty hunter
+ switch (random2(14))
+ {
+ case 0:
+ strcat(info, " looks satisfied.");
+ break;
+ case 1:
+ strcat(info, " screams, \"Die!\"");
+ break;
+ case 2:
+ strcat(info, " screams, \"At last I found you!\"");
+ break;
+ case 3:
+ strcat(info, " shouts, \"I'll get 500 for your head!\"");
+ break;
+ case 4:
+ strcat(info,
+ " says, \"You don't look worth for that money.\"");
+ break;
+ case 5:
+ strcat(info,
+ " says, \"It's nothing personal. I'm paid for it!\"");
+ break;
+ case 6:
+ strcat(info,
+ " asks \"Did you write a testament? You should.\"");
+ break;
+ case 7:
+ strcat(info, " says, \"You are ");
+ strcat(info, you.your_name);
+ strcat(info, ", aren't you?.\"");
+ break;
+ case 8:
+ strcat(info, " says, \"I suppose that you are ");
+ strcat(info, you.your_name);
+ strcat(info, ". Sorry, if I'm wrong.\"");
+ break;
+ case 9:
+ strcat(info, " says, \"One dead ");
+ strcat(info, you.your_name);
+ strcat(info, ", 500 gold pieces. It's in my contract.\"");
+ break;
+ case 10:
+ strcat(info, " shouts, \"Your time has come!\"");
+ break;
+ case 11:
+ strcat(info,
+ " says, \"My job is sometimes very exciting. Sometimes...\"");
+ break;
+ case 12:
+ strcat(info, " says, \"I think I deserve my money.\"");
+ break;
+ case 13:
+ strcat(info,
+ " screams, \"Die! I've got more contracts today.\"");
+ break;
+ }
+ break; // end Jozef
+
+ case MONS_AGNES: // she is trying to get money and treasure
+ switch (random2(10))
+ {
+ case 0:
+ strcat(info, " screams, \"Give me all your money!\"");
+ break;
+ case 1:
+ strcat(info, " screams, \"All treasure is mine!\"");
+ break;
+ case 2:
+ strcat(info, " screams, \"You'll never get my money!\"");
+ break;
+ case 3:
+ strcat(info, " grins evilly.");
+ break;
+ case 4:
+ strcat(info,
+ " screams, \"Give me everything and get away!\"");
+ break;
+ case 5:
+ strcat(info,
+ " says, \"I need new robe. I'll buy it from your money.\"");
+ break;
+ case 6:
+ strcat(info,
+ " screams, \"I want your rings! And amulets! And... EVERYTHING!\"");
+ break;
+ case 7:
+ strcat(info,
+ " screams, \"I hate dirty adventurers like you.\"");
+ break;
+ case 8:
+ strcat(info, " says, \"How can you wear that ugly dress?\"");
+ break;
+ case 9:
+ strcat(info, " screams, \"Die, beast!\"");
+ break;
+ }
+ break; // end Agnes
+
+ case MONS_MAUD: // warrior princess looking for sword "Entarex"
+ switch (random2(11))
+ {
+ case 0:
+ strcat(info, " screams, \"Submit or die!\"");
+ break;
+ case 1:
+ strcat(info, " screams, \"Give me \"Entarex\"!\"");
+ break;
+ case 2:
+ strcat(info,
+ " screams, \"If you give me \"Entarex\", I'll let you live!\"");
+ break;
+ case 3:
+ strcat(info, " frowns.");
+ break;
+ case 4:
+ strcat(info, " looks upset.");
+ break;
+ case 5:
+ strcat(info, " screams, \"You can't face my power!\"");
+ break;
+ case 6:
+ strcat(info,
+ " screams, \"Give me that sword! Immediately!\"");
+ break;
+ case 7:
+ strcat(info,
+ " screams, \"Your life or \"Entarex\"! You must choose.\"");
+ break;
+ case 8:
+ strcat(info, " screams, \"I want it!\"");
+ break;
+ case 9:
+ strcat(info, " screams, \"Die, you thief!\"");
+ break;
+ case 10:
+ // needed at least one in here to tie to the amnesia
+ // scroll reference -- bwr
+ strcat(info, " asks \"Will you think of me as you die?\"");
+ break;
+ }
+ break; // end Maud
+
+ // wizard looking for bodyparts as spell components
+ case MONS_FRANCIS:
+ switch (random2(15))
+ {
+ case 0:
+ strcat(info,
+ " says, \"You've nice eyes. I could use them.\"");
+ break;
+ case 1:
+ strcat(info, " says, \"Excuse me, but I need your head.\"");
+ break;
+ case 2:
+ strcat(info, " says, \"I only need a few of your organs!\"");
+ break;
+ case 3:
+ strcat(info, " ponders the situation.");
+ break;
+ case 4:
+ strcat(info, " looks for scalpel.");
+ break;
+
+ case 5:
+ simple_monster_message( monster, " casts a spell",
+ MSGCH_MONSTER_SPELL );
+
+ strcat(info, "'s hands started to glow with soft light.");
+ msg_type = MSGCH_MONSTER_ENCHANT;
+ break;
+
+ case 6:
+ strcat(info, " says, \"This won't hurt a bit.\"");
+ break;
+ case 7:
+ strcat(info, " throws something at you.");
+ break;
+ case 8:
+ strcat(info, " says, \"I want you in my laboratory!\"");
+ break;
+ case 9:
+ strcat(info, " says, \"What about little dissection?\"");
+ break;
+ case 10:
+ strcat(info,
+ " says, \"I have something special for you.\"");
+ break;
+ case 11:
+ strcat(info,
+ " screams, \"Don't move! I want to cut your ear!\"");
+ break;
+ case 12:
+ strcat(info,
+ " says, \"What about your heart? Do you need it?\"");
+ break;
+ case 13:
+ strcat(info,
+ " says, \"Did you know that corpses are an important natural resource?\"");
+ break;
+ case 14:
+ strcat(info,
+ " says, \"Don't worry, I'll only take what I need.\"");
+ break;
+ }
+ break; // end Francis
+
+ case MONS_RUPERT: // crazy adventurer
+ switch (random2(11))
+ {
+ case 0:
+ strcat(info, " says, \"You are a monster, aren't you?\"");
+ break;
+ case 1:
+ strcat(info, " screams, \"Die, monster!\"");
+ break;
+ case 2:
+ strcat(info, " screams, \"Give me Holy Grail!\"");
+ break;
+ case 3:
+ strcat(info, " screams, \"Red! No, blue!\"");
+ break;
+ case 4:
+ strcat(info, " looks confused.");
+ break;
+ case 5:
+ strcat(info, " looks excited.");
+ break;
+ case 6:
+ strcat(info, " shouts, \"I'm great and powerful hero!\"");
+ break;
+ case 7:
+ strcat(info,
+ " screams, \"Get ready! I'll kill you! Or something like it...\"");
+ break;
+ case 8:
+ strcat(info,
+ " says, \"My Mom always said, kill them all.\"");
+ break;
+ case 9:
+ strcat(info,
+ " screams, \"You killed all those lovely monsters, you murderer!\"");
+ break;
+ case 10:
+ strcat(info, " screams, \"Hurray!\"");
+ break;
+ }
+ break; // end Rupert
+
+ case MONS_NORRIS: // enlighten but crazy man
+ switch (random2(24))
+ {
+ case 0:
+ strcat(info, " sings \"Hare Rama, Hare Krishna!\"");
+ break;
+ case 1:
+ strcat(info, " smiles at you.");
+ break;
+ case 2:
+ strcat(info,
+ " says, \"After death you'll find inner peace.\"");
+ break;
+ case 3:
+ strcat(info,
+ " says, \"Life is just suffering. I'll help you.\"");
+ break;
+ case 4:
+ strcat(info, " is surrounded with aura of peace.");
+ break;
+ case 5:
+ strcat(info, " looks very balanced.");
+ break;
+ case 6:
+ strcat(info, " says, \"Don't resist. I'll do it for you.\"");
+ break;
+ case 7:
+ strcat(info, " screams, \"Enter NIRVANA! Now!\"");
+ break;
+ case 8:
+ strcat(info, " says, \"Death is just a liberation!\"");
+ break;
+ case 9:
+ strcat(info,
+ " says, \"Feel free to die. It's great thing.\"");
+ break;
+ case 10:
+ strcat(info, " says, \"OHM MANI PADME HUM!\"");
+ break;
+
+ case 11:
+ strcat(info, " mumbles some mantras.");
+ msg_type = MSGCH_MONSTER_SPELL;
+ break;
+
+ case 12:
+ strcat(info, " says, \"Breath deeply.\"");
+ break;
+ case 13:
+ strcat(info, " screams, \"Love! Eternal love!\"");
+ break;
+ case 14:
+ strcat(info,
+ " screams, \"Peace! I bring you eternal peace!\"");
+ break;
+ case 15:
+ strcat(info,
+ " sighs \"Enlightenment is such responsibility.\"");
+ break;
+ case 16:
+ strcat(info, " looks relaxed.");
+ break;
+ case 17:
+ strcat(info, " screams, \"Free your soul! Die!\"");
+ break;
+ case 18:
+ strcat(info, " screams, \"Blow your mind!\"");
+ break;
+ case 19:
+ strcat(info,
+ " says, \"The Orb is only a myth. Forget about it.\"");
+ break;
+ case 20:
+ strcat(info, " says, \"It's all maya.\"");
+ break;
+ case 21:
+ strcat(info, " says, \"Drop out!\"");
+ break;
+ case 22:
+ strcat(info,
+ " sings, \"Peace now, freedom now! Peace now, freedom now!\"");
+ break;
+ case 23:
+ strcat(info, " says, \"This is called Combat Meditation.\"");
+ break;
+ }
+ break; // end Norris
+
+ case MONS_MARGERY: // powerful sorceress, guarding the ORB
+ switch (random2(22))
+ {
+ case 0:
+ strcat(info, " says, \"You are dead.\"");
+ break;
+ case 1:
+ strcat(info, " looks very self-confident.");
+ break;
+ case 2:
+ strcat(info, " screams, \"You must be punished!\"");
+ break;
+ case 3:
+ strcat(info, " screams, \"You can't withstand my power!\"");
+ break;
+
+ case 4:
+ simple_monster_message( monster, " casts a spell.",
+ MSGCH_MONSTER_SPELL );
+
+ strcat(info, " is surrounded with aura of power.");
+ msg_type = MSGCH_MONSTER_ENCHANT;
+ break;
+
+ case 5:
+ strcat(info, "'s eyes starts to glow with a red light.");
+ break;
+ case 6:
+ strcat(info,
+ "'s eyes starts to glow with a green light.");
+ break;
+ case 7:
+ strcat(info, "'s eyes starts to glow with a blue light.");
+ break;
+ case 8:
+ strcat(info, " screams, \"All trespassers must die!\"");
+ break;
+ case 9:
+ strcat(info, " says, \"Die!\"");
+ break;
+ case 10:
+ strcat(info, " screams, \"You'll have to get past me!\"");
+ break;
+
+ case 11:
+ simple_monster_message( monster, " casts a spell.",
+ MSGCH_MONSTER_SPELL );
+
+ strcat(info, " becomes transparent for a moment.");
+ msg_type = MSGCH_MONSTER_ENCHANT;
+ break;
+
+ case 12:
+ strcat(info, " gestures.");
+ msg_type = MSGCH_MONSTER_SPELL;
+ break;
+
+ case 13:
+ simple_monster_message( monster, " casts a spell.",
+ MSGCH_MONSTER_SPELL );
+
+ strcat(info, "'s hands start to glow.");
+ msg_type = MSGCH_MONSTER_ENCHANT;
+ break;
+
+ case 14:
+ strcat(info, " screams, \"Ergichanteg reztahaw!\"");
+ mpr(info, MSGCH_MONSTER_SPELL);
+ mpr("You feel really bad.", MSGCH_WARN);
+ return (true);
+
+ case 15:
+ strcat(info, " screams, \"You are doomed!\"");
+ break;
+ case 16:
+ strcat(info, " screams, \"Nothing can help you.\"");
+ break;
+ case 17:
+ strcat(info, " screams, \"Death is my middle name!\"");
+ break;
+
+ case 18:
+ strcat(info, " gestures.");
+ mpr(info, MSGCH_MONSTER_SPELL);
+ mpr("You feel doomed.", MSGCH_WARN);
+ return (true);
+
+ case 19:
+ strcat(info, " gestures.");
+ mpr(info, MSGCH_MONSTER_SPELL);
+ mpr("You feel weakened.", MSGCH_WARN);
+ return (true);
+
+ case 20:
+ strcat(info, " throws some purple powder towards you.");
+ mpr(info, MSGCH_MONSTER_SPELL);
+ mpr("You feel cursed.", MSGCH_WARN);
+ return (true);
+
+ case 21:
+ strcat(info,
+ " screams, \"The ORB is only a tale, but I will kill you anyway!");
+ break;
+ }
+ break; // end Margery
+
+ case MONS_IJYB: // twisted goblin
+ switch (random2(14))
+ {
+ case 0:
+ strcat(info, " screams, \"Die!\"");
+ break;
+ case 1:
+ strcat(info, " screams, \"Me kill you!\"");
+ break;
+ case 2:
+ strcat(info, " screams, \"Me stronger than you!\"");
+ break;
+ case 3:
+ case 4:
+ strcat(info, " grins evilly.");
+ break;
+ case 5:
+ strcat(info, " screams, \"It's all mine!\"");
+ break;
+ case 6:
+ strcat(info, " screams, \"Get away!\"");
+ break;
+ case 7:
+ strcat(info, " screams, \"Level is mine! All mine!\"");
+ break;
+ case 8:
+ strcat(info, " screams, \"I cut your head off!\"");
+ break;
+ case 9:
+ strcat(info, " screams, \"I dance on your bones!\"");
+ break;
+ case 10:
+ strcat(info, " screams, \"Me very upset!\"");
+ break;
+ case 11:
+ strcat(info, " screams, \"You nasty! Big nasty!\"");
+ break;
+ case 12:
+ strcat(info, " screams, \"No! No, no, no, no!\"");
+ break;
+ case 13:
+ strcat(info, " screams, \"I no like you!\"");
+ break;
+ }
+ break; // end IJYB
+
+ case MONS_BLORK_THE_ORC: // unfriendly orc
+ switch (random2(21))
+ {
+ case 0:
+ strcat(info, " screams, \"I don't like you!\"");
+ break;
+ case 1:
+ strcat(info, " screams, \"I'm going to kill you!\"");
+ break;
+ case 2:
+ strcat(info,
+ " screams, \"I'm much stronger than you!\"");
+ break;
+ case 3:
+ case 4:
+ strcat(info, " grins evilly.");
+ break;
+ case 5:
+ strcat(info, " frowns.");
+ break;
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ strcat(info, " looks angry.");
+ break;
+ case 10:
+ strcat(info,
+ " screams, \"I'll eat your brain! And then I'll vomit it back up!\"");
+ break;
+ case 11:
+ strcat(info,
+ " screams, \"You are the ugliest creature I've ever seen!\"");
+ break;
+ case 12:
+ strcat(info, " screams, \"I'll cut your head off!\"");
+ break;
+ case 13:
+ strcat(info, " screams, \"I'll break your legs!\"");
+ break;
+ case 14:
+ strcat(info, " screams, \"I'll break your arms!\"");
+ break;
+ case 15:
+ strcat(info,
+ " screams, \"I'll crush all your ribs! One by one!\"");
+ break;
+ case 16:
+ strcat(info,
+ " screams, \"I'll make a cloak from your skin!\"");
+ break;
+ case 17:
+ strcat(info,
+ " screams, \"I'll decorate my home with your organs!\"");
+ break;
+ case 18:
+ strcat(info, " screams, \"Die!\"");
+ break;
+ case 19:
+ strcat(info,
+ " screams, \"I'll cover the dungeon with your blood!\"");
+ break;
+ case 20:
+ strcat(info, " screams, \"I'll drink your blood! Soon!\"");
+ break;
+ }
+ break; // end Blork
+
+ case MONS_EROLCHA: // ugly ogre
+ switch (random2(11))
+ {
+ case 0:
+ strcat(info, " tries to grin evilly.");
+ break;
+ case 1:
+ strcat(info, " screams, \"Eat!\"");
+ break;
+ case 2:
+ strcat(info, " screams, \"Stand! Erolcha hit you!\"");
+ break;
+ case 3:
+ strcat(info, " screams, \"Blood!\"");
+ break;
+ case 4:
+ strcat(info, " screams, \"Erolcha kill you!\"");
+ break;
+ case 5:
+ strcat(info,
+ " screams, \"Erolcha crush your head!\"");
+ break;
+ case 6:
+ strcat(info, " roars.");
+ break;
+ case 7:
+ strcat(info, " growls.");
+ break;
+ case 8:
+ strcat(info, " screams, \"Lunch!\"");
+ break;
+ case 9:
+ strcat(info, " screams, \"Erolcha happy to kill you!\"");
+ break;
+ case 10:
+ strcat(info, " screams, \"Erolcha angry!\"");
+ break;
+ }
+ break; // end Erolcha
+
+ case MONS_URUG: // orc hired to kill you
+ switch (random2(11))
+ {
+ case 0:
+ strcat(info, " grins evilly.");
+ break;
+ case 1:
+ strcat(info, " screams, \"Die!\"");
+ break;
+ case 2:
+ strcat(info, " screams, \"I'm going to kill you! Now!\"");
+ break;
+ case 3:
+ strcat(info, " screams, \"Blood and destruction!\"");
+ break;
+ case 4:
+ strcat(info,
+ " sneers, \"Innocent? I'll kill you anyway.\"");
+ break;
+ case 5:
+ strcat(info,
+ " screams, \"I'll get 30 silver pieces for your head!\"");
+ break;
+ case 6:
+ strcat(info, " roars.");
+ break;
+ case 7:
+ strcat(info, " howls with blood-lust.");
+ break;
+ case 8:
+ strcat(info, " screams, \"You are already dead.\"");
+ break;
+ case 9:
+ strcat(info, " says, \"Maybe you aren't ");
+ strcat(info, you.your_name);
+ strcat(info, ". It doesn't matter.\"");
+ break;
+ case 10:
+ strcat(info, " screams, \"I love blood!\"");
+ break;
+ }
+ break; // end Urug
+
+ case MONS_SNORG: // troll
+ switch (random2(16))
+ {
+ case 0:
+ strcat(info, " grins.");
+ break;
+ case 1:
+ case 2:
+ case 3:
+ strcat(info, " smells terrible.");
+ break;
+ case 4:
+ case 5:
+ case 6:
+ strcat(info, " looks very hungry.");
+ break;
+ case 7:
+ strcat(info, " screams, \"Snack!\"");
+ break;
+ case 8:
+ strcat(info, " roars.");
+ break;
+ case 9:
+ strcat(info, " says, \"Food!\"");
+ break;
+ case 10:
+ strcat(info, " screams, \"Snorg hungry!\"");
+ break;
+ case 11:
+ strcat(info, " screams, \"Snorg very, very hungry!\"");
+ case 12:
+ strcat(info, " says, \"Snorg eat you.\"");
+ break;
+ case 13:
+ strcat(info, " says, \"You food?\"");
+ break;
+ case 14:
+ strcat(info, " says, \"Yum, yum.\"");
+ break;
+ case 15:
+ strcat(info, " burps.");
+ break;
+ }
+ break; // end Snorg
+
+ case MONS_XTAHUA: // ancient dragon
+ switch (random2(13))
+ {
+ case 0:
+ strcat(info, " roars, \"DIE, PUNY ONE!\"");
+ break;
+ case 1:
+ strcat(info, " growls, \"YOU BORE ME SO.\"");
+ break;
+ case 2:
+ strcat(info, " rumbles, \"YOU'RE BARELY A SNACK.\"");
+ break;
+ case 3:
+ strcat(info, " roars, \"I HATE BEING BOTHERED!\"");
+ break;
+ case 4:
+ strcat(info, " roars, \"I HOPE YOU'RE TASTY!\"");
+ break;
+ case 5:
+ strcat(info, " roars, \"BAH! BLOODY ADVENTURERS.\"");
+ break;
+ case 6:
+ strcat(info, " roars, \"FACE MY WRATH!\"");
+ break;
+ case 7:
+ strcat(info, " glares at you.");
+ break;
+ case 8:
+ strcat(info,
+ " roars, \"COMING HERE WAS YOUR LAST MISTAKE!\"");
+ break;
+ case 9:
+ strcat(info,
+ " roars, \"I'VE KILLED HUNDREDS OF ADVENTURERS!\"");
+ break;
+ case 10:
+ case 11:
+ case 12:
+ strcat(info, " roars horribly.");
+ mpr(info, MSGCH_TALK);
+ mpr("You are afraid.", MSGCH_WARN);
+ return (true);
+ }
+ break; // end Xtahua
+
+ case MONS_BORIS: // ancient lich
+ switch (random2(24))
+ {
+ case 0:
+ strcat(info, " says, \"I didn't invite you.\"");
+ break;
+ case 1:
+ strcat(info, " says, \"You can't imagine my power.\"");
+ break;
+ case 2:
+ strcat(info,
+ " says, \"Orb? You want the Orb? You'll never get it.\"");
+ break;
+
+ case 3:
+ strcat(info, " says, \"The world, the flesh, and the devil.\"");
+ break;
+
+ case 4:
+ strcat(info, " gestures.");
+ break;
+
+ case 5:
+ strcat(info, " stares at you.");
+ mpr(info, MSGCH_MONSTER_SPELL);
+ mpr("You feel drained.", MSGCH_WARN);
+ return (true);
+
+ case 6:
+ strcat(info, " stares at you.");
+ mpr(info, MSGCH_MONSTER_SPELL);
+ mpr("You feel weakened.", MSGCH_WARN);
+ return (true);
+
+ case 7:
+ strcat(info, " stares at you.");
+ mpr(info, MSGCH_MONSTER_SPELL);
+ mpr("You feel troubled.", MSGCH_WARN);
+ return (true);
+
+ case 8:
+ strcat(info, " says \"Magic. You know nothing about it.\"");
+ break;
+
+ case 9:
+ strcat(info, " says, \"My power is unlimited.\"");
+ break;
+ case 10:
+ strcat(info, " says, \"You can't kill me. I'm immortal.\"");
+ break;
+
+ case 11:
+ strcat(info, " casts a spell.");
+ mpr(info, MSGCH_MONSTER_SPELL);
+ mpr("Your equipment suddenly seems to weigh more.", MSGCH_WARN);
+ return (true);
+
+ case 12:
+ strcat(info,
+ " says, \"I know the secret of eternal life. Do you?\"");
+ break;
+ case 13:
+ strcat(info, " says, \"I'll be back.\"");
+ break;
+
+ case 14:
+ strcat(info, " casts a spell.");
+ mpr(info, MSGCH_MONSTER_SPELL);
+ canned_msg( MSG_YOU_RESIST );
+ return (true);
+
+ case 15:
+ strcat(info, " casts a spell.");
+ mpr(info, MSGCH_MONSTER_SPELL);
+ mpr("Suddenly you are surrounded with pale green light.", MSGCH_WARN);
+ return (true);
+
+ case 16:
+ strcat(info, " casts a spell.");
+ mpr(info, MSGCH_MONSTER_SPELL);
+ mpr("You have terrible head-ache.", MSGCH_WARN);
+ return (true);
+
+ case 17:
+ strcat(info,
+ " says, \"I know your future. Your future is death.\"");
+ break;
+ case 18:
+ strcat(info, " says, \"Who wants to live forever? Me.\"");
+ break;
+ case 19:
+ strcat(info, " laughs.");
+ break;
+ case 20:
+ strcat(info, " says, \"Join the legion of my servants.\"");
+ break;
+ case 21:
+ strcat(info, " says, \"There's only one solution for you. To die.\"");
+ break;
+ case 22:
+ strcat(info, " says, \"You can never win.\"");
+ break;
+ case 23:
+ simple_monster_message( monster, " casts a spell.",
+ MSGCH_MONSTER_SPELL );
+
+ strcat( info, " speeds up." );
+ msg_type = MSGCH_MONSTER_ENCHANT;
+ break;
+ }
+ break; // end BORIS
+
+
+ case MONS_DEATH_COB:
+ if (one_chance_in(2000))
+ {
+ mpr("The death cob makes a corny joke.", MSGCH_TALK);
+ return (true);
+ }
+ return (false);
+
+ case MONS_KILLER_KLOWN: // Killer Klown - guess!
+ switch (random2(10))
+ {
+ case 0:
+ strcat(info, " giggles crazily.");
+ break;
+ case 1:
+ strcat(info, " laughs merrily.");
+ break;
+ case 2:
+ strcat(info, " beckons to you.");
+ break;
+ case 3:
+ strcat(info, " does a flip.");
+ break;
+ case 4:
+ strcat(info, " does a somersault.");
+ break;
+ case 5:
+ strcat(info, " smiles at you.");
+ break;
+ case 6:
+ strcat(info, " grins with merry abandon.");
+ break;
+ case 7:
+ strcat(info, " howls with blood-lust!");
+ break;
+ case 8:
+ strcat(info, " pokes out its tongue.");
+ break;
+ case 9:
+ strcat(info, " says, \"Come and play with me!\"");
+ break;
+ }
+ break; // end Killer Klown
+
+ default:
+ strcat(info,
+ " says, \"I don't know what to say. It's a bug.\"");
+ break;
+ } // end monster->type - monster type switch
+ } // end default
+
+ mpr(info, msg_type);
+ return true;
+} // end mons_speaks = end of routine
diff --git a/trunk/source/monspeak.h b/trunk/source/monspeak.h
new file mode 100644
index 0000000000..7a6559b04e
--- /dev/null
+++ b/trunk/source/monspeak.h
@@ -0,0 +1,8 @@
+#ifndef MONSPEAK_H
+#define MONSPEAK_H
+
+#include "externs.h"
+
+bool mons_speaks(struct monsters *monster);
+
+#endif
diff --git a/trunk/source/monstuff.cc b/trunk/source/monstuff.cc
new file mode 100644
index 0000000000..f2af9744a4
--- /dev/null
+++ b/trunk/source/monstuff.cc
@@ -0,0 +1,4949 @@
+/*
+ * File: monstuff.cc
+ * Summary: Misc monster related functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <8> 7 Aug 2001 MV Inteligent monsters now pick up gold
+ * <7> 26 Mar 2001 GDL Fixed monster reaching
+ * <6> 13 Mar 2001 GDL Rewrite of monster AI
+ * <5> 31 July 2000 GDL More Manticore fixes.
+ * <4> 29 July 2000 JDJ Fixed a bunch of places in handle_pickup where MSLOT_WEAPON
+ * was being erroneously used.
+ * <3> 25 July 2000 GDL Fixed Manticores
+ * <2> 11/23/99 LRH Upgraded monster AI
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "monstuff.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#include "externs.h"
+
+#include "beam.h"
+#include "cloud.h"
+#include "debug.h"
+#include "dungeon.h"
+#include "fight.h"
+#include "itemname.h"
+#include "items.h"
+#include "misc.h"
+#include "monplace.h"
+#include "monspeak.h"
+#include "mon-util.h"
+#include "mstuff2.h"
+#include "player.h"
+#include "randart.h"
+#include "religion.h"
+#include "spl-cast.h"
+#include "spells2.h"
+#include "spells4.h"
+#include "stuff.h"
+#include "view.h"
+
+static bool handle_special_ability(struct monsters *monster, bolt & beem);
+static bool handle_pickup(struct monsters *monster);
+static void handle_behaviour(struct monsters *monster);
+static void mons_in_cloud(struct monsters *monster);
+static void monster_move(struct monsters *monster);
+static bool plant_spit(struct monsters *monster, struct bolt &pbolt);
+static int map_wand_to_mspell(int wand_type);
+
+char mmov_x, mmov_y;
+
+static int compass_x[8] = { -1, 0, 1, 1, 1, 0, -1, -1 };
+static int compass_y[8] = { -1, -1, -1, 0, 1, 1, 1, 0 };
+
+#define FAR_AWAY 1000000 // used in monster_move()
+
+// This function creates an arteficial item to represent a mimic's appearance.
+// Eventually, mimics could be redone to be more like Dancing wepaons...
+// there'd only be one type and it would look like the item it carries. -- bwr
+void get_mimic_item( const struct monsters *mimic, item_def &item )
+{
+ ASSERT( mimic != NULL && mons_is_mimic( mimic->type ) );
+
+ item.base_type = OBJ_UNASSIGNED;
+ item.sub_type = 0;
+ item.special = 0;
+ item.colour = 0;
+ item.flags = 0;
+ item.quantity = 1;
+ item.plus = 0;
+ item.plus2 = 0;
+ item.x = mimic->x;
+ item.y = mimic->y;
+ item.link = NON_ITEM;
+
+ int prop = 127 * mimic->x + 269 * mimic->y;
+
+ switch (mimic->type)
+ {
+ case MONS_WEAPON_MIMIC:
+ item.base_type = OBJ_WEAPONS;
+ item.sub_type = (59 * mimic->x + 79 * mimic->y) % NUM_WEAPONS;
+
+ prop %= 100;
+
+ if (prop < 20)
+ {
+ item.flags |= ISFLAG_RANDART;
+ item.special = ((mimic->x << 8 + mimic->y) & RANDART_SEED_MASK);
+ }
+ else if (prop < 50)
+ set_equip_desc( item, ISFLAG_GLOWING );
+ else if (prop < 80)
+ set_equip_desc( item, ISFLAG_RUNED );
+ else if (prop < 85)
+ set_equip_race( item, ISFLAG_ORCISH );
+ else if (prop < 90)
+ set_equip_race( item, ISFLAG_DWARVEN );
+ else if (prop < 95)
+ set_equip_race( item, ISFLAG_ELVEN );
+ break;
+
+ case MONS_ARMOUR_MIMIC:
+ item.base_type = OBJ_ARMOUR;
+ item.sub_type = (59 * mimic->x + 79 * mimic->y) % NUM_ARMOURS;
+
+ prop %= 100;
+
+ if (prop < 20)
+ {
+ item.flags |= ISFLAG_RANDART;
+ item.special = ((mimic->x << 8 + mimic->y) & RANDART_SEED_MASK);
+ }
+ else if (prop < 40)
+ set_equip_desc( item, ISFLAG_GLOWING );
+ else if (prop < 60)
+ set_equip_desc( item, ISFLAG_RUNED );
+ else if (prop < 80)
+ set_equip_desc( item, ISFLAG_EMBROIDERED_SHINY );
+ else if (prop < 85)
+ set_equip_race( item, ISFLAG_ORCISH );
+ else if (prop < 90)
+ set_equip_race( item, ISFLAG_DWARVEN );
+ else if (prop < 95)
+ set_equip_race( item, ISFLAG_ELVEN );
+ break;
+
+ case MONS_SCROLL_MIMIC:
+ item.base_type = OBJ_SCROLLS;
+ item.sub_type = prop % NUM_SCROLLS;
+ break;
+
+ case MONS_POTION_MIMIC:
+ item.base_type = OBJ_POTIONS;
+ item.sub_type = prop % NUM_POTIONS;
+ break;
+
+ case MONS_GOLD_MIMIC:
+ default:
+ item.base_type = OBJ_GOLD;
+ item.quantity = 5 + prop % 30;
+ break;
+ }
+
+ item_colour( item ); // also sets special vals for scrolls/poitions
+}
+
+// Sets the colour of a mimic to match its description... should be called
+// whenever a mimic is created or teleported. -- bwr
+int get_mimic_colour( struct monsters *mimic )
+{
+ ASSERT( mimic != NULL && mons_is_mimic( mimic->type ) );
+
+ if (mimic->type == MONS_SCROLL_MIMIC)
+ return (LIGHTGREY);
+ else if (mimic->type == MONS_GOLD_MIMIC)
+ return (YELLOW);
+
+ item_def item;
+ get_mimic_item( mimic, item );
+
+ return (item.colour);
+}
+
+// monster curses a random player inventory item:
+bool curse_an_item( char which, char power )
+{
+ UNUSED( power );
+
+ /* use which later, if I want to curse weapon/gloves whatever
+ which, for now: 0 = non-mummy, 1 = mummy (potions as well)
+ don't change mitm.special of !odecay */
+
+ int count = 0;
+ int item = ENDOFPACK;
+
+ for (int i = 0; i < ENDOFPACK; i++)
+ {
+ if (!is_valid_item( you.inv[i] ))
+ continue;
+
+ if (you.inv[i].base_type == OBJ_WEAPONS
+ || you.inv[i].base_type == OBJ_ARMOUR
+ || you.inv[i].base_type == OBJ_JEWELLERY
+ || you.inv[i].base_type == OBJ_POTIONS)
+ {
+ if (item_cursed( you.inv[i] ))
+ continue;
+
+ if (you.inv[i].base_type == OBJ_POTIONS
+ && (which != 1 || you.inv[i].sub_type == POT_DECAY))
+ {
+ continue;
+ }
+
+ // item is valid for cursing, so we'll give it a chance
+ count++;
+ if (one_chance_in( count ))
+ item = i;
+ }
+ }
+
+ // any item to curse?
+ if (item == ENDOFPACK)
+ return (false);
+
+ // curse item:
+
+ /* problem: changes large piles of potions */
+ /* don't change you.inv_special (just for fun) */
+ if (you.inv[item].base_type == OBJ_POTIONS)
+ {
+ you.inv[item].sub_type = POT_DECAY;
+ unset_ident_flags( you.inv[item], ISFLAG_IDENT_MASK ); // all different
+ }
+ else
+ do_curse_item( you.inv[item] );
+
+ return (true);
+}
+
+static void monster_drop_ething(struct monsters *monster)
+{
+ /* drop weapons & missiles last (ie on top) so others pick up */
+ int i; // loop variable {dlb}
+ bool destroyed = false;
+ bool hostile_grid = false;
+
+ if (grd[monster->x][monster->y] == DNGN_LAVA ||
+ grd[monster->x][monster->y] == DNGN_DEEP_WATER)
+ {
+ hostile_grid = true;
+ }
+
+ for (i = MSLOT_GOLD; i >= MSLOT_WEAPON; i--)
+ {
+ int item = monster->inv[i];
+
+ if (item != NON_ITEM)
+ {
+ if (hostile_grid)
+ {
+ destroyed = true;
+ destroy_item( item );
+ }
+ else
+ {
+ move_item_to_grid( &item, monster->x, monster->y );
+ }
+
+ monster->inv[i] = NON_ITEM;
+ }
+ }
+
+ if (destroyed)
+ {
+ if (grd[monster->x][monster->y] == DNGN_LAVA)
+ mpr("You hear a hissing sound.");
+ else
+ mpr("You hear a splashing sound.");
+ }
+} // end monster_drop_ething()
+
+static void place_monster_corpse(struct monsters *monster)
+{
+ int corpse_class = mons_charclass(monster->type);
+
+ if (mons_has_ench(monster, ENCH_SHAPESHIFTER))
+ corpse_class = MONS_SHAPESHIFTER;
+ else if (mons_has_ench(monster, ENCH_GLOWING_SHAPESHIFTER))
+ corpse_class = MONS_GLOWING_SHAPESHIFTER;
+
+ if (mons_weight(corpse_class) == 0
+ || grd[monster->x][monster->y] == DNGN_LAVA
+ || grd[monster->x][monster->y] == DNGN_DEEP_WATER || coinflip())
+ {
+ return;
+ }
+
+ int o = get_item_slot();
+ if (o == NON_ITEM)
+ return;
+
+ mitm[o].flags = 0;
+ mitm[o].base_type = OBJ_CORPSES;
+ mitm[o].plus = corpse_class;
+ mitm[o].plus2 = 0; // butcher work done
+ mitm[o].sub_type = CORPSE_BODY;
+ mitm[o].special = 210; // rot time
+ mitm[o].colour = mons_colour(corpse_class);
+ mitm[o].quantity = 1;
+
+ if (mitm[o].colour == BLACK)
+ mitm[o].colour = monster->number;
+
+ // Don't care if 'o' is changed, and it shouldn't be (corpses don't stack)
+ move_item_to_grid( &o, monster->x, monster->y );
+} // end place_monster_corpse()
+
+void monster_die(struct monsters *monster, char killer, int i)
+{
+ int dmi; // dead monster's inventory
+ int monster_killed = monster_index(monster);
+ bool death_message = mons_near(monster) && player_monster_visible(monster);
+
+ // From time to time Trog gives you a little bonus
+ if (killer == KILL_YOU && you.berserker)
+ {
+ if (you.religion == GOD_TROG
+ && (!player_under_penance() && you.piety > random2(1000)))
+ {
+ int bonus = 3 + random2avg( 10, 2 );
+
+ you.berserker += bonus;
+ you.might += bonus;
+ haste_player( bonus );
+
+ mpr( "You feel the power of Trog in you as your rage grows.",
+ MSGCH_GOD, GOD_TROG );
+ }
+ else if (wearing_amulet( AMU_RAGE ) && one_chance_in(30))
+ {
+ int bonus = 2 + random2(4);
+
+ you.berserker += bonus;
+ you.might += bonus;
+ haste_player( bonus );
+
+ mpr( "Your amulet glows a violent red." );
+ }
+ }
+
+ if (you.prev_targ == monster_killed)
+ you.prev_targ = MHITNOT;
+
+ const bool pet_kill = (MON_KILL(killer) && ((i >= 0 && i < 200)
+ && mons_friendly(&menv[i])));
+
+ if (monster->type == MONS_GIANT_SPORE
+ || monster->type == MONS_BALL_LIGHTNING)
+ {
+ if (monster->hit_points < 1 && monster->hit_points > -15)
+ return;
+ }
+ else if (monster->type == MONS_FIRE_VORTEX
+ || monster->type == MONS_SPATIAL_VORTEX)
+ {
+ simple_monster_message( monster, " dissipates!", MSGCH_MONSTER_DAMAGE,
+ MDAM_DEAD );
+
+ if (!testbits(monster->flags, MF_CREATED_FRIENDLY))
+ {
+ if (YOU_KILL(killer))
+ gain_exp( exper_value( monster ) );
+ else if (pet_kill)
+ gain_exp( exper_value( monster ) / 2 + 1 );
+ }
+
+ if (monster->type == MONS_FIRE_VORTEX)
+ place_cloud(CLOUD_FIRE_MON, monster->x, monster->y, 2 + random2(4));
+ }
+ else if (monster->type == MONS_SIMULACRUM_SMALL
+ || monster->type == MONS_SIMULACRUM_LARGE)
+ {
+ simple_monster_message( monster, " vaporizes!", MSGCH_MONSTER_DAMAGE,
+ MDAM_DEAD );
+
+ if (!testbits(monster->flags, MF_CREATED_FRIENDLY))
+ {
+ if (YOU_KILL(killer))
+ gain_exp( exper_value( monster ) );
+ else if (pet_kill)
+ gain_exp( exper_value( monster ) / 2 + 1 );
+ }
+
+ place_cloud(CLOUD_COLD_MON, monster->x, monster->y, 2 + random2(4));
+ }
+ else if (monster->type == MONS_DANCING_WEAPON)
+ {
+ simple_monster_message(monster, " falls from the air.",
+ MSGCH_MONSTER_DAMAGE, MDAM_DEAD);
+
+ if (!testbits(monster->flags, MF_CREATED_FRIENDLY))
+ {
+ if (YOU_KILL(killer))
+ gain_exp( exper_value( monster ) );
+ else if (pet_kill)
+ gain_exp( exper_value( monster ) / 2 + 1 );
+ }
+ }
+ else
+ {
+ switch (killer)
+ {
+ case KILL_YOU: /* You kill in combat. */
+ case KILL_YOU_MISSILE: /* You kill by missile or beam. */
+ strcpy(info, "You ");
+ strcat(info, (wounded_damaged(monster->type)) ? "destroy" : "kill");
+ strcat(info, " ");
+ strcat(info, ptr_monam(monster, DESC_NOCAP_THE));
+ strcat(info, "!");
+
+ if (death_message)
+ mpr(info, MSGCH_MONSTER_DAMAGE, MDAM_DEAD);
+
+ if (!testbits(monster->flags, MF_CREATED_FRIENDLY))
+ {
+ gain_exp(exper_value( monster ));
+ }
+ else
+ {
+ if (death_message)
+ mpr("That felt strangely unrewarding.");
+ }
+
+ // Xom doesn't care who you killed:
+ if (you.religion == GOD_XOM
+ && random2(70) <= 10 + monster->hit_dice)
+ {
+ Xom_acts(true, 1 + random2(monster->hit_dice), false);
+ }
+
+ // Trying to prevent summoning abuse here, so we're trying to
+ // prevent summoned creatures from being being done_good kills,
+ // Only affects monsters friendly when created.
+ if (!testbits(monster->flags, MF_CREATED_FRIENDLY))
+ {
+ if (you.duration[DUR_PRAYER])
+ {
+ if (mons_holiness(monster->type) == MH_NATURAL)
+ done_good(GOOD_KILLED_LIVING, monster->hit_dice);
+
+ if (mons_holiness(monster->type) == MH_UNDEAD)
+ done_good(GOOD_KILLED_UNDEAD, monster->hit_dice);
+
+ if (mons_holiness(monster->type) == MH_DEMONIC)
+ done_good(GOOD_KILLED_DEMON, monster->hit_dice);
+
+ if (mons_holiness(monster->type) == MH_HOLY)
+ done_good(GOOD_KILLED_ANGEL_II, monster->hit_dice);
+
+ //jmf: Trog hates wizards
+ if (mons_flag(monster->type, M_ACTUAL_SPELLS))
+ done_good(GOOD_KILLED_WIZARD, monster->hit_dice);
+
+ //jmf: maybe someone hates priests?
+ if (mons_flag(monster->type, M_PRIEST))
+ done_good(GOOD_KILLED_PRIEST, monster->hit_dice);
+ }
+ else if (mons_holiness(monster->type) == MH_HOLY)
+ {
+ done_good(GOOD_KILLED_ANGEL_I, monster->hit_dice);
+ }
+ }
+
+ if (you.mutation[MUT_DEATH_STRENGTH]
+ || (you.religion == GOD_MAKHLEB && you.duration[DUR_PRAYER]
+ && (!player_under_penance() && random2(you.piety) >= 30)))
+ {
+ if (you.hp < you.hp_max)
+ {
+ mpr("You feel a little better.");
+ inc_hp(monster->hit_dice + random2(monster->hit_dice),
+ false);
+ }
+ }
+
+ if ((you.religion == GOD_MAKHLEB || you.religion == GOD_VEHUMET)
+ && you.duration[DUR_PRAYER]
+ && (!player_under_penance() && random2(you.piety) >= 30))
+ {
+ if (you.magic_points < you.max_magic_points)
+ {
+ mpr("You feel your power returning.");
+ inc_mp( 1 + random2(monster->hit_dice / 2), false );
+ }
+ }
+
+ if (you.duration[DUR_DEATH_CHANNEL]
+ && mons_holiness(monster->type) == MH_NATURAL
+ && mons_weight(mons_charclass(monster->type)))
+ {
+ if (create_monster( MONS_SPECTRAL_THING, 0, BEH_FRIENDLY,
+ monster->x, monster->y, you.pet_target,
+ mons_charclass(monster->type)) != -1)
+ {
+ if (death_message)
+ mpr("A glowing mist starts to gather...");
+ }
+ }
+ break;
+
+ case KILL_MON: /* Monster kills in combat */
+ case KILL_MON_MISSILE: /* Monster kills by missile or beam */
+ simple_monster_message(monster, " dies!", MSGCH_MONSTER_DAMAGE,
+ MDAM_DEAD);
+
+ // no piety loss if god gifts killed by other monsters
+ if (mons_friendly(monster) && !testbits(monster->flags,MF_GOD_GIFT))
+ naughty(NAUGHTY_FRIEND_DIES, 1 + (monster->hit_dice / 2));
+
+ // Trying to prevent summoning abuse here, so we're trying to
+ // prevent summoned creatures from being being done_good kills.
+ // Only affects creatures which were friendly when summoned.
+ if (!testbits(monster->flags, MF_CREATED_FRIENDLY) && pet_kill)
+ {
+ gain_exp(exper_value( monster ) / 2 + 1);
+
+ if (mons_holiness(menv[i].type) == MH_UNDEAD)
+ {
+ if (mons_holiness(monster->type) == MH_NATURAL)
+ done_good(GOOD_SLAVES_KILL_LIVING, monster->hit_dice);
+ else
+ done_good(GOOD_SERVANTS_KILL, monster->hit_dice);
+ }
+ else
+ {
+ done_good(GOOD_SERVANTS_KILL, monster->hit_dice);
+
+ if (you.religion == GOD_VEHUMET
+ && (!player_under_penance()
+ && random2(you.piety) >= 30))
+ {
+ /* Vehumet - only for non-undead servants (coding
+ convenience, no real reason except that Vehumet
+ prefers demons) */
+ if (you.magic_points < you.max_magic_points)
+ {
+ mpr("You feel your power returning.");
+ inc_mp(1 + random2(random2(monster->hit_dice)),
+ false);
+ }
+ }
+ }
+ }
+ break;
+
+ /* Monster killed by trap/inanimate thing/itself/poison not from you */
+ case KILL_MISC:
+ simple_monster_message(monster, " dies!", MSGCH_MONSTER_DAMAGE,
+ MDAM_DEAD);
+ break;
+
+ case KILL_RESET:
+ /* Monster doesn't die, just goes back to wherever it came from
+ This must only be called by monsters running out of time (or
+ abjuration), because it uses the beam variables! Or does it??? */
+ simple_monster_message( monster,
+ " disappears in a puff of smoke!" );
+
+ place_cloud( CLOUD_GREY_SMOKE_MON + random2(3), monster->x,
+ monster->y, 1 + random2(3) );
+
+ for (dmi = MSLOT_GOLD; dmi >= MSLOT_WEAPON; dmi--)
+ { /* takes whatever it's carrying back home */
+ if (monster->inv[dmi] != NON_ITEM)
+ destroy_item(monster->inv[dmi]);
+
+ monster->inv[dmi] = NON_ITEM;
+ }
+ break;
+ }
+ }
+
+ if (monster->type == MONS_MUMMY)
+ {
+ if (YOU_KILL(killer))
+ {
+ if (curse_an_item(1, 0))
+ mpr("You feel nervous for a moment...", MSGCH_MONSTER_SPELL);
+ }
+ }
+ else if (monster->type == MONS_GUARDIAN_MUMMY
+ || monster->type == MONS_GREATER_MUMMY
+ || monster->type == MONS_MUMMY_PRIEST)
+ {
+ if (YOU_KILL(killer))
+ {
+ mpr("You feel extremely nervous for a moment...",
+ MSGCH_MONSTER_SPELL);
+
+ miscast_effect( SPTYP_NECROMANCY,
+ 3 + (monster->type == MONS_GREATER_MUMMY) * 8
+ + (monster->type == MONS_MUMMY_PRIEST) * 5,
+ random2avg(88, 3), 100, "a mummy death curse" );
+ }
+ }
+ else if (monster->type == MONS_BORIS)
+ {
+ // XXX: actual blood curse effect for Boris? -- bwr
+
+ if (one_chance_in(5))
+ mons_speaks( monster );
+ else
+ {
+ // Provide the player with an ingame clue to Boris' return. -- bwr
+ const int tmp = random2(6);
+ simple_monster_message( monster,
+ (tmp == 0) ? " says, \"You haven't seen the last of me!\"" :
+ (tmp == 1) ? " says, \"I'll get you next time!\"" :
+ (tmp == 2) ? " says, \"This isn't over yet!\"" :
+ (tmp == 3) ? " says, \"I'll be back!\"" :
+ (tmp == 4) ? " says, \"This isn't the end, its only just beginning!\"" :
+ (tmp == 5) ? " says, \"Kill me? I think not!\""
+ : " says, \"You cannot defeat me so easily!\"",
+ MSGCH_TALK );
+ }
+
+ // Now that Boris is dead, he's a valid target for monster
+ // creation again. -- bwr
+ you.unique_creatures[ monster->type - 280 ] = 0;
+ }
+
+ if (killer != KILL_RESET)
+ {
+ if (mons_has_ench(monster, ENCH_ABJ_I, ENCH_ABJ_VI))
+ {
+ if (mons_weight(mons_charclass(monster->type)))
+ {
+ if (monster->type == MONS_SIMULACRUM_SMALL
+ || monster->type == MONS_SIMULACRUM_LARGE)
+ {
+ simple_monster_message( monster, " vaporizes!" );
+
+ place_cloud( CLOUD_COLD_MON, monster->x, monster->y,
+ 1 + random2(3) );
+ }
+ else
+ {
+ simple_monster_message(monster,
+ "'s corpse disappears in a puff of smoke!");
+
+ place_cloud( CLOUD_GREY_SMOKE_MON + random2(3),
+ monster->x, monster->y, 1 + random2(3) );
+ }
+ }
+ }
+ else
+ {
+ // have to add case for disintegration effect here? {dlb}
+ place_monster_corpse(monster);
+ }
+ }
+
+ monster_drop_ething(monster);
+ monster_cleanup(monster);
+} // end monster_die
+
+void monster_cleanup(struct monsters *monster)
+{
+ unsigned int monster_killed = monster_index(monster);
+ int dmi = 0;
+
+ for (unsigned char j = 0; j < NUM_MON_ENCHANTS; j++)
+ monster->enchantment[j] = ENCH_NONE;
+
+ monster->flags = 0;
+ monster->type = -1;
+ monster->hit_points = 0;
+ monster->max_hit_points = 0;
+ monster->hit_dice = 0;
+ monster->armour_class = 0;
+ monster->evasion = 0;
+ monster->speed_increment = 0;
+ monster->attitude = ATT_HOSTILE;
+ monster->behaviour = BEH_SLEEP;
+ monster->foe = MHITNOT;
+
+ mgrd[monster->x][monster->y] = NON_MONSTER;
+
+ for (dmi = MSLOT_GOLD; dmi >= MSLOT_WEAPON; dmi--)
+ {
+ monster->inv[dmi] = NON_ITEM;
+ }
+
+ for (dmi = 0; dmi < MAX_MONSTERS; dmi++)
+ {
+ if (menv[dmi].foe == monster_killed)
+ menv[dmi].foe = MHITNOT;
+ }
+
+ if (you.pet_target == monster_killed)
+ you.pet_target = MHITNOT;
+
+} // end monster_cleanup()
+
+static bool jelly_divide(struct monsters * parent)
+{
+ int jex = 0, jey = 0; // loop variables {dlb}
+ bool foundSpot = false; // to rid code of hideous goto {dlb}
+ struct monsters *child = 0; // NULL - value determined with loop {dlb}
+
+ if (!mons_flag( parent->type, M_SPLITS ) || parent->hit_points == 1)
+ return (false);
+
+ // first, find a suitable spot for the child {dlb}:
+ for (jex = -1; jex < 3; jex++)
+ {
+ // loop moves beyond those tiles contiguous to parent {dlb}:
+ if (jex > 1)
+ return (false);
+
+ for (jey = -1; jey < 2; jey++)
+ {
+ // 10-50 for now - must take clouds into account:
+ if (mgrd[parent->x + jex][parent->y + jey] == NON_MONSTER
+ && grd[parent->x + jex][parent->y + jey] > DNGN_LAST_SOLID_TILE
+ && (parent->x + jex != you.x_pos || parent->y + jey != you.y_pos))
+ {
+ foundSpot = true;
+ break;
+ }
+ }
+
+ if (foundSpot)
+ break;
+ } /* end of for jex */
+
+ int k = 0; // must remain outside loop that follows {dlb}
+
+ // now that we have a spot, find a monster slot {dlb}:
+ for (k = 0; k < MAX_MONSTERS; k++)
+ {
+ child = &menv[k];
+
+ if (child->type == -1)
+ break;
+ else if (k == MAX_MONSTERS - 1)
+ return (false);
+ }
+
+ // handle impact of split on parent {dlb}:
+ parent->max_hit_points /= 2;
+
+ if (parent->hit_points > parent->max_hit_points)
+ parent->hit_points = parent->max_hit_points;
+
+ // create child {dlb}:
+ // this is terribly partial and really requires
+ // more thought as to generation ... {dlb}
+ child->type = parent->type;
+ child->hit_dice = parent->hit_dice;
+ child->hit_points = parent->hit_points;
+ child->max_hit_points = child->hit_points;
+ child->armour_class = parent->armour_class;
+ child->evasion = parent->evasion;
+ child->speed = parent->speed;
+ child->speed_increment = 70 + random2(5);
+ child->behaviour = parent->behaviour; /* Look at this! */
+ child->foe = parent->foe;
+ child->attitude = parent->attitude;
+
+ child->x = parent->x + jex;
+ child->y = parent->y + jey;
+
+ mgrd[child->x][child->y] = k;
+
+ if (!simple_monster_message(parent, " splits in two!"))
+ {
+ if (!silenced(parent->x, parent->y) || !silenced(child->x, child->y))
+ mpr("You hear a squelching noise.");
+ }
+
+ return (true);
+} // end jelly_divde()
+
+// if you're invis and throw/zap whatever, alerts menv to your position
+void alert_nearby_monsters(void)
+{
+ struct monsters *monster = 0; // NULL {dlb}
+
+ for (int it = 0; it < MAX_MONSTERS; it++)
+ {
+ monster = &menv[it];
+
+ // Judging from the above comment, this function isn't
+ // intended to wake up monsters, so we're only going to
+ // alert monsters that aren't sleeping. For cases where an
+ // event should wake up monsters and alert them, I'd suggest
+ // calling noisy() before calling this function. -- bwr
+ if (monster->type != -1
+ && monster->behaviour != BEH_SLEEP
+ && mons_near(monster))
+ {
+ behaviour_event( monster, ME_ALERT, MHITYOU );
+ }
+ }
+} // end alert_nearby_monsters()
+
+static bool valid_morph( struct monsters *monster, int new_mclass )
+{
+ unsigned char current_tile = grd[monster->x][monster->y];
+
+ // morph targets are _always_ "base" classes, not derived ones.
+ new_mclass = mons_charclass(new_mclass);
+
+ /* various inappropriate polymorph targets */
+ if (mons_holiness( new_mclass ) != mons_holiness( monster->type )
+ || mons_flag( new_mclass, M_NO_EXP_GAIN ) // not helpless
+ || new_mclass == mons_charclass( monster->type ) // must be different
+ || new_mclass == MONS_PROGRAM_BUG
+ || new_mclass == MONS_SHAPESHIFTER
+ || new_mclass == MONS_GLOWING_SHAPESHIFTER
+
+ // These shouldn't happen anyways (demons unaffected + holiness check),
+ // but if we ever do have polydemon, these will be needed:
+ || new_mclass == MONS_PLAYER_GHOST
+ || new_mclass == MONS_PANDEMONIUM_DEMON
+ || (new_mclass >= MONS_GERYON && new_mclass <= MONS_ERESHKIGAL))
+ {
+ return (false);
+ }
+
+ /* Not fair to instakill a monster like this --
+ order of evaluation of inner conditional important */
+ if (current_tile == DNGN_LAVA || current_tile == DNGN_DEEP_WATER)
+ {
+ if (!mons_class_flies(new_mclass)
+ || monster_habitat(new_mclass) != current_tile)
+ {
+ return (false);
+ }
+ }
+
+ // not fair to strand a water monster on dry land, either. :)
+ if (monster_habitat(new_mclass) == DNGN_DEEP_WATER
+ && current_tile != DNGN_DEEP_WATER
+ && current_tile != DNGN_SHALLOW_WATER)
+ {
+ return (false);
+ }
+
+ // and putting lava monsters on non-lava sqaures is a no-no, too
+ if (monster_habitat(new_mclass) == DNGN_LAVA && current_tile != DNGN_LAVA)
+ return (false);
+
+ return (true);
+} // end valid_morph()
+
+// note that power is (as of yet) unused within this function -
+// may be worthy of consideration of later implementation, though,
+// so I'll still let the parameter exist for the time being {dlb}
+bool monster_polymorph( struct monsters *monster, int targetc, int power )
+{
+ char str_polymon[INFO_SIZE] = ""; // cannot use info[] here {dlb}
+ bool player_messaged = false;
+ int source_power, target_power, relax;
+
+ UNUSED( power );
+
+ // Used to be mons_power, but that just returns hit_dice
+ // for the monster class. By using the current hit dice
+ // the player gets the opportunity to use draining more
+ // effectively against shapeshifters. -- bwr
+ source_power = monster->hit_dice;
+ relax = 2;
+
+ if (targetc == RANDOM_MONSTER)
+ {
+ do
+ {
+ targetc = random2( NUM_MONSTERS );
+
+ // valid targets are always base classes
+ targetc = mons_charclass( targetc );
+
+ target_power = mons_power( targetc );
+
+ if (one_chance_in(100))
+ relax++;
+
+ if (relax > 50)
+ return (simple_monster_message( monster, " shudders." ));
+ }
+ while (!valid_morph( monster, targetc )
+ || target_power < source_power - relax
+ || target_power > source_power + (relax * 3) / 2);
+ }
+
+ // messaging: {dlb}
+ bool invis = mons_flag( targetc, M_INVIS )
+ || mons_has_ench( monster, ENCH_INVIS );
+
+ if (mons_has_ench( monster, ENCH_GLOWING_SHAPESHIFTER, ENCH_SHAPESHIFTER ))
+ strcat( str_polymon, " changes into " );
+ else if (targetc == MONS_PULSATING_LUMP)
+ strcat( str_polymon, " degenerates into " );
+ else
+ strcat( str_polymon, " evaporates and reforms as " );
+
+ if (invis && !player_see_invis())
+ strcat( str_polymon, "something you cannot see!" );
+ else
+ {
+ strcat( str_polymon, monam( 250, targetc, !invis, DESC_NOCAP_A ) );
+
+ if (targetc == MONS_PULSATING_LUMP)
+ strcat( str_polymon, " of flesh" );
+
+ strcat( str_polymon, "!" );
+ }
+
+ player_messaged = simple_monster_message( monster, str_polymon );
+
+ // the actual polymorphing:
+ int old_hp = monster->hit_points;
+ int old_hp_max = monster->max_hit_points;
+
+ /* deal with mons_sec */
+ monster->type = targetc;
+ monster->number = 250;
+
+ int abj = mons_has_ench( monster, ENCH_ABJ_I, ENCH_ABJ_VI );
+ int shifter = mons_has_ench( monster, ENCH_GLOWING_SHAPESHIFTER,
+ ENCH_SHAPESHIFTER );
+
+ // Note: define_monster() will clear out all enchantments! -- bwr
+ define_monster( monster_index(monster) );
+
+ // put back important enchantments:
+ if (abj != ENCH_NONE)
+ mons_add_ench( monster, abj );
+
+ if (shifter != ENCH_NONE)
+ mons_add_ench( monster, shifter );
+
+ if (mons_flag( monster->type, M_INVIS ))
+ mons_add_ench( monster, ENCH_INVIS );
+
+ monster->hit_points = monster->max_hit_points
+ * ((old_hp * 100) / old_hp_max) / 100
+ + random2(monster->max_hit_points);
+
+ if (monster->hit_points > monster->max_hit_points)
+ monster->hit_points = monster->max_hit_points;
+
+ monster->speed_increment = 67 + random2(6);
+
+ monster_drop_ething(monster);
+
+ return (player_messaged);
+} // end monster_polymorph()
+
+void monster_blink(struct monsters *monster)
+{
+ int nx, ny;
+
+ if (!random_near_space(monster->x, monster->y, nx, ny,
+ false, false))
+ return;
+
+ mgrd[monster->x][monster->y] = NON_MONSTER;
+
+ monster->x = nx;
+ monster->y = ny;
+
+ mgrd[nx][ny] = monster_index(monster);
+} // end monster_blink()
+
+// allow_adjacent: allow target to be adjacent to origin
+// restrict_LOS: restict target to be within PLAYER line of sight
+bool random_near_space(int ox, int oy, int &tx, int &ty, bool allow_adjacent,
+ bool restrict_LOS)
+{
+ int tries = 0;
+
+ do
+ {
+ tx = ox - 6 + random2(14);
+ ty = oy - 6 + random2(14);
+
+ // origin is not 'near'
+ if (tx == ox && ty == oy)
+ continue;
+
+ tries++;
+
+ if (tries > 149)
+ break;
+ }
+ while ((!see_grid(tx, ty) && restrict_LOS)
+ || grd[tx][ty] < DNGN_SHALLOW_WATER
+ || mgrd[tx][ty] != NON_MONSTER
+ || (!allow_adjacent && distance(ox, oy, tx, ty) <= 2));
+
+ return (tries < 150);
+} // end random_near_space()
+
+static bool habitat_okay( struct monsters *monster, int targ )
+{
+ bool ret = false;
+ const int habitat = monster_habitat( monster->type );
+
+ if (mons_flies( monster ))
+ {
+ // flying monsters don't care
+ ret = true;
+ }
+ else if (mons_flag( monster->type, M_AMPHIBIOUS )
+ && (targ == DNGN_DEEP_WATER || targ == DNGN_SHALLOW_WATER))
+ {
+ // Amphibious creatures are "land" by default in mon-data,
+ // we allow them to swim here. -- bwr
+ ret = true;
+ }
+ else if (monster->type == MONS_WATER_ELEMENTAL && targ >= DNGN_DEEP_WATER)
+ {
+ // water elementals can crawl out over the land
+ ret = true;
+ }
+ else if (habitat == DNGN_FLOOR
+ && (targ >= DNGN_FLOOR || targ == DNGN_SHALLOW_WATER))
+ {
+ // FLOOR habitat monster going to a non-bad place
+ ret = true;
+ }
+ else if (habitat == DNGN_DEEP_WATER
+ && (targ == DNGN_DEEP_WATER || targ == DNGN_SHALLOW_WATER))
+ {
+ // Water monster to water
+ ret = true;
+ }
+ else if (habitat == DNGN_LAVA && targ == DNGN_LAVA)
+ {
+ // Lava monster to lava
+ ret = true;
+ }
+
+ return (ret);
+}
+
+// This doesn't really swap places, it just sets the monster's
+// position equal to the player (the player has to be moved afterwards).
+// It also has a slight problem with the fact the if the player is
+// levitating over an inhospitable habitat for the monster the monster
+// will be put in a place it normally couldn't go (this could be a
+// feature because it prevents insta-killing). In order to prevent
+// that little problem, we go looking for a square for the monster
+// to "scatter" to instead... and if we can't find one the monster
+// just refuses to be swapped (not a bug, this is intentionally
+// avoiding the insta-kill). Another option is to look a bit
+// wider for a vaild square (either by a last attempt blink, or
+// by looking at a wider radius)... insta-killing should be a
+// last resort in this function (especially since Tome, Dig, and
+// Summoning can be used to set up death traps). If worse comes
+// to worse, at least consider making the Swap spell not work
+// when the player is over lava or water (if the player want's to
+// swap pets to their death, we can let that go). -- bwr
+bool swap_places(struct monsters *monster)
+{
+ bool swap;
+
+ int loc_x = you.x_pos;
+ int loc_y = you.y_pos;
+
+ swap = habitat_okay( monster, grd[loc_x][loc_y] );
+
+ // chose an appropiate habitat square at random around the target.
+ if (!swap)
+ {
+ int num_found = 0;
+ int temp_x, temp_y;
+
+ for (int x = -1; x <= 1; x++)
+ {
+ temp_x = you.x_pos + x;
+ if (temp_x < 0 || temp_x >= GXM)
+ continue;
+
+ for (int y = -1; y <= 1; y++)
+ {
+ if (x == 0 && y == 0)
+ continue;
+
+ temp_y = you.y_pos + y;
+ if (temp_y < 0 || temp_y >= GYM)
+ continue;
+
+ if (mgrd[temp_x][temp_y] == NON_MONSTER
+ && habitat_okay( monster, grd[temp_x][temp_y] ))
+ {
+ // Found an appropiate space... check if we
+ // switch the current choice to this one.
+ num_found++;
+ if (one_chance_in(num_found))
+ {
+ loc_x = temp_x;
+ loc_y = temp_y;
+ }
+ }
+ }
+ }
+
+ if (num_found)
+ swap = true;
+ }
+
+ if (swap)
+ {
+ mpr("You swap places.");
+
+ mgrd[monster->x][monster->y] = NON_MONSTER;
+
+ monster->x = loc_x;
+ monster->y = loc_y;
+
+ mgrd[monster->x][monster->y] = monster_index(monster);
+ }
+ else
+ {
+ // Might not be ideal, but it's better that insta-killing
+ // the monster... maybe try for a short blinki instead? -- bwr
+ simple_monster_message( monster, " resists." );
+ }
+
+ return (swap);
+} // end swap_places()
+
+void print_wounds(struct monsters *monster)
+{
+ // prevents segfault -- cannot use info[] here {dlb}
+ char str_wound[INFO_SIZE];
+ int dam_level;
+
+ if (monster->type == -1)
+ return;
+
+ if (monster->hit_points == monster->max_hit_points
+ || monster->hit_points < 1)
+ {
+ return;
+ }
+
+ if (monster_descriptor(monster->type, MDSC_NOMSG_WOUNDS))
+ return;
+
+ strcpy(str_wound, " is ");
+
+ if (monster->hit_points <= monster->max_hit_points / 6)
+ {
+ strcat(str_wound, "almost ");
+ strcat(str_wound, wounded_damaged(monster->type) ? "destroyed"
+ : "dead");
+ dam_level = MDAM_ALMOST_DEAD;
+ }
+ else
+ {
+ if (monster->hit_points <= monster->max_hit_points / 6)
+ {
+ strcat(str_wound, "horribly ");
+ dam_level = MDAM_HORRIBLY_DAMAGED;
+ }
+ else if (monster->hit_points <= monster->max_hit_points / 3)
+ {
+ strcat(str_wound, "heavily " );
+ dam_level = MDAM_HEAVILY_DAMAGED;
+ }
+ else if (monster->hit_points <= 3 * (monster-> max_hit_points / 4))
+ {
+ strcat(str_wound, "moderately ");
+ dam_level = MDAM_MODERATELY_DAMAGED;
+ }
+ else
+ {
+ strcat(str_wound, "lightly ");
+ dam_level = MDAM_LIGHTLY_DAMAGED;
+ }
+
+ strcat(str_wound, wounded_damaged(monster->type) ? "damaged"
+ : "wounded");
+ }
+
+ strcat(str_wound, ".");
+ simple_monster_message(monster, str_wound, MSGCH_MONSTER_DAMAGE, dam_level);
+} // end print_wounds()
+
+// (true == 'damaged') [constructs, undead, etc.]
+// and (false == 'wounded') [living creatures, etc.] {dlb}
+bool wounded_damaged(int wound_class)
+{
+ // this schema needs to be abstracted into real categories {dlb}:
+ const int holy = mons_holiness(wound_class);
+ if (holy == MH_UNDEAD || holy == MH_NONLIVING || holy == MH_PLANT)
+ return (true);
+
+ return (false);
+} // end wounded_damaged()
+
+//---------------------------------------------------------------
+//
+// behaviour_event
+//
+// 1. Change any of: monster state, foe, and attitude
+// 2. Call handle_behaviour to re-evaluate AI state and target x,y
+//
+//---------------------------------------------------------------
+void behaviour_event( struct monsters *mon, int event, int src,
+ int src_x, int src_y )
+{
+ bool isSmart = (mons_intel(mon->type) > I_ANIMAL);
+ bool isFriendly = mons_friendly(mon);
+ bool sourceFriendly = false;
+ bool setTarget = false;
+ bool breakCharm = false;
+
+ if (src == MHITYOU)
+ sourceFriendly = true;
+ else if (src != MHITNOT)
+ sourceFriendly = mons_friendly( &menv[src] );
+
+ switch(event)
+ {
+ case ME_DISTURB:
+ // assumes disturbed by noise...
+ if (mon->behaviour == BEH_SLEEP)
+ mon->behaviour = BEH_WANDER;
+
+ // A bit of code to make Project Noise actually so
+ // something again. Basically, dumb monsters and
+ // monsters who aren't otherwise occupied will at
+ // least consider the (apparent) source of the noise
+ // interesting for a moment. -- bwr
+ if (!isSmart || mon->foe == MHITNOT || mon->behaviour == BEH_WANDER)
+ {
+ mon->target_x = src_x;
+ mon->target_y = src_y;
+ }
+ break;
+
+ case ME_WHACK:
+ case ME_ANNOY:
+ // will turn monster against <src>, unless they
+ // are BOTH friendly and stupid. Hitting someone
+ // over the head, of course, always triggers this code.
+ if (isFriendly != sourceFriendly || isSmart || event == ME_WHACK)
+ {
+ mon->foe = src;
+
+ if (mon->behaviour != BEH_CORNERED)
+ mon->behaviour = BEH_SEEK;
+
+ if (src == MHITYOU)
+ {
+ mon->attitude = ATT_HOSTILE;
+ breakCharm = true;
+ }
+ }
+
+ // now set target x,y so that monster can whack
+ // back (once) at an invisible foe
+ if (event == ME_WHACK)
+ setTarget = true;
+ break;
+
+ case ME_ALERT:
+ // will alert monster to <src> and turn them
+ // against them, unless they have a current foe.
+ // it won't turn friends hostile either.
+ if (mon->behaviour != BEH_CORNERED)
+ mon->behaviour = BEH_SEEK;
+
+ if (mon->foe == MHITNOT)
+ mon->foe = src;
+ break;
+
+ case ME_SCARE:
+ mon->foe = src;
+ mon->behaviour = BEH_FLEE;
+ // assume monsters know where to run from, even
+ // if player is invisible.
+ setTarget = true;
+ break;
+
+ case ME_CORNERED:
+ // just set behaviour.. foe doesn't change.
+ if (mon->behaviour != BEH_CORNERED && !mons_has_ench(mon,ENCH_FEAR))
+ simple_monster_message(mon, " turns to fight!");
+
+ mon->behaviour = BEH_CORNERED;
+ break;
+
+ case ME_EVAL:
+ default:
+ break;
+ }
+
+ if (setTarget)
+ {
+ if (src == MHITYOU)
+ {
+ mon->target_x = you.x_pos;
+ mon->target_y = you.y_pos;
+ mon->attitude = ATT_HOSTILE;
+ }
+ else if (src != MHITNOT)
+ {
+ mon->target_x = menv[src].x;
+ mon->target_y = menv[src].y;
+ }
+ }
+
+ // now, break charms if appropriate
+ if (breakCharm)
+ mons_del_ench( mon, ENCH_CHARM );
+
+ // do any resultant foe or state changes
+ handle_behaviour( mon );
+}
+
+//---------------------------------------------------------------
+//
+// handle_behaviour
+//
+// 1. Evalutates current AI state
+// 2. Sets monster targetx,y based on current foe
+//
+//---------------------------------------------------------------
+static void handle_behaviour(struct monsters *mon)
+{
+ bool changed = true;
+ bool isFriendly = mons_friendly(mon);
+ bool proxPlayer = mons_near(mon);
+ bool proxFoe;
+ bool isHurt = (mon->hit_points <= mon->max_hit_points / 4 - 1);
+ bool isHealthy = (mon->hit_points > mon->max_hit_points / 2);
+ bool isSmart = (mons_intel(mon->type) > I_ANIMAL);
+ bool isScared = mons_has_ench(mon, ENCH_FEAR);
+
+ // immobility logic stolen from later on in handle_monster().. argh! --gdl
+ bool isMobile = !(mon->type == MONS_OKLOB_PLANT
+ || mon->type == MONS_CURSE_SKULL
+ || (mon->type >= MONS_CURSE_TOE
+ && mon->type <= MONS_POTION_MIMIC));
+
+ // check for confusion -- early out.
+ if (mons_has_ench(mon, ENCH_CONFUSION))
+ {
+ mon->target_x = 10 + random2(GXM - 10);
+ mon->target_y = 10 + random2(GYM - 10);
+ return;
+ }
+
+ // validate current target exists
+ if (mon->foe != MHITNOT && mon->foe != MHITYOU)
+ {
+ if (menv[mon->foe].type == -1)
+ mon->foe = MHITNOT;
+ }
+
+ // change proxPlayer depending on invisibility and standing
+ // in shallow water
+ if (proxPlayer && you.invis)
+ {
+ if (!mons_player_visible( mon ))
+ proxPlayer = false;
+
+ // must be able to see each other
+ if (!see_grid(mon->x, mon->y))
+ proxPlayer = false;
+
+ // now, the corollary to that is that sometimes, if a
+ // player is right next to a monster, they will 'see'
+ if (grid_distance( you.x_pos, you.y_pos, mon->x, mon->y ) == 1
+ && one_chance_in(3))
+ {
+ proxPlayer = true;
+ }
+ }
+
+ // set friendly target, if they don't already have one
+ if (isFriendly
+ && you.pet_target != MHITNOT
+ && (mon->foe == MHITNOT || mon->foe == MHITYOU))
+ {
+ mon->foe = you.pet_target;
+ }
+
+ // monsters do not attack themselves {dlb}
+ if (mon->foe == monster_index(mon))
+ mon->foe = MHITNOT;
+
+ // friendly monsters do not attack other friendly monsters
+ if (mon->foe != MHITNOT && mon->foe != MHITYOU)
+ {
+ if (isFriendly && mons_friendly(&menv[mon->foe]))
+ mon->foe = MHITNOT;
+ }
+
+ // unfriendly monsters fighting other monsters will usually
+ // target the player, if they're healthy
+ if (!isFriendly && mon->foe != MHITYOU && mon->foe != MHITNOT
+ && proxPlayer && !one_chance_in(3) && isHealthy)
+ {
+ mon->foe = MHITYOU;
+ }
+
+ // validate target again
+ if (mon->foe != MHITNOT && mon->foe != MHITYOU)
+ {
+ if (menv[mon->foe].type == -1)
+ mon->foe = MHITNOT;
+ }
+
+ while (changed)
+ {
+ int foe_x = you.x_pos;
+ int foe_y = you.y_pos;
+
+ // evaluate these each time; they may change
+ if (mon->foe == MHITNOT)
+ proxFoe = false;
+ else
+ {
+ if (mon->foe == MHITYOU)
+ {
+ foe_x = you.x_pos;
+ foe_y = you.y_pos;
+ proxFoe = proxPlayer; // take invis into account
+ }
+ else
+ {
+ proxFoe = mons_near(mon, mon->foe);
+
+ if (!mons_monster_visible( mon, &menv[mon->foe] ))
+ proxFoe = false;
+
+ // XXX monsters will rely on player LOS -- GDL
+ if (!see_grid(menv[mon->foe].x, menv[mon->foe].y))
+ proxFoe = false;
+
+ foe_x = menv[mon->foe].x;
+ foe_y = menv[mon->foe].y;
+ }
+ }
+
+ // track changes to state; attitude never changes here.
+ unsigned int new_beh = mon->behaviour;
+ unsigned int new_foe = mon->foe;
+
+ // take care of monster state changes
+ switch(mon->behaviour)
+ {
+ case BEH_SLEEP:
+ // default sleep state
+ mon->target_x = mon->x;
+ mon->target_y = mon->y;
+ new_foe = MHITNOT;
+ break;
+
+ case BEH_SEEK:
+ // no foe? then wander or seek the player
+ if (mon->foe == MHITNOT)
+ {
+ if (!proxPlayer)
+ new_beh = BEH_WANDER;
+ else
+ {
+ new_foe = MHITYOU;
+ mon->target_x = you.x_pos;
+ mon->target_y = you.y_pos;
+ }
+
+ break;
+ }
+
+ // foe gone out of LOS?
+ if (!proxFoe)
+ {
+ if (isFriendly)
+ {
+ new_foe = MHITYOU;
+ mon->target_x = foe_x;
+ mon->target_y = foe_y;
+ break;
+ }
+
+ if (mon->foe_memory > 0 && mon->foe != MHITNOT)
+ {
+ // if we've arrived at our target x,y
+ // do a stealth check. If the foe
+ // fails, monster will then start
+ // tracking foe's CURRENT position,
+ // but only for a few moves (smell and
+ // intuition only go so far)
+
+ if (mon->x == mon->target_x &&
+ mon->y == mon->target_y)
+ {
+ if (mon->foe == MHITYOU)
+ {
+ if (check_awaken(monster_index(mon)))
+ {
+ mon->target_x = you.x_pos;
+ mon->target_y = you.y_pos;
+ }
+ else
+ mon->foe_memory = 1;
+ }
+ else
+ {
+ if (coinflip()) // XXX: cheesy!
+ {
+ mon->target_x = menv[mon->foe].x;
+ mon->target_y = menv[mon->foe].y;
+ }
+ else
+ mon->foe_memory = 1;
+ }
+ }
+
+ // either keep chasing, or start
+ // wandering.
+ if (mon->foe_memory < 2)
+ {
+ mon->foe_memory = 0;
+ new_beh = BEH_WANDER;
+ }
+ break;
+ }
+
+ // hack: smarter monsters will
+ // tend to persue the player longer.
+ int memory;
+ switch(mons_intel(monster_index(mon)))
+ {
+ case I_HIGH:
+ memory = 100 + random2(200);
+ break;
+ case I_NORMAL:
+ memory = 50 + random2(100);
+ break;
+ case I_ANIMAL:
+ default:
+ memory = 25 + random2(75);
+ break;
+ case I_INSECT:
+ memory = 10 + random2(50);
+ break;
+ }
+
+ mon->foe_memory = memory;
+ break; // from case
+ }
+
+ // monster can see foe: continue 'tracking'
+ // by updating target x,y
+ if (mon->foe == MHITYOU)
+ {
+ // sometimes, your friends will wander a bit.
+ if (isFriendly && one_chance_in(8))
+ {
+ mon->target_x = 10 + random2(GXM - 10);
+ mon->target_y = 10 + random2(GYM - 10);
+ mon->foe = MHITNOT;
+ new_beh = BEH_WANDER;
+ }
+ else
+ {
+ mon->target_x = you.x_pos;
+ mon->target_y = you.y_pos;
+ }
+ }
+ else
+ {
+ mon->target_x = menv[mon->foe].x;
+ mon->target_y = menv[mon->foe].y;
+ }
+
+ if (isHurt && !isSmart && isMobile)
+ new_beh = BEH_FLEE;
+ break;
+
+ case BEH_WANDER:
+ // is our foe in LOS?
+ // Batty monsters don't automatically reseek so that
+ // they'll flitter away, we'll reset them just before
+ // they get movement in handle_monsters() instead. -- bwr
+ if (proxFoe && !testbits( mon->flags, MF_BATTY ))
+ {
+ new_beh = BEH_SEEK;
+ break;
+ }
+
+ // default wander behaviour
+ //
+ // XXX: This is really dumb wander behaviour... instead of
+ // changing the goal square every turn, better would be to
+ // have the monster store a direction and have the monster
+ // head in that direction for a while, then shift the
+ // direction to the left or right. We're changing this so
+ // wandering monsters at least appear to have some sort of
+ // attention span. -- bwr
+ if ((mon->x == mon->target_x && mon->y == mon->target_y)
+ || one_chance_in(20)
+ || testbits( mon->flags, MF_BATTY ))
+ {
+ mon->target_x = 10 + random2(GXM - 10);
+ mon->target_y = 10 + random2(GYM - 10);
+ }
+
+ // during their wanderings, monsters will
+ // eventually relax their guard (stupid
+ // ones will do so faster, smart monsters
+ // have longer memories
+ if (!proxFoe && mon->foe != MHITNOT)
+ {
+ if (one_chance_in( isSmart ? 60 : 20 ))
+ new_foe = MHITNOT;
+ }
+ break;
+
+ case BEH_FLEE:
+ // check for healed
+ if (isHealthy && !isScared)
+ new_beh = BEH_SEEK;
+ // smart monsters flee until they can
+ // flee no more... possible to get a
+ // 'CORNERED' event, at which point
+ // we can jump back to WANDER if the foe
+ // isn't present.
+
+ if (proxFoe)
+ {
+ // try to flee _from_ the correct position
+ mon->target_x = foe_x;
+ mon->target_y = foe_y;
+ }
+ break;
+
+ case BEH_CORNERED:
+ if (isHealthy)
+ new_beh = BEH_SEEK;
+
+ // foe gone out of LOS?
+ if (!proxFoe)
+ {
+ if (isFriendly || proxPlayer)
+ new_foe = MHITYOU;
+ else
+ new_beh = BEH_WANDER;
+ }
+ else
+ {
+ mon->target_x = foe_x;
+ mon->target_y = foe_y;
+ }
+ break;
+
+ default:
+ return; // uh oh
+ }
+
+ changed = (new_beh != mon->behaviour || new_foe != mon->foe);
+ mon->behaviour = new_beh;
+
+ if (mon->foe != new_foe)
+ mon->foe_memory = 0;
+
+ mon->foe = new_foe;
+ }
+} // end handle_behaviour()
+
+// note that this function *completely* blocks messaging for monsters
+// distant or invisible to the player ... look elsewhere for a function
+// permitting output of "It" messages for the invisible {dlb}
+// INtentionally avoids info and str_pass now. -- bwr
+bool simple_monster_message(struct monsters *monster, const char *event,
+ int channel, int param)
+{
+ char buff[INFO_SIZE];
+
+ if (mons_near( monster )
+ && (channel == MSGCH_MONSTER_SPELL || player_monster_visible(monster)))
+ {
+ snprintf( buff, sizeof(buff), "%s%s",
+ ptr_monam(monster, DESC_CAP_THE), event );
+
+ mpr( buff, channel, param );
+ return (true);
+ }
+
+ return (false);
+} // end simple_monster_message()
+
+// used to adjust time durations in handle_enchantment() for monster speed
+static inline int mod_speed( int val, int speed )
+{
+ return (speed ? (val * 10) / speed : val);
+}
+
+static bool handle_enchantment(struct monsters *monster)
+{
+ const int habitat = monster_habitat( monster->type );
+ bool died = false;
+ int grid;
+ int poisonval;
+ int dam;
+ int tmp;
+
+ // Yes, this is the speed we want. This function will be called in
+ // two curcumstances: (1) the monster can move and have enough energy,
+ // and (2) the monster cannot move (speed == 0) and the monster loop
+ // is running.
+ //
+ // In the first case we don't have to figure in the player's time,
+ // since the rate of call to this function already does that (ie.
+ // a bat would get here 6 times in 2 normal player turns, and if
+ // the player was twice as fast it would be 6 times every four player
+ // moves. So the only speed we care about is the monster vs the
+ // absolute time frame.
+ //
+ // In the second case, we're hacking things so that plants can suffer
+ // from sticky flame. The rate of call in this case is once every
+ // player action... so the time_taken by the player is the ratio to
+ // the absolute time frame.
+ //
+ // This will be used below for poison and sticky flame so that the
+ // damage is apparently in the absolute time frame. This is done
+ // by scaling the damage and the chance that the effect goes away.
+ // The result is that poison on a regular monster will be doing
+ // 1d3 damage every two rounds, and last eight rounds, and on
+ // a bat the same poison will be doing 1/3 the damage each action
+ // it gets (the mod fractions are randomized in), will have three
+ // turns to the other monster's one, and the effect will survive
+ // 3 times as many calls to this function (ie 8 rounds * 3 calls).
+ //
+ // -- bwr
+ const int speed = (monster->speed == 0) ? you.time_taken : monster->speed;
+
+ for (int p = 0; p < NUM_MON_ENCHANTS && !died; p++)
+ {
+ switch (monster->enchantment[p])
+ {
+ case ENCH_SLOW:
+ if (random2(250) <= mod_speed( monster->hit_dice + 10, speed ))
+ mons_del_ench(monster, ENCH_SLOW);
+ break;
+
+ case ENCH_HASTE:
+ if (random2(1000) < mod_speed( 25, speed ))
+ mons_del_ench(monster, ENCH_HASTE);
+ break;
+
+ case ENCH_FEAR:
+ if (random2(150) <= mod_speed( monster->hit_dice + 5, speed ))
+ mons_del_ench(monster, ENCH_FEAR);
+ break;
+
+ case ENCH_CONFUSION:
+ if (random2(120) < mod_speed( monster->hit_dice + 5, speed ))
+ {
+ // don't delete perma-confusion
+ if (!mons_flag(monster->type, M_CONFUSED))
+ mons_del_ench(monster, ENCH_CONFUSION);
+ }
+ break;
+
+ case ENCH_INVIS:
+ if (random2(1000) < mod_speed( 25, speed ))
+ {
+ // don't delete perma-invis
+ if (!mons_flag( monster->type, M_INVIS ))
+ mons_del_ench(monster, ENCH_INVIS);
+ }
+ break;
+
+ case ENCH_SUBMERGED:
+ // not even air elementals unsubmerge into clouds
+ if (env.cgrid[monster->x][monster->y] != EMPTY_CLOUD)
+ break;
+
+ // Air elementals are a special case, as their
+ // submerging in air isn't up to choice. -- bwr
+ if (monster->type == MONS_AIR_ELEMENTAL)
+ {
+ heal_monster( monster, 1, one_chance_in(5) );
+
+ if (one_chance_in(5))
+ mons_del_ench( monster, ENCH_SUBMERGED );
+
+ break;
+ }
+
+ // Now we handle the others:
+ grid = grd[monster->x][monster->y];
+
+ // Badly injured monsters prefer to stay submerged...
+ // electrical eels and lava snakes have ranged attacks
+ // and are more likely to surface. -- bwr
+ if (habitat == DNGN_FLOOR || habitat != grid)
+ mons_del_ench( monster, ENCH_SUBMERGED ); // forced to surface
+ else if (monster->hit_points <= monster->max_hit_points / 2)
+ break;
+ else if (((monster->type == MONS_ELECTRICAL_EEL
+ || monster->type == MONS_LAVA_SNAKE)
+ && (random2(1000) < mod_speed( 20, speed )
+ || (mons_near(monster)
+ && monster->hit_points == monster->max_hit_points
+ && !one_chance_in(10))))
+ || random2(5000) < mod_speed( 10, speed ))
+ {
+ mons_del_ench( monster, ENCH_SUBMERGED );
+ }
+ break;
+
+ case ENCH_POISON_I:
+ case ENCH_POISON_II:
+ case ENCH_POISON_III:
+ case ENCH_POISON_IV:
+ case ENCH_YOUR_POISON_I:
+ case ENCH_YOUR_POISON_II:
+ case ENCH_YOUR_POISON_III:
+ case ENCH_YOUR_POISON_IV:
+ poisonval = monster->enchantment[p] - ENCH_POISON_I;
+
+ if (poisonval < 0 || poisonval > 3)
+ poisonval = monster->enchantment[p] - ENCH_YOUR_POISON_I;
+
+ dam = (poisonval >= 3) ? 1 : 0;
+
+ if (coinflip())
+ dam += roll_dice( 1, poisonval + 2 );
+
+ if (mons_res_poison(monster) < 0)
+ dam += roll_dice( 2, poisonval ) - 1;
+
+ // We adjust damage for monster speed (since this is applied
+ // only when the monster moves), and we handle the factional
+ // part as well (so that speed 30 creatures will take damage).
+ dam *= 10;
+ dam = (dam / speed) + ((random2(speed) < (dam % speed)) ? 1 : 0);
+
+ if (dam > 0)
+ {
+ hurt_monster( monster, dam );
+
+#if DEBUG_DIAGNOSTICS
+ // for debugging, we don't have this silent.
+ simple_monster_message( monster, " takes poison damage.",
+ MSGCH_DIAGNOSTICS );
+ snprintf( info, INFO_SIZE, "poison damage: %d", dam );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ if (monster->hit_points < 1)
+ {
+ monster_die(monster,
+ ((monster->enchantment[p] < ENCH_POISON_I)
+ ? KILL_YOU : KILL_MISC), 0);
+ died = true;
+ }
+ }
+
+ // chance to get over poison (1 in 8, modified for speed)
+ if (random2(1000) < mod_speed( 125, speed ))
+ {
+ if (monster->enchantment[p] == ENCH_POISON_I)
+ mons_del_ench(monster, ENCH_POISON_I);
+ else if (monster->enchantment[p] == ENCH_YOUR_POISON_I)
+ mons_del_ench(monster, ENCH_YOUR_POISON_I);
+ else
+ monster->enchantment[p]--;
+ }
+ break;
+
+ case ENCH_YOUR_ROT_I:
+ if (random2(1000) < mod_speed( 250, speed ))
+ mons_del_ench(monster, ENCH_YOUR_ROT_I);
+ else if (monster->hit_points > 1
+ && random2(1000) < mod_speed( 333, speed ))
+ {
+ hurt_monster(monster, 1);
+ }
+ break;
+
+ //jmf: FIXME: if (undead) make_small_rot_cloud();
+ case ENCH_YOUR_ROT_II:
+ case ENCH_YOUR_ROT_III:
+ case ENCH_YOUR_ROT_IV:
+ if (monster->hit_points > 1
+ && random2(1000) < mod_speed( 333, speed ))
+ {
+ hurt_monster(monster, 1);
+ }
+
+ if (random2(1000) < mod_speed( 250, speed ))
+ monster->enchantment[p]--;
+ break;
+
+ case ENCH_BACKLIGHT_I:
+ if (random2(1000) < mod_speed( 100, speed ))
+ mons_del_ench( monster, ENCH_BACKLIGHT_I );
+ break;
+
+ case ENCH_BACKLIGHT_II:
+ case ENCH_BACKLIGHT_III:
+ case ENCH_BACKLIGHT_IV:
+ if (random2(1000) < mod_speed( 200, speed ))
+ monster->enchantment[p]--;
+ break;
+
+ // assumption: mons_res_fire has already been checked
+ case ENCH_STICKY_FLAME_I:
+ case ENCH_STICKY_FLAME_II:
+ case ENCH_STICKY_FLAME_III:
+ case ENCH_STICKY_FLAME_IV:
+ case ENCH_YOUR_STICKY_FLAME_I:
+ case ENCH_YOUR_STICKY_FLAME_II:
+ case ENCH_YOUR_STICKY_FLAME_III:
+ case ENCH_YOUR_STICKY_FLAME_IV:
+ dam = roll_dice( 2, 4 ) - 1;
+
+ if (mons_res_fire( monster ) < 0)
+ dam += roll_dice( 2, 5 ) - 1;
+
+ // We adjust damage for monster speed (since this is applied
+ // only when the monster moves), and we handle the factional
+ // part as well (so that speed 30 creatures will take damage).
+ dam *= 10;
+ dam = (dam / speed) + ((random2(speed) < (dam % speed)) ? 1 : 0);
+
+ if (dam > 0)
+ {
+ hurt_monster( monster, dam );
+ simple_monster_message(monster, " burns!");
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "sticky flame damage: %d", dam );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ if (monster->hit_points < 1)
+ {
+ monster_die(monster,
+ ((monster->enchantment[p] < ENCH_STICKY_FLAME_I)
+ ? KILL_YOU : KILL_MISC), 0);
+ died = true;
+ }
+ }
+
+ // chance to get over sticky flame (1 in 5, modified for speed)
+ if (random2(1000) < mod_speed( 200, speed ))
+ {
+ if (monster->enchantment[p] == ENCH_STICKY_FLAME_I)
+ mons_del_ench( monster, ENCH_STICKY_FLAME_I );
+ else if (monster->enchantment[p] == ENCH_YOUR_STICKY_FLAME_I)
+ mons_del_ench( monster, ENCH_YOUR_STICKY_FLAME_I );
+ else
+ monster->enchantment[p]--;
+ }
+ break;
+
+ case ENCH_SHORT_LIVED:
+ // This should only be used for ball lightning -- bwr
+ if (random2(1000) < mod_speed( 200, speed ))
+ monster->hit_points = -1;
+ break;
+
+ // 19 is taken by summoning:
+ // If these are changed, must also change abjuration
+ case ENCH_ABJ_I:
+ case ENCH_ABJ_II:
+ case ENCH_ABJ_III:
+ case ENCH_ABJ_IV:
+ if (random2(1000) < mod_speed( 100, speed ))
+ monster->enchantment[p]--;
+
+ if (monster->enchantment[p] < ENCH_ABJ_I)
+ {
+ monster_die(monster, KILL_RESET, 0);
+ died = true;
+ }
+ break;
+
+ case ENCH_ABJ_V:
+ if (random2(1000) < mod_speed( 20, speed ))
+ monster->enchantment[p] = ENCH_ABJ_IV;
+ break;
+
+ case ENCH_ABJ_VI:
+ if (random2(1000) < mod_speed( 10, speed ))
+ monster->enchantment[p] = ENCH_ABJ_V;
+ break;
+
+ case ENCH_CHARM:
+ if (random2(500) <= mod_speed( monster->hit_dice + 10, speed ))
+ mons_del_ench(monster, ENCH_CHARM);
+ break;
+
+ case ENCH_GLOWING_SHAPESHIFTER: // this ench never runs out
+ // number of actions is fine for shapeshifters
+ if (monster->type == MONS_GLOWING_SHAPESHIFTER
+ || random2(1000) < mod_speed( 250, speed ))
+ {
+ monster_polymorph(monster, RANDOM_MONSTER, 0);
+ }
+ break;
+
+ case ENCH_SHAPESHIFTER: // this ench never runs out
+ if (monster->type == MONS_SHAPESHIFTER
+ || random2(1000) < mod_speed( 1000 / ((15 * monster->hit_dice) / 5), speed ))
+ {
+ monster_polymorph(monster, RANDOM_MONSTER, 0);
+ }
+ break;
+
+ case ENCH_TP_I:
+ mons_del_ench( monster, ENCH_TP_I );
+ monster_teleport( monster, true );
+ break;
+
+ case ENCH_TP_II:
+ case ENCH_TP_III:
+ case ENCH_TP_IV:
+ tmp = mod_speed( 1000, speed );
+
+ if (tmp < 1000 && random2(1000) < tmp)
+ monster->enchantment[p]--;
+ else if (monster->enchantment[p] - tmp / 1000 >= ENCH_TP_I)
+ {
+ monster->enchantment[p] -= tmp / 1000;
+ tmp %= 1000;
+
+ if (random2(1000) < tmp)
+ {
+ if (monster->enchantment[p] > ENCH_TP_I)
+ monster->enchantment[p]--;
+ else
+ {
+ mons_del_ench( monster, ENCH_TP_I, ENCH_TP_IV );
+ monster_teleport( monster, true );
+ }
+ }
+ }
+ else
+ {
+ mons_del_ench( monster, ENCH_TP_I, ENCH_TP_IV );
+ monster_teleport( monster, true );
+ }
+ break;
+
+ case ENCH_SLEEP_WARY:
+ if (random2(1000) < mod_speed( 50, speed ))
+ mons_del_ench(monster, ENCH_SLEEP_WARY);
+ break;
+ }
+ }
+
+ return (died);
+} // end handle_enchantment()
+
+//---------------------------------------------------------------
+//
+// handle_movement
+//
+// Move the monster closer to its target square.
+//
+//---------------------------------------------------------------
+static void handle_movement(struct monsters *monster)
+{
+ int dx, dy;
+
+ // some calculations
+ if (monster->type == MONS_BORING_BEETLE && monster->foe == MHITYOU)
+ {
+ dx = you.x_pos - monster->x;
+ dy = you.y_pos - monster->y;
+ }
+ else
+ {
+ dx = monster->target_x - monster->x;
+ dy = monster->target_y - monster->y;
+ }
+
+ // move the monster:
+ mmov_x = (dx > 0) ? 1 : ((dx < 0) ? -1 : 0);
+ mmov_y = (dy > 0) ? 1 : ((dy < 0) ? -1 : 0);
+
+ if (monster->behaviour == BEH_FLEE)
+ {
+ mmov_x *= -1;
+ mmov_y *= -1;
+ }
+
+ // bounds check: don't let fleeing monsters try to run
+ // off the map
+ if (monster->target_x + mmov_x < 0 || monster->target_x + mmov_x >= GXM)
+ mmov_x = 0;
+
+ if (monster->target_y + mmov_y < 0 || monster->target_y + mmov_y >= GYM)
+ mmov_y = 0;
+
+ // now quit if we're can't move
+ if (mmov_x == 0 && mmov_y == 0)
+ return;
+
+ // reproduced here is some semi-legacy code that makes monsters
+ // move somewhat randomly along oblique paths. It is an exceedingly
+ // good idea, given crawl's unique line of sight properties.
+ //
+ // Added a check so that oblique movement paths aren't used when
+ // close to the target square. -- bwr
+ if (grid_distance( dx, dy, 0, 0 ) > 3)
+ {
+ if (abs(dx) > abs(dy))
+ {
+ // sometimes we'll just move parallel the x axis
+ if (coinflip())
+ mmov_y = 0;
+ }
+
+ if (abs(dy) > abs(dx))
+ {
+ // sometimes we'll just move parallel the y axis
+ if (coinflip())
+ mmov_x = 0;
+ }
+ }
+} // end handle_movement()
+
+//---------------------------------------------------------------
+//
+// handle_nearby_ability
+//
+// Gives monsters a chance to use a special ability when they're
+// next to the player.
+//
+//---------------------------------------------------------------
+static void handle_nearby_ability(struct monsters *monster)
+{
+ if (!mons_near( monster )
+ || monster->behaviour == BEH_SLEEP
+ || mons_has_ench( monster, ENCH_SUBMERGED ))
+ {
+ return;
+ }
+
+ if (mons_flag(monster->type, M_SPEAKS) && one_chance_in(21)
+ && monster->behaviour != BEH_WANDER)
+ {
+ mons_speaks(monster);
+ }
+
+ switch (monster->type)
+ {
+ case MONS_SPATIAL_VORTEX:
+ case MONS_KILLER_KLOWN:
+ // used for colour (butterflies too, but they don't change)
+ monster->number = random_colour();
+ break;
+
+ case MONS_GIANT_EYEBALL:
+ if (coinflip() && !mons_friendly(monster)
+ && monster->behaviour != BEH_WANDER)
+ {
+ simple_monster_message(monster, " stares at you.");
+
+ if (you.paralysis < 10)
+ you.paralysis += 2 + random2(3);
+ }
+ break;
+
+ case MONS_EYE_OF_DRAINING:
+ if (coinflip() && !mons_friendly(monster)
+ && monster->behaviour != BEH_WANDER)
+ {
+ simple_monster_message(monster, " stares at you.");
+
+ dec_mp(5 + random2avg(13, 3));
+
+ heal_monster(monster, 10, true); // heh heh {dlb}
+ }
+ break;
+
+ case MONS_LAVA_WORM:
+ case MONS_LAVA_FISH:
+ case MONS_LAVA_SNAKE:
+ case MONS_SALAMANDER:
+ case MONS_BIG_FISH:
+ case MONS_GIANT_GOLDFISH:
+ case MONS_ELECTRICAL_EEL:
+ case MONS_JELLYFISH:
+ case MONS_WATER_ELEMENTAL:
+ case MONS_SWAMP_WORM:
+ // XXX: We're being a bit player-centric here right now...
+ // really we should replace the grid_distance() check
+ // with one that checks for unaligned monsters as well. -- bwr
+ if (mons_has_ench( monster, ENCH_SUBMERGED))
+ {
+ if (grd[monster->x][monster->y] == DNGN_SHALLOW_WATER
+ || grd[monster->x][monster->y] == DNGN_BLUE_FOUNTAIN
+ || (!mons_friendly(monster)
+ && grid_distance( monster->x, monster->y,
+ you.x_pos, you.y_pos ) == 1
+ && (monster->hit_points == monster->max_hit_points
+ || (monster->hit_points > monster->max_hit_points / 2
+ && coinflip()))))
+ {
+ mons_del_ench( monster, ENCH_SUBMERGED );
+ }
+ }
+ else if (monster_habitat(monster->type) == grd[monster->x][monster->y]
+ && (one_chance_in(5)
+ || (grid_distance( monster->x, monster->y,
+ you.x_pos, you.y_pos ) > 1
+ && monster->type != MONS_ELECTRICAL_EEL
+ && monster->type != MONS_LAVA_SNAKE
+ && !one_chance_in(20))
+ || monster->hit_points <= monster->max_hit_points / 2)
+ || env.cgrid[monster->x][monster->y] != EMPTY_CLOUD)
+ {
+ mons_add_ench( monster, ENCH_SUBMERGED );
+ }
+ break;
+
+ case MONS_AIR_ELEMENTAL:
+ if (one_chance_in(5))
+ mons_add_ench( monster, ENCH_SUBMERGED );
+ break;
+
+ case MONS_PANDEMONIUM_DEMON:
+ if (ghost.values[ GVAL_DEMONLORD_CYCLE_COLOUR ])
+ monster->number = random_colour();
+ break;
+ }
+} // end handle_nearby_ability()
+
+//---------------------------------------------------------------
+//
+// handle_special_ability
+//
+// $$$ not sure what to say here...
+//
+//---------------------------------------------------------------
+static bool handle_special_ability(struct monsters *monster, bolt & beem)
+{
+ bool used = false;
+
+ FixedArray < unsigned int, 19, 19 > show;
+
+ if (!mons_near( monster )
+ || monster->behaviour == BEH_SLEEP
+ || mons_has_ench( monster, ENCH_SUBMERGED ))
+ {
+ return (false);
+ }
+
+// losight(show, grd, you.x_pos, you.y_pos);
+
+ switch (monster->type)
+ {
+ case MONS_BALL_LIGHTNING:
+ if (monster->attitude == ATT_HOSTILE
+ && distance( you.x_pos, you.y_pos, monster->x, monster->y ) <= 5)
+ {
+ monster->hit_points = -1;
+ used = true;
+ break;
+ }
+
+ for (int i = 0; i < MAX_MONSTERS; i++)
+ {
+ struct monsters *targ = &menv[i];
+
+ if (targ->type == -1 || targ->type == NON_MONSTER)
+ continue;
+
+ if (distance( monster->x, monster->y, targ->x, targ->y ) >= 5)
+ continue;
+
+ if (monster->attitude == targ->attitude)
+ continue;
+
+ // faking LOS by checking the neighbouring square
+ int dx = targ->x - monster->x;
+ if (dx)
+ dx /= dx;
+
+ int dy = targ->y - monster->y;
+ if (dy)
+ dy /= dy;
+
+ const int tx = monster->x + dx;
+ const int ty = monster->y + dy;
+
+ if (tx < 0 || tx > GXM || ty < 0 || ty > GYM)
+ continue;
+
+ if (grd[tx][ty] > DNGN_LAST_SOLID_TILE)
+ {
+ monster->hit_points = -1;
+ used = true;
+ break;
+ }
+ }
+ break;
+
+ case MONS_LAVA_SNAKE:
+ if (mons_has_ench(monster, ENCH_CONFUSION))
+ break;
+
+ if (!mons_player_visible( monster ))
+ break;
+
+ if (coinflip())
+ break;
+
+ // setup tracer
+ strcpy(beem.beam_name, "glob of lava");
+ beem.range = 4;
+ beem.rangeMax = 13;
+ beem.damage = dice_def( 3, 10 );
+ beem.colour = RED;
+ beem.type = SYM_ZAP;
+ beem.flavour = BEAM_LAVA;
+ beem.hit = 20;
+ beem.beam_source = monster_index(monster);
+ beem.thrower = KILL_MON;
+ beem.aux_source = "glob of lava";
+
+ // fire tracer
+ fire_tracer(monster, beem);
+
+ // good idea?
+ if (mons_should_fire(beem))
+ {
+ simple_monster_message(monster, " spits lava!");
+ fire_beam(beem);
+ used = true;
+ }
+ break;
+
+ case MONS_ELECTRICAL_EEL:
+ if (mons_has_ench(monster, ENCH_CONFUSION))
+ break;
+
+ if (!mons_player_visible( monster ))
+ break;
+
+ if (coinflip())
+ break;
+
+ // setup tracer
+ strcpy(beem.beam_name, "bolt of electricity");
+ beem.damage = dice_def( 3, 6 );
+ beem.colour = LIGHTCYAN;
+ beem.type = SYM_ZAP;
+ beem.flavour = BEAM_ELECTRICITY;
+ beem.hit = 150;
+ beem.beam_source = monster_index(monster);
+ beem.thrower = KILL_MON;
+ beem.aux_source = "bolt of electricity";
+ beem.range = 4;
+ beem.rangeMax = 13;
+ beem.isBeam = true;
+
+ // fire tracer
+ fire_tracer(monster, beem);
+
+ // good idea?
+ if (mons_should_fire(beem))
+ {
+ simple_monster_message(monster, " shoots out a bolt of electricity!");
+ fire_beam(beem);
+ used = true;
+ }
+ break;
+
+ case MONS_ACID_BLOB:
+ case MONS_OKLOB_PLANT:
+ if (mons_has_ench(monster, ENCH_CONFUSION))
+ break;
+
+ if (!mons_player_visible( monster ))
+ break;
+
+ if (one_chance_in(3))
+ used = plant_spit(monster, beem);
+
+ break;
+
+ case MONS_PIT_FIEND:
+ if (one_chance_in(3))
+ break;
+ // deliberate fall through
+ case MONS_FIEND:
+ if (mons_has_ench(monster, ENCH_CONFUSION))
+ break;
+
+ // friendly fiends won't use torment, preferring hellfire
+ // (right now there is no way a monster can predict how
+ // badly they'll damage the player with torment) -- GDL
+ if (one_chance_in(4))
+ {
+ int spell_cast;
+
+ switch (random2(4))
+ {
+ case 0:
+ if (!mons_friendly(monster))
+ {
+ spell_cast = MS_TORMENT;
+ mons_cast(monster, beem, spell_cast);
+ used = true;
+ break;
+ }
+ // deliberate fallthrough -- see above
+ case 1:
+ case 2:
+ case 3:
+ spell_cast = MS_HELLFIRE;
+ setup_mons_cast(monster, beem, spell_cast);
+
+ // fire tracer
+ fire_tracer(monster, beem);
+
+ // good idea?
+ if (mons_should_fire(beem))
+ {
+ simple_monster_message( monster, " makes a gesture!",
+ MSGCH_MONSTER_SPELL );
+
+ mons_cast(monster, beem, spell_cast);
+ used = true;
+ }
+ break;
+ }
+
+ mmov_x = 0;
+ mmov_y = 0;
+ }
+ break;
+
+ case MONS_IMP:
+ case MONS_PHANTOM:
+ case MONS_INSUBSTANTIAL_WISP:
+ case MONS_BLINK_FROG:
+ case MONS_KILLER_KLOWN:
+ if (one_chance_in(7))
+ {
+ simple_monster_message(monster, " blinks.");
+ monster_blink(monster);
+ }
+ break;
+
+ case MONS_MANTICORE:
+ if (!mons_player_visible( monster ))
+ break;
+
+ if (mons_has_ench(monster, ENCH_CONFUSION))
+ break;
+
+ if (!mons_near(monster))
+ break;
+
+ // the fewer spikes the manticore has left, the less
+ // likely it will use them.
+ if (random2(16) >= static_cast<int>(monster->number))
+ break;
+
+ // do the throwing right here, since the beam is so
+ // easy to set up and doesn't involve inventory.
+
+ // set up the beam
+ strcpy(beem.beam_name, "volley of spikes");
+ beem.range = 9;
+ beem.rangeMax = 9;
+ beem.hit = 14;
+ beem.damage = dice_def( 2, 10 );
+ beem.beam_source = monster_index(monster);
+ beem.type = SYM_MISSILE;
+ beem.colour = LIGHTGREY;
+ beem.flavour = BEAM_MISSILE;
+ beem.thrower = KILL_MON;
+ beem.aux_source = "volley of spikes";
+ beem.isBeam = false;
+
+ // fire tracer
+ fire_tracer(monster, beem);
+
+ // good idea?
+ if (mons_should_fire(beem))
+ {
+ simple_monster_message(monster, " flicks its tail!");
+ fire_beam(beem);
+ used = true;
+ // decrement # of volleys left
+ monster->number -= 1;
+ }
+ break;
+
+ // dragon breath weapon:
+ case MONS_DRAGON:
+ case MONS_HELL_HOUND:
+ case MONS_ICE_DRAGON:
+ case MONS_LINDWURM:
+ case MONS_FIREDRAKE:
+ case MONS_XTAHUA:
+ if (!mons_player_visible( monster ))
+ break;
+
+ if (mons_has_ench(monster, ENCH_CONFUSION))
+ break;
+
+ if ((monster->type != MONS_HELL_HOUND && random2(13) < 3)
+ || one_chance_in(10))
+ {
+ setup_dragon(monster, beem);
+
+ // fire tracer
+ fire_tracer(monster, beem);
+
+ // good idea?
+ if (mons_should_fire(beem))
+ {
+ simple_monster_message(monster, " breathes.");
+ fire_beam(beem);
+ mmov_x = 0;
+ mmov_y = 0;
+ used = true;
+ }
+ }
+ break;
+ }
+
+ return (used);
+} // end handle_special_ability()
+
+//---------------------------------------------------------------
+//
+// handle_potion
+//
+// Give the monster a chance to quaff a potion. Returns true if
+// the monster imbibed.
+//
+//---------------------------------------------------------------
+static bool handle_potion(struct monsters *monster, bolt & beem)
+{
+
+ // yes, there is a logic to this ordering {dlb}:
+ if (monster->behaviour == BEH_SLEEP)
+ return (false);
+ else if (monster->inv[MSLOT_POTION] == NON_ITEM)
+ return (false);
+ else if (!one_chance_in(3))
+ return (false);
+ else
+ {
+ bool imbibed = false;
+
+ switch (mitm[monster->inv[MSLOT_POTION]].sub_type)
+ {
+ case POT_HEALING:
+ case POT_HEAL_WOUNDS:
+ if (monster->hit_points <= monster->max_hit_points / 2
+ && mons_holiness(monster->type) != MH_UNDEAD
+ && mons_holiness(monster->type) != MH_NONLIVING
+ && mons_holiness(monster->type) != MH_PLANT)
+ {
+ simple_monster_message(monster, " drinks a potion.");
+
+ if (heal_monster(monster, 5 + random2(7), false))
+ simple_monster_message(monster, " is healed!");
+
+ if (mitm[monster->inv[MSLOT_POTION]].sub_type
+ == POT_HEAL_WOUNDS)
+ {
+ heal_monster(monster, 10 + random2avg(28, 3), false);
+ }
+
+ imbibed = true;
+ }
+ break;
+
+ case POT_SPEED:
+ // notice that these are the same odd colours used in
+ // mons_ench_f2() {dlb}
+ beem.colour = BLUE;
+ // intentional fall through
+ case POT_INVISIBILITY:
+ if (mitm[monster->inv[MSLOT_POTION]].sub_type == POT_INVISIBILITY)
+ beem.colour = MAGENTA;
+
+ // why only drink these if not near player? {dlb}
+ if (!mons_near(monster))
+ {
+ simple_monster_message(monster, " drinks a potion.");
+
+ mons_ench_f2(monster, beem);
+
+ imbibed = true;
+ }
+ break;
+ }
+
+ if (imbibed)
+ {
+ if (dec_mitm_item_quantity( monster->inv[MSLOT_POTION], 1 ))
+ monster->inv[MSLOT_POTION] = NON_ITEM;
+ }
+
+ return (imbibed);
+ }
+} // end handle_potion()
+
+static bool handle_reaching(struct monsters *monster)
+{
+ bool ret = false;
+ const int wpn = monster->inv[MSLOT_WEAPON];
+
+ if (mons_aligned(monster_index(monster), monster->foe))
+ return (false);
+
+ if (mons_has_ench( monster, ENCH_SUBMERGED ))
+ return (false);
+
+ if (wpn != NON_ITEM && get_weapon_brand( mitm[wpn] ) == SPWPN_REACHING )
+ {
+ if (monster->foe == MHITYOU)
+ {
+ // this check isn't redundant -- player may be invisible.
+ if (monster->target_x == you.x_pos && monster->target_y == you.y_pos)
+ {
+ int dx = abs(monster->x - you.x_pos);
+ int dy = abs(monster->y - you.y_pos);
+
+ if ((dx == 2 && dy <= 2) || (dy == 2 && dx <= 2))
+ {
+ ret = true;
+ monster_attack( monster_index(monster) );
+ }
+ }
+ }
+ else if (monster->foe != MHITNOT)
+ {
+ // same comments as to invisibility as above.
+ if (monster->target_x == menv[monster->foe].x
+ && monster->target_y == menv[monster->foe].y)
+ {
+ int dx = abs(monster->x - menv[monster->foe].x);
+ int dy = abs(monster->y - menv[monster->foe].y);
+ if ((dx == 2 && dy <= 2) || (dy == 2 && dx <= 2))
+ {
+ ret = true;
+ monsters_fight( monster_index(monster), monster->foe );
+ }
+ }
+ }
+ }
+
+ return ret;
+} // end handle_reaching()
+
+//---------------------------------------------------------------
+//
+// handle_scroll
+//
+// Give the monster a chance to read a scroll. Returns true if
+// the monster read something.
+//
+//---------------------------------------------------------------
+static bool handle_scroll(struct monsters *monster)
+{
+ // yes, there is a logic to this ordering {dlb}:
+ if (mons_has_ench(monster, ENCH_CONFUSION)
+ || monster->behaviour == BEH_SLEEP
+ || mons_has_ench( monster, ENCH_SUBMERGED ))
+ {
+ return (false);
+ }
+ else if (monster->inv[MSLOT_SCROLL] == NON_ITEM)
+ return (false);
+ else if (!one_chance_in(3))
+ return (false);
+ else
+ {
+ bool read = false;
+
+ // notice how few cases are actually accounted for here {dlb}:
+ switch (mitm[monster->inv[MSLOT_SCROLL]].sub_type)
+ {
+ case SCR_TELEPORTATION:
+ if (!mons_has_ench(monster, ENCH_TP_I))
+ {
+ if (monster->behaviour == BEH_FLEE)
+ {
+ simple_monster_message(monster, " reads a scroll.");
+ monster_teleport(monster, false);
+ read = true;
+ }
+ }
+ break;
+
+ case SCR_BLINKING:
+ if (monster->behaviour == BEH_FLEE)
+ {
+ if (mons_near(monster))
+ {
+ simple_monster_message(monster, " reads a scroll.");
+ simple_monster_message(monster, " blinks!");
+ monster_blink(monster);
+ read = true;
+ }
+ }
+ break;
+
+ case SCR_SUMMONING:
+ if (mons_near(monster))
+ {
+ simple_monster_message(monster, " reads a scroll.");
+ create_monster( MONS_ABOMINATION_SMALL, ENCH_ABJ_II,
+ SAME_ATTITUDE(monster), monster->x, monster->y,
+ monster->foe, 250 );
+ read = true;
+ }
+ break;
+ }
+
+ if (read)
+ {
+ if (dec_mitm_item_quantity( monster->inv[MSLOT_SCROLL], 1 ))
+ monster->inv[MSLOT_SCROLL] = NON_ITEM;
+ }
+
+ return read;
+ }
+} // end handle_scroll()
+
+//---------------------------------------------------------------
+//
+// handle_wand
+//
+// Give the monster a chance to zap a wand. Returns true if the
+// monster zapped.
+//
+//---------------------------------------------------------------
+static bool handle_wand(struct monsters *monster, bolt &beem)
+{
+ // yes, there is a logic to this ordering {dlb}:
+ if (monster->behaviour == BEH_SLEEP)
+ return (false);
+ else if (!mons_near(monster))
+ return (false);
+ else if (mons_has_ench( monster, ENCH_SUBMERGED ))
+ return (false);
+ else if (monster->inv[MSLOT_WAND] == NON_ITEM
+ || mitm[monster->inv[MSLOT_WAND]].plus <= 0)
+ {
+ return (false);
+ }
+ else if (coinflip())
+ {
+ bool niceWand = false;
+ bool zap = false;
+
+ // map wand type to monster spell type
+ int mzap = map_wand_to_mspell(mitm[monster->inv[MSLOT_WAND]].sub_type);
+ if (mzap == 0)
+ return (false);
+
+ // set up the beam
+ int power = 30 + monster->hit_dice;
+ struct SBeam theBeam = mons_spells(mzap, power);
+
+ // XXX: ugly hack this:
+ static char wand_buff[ ITEMNAME_SIZE ];
+
+ strcpy( beem.beam_name, theBeam.name.c_str() );
+ beem.beam_source = monster_index(monster);
+ beem.source_x = monster->x;
+ beem.source_y = monster->y;
+ beem.colour = theBeam.colour;
+ beem.range = theBeam.range;
+ beem.rangeMax = theBeam.rangeMax;
+ beem.damage = theBeam.damage;
+ beem.ench_power = theBeam.ench_power;
+ beem.hit = theBeam.hit;
+ beem.type = theBeam.type;
+ beem.flavour = theBeam.flavour;
+ beem.thrower = theBeam.thrown;
+ beem.isBeam = theBeam.isBeam;
+
+ item_def item = mitm[ monster->inv[MSLOT_WAND] ];
+
+#if HISCORE_WEAPON_DETAIL
+ set_ident_flags( item, ISFLAG_IDENT_MASK );
+#else
+ unset_ident_flags( item, ISFLAG_IDENT_MASK );
+ set_ident_flags( item, ISFLAG_KNOW_TYPE );
+#endif
+
+ item_name( item, DESC_PLAIN, wand_buff );
+
+ beem.aux_source = wand_buff;
+
+ switch (mitm[monster->inv[MSLOT_WAND]].sub_type)
+ {
+ // these have been deemed "too tricky" at this time {dlb}:
+ case WAND_POLYMORPH_OTHER:
+ case WAND_ENSLAVEMENT:
+ case WAND_DIGGING:
+ case WAND_RANDOM_EFFECTS:
+ return (false);
+
+ // these are wands that monsters will aim at themselves {dlb}:
+ case WAND_HASTING:
+ if (!mons_has_ench(monster, ENCH_HASTE))
+ {
+ beem.target_x = monster->x;
+ beem.target_y = monster->y;
+
+ niceWand = true;
+ break;
+ }
+ return (false);
+
+ case WAND_HEALING:
+ if (monster->hit_points <= monster->max_hit_points / 2)
+ {
+ beem.target_x = monster->x;
+ beem.target_y = monster->y;
+
+ niceWand = true;
+ break;
+ }
+ return (false);
+
+ case WAND_INVISIBILITY:
+ if (!mons_has_ench( monster, ENCH_INVIS )
+ && !mons_has_ench( monster, ENCH_SUBMERGED ))
+ {
+ beem.target_x = monster->x;
+ beem.target_y = monster->y;
+
+ niceWand = true;
+ break;
+ }
+ return (false);
+
+ case WAND_TELEPORTATION:
+ if (monster->hit_points <= monster->max_hit_points / 2)
+ {
+ if (!mons_has_ench(monster, ENCH_TP_I) && !one_chance_in(20))
+ {
+ beem.target_x = monster->x;
+ beem.target_y = monster->y;
+
+ niceWand = true;
+ break;
+ }
+ // this break causes the wand to be tried on the player:
+ break;
+ }
+ return (false);
+ }
+
+ // fire tracer, if necessary
+ if (!niceWand)
+ {
+ fire_tracer( monster, beem );
+
+ // good idea?
+ zap = mons_should_fire( beem );
+ }
+
+ if (niceWand || zap)
+ {
+ if (!simple_monster_message(monster, " zaps a wand."))
+ {
+ if (!silenced(you.x_pos, you.y_pos))
+ mpr("You hear a zap.");
+ }
+
+ // charge expenditure {dlb}
+ mitm[monster->inv[MSLOT_WAND]].plus--;
+ beem.isTracer = false;
+ fire_beam( beem );
+
+ return (true);
+ }
+ }
+
+ return (false);
+} // end handle_wand()
+
+//---------------------------------------------------------------
+//
+// handle_spell
+//
+// Give the monster a chance to cast a spell. Returns true if
+// a spell was cast.
+//
+//---------------------------------------------------------------
+static bool handle_spell( struct monsters *monster, bolt & beem )
+{
+ bool monsterNearby = mons_near(monster);
+ bool finalAnswer = false; // as in: "Is that your...?" {dlb}
+
+ // yes, there is a logic to this ordering {dlb}:
+ if (monster->behaviour == BEH_SLEEP
+ || !mons_flag( monster->type, M_SPELLCASTER )
+ || mons_has_ench( monster, ENCH_SUBMERGED ))
+ {
+ return (false);
+ }
+
+ if ((mons_flag(monster->type, M_ACTUAL_SPELLS)
+ || mons_flag(monster->type, M_PRIEST))
+ && (mons_has_ench(monster, ENCH_GLOWING_SHAPESHIFTER, ENCH_SHAPESHIFTER)))
+ {
+ return (false); //jmf: shapeshiftes don't get spells, just
+ // physical powers.
+ }
+ else if (mons_has_ench(monster, ENCH_CONFUSION)
+ && !mons_flag(monster->type, M_CONFUSED))
+ {
+ return (false);
+ }
+ else if (monster->type == MONS_PANDEMONIUM_DEMON
+ && !ghost.values[ GVAL_DEMONLORD_SPELLCASTER ])
+ {
+ return (false);
+ }
+ else if (random2(200) > monster->hit_dice + 50
+ || (monster->type == MONS_BALL_LIGHTNING && coinflip()))
+ {
+ return (false);
+ }
+ else
+ {
+ int spell_cast = MS_NO_SPELL;
+ int hspell_pass[6] = { MS_NO_SPELL, MS_NO_SPELL, MS_NO_SPELL,
+ MS_NO_SPELL, MS_NO_SPELL, MS_NO_SPELL };
+
+ int msecc = ((monster->type == MONS_HELLION) ? MST_BURNING_DEVIL :
+ (monster->type == MONS_PANDEMONIUM_DEMON) ? MST_GHOST
+ : monster->number);
+
+ mons_spell_list( msecc, hspell_pass );
+
+ // forces the casting of dig when player not visible - this is EVIL!
+ if (!monsterNearby)
+ {
+ if (hspell_pass[4] == MS_DIG && monster->behaviour == BEH_SEEK)
+ {
+ spell_cast = MS_DIG;
+ finalAnswer = true;
+ }
+ else if (hspell_pass[2] == MS_HEAL
+ && monster->hit_points < monster->max_hit_points)
+ {
+ // The player's out of sight!
+ // Quick, let's take a turn to heal ourselves. -- bwr
+ spell_cast = MS_HEAL;
+ finalAnswer = true;
+ }
+ else if (monster->behaviour == BEH_FLEE)
+ {
+ // Since the player isn't around, we'll extend the monster's
+ // normal fleeing choices to include the self-enchant slot.
+ if (ms_useful_fleeing_out_of_sight(monster,hspell_pass[5]))
+ {
+ spell_cast = hspell_pass[5];
+ finalAnswer = true;
+ }
+ else if (ms_useful_fleeing_out_of_sight(monster,hspell_pass[2]))
+ {
+ spell_cast = hspell_pass[2];
+ finalAnswer = true;
+ }
+ }
+ else if (monster->foe == MHITYOU)
+ {
+ return (false);
+ }
+ }
+
+ // Promote the casting of useful spells for low-HP monsters.
+ if (!finalAnswer
+ && monster->hit_points < monster->max_hit_points / 4
+ && !one_chance_in(4))
+ {
+ // Note: There should always be at least some chance we don't
+ // get here... even if the monster is on it's last HP. That
+ // way we don't have to worry about monsters infinitely casting
+ // Healing on themselves (ie orc priests).
+ if (monster->behaviour == BEH_FLEE
+ && ms_low_hitpoint_cast( monster, hspell_pass[5] ))
+ {
+ spell_cast = hspell_pass[5];
+ finalAnswer = true;
+ }
+ else if (ms_low_hitpoint_cast( monster, hspell_pass[2] ))
+ {
+ spell_cast = hspell_pass[2];
+ finalAnswer = true;
+ }
+ }
+
+ if (!finalAnswer)
+ {
+ // should monster not have selected dig by now, it never will:
+ if (hspell_pass[4] == MS_DIG)
+ hspell_pass[4] = MS_NO_SPELL;
+
+ // remove healing/invis/haste if we don't need them
+ int num_no_spell = 0;
+
+ for (int i = 0; i < 6; i++)
+ {
+ if (hspell_pass[i] == MS_NO_SPELL)
+ num_no_spell++;
+ else if (ms_waste_of_time( monster, hspell_pass[i] ))
+ {
+ hspell_pass[i] = MS_NO_SPELL;
+ num_no_spell++;
+ }
+ }
+
+ // If no useful spells... cast no spell.
+ if (num_no_spell == 6)
+ return (false);
+
+ // up to four tries to pick a spell.
+ for (int loopy = 0; loopy < 4; loopy ++)
+ {
+ bool spellOK = false;
+
+ // setup spell - fleeing monsters will always try to
+ // choose their emergency spell.
+ if (monster->behaviour == BEH_FLEE)
+ {
+ spell_cast = (one_chance_in(5) ? MS_NO_SPELL
+ : hspell_pass[5]);
+ }
+ else
+ {
+ // Randomly picking one of the non-emergency spells:
+ spell_cast = hspell_pass[random2(5)];
+ }
+
+ if (spell_cast == MS_NO_SPELL)
+ continue;
+
+ // setup the spell
+ setup_mons_cast(monster, beem, spell_cast);
+
+ // beam-type spells requiring tracers
+ if (ms_requires_tracer(spell_cast))
+ {
+ fire_tracer(monster, beem);
+ // good idea?
+ if (mons_should_fire(beem))
+ spellOK = true;
+ }
+ else
+ {
+ // all direct-effect/summoning/self-enchantments/etc
+ spellOK = true;
+
+ if (ms_direct_nasty(spell_cast)
+ && mons_aligned(monster_index(monster), monster->foe))
+ {
+ spellOK = false;
+ }
+ else if (monster->foe == MHITYOU || monster->foe == MHITNOT)
+ {
+ // XXX: Note the crude hack so that monsters can
+ // use ME_ALERT to target (we should really have
+ // a measure of time instead of peeking to see
+ // if the player is still there). -- bwr
+ if (!mons_player_visible( monster )
+ && (monster->target_x != you.x_pos
+ || monster->target_y != you.y_pos
+ || coinflip()))
+ {
+ spellOK = false;
+ }
+ }
+ else if (!mons_monster_visible( monster, &menv[monster->foe] ))
+ {
+ spellOK = false;
+ }
+ }
+
+ // if not okay, then maybe we'll cast a defensive spell
+ if (!spellOK)
+ spell_cast = (coinflip() ? hspell_pass[2] : MS_NO_SPELL);
+
+ if (spell_cast != MS_NO_SPELL)
+ break;
+ }
+ }
+
+ // should the monster *still* not have a spell, well, too bad {dlb}:
+ if (spell_cast == MS_NO_SPELL)
+ return (false);
+
+ // Try to animate dead: if nothing rises, pretend we didn't cast it
+ if (spell_cast == MS_ANIMATE_DEAD
+ && !animate_dead( 100, SAME_ATTITUDE(monster), monster->foe, 0 ))
+ {
+ return (false);
+ }
+
+ if (monsterNearby) // handle monsters within range of player
+ {
+ if (monster->type == MONS_GERYON)
+ {
+ if (silenced(monster->x, monster->y))
+ return (false);
+
+ simple_monster_message( monster, " winds a great silver horn.",
+ MSGCH_MONSTER_SPELL );
+ }
+ else if (mons_is_demon( monster->type ))
+ {
+ simple_monster_message( monster, " gestures.",
+ MSGCH_MONSTER_SPELL );
+ }
+ else
+ {
+ switch (monster->type)
+ {
+ default:
+ if (silenced(monster->x, monster->y))
+ return (false);
+
+ if (mons_flag(monster->type, M_PRIEST))
+ {
+ switch (random2(3))
+ {
+ case 0:
+ simple_monster_message( monster,
+ " prays.",
+ MSGCH_MONSTER_SPELL );
+ break;
+ case 1:
+ simple_monster_message( monster,
+ " mumbles some strange prayers.",
+ MSGCH_MONSTER_SPELL );
+ break;
+ case 2:
+ default:
+ simple_monster_message( monster,
+ " utters an invocation.",
+ MSGCH_MONSTER_SPELL );
+ break;
+ }
+ }
+ else
+ {
+ switch (random2(3))
+ {
+ case 0:
+ // XXX: could be better, chosen to match the
+ // ones in monspeak.cc... has the problem
+ // that it doesn't suggest a vocal component. -- bwr
+ simple_monster_message( monster,
+ " gestures wildly.",
+ MSGCH_MONSTER_SPELL );
+ break;
+ case 1:
+ simple_monster_message( monster,
+ " mumbles some strange words.",
+ MSGCH_MONSTER_SPELL );
+ break;
+ case 2:
+ default:
+ simple_monster_message( monster,
+ " casts a spell.",
+ MSGCH_MONSTER_SPELL );
+ break;
+ }
+ }
+ break;
+
+ case MONS_BALL_LIGHTNING:
+ monster->hit_points = -1;
+ break;
+
+ case MONS_STEAM_DRAGON:
+ case MONS_MOTTLED_DRAGON:
+ case MONS_STORM_DRAGON:
+ case MONS_GOLDEN_DRAGON:
+ case MONS_SHADOW_DRAGON:
+ case MONS_SWAMP_DRAGON:
+ case MONS_SWAMP_DRAKE:
+ case MONS_HELL_HOG:
+ case MONS_SERPENT_OF_HELL:
+ case MONS_QUICKSILVER_DRAGON:
+ case MONS_IRON_DRAGON:
+ if (!simple_monster_message(monster, " breathes.",
+ MSGCH_MONSTER_SPELL))
+ {
+ if (!silenced(monster->x, monster->y)
+ && !silenced(you.x_pos, you.y_pos))
+ {
+ mpr("You hear a roar.", MSGCH_MONSTER_SPELL);
+ }
+ }
+ break;
+
+ case MONS_VAPOUR:
+ mons_add_ench( monster, ENCH_SUBMERGED );
+ break;
+
+ case MONS_BRAIN_WORM:
+ case MONS_ELECTRIC_GOLEM:
+ // These don't show any signs that they're casting a spell.
+ break;
+
+ case MONS_GREAT_ORB_OF_EYES:
+ case MONS_SHINING_EYE:
+ case MONS_EYE_OF_DEVASTATION:
+ simple_monster_message(monster, " gazes.", MSGCH_MONSTER_SPELL);
+ break;
+
+ case MONS_GIANT_ORANGE_BRAIN:
+ simple_monster_message(monster, " pulsates.",
+ MSGCH_MONSTER_SPELL);
+ break;
+
+ case MONS_NAGA:
+ case MONS_NAGA_WARRIOR:
+ simple_monster_message(monster, " spits poison.",
+ MSGCH_MONSTER_SPELL);
+ break;
+ }
+ }
+ }
+ else // handle far-away monsters
+ {
+ if (monster->type == MONS_GERYON
+ && !silenced(you.x_pos, you.y_pos))
+ {
+ mpr("You hear a weird and mournful sound.");
+ }
+ }
+
+ // FINALLY! determine primary spell effects {dlb}:
+ if (spell_cast == MS_BLINK && monsterNearby)
+ // why only cast blink if nearby? {dlb}
+ {
+ simple_monster_message(monster, " blinks!");
+ monster_blink(monster);
+ }
+ else
+ {
+ mons_cast(monster, beem, spell_cast);
+ mmov_x = 0;
+ mmov_y = 0;
+ }
+ } // end "if mons_flag(monster->type, M_SPELLCASTER) ...
+
+ return (true);
+} // end handle_spell()
+
+//---------------------------------------------------------------
+//
+// handle_throw
+//
+// Give the monster a chance to throw something. Returns true if
+// the monster hurled.
+//
+//---------------------------------------------------------------
+static bool handle_throw(struct monsters *monster, bolt & beem)
+{
+ // yes, there is a logic to this ordering {dlb}:
+ if (mons_has_ench(monster, ENCH_CONFUSION)
+ || monster->behaviour == BEH_SLEEP
+ || mons_has_ench( monster, ENCH_SUBMERGED ))
+ {
+ return (false);
+ }
+
+ if (mons_itemuse(monster->type) < MONUSE_OPEN_DOORS)
+ return (false);
+
+ const int mon_item = monster->inv[MSLOT_MISSILE];
+ if (mon_item == NON_ITEM || !is_valid_item( mitm[mon_item] ))
+ return (false);
+
+ // don't allow offscreen throwing.. for now.
+ if (monster->foe == MHITYOU && !mons_near(monster))
+ return (false);
+
+ // poor 2-headed ogres {dlb}
+ if (monster->type == MONS_TWO_HEADED_OGRE || monster->type == MONS_ETTIN)
+ return (false);
+
+ // recent addition {GDL} - monsters won't throw if they can do melee.
+ // wastes valuable ammo, and most monsters are better at melee anyway.
+ if (adjacent( beem.target_x, beem.target_y, monster->x, monster->y ))
+ return (false);
+
+ if (one_chance_in(5))
+ return (false);
+
+ // new (GDL) - don't throw idiotic stuff. It's a waste of time.
+ int wepClass = mitm[mon_item].base_type;
+ int wepType = mitm[mon_item].sub_type;
+
+ int weapon = monster->inv[MSLOT_WEAPON];
+
+ int lnchClass = (weapon != NON_ITEM) ? mitm[weapon].base_type : -1;
+ int lnchType = (weapon != NON_ITEM) ? mitm[weapon].sub_type : 0;
+
+ bool thrown = false;
+ bool launched = false;
+
+ throw_type( lnchClass, lnchType, wepClass, wepType, launched, thrown );
+
+ if (!launched && !thrown)
+ return (false);
+
+ // ok, we'll try it.
+ setup_generic_throw( monster, beem );
+
+ // fire tracer
+ fire_tracer( monster, beem );
+
+ // good idea?
+ if (mons_should_fire( beem ))
+ {
+ beem.beam_name[0] = '\0';
+ return (mons_throw( monster, beem, mon_item ));
+ }
+
+ return (false);
+} // end handle_throw()
+
+
+//---------------------------------------------------------------
+//
+// handle_monsters
+//
+// This is the routine that controls monster AI.
+//
+//---------------------------------------------------------------
+void handle_monsters(void)
+{
+ bool brkk = false;
+ struct bolt beem;
+ int i;
+
+ FixedArray < unsigned int, 19, 19 > show;
+
+// losight(show, grd, you.x_pos, you.y_pos);
+
+ for (i = 0; i < MAX_MONSTERS; i++)
+ {
+ struct monsters *monster = &menv[i];
+
+ if (monster->type != -1)
+ {
+ if (monster->hit_points > monster->max_hit_points)
+ monster->hit_points = monster->max_hit_points;
+
+ // monster just summoned (or just took stairs), skip this action
+ if (testbits( monster->flags, MF_JUST_SUMMONED ))
+ {
+ monster->flags &= ~MF_JUST_SUMMONED;
+ continue;
+ }
+
+ monster->speed_increment += (monster->speed * you.time_taken) / 10;
+
+ if (you.slow > 0)
+ {
+ monster->speed_increment += (monster->speed * you.time_taken) / 10;
+ }
+
+ // Handle enchantments and clouds on nonmoving monsters:
+ if (monster->speed == 0)
+ {
+ if (env.cgrid[monster->x][monster->y] != EMPTY_CLOUD
+ && !mons_has_ench( monster, ENCH_SUBMERGED ))
+ {
+ mons_in_cloud( monster );
+ }
+
+ handle_enchantment( monster );
+ }
+
+ // memory is decremented here for a reason -- we only want it
+ // decrementing once per monster "move"
+ if (monster->foe_memory > 0)
+ monster->foe_memory--;
+
+ if (monster->type == MONS_GLOWING_SHAPESHIFTER)
+ mons_add_ench( monster, ENCH_GLOWING_SHAPESHIFTER );
+
+ // otherwise there are potential problems with summonings
+ if (monster->type == MONS_SHAPESHIFTER)
+ mons_add_ench( monster, ENCH_SHAPESHIFTER );
+
+ // We reset batty monsters from wander to seek here, instead
+ // of in handle_behaviour() since that will be called with
+ // every single movement, and we want these monsters to
+ // hit and run. -- bwr
+ if (monster->foe != MHITNOT
+ && monster->behaviour == BEH_WANDER
+ && testbits( monster->flags, MF_BATTY ))
+ {
+ monster->behaviour = BEH_SEEK;
+ }
+
+ while (monster->speed_increment >= 80)
+ { // The continues & breaks are WRT this.
+ if (monster->type != -1 && monster->hit_points < 1)
+ break;
+
+ monster->speed_increment -= 10;
+
+ if (env.cgrid[monster->x][monster->y] != EMPTY_CLOUD)
+ {
+ if (mons_has_ench( monster, ENCH_SUBMERGED ))
+ break;
+
+ if (monster->type == -1)
+ break; // problem with vortices
+
+ mons_in_cloud(monster);
+
+ if (monster->type == -1)
+ {
+ monster->speed_increment = 1;
+ break;
+ }
+ }
+
+ handle_behaviour(monster);
+
+ if (handle_enchantment(monster))
+ continue;
+
+ // submerging monsters will hide from clouds
+ const int habitat = monster_habitat( monster->type );
+ if (habitat != DNGN_FLOOR
+ && habitat == grd[monster->x][monster->y]
+ && env.cgrid[monster->x][monster->y] != EMPTY_CLOUD)
+ {
+ mons_add_ench( monster, ENCH_SUBMERGED );
+ }
+
+ // regenerate:
+ if (monster_descriptor(monster->type, MDSC_REGENERATES)
+
+ || (monster->type == MONS_FIRE_ELEMENTAL
+ && (grd[monster->x][monster->y] == DNGN_LAVA
+ || env.cgrid[monster->x][monster->y] == CLOUD_FIRE
+ || env.cgrid[monster->x][monster->y] == CLOUD_FIRE_MON))
+
+ || (monster->type == MONS_WATER_ELEMENTAL
+ && (grd[monster->x][monster->y] == DNGN_SHALLOW_WATER
+ || grd[monster->x][monster->y] == DNGN_DEEP_WATER))
+
+ || (monster->type == MONS_AIR_ELEMENTAL
+ && env.cgrid[monster->x][monster->y] == EMPTY_CLOUD
+ && one_chance_in(3))
+
+ || one_chance_in(25))
+ {
+ heal_monster(monster, 1, false);
+ }
+
+ if (monster->speed >= 100)
+ continue;
+
+ if (monster->type == MONS_ZOMBIE_SMALL
+ || monster->type == MONS_ZOMBIE_LARGE
+ || monster->type == MONS_SIMULACRUM_SMALL
+ || monster->type == MONS_SIMULACRUM_LARGE
+ || monster->type == MONS_SKELETON_SMALL
+ || monster->type == MONS_SKELETON_LARGE)
+ {
+ monster->max_hit_points = monster->hit_points;
+ }
+
+ if (igrd[monster->x][monster->y] != NON_ITEM
+ && (mons_itemuse(monster->type) == MONUSE_WEAPONS_ARMOUR
+ || mons_itemuse(monster->type) == MONUSE_EATS_ITEMS
+ || monster->type == MONS_NECROPHAGE
+ || monster->type == MONS_GHOUL))
+ {
+ if (handle_pickup(monster))
+ continue;
+ }
+
+ // calculates mmov_x, mmov_y based on monster target.
+ handle_movement(monster);
+
+ brkk = false;
+
+ if (mons_has_ench( monster, ENCH_CONFUSION )
+ || (monster->type == MONS_AIR_ELEMENTAL
+ && mons_has_ench( monster, ENCH_SUBMERGED )))
+ {
+ mmov_x = random2(3) - 1;
+ mmov_y = random2(3) - 1;
+
+ // bounds check: don't let confused monsters try to run
+ // off the map
+ if (monster->target_x + mmov_x < 0
+ || monster->target_x + mmov_x >= GXM)
+ {
+ mmov_x = 0;
+ }
+
+ if (monster->target_y + mmov_y < 0
+ || monster->target_y + mmov_y >= GYM)
+ {
+ mmov_y = 0;
+ }
+
+ if (mgrd[monster->x + mmov_x][monster->y + mmov_y] != NON_MONSTER
+ && (mmov_x != 0 || mmov_y != 0))
+ {
+ mmov_x = 0;
+ mmov_y = 0;
+
+ if (monsters_fight(i, mgrd[monster->x + mmov_x][monster->y + mmov_y]))
+ {
+ brkk = true;
+ }
+ }
+ }
+
+ if (brkk)
+ continue;
+
+ handle_nearby_ability( monster );
+
+ beem.target_x = monster->target_x;
+ beem.target_y = monster->target_y;
+
+ if (monster->behaviour != BEH_SLEEP
+ && monster->behaviour != BEH_WANDER)
+ {
+ // prevents unfriendlies from nuking you from offscreen.
+ // How nice!
+ if (mons_friendly(monster) || mons_near(monster))
+ {
+ if (handle_special_ability(monster, beem))
+ continue;
+
+ if (handle_potion(monster, beem))
+ continue;
+
+ if (handle_scroll(monster))
+ continue;
+
+ // shapeshifters don't get spells
+ if (!mons_has_ench( monster, ENCH_GLOWING_SHAPESHIFTER,
+ ENCH_SHAPESHIFTER )
+ || !mons_flag( monster->type, M_ACTUAL_SPELLS ))
+ {
+ if (handle_spell(monster, beem))
+ continue;
+ }
+
+ if (handle_wand(monster, beem))
+ continue;
+
+ if (handle_reaching(monster))
+ continue;
+ }
+
+ if (handle_throw(monster, beem))
+ continue;
+ }
+
+ // see if we move into (and fight) an unfriendly monster
+ int targmon = mgrd[monster->x + mmov_x][monster->y + mmov_y];
+ if (targmon != NON_MONSTER
+ && targmon != i
+ && !mons_aligned(i, targmon))
+ {
+ // figure out if they fight
+ if (monsters_fight(i, targmon))
+ {
+ if (testbits(monster->flags, MF_BATTY))
+ {
+ monster->behaviour = BEH_WANDER;
+ monster->target_x = 10 + random2(GXM - 10);
+ monster->target_y = 10 + random2(GYM - 10);
+ // monster->speed_increment -= monster->speed;
+ }
+
+ mmov_x = 0;
+ mmov_y = 0;
+ brkk = true;
+ }
+ }
+
+ if (brkk)
+ continue;
+
+ if (monster->x + mmov_x == you.x_pos
+ && monster->y + mmov_y == you.y_pos)
+ {
+ bool isFriendly = mons_friendly(monster);
+ bool attacked = false;
+
+ if (!isFriendly)
+ {
+ monster_attack(i);
+ attacked = true;
+
+ if (testbits(monster->flags, MF_BATTY))
+ {
+ monster->behaviour = BEH_WANDER;
+ monster->target_x = 10 + random2(GXM - 10);
+ monster->target_y = 10 + random2(GYM - 10);
+ }
+ }
+
+ if ((monster->type == MONS_GIANT_SPORE
+ || monster->type == MONS_BALL_LIGHTNING)
+ && monster->hit_points < 1)
+ {
+
+ // detach monster from the grid first, so it
+ // doesn't get hit by its own explosion (GDL)
+ mgrd[monster->x][monster->y] = NON_MONSTER;
+
+ spore_goes_pop(monster);
+ monster_cleanup(monster);
+ continue;
+ }
+
+ if (attacked)
+ {
+ mmov_x = 0;
+ mmov_y = 0;
+ continue; //break;
+ }
+ }
+
+ if (monster->type == -1 || monster->type == MONS_OKLOB_PLANT
+ || monster->type == MONS_CURSE_SKULL
+ || (monster->type >= MONS_CURSE_TOE
+ && monster->type <= MONS_POTION_MIMIC))
+ {
+ continue;
+ }
+
+ monster_move(monster);
+
+ // reevaluate behaviour, since the monster's
+ // surroundings have changed (it may have moved,
+ // or died for that matter. Don't bother for
+ // dead monsters. :)
+ if (monster->type != -1)
+ handle_behaviour(monster);
+
+ } // end while
+
+ if (monster->type != -1 && monster->hit_points < 1)
+ {
+ if (monster->type == MONS_GIANT_SPORE
+ || monster->type == MONS_BALL_LIGHTNING)
+ {
+ // detach monster from the grid first, so it
+ // doesn't get hit by its own explosion (GDL)
+ mgrd[monster->x][monster->y] = NON_MONSTER;
+
+ spore_goes_pop( monster );
+ monster_cleanup( monster );
+ continue;
+ }
+ else
+ {
+ monster_die( monster, KILL_MISC, 0 );
+ }
+ }
+ } // end of if (mons_class != -1)
+ } // end of for loop
+
+ // Clear any summoning flags so that lower indiced
+ // monsters get their actions in the next round.
+ for (i = 0; i < MAX_MONSTERS; i++)
+ {
+ menv[i].flags &= ~MF_JUST_SUMMONED;
+ }
+} // end handle_monster()
+
+
+//---------------------------------------------------------------
+//
+// handle_pickup
+//
+// Returns false if monster doesn't spend any time pickup up
+//
+//---------------------------------------------------------------
+static bool handle_pickup(struct monsters *monster)
+{
+ // single calculation permissible {dlb}
+ char str_pass[ ITEMNAME_SIZE ];
+ bool monsterNearby = mons_near(monster);
+ int item = NON_ITEM;
+
+ if (mons_has_ench( monster, ENCH_SUBMERGED ))
+ return (false);
+
+ if (monster->type == MONS_JELLY
+ || monster->type == MONS_BROWN_OOZE
+ || monster->type == MONS_ACID_BLOB
+ || monster->type == MONS_ROYAL_JELLY)
+ {
+ int hps_gained = 0;
+ int max_eat = roll_dice( 1, 10 );
+ int eaten = 0;
+
+ for (item = igrd[monster->x][monster->y];
+ item != NON_ITEM && eaten < max_eat && hps_gained < 50;
+ item = mitm[item].link)
+ {
+ int quant = mitm[item].quantity;
+
+ // don't eat fixed artefacts
+ if (is_fixed_artefact( mitm[item] ))
+ continue;
+
+ // shouldn't eat stone things
+ // - but what about wands and rings?
+ if (mitm[item].base_type == OBJ_MISSILES
+ && (mitm[item].sub_type == MI_STONE
+ || mitm[item].sub_type == MI_LARGE_ROCK))
+ {
+ continue;
+ }
+
+ // don't eat special game items
+ if (mitm[item].base_type == OBJ_ORBS
+ || (mitm[item].base_type == OBJ_MISCELLANY
+ && mitm[item].sub_type == MISC_RUNE_OF_ZOT))
+ {
+ continue;
+ }
+
+ if (mitm[igrd[monster->x][monster->y]].base_type != OBJ_GOLD)
+ {
+ if (quant > max_eat - eaten)
+ quant = max_eat - eaten;
+
+ hps_gained += (quant * mass_item( mitm[item] )) / 20 + quant;
+ eaten += quant;
+ }
+ else
+ {
+ // shouldn't be much trouble to digest a huge pile of gold!
+ if (quant > 500)
+ quant = 500 + roll_dice( 2, (quant - 500) / 2 );
+
+ hps_gained += quant / 10 + 1;
+ eaten++;
+ }
+
+ dec_mitm_item_quantity( item, quant );
+ }
+
+ if (eaten)
+ {
+ if (hps_gained < 1)
+ hps_gained = 1;
+ else if (hps_gained > 50)
+ hps_gained = 50;
+
+ // This is done manually instead of using heal_monster(),
+ // because that function doesn't work quite this way. -- bwr
+ monster->hit_points += hps_gained;
+
+ if (monster->max_hit_points < monster->hit_points)
+ monster->max_hit_points = monster->hit_points;
+
+ if (!silenced(you.x_pos, you.y_pos)
+ && !silenced(monster->x, monster->y))
+ {
+ strcpy(info, "You hear a");
+ if (!monsterNearby)
+ strcat(info, " distant");
+ strcat(info, " slurping noise.");
+ mpr(info);
+ }
+
+ if (mons_flag( monster->type, M_SPLITS ))
+ {
+ const int reqd = (monster->hit_dice <= 6)
+ ? 50 : monster->hit_dice * 8;
+
+ if (monster->hit_points >= reqd)
+ jelly_divide(monster);
+ }
+ }
+
+ return (false);
+ } // end "if jellies"
+
+ // Note: Monsters only look at top of stacks.
+ item = igrd[monster->x][monster->y];
+
+ switch (mitm[item].base_type)
+ {
+ case OBJ_WEAPONS:
+ if (monster->inv[MSLOT_WEAPON] != NON_ITEM)
+ return (false);
+
+ if (is_fixed_artefact( mitm[item] ))
+ return (false);
+
+ if (is_random_artefact( mitm[item] ))
+ return (false);
+
+ // wimpy monsters (Kob, gob) shouldn't pick up halberds etc
+ // of course, this also block knives {dlb}:
+ if ((mons_charclass(monster->type) == MONS_KOBOLD
+ || mons_charclass(monster->type) == MONS_GOBLIN)
+ && property( mitm[item], PWPN_HIT ) <= 0)
+ {
+ return (false);
+ }
+
+ // Nobody picks up giant clubs:
+ if (mitm[item].sub_type == WPN_GIANT_CLUB
+ || mitm[item].sub_type == WPN_GIANT_SPIKED_CLUB)
+ {
+ return (false);
+ }
+
+ monster->inv[MSLOT_WEAPON] = item;
+
+ if (get_weapon_brand(mitm[monster->inv[MSLOT_WEAPON]]) == SPWPN_PROTECTION)
+ {
+ monster->armour_class += 3;
+ }
+
+ if (monsterNearby)
+ {
+ strcpy(info, ptr_monam(monster, DESC_CAP_THE));
+ strcat(info, " picks up ");
+ it_name(monster->inv[MSLOT_WEAPON], DESC_NOCAP_A, str_pass);
+ strcat(info, str_pass);
+ strcat(info, ".");
+ mpr(info);
+ }
+ break;
+
+ case OBJ_MISSILES:
+ // don't pick up if we're in combat, and there isn't much there
+ if (mitm[item].quantity < 5 || monster->behaviour != BEH_WANDER)
+ return (false);
+
+ if (monster->inv[MSLOT_MISSILE] != NON_ITEM
+ && mitm[monster->inv[MSLOT_MISSILE]].sub_type == mitm[item].sub_type
+ && mitm[monster->inv[MSLOT_MISSILE]].plus == mitm[item].plus
+ && mitm[monster->inv[MSLOT_MISSILE]].special == mitm[item].special)
+ {
+ if (monsterNearby)
+ {
+ strcpy(info, ptr_monam(monster, DESC_CAP_THE));
+ strcat(info, " picks up ");
+ it_name(item, DESC_NOCAP_A, str_pass);
+ strcat(info, str_pass);
+ strcat(info, ".");
+ mpr(info);
+ }
+
+ inc_mitm_item_quantity( monster->inv[MSLOT_MISSILE],
+ mitm[item].quantity );
+
+ dec_mitm_item_quantity( item, mitm[item].quantity );
+ return (true);
+ }
+
+ // nobody bothers to pick up rocks if they don't already have some:
+ if (mitm[item].sub_type == MI_LARGE_ROCK)
+ return (false);
+
+ // monsters with powerful melee attacks don't bother
+ if (mons_damage(monster->type, 0) > 5)
+ return (false);
+
+ monster->inv[MSLOT_MISSILE] = item;
+
+ if (monsterNearby)
+ {
+ strcpy(info, ptr_monam(monster, DESC_CAP_THE));
+ strcat(info, " picks up ");
+ it_name(monster->inv[MSLOT_MISSILE], DESC_NOCAP_A, str_pass);
+ strcat(info, str_pass);
+ strcat(info, ".");
+ mpr(info);
+ }
+ break;
+
+ case OBJ_WANDS:
+ if (monster->inv[MSLOT_WAND] != NON_ITEM)
+ return (false);
+
+ monster->inv[MSLOT_WAND] = item;
+
+ if (monsterNearby)
+ {
+ strcpy(info, ptr_monam(monster, DESC_CAP_THE));
+ strcat(info, " picks up ");
+ it_name(monster->inv[MSLOT_WAND], DESC_NOCAP_A, str_pass);
+ strcat(info, str_pass);
+ strcat(info, ".");
+ mpr(info);
+ }
+ break;
+
+ case OBJ_SCROLLS:
+ if (monster->inv[MSLOT_SCROLL] != NON_ITEM)
+ return (false);
+
+ monster->inv[MSLOT_SCROLL] = item;
+
+ if (monsterNearby)
+ {
+ strcpy(info, ptr_monam(monster, DESC_CAP_THE));
+ strcat(info, " picks up ");
+ it_name(monster->inv[MSLOT_SCROLL], DESC_NOCAP_A, str_pass);
+ strcat(info, str_pass);
+ strcat(info, ".");
+ mpr(info);
+ }
+ break;
+
+ case OBJ_POTIONS:
+ if (monster->inv[MSLOT_POTION] != NON_ITEM)
+ return (false);
+
+ monster->inv[MSLOT_POTION] = item;
+
+ if (monsterNearby)
+ {
+ strcpy(info, ptr_monam(monster, DESC_CAP_THE));
+ strcat(info, " picks up ");
+ it_name(monster->inv[MSLOT_POTION], DESC_NOCAP_A, str_pass);
+ strcat(info, str_pass);
+ strcat(info, ".");
+ mpr(info);
+ }
+ break;
+
+ case OBJ_CORPSES:
+ if (monster->type != MONS_NECROPHAGE && monster->type != MONS_GHOUL)
+ return (false);
+
+ monster->hit_points += 1 + random2(mons_weight(mitm[item].plus)) / 100;
+
+ // limited growth factor here -- should 77 really be the cap? {dlb}:
+ if (monster->hit_points > 100)
+ monster->hit_points = 100;
+
+ if (monster->hit_points > monster->max_hit_points)
+ monster->max_hit_points = monster->hit_points;
+
+ if (monsterNearby)
+ {
+ strcpy(info, ptr_monam(monster, DESC_CAP_THE));
+ strcat(info, " eats ");
+ it_name(item, DESC_NOCAP_THE, str_pass);
+ strcat(info, str_pass);
+ strcat(info, ".");
+ mpr(info);
+ }
+
+ destroy_item( item );
+ return (true);
+
+ case OBJ_GOLD: //mv - monsters now pick up gold (19 May 2001)
+ if (monsterNearby)
+ {
+
+ strcpy(info, monam( monster->number, monster->type,
+ player_monster_visible( monster ),
+ DESC_CAP_THE ));
+
+ strcat(info, " picks up some gold.");
+ mpr(info);
+ }
+
+ if (monster->inv[MSLOT_GOLD] != NON_ITEM)
+ {
+ // transfer gold to monster's object, destroy ground object
+ inc_mitm_item_quantity( monster->inv[MSLOT_GOLD],
+ mitm[item].quantity );
+
+ destroy_item( item );
+ return (true);
+ }
+ else
+ {
+ monster->inv[MSLOT_GOLD] = item;
+ }
+ break;
+
+ default:
+ return (false);
+ }
+
+ // Item has been picked-up, move to monster inventory.
+ mitm[item].x = 0;
+ mitm[item].y = 0;
+
+ // Monster's only take the top item of stacks, so relink the
+ // top item, and unlink the item.
+ igrd[monster->x][monster->y] = mitm[item].link;
+ mitm[item].link = NON_ITEM;
+
+ if (monster->speed_increment > 25)
+ monster->speed_increment -= monster->speed;
+
+ return (true);
+} // end handle_pickup()
+
+static void monster_move(struct monsters *monster)
+{
+ FixedArray < bool, 3, 3 > good_move;
+ int count_x, count_y, count;
+ int okmove = DNGN_SHALLOW_WATER;
+
+ const int habitat = monster_habitat( monster->type );
+ bool deep_water_available = false;
+
+ // let's not even bother with this if mmov_x and mmov_y are zero.
+ if (mmov_x == 0 && mmov_y == 0)
+ return;
+
+ // effectively slows down monster movement across water.
+ // Fire elementals can't cross at all.
+ if (monster->type == MONS_FIRE_ELEMENTAL || one_chance_in(5))
+ okmove = DNGN_WATER_STUCK;
+
+ if (mons_flies(monster) > 0
+ || habitat != DNGN_FLOOR
+ || mons_flag( monster->type, M_AMPHIBIOUS ))
+ {
+ okmove = MINMOVE;
+ }
+
+ for (count_x = 0; count_x < 3; count_x++)
+ {
+ for (count_y = 0; count_y < 3; count_y++)
+ {
+ good_move[count_x][count_y] = true;
+ const int targ_x = monster->x + count_x - 1;
+ const int targ_y = monster->y + count_y - 1;
+ int target_grid = grd[targ_x][targ_y];
+
+ const int targ_cloud = env.cgrid[ targ_x ][ targ_y ];
+ const int curr_cloud = env.cgrid[ monster->x ][ monster->y ];
+
+ // bounds check - don't consider moving out of grid!
+ if (targ_x < 0 || targ_x >= GXM || targ_y < 0 || targ_y >= GYM)
+ {
+ good_move[count_x][count_y] = false;
+ continue;
+ }
+
+ if (target_grid == DNGN_DEEP_WATER)
+ deep_water_available = true;
+
+ if (monster->type == MONS_BORING_BEETLE
+ && target_grid == DNGN_ROCK_WALL)
+ {
+ // don't burrow out of bounds
+ if (targ_x <= 7 || targ_x >= (GXM - 8)
+ || targ_y <= 7 || targ_y >= (GYM - 8))
+ {
+ good_move[count_x][count_y] = false;
+ continue;
+ }
+
+ // don't burrow at an angle (legacy behaviour)
+ if (count_x != 1 && count_y != 1)
+ {
+ good_move[count_x][count_y] = false;
+ continue;
+ }
+ }
+ else if (grd[ targ_x ][ targ_y ] < okmove)
+ {
+ good_move[count_x][count_y] = false;
+ continue;
+ }
+ else if (!habitat_okay( monster, target_grid ))
+ {
+ good_move[count_x][count_y] = false;
+ continue;
+ }
+
+ if (monster->type == MONS_WANDERING_MUSHROOM
+ && see_grid(targ_x, targ_y))
+ {
+ good_move[count_x][count_y] = false;
+ continue;
+ }
+
+ // Water elementals avoid fire and heat
+ if (monster->type == MONS_WATER_ELEMENTAL
+ && (target_grid == DNGN_LAVA
+ || targ_cloud == CLOUD_FIRE
+ || targ_cloud == CLOUD_FIRE_MON
+ || targ_cloud == CLOUD_STEAM
+ || targ_cloud == CLOUD_STEAM_MON))
+ {
+ good_move[count_x][count_y] = false;
+ continue;
+ }
+
+ // Fire elementals avoid water and cold
+ if (monster->type == MONS_FIRE_ELEMENTAL
+ && (target_grid == DNGN_DEEP_WATER
+ || target_grid == DNGN_SHALLOW_WATER
+ || target_grid == DNGN_BLUE_FOUNTAIN
+ || targ_cloud == CLOUD_COLD
+ || targ_cloud == CLOUD_COLD_MON))
+ {
+ good_move[count_x][count_y] = false;
+ continue;
+ }
+
+ // Submerged water creatures avoid the shallows where
+ // they would be forced to surface. -- bwr
+ if (habitat == DNGN_DEEP_WATER
+ && (targ_x != you.x_pos || targ_y != you.y_pos)
+ && target_grid != DNGN_DEEP_WATER
+ && grd[monster->x][monster->y] == DNGN_DEEP_WATER
+ && (mons_has_ench( monster, ENCH_SUBMERGED )
+ || monster->hit_points < (monster->max_hit_points * 3) / 4))
+ {
+ good_move[count_x][count_y] = false;
+ continue;
+ }
+
+ // smacking the player is always a good move if
+ // we're hostile (even if we're heading somewhere
+ // else)
+
+ // smacking another monster is good, if the monsters
+ // are aligned differently
+ if (mgrd[targ_x][targ_y] != NON_MONSTER)
+ {
+ if (mons_aligned(monster_index(monster), mgrd[targ_x][targ_y]))
+ {
+ good_move[count_x][count_y] = false;
+ continue;
+ }
+ }
+
+ // wandering through a trap is OK if we're pretty healthy, or
+ // really stupid.
+ if (trap_at_xy(targ_x,targ_y) >= 0
+ && mons_intel(monster->type) != I_PLANT)
+ {
+ if (monster->hit_points < monster->max_hit_points / 2)
+ {
+ good_move[count_x][count_y] = false;
+ continue;
+ }
+ }
+
+ if (targ_cloud != EMPTY_CLOUD)
+ {
+ if (curr_cloud != EMPTY_CLOUD
+ && env.cloud[targ_cloud].type == env.cloud[curr_cloud].type)
+ {
+ continue;
+ }
+
+ switch (env.cloud[ targ_cloud ].type)
+ {
+ case CLOUD_FIRE:
+ case CLOUD_FIRE_MON:
+ if (mons_res_fire(monster) > 0)
+ continue;
+
+ if (monster->hit_points >= 15 + random2avg(46, 5))
+ continue;
+ break;
+
+ case CLOUD_STINK:
+ case CLOUD_STINK_MON:
+ if (mons_res_poison(monster) > 0)
+ continue;
+ if (1 + random2(5) < monster->hit_dice)
+ continue;
+ if (monster->hit_points >= random2avg(19, 2))
+ continue;
+ break;
+
+ case CLOUD_COLD:
+ case CLOUD_COLD_MON:
+ if (mons_res_cold(monster) > 0)
+ continue;
+
+ if (monster->hit_points >= 15 + random2avg(46, 5))
+ continue;
+ break;
+
+ case CLOUD_POISON:
+ case CLOUD_POISON_MON:
+ if (mons_res_poison(monster) > 0)
+ continue;
+
+ if (monster->hit_points >= random2avg(37, 4))
+ continue;
+ break;
+
+ // this isn't harmful, but dumb critters might think so.
+ case CLOUD_GREY_SMOKE:
+ case CLOUD_GREY_SMOKE_MON:
+ if (mons_intel(monster->type) > I_ANIMAL || coinflip())
+ continue;
+
+ if (mons_res_fire(monster) > 0)
+ continue;
+
+ if (monster->hit_points >= random2avg(19, 2))
+ continue;
+ break;
+
+ default:
+ continue; // harmless clouds
+ }
+
+ // if we get here, the cloud is potentially harmful.
+ // exceedingly dumb creatures will still wander in.
+ if (mons_intel(monster->type) != I_PLANT)
+ good_move[count_x][count_y] = false;
+ }
+ }
+ } // now we know where we _can_ move.
+
+ // normal/smart monsters know about secret doors (they _live_ in the
+ // dungeon!)
+ if (grd[monster->x + mmov_x][monster->y + mmov_y] == DNGN_CLOSED_DOOR
+ || (grd[monster->x + mmov_x][monster->y + mmov_y] == DNGN_SECRET_DOOR
+ && (mons_intel(monster_index(monster)) == I_HIGH
+ || mons_intel(monster_index(monster)) == I_NORMAL)))
+ {
+ if (monster->type == MONS_ZOMBIE_SMALL
+ || monster->type == MONS_ZOMBIE_LARGE
+ || monster->type == MONS_SIMULACRUM_SMALL
+ || monster->type == MONS_SIMULACRUM_LARGE
+ || monster->type == MONS_SKELETON_SMALL
+ || monster->type == MONS_SKELETON_LARGE
+ || monster->type == MONS_SPECTRAL_THING)
+ {
+ // for zombies, monster type is kept in mon->number
+ if (mons_itemuse(monster->number) >= MONUSE_OPEN_DOORS)
+ {
+ grd[monster->x + mmov_x][monster->y + mmov_y] = DNGN_OPEN_DOOR;
+ return;
+ }
+ }
+ else if (mons_itemuse(monster->type) >= MONUSE_OPEN_DOORS)
+ {
+ grd[monster->x + mmov_x][monster->y + mmov_y] = DNGN_OPEN_DOOR;
+ return;
+ }
+ } // endif - secret/closed doors
+
+ // jellies eat doors. Yum!
+ if ((grd[monster->x + mmov_x][monster->y + mmov_y] == DNGN_CLOSED_DOOR
+ || grd[monster->x + mmov_x][monster->y + mmov_y] == DNGN_OPEN_DOOR)
+ && mons_itemuse(monster->type) == MONUSE_EATS_ITEMS)
+ {
+ grd[monster->x + mmov_x][monster->y + mmov_y] = DNGN_FLOOR;
+
+ if (!silenced(you.x_pos, you.y_pos)
+ && !silenced(monster->x, monster->y))
+ {
+ strcpy(info, "You hear a");
+ if (!mons_near(monster))
+ strcat(info, " distant");
+ strcat(info, " slurping noise.");
+ mpr(info);
+ }
+
+ monster->hit_points += 5;
+
+ // note here, that this makes jellies "grow" {dlb}:
+ if (monster->hit_points > monster->max_hit_points)
+ monster->max_hit_points = monster->hit_points;
+
+ if (mons_flag( monster->type, M_SPLITS ))
+ {
+ // and here is where the jelly might divide {dlb}
+ const int reqd = (monster->hit_dice < 6) ? 50
+ : monster->hit_dice * 8;
+
+ if (monster->hit_points >= reqd)
+ jelly_divide(monster);
+ }
+ } // done door-eating jellies
+
+
+ // water creatures have a preferance for water they can hide in -- bwr
+ if (habitat == DNGN_DEEP_WATER
+ && deep_water_available
+ && grd[monster->x][monster->y] != DNGN_DEEP_WATER
+ && grd[monster->x + mmov_x][monster->y + mmov_y] != DNGN_DEEP_WATER
+ && (monster->x + mmov_x != you.x_pos
+ || monster->y + mmov_y != you.y_pos)
+ && (coinflip()
+ || monster->hit_points <= (monster->max_hit_points * 3) / 4))
+ {
+ count = 0;
+
+ for (count_x = 0; count_x < 3; count_x++)
+ {
+ for (count_y = 0; count_y < 3; count_y++)
+ {
+ if (good_move[count_x][count_y]
+ && grd[monster->x + count_x - 1][monster->y + count_y - 1]
+ == DNGN_DEEP_WATER)
+ {
+ count++;
+
+ if (one_chance_in( count ))
+ {
+ mmov_x = count_x - 1;
+ mmov_y = count_y - 1;
+ }
+ }
+ }
+ }
+ }
+
+
+ // now, if a monster can't move in its intended direction, try
+ // either side. If they're both good, move in whichever dir
+ // gets it closer(farther for fleeing monsters) to its target.
+ // If neither does, do nothing.
+ if (good_move[mmov_x + 1][mmov_y + 1] == false)
+ {
+ int current_distance = grid_distance( monster->x, monster->y,
+ monster->target_x,
+ monster->target_y );
+
+ int dir = -1;
+ int i, mod, newdir;
+
+ for (i = 0; i < 8; i++)
+ {
+ if (compass_x[i] == mmov_x && compass_y[i] == mmov_y)
+ {
+ dir = i;
+ break;
+ }
+ }
+
+ if (dir < 0)
+ goto forget_it;
+
+ int dist[2];
+
+ // first 1 away, then 2 (3 is silly)
+ for (int j = 1; j <= 2; j++)
+ {
+ int sdir, inc;
+
+ if (coinflip())
+ {
+ sdir = -j;
+ inc = 2*j;
+ }
+ else
+ {
+ sdir = j;
+ inc = -2*j;
+ }
+
+ // try both directions
+ for (mod = sdir, i = 0; i < 2; mod += inc, i++)
+ {
+ newdir = (dir + 8 + mod) % 8;
+ if (good_move[compass_x[newdir] + 1][compass_y[newdir] + 1])
+ {
+ dist[i] = grid_distance( monster->x + compass_x[newdir],
+ monster->y + compass_y[newdir],
+ monster->target_x,
+ monster->target_y );
+ }
+ else
+ {
+ dist[i] = (monster->behaviour == BEH_FLEE) ? (-FAR_AWAY)
+ : FAR_AWAY;
+ }
+ }
+
+ // now choose
+ if (dist[0] == dist[1] && abs(dist[0]) == FAR_AWAY)
+ continue;
+
+ // which one was better? -- depends on FLEEING or not
+ if (monster->behaviour == BEH_FLEE)
+ {
+ if (dist[0] >= dist[1] && dist[0] >= current_distance)
+ {
+ mmov_x = compass_x[((dir+8)+sdir)%8];
+ mmov_y = compass_y[((dir+8)+sdir)%8];
+ break;
+ }
+ if (dist[1] >= dist[0] && dist[1] >= current_distance)
+ {
+ mmov_x = compass_x[((dir+8)-sdir)%8];
+ mmov_y = compass_y[((dir+8)-sdir)%8];
+ break;
+ }
+ }
+ else
+ {
+ if (dist[0] <= dist[1] && dist[0] <= current_distance)
+ {
+ mmov_x = compass_x[((dir+8)+sdir)%8];
+ mmov_y = compass_y[((dir+8)+sdir)%8];
+ break;
+ }
+ if (dist[1] <= dist[0] && dist[1] <= current_distance)
+ {
+ mmov_x = compass_x[((dir+8)-sdir)%8];
+ mmov_y = compass_y[((dir+8)-sdir)%8];
+ break;
+ }
+ }
+ }
+ } // end - try to find good alternate move
+
+forget_it:
+
+ // ------------------------------------------------------------------
+ // if we haven't found a good move by this point, we're not going to.
+ // ------------------------------------------------------------------
+
+ // take care of beetle burrowing
+ if (monster->type == MONS_BORING_BEETLE)
+ {
+ if (grd[monster->x + mmov_x][monster->y + mmov_y] == DNGN_ROCK_WALL
+ && good_move[mmov_x + 1][mmov_y + 1] == true)
+ {
+ grd[monster->x + mmov_x][monster->y + mmov_y] = DNGN_FLOOR;
+
+ if (!silenced(you.x_pos, you.y_pos))
+ mpr("You hear a grinding noise.");
+ }
+ }
+
+ mgrd[monster->x][monster->y] = NON_MONSTER;
+
+ if (good_move[mmov_x + 1][mmov_y + 1] && !(mmov_x == 0 && mmov_y == 0))
+ {
+ // check for attacking player
+ if (monster->x + mmov_x == you.x_pos
+ && monster->y + mmov_y == you.y_pos)
+ {
+ monster_attack( monster_index(monster) );
+ mmov_x = 0;
+ mmov_y = 0;
+ }
+
+ // If we're following the player through stairs, the only valid
+ // movement is towards the player. -- bwr
+ if (testbits( monster->flags, MF_TAKING_STAIRS ))
+ {
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "%s is skipping movement in order to follow.",
+ ptr_monam( monster, DESC_CAP_THE ) );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+ mmov_x = 0;
+ mmov_y = 0;
+ }
+
+ // check for attacking another monster
+ int targmon = mgrd[monster->x + mmov_x][monster->y + mmov_y];
+ if (targmon != NON_MONSTER)
+ {
+ monsters_fight(monster_index(monster), targmon);
+ mmov_x = 0;
+ mmov_y = 0;
+ }
+
+ if (monster->type == MONS_EFREET
+ || monster->type == MONS_FIRE_ELEMENTAL)
+ {
+ place_cloud( CLOUD_FIRE_MON, monster->x, monster->y,
+ 2 + random2(4) );
+ }
+
+ /* this appears to be the real one, ie where the movement occurs: */
+ monster->x += mmov_x;
+ monster->y += mmov_y;
+ }
+ else
+ {
+ // fleeing monsters that can't move will panic and possibly
+ // turn to face their attacker
+ if (monster->behaviour == BEH_FLEE)
+ behaviour_event(monster, ME_CORNERED);
+ }
+
+ /* need to put in something so that monster picks up multiple
+ items (eg ammunition) identical to those it's carrying. */
+ mgrd[monster->x][monster->y] = monster_index(monster);
+
+ // monsters stepping on traps:
+ if (grd[monster->x][monster->y] >= DNGN_TRAP_MECHANICAL
+ && grd[monster->x][monster->y] <= DNGN_UNDISCOVERED_TRAP
+ && (mmov_x != 0 || mmov_y != 0))
+ {
+ mons_trap(monster);
+ }
+} // end monster_move()
+
+
+static bool plant_spit(struct monsters *monster, struct bolt &pbolt)
+{
+ bool didSpit = false;
+
+ char spit_string[INFO_SIZE];
+
+ // setup plant spit
+ strcpy( pbolt.beam_name, "acid" );
+ pbolt.type = SYM_ZAP;
+ pbolt.range = 9;
+ pbolt.rangeMax = 9;
+ pbolt.colour = YELLOW;
+ pbolt.flavour = BEAM_ACID;
+ pbolt.beam_source = monster_index(monster);
+ pbolt.damage = dice_def( 3, 7 );
+ pbolt.hit = 20 + (3 * monster->hit_dice);
+ pbolt.thrower = KILL_MON_MISSILE;
+ pbolt.aux_source = NULL;
+
+ // fire tracer
+ fire_tracer(monster, pbolt);
+
+ if (mons_should_fire(pbolt))
+ {
+ strcpy( spit_string, " spits" );
+ if (pbolt.target_x == you.x_pos && pbolt.target_y == you.y_pos)
+ strcat( spit_string, " at you" );
+
+ strcat( spit_string, "." );
+ simple_monster_message( monster, spit_string );
+
+ fire_beam( pbolt );
+ didSpit = true;
+ }
+
+ return (didSpit);
+} // end plant_spit()
+
+static void mons_in_cloud(struct monsters *monster)
+{
+ int wc = env.cgrid[monster->x][monster->y];
+ int hurted = 0;
+ struct bolt beam;
+
+ const int speed = ((monster->speed > 0) ? monster->speed : 10);
+
+ if (mons_is_mimic( monster->type ))
+ {
+ mimic_alert(monster);
+ return;
+ }
+
+ switch (env.cloud[wc].type)
+ {
+ case CLOUD_DEBUGGING:
+ cprintf("Fatal error: monster steps on nonexistent cloud!");
+ exit(0);
+ return;
+
+ case CLOUD_FIRE:
+ case CLOUD_FIRE_MON:
+ if (monster->type == MONS_FIRE_VORTEX
+ || monster->type == MONS_EFREET
+ || monster->type == MONS_FIRE_ELEMENTAL)
+ {
+ return;
+ }
+
+ simple_monster_message(monster, " is engulfed in flame!");
+
+ if (mons_res_fire(monster) > 0)
+ return;
+
+ hurted += ((random2avg(16, 3) + 6) * 10) / speed;
+
+ if (mons_res_fire(monster) < 0)
+ hurted += (random2(15) * 10) / speed;
+
+ // remember that the above is in addition to the other you.damage.
+ hurted -= random2(1 + monster->armour_class);
+ break; // to damage routine at end {dlb}
+
+ case CLOUD_STINK:
+ case CLOUD_STINK_MON:
+ simple_monster_message(monster, " is engulfed in noxious gasses!");
+
+ if (mons_res_poison(monster) > 0)
+ return;
+
+ beam.flavour = BEAM_CONFUSION;
+
+ if (1 + random2(27) >= monster->hit_dice)
+ mons_ench_f2(monster, beam);
+
+ hurted += (random2(3) * 10) / speed;
+ break; // to damage routine at end {dlb}
+
+ case CLOUD_COLD:
+ case CLOUD_COLD_MON:
+ simple_monster_message(monster, " is engulfed in freezing vapours!");
+
+ if (mons_res_cold(monster) > 0)
+ return;
+
+ hurted += ((6 + random2avg(16, 3)) * 10) / speed;
+
+ if (mons_res_cold(monster) < 0)
+ hurted += (random2(15) * 10) / speed;
+
+ // remember that the above is in addition to the other damage.
+ hurted -= random2(1 + monster->armour_class);
+ break; // to damage routine at end {dlb}
+
+ // what of armour of poison resistance here? {dlb}
+ case CLOUD_POISON:
+ case CLOUD_POISON_MON:
+ simple_monster_message(monster, " is engulfed in a cloud of poison!");
+
+ if (mons_res_poison(monster) > 0)
+ return;
+
+ poison_monster(monster, (env.cloud[wc].type == CLOUD_POISON));
+
+ hurted += (random2(8) * 10) / speed;
+
+ if (mons_res_poison(monster) < 0)
+ hurted += (random2(4) * 10) / speed;
+ break; // to damage routine at end {dlb}
+
+ case CLOUD_STEAM:
+ case CLOUD_STEAM_MON:
+ // couldn't be bothered coding for armour of res fire
+
+ // what of whether it is wearing steam dragon armour? {dlb}
+ if (monster->type == MONS_STEAM_DRAGON)
+ return;
+
+ simple_monster_message(monster, " is engulfed in steam!");
+
+ if (mons_res_fire(monster) > 0)
+ return;
+
+ hurted += (random2(6) * 10) / speed;
+
+ if (mons_res_fire(monster) < 0)
+ hurted += (random2(6) * 10) / speed;
+
+ hurted -= random2(1 + monster->armour_class);
+ break; // to damage routine at end {dlb}
+
+ case CLOUD_MIASMA:
+ case CLOUD_MIASMA_MON:
+ simple_monster_message(monster, " is engulfed in a dark miasma!");
+
+ if (mons_holiness(monster->type) != MH_NATURAL)
+ return;
+
+ poison_monster(monster, (env.cloud[wc].type == CLOUD_MIASMA));
+
+ if (monster->max_hit_points > 4 && coinflip())
+ monster->max_hit_points--;
+
+ beam.flavour = BEAM_SLOW;
+
+ if (one_chance_in(3))
+ mons_ench_f2(monster, beam);
+
+ hurted += (10 * random2avg(12, 3)) / speed; // 3
+ break; // to damage routine at end {dlb}
+
+ default: // 'harmless' clouds -- colored smoke, etc {dlb}.
+ return;
+ }
+
+ if (hurted < 0)
+ hurted = 0;
+ else if (hurted > 0)
+ {
+ hurt_monster(monster, hurted);
+
+ if (monster->hit_points < 1)
+ {
+ switch (env.cloud[wc].type)
+ {
+ case CLOUD_FIRE_MON:
+ case CLOUD_STINK_MON:
+ case CLOUD_COLD_MON:
+ case CLOUD_POISON_MON:
+ case CLOUD_STEAM_MON:
+ case CLOUD_MIASMA_MON:
+ monster_die(monster, KILL_MISC, 0);
+ break;
+ default:
+ monster_die(monster, KILL_YOU, 0);
+ }
+
+ switch (env.cloud[wc].type)
+ {
+ case CLOUD_FIRE:
+ case CLOUD_FIRE_MON:
+ case CLOUD_COLD:
+ case CLOUD_COLD_MON:
+ case CLOUD_STEAM:
+ case CLOUD_STEAM_MON:
+ monster->speed_increment = 1;
+ }
+ }
+ }
+} // end mons_in_cloud()
+
+unsigned char monster_habitat(int which_class)
+{
+ switch (which_class)
+ {
+ case MONS_BIG_FISH:
+ case MONS_GIANT_GOLDFISH:
+ case MONS_ELECTRICAL_EEL:
+ case MONS_JELLYFISH:
+ case MONS_SWAMP_WORM:
+ case MONS_WATER_ELEMENTAL:
+ return (DNGN_DEEP_WATER); // no shallow water (only) monsters? {dlb}
+ // must remain DEEP_WATER for now, else breaks code {dlb}
+
+ case MONS_LAVA_WORM:
+ case MONS_LAVA_FISH:
+ case MONS_LAVA_SNAKE:
+ case MONS_SALAMANDER:
+ return (DNGN_LAVA);
+
+ default:
+ return (DNGN_FLOOR); // closest match to terra firma {dlb}
+ }
+} // end monster_habitat()
+
+bool monster_descriptor(int which_class, unsigned char which_descriptor)
+{
+ if (which_descriptor == MDSC_LEAVES_HIDE)
+ {
+ switch (which_class)
+ {
+ case MONS_DRAGON:
+ case MONS_TROLL:
+ case MONS_ICE_DRAGON:
+ case MONS_STEAM_DRAGON:
+ case MONS_MOTTLED_DRAGON:
+ case MONS_STORM_DRAGON:
+ case MONS_GOLDEN_DRAGON:
+ case MONS_SWAMP_DRAGON:
+ return (true);
+ default:
+ return (false);
+ }
+ }
+
+ if (which_descriptor == MDSC_REGENERATES)
+ {
+ switch (which_class)
+ {
+ case MONS_CACODEMON:
+ case MONS_DEEP_TROLL:
+ case MONS_HELLWING:
+ case MONS_IMP:
+ case MONS_IRON_TROLL:
+ case MONS_LEMURE:
+ case MONS_ROCK_TROLL:
+ case MONS_SLIME_CREATURE:
+ case MONS_SNORG:
+ case MONS_TROLL:
+ case MONS_HYDRA:
+ case MONS_KILLER_KLOWN:
+ return (true);
+ default:
+ return (false);
+ }
+ }
+
+ if (which_descriptor == MDSC_NOMSG_WOUNDS)
+ {
+ switch (which_class)
+ {
+ case MONS_RAKSHASA:
+ case MONS_RAKSHASA_FAKE:
+ case MONS_SKELETON_LARGE:
+ case MONS_SKELETON_SMALL:
+ case MONS_ZOMBIE_LARGE:
+ case MONS_ZOMBIE_SMALL:
+ case MONS_SIMULACRUM_SMALL:
+ case MONS_SIMULACRUM_LARGE:
+ return (true);
+ default:
+ return (false);
+ }
+ }
+ return (false);
+} // end monster_descriptor()
+
+bool message_current_target(void)
+{
+ if (you.prev_targ != MHITNOT && you.prev_targ != MHITYOU)
+ {
+ struct monsters *montarget = &menv[you.prev_targ];
+
+ if (mons_near(montarget) && player_monster_visible( montarget ))
+ {
+ snprintf( info, INFO_SIZE,
+ "You are currently targeting %s (use p/t to fire).",
+ ptr_monam(montarget, DESC_NOCAP_THE) );
+
+ mpr(info);
+ return (true); // early return {dlb}
+ }
+
+ mpr("You have no current target.");
+ }
+
+ return (false);
+} // end message_current_target()
+
+// aaah, the simple joys of pointer arithmetic! {dlb}:
+unsigned int monster_index(struct monsters *monster)
+{
+ return (monster - menv.buffer());
+} // end monster_index()
+
+bool hurt_monster(struct monsters * victim, int damage_dealt)
+{
+ bool just_a_scratch = true;
+
+ if (damage_dealt > 0)
+ {
+ just_a_scratch = false;
+ victim->hit_points -= damage_dealt;
+ }
+
+ return (!just_a_scratch);
+} // end hurt_monster()
+
+bool heal_monster(struct monsters * patient, int health_boost,
+ bool permit_growth)
+{
+ if (health_boost < 1)
+ return (false);
+ else if (!permit_growth && patient->hit_points == patient->max_hit_points)
+ return (false);
+ else
+ {
+ patient->hit_points += health_boost;
+
+ if (patient->hit_points > patient->max_hit_points)
+ {
+ if (permit_growth)
+ patient->max_hit_points++;
+
+ patient->hit_points = patient->max_hit_points;
+ }
+ }
+
+ return (true);
+} // end heal_monster()
+
+static int map_wand_to_mspell(int wand_type)
+{
+ int mzap = 0;
+
+ switch (wand_type)
+ {
+ case WAND_FLAME:
+ mzap = MS_FLAME;
+ break;
+ case WAND_FROST:
+ mzap = MS_FROST;
+ break;
+ case WAND_SLOWING:
+ mzap = MS_SLOW;
+ break;
+ case WAND_HASTING:
+ mzap = MS_HASTE;
+ break;
+ case WAND_MAGIC_DARTS:
+ mzap = MS_MMISSILE;
+ break;
+ case WAND_HEALING:
+ mzap = MS_HEAL;
+ break;
+ case WAND_PARALYSIS:
+ mzap = MS_PARALYSIS;
+ break;
+ case WAND_FIRE:
+ mzap = MS_FIRE_BOLT;
+ break;
+ case WAND_COLD:
+ mzap = MS_COLD_BOLT;
+ break;
+ case WAND_CONFUSION:
+ mzap = MS_CONFUSE;
+ break;
+ case WAND_INVISIBILITY:
+ mzap = MS_INVIS;
+ break;
+ case WAND_TELEPORTATION:
+ mzap = MS_TELEPORT_OTHER;
+ break;
+ case WAND_LIGHTNING:
+ mzap = MS_LIGHTNING_BOLT;
+ break;
+ case WAND_DRAINING:
+ mzap = MS_NEGATIVE_BOLT;
+ break;
+ default:
+ mzap = 0;
+ break;
+ }
+
+ return (mzap);
+}
diff --git a/trunk/source/monstuff.h b/trunk/source/monstuff.h
new file mode 100644
index 0000000000..f6202f23ae
--- /dev/null
+++ b/trunk/source/monstuff.h
@@ -0,0 +1,151 @@
+/*
+ * File: monstuff.cc
+ * Summary: Misc monster related functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef MONSTUFF_H
+#define MONSTUFF_H
+
+
+// useful macro
+#define SAME_ATTITUDE(x) (mons_friendly(x)?BEH_FRIENDLY:BEH_HOSTILE)
+
+// for definition of type monsters {dlb}
+#include "externs.h"
+// for definition of type monsters {dlb}
+
+void get_mimic_item( const struct monsters *mimic, item_def & item );
+int get_mimic_colour( struct monsters *mimic );
+
+// last updated: 08jun2000 {dlb}
+/* ***********************************************************************
+ * called from: fight - item_use - items - spell
+ * *********************************************************************** */
+void alert_nearby_monsters(void);
+
+
+// last updated: 08jun2000 {dlb}
+/* ***********************************************************************
+ * called from: beam - effects - monstuff
+ * *********************************************************************** */
+bool monster_polymorph(struct monsters *monster, int targetc, int power);
+
+// last updated: 08jun2000 {dlb}
+/* ***********************************************************************
+ * called from: bang - beam - effects - fight - misc - monstuff - mstuff2 -
+ * spells1 - spells2 - spells3 - spells4
+ * *********************************************************************** */
+void monster_die(struct monsters *monster, char killer, int i);
+
+// last updated: 17dec2000 {gdl}
+/* ***********************************************************************
+ * called from: monstuff - fight
+ * *********************************************************************** */
+void monster_cleanup(struct monsters *monster);
+
+
+/* ***********************************************************************
+ * called from: monstuff beam effects fight view
+ * *********************************************************************** */
+void behaviour_event( struct monsters *mon, int event_type,
+ int src = MHITNOT, int src_x = 0, int src_y = 0 );
+
+/* ***********************************************************************
+ * called from: fight - it_use3 - spells
+ * *********************************************************************** */
+bool curse_an_item(char which, char power);
+
+
+/* ***********************************************************************
+ * called from: fight
+ * *********************************************************************** */
+void monster_blink(struct monsters *monster);
+
+
+/* ***********************************************************************
+ * called from: spells1 spells4 monstuff
+ * defaults are set up for player blink; monster blink should call with
+ * false, false
+ * *********************************************************************** */
+bool random_near_space( int ox, int oy, int &tx, int &ty,
+ bool allow_adjacent = false, bool restrict_LOS = true);
+
+
+/* ***********************************************************************
+ * called from: beam - effects - fight - monstuff - mstuff2 - spells1 -
+ * spells2 - spells4
+ * *********************************************************************** */
+bool simple_monster_message(struct monsters *monster, const char *event,
+ int channel = MSGCH_PLAIN, int param = 0);
+
+
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+bool swap_places(struct monsters *monster);
+
+
+/* ***********************************************************************
+ * called from: bang - beam - direct - fight - spells1 - spells2 - spells3
+ * *********************************************************************** */
+void print_wounds(struct monsters *monster);
+
+
+/* ***********************************************************************
+ * called from: fight
+ * *********************************************************************** */
+bool wounded_damaged(int wound_class);
+
+
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void handle_monsters(void);
+
+
+/* ***********************************************************************
+ * called from: acr - bang - beam - direct - dungeon - fight - files -
+ * monplace - mstuff2 - spells3 - view
+ * *********************************************************************** */
+unsigned char monster_habitat(int which_class);
+
+
+/* ***********************************************************************
+ * called from: misc
+ * *********************************************************************** */
+bool monster_descriptor(int which_class, unsigned char which_descriptor);
+
+
+/* ***********************************************************************
+ * called from: direct - item_use - spells1
+ * *********************************************************************** */
+bool message_current_target(void);
+
+
+/* ***********************************************************************
+ * called from: xxx
+ * *********************************************************************** */
+unsigned int monster_index(struct monsters *monster);
+
+
+// last updated 08jun2000 {dlb}
+/* ***********************************************************************
+ * called from: bang - beam - effects - fight - monstuff - mstuff2 -
+ * spells2 - spells3 - spells4
+ * *********************************************************************** */
+bool hurt_monster(struct monsters *victim, int damage_dealt);
+
+
+/* ***********************************************************************
+ * called from: beam - fight - files - monstuff - spells1
+ * *********************************************************************** */
+bool heal_monster(struct monsters *patient, int health_boost, bool permit_growth);
+
+
+#endif
diff --git a/trunk/source/mstuff2.cc b/trunk/source/mstuff2.cc
new file mode 100644
index 0000000000..38d0d8c885
--- /dev/null
+++ b/trunk/source/mstuff2.cc
@@ -0,0 +1,1665 @@
+/*
+ * File: mstuff2.cc
+ * Summary: Misc monster related functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <5> 31 July 2000 JDJ Fixed mon_throw to use lnchType.
+ * <4> 29 July 2000 JDJ Tweaked mons_throw so it doesn't index past
+ * the end of the array when monsters don't have
+ * a weapon equipped.
+ * <3> 25 July 2000 GDL Fixed Manticores
+ * <2> 28 July 2000 GDL Revised monster throwing
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "mstuff2.h"
+
+#include <string>
+#include <string.h>
+#include <stdio.h>
+
+#include "externs.h"
+
+#include "beam.h"
+#include "debug.h"
+#include "effects.h"
+#include "itemname.h"
+#include "items.h"
+#include "misc.h"
+#include "monplace.h"
+#include "monstuff.h"
+#include "mon-util.h"
+#include "player.h"
+#include "spells2.h"
+#include "spells4.h"
+#include "spl-cast.h"
+#include "stuff.h"
+#include "view.h"
+#include "wpn-misc.h"
+
+static unsigned char monster_abjuration(int pow, bool test);
+
+// XXX: must fix species abils to not use duration 15
+// -- ummm ... who wrote this? {dlb}
+
+// NB: only works because grid location already verified
+// to be some sort of trap prior to function call: {dlb}
+void mons_trap(struct monsters *monster)
+{
+ int temp_rand = 0; // probability determination {dlb}
+
+ // single calculation permissible {dlb}
+ bool monsterNearby = mons_near(monster);
+
+ // new function call {dlb}
+ int which_trap = trap_at_xy(monster->x, monster->y);
+ if (which_trap == -1)
+ return;
+
+ bool trapKnown = (grd[monster->x][monster->y] != DNGN_UNDISCOVERED_TRAP);
+ bool revealTrap = false; // more sophisticated trap uncovering {dlb}
+ bool projectileFired = false; // <sigh> I had to do it, I swear {dlb}
+ int damage_taken = -1; // must initialize at -1 for this f(x) {dlb}
+
+ struct bolt beem;
+
+
+ // flying monsters neatly avoid mechanical traps
+ // and may actually exit this function early: {dlb}
+ if (mons_flies(monster))
+ {
+ if (trap_category(env.trap[which_trap].type) == DNGN_TRAP_MECHANICAL)
+ {
+ if (trapKnown)
+ simple_monster_message(monster, " flies safely over a trap.");
+
+ return; // early return {dlb}
+ }
+ }
+
+ //
+ // Trap damage to monsters is not a function of level, beacuse they
+ // are fairly stupid and tend to have fewer hp than players -- this
+ // choice prevents traps from easily killing large monsters fairly
+ // deep within the dungeon.
+ //
+ switch (env.trap[which_trap].type)
+ {
+ case TRAP_DART:
+ projectileFired = true;
+ strcpy(beem.beam_name, " dart");
+ beem.damage = dice_def( 1, 4 );
+ beem.colour = OBJ_MISSILES;
+ beem.type = MI_DART;
+ break;
+ case TRAP_NEEDLE:
+ projectileFired = true;
+ strcpy(beem.beam_name, " needle");
+ beem.damage = dice_def( 1, 0 );
+ beem.colour = OBJ_MISSILES;
+ beem.type = MI_NEEDLE;
+ break;
+ case TRAP_ARROW:
+ projectileFired = true;
+ strcpy(beem.beam_name, "n arrow");
+ beem.damage = dice_def( 1, 7 );
+ beem.colour = OBJ_MISSILES;
+ beem.type = MI_ARROW;
+ break;
+ case TRAP_SPEAR:
+ projectileFired = true;
+ strcpy(beem.beam_name, " spear");
+ beem.damage = dice_def( 1, 10 );
+ beem.colour = OBJ_WEAPONS;
+ beem.type = WPN_SPEAR;
+ break;
+ case TRAP_BOLT:
+ projectileFired = true;
+ strcpy(beem.beam_name, " bolt");
+ beem.damage = dice_def( 1, 13 );
+ beem.colour = OBJ_MISSILES;
+ beem.type = MI_BOLT;
+ break;
+ case TRAP_AXE:
+ projectileFired = true;
+ strcpy(beem.beam_name, "n axe");
+ beem.damage = dice_def( 1, 15 );
+ beem.colour = OBJ_WEAPONS;
+ beem.type = WPN_HAND_AXE;
+ break;
+ // teleport traps are *never* revealed through
+ // the triggering action of a monster, as any
+ // number of factors could have been in play: {dlb}
+ case TRAP_TELEPORT:
+ monster_teleport(monster, true);
+ break;
+ // amnesia traps do not affect monsters (yet) and
+ // only monsters of normal+ IQ will direct a msg
+ // to the player - also, *never* revealed: {dlb}
+ case TRAP_AMNESIA:
+ if (mons_intel(monster->type) > I_ANIMAL)
+ simple_monster_message(monster,
+ " seems momentarily disoriented.");
+ break;
+ // blade traps sometimes fail to trigger altogether,
+ // resulting in an "early return" from this f(x) for
+ // some - otherwise, blade *always* revealed: {dlb}
+ case TRAP_BLADE:
+ if (one_chance_in(5))
+ {
+ if (trapKnown)
+ {
+ simple_monster_message(monster,
+ " fails to trigger a blade trap.");
+ }
+ return; // early return {dlb}
+ }
+ else if (random2(monster->evasion) > 8)
+ {
+ if (monsterNearby && !simple_monster_message(monster,
+ " avoids a huge, swinging blade."))
+ {
+ mpr("A huge blade swings out!");
+ }
+
+ damage_taken = -1; // just to be certain {dlb}
+ }
+ else
+ {
+ if (monsterNearby)
+ {
+ strcpy(info, "A huge blade swings out");
+
+ if (player_monster_visible( monster ))
+ {
+ strcat(info, " and slices into ");
+ strcat(info, ptr_monam( monster, DESC_NOCAP_THE ));
+ }
+
+ strcat(info, "!");
+ mpr(info);
+ }
+
+ damage_taken = 10 + random2avg(29, 2);
+ damage_taken -= random2(1 + monster->armour_class);
+
+ if (damage_taken < 0)
+ damage_taken = 0;
+ }
+
+ revealTrap = true;
+ break;
+
+ // zot traps are out to get *the player*! Hostile monsters
+ // benefit and friendly monsters suffer - such is life - on
+ // rare occasion, the trap affects nearby players, triggering
+ // an "early return" - zot traps are *never* revealed - instead,
+ // enchantment messages serve as clues to the trap's presence: {dlb}
+ case TRAP_ZOT:
+ if (monsterNearby)
+ {
+ if (one_chance_in(5))
+ {
+ mpr("The power of Zot is invoked against you!");
+ miscast_effect( SPTYP_RANDOM, 10 + random2(30),
+ 75 + random2(100), 0, "the power of Zot" );
+ return; // early return {dlb}
+ }
+ }
+
+ // output triggering message to player, where appropriate: {dlb}
+ if (!silenced(monster->x, monster->y)
+ && !silenced(you.x_pos, you.y_pos))
+ {
+ if (monsterNearby)
+ strcpy(info, "You hear a loud \"Zot\"!");
+ else
+ strcpy(info, "You hear a distant \"Zot\"!");
+ mpr(info);
+ }
+
+ // determine trap effects upon monster, based upon
+ // whether it is naughty or nice to the player: {dlb}
+
+ // NB: beem[].colour values are mislabeled as colours (?) -
+ // cf. mons_ench_f2() [which are also mislabeled] {dlb}
+ temp_rand = random2(16);
+
+ beem.thrower = KILL_MON; // probably unnecessary
+ beem.aux_source = NULL;
+
+ if (mons_friendly(monster))
+ {
+ beem.colour = ((temp_rand < 3) ? CYAN : //paralyze - 3 in 16
+ (temp_rand < 7) ? RED // confuse - 4 in 16
+ : BLACK); // slow - 9 in 16
+ }
+ else
+ {
+ beem.colour = ((temp_rand < 3) ? BLUE : //haste - 3 in 16 {dlb}
+ (temp_rand < 7) ? MAGENTA //invis - 4 in 16 {dlb}
+ : GREEN); // heal - 9 in 16 {dlb}
+ }
+
+ mons_ench_f2(monster, beem);
+ damage_taken = 0; // just to be certain {dlb}
+ break;
+ }
+
+
+ // go back and handle projectile traps: {dlb}
+ bool apply_poison = false;
+
+ if (projectileFired)
+ {
+ // projectile traps *always* revealed after "firing": {dlb}
+ revealTrap = true;
+
+ // determine whether projectile hits, calculate damage: {dlb}
+ if (((20 + (you.your_level * 2)) * random2(200)) / 100
+ >= monster->evasion)
+ {
+ damage_taken = roll_dice( beem.damage );
+ damage_taken -= random2(1 + monster->armour_class);
+
+ if (damage_taken < 0)
+ damage_taken = 0;
+
+ if (beem.colour == OBJ_MISSILES
+ && beem.type == MI_NEEDLE
+ && random2(100) < 50 - (3*monster->armour_class/2))
+ {
+ apply_poison = true;
+ }
+ }
+ else
+ {
+ damage_taken = -1; // negative damage marks a miss
+ }
+
+ if (monsterNearby)
+ {
+ snprintf( info, INFO_SIZE, "A%s %s %s%s!",
+ beem.beam_name,
+ (damage_taken >= 0) ? "hits" : "misses",
+ ptr_monam( monster, DESC_NOCAP_THE ),
+ (damage_taken == 0) ? ", but does no damage" : "" );
+
+ mpr(info);
+ }
+
+ if (apply_poison)
+ poison_monster( monster, false );
+
+ // generate "fallen" projectile, where appropriate: {dlb}
+ if (random2(10) < 7)
+ {
+ beem.target_x = monster->x;
+ beem.target_y = monster->y;
+ itrap(beem, which_trap);
+ }
+ }
+
+
+ // reveal undiscovered traps, where appropriate: {dlb}
+ if (monsterNearby && !trapKnown && revealTrap)
+ {
+ grd[monster->x][monster->y] = trap_category(env.trap[which_trap].type);
+ }
+
+ // apply damage and handle death, where appropriate: {dlb}
+ if (damage_taken > 0)
+ {
+ hurt_monster(monster, damage_taken);
+
+ if (monster->hit_points < 1)
+ {
+ monster_die(monster, KILL_MISC, 0);
+ monster->speed_increment = 1;
+ }
+ }
+
+ return;
+} // end mons_trap()
+
+void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast)
+{
+ // always do setup. It might be done already, but it doesn't
+ // hurt to do it again (cheap).
+ setup_mons_cast(monster, pbolt, spell_cast);
+
+ // single calculation permissible {dlb}
+ bool monsterNearby = mons_near(monster);
+
+ int sumcount = 0;
+ int sumcount2;
+ int summonik = 0;
+ int duration = 0;
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "Mon #%d casts %s (#%d)", monster_index(monster),
+ mons_spell_name( spell_cast ), spell_cast );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ if (spell_cast == MS_HELLFIRE_BURST || spell_cast == MS_BRAIN_FEED
+ || spell_cast == MS_SMITE || spell_cast == MS_MUTATION)
+ { // etc.
+ if (monster->foe == MHITYOU || monster->foe == MHITNOT)
+ {
+ if (monsterNearby)
+ direct_effect( pbolt );
+ return;
+ }
+
+ mons_direct_effect( pbolt, monster_index(monster) );
+ return;
+ }
+
+ switch (spell_cast)
+ {
+ case MS_VAMPIRE_SUMMON:
+ sumcount2 = 3 + random2(3) + monster->hit_dice / 5;
+
+ for (sumcount = 0; sumcount < sumcount2; sumcount++)
+ {
+ int mons = MONS_GIANT_BAT;
+
+ if (!one_chance_in(3))
+ {
+ switch (random2(4))
+ {
+ case 0:
+ mons = MONS_ORANGE_RAT;
+ break;
+
+ case 1:
+ mons = MONS_GREEN_RAT;
+ break;
+
+ case 2:
+ mons = MONS_GREY_RAT;
+ break;
+
+ case 3:
+ default:
+ mons = MONS_RAT;
+ break;
+ }
+ }
+
+ create_monster( mons, ENCH_ABJ_V, SAME_ATTITUDE(monster),
+ monster->x, monster->y, monster->foe, 250 );
+ }
+ return;
+
+ case MS_LEVEL_SUMMON: // summon anything appropriate for level
+ if (!mons_friendly(monster) && monsterNearby
+ && monster_abjuration(1, true) > 0 && coinflip())
+ {
+ monster_abjuration( monster->hit_dice * 10, false );
+ return;
+ }
+
+ sumcount2 = 1 + random2(4) + random2( monster->hit_dice / 7 + 1 );
+
+ for (sumcount = 0; sumcount < sumcount2; sumcount++)
+ {
+ create_monster( RANDOM_MONSTER, ENCH_ABJ_V, SAME_ATTITUDE(monster),
+ monster->x, monster->y, monster->foe, 250 );
+ }
+ return;
+
+ case MS_FAKE_RAKSHASA_SUMMON:
+ sumcount2 = (coinflip() ? 2 : 3);
+
+ for (sumcount = 0; sumcount < sumcount2; sumcount++)
+ {
+ create_monster( MONS_RAKSHASA_FAKE, ENCH_ABJ_III,
+ SAME_ATTITUDE(monster), monster->x, monster->y,
+ monster->foe, 250 );
+ }
+ return;
+
+ case MS_SUMMON_DEMON: // class 2-4 demons
+ if (!mons_friendly(monster) && monsterNearby
+ && monster_abjuration(1, true) > 0 && coinflip())
+ {
+ monster_abjuration(monster->hit_dice * 10, false);
+ return;
+ }
+
+ sumcount2 = 1 + random2(2) + random2( monster->hit_dice / 10 + 1 );
+
+ duration = ENCH_ABJ_II + monster->hit_dice / 10;
+ if (duration > ENCH_ABJ_VI)
+ duration = ENCH_ABJ_VI;
+
+ for (sumcount = 0; sumcount < sumcount2; sumcount++)
+ {
+ create_monster( summon_any_demon(DEMON_COMMON), duration,
+ SAME_ATTITUDE(monster), monster->x, monster->y,
+ monster->foe, 250 );
+ }
+ return;
+
+ case MS_ANIMATE_DEAD:
+ // see special handling in monstuff::handle_spell {dlb}
+ animate_dead( 5 + random2(5), SAME_ATTITUDE(monster), monster->foe, 1 );
+ return;
+
+ case MS_SUMMON_DEMON_LESSER: // class 5 demons
+ sumcount2 = 1 + random2(3) + random2( monster->hit_dice / 5 + 1 );
+
+ duration = ENCH_ABJ_II + monster->hit_dice / 5;
+ if (duration > ENCH_ABJ_VI)
+ duration = ENCH_ABJ_VI;
+
+ for (sumcount = 0; sumcount < sumcount2; sumcount++)
+ {
+ create_monster( summon_any_demon(DEMON_LESSER), duration,
+ SAME_ATTITUDE(monster), monster->x, monster->y,
+ monster->foe, 250 );
+ }
+ return;
+
+ case MS_SUMMON_UFETUBUS:
+ sumcount2 = 2 + random2(2) + random2( monster->hit_dice / 5 + 1 );
+
+ duration = ENCH_ABJ_II + monster->hit_dice / 5;
+ if (duration > ENCH_ABJ_VI)
+ duration = ENCH_ABJ_VI;
+
+ for (sumcount = 0; sumcount < sumcount2; sumcount++)
+ {
+ create_monster( MONS_UFETUBUS, duration, SAME_ATTITUDE(monster),
+ monster->x, monster->y, monster->foe, 250 );
+ }
+ return;
+
+ case MS_SUMMON_BEAST: // Geryon
+ create_monster( MONS_BEAST, ENCH_ABJ_IV, SAME_ATTITUDE(monster),
+ monster->x, monster->y, monster->foe, 250 );
+ return;
+
+ case MS_SUMMON_UNDEAD: // summon undead around player
+ if (!mons_friendly(monster) && monsterNearby
+ && monster_abjuration(1, true) > 0 && coinflip())
+ {
+ monster_abjuration( monster->hit_dice * 10, false );
+ return;
+ }
+
+ sumcount2 = 2 + random2(2) + random2( monster->hit_dice / 4 + 1 );
+
+ duration = ENCH_ABJ_II + monster->hit_dice / 5;
+ if (duration > ENCH_ABJ_VI)
+ duration = ENCH_ABJ_VI;
+
+ for (sumcount = 0; sumcount < sumcount2; sumcount++)
+ {
+ do
+ {
+ summonik = random2(241); // hmmmm ... {dlb}
+ }
+ while (mons_holiness(summonik) != MH_UNDEAD);
+
+ create_monster(summonik, duration, SAME_ATTITUDE(monster),
+ you.x_pos, you.y_pos, monster->foe, 250);
+ }
+ return;
+
+ case MS_TORMENT:
+ if (!monsterNearby || mons_friendly(monster))
+ return;
+
+ simple_monster_message(monster, " calls on the powers of Hell!");
+
+ torment(monster->x, monster->y);
+ return;
+
+ case MS_SUMMON_DEMON_GREATER:
+ if (!mons_friendly(monster) && !monsterNearby &&
+ monster_abjuration(1, true) > 0 && coinflip())
+ {
+ monster_abjuration(monster->hit_dice * 10, false);
+ return;
+ }
+
+ sumcount2 = 1 + random2( monster->hit_dice / 10 + 1 );
+
+ duration = ENCH_ABJ_II + monster->hit_dice / 10;
+ if (duration > ENCH_ABJ_VI)
+ duration = ENCH_ABJ_VI;
+
+ for (sumcount = 0; sumcount < sumcount2; sumcount++)
+ {
+ create_monster( summon_any_demon(DEMON_GREATER), duration,
+ SAME_ATTITUDE(monster), monster->x, monster->y,
+ monster->foe, 250 );
+ }
+ return;
+
+ case MS_CANTRIP:
+ // Monster spell of uselessness, just prints a message.
+ // This spell exists so that some monsters with really strong
+ // spells (ie orc priest) can be toned down a bit. -- bwr
+ //
+ // XXX: Needs expansion, and perhaps different priest/mage flavours.
+ switch (random2(7))
+ {
+ case 0:
+ simple_monster_message( monster, " glows brightly for a moment.",
+ MSGCH_MONSTER_ENCHANT );
+ break;
+ case 1:
+ mpr( "You feel troubled." );
+ break;
+ case 2:
+ mpr( "You feel a wave of unholy energy pass over you." );
+ break;
+ case 3:
+ simple_monster_message( monster, " looks stronger.",
+ MSGCH_MONSTER_ENCHANT );
+ break;
+ case 4:
+ simple_monster_message( monster, " becomes somewhat translucent.",
+ MSGCH_MONSTER_ENCHANT );
+ break;
+ case 5:
+ simple_monster_message( monster, "'s eyes start to glow.",
+ MSGCH_MONSTER_ENCHANT );
+ break;
+ case 6:
+ default:
+ if (one_chance_in(20))
+ mpr( "You resist (whatever that was supposed to do)." );
+ else
+ mpr( "You resist." );
+ break;
+ }
+ return;
+ }
+
+ fire_beam( pbolt );
+} // end mons_cast()
+
+
+/*
+ * setup bolt structure for monster spell casting.
+ *
+ */
+
+void setup_mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast)
+{
+ // always set these -- used by things other than fire_beam()
+ pbolt.ench_power = 12 * monster->hit_dice;
+
+ if (spell_cast == MS_TELEPORT)
+ pbolt.ench_power = 2000;
+ else if (spell_cast == MS_PAIN) // this is cast by low HD monsters
+ pbolt.ench_power *= 2;
+
+ pbolt.beam_source = monster_index(monster);
+
+ // set bolt type
+ if (spell_cast == MS_HELLFIRE_BURST
+ || spell_cast == MS_BRAIN_FEED
+ || spell_cast == MS_SMITE || spell_cast == MS_MUTATION)
+ { // etc.
+ switch (spell_cast)
+ {
+ case MS_HELLFIRE_BURST:
+ pbolt.type = DMNBM_HELLFIRE;
+ break;
+ case MS_BRAIN_FEED:
+ pbolt.type = DMNBM_BRAIN_FEED;
+ break;
+ case MS_SMITE:
+ pbolt.type = DMNBM_SMITING;
+ break;
+ case MS_MUTATION:
+ pbolt.type = DMNBM_MUTATION;
+ break;
+ }
+ return;
+ }
+
+ // the below are no-ops since they don't involve direct_effect,
+ // fire_tracer, or beam.
+ switch (spell_cast)
+ {
+ case MS_VAMPIRE_SUMMON:
+ case MS_LEVEL_SUMMON: // summon anything appropriate for level
+ case MS_FAKE_RAKSHASA_SUMMON:
+ case MS_SUMMON_DEMON:
+ case MS_ANIMATE_DEAD:
+ case MS_SUMMON_DEMON_LESSER:
+ case MS_SUMMON_UFETUBUS:
+ case MS_SUMMON_BEAST: // Geryon
+ case MS_SUMMON_UNDEAD: // summon undead around player
+ case MS_TORMENT:
+ case MS_SUMMON_DEMON_GREATER:
+ case MS_CANTRIP:
+ return;
+ default:
+ break;
+ }
+
+ // Need to correct this for power of spellcaster
+ int power = 12 * monster->hit_dice;
+
+ struct SBeam theBeam = mons_spells(spell_cast, power);
+
+ pbolt.colour = theBeam.colour;
+ pbolt.range = theBeam.range;
+ pbolt.rangeMax = theBeam.rangeMax;
+ pbolt.hit = theBeam.hit;
+ pbolt.damage = theBeam.damage;
+ pbolt.ench_power = theBeam.ench_power;
+ pbolt.type = theBeam.type;
+ pbolt.flavour = theBeam.flavour;
+ pbolt.thrower = theBeam.thrown;
+ pbolt.aux_source = NULL;
+ strcpy( pbolt.beam_name, theBeam.name.c_str() );
+ pbolt.isBeam = theBeam.isBeam;
+ pbolt.source_x = monster->x;
+ pbolt.source_y = monster->y;
+ pbolt.isTracer = false;
+
+ if (pbolt.beam_name[0] && pbolt.beam_name[0] != '0')
+ pbolt.aux_source = pbolt.beam_name;
+ else
+ pbolt.aux_source = NULL;
+
+ if (spell_cast == MS_HASTE
+ || spell_cast == MS_INVIS
+ || spell_cast == MS_HEAL || spell_cast == MS_TELEPORT)
+ {
+ pbolt.target_x = monster->x;
+ pbolt.target_y = monster->y;
+ }
+} // end setup_mons_cast()
+
+
+void monster_teleport(struct monsters *monster, bool instan)
+{
+ if (!instan)
+ {
+ if (mons_del_ench(monster, ENCH_TP_I, ENCH_TP_IV))
+ {
+ simple_monster_message(monster, " seems more stable.");
+ }
+ else
+ mons_add_ench(monster, (coinflip() ? ENCH_TP_III : ENCH_TP_IV ));
+
+ return;
+ }
+
+ simple_monster_message(monster, " disappears!");
+
+ // pick the monster up
+ mgrd[monster->x][monster->y] = NON_MONSTER;
+
+ char ogrid = monster_habitat(monster->type);
+
+ int newx, newy;
+ while(true)
+ {
+ newx = 10 + random2(GXM - 20);
+ newy = 10 + random2(GYM - 20);
+
+ // don't land on top of another monster
+ if (mgrd[newx][newy] != NON_MONSTER)
+ continue;
+
+ // monsters going to the same habitat
+ if (ogrid == grd[newx][newy])
+ break;
+
+ // DEEP_WATER monsters can be teleported to SHALLOW_WATER
+ if (ogrid == DNGN_DEEP_WATER && grd[newx][newy] == DNGN_SHALLOW_WATER)
+ break;
+ }
+
+ monster->x = newx;
+ monster->y = newy;
+
+ mgrd[monster->x][monster->y] = monster_index(monster);
+
+ /* Mimics change form/colour when t'ported */
+ if (mons_is_mimic( monster->type ))
+ {
+ monster->type = MONS_GOLD_MIMIC + random2(5);
+ monster->number = get_mimic_colour( monster );
+ }
+} // end monster_teleport()
+
+void setup_dragon(struct monsters *monster, struct bolt &pbolt)
+{
+ strcpy(pbolt.beam_name, ptr_monam( monster, DESC_PLAIN ));
+
+ switch (monster->type)
+ {
+ case MONS_FIREDRAKE:
+ case MONS_HELL_HOUND:
+ case MONS_DRAGON:
+ case MONS_LINDWURM:
+ case MONS_XTAHUA:
+ strcat(pbolt.beam_name, "'s blast of flame");
+ pbolt.flavour = BEAM_FIRE;
+ pbolt.colour = RED;
+ pbolt.aux_source = "blast of flame";
+ break;
+
+ case MONS_ICE_DRAGON:
+ strcat(pbolt.beam_name, "'s blast of cold");
+ pbolt.flavour = BEAM_COLD;
+ pbolt.colour = WHITE;
+ pbolt.aux_source = "blast of cold";
+ break;
+
+ default:
+ DEBUGSTR("Bad monster class in setup_dragon()");
+ }
+
+ pbolt.range = 4;
+ pbolt.rangeMax = 13;
+ pbolt.damage = dice_def( 3, (monster->hit_dice * 2) );
+ pbolt.type = SYM_ZAP;
+ pbolt.hit = 30;
+ pbolt.beam_source = monster_index(monster);
+ pbolt.thrower = KILL_MON;
+ pbolt.isBeam = true;
+} // end setup_dragon();
+
+void setup_generic_throw(struct monsters *monster, struct bolt &pbolt)
+{
+ pbolt.range = 9;
+ pbolt.rangeMax = 9;
+ pbolt.beam_source = monster_index(monster);
+
+ pbolt.type = SYM_MISSILE;
+ pbolt.flavour = BEAM_MISSILE;
+ pbolt.thrower = KILL_MON_MISSILE;
+ pbolt.aux_source = NULL;
+ pbolt.isBeam = false;
+}
+
+// decide if something is launched or thrown
+// pass -1 for launcher class & 0 for type if no weapon is weilded
+
+void throw_type( int lnchClass, int lnchType, int wepClass, int wepType,
+ bool &launched, bool &thrown )
+{
+ if (wepClass == OBJ_MISSILES
+ && lnchClass == OBJ_WEAPONS
+ && launches_things(lnchType) && wepType == launched_by(lnchType))
+ {
+ launched = true;
+ }
+
+ if (wepClass == OBJ_WEAPONS)
+ {
+ if (wepType == WPN_DAGGER || wepType == WPN_HAND_AXE || wepType == WPN_SPEAR)
+ {
+ thrown = true;
+ }
+ }
+
+ if (wepClass == OBJ_MISSILES)
+ {
+ if (wepType == MI_DART || wepType == MI_STONE || wepType == MI_LARGE_ROCK)
+ {
+ thrown = true;
+ }
+ }
+
+ // launched overrides thrown
+ if (launched == true)
+ thrown = false;
+}
+
+bool mons_throw(struct monsters *monster, struct bolt &pbolt, int hand_used)
+{
+ // this was assumed during cleanup down below:
+ ASSERT( hand_used == monster->inv[MSLOT_MISSILE] );
+
+ // XXX: ugly hack, but avoids adding dynamic allocation to this code
+ static char throw_buff[ ITEMNAME_SIZE ];
+
+ int baseHit = 0, baseDam = 0; // from thrown or ammo
+ int ammoHitBonus = 0, ammoDamBonus = 0; // from thrown or ammo
+ int lnchHitBonus = 0, lnchDamBonus = 0; // special add from launcher
+ int exHitBonus = 0, exDamBonus = 0; // 'extra' bonus from skill/dex/str
+
+ int hitMult = 0;
+ int damMult = 0;
+
+ bool launched = false; // item is launched
+ bool thrown = false; // item is sensible thrown item
+
+ // some initial convenience & initializations
+ int wepClass = mitm[hand_used].base_type;
+ int wepType = mitm[hand_used].sub_type;
+
+ int weapon = monster->inv[MSLOT_WEAPON];
+
+ int lnchClass = (weapon != NON_ITEM) ? mitm[weapon].base_type : -1;
+ int lnchType = (weapon != NON_ITEM) ? mitm[weapon].sub_type : 0;
+
+ item_def item = mitm[hand_used]; // copy changed for venom launchers
+ item.quantity = 1;
+
+ pbolt.range = 9;
+ pbolt.beam_source = monster_index(monster);
+
+ pbolt.type = SYM_MISSILE;
+ pbolt.colour = item.colour;
+ pbolt.flavour = BEAM_MISSILE;
+ pbolt.thrower = KILL_MON_MISSILE;
+ pbolt.aux_source = NULL;
+
+ // figure out if we're thrown or launched
+ throw_type( lnchClass, lnchType, wepClass, wepType, launched, thrown );
+
+ // extract launcher bonuses due to magic
+ if (launched)
+ {
+ lnchHitBonus = mitm[ weapon ].plus;
+ lnchDamBonus = mitm[ weapon ].plus2;
+ }
+
+ // extract weapon/ammo bonuses due to magic
+ ammoHitBonus = item.plus;
+ ammoDamBonus = item.plus2;
+
+ if (thrown)
+ {
+ // Darts are easy.
+ if (wepClass == OBJ_MISSILES && wepType == MI_DART)
+ {
+ baseHit = 5;
+ hitMult = 40;
+ damMult = 25;
+ }
+ else
+ {
+ baseHit = 0;
+ hitMult = 30;
+ damMult = 25;
+ }
+
+ baseDam = property( item, PWPN_DAMAGE );
+
+ if (wepClass == OBJ_MISSILES) // throw missile
+ // ammo damage needs adjusting here - OBJ_MISSILES
+ // don't get separate tohit/damage bonuses!
+ ammoDamBonus = ammoHitBonus;
+
+ // give monster "skill" bonuses based on HD
+ exHitBonus = (hitMult * monster->hit_dice) / 10 + 1;
+ exDamBonus = (damMult * monster->hit_dice) / 10 + 1;
+ }
+
+ if (launched)
+ {
+ switch (lnchType)
+ {
+ case WPN_BLOWGUN:
+ baseHit = 2;
+ hitMult = 60;
+ damMult = 0;
+ lnchDamBonus = 0;
+ break;
+ case WPN_BOW:
+ baseHit = 0;
+ hitMult = 60;
+ damMult = 35;
+ // monsters get half the launcher damage bonus,
+ // which is about as fair as I can figure it.
+ lnchDamBonus = (lnchDamBonus + 1) / 2;
+ break;
+ case WPN_CROSSBOW:
+ baseHit = 4;
+ hitMult = 70;
+ damMult = 30;
+ break;
+ case WPN_HAND_CROSSBOW:
+ baseHit = 2;
+ hitMult = 50;
+ damMult = 20;
+ break;
+ case WPN_SLING:
+ baseHit = 1;
+ hitMult = 40;
+ damMult = 20;
+ // monsters get half the launcher damage bonus,
+ // which is about as fair as I can figure it.
+ lnchDamBonus /= 2;
+ break;
+ }
+
+ baseDam = property( item, PWPN_HIT );
+
+ // missiles don't have pluses2; use hit bonus
+ ammoDamBonus = ammoHitBonus;
+
+ exHitBonus = (hitMult * monster->hit_dice) / 10 + 1;
+ exDamBonus = (damMult * monster->hit_dice) / 10 + 1;
+
+ // elven bow w/ elven arrow, also orcish
+ if (get_equip_race( mitm[monster->inv[MSLOT_WEAPON]] )
+ == get_equip_race( mitm[monster->inv[MSLOT_MISSILE]] ))
+ {
+ baseHit++;
+ baseDam++;
+
+ if (cmp_equip_race(mitm[monster->inv[MSLOT_WEAPON]], ISFLAG_ELVEN))
+ pbolt.hit++;
+ }
+
+ // monsters no longer gain unfair advantages with weapons of fire/ice
+ // and incorrect ammo. They now have same restriction as players.
+
+ const int bow_brand = get_weapon_brand(mitm[monster->inv[MSLOT_WEAPON]]);
+
+ const int ammo_brand = get_ammo_brand( item );
+
+ bool poison = (ammo_brand == SPMSL_POISONED
+ || ammo_brand == SPMSL_POISONED_II);
+
+ // POISON brand launchers poison ammo
+ if (bow_brand == SPWPN_VENOM && ammo_brand == SPMSL_NORMAL)
+ set_item_ego_type( item, OBJ_MISSILES, SPMSL_POISONED );
+
+
+ // WEAPON or AMMO of FIRE
+ if ((bow_brand == SPWPN_FLAME || ammo_brand == SPMSL_FLAME)
+ && bow_brand != SPWPN_FROST && ammo_brand != SPMSL_ICE)
+ {
+ baseHit += 2;
+ exDamBonus += 6;
+ pbolt.flavour = BEAM_FIRE;
+ strcpy(pbolt.beam_name, "bolt of ");
+
+ if (poison)
+ strcat(pbolt.beam_name, "poison ");
+
+ strcat(pbolt.beam_name, "flame");
+ pbolt.colour = RED;
+ pbolt.type = SYM_ZAP;
+ }
+
+ // WEAPON or AMMO of FROST
+ if ((bow_brand == SPWPN_FROST || ammo_brand == SPMSL_ICE)
+ && bow_brand != SPWPN_FLAME && ammo_brand != SPMSL_FLAME)
+ {
+ baseHit += 2;
+ exDamBonus += 6;
+ pbolt.flavour = BEAM_COLD;
+ strcpy(pbolt.beam_name, "bolt of ");
+
+ if (poison)
+ strcat(pbolt.beam_name, "poison ");
+
+ strcat(pbolt.beam_name, "frost");
+ pbolt.colour = WHITE;
+ pbolt.type = SYM_ZAP;
+ }
+
+ // Note: we already have 10 energy taken off. -- bwr
+ if (lnchType == WPN_CROSSBOW)
+ monster->speed_increment += ((bow_brand == SPWPN_SPEED) ? 4 : -2);
+ else if (bow_brand == SPWPN_SPEED)
+ monster->speed_increment += 5;
+ }
+
+ // monster intelligence bonus
+ if (mons_intel(monster->type) == I_HIGH)
+ exHitBonus += 10;
+
+ // now, if a monster is, for some reason, throwing something really
+ // stupid, it will have baseHit of 0 and damage of 0. Ah well.
+ strcpy(info, ptr_monam( monster, DESC_CAP_THE) );
+
+ strcat(info, (launched) ? " shoots " : " throws ");
+
+ if (strlen(pbolt.beam_name) > 0)
+ {
+ strcat(info, "a ");
+ strcat(info, pbolt.beam_name);
+ }
+ else
+ {
+ // build shoot message
+ char str_pass[ ITEMNAME_SIZE ];
+ item_name( item, DESC_NOCAP_A, str_pass );
+ strcat(info, str_pass);
+
+ // build beam name
+ item_name( item, DESC_PLAIN, str_pass );
+ strcpy(pbolt.beam_name, str_pass);
+ }
+
+ strcat(info, ".");
+ mpr(info);
+
+
+ if (launched)
+ {
+ snprintf( throw_buff, sizeof(throw_buff), "Shot with a%s %s by %s",
+ (is_vowel(pbolt.beam_name[0]) ? "n" : ""), pbolt.beam_name,
+ ptr_monam( monster, DESC_NOCAP_A ) );
+ }
+ else
+ {
+ snprintf( throw_buff, sizeof(throw_buff), "Hit by a%s %s thrown by %s",
+ (is_vowel(pbolt.beam_name[0]) ? "n" : ""), pbolt.beam_name,
+ ptr_monam( monster, DESC_NOCAP_A ) );
+ }
+
+ pbolt.aux_source = throw_buff;
+
+ // add everything up.
+ pbolt.hit = baseHit + random2avg(exHitBonus, 2) + ammoHitBonus;
+ pbolt.damage = dice_def( 1, baseDam + random2avg(exDamBonus, 2) + ammoDamBonus );
+
+ if (launched)
+ {
+ pbolt.damage.size += lnchDamBonus;
+ pbolt.hit += lnchHitBonus;
+ }
+
+ // decrease inventory
+ fire_beam( pbolt, &item );
+
+ if (dec_mitm_item_quantity( hand_used, 1 ))
+ monster->inv[MSLOT_MISSILE] = NON_ITEM;
+
+
+ return (true);
+} // end mons_throw()
+
+// should really do something about mons_hit, but can't be bothered
+void spore_goes_pop(struct monsters *monster)
+{
+ struct bolt beam;
+ int type = monster->type;
+
+ if (monster == NULL)
+ return;
+
+ beam.isTracer = false;
+ beam.beam_source = monster_index(monster);
+ beam.type = SYM_BURST;
+ beam.target_x = monster->x;
+ beam.target_y = monster->y;
+ beam.thrower = KILL_MON; // someone else's explosion
+ beam.aux_source = NULL;
+
+ if (type == MONS_GIANT_SPORE)
+ {
+ beam.flavour = BEAM_SPORE;
+ strcpy(beam.beam_name, "explosion of spores");
+ beam.colour = LIGHTGREY;
+ beam.damage = dice_def( 3, 15 );
+ beam.ex_size = 2;
+ strcpy( info, "The giant spore explodes!" );
+ }
+ else
+ {
+ beam.flavour = BEAM_ELECTRICITY;
+ strcpy(beam.beam_name, "blast of lightning");
+ beam.colour = LIGHTCYAN;
+ beam.damage = dice_def( 3, 20 );
+ beam.ex_size = coinflip() ? 3 : 2;
+ strcpy( info, "The ball lightning explodes!" );
+ }
+
+ if (mons_near(monster))
+ {
+ viewwindow(1, false);
+ mpr( info );
+ }
+
+ explosion(beam);
+} // end spore_goes_pop()
+
+struct SBeam mons_spells( int spell_cast, int power )
+{
+ ASSERT(power > 0);
+
+ struct SBeam beam;
+
+ beam.name = "****"; // initialize to some bogus values so we can catch problems
+ beam.colour = 1000;
+ beam.range = -1;
+ beam.hit = -1;
+ beam.damage = dice_def( 1, 0 );
+ beam.ench_power = -1;
+ beam.type = -1;
+ beam.flavour = -1;
+ beam.thrown = -1;
+
+ switch (spell_cast)
+ {
+ case MS_MMISSILE:
+ beam.colour = LIGHTMAGENTA; //inv_colour [throw_2];
+ beam.name = "magic dart"; // inv_name [throw_2]);
+ beam.range = 6;
+ beam.rangeMax = 10;
+ beam.damage = dice_def( 3, 4 + (power / 100) );
+ beam.hit = 1500;
+ beam.type = SYM_ZAP;
+ beam.thrown = KILL_MON_MISSILE;
+ beam.flavour = BEAM_MMISSILE;
+ beam.isBeam = false;
+ break;
+
+ case MS_FLAME:
+ beam.colour = RED;
+ beam.name = "puff of flame";
+ beam.range = 6;
+ beam.rangeMax = 10;
+
+ // should this be the same as magic missile?
+ // No... magic missile is special in that it has a really
+ // high to-hit value, so these should do more damage -- bwr
+ beam.damage = dice_def( 3, 5 + (power / 40) );
+
+ beam.hit = 60;
+ beam.type = SYM_ZAP;
+ beam.thrown = KILL_MON_MISSILE;
+ beam.flavour = BEAM_FIRE;
+ beam.isBeam = false;
+ break;
+
+ case MS_FROST:
+ beam.colour = WHITE;
+ beam.name = "puff of frost";
+ beam.range = 6;
+ beam.rangeMax = 10;
+
+ // should this be the same as magic missile?
+ // see MS_FLAME -- bwr
+ beam.damage = dice_def( 3, 5 + (power / 40) );
+
+ beam.hit = 60;
+ beam.type = SYM_ZAP;
+ beam.thrown = KILL_MON_MISSILE;
+ beam.flavour = BEAM_COLD;
+ beam.isBeam = false;
+ break;
+
+ case MS_PARALYSIS:
+ beam.name = "0";
+ beam.range = 5;
+ beam.rangeMax = 9;
+ beam.type = 0;
+ beam.flavour = BEAM_PARALYSIS;
+ beam.thrown = KILL_MON_MISSILE;
+ beam.isBeam = true;
+ break;
+
+ case MS_SLOW:
+ beam.name = "0";
+ beam.range = 5;
+ beam.rangeMax = 9;
+ beam.type = 0;
+ beam.flavour = BEAM_SLOW;
+ beam.thrown = KILL_MON_MISSILE;
+ beam.isBeam = true;
+ break;
+
+ case MS_HASTE: // (self)
+ beam.name = "0";
+ beam.range = 5;
+ beam.rangeMax = 9;
+ beam.type = 0;
+ beam.flavour = BEAM_HASTE;
+ beam.thrown = KILL_MON_MISSILE;
+ beam.isBeam = true;
+ break;
+
+ case MS_CONFUSE:
+ beam.name = "0";
+ beam.range = 5;
+ beam.rangeMax = 9;
+ beam.type = 0;
+ beam.flavour = BEAM_CONFUSION;
+ beam.thrown = KILL_MON_MISSILE;
+ beam.isBeam = true;
+ break;
+
+ case MS_VENOM_BOLT:
+ beam.name = "bolt of poison";
+ beam.range = 7;
+ beam.rangeMax = 16;
+ beam.damage = dice_def( 3, 6 + power / 13 );
+ beam.colour = LIGHTGREEN;
+ beam.type = SYM_ZAP;
+ beam.thrown = KILL_MON;
+ beam.flavour = BEAM_POISON;
+ beam.hit = 7 + random2(power) / 80;
+ beam.isBeam = true;
+ break;
+
+ case MS_FIRE_BOLT:
+ beam.name = "bolt of fire";
+ beam.range = 4;
+ beam.rangeMax = 13;
+ beam.damage = dice_def( 3, 8 + power / 11 );
+ beam.colour = RED;
+ beam.type = SYM_ZAP;
+ beam.thrown = KILL_MON;
+ beam.flavour = BEAM_FIRE;
+ beam.hit = 8 + random2(power) / 80; // hit
+ beam.isBeam = true;
+ break;
+
+ case MS_COLD_BOLT:
+ beam.name = "bolt of cold";
+ beam.range = 4;
+ beam.rangeMax = 13;
+ beam.damage = dice_def( 3, 8 + power / 11 );
+ beam.colour = WHITE;
+ beam.type = SYM_ZAP;
+ beam.thrown = KILL_MON;
+ beam.flavour = BEAM_COLD;
+ beam.hit = 8 + random2(power) / 80; // hit
+ beam.isBeam = true;
+ break;
+
+ case MS_LIGHTNING_BOLT:
+ beam.name = "bolt of lightning";
+ beam.range = 7;
+ beam.rangeMax = 16;
+ beam.damage = dice_def( 3, 10 + power / 9 );
+ beam.colour = LIGHTCYAN;
+ beam.type = SYM_ZAP;
+ beam.thrown = KILL_MON;
+ beam.flavour = BEAM_ELECTRICITY;
+ beam.hit = 10 + random2(power) / 40;
+ beam.isBeam = true;
+ break;
+
+ case MS_INVIS:
+ beam.name = "0";
+ beam.range = 5;
+ beam.rangeMax = 9;
+ beam.type = 0;
+ beam.flavour = BEAM_INVISIBILITY;
+ beam.thrown = KILL_MON;
+ beam.isBeam = true;
+ break;
+
+ case MS_FIREBALL:
+ beam.colour = RED;
+ beam.name = "fireball";
+ beam.range = 6;
+ beam.rangeMax = 10;
+ beam.damage = dice_def( 3, 7 + power / 10 );
+ beam.hit = 40;
+ beam.type = SYM_ZAP;
+ beam.thrown = KILL_MON;
+ beam.flavour = BEAM_EXPLOSION; // why not BEAM_FIRE? {dlb}
+ beam.isBeam = false;
+ break;
+
+ case MS_HEAL:
+ beam.name = "0";
+ beam.range = 5;
+ beam.rangeMax = 9;
+ beam.type = 0;
+ beam.flavour = BEAM_HEALING;
+ beam.thrown = KILL_MON;
+ beam.hit = 5 + (power / 5);
+ beam.isBeam = true;
+ break;
+
+ case MS_TELEPORT:
+ beam.name = "0";
+ beam.range = 5;
+ beam.rangeMax = 9;
+ beam.type = 0;
+ beam.flavour = BEAM_TELEPORT; // 6 is used by digging
+ beam.thrown = KILL_MON;
+ beam.isBeam = true;
+ break;
+
+ case MS_TELEPORT_OTHER:
+ beam.name = "0";
+ beam.range = 5;
+ beam.rangeMax = 9;
+ beam.type = 0;
+ beam.flavour = BEAM_TELEPORT; // 6 is used by digging
+ beam.thrown = KILL_MON;
+ beam.isBeam = true;
+ break;
+
+ case MS_BLINK:
+ beam.isBeam = false;
+ break;
+
+ case MS_CRYSTAL_SPEAR: // was splinters
+ beam.name = "crystal spear";
+ beam.range = 7;
+ beam.rangeMax = 16;
+ beam.damage = dice_def( 3, 12 + power / 10 );
+ beam.colour = WHITE;
+ beam.type = SYM_MISSILE;
+ beam.thrown = KILL_MON;
+ beam.flavour = BEAM_MMISSILE;
+ beam.hit = 6; // + random2(power) / 10;
+ beam.isBeam = false;
+ break;
+
+ case MS_DIG:
+ beam.name = "0";
+ beam.range = 3;
+ beam.rangeMax = 7 + random2(power) / 10;
+ beam.type = 0;
+ beam.flavour = BEAM_DIGGING;
+ beam.thrown = KILL_MON;
+ beam.isBeam = true;
+ break;
+
+ case MS_NEGATIVE_BOLT: // negative energy
+ beam.name = "bolt of negative energy";
+ beam.range = 7;
+ beam.rangeMax = 16;
+ beam.damage = dice_def( 3, 6 + power / 13 );
+ beam.colour = DARKGREY;
+ beam.type = SYM_ZAP;
+ beam.thrown = KILL_MON;
+ beam.flavour = BEAM_NEG;
+ beam.hit = 7 + random2(power) / 80;
+ beam.isBeam = true;
+ break;
+
+ // 20, 21 are used
+
+ case MS_ORB_ENERGY: // mystic blast
+ beam.colour = LIGHTMAGENTA;
+ beam.name = "orb of energy";
+ beam.range = 6;
+ beam.rangeMax = 10;
+ beam.damage = dice_def( 3, 7 + (power / 14) );
+ beam.hit = 10 + (power / 20);
+ beam.type = SYM_ZAP;
+ beam.thrown = KILL_MON_MISSILE;
+ beam.flavour = BEAM_MMISSILE;
+ beam.isBeam = false;
+ break;
+
+ // 23 is brain feed
+
+ case MS_STEAM_BALL:
+ beam.colour = LIGHTGREY;
+ beam.name = "ball of steam";
+ beam.range = 6;
+ beam.rangeMax = 10;
+ beam.damage = dice_def( 3, 6 );
+ beam.hit = 11;
+ beam.type = SYM_ZAP;
+ beam.thrown = KILL_MON_MISSILE;
+ beam.flavour = BEAM_FIRE; // fire - I think this is appropriate
+ beam.isBeam = false;
+ break;
+
+ // 27 is summon devils
+ // 28 is animate dead
+
+ case MS_PAIN:
+ beam.name = "0";
+ beam.range = 7;
+ beam.rangeMax = 14;
+ beam.type = 0;
+ beam.flavour = BEAM_PAIN; // pain
+ beam.thrown = KILL_MON;
+ // beam.damage = dice_def( 1, 50 );
+ beam.damage = dice_def( 1, 7 + (power / 20) );
+ beam.ench_power = 50;
+ beam.isBeam = true;
+ break;
+
+ // 30 is smiting
+
+ case MS_STICKY_FLAME:
+ beam.colour = RED;
+ beam.name = "sticky flame";
+ beam.range = 6;
+ beam.rangeMax = 10;
+ beam.damage = dice_def( 3, 3 + power / 50 );
+ beam.hit = 8 + power / 15;
+ beam.type = SYM_ZAP;
+ beam.thrown = KILL_MON_MISSILE;
+ beam.flavour = BEAM_FIRE;
+ beam.isBeam = false;
+ break;
+
+ case MS_POISON_BLAST: // demon
+ beam.name = "blast of poison";
+ beam.range = 7;
+ beam.rangeMax = 16;
+ beam.damage = dice_def( 3, 3 + power / 25 );
+ beam.colour = LIGHTGREEN;
+ beam.type = SYM_ZAP;
+ beam.thrown = KILL_MON;
+ beam.flavour = BEAM_POISON;
+ beam.hit = 7 + random2(power) / 80;
+ beam.isBeam = true;
+ break;
+
+ case MS_PURPLE_BLAST: // purple bang thing
+ beam.colour = LIGHTMAGENTA;
+ beam.name = "orb of energy";
+ beam.range = 6;
+ beam.rangeMax = 10;
+ beam.damage = dice_def( 3, 10 + power / 15 );
+ beam.hit = 10 + power / 20;
+ beam.type = SYM_ZAP;
+ beam.thrown = KILL_MON_MISSILE;
+ beam.flavour = BEAM_EXPLOSION; // an exploding magical missile
+ beam.isBeam = false;
+ break;
+
+ case MS_ENERGY_BOLT: // eye of devastation
+ beam.colour = YELLOW;
+ beam.name = "bolt of energy";
+ beam.range = 9;
+ beam.rangeMax = 23;
+ beam.damage = dice_def( 3, 20 );
+ beam.hit = 9;
+ beam.type = SYM_ZAP;
+ beam.thrown = KILL_MON_MISSILE;
+ beam.flavour = BEAM_NUKE; // a magical missile which destroys walls
+ beam.isBeam = true;
+ break;
+
+ case MS_STING: // sting
+ beam.colour = GREEN;
+ beam.name = "sting";
+ beam.range = 8;
+ beam.rangeMax = 12;
+ beam.damage = dice_def( 1, 6 + power / 25 );
+ beam.hit = 60;
+ beam.type = SYM_ZAP;
+ beam.thrown = KILL_MON_MISSILE;
+ beam.flavour = BEAM_POISON;
+ beam.isBeam = false;
+ break;
+
+ case MS_IRON_BOLT:
+ beam.colour = LIGHTCYAN;
+ beam.name = "iron bolt";
+ beam.range = 4;
+ beam.rangeMax = 8;
+ beam.damage = dice_def( 3, 8 + (power / 9) );
+ beam.hit = 6 + (power / 25);
+ beam.type = SYM_MISSILE;
+ beam.thrown = KILL_MON_MISSILE;
+ beam.flavour = BEAM_MMISSILE; // similarly unresisted thing
+ beam.isBeam = false;
+ break;
+
+ case MS_STONE_ARROW:
+ beam.colour = LIGHTGREY;
+ beam.name = "stone arrow";
+ beam.range = 8;
+ beam.rangeMax = 12;
+ beam.damage = dice_def( 3, 5 + (power / 10) );
+ beam.hit = 5 + power / 47;
+ beam.type = SYM_MISSILE;
+ beam.thrown = KILL_MON_MISSILE;
+ beam.flavour = BEAM_MMISSILE; // similarly unresisted thing
+ beam.isBeam = false;
+ break;
+
+ case MS_POISON_SPLASH:
+ beam.colour = GREEN;
+ beam.name = "splash of poison";
+ beam.range = 5;
+ beam.rangeMax = 10;
+ beam.damage = dice_def( 1, 4 + power / 10 );
+ beam.hit = 9;
+ beam.type = SYM_ZAP;
+ beam.thrown = KILL_MON_MISSILE;
+ beam.flavour = BEAM_POISON;
+ beam.isBeam = false;
+ break;
+
+ case MS_DISINTEGRATE:
+ beam.name = "0";
+ beam.range = 7;
+ beam.rangeMax = 14;
+ beam.type = 0;
+ beam.flavour = BEAM_DISINTEGRATION;
+ beam.thrown = KILL_MON;
+ beam.ench_power = 50;
+ // beam.hit = 30 + (power / 10);
+ beam.damage = dice_def( 1, 30 + (power / 10) );
+ beam.isBeam = true;
+ break;
+
+ case MS_MARSH_GAS: // swamp drake
+ beam.name = "foul vapour";
+ beam.range = 7;
+ beam.rangeMax = 16;
+ beam.damage = dice_def( 3, 2 + power / 25 );
+ beam.colour = GREEN;
+ beam.type = SYM_ZAP;
+ beam.thrown = KILL_MON;
+ beam.flavour = BEAM_POISON;
+ beam.hit = 7 + random2(power) / 80;
+ beam.isBeam = false;
+ break;
+
+ case MS_QUICKSILVER_BOLT: // Quicksilver dragon
+ beam.colour = random_colour();
+ beam.name = "bolt of energy";
+ beam.range = 9;
+ beam.rangeMax = 23;
+ beam.damage = dice_def( 3, 25 );
+ beam.hit = 9;
+ beam.type = SYM_ZAP;
+ beam.thrown = KILL_MON_MISSILE;
+ beam.flavour = BEAM_MMISSILE;
+ beam.isBeam = false;
+ break;
+
+ case MS_HELLFIRE: // fiend's hellfire
+ beam.name = "hellfire";
+ beam.colour = RED;
+ beam.range = 4;
+ beam.rangeMax = 13;
+ beam.damage = dice_def( 3, 25 );
+ beam.hit = 20;
+ beam.type = SYM_ZAP;
+ beam.thrown = KILL_MON;
+ beam.flavour = BEAM_EXPLOSION; // hellfire - not BEAM_HELLFIRE? {dlb}
+ beam.isBeam = true;
+ break;
+
+ case MS_METAL_SPLINTERS:
+ beam.name = "spray of metal splinters";
+ beam.range = 7;
+ beam.rangeMax = 16;
+ beam.damage = dice_def( 3, 20 + power / 20 );
+ beam.colour = CYAN;
+ beam.type = SYM_ZAP;
+ beam.thrown = KILL_MON;
+ beam.flavour = BEAM_FRAG;
+ beam.hit = 15 + random2(power) / 50;
+ beam.isBeam = true;
+ break;
+
+ case MS_BANISHMENT:
+ beam.name = "0";
+ beam.range = 5;
+ beam.rangeMax = 9;
+ beam.type = 0;
+ beam.flavour = BEAM_BANISH;
+ beam.thrown = KILL_MON_MISSILE;
+ beam.isBeam = true;
+ break;
+
+ default:
+ DEBUGSTR("Unknown spell");
+ }
+
+ return (beam);
+} // end mons_spells()
+
+static unsigned char monster_abjuration(int pow, bool test)
+{
+
+ unsigned char result = 0;
+ struct monsters *monster = 0; // NULL {dlb}
+
+ if (!test)
+ mpr("Send 'em back where they came from!");
+
+ for (int ab = 0; ab < MAX_MONSTERS; ab++)
+ {
+ int abjLevel;
+
+ monster = &menv[ab];
+
+ if (monster->type == -1 || !mons_near(monster))
+ continue;
+
+ if (!mons_friendly(monster))
+ continue;
+
+ abjLevel = mons_has_ench(monster, ENCH_ABJ_I, ENCH_ABJ_VI);
+ if (abjLevel == ENCH_NONE)
+ continue;
+
+ result++;
+
+ if (test)
+ continue;
+
+ if (pow > 60)
+ pow = 60;
+
+ abjLevel -= 1 + (random2(pow) / 3);
+
+ if (abjLevel < ENCH_ABJ_I)
+ monster_die(monster, KILL_RESET, 0);
+ else
+ {
+ simple_monster_message(monster, " shudders.");
+ mons_del_ench(monster, ENCH_ABJ_I, ENCH_ABJ_VI);
+ mons_add_ench(monster, abjLevel);
+ }
+ }
+
+ return result;
+} // end monster_abjuration()
diff --git a/trunk/source/mstuff2.h b/trunk/source/mstuff2.h
new file mode 100644
index 0000000000..1bdd23232f
--- /dev/null
+++ b/trunk/source/mstuff2.h
@@ -0,0 +1,117 @@
+/*
+ * File: mstuff2.h
+ * Summary: Misc monster related functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> 4/24/99 JDJ mons_spells returns an
+ * SBeam instead of using
+ * func_pass.
+ */
+
+
+#ifndef MSTUFF2_H
+#define MSTUFF2_H
+
+
+#include <string>
+#include "externs.h"
+
+
+struct SBeam
+{
+ std::string name;
+ int colour;
+ int range;
+ int rangeMax;
+ int hit;
+ dice_def damage;
+ int ench_power;
+ int type;
+ int flavour;
+ int thrown;
+ bool isBeam;
+};
+
+
+/*
+ beam_colour = _pass[0];
+ beam_range = _pass[1];
+ beam_damage = _pass[2];
+ beam_hit = _pass[3];
+ beam_type = _pass[4];
+ beam_flavour = _pass[5];
+ thing_thrown = _pass[6];
+ */
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: monstuff - mstuff2
+ * *********************************************************************** */
+struct SBeam mons_spells(int spell_cast, int power);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: monstuff
+ * *********************************************************************** */
+void setup_dragon(struct monsters *monster, struct bolt &pbolt);
+
+
+// last updated 13feb2001 {gdl}
+/* ***********************************************************************
+ * called from: monstuff
+ * *********************************************************************** */
+void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast);
+
+// last updated 7jan2001 {gdl}
+/* ***********************************************************************
+ * called from: monstuff
+ * *********************************************************************** */
+void setup_mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast);
+
+// last updated 28july2000 (gdl)
+/* ***********************************************************************
+ * called from: monstuff
+ * *********************************************************************** */
+bool mons_throw(struct monsters *monster, struct bolt &pbolt, int hand_used);
+
+// last updated 07jan2001 (gdl)
+/* ***********************************************************************
+ * called from: monstuff
+ * *********************************************************************** */
+void setup_generic_throw(struct monsters *monster, struct bolt &pbolt);
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: monstuff
+ * *********************************************************************** */
+void mons_trap(struct monsters *monster);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: beam - fight - files - monstuff - mstuff2 - spells4
+ * *********************************************************************** */
+void monster_teleport(struct monsters *monster, bool instan);
+
+
+// last updated Dec17,2000 -- gdl
+/* ***********************************************************************
+ * called from: monstuff
+ * *********************************************************************** */
+void spore_goes_pop(struct monsters *monster);
+
+
+// last updated Jan14,2001 -- gdl
+/* ***********************************************************************
+ * called from: monstuff
+ * *********************************************************************** */
+void throw_type(int lnchClass, int lnchType, int wepClass, int wepType,
+ bool &launched, bool &thrown);
+
+
+
+#endif
diff --git a/trunk/source/mutation.cc b/trunk/source/mutation.cc
new file mode 100644
index 0000000000..036d624fb9
--- /dev/null
+++ b/trunk/source/mutation.cc
@@ -0,0 +1,2326 @@
+/*
+ * File: mutation.cc
+ * Summary: Functions for handling player mutations.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <5> 7/29/00 JDJ Made give_cosmetic_mutation static
+ * <4> 9/25/99 CDL linuxlib -> liblinux
+ * <3> 9/21/99 LRH Added many new scales
+ * <2> 5/20/99 BWR Fixed it so demonspwan should
+ * always get a mutation, 3 level
+ * perma_mutations now work.
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "mutation.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#ifdef LINUX
+#include "liblinux.h"
+#endif
+
+#include "externs.h"
+
+#include "defines.h"
+#include "effects.h"
+#include "macro.h"
+#include "ouch.h"
+#include "player.h"
+#include "skills2.h"
+#include "stuff.h"
+#include "transfor.h"
+#include "view.h"
+
+
+int how_mutated(void);
+char body_covered(void);
+bool perma_mutate(int which_mut, char how_much);
+
+const char *mutation_descrip[][3] = {
+ {"You have tough skin (AC +1).", "You have very tough skin (AC +2).",
+ "You have extremely tough skin (AC +3)."},
+
+ {"Your muscles are strong (Str +", "", ""},
+ {"Your mind is acute (Int +", "", ""},
+ {"You are agile (Dex +", "", ""},
+
+ {"You are partially covered in green scales (AC + 1).",
+ "You are mostly covered in green scales (AC + 3).",
+ "You are covered in green scales (AC + 5)."},
+
+ {"You are partially covered in thick black scales (AC + 3, dex - 1).",
+ "You are mostly covered in thick black scales (AC + 6, dex - 2).",
+ "You are completely covered in thick black scales (AC + 9, dex - 3)."},
+
+ {"You are partially covered in supple grey scales (AC + 1).",
+ "You are mostly covered in supple grey scales (AC + 2).",
+ "You are completely covered in supple grey scales (AC + 3)."},
+
+ {"You are protected by plates of bone (AC + 2, dex - 1).",
+ "You are protected by plates of bone (AC + 3, dex - 2).",
+ "You are protected by plates of bone (AC + 4, dex - 3)."},
+
+ {"You are surrounded by a mild repulsion field (ev + 1).",
+ "You are surrounded by a moderate repulsion field (ev + 3).",
+ "You are surrounded by a strong repulsion field (ev + 5; repel missiles)."},
+ {"Your system is immune to poisons.", "Your system is immune to poisons.",
+ "Your system is immune to poisons."},
+// 10
+
+ {"Your digestive system is specialised to digest meat.",
+ "Your digestive system is specialised to digest meat.",
+ "You are primarily a carnivore."},
+
+ {"You digest meat inefficiently.", "You digest meat inefficiently.",
+ "You are primarily a herbivore."},
+
+ {"Your flesh is heat resistant.", "Your flesh is very heat resistant.",
+ "Your flesh is almost immune to the effects of heat."},
+
+ {"Your flesh is cold resistant.", "Your flesh is very cold resistant.",
+ "Your flesh is almost immune to the effects of cold."},
+
+ {"You are immune to electric shocks.", "You are immune to electric shocks.",
+ "You are immune to electric shocks."},
+
+ {"Your natural rate of healing is unusually fast.",
+ "You heal very quickly.",
+ "You regenerate."},
+
+ {"You have a fast metabolism.", "You have a very fast metabolism.",
+ "Your metabolism is lightning-fast."},
+
+ {"You have a slow metabolism.", "You have a slow metabolism.",
+ "You need consume almost no food."},
+
+ {"You are weak (Str -", "", ""},
+ {"You are dopey (Int -", "", ""},
+// 20
+ {"You are clumsy (Dex -", "", ""},
+
+ {"You can control translocations.", "You can control translocations.",
+ "You can control translocations."},
+
+ {"Space occasionally distorts in your vicinity.",
+ "Space sometimes distorts in your vicinity.",
+ "Space frequently distorts in your vicinity."},
+
+ {"You are resistant to magic.", "You are highly resistant to magic.",
+ "You are extremely resistant to the effects of magic."},
+
+ {"You cover the ground quickly.", "You cover the ground very quickly.",
+ "You cover the ground extremely quickly."},
+
+ {"You have supernaturally acute eyesight.",
+ "You have supernaturally acute eyesight.",
+ "You have supernaturally acute eyesight."},
+
+ {"Armour fits poorly on your deformed body.",
+ "Armour fits poorly on your badly deformed body.",
+ "Armour fits poorly on your hideously deformed body."},
+
+ {"You can teleport at will.", "You are good at teleporting at will.",
+ "You can teleport instantly at will."},
+
+ {"You can spit poison.", "You can spit poison.", "You can spit poison."},
+
+ {"You can sense your immediate surroundings.",
+ "You can sense your surroundings.",
+ "You can sense a large area of your surroundings."},
+
+// 30
+
+ {"You can breathe flames.", "You can breathe fire.",
+ "You can breathe blasts of fire."},
+
+ {"You can translocate small distances instantaneously.",
+ "You can translocate small distances instantaneously.",
+ "You can translocate small distances instantaneously."},
+
+ {"You have a pair of small horns on your head.",
+ "You have a pair of horns on your head.",
+ "You have a pair of large horns on your head."},
+
+ {"Your muscles are strong (Str +1), but stiff (Dex -1).",
+ "Your muscles are very strong (Str +2), but stiff (Dex -2).",
+ "Your muscles are extremely strong (Str +3), but stiff (Dex -3)."},
+
+ {"Your muscles are flexible (Dex +1), but weak (Str -1).",
+ "Your muscles are very flexible (Dex +2), but weak (Str -2).",
+ "Your muscles are extremely flexible (Dex +3), but weak (Str -3)."},
+
+ {"You occasionally forget where you are.",
+ "You sometimes forget where you are.",
+ "You frequently forget where you are."},
+
+ {"You possess an exceptional clarity of mind.",
+ "You possess an unnatural clarity of mind.",
+ "You possess a supernatural clarity of mind."},
+
+ {"You tend to lose your temper in combat.",
+ "You often lose your temper in combat.",
+ "You have an uncontrollable temper."},
+
+ {"Your body is slowly deteriorating.", "Your body is deteriorating.",
+ "Your body is rapidly deteriorating."},
+
+ {"Your vision is a little blurry.", "Your vision is quite blurry.",
+ "Your vision is extremely blurry."},
+// 40
+
+ {"You are somewhat resistant to further mutation.",
+ "You are somewhat resistant to both further mutation and mutation removal.",
+ "Your current mutations are irrevocably fixed, and you can mutate no more."},
+
+ {"You are frail (-10 percent hp).", "You are very frail (-20 percent hp).",
+ "You are extremely frail (-30 percent hp)."},
+
+ {"You are robust (+10 percent hp).",
+ "You are very robust (+20 percent hp).",
+ "You are extremely robust (+30 percent hp)."},
+
+ {"You are immune to unholy pain and torment.", "", ""},
+
+ {"You resist negative energy.",
+ "You are quite resistant to negative energy.",
+ "You are immune to negative energy."},
+
+ /* Use player_has_spell() to avoid duplication */
+ {"You can summon minor demons to your aid.", "", ""},
+ {"You can summon demons to your aid.", "", ""},
+ {"You can hurl blasts of hellfire.", "", ""},
+ {"You can call on the torments of Hell.", "", ""},
+ {"You can raise the dead to walk for you.", "", ""},
+// 50
+ {"You can control demons.", "", ""},
+ {"You can travel to (but not from) Pandemonium at will.", "", ""},
+ {"You can draw strength from death and destruction.", "", ""},
+
+ /* Not worshippers of Vehumet */
+ {"You can channel magical energy from Hell.", "", ""},
+
+ {"You can drain life in unarmed combat.", "", ""},
+
+ /* Not conjurers/worshippers of Makhleb */
+ {"You can throw forth the flames of Gehenna.", "", ""},
+
+ {"You can throw forth the frost of Cocytus.", "", ""},
+
+ {"You can invoke the powers of Tartarus to smite your living foes.", "", ""},
+ {"You have sharp fingernails.", "Your fingernails are very sharp.",
+ "You have claws for hands."},
+
+ {"You have hooves in place of feet.", "", ""},
+ // 60 - leave some space for more demonic powers...
+ {"You can exhale a cloud of poison.", "", ""},
+
+ {"Your tail ends in a poisonous barb.",
+ "Your tail ends in a sharp poisonous barb.",
+ "Your tail ends in a wicked poisonous barb."}, //jmf: nagas & dracos
+
+ {"Your wings are large and strong.", "", ""}, //jmf: dracos only
+
+ //jmf: these next two are for evil gods to mark their followers; good gods
+ // will never accept a 'marked' worhsipper
+
+ {"There is a blue sigil on each of your hands.",
+ "There are several blue sigils on your hands and arms.",
+ "Your hands, arms and shoulders are covered in intricate, arcane blue writing."},
+
+ {"There is a green sigil on your chest.",
+ "There are several green sigils on your chest and abdomen.",
+ "Your chest, abdomen and neck are covered in intricate, arcane green writing."},
+
+ {"", "", ""},
+ {"", "", ""},
+ {"", "", ""},
+ {"", "", ""},
+ {"", "", ""},
+ // 70
+
+ {"You are partially covered in red scales (AC + 1).",
+ "You are mostly covered in red scales (AC + 2).",
+ "You are covered in red scales (AC + 4)."},
+
+ {"You are partially covered in smooth nacreous scales (AC + 1).",
+ "You are mostly covered in smooth nacreous scales (AC + 3).",
+ "You are completely covered in smooth nacreous scales (AC + 5)."},
+
+ {"You are partially covered in ridged grey scales (AC + 2, dex - 1).",
+ "You are mostly covered in ridged grey scales (AC + 4, dex - 1).",
+ "You are completely covered in ridged grey scales (AC + 6, dex - 2)."},
+
+ {"You are partially covered in metallic scales (AC + 3, dex - 2).",
+ "You are mostly covered in metallic scales (AC + 7, dex - 3).",
+ "You are completely covered in metallic scales (AC + 10, dex - 4)."},
+
+ {"You are partially covered in black scales (AC + 1).",
+ "You are mostly covered in black scales (AC + 3).",
+ "You are completely covered in black scales (AC + 5)."},
+
+ {"You are partially covered in white scales (AC + 1).",
+ "You are mostly covered in white scales (AC + 3).",
+ "You are completely covered in white scales (AC + 5)."},
+
+ {"You are partially covered in yellow scales (AC + 2).",
+ "You are mostly covered in yellow scales (AC + 4, dex - 1).",
+ "You are completely covered in yellow scales (AC + 6, dex - 2)."},
+
+ {"You are partially covered in brown scales (AC + 2).",
+ "You are mostly covered in brown scales (AC + 4).",
+ "You are completely covered in brown scales (AC + 5)."},
+
+ {"You are partially covered in blue scales (AC + 1).",
+ "You are mostly covered in blue scales (AC + 2).",
+ "You are completely covered in blue scales (AC + 3)."},
+
+ {"You are partially covered in purple scales (AC + 2).",
+ "You are mostly covered in purple scales (AC + 4).",
+ "You are completely covered in purple scales (AC + 6)."},
+
+// 80
+
+ {"You are partially covered in speckled scales (AC + 1).",
+ "You are mostly covered in speckled scales (AC + 2).",
+ "You are covered in speckled scales (AC + 3)."},
+
+ {"You are partially covered in orange scales (AC + 1).",
+ "You are mostly covered in orange scales (AC + 3).",
+ "You are completely covered in orange scales (AC + 4)."},
+
+ {"You are partially covered in indigo scales (AC + 2).",
+ "You are mostly covered in indigo scales (AC + 3).",
+ "You are completely covered in indigo scales (AC + 5)."},
+
+ {"You are partially covered in knobbly red scales (AC + 2).",
+ "You are mostly covered in knobbly red scales (AC + 5, dex - 1).",
+ "You are completely covered in knobbly red scales (AC + 7, dex - 2)."},
+
+ {"You are partially covered in iridescent scales (AC + 1).",
+ "You are mostly covered in iridescent scales (AC + 2).",
+ "You are completely covered in iridescent scales (AC + 3)."},
+
+ {"You are partially covered in patterned scales (AC + 1).",
+ "You are mostly covered in patterned scales (AC + 2).",
+ "You are completely covered in patterned scales (AC + 3)."},
+};
+
+/*
+ If giving a mutation which must succeed (eg demonspawn), must add exception
+ to the "resist mutation" mutation thing.
+ */
+
+const char *gain_mutation[][3] = {
+ {"Your skin toughens.", "Your skin toughens.", "Your skin toughens."},
+
+ {"", "", ""}, // replaced with player::modify_stat() handling {dlb}
+ {"", "", ""}, // replaced with player::modify_stat() handling {dlb}
+ {"", "", ""}, // replaced with player::modify_stat() handling {dlb}
+
+ {"Green scales grow over part of your body.",
+ "Green scales spread over more of your body.",
+ "Green scales cover you completely."},
+
+ {"Thick black scales grow over part of your body.",
+ "Thick black scales spread over more of your body.",
+ "Thick black scales cover you completely."},
+
+ {"Supple grey scales grow over part of your body.",
+ "Supple grey scales spread over more of your body.",
+ "Supple grey scales cover you completely."},
+
+ {"You grow protective plates of bone.",
+ "You grow more protective plates of bone.",
+ "You grow more protective plates of bone."},
+
+ {"You begin to radiate repulsive energy.",
+ "Your repulsive radiation grows stronger.",
+ "Your repulsive radiation grows stronger."},
+
+ {"You feel healthy.", "You feel healthy.", "You feel healthy."},
+// 10
+ {"You hunger for flesh.", "You hunger for flesh.", "You hunger for flesh."},
+
+ {"You hunger for vegetation.", "You hunger for vegetation.",
+ "You hunger for vegetation."},
+
+ {"You feel a sudden chill.", "You feel a sudden chill.",
+ "You feel a sudden chill."},
+
+ {"You feel hot for a moment.", "You feel hot for a moment.",
+ "You feel hot for a moment."},
+
+ {"You feel insulated.", "You feel insulated.", "You feel insulated."},
+
+ {"You begin to heal more quickly.",
+ "You begin to heal more quickly.",
+ "You begin to regenerate."},
+
+ {"You feel a little hungry.", "You feel a little hungry.",
+ "You feel a little hungry."},
+
+ {"Your metabolism slows.", "Your metabolism slows.",
+ "Your metabolism slows."},
+
+ {"You feel weaker.", "You feel weaker.", "You feel weaker."},
+
+ {"You feel less intelligent.", "You feel less intelligent",
+ "You feel less intelligent"},
+// 20
+ {"You feel clumsy.", "You feel clumsy.",
+ "You feel clumsy."},
+
+ {"You feel controlled.", "You feel controlled.",
+ "You feel controlled."},
+
+ {"You feel weirdly uncertain.",
+ "You feel even more weirdly uncertain.",
+ "You feel even more weirdly uncertain."},
+
+ {"You feel resistant to magic.",
+ "You feel more resistant to magic.",
+ "You feel almost impervious to the effects of magic."},
+
+ {"You feel quick.", "You feel quick.", "You feel quick."},
+
+ {"Your vision sharpens.", "Your vision sharpens.", "Your vision sharpens."},
+
+ {"Your body twists and deforms.", "Your body twists and deforms.",
+ "Your body twists and deforms."},
+
+ {"You feel jumpy.", "You feel more jumpy.", "You feel even more jumpy."},
+
+ {"There is a nasty taste in your mouth for a moment.",
+ "There is a nasty taste in your mouth for a moment.",
+ "There is a nasty taste in your mouth for a moment."},
+
+ {"You feel aware of your surroundings.",
+ "You feel more aware of your surroundings.",
+ "You feel even more aware of your surroundings."},
+// 30
+
+ {"Your throat feels hot.", "Your throat feels hot.",
+ "Your throat feels hot."},
+
+ {"You feel a little jumpy.", "You feel more jumpy.",
+ "You feel even more jumpy."},
+
+ {"A pair of horns grows on your head!",
+ "The horns on your head grow some more.",
+ "The horns on your head grow some more."},
+
+ {"Your muscles feel sore.", "Your muscles feel sore.",
+ "Your muscles feel sore."},
+
+ {"Your muscles feel loose.", "Your muscles feel loose.",
+ "Your muscles feel loose."},
+
+ {"You feel a little disoriented.", "You feel a little disoriented.",
+ "Where the Hells are you?"},
+
+ {"Your thoughts seem clearer.", "Your thoughts seem clearer.",
+ "Your thoughts seem clearer."},
+
+ {"You feel a little pissed off.", "You feel angry.",
+ "You feel extremely angry at everything!"},
+
+ {"You feel yourself wasting away.", "You feel yourself wasting away.",
+ "You feel your body start to fall apart."},
+
+ {"Your vision blurs.", "Your vision blurs.", "Your vision blurs."},
+// 40
+
+ {"You feel genetically stable.", "You feel genetically stable.",
+ "You feel genetically immutable."},
+
+ {"You feel frail.", "You feel frail.", "You feel frail."},
+ {"You feel robust.", "You feel robust.", "You feel robust."},
+ {"You feel a strange anaesthesia.", "", ""},
+ {"You feel negative.", "You feel negative.", "You feel negative."},
+ {"A thousand chattering voices call out to you.", "", ""},
+ {"Help is not far away!", "", ""},
+ {"You smell fire and brimstone.", "", ""},
+ {"You feel a terrifying power at your call.", "", ""},
+ {"You feel an affinity for the dead.", "", ""},
+// 50
+ {"You feel an affinity for all demonkind.", "", ""},
+ {"You feel something pulling you to a strange and terrible place.", "", ""},
+ {"You feel hungry for death.", "", ""},
+ {"You feel a flux of magical energy.", "", ""},
+ {"Your skin tingles in a strangely unpleasant way.", "", ""},
+ {"You smell the fires of Gehenna.", "", ""},
+ {"You feel the icy cold of Cocytus chill your soul.", "", ""},
+ {"A shadow passes over the world around you.", "", ""},
+
+ {"Your fingernails lengthen.", "Your fingernails sharpen.",
+ "Your hands twist into claws."},
+
+ {"Your feet shrivel into cloven hooves.", "", ""},
+ // 60
+
+ {"You taste something nasty.", "You taste something very nasty.",
+ "You taste something extremely nasty."},
+
+ {"A poisonous barb forms on the end of your tail.",
+ "The barb on your tail looks sharper.",
+ "The barb on your tail looks very sharp."},
+
+ {"Your wings grow larger and stronger.", "", ""},
+
+ {"Your hands itch.", "Your hands and forearms itch.",
+ "Your arms, hands and shoulders itch."},
+
+ {"Your chest itches.", "Your chest and abdomen itch.",
+ "Your chest, abdomen and neck itch."},
+
+ {"", "", ""},
+ {"", "", ""},
+ {"", "", ""},
+ {"", "", ""},
+ {"", "", ""},
+ // 70
+
+ {"Red scales grow over part of your body.",
+ "Red scales spread over more of your body.",
+ "Red scales cover you completely."},
+ {"Smooth nacreous scales grow over part of your body.",
+ "Smooth nacreous scales spread over more of your body.",
+ "Smooth nacreous scales cover you completely."},
+ {"Ridged grey scales grow over part of your body.",
+ "Ridged grey scales spread over more of your body.",
+ "Ridged grey scales cover you completely."},
+ {"Metallic scales grow over part of your body.",
+ "Metallic scales spread over more of your body.",
+ "Metallic scales cover you completely."},
+ {"Black scales grow over part of your body.",
+ "Black scales spread over more of your body.",
+ "Black scales cover you completely."},
+ {"White scales grow over part of your body.",
+ "White scales spread over more of your body.",
+ "White scales cover you completely."},
+ {"Yellow scales grow over part of your body.",
+ "Yellow scales spread over more of your body.",
+ "Yellow scales cover you completely."},
+ {"Brown scales grow over part of your body.",
+ "Brown scales spread over more of your body.",
+ "Brown scales cover you completely."},
+ {"Blue scales grow over part of your body.",
+ "Blue scales spread over more of your body.",
+ "Blue scales cover you completely."},
+ {"Purple scales grow over part of your body.",
+ "Purple scales spread over more of your body.",
+ "Purple scales cover you completely."},
+ // 80
+
+ {"Speckled scales grow over part of your body.",
+ "Speckled scales spread over more of your body.",
+ "Speckled scales cover you completely."},
+ {"Orange scales grow over part of your body.",
+ "Orange scales spread over more of your body.",
+ "Orange scales cover you completely."},
+ {"Indigo scales grow over part of your body.",
+ "Indigo scales spread over more of your body.",
+ "Indigo scales cover you completely."},
+ {"Knobbly red scales grow over part of your body.",
+ "Knobbly red scales spread over more of your body.",
+ "Knobbly red scales cover you completely."},
+ {"Iridescent scales grow over part of your body.",
+ "Iridescent scales spread over more of your body.",
+ "Iridescent scales cover you completely."},
+ {"Patterned scales grow over part of your body.",
+ "Patterned scales spread over more of your body.",
+ "Patterned scales cover you completely."},
+};
+
+const char *lose_mutation[][3] = {
+
+ {"Your skin feels delicate.", "Your skin feels delicate.",
+ "Your skin feels delicate."},
+
+ {"You feel weaker.", "You feel weaker.", "You feel weaker."},
+
+ {"You feel less intelligent.", "You feel less intelligent",
+ "You feel less intelligent"},
+
+ {"You feel clumsy.", "You feel clumsy.", "You feel clumsy."},
+
+ {"Your green scales disappear.",
+ "Your green scales recede somewhat.",
+ "Your green scales recede somewhat."},
+
+ {"Your black scales disappear.", "Your black scales recede somewhat.",
+ "Your black scales recede somewhat."},
+
+ {"Your grey scales disappear.", "Your grey scales recede somewhat.",
+ "Your grey scales recede somewhat."},
+
+ {"Your bony plates shrink away.", "Your bony plates shrink.",
+ "Your bony plates shrink."},
+
+ {"You feel attractive.", "You feel attractive.", "You feel attractive."},
+
+ {"You feel a little less healthy.", "You feel a little less healthy.",
+ "You feel a little less healthy."},
+
+ {"You feel able to eat a more balanced diet.",
+ "You feel able to eat a more balanced diet.",
+ "You feel able to eat a more balanced diet."},
+
+ {"You feel able to eat a more balanced diet.",
+ "You feel able to eat a more balanced diet.",
+ "You feel able to eat a more balanced diet."},
+
+ {"You feel hot for a moment.", "You feel hot for a moment.",
+ "You feel hot for a moment."},
+
+ {"You feel a sudden chill.", "You feel a sudden chill.",
+ "You feel a sudden chill."},
+
+ {"You feel conductive.", "You feel conductive.", "You feel conductive."},
+
+ {"Your rate of healing slows.", "Your rate of healing slows.",
+ "Your rate of healing slows."},
+
+ {"Your metabolism slows.", "Your metabolism slows.",
+ "Your metabolism slows."},
+
+ {"You feel a little hungry.", "You feel a little hungry.",
+ "You feel a little hungry."},
+
+ {"", "", ""}, // replaced with player::modify_stat() handling {dlb}
+ {"", "", ""}, // replaced with player::modify_stat() handling {dlb}
+// 20
+ {"", "", ""}, // replaced with player::modify_stat() handling {dlb}
+
+ {"You feel random.", "You feel uncontrolled.", "You feel uncontrolled."},
+ {"You feel stable.", "You feel stable.", "You feel stable."},
+
+ {"You feel less resistant to magic.", "You feel less resistant to magic.",
+ "You feel vulnerable to magic again."},
+
+ {"You feel sluggish.", "You feel sluggish.", "You feel sluggish."},
+
+ {"Your vision seems duller.", "Your vision seems duller.",
+ "Your vision seems duller."},
+
+ {"Your body's shape seems more normal.",
+ "Your body's shape seems slightly more normal.",
+ "Your body's shape seems slightly more normal."},
+
+ {"You feel static.", "You feel less jumpy.", "You feel less jumpy."},
+
+ {"You feel an ache in your throat.",
+ "You feel an ache in your throat.", "You feel an ache in your throat."},
+
+ {"You feel slightly disorientated.", "You feel slightly disorientated.",
+ "You feel slightly disorientated."},
+// 30
+
+ {"A chill runs up and down your throat.",
+ "A chill runs up and down your throat.",
+ "A chill runs up and down your throat."},
+
+ {"You feel a little less jumpy.", "You feel less jumpy.",
+ "You feel less jumpy."},
+
+ {"The horns on your head shrink away.",
+ "The horns on your head shrink a bit.",
+ "The horns on your head shrink a bit."},
+
+ {"Your muscles feel loose.", "Your muscles feel loose.",
+ "Your muscles feel loose."},
+
+ {"Your muscles feel sore.", "Your muscles feel sore.",
+ "Your muscles feel sore."},
+
+ {"You feel less disoriented.", "You feel less disoriented.",
+ "You feel less disoriented."},
+
+ {"Your thinking seems confused.", "Your thinking seems confused.",
+ "Your thinking seems confused."},
+
+ {"You feel a little more calm.", "You feel a little less angry.",
+ "You feel a little less angry."},
+
+ {"You feel healthier.", "You feel a little healthier.",
+ "You feel a little healthier."},
+
+ {"Your vision sharpens.", "Your vision sharpens a little.",
+ "Your vision sharpens a little."},
+// 40
+
+ {"You feel genetically unstable.", "You feel genetically unstable.",
+ "You feel genetically unstable."},
+
+ {"You feel robust.", "You feel robust.", "You feel robust."},
+ {"You feel frail.", "You feel frail.", "You feel frail."},
+
+/* Some demonic powers (which can't be lost) start here... */
+ {"", "", ""},
+ {"", "", ""},
+ {"", "", ""},
+ {"", "", ""},
+ {"", "", ""},
+ {"", "", ""},
+ {"", "", ""},
+// 50
+ {"", "", ""},
+ {"", "", ""},
+ {"", "", ""},
+ {"", "", ""},
+ {"", "", ""},
+ {"", "", ""},
+ {"", "", ""},
+ {"", "", ""},
+
+ {"Your fingernails shrink to normal size.",
+ "Your fingernails look duller.", "Your hands feel fleshier."},
+
+ {"Your hooves expand and flesh out into feet!", "", ""},
+ // 60
+ {"", "", ""},
+ {"", "", ""},
+ {"", "", ""},
+ {"", "", ""},
+ {"", "", ""},
+ {"", "", ""},
+ {"", "", ""},
+ {"", "", ""},
+ {"", "", ""},
+ {"", "", ""},
+// 70
+
+ {"Your red scales disappear.", "Your red scales recede somewhat.",
+ "Your red scales recede somewhat."},
+
+ {"Your smooth nacreous scales disappear.",
+ "Your smooth nacreous scales recede somewhat.",
+ "Your smooth nacreous scales recede somewhat."},
+
+ {"Your ridged grey scales disappear.",
+ "Your ridged grey scales recede somewhat.",
+ "Your ridged grey scales recede somewhat."},
+
+ {"Your metallic scales disappear.",
+ "Your metallic scales recede somewhat.",
+ "Your metallic scales recede somewhat."},
+
+ {"Your black scales disappear.", "Your black scales recede somewhat.",
+ "Your black scales recede somewhat."},
+
+ {"Your white scales disappear.", "Your white scales recede somewhat.",
+ "Your white scales recede somewhat."},
+
+ {"Your yellow scales disappear.", "Your yellow scales recede somewhat.",
+ "Your yellow scales recede somewhat."},
+
+ {"Your brown scales disappear.", "Your brown scales recede somewhat.",
+ "Your brown scales recede somewhat."},
+
+ {"Your blue scales disappear.", "Your blue scales recede somewhat.",
+ "Your blue scales recede somewhat."},
+
+ {"Your purple scales disappear.", "Your purple scales recede somewhat.",
+ "Your purple scales recede somewhat."},
+// 80
+
+ {"Your speckled scales disappear.",
+ "Your speckled scales recede somewhat.",
+ "Your speckled scales recede somewhat."},
+
+ {"Your orange scales disappear.", "Your orange scales recede somewhat.",
+ "Your orange scales recede somewhat."},
+
+ {"Your indigo scales disappear.", "Your indigo scales recede somewhat.",
+ "Your indigo scales recede somewhat."},
+
+ {"Your knobbly red scales disappear.",
+ "Your knobbly red scales recede somewhat.",
+ "Your knobbly red scales recede somewhat."},
+
+ {"Your iridescent scales disappear.",
+ "Your iridescent scales recede somewhat.",
+ "Your iridescent scales recede somewhat."},
+
+ {"Your patterned scales disappear.",
+ "Your patterned scales recede somewhat.",
+ "Your patterned scales recede somewhat."},
+};
+
+/*
+ Chance out of 10 that mutation will be given/removed randomly. 0 means never.
+ */
+const char mutation_rarity[] = {
+ 10, // tough skin
+ 8, // str
+ 8, // int
+ 8, // dex
+ 2, // gr scales
+ 1, // bl scales
+ 2, // grey scales
+ 1, // bone
+ 1, // repuls field
+ 4, // res poison
+// 10
+ 5, // carn
+ 5, // herb
+ 4, // res fire
+ 4, // res cold
+ 2, // res elec
+ 3, // regen
+ 10, // fast meta
+ 7, // slow meta
+ 10, // abil loss
+ 10, // ""
+// 20
+ 10, // ""
+ 2, // tele control
+ 3, // teleport
+ 5, // res magic
+ 1, // run
+ 2, // see invis
+ 8, // deformation
+ 2, // teleport at will
+ 8, // spit poison
+ 3, // sense surr
+// 30
+ 4, // breathe fire
+ 3, // blink
+ 7, // horns
+ 10, // strong/stiff muscles
+ 10, // weak/loose muscles
+ 6, // forgetfulness
+ 6, // clarity (as the amulet)
+ 7, // berserk/temper
+ 10, // deterioration
+ 10, // blurred vision
+// 40
+ 4, // resist mutation
+ 10, // frail
+ 5, // robust
+/* Some demonic powers start here: */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+// 50
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2, //jmf: claws
+ 1, //jmf: hooves
+// 60
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+// 70
+ 2, // red scales
+ 1, // nac scales
+ 2, // r-grey scales
+ 1, // metal scales
+ 2, // black scales
+ 2, // wh scales
+ 2, // yel scales
+ 2, // brown scales
+ 2, // blue scales
+ 2, // purple scales
+// 80
+ 2, // speckled scales
+ 2, // orange scales
+ 2, // indigo scales
+ 1, // kn red scales
+ 1, // irid scales
+ 1, // pattern scales
+ 0, //
+ 0, //
+ 0, //
+ 0 //
+};
+
+void display_mutations(void)
+{
+ int i;
+ int j = 0;
+ const char *mut_title = "Innate abilities, Weirdness & Mutations";
+ const int num_lines = get_number_of_lines();
+
+#ifdef DOS_TERM
+ char buffer[4800];
+
+ window(1, 1, 80, 25);
+ gettext(1, 1, 80, 25, buffer);
+#endif
+
+ clrscr();
+ textcolor(WHITE);
+
+ // center title
+ i = 40 - strlen(mut_title) / 2;
+ if (i<1) i=1;
+ gotoxy(i, 1);
+ cprintf(mut_title);
+ gotoxy(1,3);
+ textcolor(LIGHTBLUE); //textcolor for inborn abilities and weirdness
+
+ switch (you.species) //mv: following code shows innate abilities - if any
+ {
+ case SP_MERFOLK:
+ cprintf("You revert to your normal form in water." EOL);
+ j++;
+ break;
+
+ case SP_NAGA:
+ // breathe poison replaces spit poison:
+ if (!you.mutation[MUT_BREATHE_POISON])
+ cprintf("You can spit poison." EOL);
+ else
+ cprintf("You can exhale a cloud of poison." EOL);
+
+ cprintf("Your system is immune to poisons." EOL);
+ cprintf("You can see invisible." EOL);
+ j += 3;
+ break;
+
+ case SP_GNOME:
+ cprintf("You can sense your surroundings." EOL);
+ j++;
+ break;
+
+ case SP_TROLL:
+ cprintf("Your body regenerates quickly." EOL);
+ j++;
+ break;
+
+ case SP_GHOUL:
+ cprintf("Your body is rotting away." EOL);
+ cprintf("You are carnivorous." EOL);
+ j += 2;
+ break;
+
+ case SP_KOBOLD:
+ cprintf("You are carnivorous." EOL);
+ j++;
+ break;
+
+ case SP_GREY_ELF:
+ if (you.experience_level > 4)
+ {
+ cprintf("You are very charming." EOL);
+ j++;
+ }
+ break;
+
+ case SP_KENKU:
+ if (you.experience_level > 4)
+ {
+ cprintf("You can fly");
+ cprintf((you.experience_level > 14) ? " continuously." EOL : "."
+ EOL);
+ j++;
+ }
+ break;
+
+ case SP_MUMMY:
+ cprintf("You are");
+ cprintf((you.experience_level > 25) ? " very strongly" :
+ ((you.experience_level > 12) ? " strongly" : ""));
+ cprintf(" in touch with the powers of death." EOL);
+ j++;
+
+ if (you.experience_level >= 12)
+ {
+ cprintf("You can restore your body by infusing magical energy." EOL);
+ j++;
+ }
+ break;
+
+ case SP_GREEN_DRACONIAN:
+ if (you.experience_level > 6)
+ {
+ cprintf("You are resistant to poison." EOL);
+ cprintf("You can breathe poison." EOL);
+ j += 2;
+ }
+ break;
+
+ case SP_RED_DRACONIAN:
+ if (you.experience_level > 6)
+ {
+ cprintf("You can breathe fire." EOL);
+ j++;
+ }
+ if (you.experience_level > 17)
+ {
+ cprintf("You are resistant to fire." EOL);
+ j++;
+ }
+ break;
+
+ case SP_WHITE_DRACONIAN:
+ if (you.experience_level > 6)
+ {
+ cprintf("You can breathe frost." EOL);
+ j++;
+ }
+ if (you.experience_level > 17)
+ {
+ cprintf("You are resistant to cold." EOL);
+ j++;
+ }
+ break;
+
+ case SP_BLACK_DRACONIAN:
+ if (you.experience_level > 6)
+ {
+ cprintf("You can breathe lightning." EOL);
+ j++;
+ }
+ if (you.experience_level > 17)
+ {
+ cprintf("You are resistant to lightning." EOL);
+ j++;
+ }
+ break;
+
+ case SP_GOLDEN_DRACONIAN:
+ if (you.experience_level > 6)
+ {
+ cprintf("You can spit acid." EOL);
+ j++;
+ }
+ break;
+
+ case SP_PURPLE_DRACONIAN:
+ if (you.experience_level > 6)
+ {
+ cprintf("You can breathe power." EOL);
+ j++;
+ }
+ break;
+
+ case SP_MOTTLED_DRACONIAN:
+ if (you.experience_level > 6)
+ {
+ cprintf("You can breathe sticky flames." EOL);
+ j++;
+ }
+ break;
+
+ case SP_PALE_DRACONIAN:
+ if (you.experience_level > 6)
+ {
+ cprintf("You can breathe steam." EOL);
+ j++;
+ }
+ break;
+ } //end switch - innate abilities
+
+ textcolor(LIGHTGREY);
+
+ for (i = 0; i < 100; i++)
+ {
+ if (you.mutation[i] != 0)
+ {
+ // this is already handled above:
+ if (you.species == SP_NAGA && i == MUT_BREATHE_POISON)
+ continue;
+
+ j++;
+ textcolor(LIGHTGREY);
+
+ if (j > num_lines - 4)
+ {
+ gotoxy( 1, num_lines - 1 );
+ cprintf("-more-");
+
+ if (getch() == 0)
+ getch();
+
+ clrscr();
+
+ // center title
+ int x = 40 - strlen(mut_title) / 2;
+ if (x < 1)
+ x = 1;
+
+ gotoxy(x, 1);
+ textcolor(WHITE);
+ cprintf(mut_title);
+ textcolor(LIGHTGREY);
+ gotoxy(1,3);
+ j = 1;
+ }
+
+ /* mutation is actually a demonic power */
+ if (you.demon_pow[i] != 0)
+ textcolor(RED);
+
+ /* same as above, but power is enhanced by mutation */
+ if (you.demon_pow[i] != 0 && you.demon_pow[i] < you.mutation[i])
+ textcolor(LIGHTRED);
+
+ cprintf( mutation_name( i ) );
+ cprintf(EOL);
+ }
+ }
+
+ if (j == 0)
+ cprintf( "You are not a mutant." EOL );
+
+ if (getch() == 0)
+ getch();
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+#endif
+
+ //cprintf("xxxxxxxxxxxxx");
+ //last_requested = 0;
+
+ return;
+} // end display_mutations()
+
+bool mutate(int which_mutation, bool failMsg)
+{
+ char mutat = which_mutation;
+ bool force_mutation = false; // is mutation forced?
+ int i;
+
+ if (which_mutation >= 1000) // must give mutation without failure
+ {
+ force_mutation = true;
+ mutat -= 1000;
+ which_mutation -= 1000;
+ }
+
+ // Undead bodies don't mutate, they fall apart. -- bwr
+ if (you.is_undead)
+ {
+ if (force_mutation
+ || (wearing_amulet(AMU_RESIST_MUTATION) && coinflip()))
+ {
+ mpr( "Your body decomposes!" );
+
+ if (coinflip())
+ lose_stat( STAT_RANDOM, 1 );
+ else
+ {
+ ouch( 3, 0, KILLED_BY_ROTTING );
+ rot_hp( roll_dice( 1, 3 ) );
+ }
+
+ return (true);
+ }
+
+ if (failMsg)
+ mpr("You feel odd for a moment.");
+
+ return (false);
+ }
+
+ if (wearing_amulet(AMU_RESIST_MUTATION)
+ && !force_mutation && !one_chance_in(10))
+ {
+ if (failMsg)
+ mpr("You feel odd for a moment.");
+
+ return (false);
+ }
+
+ if (you.mutation[MUT_MUTATION_RESISTANCE]
+ && !force_mutation
+ && (you.mutation[MUT_MUTATION_RESISTANCE] == 3 || !one_chance_in(3)))
+ {
+ if (failMsg)
+ mpr("You feel odd for a moment.");
+
+ return (false);
+ }
+
+ if (which_mutation == 100 && random2(15) < how_mutated())
+ {
+ if (!force_mutation && !one_chance_in(3))
+ return (false);
+ else
+ return (delete_mutation(100));
+ }
+
+ if (which_mutation == 100)
+ {
+ do
+ {
+ mutat = random2(NUM_MUTATIONS);
+
+ if (one_chance_in(1000))
+ return false;
+ }
+ while ((you.mutation[mutat] >= 3
+ && (mutat != MUT_STRONG && mutat != MUT_CLEVER
+ && mutat != MUT_AGILE) && (mutat != MUT_WEAK
+ && mutat != MUT_DOPEY
+ && mutat != MUT_CLUMSY))
+ || you.mutation[mutat] > 13
+ || random2(10) >= mutation_rarity[mutat] + you.demon_pow[mutat]);
+ }
+
+ if (you.mutation[mutat] >= 3
+ && (mutat != MUT_STRONG && mutat != MUT_CLEVER && mutat != MUT_AGILE)
+ && (mutat != MUT_WEAK && mutat != MUT_DOPEY && mutat != MUT_CLUMSY))
+ {
+ return false;
+ }
+
+ if (you.mutation[mutat] > 13 && !force_mutation)
+ return false;
+
+ // These can be forced by demonspawn
+ if ((mutat == MUT_TOUGH_SKIN
+ || (mutat >= MUT_GREEN_SCALES && mutat <= MUT_BONEY_PLATES)
+ || (mutat >= MUT_RED_SCALES && mutat <= MUT_PATTERNED_SCALES))
+ && body_covered() >= 3 && !force_mutation)
+ {
+ return false;
+ }
+
+ if (mutat == MUT_HORNS && you.species == SP_MINOTAUR)
+ return false;
+
+ // nagas have see invis and res poison and can spit poison
+ if (you.species == SP_NAGA)
+ {
+ if (mutat == MUT_ACUTE_VISION || mutat == MUT_POISON_RESISTANCE)
+ return false;
+
+ // gdl: spit poison 'upgrades' to breathe poison. Why not..
+ if (mutat == MUT_SPIT_POISON)
+ {
+ if (coinflip())
+ return false;
+ {
+ mutat = MUT_BREATHE_POISON;
+
+ // breathe poison replaces spit poison (so it takes the slot)
+ for (i = 0; i < 52; i++)
+ {
+ if (you.ability_letter_table[i] == ABIL_SPIT_POISON)
+ you.ability_letter_table[i] = ABIL_BREATHE_POISON;
+ }
+ }
+ }
+ }
+
+ // gnomes can already sense surroundings
+ if (you.species == SP_GNOME && mutat == MUT_MAPPING)
+ return false;
+
+ // spriggans already run at max speed (centaurs can get a bit faster)
+ if (you.species == SP_SPRIGGAN && mutat == MUT_FAST)
+ return false;
+
+ // this might have issues if we allowed it -- bwr
+ if (you.species == SP_KOBOLD
+ && (mutat == MUT_CARNIVOROUS || mutat == MUT_HERBIVOROUS))
+ {
+ return (false);
+ }
+
+ // This one can be forced by demonspawn
+ if (mutat == MUT_REGENERATION
+ && you.mutation[MUT_SLOW_METABOLISM] > 0 && !force_mutation)
+ {
+ return false; /* if you have a slow metabolism, no regen */
+ }
+
+ if (mutat == MUT_SLOW_METABOLISM && you.mutation[MUT_REGENERATION] > 0)
+ return false; /* if you have a slow metabolism, no regen */
+
+ // This one can be forced by demonspawn
+ if (mutat == MUT_ACUTE_VISION
+ && you.mutation[MUT_BLURRY_VISION] > 0 && !force_mutation)
+ {
+ return false;
+ }
+
+ if (mutat == MUT_BLURRY_VISION && you.mutation[MUT_ACUTE_VISION] > 0)
+ return false; /* blurred vision/see invis */
+
+ //jmf: added some checks for new mutations
+ if (mutat == MUT_STINGER
+ && !(you.species == SP_NAGA || player_genus(GENPC_DRACONIAN)))
+ {
+ return false;
+ }
+
+ // putting boots on after they are forced off. -- bwr
+ if (mutat == MUT_HOOVES
+ && (you.species == SP_NAGA || you.species == SP_CENTAUR
+ || you.species == SP_KENKU || player_genus(GENPC_DRACONIAN)))
+ {
+ return false;
+ }
+
+ if (mutat == MUT_BIG_WINGS && !player_genus(GENPC_DRACONIAN))
+ return false;
+
+ //jmf: added some checks for new mutations
+ mpr("You mutate.", MSGCH_MUTATION);
+
+ // find where these things are actually changed
+ // -- do not globally force redraw {dlb}
+ you.redraw_hit_points = 1;
+ you.redraw_magic_points = 1;
+ you.redraw_armour_class = 1;
+ you.redraw_evasion = 1;
+ you.redraw_experience = 1;
+ you.redraw_gold = 1;
+ //you.redraw_hunger = 1;
+
+ switch (mutat)
+ {
+ case MUT_STRONG:
+ if (you.mutation[MUT_WEAK] > 0)
+ {
+ delete_mutation(MUT_WEAK);
+ return true;
+ }
+ // replaces earlier, redundant code - 12mar2000 {dlb}
+ modify_stat(STAT_STRENGTH, 1, false);
+ break;
+
+ case MUT_CLEVER:
+ if (you.mutation[MUT_DOPEY] > 0)
+ {
+ delete_mutation(MUT_DOPEY);
+ return true;
+ }
+ // replaces earlier, redundant code - 12mar2000 {dlb}
+ modify_stat(STAT_INTELLIGENCE, 1, false);
+ break;
+
+ case MUT_AGILE:
+ if (you.mutation[MUT_CLUMSY] > 0)
+ {
+ delete_mutation(MUT_CLUMSY);
+ return true;
+ }
+ // replaces earlier, redundant code - 12mar2000 {dlb}
+ modify_stat(STAT_DEXTERITY, 1, false);
+ break;
+
+ case MUT_WEAK:
+ if (you.mutation[MUT_STRONG] > 0)
+ {
+ delete_mutation(MUT_STRONG);
+ return true;
+ }
+ modify_stat(STAT_STRENGTH, -1, true);
+ mpr(gain_mutation[mutat][0], MSGCH_MUTATION);
+ break;
+
+ case MUT_DOPEY:
+ if (you.mutation[MUT_CLEVER] > 0)
+ {
+ delete_mutation(MUT_CLEVER);
+ return true;
+ }
+ modify_stat(STAT_INTELLIGENCE, -1, true);
+ mpr(gain_mutation[mutat][0], MSGCH_MUTATION);
+ break;
+
+ case MUT_CLUMSY:
+ if (you.mutation[MUT_AGILE] > 0)
+ {
+ delete_mutation(MUT_AGILE);
+ return true;
+ }
+ modify_stat(STAT_DEXTERITY, -1, true);
+ mpr(gain_mutation[mutat][0], MSGCH_MUTATION);
+ break;
+
+ case MUT_REGENERATION:
+ if (you.mutation[MUT_SLOW_METABOLISM] > 0)
+ {
+ // Should only get here from demonspawn, where our innate
+ // ability will clear away the counter-mutation.
+ while (delete_mutation(MUT_SLOW_METABOLISM))
+ ;
+ }
+ mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION);
+ break;
+
+ case MUT_ACUTE_VISION:
+ if (you.mutation[MUT_BLURRY_VISION] > 0)
+ {
+ // Should only get here from demonspawn, where our inate
+ // ability will clear away the counter-mutation.
+ while (delete_mutation(MUT_BLURRY_VISION))
+ ;
+ }
+ mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION);
+ break;
+
+ case MUT_CARNIVOROUS:
+ if (you.mutation[MUT_HERBIVOROUS] > 0)
+ {
+ delete_mutation(MUT_HERBIVOROUS);
+ return true;
+ }
+ mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION);
+ break;
+
+ case MUT_HERBIVOROUS:
+ if (you.mutation[MUT_CARNIVOROUS] > 0)
+ {
+ delete_mutation(MUT_CARNIVOROUS);
+ return true;
+ }
+ mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION);
+ break;
+
+ case MUT_SHOCK_RESISTANCE:
+ mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION);
+ break;
+
+ case MUT_FAST_METABOLISM:
+ if (you.mutation[MUT_SLOW_METABOLISM] > 0)
+ {
+ delete_mutation(MUT_SLOW_METABOLISM);
+ return true;
+ }
+ mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION);
+ break;
+
+ case MUT_SLOW_METABOLISM:
+ if (you.mutation[MUT_FAST_METABOLISM] > 0)
+ {
+ delete_mutation(MUT_FAST_METABOLISM);
+ return true;
+ }
+ //if (you.mutation[mutat] == 0 || you.mutation[mutat] == 2)
+ mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION);
+ break;
+
+ case MUT_TELEPORT_CONTROL:
+ you.attribute[ATTR_CONTROL_TELEPORT]++;
+ mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION);
+ break;
+
+
+ case MUT_HOOVES: //jmf: like horns
+ mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION);
+ if (you.equip[EQ_BOOTS] != -1)
+ {
+ FixedVector < char, 8 > removed;
+
+ for (int i = EQ_WEAPON; i < EQ_RIGHT_RING; i++)
+ {
+ removed[i] = 0;
+ }
+
+ removed[EQ_BOOTS] = 1;
+ remove_equipment(removed);
+ }
+ break;
+
+ case MUT_CLAWS:
+ mpr( gain_mutation[ mutat ][ you.mutation[mutat] ], MSGCH_MUTATION );
+
+ // gloves aren't prevented until level three
+ if (you.mutation[ mutat ] >= 3 && you.equip[ EQ_GLOVES ] != -1)
+ {
+ FixedVector < char, 8 > removed;
+
+ for (int i = EQ_WEAPON; i < EQ_RIGHT_RING; i++)
+ {
+ removed[i] = 0;
+ }
+
+ removed[ EQ_GLOVES ] = 1;
+ remove_equipment( removed );
+ }
+ break;
+
+ case MUT_HORNS: // horns force your helmet off
+ {
+ mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION);
+
+ if (you.equip[EQ_HELMET] != -1
+ && you.inv[you.equip[EQ_HELMET]].plus2 > 1)
+ {
+ break; // horns don't push caps/wizard hats off
+ }
+
+ FixedVector < char, 8 > removed;
+
+ for (int i = EQ_WEAPON; i < EQ_RIGHT_RING; i++)
+ {
+ removed[i] = 0;
+ }
+
+ removed[EQ_HELMET] = 1;
+ remove_equipment(removed);
+ }
+ break;
+
+ case MUT_STRONG_STIFF:
+ if (you.mutation[MUT_FLEXIBLE_WEAK] > 0)
+ {
+ delete_mutation(MUT_FLEXIBLE_WEAK);
+ return true;
+ }
+ modify_stat(STAT_STRENGTH, 1, true);
+ modify_stat(STAT_DEXTERITY, -1, true);
+ mpr(gain_mutation[mutat][0], MSGCH_MUTATION);
+ break;
+
+ case MUT_FLEXIBLE_WEAK:
+ if (you.mutation[MUT_STRONG_STIFF] > 0)
+ {
+ delete_mutation(MUT_STRONG_STIFF);
+ return true;
+ }
+ modify_stat(STAT_STRENGTH, -1, true);
+ modify_stat(STAT_DEXTERITY, 1, true);
+ mpr(gain_mutation[mutat][0], MSGCH_MUTATION);
+ break;
+
+ case MUT_FRAIL:
+ if (you.mutation[MUT_ROBUST] > 0)
+ {
+ delete_mutation(MUT_ROBUST);
+ return true;
+ }
+ mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION);
+ you.mutation[mutat]++;
+ calc_hp();
+ return true;
+
+ case MUT_ROBUST:
+ if (you.mutation[MUT_FRAIL] > 0)
+ {
+ delete_mutation(MUT_FRAIL);
+ return true;
+ }
+ mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION);
+ you.mutation[mutat]++;
+ calc_hp();
+ return true;
+
+ case MUT_BLACK_SCALES:
+ case MUT_BONEY_PLATES:
+ modify_stat(STAT_DEXTERITY, -1, true);
+ // deliberate fall-through
+ default:
+ mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION);
+ break;
+
+ case MUT_GREY2_SCALES:
+ if (you.mutation[mutat] != 1)
+ modify_stat(STAT_DEXTERITY, -1, true);
+
+ mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION);
+ break;
+
+ case MUT_METALLIC_SCALES:
+ if (you.mutation[mutat] == 0)
+ modify_stat(STAT_DEXTERITY, -2, true);
+ else
+ modify_stat(STAT_DEXTERITY, -1, true);
+
+ mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION);
+ break;
+
+ case MUT_RED2_SCALES:
+ case MUT_YELLOW_SCALES:
+ if (you.mutation[mutat] != 0)
+ modify_stat(STAT_DEXTERITY, -1, true);
+
+ mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION);
+ break;
+ }
+
+ you.mutation[mutat]++;
+
+ /* remember, some mutations don't get this far (eg frail) */
+ return true;
+} // end mutation()
+
+int how_mutated(void)
+{
+ int j = 0;
+
+ for (int i = 0; i < 100; i++)
+ {
+ if (you.mutation[i] && you.demon_pow[i] < you.mutation[i])
+ {
+ // these allow for 14 levels:
+ if (i == MUT_STRONG || i == MUT_CLEVER || i == MUT_AGILE
+ || i == MUT_WEAK || i == MUT_DOPEY || i == MUT_CLUMSY)
+ {
+ j += (you.mutation[i] / 5 + 1);
+ }
+ else
+ {
+ j += you.mutation[i];
+ }
+ }
+ }
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "levels: %d", j );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ return (j);
+} // end how_mutated()
+
+bool delete_mutation(char which_mutation)
+{
+ char mutat = which_mutation;
+ int i;
+
+ if (you.mutation[MUT_MUTATION_RESISTANCE] > 1
+ && (you.mutation[MUT_MUTATION_RESISTANCE] == 3 || coinflip()))
+ {
+ mpr("You feel rather odd for a moment.");
+ return false;
+ }
+
+ if (which_mutation == 100)
+ {
+ do
+ {
+ mutat = random2(NUM_MUTATIONS);
+ if (one_chance_in(1000))
+ return false;
+ }
+ while ((you.mutation[mutat] == 0
+ && (mutat != MUT_STRONG && mutat != MUT_CLEVER && mutat != MUT_AGILE)
+ && (mutat != MUT_WEAK && mutat != MUT_DOPEY && mutat != MUT_CLUMSY))
+ || random2(10) >= mutation_rarity[mutat]
+ || you.demon_pow[mutat] >= you.mutation[mutat]);
+ }
+
+ if (you.mutation[mutat] == 0)
+ return false;
+
+ if (you.demon_pow[mutat] >= you.mutation[mutat])
+ return false;
+
+ mpr("You mutate.", MSGCH_MUTATION);
+
+ switch (mutat)
+ {
+ case MUT_STRONG:
+ modify_stat(STAT_STRENGTH, -1, true);
+ mpr(lose_mutation[mutat][0], MSGCH_MUTATION);
+ break;
+
+ case MUT_CLEVER:
+ modify_stat(STAT_INTELLIGENCE, -1, true);
+ mpr(lose_mutation[mutat][0], MSGCH_MUTATION);
+ break;
+
+ case MUT_AGILE:
+ modify_stat(STAT_DEXTERITY, -1, true);
+ mpr(lose_mutation[mutat][0], MSGCH_MUTATION);
+ break;
+
+ case MUT_WEAK:
+ modify_stat(STAT_STRENGTH, 1, false);
+ break;
+
+ case MUT_DOPEY:
+ modify_stat(STAT_INTELLIGENCE, 1, false);
+ break;
+
+ case MUT_CLUMSY:
+ // replaces earlier, redundant code - 12mar2000 {dlb}
+ modify_stat(STAT_DEXTERITY, 1, false);
+ break;
+
+ case MUT_SHOCK_RESISTANCE:
+ mpr(lose_mutation[mutat][you.mutation[mutat] - 1], MSGCH_MUTATION);
+ break;
+
+ case MUT_FAST_METABOLISM:
+ mpr(lose_mutation[mutat][you.mutation[mutat] - 1], MSGCH_MUTATION);
+ break;
+
+ case MUT_SLOW_METABOLISM:
+ mpr(lose_mutation[mutat][you.mutation[mutat] - 1], MSGCH_MUTATION);
+ break;
+
+ case MUT_TELEPORT_CONTROL:
+ you.attribute[ATTR_CONTROL_TELEPORT]--;
+ mpr(lose_mutation[mutat][you.mutation[mutat] - 1], MSGCH_MUTATION);
+ break;
+
+ case MUT_STRONG_STIFF:
+ modify_stat(STAT_STRENGTH, -1, true);
+ modify_stat(STAT_DEXTERITY, 1, true);
+ mpr(lose_mutation[mutat][0], MSGCH_MUTATION);
+ break;
+
+ case MUT_FLEXIBLE_WEAK:
+ modify_stat(STAT_STRENGTH, 1, true);
+ modify_stat(STAT_DEXTERITY, -1, true);
+ mpr(lose_mutation[mutat][0], MSGCH_MUTATION);
+ break;
+
+ case MUT_FRAIL:
+ mpr(lose_mutation[mutat][0], MSGCH_MUTATION);
+ if (you.mutation[mutat] > 0)
+ you.mutation[mutat]--;
+ calc_hp();
+ return true;
+
+ case MUT_ROBUST:
+ mpr(lose_mutation[mutat][0], MSGCH_MUTATION);
+ if (you.mutation[mutat] > 0)
+ you.mutation[mutat]--;
+ calc_hp();
+ return true;
+
+ case MUT_BLACK_SCALES:
+ case MUT_BONEY_PLATES:
+ modify_stat(STAT_DEXTERITY, 1, true);
+
+ default:
+ mpr(lose_mutation[mutat][you.mutation[mutat] - 1], MSGCH_MUTATION);
+ break;
+
+ case MUT_GREY2_SCALES:
+ if (you.mutation[mutat] != 2)
+ modify_stat(STAT_DEXTERITY, 1, true);
+ mpr(lose_mutation[mutat][you.mutation[mutat] - 1], MSGCH_MUTATION);
+ break;
+
+ case MUT_METALLIC_SCALES:
+ if (you.mutation[mutat] == 1)
+ modify_stat(STAT_DEXTERITY, 2, true);
+ else
+ modify_stat(STAT_DEXTERITY, 1, true);
+
+ mpr(lose_mutation[mutat][you.mutation[mutat] - 1], MSGCH_MUTATION);
+ break;
+
+ case MUT_RED2_SCALES:
+ case MUT_YELLOW_SCALES:
+ if (you.mutation[mutat] != 1)
+ modify_stat(STAT_DEXTERITY, 1, true);
+
+ mpr(lose_mutation[mutat][you.mutation[mutat] - 1], MSGCH_MUTATION);
+ break;
+
+ case MUT_BREATHE_POISON:
+ // can't be removed yet, but still covered:
+ if (you.species == SP_NAGA)
+ {
+ // natural ability to spit poison retakes the slot
+ for (i = 0; i < 52; i++)
+ {
+ if (you.ability_letter_table[i] == ABIL_BREATHE_POISON)
+ you.ability_letter_table[i] = ABIL_SPIT_POISON;
+ }
+ }
+ break;
+ }
+
+ // find where these things are actually altered
+ /// -- do not globally force redraw {dlb}
+ you.redraw_hit_points = 1;
+ you.redraw_magic_points = 1;
+ you.redraw_armour_class = 1;
+ you.redraw_evasion = 1;
+ you.redraw_experience = 1;
+ you.redraw_gold = 1;
+ //you.redraw_hunger = 1;
+
+ if (you.mutation[mutat] > 0)
+ you.mutation[mutat]--;
+
+ return true;
+} // end delete_mutation()
+
+char body_covered(void)
+{
+ /* checks how much of your body is covered by scales etc */
+ char covered = 0;
+
+ if (you.species == SP_NAGA)
+ covered++;
+
+ if (player_genus(GENPC_DRACONIAN))
+ return 3;
+
+ covered += you.mutation[MUT_TOUGH_SKIN];
+ covered += you.mutation[MUT_GREEN_SCALES];
+ covered += you.mutation[MUT_BLACK_SCALES];
+ covered += you.mutation[MUT_GREY_SCALES];
+ covered += you.mutation[MUT_BONEY_PLATES];
+ covered += you.mutation[MUT_RED_SCALES];
+ covered += you.mutation[MUT_NACREOUS_SCALES];
+ covered += you.mutation[MUT_GREY2_SCALES];
+ covered += you.mutation[MUT_METALLIC_SCALES];
+ covered += you.mutation[MUT_BLACK2_SCALES];
+ covered += you.mutation[MUT_WHITE_SCALES];
+ covered += you.mutation[MUT_YELLOW_SCALES];
+ covered += you.mutation[MUT_BROWN_SCALES];
+ covered += you.mutation[MUT_BLUE_SCALES];
+ covered += you.mutation[MUT_PURPLE_SCALES];
+ covered += you.mutation[MUT_SPECKLED_SCALES];
+ covered += you.mutation[MUT_ORANGE_SCALES];
+ covered += you.mutation[MUT_INDIGO_SCALES];
+ covered += you.mutation[MUT_RED2_SCALES];
+ covered += you.mutation[MUT_IRIDESCENT_SCALES];
+ covered += you.mutation[MUT_PATTERNED_SCALES];
+
+ return covered;
+}
+
+const char *mutation_name( char which_mutat, int level )
+{
+ static char mut_string[INFO_SIZE];
+
+ // level == -1 means default action of current level
+ if (level == -1)
+ level = you.mutation[ which_mutat ];
+
+ if (which_mutat == MUT_STRONG || which_mutat == MUT_CLEVER
+ || which_mutat == MUT_AGILE || which_mutat == MUT_WEAK
+ || which_mutat == MUT_DOPEY || which_mutat == MUT_CLUMSY)
+ {
+ snprintf( mut_string, sizeof( mut_string ), "%s%d).",
+ mutation_descrip[ which_mutat ][0], level );
+
+ return (mut_string);
+ }
+
+ // Some mutations only have one "level", and it's better
+ // to show the first level description than a blank description.
+ if (mutation_descrip[ which_mutat ][ level - 1 ][0] == '\0')
+ return (mutation_descrip[ which_mutat ][ 0 ]);
+ else
+ return (mutation_descrip[ which_mutat ][ level - 1 ]);
+} // end mutation_name()
+
+/* Use an attribute counter for how many demonic mutations a dspawn has */
+void demonspawn(void)
+{
+ int whichm = -1;
+ char howm = 1;
+ int counter = 0;
+
+ const int scale_levels = body_covered();
+
+ you.attribute[ATTR_NUM_DEMONIC_POWERS]++;
+
+ mpr("Your demonic ancestry asserts itself...", MSGCH_INTRINSIC_GAIN);
+
+ // Merged the demonspawn lists into a single loop. Now a high level
+ // character can potentially get mutations from the low level list if
+ // its having trouble with the high level list.
+ do
+ {
+ if (you.experience_level >= 10)
+ {
+ if (you.skills[SK_CONJURATIONS] < 5)
+ { // good conjurers don't get bolt of draining
+ whichm = MUT_SMITE;
+ howm = 1;
+ }
+
+ if (you.skills[SK_CONJURATIONS] < 10 && one_chance_in(4))
+ { // good conjurers don't get hellfire
+ whichm = MUT_HURL_HELLFIRE;
+ howm = 1;
+ }
+
+ if (you.skills[SK_SUMMONINGS] < 5 && one_chance_in(3))
+ { // good summoners don't get summon demon
+ whichm = MUT_SUMMON_DEMONS;
+ howm = 1;
+ }
+
+ if (one_chance_in(8))
+ {
+ whichm = MUT_MAGIC_RESISTANCE;
+ howm = (coinflip() ? 2 : 3);
+ }
+
+ if (one_chance_in(12))
+ {
+ whichm = MUT_FAST;
+ howm = 1;
+ }
+
+ if (one_chance_in(7))
+ {
+ whichm = MUT_TELEPORT_AT_WILL;
+ howm = 2;
+ }
+
+ if (one_chance_in(10))
+ {
+ whichm = MUT_REGENERATION;
+ howm = (coinflip() ? 2 : 3);
+ }
+
+ if (one_chance_in(12))
+ {
+ whichm = MUT_SHOCK_RESISTANCE;
+ howm = 1;
+ }
+
+ if (!you.mutation[MUT_CALL_TORMENT] && one_chance_in(15))
+ {
+ whichm = MUT_TORMENT_RESISTANCE;
+ howm = 1;
+ }
+
+ if (one_chance_in(12))
+ {
+ whichm = MUT_NEGATIVE_ENERGY_RESISTANCE;
+ howm = 1 + random2(3);
+ }
+
+ if (!you.mutation[MUT_TORMENT_RESISTANCE] && one_chance_in(20))
+ {
+ whichm = MUT_CALL_TORMENT;
+ howm = 1;
+ }
+
+ if (you.skills[SK_SUMMONINGS] < 5 && you.skills[SK_NECROMANCY] < 5
+ && one_chance_in(12))
+ {
+ whichm = MUT_CONTROL_DEMONS;
+ howm = 1;
+ }
+
+ if (you.skills[SK_TRANSLOCATIONS] < 5 && one_chance_in(15))
+ {
+ whichm = MUT_PANDEMONIUM;
+ howm = 1;
+ }
+
+ if (you.religion != GOD_VEHUMET && one_chance_in(11))
+ {
+ whichm = MUT_DEATH_STRENGTH;
+ howm = 1;
+ }
+
+ if (you.religion != GOD_VEHUMET && one_chance_in(11))
+ {
+ whichm = MUT_CHANNEL_HELL;
+ howm = 1;
+ }
+
+ if (you.skills[SK_SUMMONINGS] < 3 && you.skills[SK_NECROMANCY] < 3
+ && one_chance_in(10))
+ {
+ whichm = MUT_RAISE_DEAD;
+ howm = 1;
+ }
+
+ if (you.skills[SK_UNARMED_COMBAT] > 5 && one_chance_in(14))
+ {
+ whichm = MUT_DRAIN_LIFE;
+ howm = 1;
+ }
+ }
+
+ // check here so we can see if we need to extent our options:
+ if (whichm != -1 && you.mutation[whichm] != 0)
+ whichm = -1;
+
+ if (you.experience_level < 10 || (counter > 0 && whichm == -1))
+ {
+ if ((!you.mutation[MUT_THROW_FROST] // only one of these
+ && !you.mutation[MUT_THROW_FLAMES]
+ && !you.mutation[MUT_BREATHE_FLAMES])
+ && (!you.skills[SK_CONJURATIONS] // conjurers seldomly
+ || one_chance_in(5))
+ && (!you.skills[SK_ICE_MAGIC] // already ice & fire?
+ || !you.skills[SK_FIRE_MAGIC]))
+ {
+ // try to give the flavour the character doesn't have:
+ if (!you.skills[SK_FIRE_MAGIC])
+ whichm = MUT_THROW_FLAMES;
+ else if (!you.skills[SK_ICE_MAGIC])
+ whichm = MUT_THROW_FROST;
+ else
+ whichm = (coinflip() ? MUT_THROW_FLAMES : MUT_THROW_FROST);
+
+ howm = 1;
+ }
+
+ if (!you.skills[SK_SUMMONINGS] && one_chance_in(3))
+ { /* summoners don't get summon imp */
+ whichm = (you.experience_level < 10) ? MUT_SUMMON_MINOR_DEMONS
+ : MUT_SUMMON_DEMONS;
+ howm = 1;
+ }
+
+ if (one_chance_in(4))
+ {
+ whichm = MUT_POISON_RESISTANCE;
+ howm = 1;
+ }
+
+ if (one_chance_in(4))
+ {
+ whichm = MUT_COLD_RESISTANCE;
+ howm = 1;
+ }
+
+ if (one_chance_in(4))
+ {
+ whichm = MUT_HEAT_RESISTANCE;
+ howm = 1;
+ }
+
+ if (one_chance_in(5))
+ {
+ whichm = MUT_ACUTE_VISION;
+ howm = 1;
+ }
+
+ if (!you.skills[SK_POISON_MAGIC] && one_chance_in(7))
+ {
+ whichm = MUT_SPIT_POISON;
+ howm = (you.experience_level < 10) ? 1 : 3;
+ }
+
+ if (one_chance_in(10))
+ {
+ whichm = MUT_MAPPING;
+ howm = 3;
+ }
+
+ if (one_chance_in(12))
+ {
+ whichm = MUT_TELEPORT_CONTROL;
+ howm = 1;
+ }
+
+ if (!you.mutation[MUT_THROW_FROST] // not with these
+ && !you.mutation[MUT_THROW_FLAMES]
+ && !you.mutation[MUT_BREATHE_FLAMES]
+ && !you.skills[SK_FIRE_MAGIC] // or with fire already
+ && one_chance_in(5))
+ {
+ whichm = MUT_BREATHE_FLAMES;
+ howm = 2;
+ }
+
+ if (!you.skills[SK_TRANSLOCATIONS] && one_chance_in(12))
+ {
+ whichm = (you.experience_level < 10) ? MUT_BLINK
+ : MUT_TELEPORT_AT_WILL;
+ howm = 2;
+ }
+
+ if (scale_levels < 3 && one_chance_in( 1 + scale_levels * 5 ))
+ {
+ const int bonus = (you.experience_level < 10) ? 0 : 1;
+ int levels = 0;
+
+ if (one_chance_in(10))
+ {
+ whichm = MUT_TOUGH_SKIN;
+ levels = (coinflip() ? 2 : 3);
+ }
+
+ if (one_chance_in(24))
+ {
+ whichm = MUT_GREEN_SCALES;
+ levels = (coinflip() ? 2 : 3);
+ }
+
+ if (one_chance_in(24))
+ {
+ whichm = MUT_BLACK_SCALES;
+ levels = (coinflip() ? 2 : 3);
+ }
+
+ if (one_chance_in(24))
+ {
+ whichm = MUT_GREY_SCALES;
+ levels = (coinflip() ? 2 : 3);
+ }
+
+ if (one_chance_in(12))
+ {
+ whichm = MUT_RED_SCALES + random2(16);
+
+ switch (whichm)
+ {
+ case MUT_RED_SCALES:
+ case MUT_NACREOUS_SCALES:
+ case MUT_BLACK2_SCALES:
+ case MUT_WHITE_SCALES:
+ case MUT_BLUE_SCALES:
+ case MUT_SPECKLED_SCALES:
+ case MUT_ORANGE_SCALES:
+ case MUT_IRIDESCENT_SCALES:
+ case MUT_PATTERNED_SCALES:
+ levels = (coinflip() ? 2 : 3);
+ break;
+
+ default:
+ levels = (coinflip() ? 1 : 2);
+ break;
+ }
+ }
+
+ if (one_chance_in(30))
+ {
+ whichm = MUT_BONEY_PLATES;
+ levels = (coinflip() ? 1 : 2);
+ }
+
+ if (levels)
+ howm = MINIMUM( 3 - scale_levels, levels + bonus );
+ }
+
+ if (one_chance_in(25))
+ {
+ whichm = MUT_REPULSION_FIELD;
+ howm = (coinflip() ? 2 : 3);
+ }
+
+ if (one_chance_in( (you.experience_level < 10) ? 5 : 20 ))
+ {
+ whichm = MUT_HORNS;
+ howm = (coinflip() ? 1 : 2);
+
+ if (you.experience_level > 4 || one_chance_in(5))
+ howm++;
+ }
+ }
+
+ if (whichm != -1 && you.mutation[whichm] != 0)
+ whichm = -1;
+
+ counter++;
+ }
+ while (whichm == -1 && counter < 5000);
+
+ if (whichm == -1 || !perma_mutate( whichm, howm ))
+ {
+ /* unlikely but remotely possible */
+ /* I know this is a cop-out */
+ modify_stat(STAT_STRENGTH, 1, true);
+ modify_stat(STAT_INTELLIGENCE, 1, true);
+ modify_stat(STAT_DEXTERITY, 1, true);
+ mpr("You feel much better now.", MSGCH_INTRINSIC_GAIN);
+ }
+} // end demonspawn()
+
+bool perma_mutate(int which_mut, char how_much)
+{
+ char levels = 0;
+
+ if (mutate(which_mut + 1000))
+ levels++;
+
+ if (how_much >= 2 && mutate(which_mut + 1000))
+ levels++;
+
+ if (how_much >= 3 && mutate(which_mut + 1000))
+ levels++;
+
+ you.demon_pow[which_mut] = levels;
+
+ return (levels > 0);
+} // end perma_mutate()
+
+bool give_good_mutation(bool failMsg)
+{
+ int temp_rand = 0; // probability determination {dlb}
+ int which_good_one = 0;
+
+ temp_rand = random2(25);
+
+ which_good_one = ((temp_rand >= 24) ? MUT_TOUGH_SKIN :
+ (temp_rand == 23) ? MUT_STRONG :
+ (temp_rand == 22) ? MUT_CLEVER :
+ (temp_rand == 21) ? MUT_AGILE :
+ (temp_rand == 20) ? MUT_HEAT_RESISTANCE :
+ (temp_rand == 19) ? MUT_COLD_RESISTANCE :
+ (temp_rand == 18) ? MUT_SHOCK_RESISTANCE :
+ (temp_rand == 17) ? MUT_REGENERATION :
+ (temp_rand == 16) ? MUT_TELEPORT_CONTROL :
+ (temp_rand == 15) ? MUT_MAGIC_RESISTANCE :
+ (temp_rand == 14) ? MUT_FAST :
+ (temp_rand == 13) ? MUT_ACUTE_VISION :
+ (temp_rand == 12) ? MUT_GREEN_SCALES :
+ (temp_rand == 11) ? MUT_BLACK_SCALES :
+ (temp_rand == 10) ? MUT_GREY_SCALES :
+ (temp_rand == 9) ? MUT_BONEY_PLATES :
+ (temp_rand == 8) ? MUT_REPULSION_FIELD :
+ (temp_rand == 7) ? MUT_POISON_RESISTANCE :
+ (temp_rand == 6) ? MUT_TELEPORT_AT_WILL :
+ (temp_rand == 5) ? MUT_SPIT_POISON :
+ (temp_rand == 4) ? MUT_MAPPING :
+ (temp_rand == 3) ? MUT_BREATHE_FLAMES :
+ (temp_rand == 2) ? MUT_BLINK :
+ (temp_rand == 1) ? MUT_CLARITY
+ : MUT_ROBUST);
+
+ return (mutate(which_good_one, failMsg));
+} // end give_good_mutation()
+
+bool give_bad_mutation(bool forceMutation, bool failMsg)
+{
+ int temp_rand = 0; // probability determination {dlb}
+ int which_bad_one = 0;
+
+ temp_rand = random2(12);
+
+ which_bad_one = ((temp_rand >= 11) ? MUT_CARNIVOROUS :
+ (temp_rand == 10) ? MUT_HERBIVOROUS :
+ (temp_rand == 9) ? MUT_FAST_METABOLISM :
+ (temp_rand == 8) ? MUT_WEAK :
+ (temp_rand == 7) ? MUT_DOPEY :
+ (temp_rand == 6) ? MUT_CLUMSY :
+ (temp_rand == 5) ? MUT_TELEPORT :
+ (temp_rand == 4) ? MUT_DEFORMED :
+ (temp_rand == 3) ? MUT_LOST :
+ (temp_rand == 2) ? MUT_DETERIORATION :
+ (temp_rand == 1) ? MUT_BLURRY_VISION
+ : MUT_FRAIL);
+
+ if (forceMutation)
+ which_bad_one += 1000;
+
+ return (mutate(which_bad_one), failMsg);
+} // end give_bad_mutation()
+
+//jmf: might be useful somewhere (eg Xom or transmigration effect)
+bool give_cosmetic_mutation()
+{
+ int mutation = -1;
+ int how_much = 0;
+ int counter = 0;
+
+ do
+ {
+ mutation = MUT_DEFORMED;
+ how_much = 1 + random2(3);
+
+ if (one_chance_in(6))
+ {
+ mutation = MUT_ROBUST;
+ how_much = 1 + random2(3);
+ }
+
+ if (one_chance_in(6))
+ {
+ mutation = MUT_FRAIL;
+ how_much = 1 + random2(3);
+ }
+
+ if (one_chance_in(5))
+ {
+ mutation = MUT_TOUGH_SKIN;
+ how_much = 1 + random2(3);
+ }
+
+ if (one_chance_in(4))
+ {
+ mutation = MUT_CLAWS;
+ how_much = 1 + random2(3);
+ }
+
+ if (you.species != SP_CENTAUR && you.species != SP_NAGA
+ && you.species != SP_KENKU && !player_genus(GENPC_DRACONIAN)
+ && one_chance_in(5))
+ {
+ mutation = MUT_HOOVES;
+ how_much = 1;
+ }
+
+ if (player_genus(GENPC_DRACONIAN) && one_chance_in(5))
+ {
+ mutation = MUT_BIG_WINGS;
+ how_much = 1;
+ }
+
+ if (one_chance_in(5))
+ {
+ mutation = MUT_CARNIVOROUS;
+ how_much = 1 + random2(3);
+ }
+
+ if (one_chance_in(6))
+ {
+ mutation = MUT_HORNS;
+ how_much = 1 + random2(3);
+ }
+
+ if ((you.species == SP_NAGA || player_genus(GENPC_DRACONIAN))
+ && one_chance_in(4))
+ {
+ mutation = MUT_STINGER;
+ how_much = 1 + random2(3);
+ }
+
+ if (you.species == SP_NAGA && one_chance_in(6))
+ {
+ mutation = MUT_BREATHE_POISON;
+ how_much = 1;
+ }
+
+ if (!(you.species == SP_NAGA || player_genus(GENPC_DRACONIAN))
+ && one_chance_in(7))
+ {
+ mutation = MUT_SPIT_POISON;
+ how_much = 1;
+ }
+
+ if (!(you.species == SP_NAGA || player_genus(GENPC_DRACONIAN))
+ && one_chance_in(8))
+ {
+ mutation = MUT_BREATHE_FLAMES;
+ how_much = 1 + random2(3);
+ }
+
+ if (you.mutation[mutation] > 0)
+ how_much -= you.mutation[mutation];
+
+ if (how_much < 0)
+ how_much = 0;
+ }
+ while (how_much == 0 && counter++ < 5000);
+
+ if (how_much != 0)
+ return mutate(mutation);
+ else
+ return false;
+} // end give_cosmetic_mutation()
diff --git a/trunk/source/mutation.h b/trunk/source/mutation.h
new file mode 100644
index 0000000000..b305098d62
--- /dev/null
+++ b/trunk/source/mutation.h
@@ -0,0 +1,71 @@
+/*
+ * File: mutation.cc
+ * Summary: Functions for handling player mutations.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef MUTATION_H
+#define MUTATION_H
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - decks - effects - fight - food - it_use2 - items -
+ * mutation - religion - spell - spells
+ * *********************************************************************** */
+bool mutate(int which_mutation, bool failMsg = true);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void display_mutations(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: decks - it_use2 - mutation - spells
+ * *********************************************************************** */
+bool delete_mutation(char which_mutation);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: chardump
+ * *********************************************************************** */
+// default of level == -1, means to use the player's current level
+const char *mutation_name( char which_mutat, int level = -1 );
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: religion
+ * *********************************************************************** */
+bool give_good_mutation( bool failMsg = true );
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: items - religion
+ * *********************************************************************** */
+bool give_cosmetic_mutation( void );
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: items - spells
+ * *********************************************************************** */
+bool give_bad_mutation( bool forceMutation = false, bool failMsg = true );
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: player
+ * *********************************************************************** */
+void demonspawn(void);
+
+
+#endif
diff --git a/trunk/source/newgame.cc b/trunk/source/newgame.cc
new file mode 100644
index 0000000000..1bc895034f
--- /dev/null
+++ b/trunk/source/newgame.cc
@@ -0,0 +1,4430 @@
+/*
+ * File: newgame.cc
+ * Summary: Functions used when starting a new game.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <16> 19-Jun-2000 GDL changed handle to FILE *
+ * <15> 06-Mar-2000 bwr changes to berserer, paladin, enchanter
+ * <14> 10-Jan-2000 DLB class_allowed() lists excluded
+ * species for all but hunters
+ * some clean-up of init_player()
+ * <13> 1/10/2000 BCR Made ogre berserkers get club
+ * skill, Trolls get unarmed skill
+ * Halflings can be assasins and
+ * warpers
+ * <12> 12/4/99 jmf Gave Paladins more armour skill + a
+ * long sword (to compensate for
+ * their inability to use poison).
+ * Allowed Spriggan Stalkers (since
+ * that's basically just a venom mage
+ * + assassin, both of which are now
+ * legal).
+ * <11> 11/22/99 LRH Er, re-un-capitalised class
+ * names (makes them distinguish-
+ * able in score list)
+ * <10> 10/31/99 CDL Allow Spriggan Assassins
+ * Remove some old comments
+ * <9> 10/12/99 BCR Made sure all the classes are
+ * capitalized correctly.
+ * <8> 9/09/99 BWR Changed character selection
+ * screens look (added sub-species
+ * menus from Dustin Ragan)
+ * <7> 7/13/99 BWR Changed assassins to use
+ * hand crossbows, changed
+ * rangers into hunters.
+ * <6> 6/22/99 BWR Added new rangers/slingers
+ * <5> 6/17/99 BCR Removed some Linux/Mac filename
+ * weirdness
+ * <4> 6/13/99 BWR SysEnv support
+ * <3> 6/11/99 DML Removed tmpfile purging.
+ * <2> 5/20/99 BWR CRAWL_NAME, new berserk, upped
+ * troll food consumption, added
+ * demonspawn transmuters.
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "newgame.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#ifdef LINUX
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+
+#ifdef USE_EMX
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+
+#ifdef OS9
+#include <stat.h>
+#else
+#include <sys/stat.h>
+#endif
+
+#include "externs.h"
+
+#include "abl-show.h"
+#include "dungeon.h"
+#include "files.h"
+#include "fight.h"
+#include "itemname.h"
+#include "items.h"
+#include "macro.h"
+#include "player.h"
+#include "randart.h"
+#include "skills.h"
+#include "skills2.h"
+#include "spl-util.h"
+#include "stuff.h"
+#include "version.h"
+#include "wpn-misc.h"
+
+
+#define MIN_START_STAT 1
+
+bool class_allowed(unsigned char speci, int char_class);
+bool verifyPlayerName(void);
+void choose_weapon(void);
+void enterPlayerName(bool blankOK);
+void give_basic_knowledge(int which_job);
+void give_basic_spells(int which_job);
+void give_last_paycheck(int which_job);
+void init_player(void);
+void jobs_stat_init(int which_job);
+void openingScreen(void);
+void species_stat_init(unsigned char which_species);
+
+#if 0
+// currently unused -- bwr
+static void give_random_wand( int slot );
+static void give_random_scroll( int slot );
+#endif
+
+static void give_random_potion( int slot );
+static void give_random_secondary_armour( int slot );
+static bool give_wanderer_weapon( int slot, int wpn_skill );
+static void create_wanderer(void);
+static void give_items_skills(void);
+static bool choose_race(void);
+static bool choose_class(void);
+
+int give_first_conjuration_book()
+{
+ // Assume the fire/earth book, as conjurations is strong with fire -- bwr
+ int book = BOOK_CONJURATIONS_I;
+
+ // Conjuration books are largely Fire or Ice, so we'll use
+ // that as the primary condition, and air/earth to break ties. -- bwr
+ if (you.skills[SK_ICE_MAGIC] > you.skills[SK_FIRE_MAGIC]
+ || (you.skills[SK_FIRE_MAGIC] == you.skills[SK_ICE_MAGIC]
+ && you.skills[SK_AIR_MAGIC] > you.skills[SK_EARTH_MAGIC]))
+ {
+ book = BOOK_CONJURATIONS_II;
+ }
+ else if (you.skills[SK_FIRE_MAGIC] == 0 && you.skills[SK_EARTH_MAGIC] == 0)
+ {
+ // If we're here its because we were going to default to the
+ // fire/earth book... but we don't have those skills. So we
+ // choose randomly based on the species weighting, again
+ // ignoring air/earth which are secondary in these books. -- bwr
+ if (random2( species_skills( SK_ICE_MAGIC, you.species ) )
+ < random2( species_skills( SK_FIRE_MAGIC, you.species ) ))
+ {
+ book = BOOK_CONJURATIONS_II;
+ }
+ }
+
+ return (book);
+}
+
+static void pick_random_species_and_class( void )
+{
+ //
+ // We pick both species and class at the same time to give each
+ // valid possibility a fair chance. For proof that this will
+ // work correctly see the proof in religion.cc:handle_god_time().
+ //
+ int job_count = 0;
+
+ int species = -1;
+ int job = -1;
+
+ // for each valid (species, class) choose one randomly
+ for (int sp = SP_HUMAN; sp < NUM_SPECIES; sp++)
+ {
+ // we only want draconians counted once in this loop...
+ // we'll add the variety lower down -- bwr
+ if (sp >= SP_WHITE_DRACONIAN && sp <= SP_UNK2_DRACONIAN)
+ continue;
+
+ for (int cl = JOB_FIGHTER; cl < NUM_JOBS; cl++)
+ {
+ if (class_allowed(sp, cl))
+ {
+ job_count++;
+ if (one_chance_in( job_count ))
+ {
+ species = sp;
+ job = cl;
+ }
+ }
+ }
+ }
+
+ // at least one job must exist in the game else we're in big trouble
+ ASSERT( species != -1 && job != -1 );
+
+ // return draconian variety here
+ if (species == SP_RED_DRACONIAN)
+ you.species = SP_RED_DRACONIAN + random2(9);
+ else
+ you.species = species;
+
+ you.char_class = job;
+}
+
+static bool check_saved_game(void)
+{
+ FILE *handle;
+ char char_fil[kFileNameSize];
+
+#ifdef LOAD_UNPACKAGE_CMD
+ // Create the file name base
+ char name_buff[kFileNameLen];
+
+ snprintf( name_buff, sizeof(name_buff),
+ SAVE_DIR_PATH "%s%d", you.your_name, (int) getuid() );
+
+ char zip_buff[kFileNameLen];
+
+ strcpy(zip_buff, name_buff);
+ strcat(zip_buff, PACKAGE_SUFFIX);
+
+ // Create save dir name
+ strcpy(char_fil, name_buff);
+ strcat(char_fil, ".sav");
+
+ handle = fopen(zip_buff, "rb+");
+ if (handle != NULL)
+ {
+ cprintf(EOL "Loading game..." EOL);
+
+ // Create command
+ char cmd_buff[1024];
+
+ snprintf( cmd_buff, sizeof(cmd_buff), LOAD_UNPACKAGE_CMD, name_buff );
+
+ if (system( cmd_buff ) != 0)
+ {
+ cprintf( EOL "Warning: Zip command (LOAD_UNPACKAGE_CMD) returned non-zero value!" EOL );
+ }
+
+ fclose(handle);
+
+ // Remove save game package
+ unlink(zip_buff);
+ }
+ else
+ {
+#ifdef DO_ANTICHEAT_CHECKS
+ // Simple security patch -- must have zip file otherwise invalidate
+ // the character. Right now this just renames the .sav file to
+ // .bak, allowing anyone with the appropriate permissions to
+ // fix a character in the case of a bug. This could be changed
+ // to unlinking the file(s) which would remove the character.
+ strcat(name_buff, ".bak");
+ rename(char_fil, name_buff);
+#endif
+ }
+
+#else
+ strcpy(char_fil, "");
+ strncat(char_fil, you.your_name, kFileNameLen);
+ strcat(char_fil, ".sav");
+#endif
+
+ handle = fopen(char_fil, "rb+");
+
+ if (handle != NULL)
+ {
+ fclose(handle);
+ return true;
+ }
+ return false;
+}
+
+bool new_game(void)
+{
+ int i, j; // loop variables {dlb}
+
+ //jmf: NEW ASSERTS: we ought to do a *lot* of these
+ ASSERT(NUM_SPELLS < SPELL_NO_SPELL);
+ ASSERT(NUM_DURATIONS > DUR_LAST_DUR);
+ ASSERT(NUM_JOBS < JOB_UNKNOWN);
+ ASSERT(NUM_ATTRIBUTES < 30);
+
+ init_player();
+
+ you.exp_available = 25; // now why is this all the way up here? {dlb}
+
+ textcolor(LIGHTGREY);
+
+ // copy name into you.your_name if set from environment --
+ // note that you.your_name could already be set from init.txt
+ // this, clearly, will overwrite such information {dlb}
+ if (SysEnv.crawl_name)
+ {
+ strncpy( you.your_name, SysEnv.crawl_name, kNameLen );
+ you.your_name[ kNameLen - 1 ] = '\0';
+ }
+
+ openingScreen();
+ enterPlayerName(true);
+
+ if (you.your_name[0] != '\0')
+ {
+ if (check_saved_game())
+ {
+ textcolor( BROWN );
+ cprintf( EOL "Welcome back, " );
+ textcolor( YELLOW );
+ cprintf( you.your_name );
+ cprintf( "!" );
+ textcolor( LIGHTGREY );
+
+ return (false);
+ }
+ }
+
+ if (Options.random_pick)
+ {
+ pick_random_species_and_class();
+ }
+ else
+ {
+ bool keep_going = true;
+ while (keep_going)
+ {
+ if (choose_race())
+ keep_going = !choose_class();
+ else
+ keep_going = false;
+ }
+ }
+
+ strcpy( you.class_name, get_class_name( you.char_class ) );
+
+ // new: pick name _after_ race and class choices
+ if (you.your_name[0] == '\0')
+ {
+ clrscr();
+
+ char spec_buff[80];
+ strncpy(spec_buff, species_name(you.species, you.experience_level), 80);
+
+ snprintf( info, INFO_SIZE, "You are a%s %s %s." EOL,
+ (is_vowel( spec_buff[0] )) ? "n" : "", spec_buff,
+ you.class_name );
+
+ cprintf( info );
+
+ enterPlayerName(false);
+
+ if (check_saved_game())
+ {
+ cprintf(EOL "Do you really want to overwrite your old game?");
+ char c = getch();
+ if (!(c == 'Y' || c == 'y'))
+ {
+ textcolor( BROWN );
+ cprintf(EOL EOL "Welcome back, ");
+ textcolor( YELLOW );
+ cprintf(you.your_name);
+ cprintf("!");
+ textcolor( LIGHTGREY );
+
+ return (false);
+ }
+ }
+ }
+
+
+// ************ round-out character statistics and such ************
+
+ species_stat_init( you.species ); // must be down here {dlb}
+
+ you.is_undead = ((you.species == SP_MUMMY) ? US_UNDEAD :
+ (you.species == SP_GHOUL) ? US_HUNGRY_DEAD : US_ALIVE);
+
+ // before we get into the inventory init, set light radius based
+ // on species vision. currently, all species see out to 8 squares.
+ you.normal_vision = 8;
+ you.current_vision = 8;
+
+ jobs_stat_init( you.char_class );
+ give_last_paycheck( you.char_class );
+
+ // randomly boost stats a number of times based on species
+ // - should be a function {dlb}
+ unsigned char points_left = (you.species == SP_DEMIGOD
+ || you.species == SP_DEMONSPAWN) ? 15 : 8;
+
+ // first spend points to get us to the minimum allowed value -- bwr
+ if (you.strength < MIN_START_STAT)
+ {
+ points_left -= (MIN_START_STAT - you.strength);
+ you.strength = MIN_START_STAT;
+ }
+
+ if (you.intel < MIN_START_STAT)
+ {
+ points_left -= (MIN_START_STAT - you.intel);
+ you.intel = MIN_START_STAT;
+ }
+
+ if (you.dex < MIN_START_STAT)
+ {
+ points_left -= (MIN_START_STAT - you.dex);
+ you.dex = MIN_START_STAT;
+ }
+
+ // now randomly assign the remaining points --bwr
+ while (points_left > 0)
+ {
+ switch (random2( NUM_STATS ))
+ {
+ case STAT_STRENGTH:
+ if (you.strength > 17 && coinflip())
+ continue;
+
+ you.strength++;
+ break;
+
+ case STAT_DEXTERITY:
+ if (you.dex > 17 && coinflip())
+ continue;
+
+ you.dex++;
+ break;
+
+ case STAT_INTELLIGENCE:
+ if (you.intel > 17 && coinflip())
+ continue;
+
+ you.intel++;
+ break;
+ }
+
+ points_left--;
+ }
+
+ // this function depends on stats being finalized
+ give_items_skills();
+
+ // then: adjust hp_max by species {dlb}
+ if (player_genus(GENPC_DRACONIAN) || player_genus(GENPC_DWARVEN))
+ inc_max_hp(1);
+ else
+ {
+ switch (you.species)
+ {
+ case SP_CENTAUR:
+ case SP_OGRE:
+ case SP_TROLL:
+ inc_max_hp(3);
+ break;
+
+ case SP_GHOUL:
+ case SP_MINOTAUR:
+ case SP_NAGA:
+ case SP_OGRE_MAGE:
+ case SP_DEMIGOD:
+ inc_max_hp(2);
+ break;
+
+ case SP_HILL_ORC:
+ case SP_MUMMY:
+ case SP_MERFOLK:
+ inc_max_hp(1);
+ break;
+
+ case SP_ELF:
+ case SP_GREY_ELF:
+ case SP_HIGH_ELF:
+ dec_max_hp(1);
+ break;
+
+ case SP_DEEP_ELF:
+ case SP_GNOME:
+ case SP_HALFLING:
+ case SP_KENKU:
+ case SP_KOBOLD:
+ case SP_SPRIGGAN:
+ dec_max_hp(2);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // then: adjust max_magic_points by species {dlb}
+ switch (you.species)
+ {
+ case SP_SPRIGGAN:
+ case SP_DEMIGOD:
+ case SP_GREY_ELF:
+ case SP_DEEP_ELF:
+ inc_max_mp(1);
+ break;
+
+ default:
+ break;
+ }
+
+ // these need to be set above using functions!!! {dlb}
+ you.max_dex = you.dex;
+ you.max_strength = you.strength;
+ you.max_intel = you.intel;
+
+ if (!you.is_undead)
+ {
+ for (i = 0; i < ENDOFPACK; i++)
+ {
+ if (!you.inv[i].quantity)
+ {
+ you.inv[i].quantity = 1;
+ you.inv[i].base_type = OBJ_FOOD;
+ you.inv[i].sub_type = FOOD_BREAD_RATION;
+
+ if (you.species == SP_HILL_ORC || you.species == SP_KOBOLD
+ || you.species == SP_OGRE || you.species == SP_TROLL)
+ {
+ you.inv[i].sub_type = FOOD_MEAT_RATION;
+ }
+
+ you.inv[i].colour = BROWN;
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < ENDOFPACK; i++)
+ {
+ if (you.inv[i].quantity)
+ {
+ if (you.inv[i].base_type == OBJ_BOOKS)
+ {
+ you.had_book[you.inv[i].sub_type] = 1;
+ if (you.inv[i].sub_type == BOOK_MINOR_MAGIC_I
+ || you.inv[i].sub_type == BOOK_MINOR_MAGIC_II
+ || you.inv[i].sub_type == BOOK_MINOR_MAGIC_III)
+ {
+ you.had_book[BOOK_MINOR_MAGIC_I] = 1;
+ you.had_book[BOOK_MINOR_MAGIC_II] = 1;
+ you.had_book[BOOK_MINOR_MAGIC_III] = 1;
+ }
+ if (you.inv[i].sub_type == BOOK_CONJURATIONS_I
+ || you.inv[i].sub_type == BOOK_CONJURATIONS_II)
+ {
+ you.had_book[BOOK_CONJURATIONS_I] = 1;
+ you.had_book[BOOK_CONJURATIONS_II] = 1;
+ }
+ }
+
+ // don't change object type modifier unless it starts plain
+ if (you.inv[i].base_type <= OBJ_ARMOUR
+ && cmp_equip_race( you.inv[i], 0 )) // == DARM_PLAIN
+ {
+ // now add appropriate species type mod:
+ switch (you.species)
+ {
+ case SP_ELF:
+ case SP_HIGH_ELF:
+ case SP_GREY_ELF:
+ case SP_DEEP_ELF:
+ case SP_SLUDGE_ELF:
+ set_equip_race( you.inv[i], ISFLAG_ELVEN );
+ break;
+
+ case SP_HILL_DWARF:
+ case SP_MOUNTAIN_DWARF:
+ set_equip_race( you.inv[i], ISFLAG_DWARVEN );
+ if (you.inv[i].colour == LIGHTCYAN)
+ you.inv[i].colour = CYAN;
+ break;
+
+ case SP_HILL_ORC:
+ set_equip_race( you.inv[i], ISFLAG_ORCISH );
+ break;
+ }
+ }
+ }
+ }
+
+ // must remember to check for already existing colours/combinations
+ for (i = 0; i < 4; i++)
+ {
+ for (j = 0; j < 50; j++)
+ {
+ you.item_description[i][j] = 255;
+ }
+ }
+
+ you.item_description[IDESC_POTIONS][POT_PORRIDGE] = 153; // "gluggy white"
+ you.item_description[IDESC_POTIONS][POT_WATER] = 0; // "clear"
+
+ int passout;
+
+ for (i = 0; i < 4; i++)
+ {
+ for (j = 0; j < 50; j++)
+ {
+ if (you.item_description[i][j] != 255)
+ continue;
+
+ do
+ {
+ passout = 1;
+
+ switch (i)
+ {
+ case IDESC_WANDS: // wands
+ you.item_description[i][j] = random2( 16 * 12 );
+ if (coinflip())
+ you.item_description[i][j] %= 12;
+ break;
+
+ case IDESC_POTIONS: // potions
+ you.item_description[i][j] = random2( 15 * 14 );
+ if (coinflip())
+ you.item_description[i][j] %= 14;
+ break;
+
+ case IDESC_SCROLLS: // scrolls
+ you.item_description[i][j] = random2(151);
+ you.item_description[IDESC_SCROLLS_II][j] = random2(151);
+ break;
+
+ case IDESC_RINGS: // rings
+ you.item_description[i][j] = random2( 13 * 13 );
+ if (coinflip())
+ you.item_description[i][j] %= 13;
+ break;
+ }
+
+ // don't have p < j because some are preassigned
+ for (int p = 0; p < 50; p++)
+ {
+ if (you.item_description[i][p] == you.item_description[i][j]
+ && j != p)
+ {
+ passout = 0;
+ }
+ }
+ }
+ while (passout == 0);
+ }
+ }
+
+ for (i = 0; i < 50; i++)
+ {
+ if (!you.skills[i])
+ continue;
+
+ // Start with the amount of skill points required for a human...
+ const int points = skill_exp_needed( you.skills[i] + 1 );
+
+ you.skill_points[i] = points + 1;
+
+ if (i == SK_SPELLCASTING)
+ you.skill_points[i] = (points * 130) / 100 + 1;
+ else if (i == SK_INVOCATIONS || i == SK_EVOCATIONS)
+ you.skill_points[i] = (points * 75) / 100 + 1;
+
+ // ...and find out what level that earns this character.
+ const int sp_diff = species_skills( i, you.species );
+ you.skills[i] = 0;
+
+ for (int lvl = 1; lvl <= 8; lvl++)
+ {
+ if (you.skill_points[i] > (skill_exp_needed(lvl+1) * sp_diff) / 100)
+ you.skills[i] = lvl;
+ else
+ break;
+ }
+ }
+
+ calc_total_skill_points();
+
+ for (i = 0; i < ENDOFPACK; i++)
+ {
+ if (you.inv[i].base_type != OBJ_WEAPONS)
+ {
+ set_ident_type( you.inv[i].base_type,
+ you.inv[i].sub_type, ID_KNOWN_TYPE );
+ }
+
+ if (you.inv[i].base_type == OBJ_POTIONS
+ || you.inv[i].base_type == OBJ_WANDS
+ || you.inv[i].base_type == OBJ_JEWELLERY)
+ {
+ item_colour( you.inv[i] ); // set correct special and colour
+ }
+ }
+
+ // we calculate hp and mp here; all relevant factors should be
+ // finalized by now (GDL)
+ calc_hp();
+ calc_mp();
+
+ // make sure the starting player is fully charged up
+ set_hp( you.hp_max, false );
+ set_mp( you.max_magic_points, false );
+
+ give_basic_spells(you.char_class);
+ give_basic_knowledge(you.char_class);
+
+ // tmpfile purging removed in favour of marking
+ for (int lvl = 0; lvl < MAX_LEVELS; lvl++)
+ {
+ for (int dng = 0; dng < MAX_BRANCHES; dng++)
+ {
+ tmp_file_pairs[lvl][dng] = false;
+ }
+ }
+
+ // places staircases to the branch levels:
+ for (i = 0; i < 30; i++)
+ {
+ you.branch_stairs[i] = 100;
+ }
+
+ you.branch_stairs[STAIRS_ECUMENICAL_TEMPLE] = 3 + random2(4); // avg: 4.5
+
+ you.branch_stairs[STAIRS_ORCISH_MINES] = 5 + random2(6); // avg: 7.5
+
+ you.branch_stairs[STAIRS_ELVEN_HALLS] =
+ you.branch_stairs[STAIRS_ORCISH_MINES] + (coinflip() ? 4 : 3); // 11.0
+
+ you.branch_stairs[STAIRS_LAIR] = 7 + random2(6); // avg: 9.5
+
+ you.branch_stairs[STAIRS_HIVE] = 10 + random2(6); // avg: 12.5
+
+ you.branch_stairs[STAIRS_SLIME_PITS] =
+ you.branch_stairs[STAIRS_LAIR] + 3 + random2(4); // avg: 14.0
+
+ you.branch_stairs[STAIRS_SWAMP] =
+ you.branch_stairs[STAIRS_LAIR] + 2 + random2(6); // avg: 14.0
+
+ you.branch_stairs[STAIRS_SNAKE_PIT] =
+ you.branch_stairs[STAIRS_LAIR] + (coinflip() ? 7 : 6); // avg: 16.0
+
+ you.branch_stairs[STAIRS_VAULTS] = 13 + random2(6); // avg: 15.5
+
+ you.branch_stairs[STAIRS_CRYPT] =
+ you.branch_stairs[STAIRS_VAULTS] + 2 + random2(3); // avg: 18.5
+
+ you.branch_stairs[STAIRS_HALL_OF_BLADES] =
+ you.branch_stairs[STAIRS_VAULTS] + 4; // avg: 19.5
+
+ you.branch_stairs[STAIRS_TOMB] =
+ you.branch_stairs[STAIRS_CRYPT] + ((coinflip()) ? 3 : 2); // avg: 20.0
+
+ you.branch_stairs[STAIRS_HALL_OF_ZOT] = 26; // always 26
+
+ return (true);
+} // end of new_game()
+
+static bool species_is_undead( unsigned char speci )
+{
+ return (speci == SP_MUMMY || speci == SP_GHOUL);
+}
+
+bool class_allowed( unsigned char speci, int char_class )
+{
+ switch (char_class)
+ {
+ case JOB_FIGHTER:
+ switch (speci)
+ {
+ case SP_OGRE_MAGE:
+ case SP_SPRIGGAN:
+ return false;
+ }
+ return true;
+
+ case JOB_WIZARD:
+ if (species_is_undead( speci ))
+ return false;
+
+ switch (speci)
+ {
+ case SP_GNOME:
+ case SP_HALFLING:
+ case SP_HILL_DWARF:
+ case SP_HILL_ORC:
+ case SP_KENKU:
+ case SP_KOBOLD:
+ case SP_MINOTAUR:
+ case SP_OGRE:
+ case SP_SPRIGGAN:
+ case SP_TROLL:
+ return false;
+ }
+ return true;
+
+ case JOB_PRIEST:
+ if (player_genus(GENPC_DRACONIAN, speci))
+ return false;
+ if (species_is_undead( speci ))
+ return false;
+
+ switch (speci)
+ {
+ case SP_CENTAUR:
+ case SP_DEMIGOD:
+ case SP_DEMONSPAWN:
+ case SP_GNOME:
+ case SP_HALFLING:
+ case SP_KENKU:
+ case SP_KOBOLD:
+ case SP_MINOTAUR:
+ case SP_NAGA:
+ case SP_OGRE:
+ case SP_OGRE_MAGE:
+ case SP_SPRIGGAN:
+ case SP_TROLL:
+ return false;
+ }
+ return true;
+
+ case JOB_THIEF:
+ if (species_is_undead( speci ))
+ return false;
+
+ switch (speci)
+ {
+ case SP_CENTAUR:
+ case SP_KENKU:
+ case SP_MINOTAUR:
+ case SP_OGRE:
+ case SP_OGRE_MAGE:
+ case SP_SPRIGGAN:
+ case SP_TROLL:
+ return false;
+ }
+ return true;
+
+ case JOB_GLADIATOR:
+ if (player_genus(GENPC_ELVEN, speci))
+ return false;
+ if (species_is_undead( speci ))
+ return false;
+
+ switch (speci)
+ {
+ case SP_GNOME:
+ case SP_HALFLING:
+ case SP_KOBOLD:
+ case SP_NAGA:
+ case SP_OGRE:
+ case SP_OGRE_MAGE:
+ case SP_SPRIGGAN:
+ case SP_TROLL:
+ return false;
+ }
+ return true;
+
+ case JOB_NECROMANCER:
+ if (player_genus(GENPC_DWARVEN, speci))
+ return false;
+ if (player_genus(GENPC_DRACONIAN, speci))
+ return false;
+
+ switch (speci)
+ {
+ case SP_CENTAUR:
+ case SP_ELF:
+ case SP_GHOUL:
+ case SP_GNOME:
+ case SP_GREY_ELF:
+ case SP_HALFLING:
+ case SP_HIGH_ELF:
+ case SP_MINOTAUR:
+ case SP_OGRE:
+ case SP_SPRIGGAN:
+ case SP_TROLL:
+ case SP_MERFOLK:
+ return false;
+ }
+ return true;
+
+ case JOB_PALADIN:
+ switch (speci)
+ {
+ case SP_HUMAN:
+ case SP_MOUNTAIN_DWARF:
+ case SP_HIGH_ELF:
+ return true;
+ }
+ return false;
+
+ case JOB_ASSASSIN:
+ if (player_genus(GENPC_DWARVEN, speci))
+ return false;
+ if (player_genus(GENPC_DRACONIAN, speci))
+ return false;
+
+ switch (speci)
+ {
+ case SP_CENTAUR:
+ case SP_GHOUL:
+ case SP_GNOME:
+ case SP_MINOTAUR:
+ case SP_OGRE:
+ case SP_OGRE_MAGE:
+ case SP_TROLL:
+ return false;
+ }
+ return true;
+
+ case JOB_BERSERKER:
+ if (player_genus(GENPC_ELVEN, speci))
+ return false;
+ if (player_genus(GENPC_DRACONIAN, speci))
+ return false;
+ if (species_is_undead( speci ))
+ return false;
+
+ switch (speci)
+ {
+ case SP_DEMIGOD:
+ case SP_GNOME:
+ case SP_HALFLING:
+ case SP_KENKU:
+ case SP_KOBOLD:
+ case SP_MOUNTAIN_DWARF:
+ case SP_NAGA:
+ case SP_OGRE_MAGE:
+ case SP_SPRIGGAN:
+ case SP_MERFOLK:
+ return false;
+ }
+ return true;
+
+ case JOB_HUNTER:
+ if (player_genus(GENPC_DRACONIAN, speci)) // use bows
+ return true;
+ if (player_genus(GENPC_DWARVEN, speci)) // use xbows
+ return true;
+
+ switch (speci)
+ {
+ // bows --
+ case SP_CENTAUR:
+ case SP_DEMIGOD:
+ case SP_DEMONSPAWN:
+ case SP_ELF:
+ case SP_GREY_ELF:
+ case SP_HIGH_ELF:
+ case SP_HUMAN:
+ case SP_KENKU:
+ case SP_MINOTAUR:
+ case SP_NAGA:
+ case SP_SLUDGE_ELF:
+ // xbows --
+ case SP_HILL_ORC:
+ // slings --
+ case SP_GNOME:
+ case SP_HALFLING:
+ // spear
+ case SP_MERFOLK:
+ return true;
+ }
+ return false;
+
+ case JOB_CONJURER:
+ if (species_is_undead( speci ))
+ return false;
+
+ switch (speci)
+ {
+ case SP_CENTAUR:
+ case SP_GNOME:
+ case SP_HALFLING:
+ case SP_KOBOLD:
+ case SP_MINOTAUR:
+ case SP_OGRE:
+ case SP_SPRIGGAN:
+ case SP_TROLL:
+ case SP_MERFOLK:
+ case SP_SLUDGE_ELF:
+ return false;
+ }
+ return true;
+
+ case JOB_ENCHANTER:
+ if (player_genus(GENPC_DRACONIAN, speci))
+ return false;
+ if (species_is_undead( speci ))
+ return false;
+
+ switch (speci)
+ {
+ case SP_GNOME:
+ case SP_HILL_ORC:
+ case SP_KENKU:
+ case SP_KOBOLD:
+ case SP_MINOTAUR:
+ case SP_OGRE:
+ case SP_TROLL:
+ case SP_SLUDGE_ELF:
+ return false;
+ }
+ return true;
+
+ case JOB_FIRE_ELEMENTALIST:
+ if (player_genus(GENPC_DRACONIAN, speci))
+ return false;
+ if (species_is_undead( speci ))
+ return false;
+
+ switch (speci)
+ {
+ case SP_GNOME:
+ case SP_GREY_ELF:
+ case SP_HALFLING:
+ case SP_KOBOLD:
+ case SP_MINOTAUR:
+ case SP_NAGA:
+ case SP_OGRE:
+ case SP_SPRIGGAN:
+ case SP_TROLL:
+ case SP_MERFOLK:
+ return false;
+ }
+ return true;
+
+ case JOB_ICE_ELEMENTALIST:
+ if (player_genus(GENPC_DWARVEN, speci))
+ return false;
+ if (player_genus(GENPC_DRACONIAN, speci))
+ return false;
+ if (species_is_undead( speci ))
+ return false;
+
+ switch (speci)
+ {
+ case SP_GNOME:
+ case SP_GREY_ELF:
+ case SP_HALFLING:
+ case SP_HILL_ORC:
+ case SP_KENKU:
+ case SP_KOBOLD:
+ case SP_MINOTAUR:
+ case SP_NAGA:
+ case SP_OGRE:
+ case SP_SPRIGGAN:
+ case SP_TROLL:
+ return false;
+ }
+ return true;
+
+ case JOB_SUMMONER:
+ if (player_genus(GENPC_DWARVEN, speci))
+ return false;
+ if (species_is_undead( speci ))
+ return false;
+
+ switch (speci)
+ {
+ case SP_CENTAUR:
+ case SP_GNOME:
+ case SP_HALFLING:
+ case SP_MINOTAUR:
+ case SP_OGRE:
+ case SP_SPRIGGAN:
+ case SP_TROLL:
+ return false;
+ }
+ return true;
+
+ case JOB_AIR_ELEMENTALIST:
+ if (player_genus(GENPC_DWARVEN, speci))
+ return false;
+ if (player_genus(GENPC_DRACONIAN, speci))
+ return false;
+ if (species_is_undead( speci ))
+ return false;
+
+ switch (speci)
+ {
+ case SP_GNOME:
+ case SP_HALFLING:
+ case SP_HILL_ORC:
+ case SP_KOBOLD:
+ case SP_MINOTAUR:
+ case SP_NAGA:
+ case SP_OGRE:
+ case SP_SPRIGGAN:
+ case SP_TROLL:
+ case SP_MERFOLK:
+ return false;
+ }
+ return true;
+
+ case JOB_EARTH_ELEMENTALIST:
+ if (player_genus(GENPC_DRACONIAN, speci))
+ return false;
+ if (species_is_undead( speci ))
+ return false;
+
+ switch (speci)
+ {
+ case SP_ELF:
+ case SP_GREY_ELF:
+ case SP_HALFLING:
+ case SP_HIGH_ELF:
+ case SP_KENKU:
+ case SP_KOBOLD:
+ case SP_MINOTAUR:
+ case SP_NAGA:
+ case SP_OGRE:
+ case SP_SPRIGGAN:
+ case SP_TROLL:
+ case SP_MERFOLK:
+ return false;
+ }
+ return true;
+
+ case JOB_CRUSADER:
+ if (player_genus(GENPC_DWARVEN, speci))
+ return false;
+ if (species_is_undead( speci ))
+ return false;
+ if (player_genus(GENPC_DRACONIAN, speci))
+ return false;
+
+ switch (speci)
+ {
+ case SP_GNOME:
+ //case SP_HALFLING: //jmf: they're such good enchanters...
+ case SP_KENKU:
+ case SP_KOBOLD:
+ case SP_MINOTAUR:
+ case SP_NAGA:
+ case SP_OGRE:
+ case SP_SPRIGGAN:
+ case SP_TROLL:
+ case SP_MERFOLK:
+ case SP_SLUDGE_ELF:
+ return false;
+ }
+ return true;
+
+ case JOB_DEATH_KNIGHT:
+ if (player_genus(GENPC_DWARVEN, speci))
+ return false;
+
+ switch (speci)
+ {
+ case SP_ELF:
+ case SP_GHOUL:
+ case SP_GNOME:
+ case SP_GREY_ELF:
+ case SP_HALFLING:
+ case SP_HIGH_ELF:
+ // case SP_KOBOLD:
+ case SP_MINOTAUR:
+ case SP_OGRE:
+ case SP_OGRE_MAGE:
+ case SP_SPRIGGAN:
+ case SP_TROLL:
+ case SP_MERFOLK:
+ return false;
+ }
+ return true;
+
+ case JOB_VENOM_MAGE:
+ if (player_genus(GENPC_DWARVEN, speci))
+ return false;
+ if (species_is_undead( speci ))
+ return false;
+
+ switch (speci)
+ {
+ case SP_CENTAUR:
+ case SP_ELF:
+ case SP_GNOME:
+ case SP_GREY_ELF:
+ case SP_HALFLING:
+ case SP_HIGH_ELF:
+ case SP_MINOTAUR:
+ case SP_OGRE:
+ case SP_TROLL:
+ return false;
+ }
+ return true;
+
+ case JOB_CHAOS_KNIGHT:
+ if (player_genus(GENPC_DWARVEN, speci))
+ return false;
+ if (species_is_undead( speci ))
+ return false;
+
+ switch (speci)
+ {
+ case SP_DEMIGOD:
+ case SP_GNOME:
+ case SP_GREY_ELF:
+ case SP_HALFLING:
+ case SP_KENKU:
+ case SP_OGRE:
+ case SP_OGRE_MAGE:
+ case SP_SPRIGGAN:
+ case SP_TROLL:
+ case SP_MERFOLK:
+ return false;
+ }
+ return true;
+
+ case JOB_TRANSMUTER:
+ if (species_is_undead( speci ))
+ return false;
+
+ switch (speci)
+ {
+ case SP_HALFLING:
+ case SP_HILL_DWARF:
+ case SP_HILL_ORC:
+ case SP_KENKU:
+ case SP_MINOTAUR:
+ case SP_OGRE:
+ case SP_TROLL:
+ return false;
+ }
+ return true;
+
+ case JOB_HEALER:
+ if (player_genus(GENPC_DRACONIAN, speci))
+ return false;
+ if (species_is_undead( speci ))
+ return false;
+
+ switch (speci)
+ {
+ case SP_DEMIGOD:
+ case SP_DEMONSPAWN:
+ case SP_GNOME:
+ case SP_HALFLING:
+ case SP_KENKU:
+ case SP_KOBOLD:
+ case SP_MINOTAUR:
+ case SP_NAGA:
+ case SP_OGRE:
+ case SP_OGRE_MAGE:
+ case SP_SPRIGGAN:
+ case SP_TROLL:
+ return false;
+ }
+ return true;
+
+ case JOB_REAVER:
+ if (species_is_undead( speci ))
+ return false;
+
+ switch (speci)
+ {
+ case SP_GNOME:
+ case SP_GREY_ELF:
+ case SP_HALFLING:
+ case SP_HILL_DWARF:
+ case SP_MINOTAUR:
+ case SP_MOUNTAIN_DWARF:
+ case SP_OGRE:
+ case SP_OGRE_MAGE:
+ case SP_SPRIGGAN:
+ case SP_TROLL:
+ case SP_MERFOLK:
+ case SP_SLUDGE_ELF:
+ return false;
+ }
+ return true;
+
+ case JOB_STALKER:
+ if (player_genus(GENPC_DWARVEN, speci))
+ return false;
+ if (player_genus(GENPC_DRACONIAN, speci))
+ return false;
+ if (species_is_undead( speci ))
+ return false;
+
+ switch (speci)
+ {
+ case SP_CENTAUR:
+ case SP_GNOME:
+ case SP_HALFLING:
+ case SP_MINOTAUR:
+ case SP_OGRE:
+ case SP_OGRE_MAGE:
+ case SP_TROLL:
+ return false;
+ }
+ return true;
+
+ case JOB_MONK:
+ if (species_is_undead( speci ))
+ return false;
+
+ switch (speci)
+ {
+ case SP_CENTAUR:
+ case SP_GNOME:
+ case SP_HILL_DWARF:
+ case SP_KOBOLD:
+ case SP_NAGA:
+ case SP_OGRE:
+ case SP_OGRE_MAGE:
+ case SP_SPRIGGAN:
+ case SP_TROLL:
+ return false;
+ }
+ return true;
+
+ case JOB_WARPER:
+ if (player_genus(GENPC_DWARVEN, speci))
+ return false;
+ if (player_genus(GENPC_DRACONIAN, speci))
+ return false;
+ if (species_is_undead( speci ))
+ return false;
+
+ switch (speci)
+ {
+ case SP_CENTAUR:
+ case SP_GNOME:
+ case SP_HILL_ORC:
+ case SP_HALFLING:
+ case SP_KENKU:
+ case SP_MINOTAUR:
+ case SP_OGRE:
+ case SP_TROLL:
+ case SP_MERFOLK:
+ return false;
+ }
+ return true;
+
+ case JOB_WANDERER:
+ switch (speci)
+ {
+ case SP_HUMAN:
+ case SP_DEMIGOD:
+ case SP_DEMONSPAWN:
+ return true;
+ }
+ return false;
+
+ case JOB_QUITTER: // shouldn't happen since 'x' is handled specially
+ default:
+ return false;
+ }
+} // end class_allowed()
+
+static char startwep[5] = { WPN_SHORT_SWORD, WPN_MACE,
+ WPN_HAND_AXE, WPN_SPEAR, WPN_TRIDENT };
+
+void choose_weapon( void )
+{
+ char wepName[ ITEMNAME_SIZE ];
+ unsigned char keyin = 0;
+ int num_choices = 4;
+ int temp_rand; // probability determination {dlb}
+
+ if (you.char_class == JOB_CHAOS_KNIGHT)
+ {
+ temp_rand = random2(4);
+
+ you.inv[0].sub_type = ((temp_rand == 0) ? WPN_SHORT_SWORD :
+ (temp_rand == 1) ? WPN_MACE :
+ (temp_rand == 2) ? WPN_HAND_AXE : WPN_SPEAR);
+ return;
+ }
+
+ if (you.char_class == JOB_GLADIATOR || you.species == SP_MERFOLK)
+ num_choices = 5;
+
+ if (Options.weapon != WPN_UNKNOWN && Options.weapon != WPN_RANDOM
+ && (Options.weapon != WPN_TRIDENT || num_choices == 5))
+ {
+ you.inv[0].sub_type = Options.weapon;
+ return;
+ }
+
+ if (!Options.random_pick && Options.weapon != WPN_RANDOM)
+ {
+ clrscr();
+
+ textcolor( CYAN );
+ cprintf(EOL " You have a choice of weapons:" EOL);
+ textcolor( LIGHTGREY );
+
+ for(int i=0; i<num_choices; i++)
+ {
+ int x = effective_stat_bonus(startwep[i]);
+ standard_name_weap(startwep[i], wepName);
+
+ snprintf( info, INFO_SIZE, "%c - %s%s" EOL, 'a' + i, wepName,
+ (x <= -4) ? " (not ideal)" : "" );
+
+ cprintf(info);
+ }
+
+ cprintf(EOL "? - Random" EOL);
+
+ do
+ {
+ textcolor( CYAN );
+ cprintf(EOL "Which weapon? ");
+ textcolor( LIGHTGREY );
+
+ keyin = get_ch();
+ }
+ while (keyin != '?' && (keyin < 'a' || keyin > ('a' + num_choices)));
+
+ if (keyin != '?' && effective_stat_bonus(startwep[keyin-'a']) > -4)
+ cprintf(EOL "A fine choice. " EOL);
+ }
+
+ if (Options.random_pick || Options.weapon == WPN_RANDOM || keyin == '?')
+ {
+ // try to choose a decent weapon
+ for(int times=0; times<50; times++)
+ {
+ keyin = random2(num_choices);
+ int x = effective_stat_bonus(startwep[keyin]);
+ if (x > -2)
+ break;
+ }
+ keyin += 'a';
+ }
+
+ you.inv[0].sub_type = startwep[keyin-'a'];
+}
+
+void init_player(void)
+{
+ unsigned char i = 0; // loop variable
+
+ you.birth_time = time( NULL );
+ you.real_time = 0;
+ you.num_turns = 0;
+
+#ifdef WIZARD
+ you.wizard = (Options.wiz_mode == WIZ_YES) ? true : false;
+#else
+ you.wizard = false;
+#endif
+
+ you.berserk_penalty = 0;
+ you.berserker = 0;
+ you.conf = 0;
+ you.confusing_touch = 0;
+ you.deaths_door = 0;
+ you.disease = 0;
+ you.elapsed_time = 0;
+ you.exhausted = 0;
+ you.haste = 0;
+ you.invis = 0;
+ you.levitation = 0;
+ you.might = 0;
+ you.paralysis = 0;
+ you.poison = 0;
+ you.rotting = 0;
+ you.fire_shield = 0;
+ you.slow = 0;
+ you.special_wield = SPWLD_NONE;
+ you.sure_blade = 0;
+ you.synch_time = 0;
+
+ you.base_hp = 5000;
+ you.base_hp2 = 5000;
+ you.base_magic_points = 5000;
+ you.base_magic_points2 = 5000;
+
+ you.magic_points_regeneration = 0;
+ you.strength = 0;
+ you.max_strength = 0;
+ you.intel = 0;
+ you.max_intel = 0;
+ you.dex = 0;
+ you.max_dex = 0;
+ you.experience = 0;
+ you.experience_level = 1;
+ you.max_level = 1;
+ you.char_class = JOB_FIGHTER;
+
+ you.hunger = 6000;
+ you.hunger_state = HS_SATIATED;
+
+ you.gold = 0;
+ // you.speed = 10; // 0.75; // unused
+
+ you.burden = 0;
+ you.burden_state = BS_UNENCUMBERED;
+
+ you.spell_no = 0;
+
+ you.your_level = 0;
+ you.level_type = LEVEL_DUNGEON;
+ you.where_are_you = BRANCH_MAIN_DUNGEON;
+ you.char_direction = DIR_DESCENDING;
+
+ you.prev_targ = MHITNOT;
+ you.pet_target = MHITNOT;
+
+ you.x_pos = 0;
+ you.y_pos = 0;
+
+ you.running = 0;
+ you.run_x = 0;
+ you.run_y = 0;
+ for (i = 0; i < 3; i++)
+ {
+ you.run_check[i].grid = 0;
+ you.run_check[i].dx = 0;
+ you.run_check[i].dy = 0;
+ }
+
+ you.religion = GOD_NO_GOD;
+ you.piety = 0;
+
+ you.gift_timeout = 0;
+
+ for (i = 0; i < MAX_NUM_GODS; i++)
+ {
+ you.penance[i] = 0;
+ you.worshipped[i] = 0;
+ }
+
+ ghost.name[0] = '\0';
+
+ for (i = 0; i < NUM_GHOST_VALUES; i++)
+ ghost.values[i] = 0;
+
+ for (i = EQ_WEAPON; i < NUM_EQUIP; i++)
+ you.equip[i] = -1;
+
+ for (i = 0; i < 25; i++)
+ you.spells[i] = SPELL_NO_SPELL;
+
+ for (i = 0; i < 52; i++)
+ {
+ you.spell_letter_table[i] = -1;
+ you.ability_letter_table[i] = ABIL_NON_ABILITY;
+ }
+
+ for (i = 0; i < 100; i++)
+ you.mutation[i] = 0;
+
+ for (i = 0; i < 100; i++)
+ you.demon_pow[i] = 0;
+
+ for (i = 0; i < 50; i++)
+ you.had_book[i] = 0;
+
+ for (i = 0; i < 50; i++)
+ you.unique_items[i] = UNIQ_NOT_EXISTS;
+
+ for (i = 0; i < NO_UNRANDARTS; i++)
+ set_unrandart_exist(i, 0);
+
+ for (i = 0; i < 50; i++)
+ {
+ you.skills[i] = 0;
+ you.skill_points[i] = 0;
+ you.skill_order[i] = MAX_SKILL_ORDER;
+ you.practise_skill[i] = 1;
+ }
+
+ you.skill_cost_level = 1;
+ you.total_skill_points = 0;
+
+ for (i = 0; i < 30; i++)
+ you.attribute[i] = 0;
+
+ for (i = 0; i < ENDOFPACK; i++)
+ {
+ you.inv[i].quantity = 0;
+ you.inv[i].base_type = OBJ_WEAPONS;
+ you.inv[i].sub_type = WPN_CLUB;
+ you.inv[i].plus = 0;
+ you.inv[i].plus2 = 0;
+ you.inv[i].special = 0;
+ you.inv[i].colour = 0;
+ set_ident_flags( you.inv[i], ISFLAG_IDENT_MASK );
+
+ you.inv[i].x = -1;
+ you.inv[i].y = -1;
+ you.inv[i].link = i;
+ }
+
+ for (i = 0; i < NUM_DURATIONS; i++)
+ you.duration[i] = 0;
+}
+
+void give_last_paycheck(int which_job)
+{
+ switch (which_job)
+ {
+ case JOB_HEALER:
+ case JOB_THIEF:
+ you.gold = roll_dice( 2, 100 );
+ break;
+
+ case JOB_WANDERER:
+ case JOB_WARPER:
+ case JOB_ASSASSIN:
+ you.gold = roll_dice( 2, 50 );
+ break;
+
+ default:
+ you.gold = roll_dice( 2, 20 );
+ break;
+
+ case JOB_PALADIN:
+ case JOB_MONK:
+ you.gold = 0;
+ break;
+ }
+}
+
+// requires stuff::modify_all_stats() and works because
+// stats zeroed out by newgame::init_player()... recall
+// that demonspawn & demingods get more later on {dlb}
+void species_stat_init(unsigned char which_species)
+{
+ int sb = 0; // strength base
+ int ib = 0; // intelligence base
+ int db = 0; // dexterity base
+
+ // Note: The stats in in this list aren't intended to sum the same
+ // for all races. The fact that Mummies and Ghouls are really low
+ // is considered acceptable (Mummies don't have to eat, and Ghouls
+ // are supposted to be a really hard race). Also note that Demigods
+ // and Demonspawn get seven more random points added later. -- bwr
+ switch (which_species)
+ {
+ default: sb = 6; ib = 6; db = 6; break; // 18
+ case SP_HUMAN: sb = 6; ib = 6; db = 6; break; // 18
+ case SP_DEMIGOD: sb = 7; ib = 7; db = 7; break; // 21+7
+ case SP_DEMONSPAWN: sb = 4; ib = 4; db = 4; break; // 12+7
+
+ case SP_ELF: sb = 5; ib = 8; db = 8; break; // 21
+ case SP_HIGH_ELF: sb = 5; ib = 9; db = 8; break; // 22
+ case SP_GREY_ELF: sb = 4; ib = 9; db = 8; break; // 21
+ case SP_DEEP_ELF: sb = 3; ib = 10; db = 8; break; // 21
+ case SP_SLUDGE_ELF: sb = 6; ib = 7; db = 7; break; // 20
+
+ case SP_HILL_DWARF: sb = 10; ib = 3; db = 4; break; // 17
+ case SP_MOUNTAIN_DWARF: sb = 9; ib = 4; db = 5; break; // 18
+
+ case SP_TROLL: sb = 13; ib = 2; db = 3; break; // 18
+ case SP_OGRE: sb = 12; ib = 3; db = 3; break; // 18
+ case SP_OGRE_MAGE: sb = 9; ib = 7; db = 3; break; // 19
+
+ case SP_MINOTAUR: sb = 10; ib = 3; db = 3; break; // 16
+ case SP_HILL_ORC: sb = 9; ib = 3; db = 4; break; // 16
+ case SP_CENTAUR: sb = 8; ib = 5; db = 2; break; // 15
+ case SP_NAGA: sb = 8; ib = 6; db = 4; break; // 18
+
+ case SP_GNOME: sb = 6; ib = 6; db = 7; break; // 19
+ case SP_MERFOLK: sb = 6; ib = 5; db = 7; break; // 18
+ case SP_KENKU: sb = 6; ib = 6; db = 7; break; // 19
+
+ case SP_KOBOLD: sb = 5; ib = 4; db = 8; break; // 17
+ case SP_HALFLING: sb = 3; ib = 6; db = 9; break; // 18
+ case SP_SPRIGGAN: sb = 2; ib = 7; db = 9; break; // 18
+
+ case SP_MUMMY: sb = 7; ib = 3; db = 3; break; // 13
+ case SP_GHOUL: sb = 9; ib = 1; db = 2; break; // 13
+
+ case SP_RED_DRACONIAN:
+ case SP_WHITE_DRACONIAN:
+ case SP_GREEN_DRACONIAN:
+ case SP_GOLDEN_DRACONIAN:
+ case SP_GREY_DRACONIAN:
+ case SP_BLACK_DRACONIAN:
+ case SP_PURPLE_DRACONIAN:
+ case SP_MOTTLED_DRACONIAN:
+ case SP_PALE_DRACONIAN:
+ case SP_UNK0_DRACONIAN:
+ case SP_UNK1_DRACONIAN:
+ case SP_UNK2_DRACONIAN: sb = 9; ib = 6; db = 2; break; // 17
+ }
+
+ modify_all_stats( sb, ib, db );
+}
+
+void jobs_stat_init(int which_job)
+{
+ int s = 0; // strength mod
+ int i = 0; // intelligence mod
+ int d = 0; // dexterity mod
+ int hp = 0; // HP base
+ int mp = 0; // MP base
+
+ // Note: Wanderers are correct, they're a challenging class. -- bwr
+ switch (which_job)
+ {
+ case JOB_FIGHTER: s = 7; i = 0; d = 3; hp = 15; mp = 0; break;
+ case JOB_BERSERKER: s = 7; i = -1; d = 4; hp = 15; mp = 0; break;
+ case JOB_GLADIATOR: s = 6; i = 0; d = 4; hp = 14; mp = 0; break;
+ case JOB_PALADIN: s = 6; i = 2; d = 2; hp = 14; mp = 0; break;
+
+ case JOB_CRUSADER: s = 4; i = 3; d = 3; hp = 13; mp = 1; break;
+ case JOB_DEATH_KNIGHT: s = 4; i = 3; d = 3; hp = 13; mp = 1; break;
+ case JOB_CHAOS_KNIGHT: s = 4; i = 3; d = 3; hp = 13; mp = 1; break;
+
+ case JOB_REAVER: s = 4; i = 4; d = 2; hp = 13; mp = 1; break;
+ case JOB_HEALER: s = 4; i = 4; d = 2; hp = 13; mp = 1; break;
+ case JOB_PRIEST: s = 4; i = 4; d = 2; hp = 12; mp = 1; break;
+
+ case JOB_ASSASSIN: s = 2; i = 2; d = 6; hp = 12; mp = 0; break;
+ case JOB_THIEF: s = 3; i = 2; d = 5; hp = 13; mp = 0; break;
+ case JOB_STALKER: s = 2; i = 3; d = 5; hp = 12; mp = 1; break;
+
+ case JOB_HUNTER: s = 3; i = 3; d = 4; hp = 13; mp = 0; break;
+ case JOB_WARPER: s = 3; i = 4; d = 3; hp = 12; mp = 1; break;
+
+ case JOB_MONK: s = 2; i = 2; d = 6; hp = 13; mp = 0; break;
+ case JOB_TRANSMUTER: s = 2; i = 4; d = 4; hp = 12; mp = 1; break;
+
+ case JOB_WIZARD: s = -1; i = 8; d = 3; hp = 8; mp = 5; break;
+ case JOB_CONJURER: s = 0; i = 6; d = 4; hp = 10; mp = 3; break;
+ case JOB_ENCHANTER: s = 0; i = 6; d = 4; hp = 10; mp = 3; break;
+ case JOB_FIRE_ELEMENTALIST: s = 0; i = 6; d = 4; hp = 10; mp = 3; break;
+ case JOB_ICE_ELEMENTALIST: s = 0; i = 6; d = 4; hp = 10; mp = 3; break;
+ case JOB_AIR_ELEMENTALIST: s = 0; i = 6; d = 4; hp = 10; mp = 3; break;
+ case JOB_EARTH_ELEMENTALIST:s = 0; i = 6; d = 4; hp = 10; mp = 3; break;
+ case JOB_SUMMONER: s = 0; i = 6; d = 4; hp = 10; mp = 3; break;
+ case JOB_VENOM_MAGE: s = 0; i = 6; d = 4; hp = 10; mp = 3; break;
+ case JOB_NECROMANCER: s = 0; i = 6; d = 4; hp = 10; mp = 3; break;
+
+ case JOB_WANDERER: s = 2; i = 2; d = 2; hp = 11; mp = 1; break;
+ default: s = 0; i = 0; d = 0; hp = 10; mp = 0; break;
+ }
+
+ modify_all_stats( s, i, d );
+
+ set_hp( hp, true );
+ set_mp( mp, true );
+}
+
+void give_basic_knowledge(int which_job)
+{
+ switch (which_job)
+ {
+ case JOB_PRIEST:
+ case JOB_PALADIN:
+ set_ident_type( OBJ_POTIONS, POT_HEALING, ID_KNOWN_TYPE );
+ break;
+
+ case JOB_HEALER:
+ set_ident_type( OBJ_POTIONS, POT_HEALING, ID_KNOWN_TYPE );
+ set_ident_type( OBJ_POTIONS, POT_HEAL_WOUNDS, ID_KNOWN_TYPE );
+ break;
+
+ case JOB_ASSASSIN:
+ case JOB_STALKER:
+ case JOB_VENOM_MAGE:
+ set_ident_type( OBJ_POTIONS, POT_POISON, ID_KNOWN_TYPE );
+ break;
+
+ case JOB_WARPER:
+ set_ident_type( OBJ_SCROLLS, SCR_BLINKING, ID_KNOWN_TYPE );
+ break;
+
+ case JOB_TRANSMUTER:
+ set_ident_type( OBJ_POTIONS, POT_WATER, ID_KNOWN_TYPE );
+ set_ident_type( OBJ_POTIONS, POT_CONFUSION, ID_KNOWN_TYPE );
+ set_ident_type( OBJ_POTIONS, POT_POISON, ID_KNOWN_TYPE );
+ break;
+
+ default:
+ break;
+ }
+
+ return;
+} // end give_basic_knowledge()
+
+void give_basic_spells(int which_job)
+{
+ // wanderers may or may not already have a spell -- bwr
+ if (which_job == JOB_WANDERER)
+ return;
+
+ unsigned char which_spell = SPELL_NO_SPELL;
+
+ switch (which_job)
+ {
+ case JOB_CONJURER:
+ case JOB_REAVER:
+ case JOB_WIZARD:
+ which_spell = SPELL_MAGIC_DART;
+ break;
+ case JOB_STALKER:
+ case JOB_VENOM_MAGE:
+ which_spell = SPELL_STING;
+ break;
+ case JOB_SUMMONER:
+ which_spell = SPELL_SUMMON_SMALL_MAMMAL;
+ break;
+ case JOB_ICE_ELEMENTALIST:
+ which_spell = SPELL_FREEZE;
+ break;
+ case JOB_NECROMANCER:
+ which_spell = SPELL_PAIN;
+ break;
+ case JOB_ENCHANTER:
+ which_spell = SPELL_BACKLIGHT;
+ break;
+ case JOB_FIRE_ELEMENTALIST:
+ which_spell = SPELL_FLAME_TONGUE;
+ break;
+ case JOB_AIR_ELEMENTALIST:
+ which_spell = SPELL_SHOCK;
+ break;
+ case JOB_EARTH_ELEMENTALIST:
+ which_spell = SPELL_SANDBLAST;
+ break;
+ case JOB_DEATH_KNIGHT:
+ if (you.species == SP_DEMIGOD || you.religion != GOD_YREDELEMNUL)
+ which_spell = SPELL_PAIN;
+ break;
+
+ default:
+ break;
+ }
+
+ if (which_spell != SPELL_NO_SPELL)
+ add_spell_to_memory( which_spell );
+
+ return;
+} // end give_basic_spells()
+
+
+/* ************************************************************************
+
+// MAKE INTO FUNCTION!!! {dlb}
+// randomly boost stats a number of times based on species {dlb}
+ unsigned char points_left = ( you.species == SP_DEMIGOD || you.species == SP_DEMONSPAWN ) ? 15 : 8;
+
+ do
+ {
+ switch ( random2(NUM_STATS) )
+ {
+ case STAT_STRENGTH:
+ if ( you.strength > 17 && coinflip() )
+ continue;
+ you.strength++;
+ break;
+ case STAT_DEXTERITY:
+ if ( you.dex > 17 && coinflip() )
+ continue;
+ you.dex++;
+ break;
+ case STAT_INTELLIGENCE:
+ if ( you.intel > 17 && coinflip() )
+ continue;
+ you.intel++;
+ break;
+ }
+ points_left--;
+ }
+ while (points_left > 0);
+
+************************************************************************ */
+
+
+// eventually, this should be something more grand {dlb}
+void openingScreen(void)
+{
+/* **********************************************
+// this does not work just yet ... {dlb}:
+ cprintf(EOL "Hello, ");
+
+ if ( you.your_name[0] != '\0' )
+ {
+ cprintf(you.your_name); // better be less than 31 characters :P {dlb}
+ // of course, invalid names will appear {dlb}
+ cprintf(", ");
+ }
+********************************************** */
+
+ textcolor( YELLOW );
+ cprintf("Hello, welcome to Dungeon Crawl " VERSION "!");
+ textcolor( BROWN );
+ cprintf(EOL "(c) Copyright 1997-2002 Linley Henzell");
+ cprintf(EOL "Please consult crawl.txt for instructions and legal details."
+ EOL);
+ textcolor( LIGHTGREY );
+
+ return;
+} // end openingScreen()
+
+
+void enterPlayerName(bool blankOK)
+{
+ // temporary 'til copyover to you.your_name {dlb}
+ // made this rediculously long so that the game doesn't
+ // crash if a really really long name is entered (argh). {gdl}
+ char name_entered[200];
+
+ // anything to avoid goto statements {dlb}
+ bool acceptable_name = false;
+ bool first_time = true;
+
+ // first time -- names set through init.txt/environment assumed ok {dlb}
+ if (you.your_name[0] != '\0')
+ acceptable_name = true;
+
+ do
+ {
+ // prompt for a new name if current one unsatisfactory {dlb}:
+ if (!acceptable_name)
+ {
+ textcolor( CYAN );
+ if (blankOK && first_time)
+ cprintf(EOL "Press <Enter> to answer this after race and class are chosen."EOL);
+
+ first_time = false;
+
+ cprintf(EOL "What is your name today? ");
+ textcolor( LIGHTGREY );
+ get_input_line( name_entered, sizeof( name_entered ) );
+
+ strncpy( you.your_name, name_entered, kNameLen );
+ you.your_name[ kNameLen - 1 ] = '\0';
+ }
+
+ // verification begins here {dlb}:
+ if (you.your_name[0] == '\0')
+ {
+ if (blankOK)
+ return;
+
+ cprintf(EOL "That's a silly name!" EOL);
+ acceptable_name = false;
+ }
+
+ // if SAVE_DIR_PATH is defined, userid will be tacked onto the end
+ // of each character's files, making bones a valid player name.
+#ifndef SAVE_DIR_PATH
+ // this would cause big probs with ghosts
+ // what would? {dlb}
+ // ... having the name "bones" of course! The problem comes from
+ // the fact that bones files would have the exact same filename
+ // as level files for a character named "bones". -- bwr
+ else if (stricmp(you.your_name, "bones") == 0)
+ {
+ cprintf(EOL "That's a silly name!" EOL);
+ acceptable_name = false;
+ }
+#endif
+ else
+ acceptable_name = verifyPlayerName();
+
+ }
+ while (!acceptable_name);
+} // end enterPlayerName()
+
+bool verifyPlayerName(void)
+{
+#if defined(DOS) || defined(WIN32CONSOLE)
+ static int william_tanksley_asked_for_this = 2;
+
+ // quick check for CON -- blows up real good under DOS/Windows
+ if (stricmp(you.your_name, "con") == 0)
+ {
+ cprintf(EOL "Sorry, that name gives your OS a headache." EOL);
+ return (false);
+ }
+
+ // quick check for LPTx -- thank you, Mr. Tanksley! ;-)
+ if (strnicmp(you.your_name, "LPT", 3) == 0)
+ {
+ switch (william_tanksley_asked_for_this)
+ {
+ case 2:
+ cprintf(EOL "Hello, William! How is work on Omega going?" EOL);
+ break;
+ case 1:
+ cprintf(EOL "Look, it's just not a legal name." EOL);
+ break;
+ case 0:
+ strcpy(you.your_name, "William");
+ return (true);
+ } // end switch
+
+ william_tanksley_asked_for_this --;
+ return (false);
+ }
+#endif
+
+ const size_t len = strlen( you.your_name );
+ for (unsigned int i = 0; i < len; i++)
+ {
+#if MAC
+ // the only bad character on Macs is the path seperator
+ if (you.your_name[i] == ':')
+ {
+ cprintf(EOL "No colons, please." EOL);
+ return (false);
+ }
+#else
+ // Note that this includes systems which may be using the
+ // packaging system. The packaging system is very simple
+ // and doesn't take the time to escape every characters that
+ // might be a problem for some random shell or OS... so we
+ // play it very conservative here. -- bwr
+ if (!isalnum( you.your_name[i] ) && you.your_name[i] != '_')
+ {
+ cprintf( EOL "Alpha-numerics and underscores only, please." EOL );
+ return (false);
+ }
+#endif
+ }
+
+#ifdef SAVE_DIR_PATH
+ // Until we have a better way to handle the fact that this could lead
+ // to some confusion with where the name ends and the uid begins. -- bwr
+ if (isdigit( you.your_name[ len - 1 ] ))
+ {
+ cprintf( EOL "Sorry, your name cannot end with a digit." EOL );
+ return (false);
+ }
+#endif
+
+ return (true);
+} // end verifyPlayerName()
+
+#if 0
+// currently unused
+static void give_random_scroll( int slot )
+{
+ you.inv[ slot ].quantity = 1;
+ you.inv[ slot ].base_type = OBJ_SCROLLS;
+ you.inv[ slot ].plus = 0;
+ you.inv[ slot ].special = 0;
+ you.inv[ slot ].colour = WHITE;
+
+ switch (random2(8))
+ {
+ case 0:
+ you.inv[ slot ].sub_type = SCR_DETECT_CURSE;
+ break;
+
+ case 1:
+ you.inv[ slot ].sub_type = SCR_IDENTIFY;
+ break;
+
+ case 2:
+ case 3:
+ you.inv[ slot ].sub_type = SCR_BLINKING;
+ break;
+
+ case 4:
+ you.inv[ slot ].sub_type = SCR_FEAR;
+ break;
+
+ case 5:
+ you.inv[ slot ].sub_type = SCR_SUMMONING;
+ break;
+
+ case 6:
+ case 7:
+ default:
+ you.inv[ slot ].sub_type = SCR_TELEPORTATION;
+ break;
+ }
+}
+#endif
+
+static void give_random_potion( int slot )
+{
+ you.inv[ slot ].quantity = 1;
+ you.inv[ slot ].base_type = OBJ_POTIONS;
+ you.inv[ slot ].plus = 0;
+ you.inv[ slot ].plus2 = 0;
+
+ switch (random2(8))
+ {
+ case 0:
+ case 1:
+ case 2:
+ you.inv[ slot ].sub_type = POT_HEALING;
+ break;
+ case 3:
+ case 4:
+ you.inv[ slot ].sub_type = POT_HEAL_WOUNDS;
+ break;
+ case 5:
+ you.inv[ slot ].sub_type = POT_SPEED;
+ break;
+ case 6:
+ you.inv[ slot ].sub_type = POT_MIGHT;
+ break;
+ case 7:
+ you.inv[ slot ].sub_type = POT_BERSERK_RAGE;
+ break;
+ }
+}
+
+#if 0
+// currently unused
+static void give_random_wand( int slot )
+{
+ you.inv[ slot ].quantity = 1;
+ you.inv[ slot ].base_type = OBJ_WANDS;
+ you.inv[ slot ].special = 0;
+ you.inv[ slot ].plus2 = 0;
+ you.inv[ slot ].colour = random_colour();
+
+ switch (random2(4))
+ {
+ case 0:
+ you.inv[ slot ].sub_type = WAND_SLOWING;
+ you.inv[ slot ].plus = 7 + random2(5);
+ break;
+ case 1:
+ you.inv[ slot ].sub_type = WAND_PARALYSIS;
+ you.inv[ slot ].plus = 5 + random2(4);
+ break;
+ case 2:
+ you.inv[ slot ].sub_type = coinflip() ? WAND_FROST : WAND_FLAME;
+ you.inv[ slot ].plus = 6 + random2(4);
+ break;
+ case 3:
+ you.inv[ slot ].sub_type = WAND_TELEPORTATION;
+ you.inv[ slot ].plus = 3 + random2(4);
+ break;
+ }
+}
+#endif
+
+static void give_random_secondary_armour( int slot )
+{
+ you.inv[ slot ].quantity = 1;
+ you.inv[ slot ].base_type = OBJ_ARMOUR;
+ you.inv[ slot ].special = 0;
+ you.inv[ slot ].plus = 0;
+ you.inv[ slot ].plus2 = 0;
+ you.inv[ slot ].colour = BROWN;
+
+ switch (random2(4))
+ {
+ case 0:
+ you.inv[ slot ].sub_type = ARM_CLOAK;
+ you.equip[EQ_CLOAK] = slot;
+ break;
+ case 1:
+ you.inv[ slot ].sub_type = ARM_BOOTS;
+ you.equip[EQ_BOOTS] = slot;
+ break;
+ case 2:
+ you.inv[ slot ].sub_type = ARM_GLOVES;
+ you.equip[EQ_GLOVES] = slot;
+ break;
+ case 3:
+ you.inv[ slot ].sub_type = ARM_HELMET;
+ you.equip[EQ_HELMET] = slot;
+ break;
+ }
+}
+
+// Returns true if a "good" weapon is given
+static bool give_wanderer_weapon( int slot, int wpn_skill )
+{
+ bool ret = false;
+
+ // Slot's always zero, but we pass it anyways.
+
+ // We'll also re-fill the template, all this for later possible
+ // safe reuse of code in the future.
+ you.inv[ slot ].quantity = 1;
+ you.inv[ slot ].base_type = OBJ_WEAPONS;
+ you.inv[ slot ].colour = LIGHTCYAN;
+ you.inv[ slot ].plus = 0;
+ you.inv[ slot ].plus2 = 0;
+ you.inv[ slot ].special = 0;
+
+ // Now fill in the type according to the random wpn_skill
+ switch (wpn_skill)
+ {
+ case SK_MACES_FLAILS:
+ you.inv[ slot ].sub_type = WPN_CLUB;
+ you.inv[ slot ].colour = BROWN;
+ break;
+
+ case SK_POLEARMS:
+ you.inv[ slot ].sub_type = WPN_SPEAR;
+ break;
+
+ case SK_SHORT_BLADES:
+ you.inv[ slot ].sub_type = WPN_DAGGER;
+ break;
+
+ case SK_AXES:
+ you.inv[ slot ].sub_type = WPN_HAND_AXE;
+ ret = true;
+ break;
+
+ case SK_STAVES:
+ you.inv[ slot ].sub_type = WPN_QUARTERSTAFF;
+ you.inv[ slot ].colour = BROWN;
+ ret = true;
+ break;
+
+ case SK_LONG_SWORDS:
+ default:
+ // all long swords are too good for a starting character...
+ // especially this class where we have to be careful about
+ // giving away anything good at all.
+ // We default here if the character only has fighting skill -- bwr
+ you.inv[ slot ].sub_type = WPN_SHORT_SWORD;
+ ret = true;
+ break;
+ }
+
+ return (ret);
+}
+
+//
+// The idea behind wanderers is a class that has various different
+// random skills that's a challenge to play... not a class that can
+// be continually rerolled to gain the ideal character. To maintain
+// this, we have to try and make sure that they typically get worse
+// equipment than any other class... this for certain means no
+// spellbooks ever, and the bows and xbows down below might be too
+// much... so pretty much things should be removed rather than
+// added here. -- bwr
+//
+static void create_wanderer( void )
+{
+ const int util_skills[] =
+ { SK_DARTS, SK_THROWING, SK_ARMOUR, SK_DODGING, SK_STEALTH,
+ SK_STABBING, SK_SHIELDS, SK_TRAPS_DOORS, SK_UNARMED_COMBAT,
+ SK_INVOCATIONS, SK_EVOCATIONS };
+ const int num_util_skills = sizeof(util_skills) / sizeof(int);
+
+ // Long swords is missing to increae it's rarity because we
+ // can't give out a long sword to a starting character (they're
+ // all too good)... Staves is also removed because it's not
+ // one of the fighter options.-- bwr
+ const int fight_util_skills[] =
+ { SK_FIGHTING, SK_SHORT_BLADES, SK_AXES,
+ SK_MACES_FLAILS, SK_POLEARMS,
+ SK_DARTS, SK_THROWING, SK_ARMOUR, SK_DODGING, SK_STEALTH,
+ SK_STABBING, SK_SHIELDS, SK_TRAPS_DOORS, SK_UNARMED_COMBAT,
+ SK_INVOCATIONS, SK_EVOCATIONS };
+ const int num_fight_util_skills = sizeof(fight_util_skills) / sizeof(int);
+
+ const int not_rare_skills[] =
+ { SK_SLINGS, SK_BOWS, SK_CROSSBOWS,
+ SK_SPELLCASTING, SK_CONJURATIONS, SK_ENCHANTMENTS,
+ SK_FIRE_MAGIC, SK_ICE_MAGIC, SK_AIR_MAGIC, SK_EARTH_MAGIC,
+ SK_FIGHTING, SK_SHORT_BLADES, SK_LONG_SWORDS, SK_AXES,
+ SK_MACES_FLAILS, SK_POLEARMS, SK_STAVES,
+ SK_DARTS, SK_THROWING, SK_ARMOUR, SK_DODGING, SK_STEALTH,
+ SK_STABBING, SK_SHIELDS, SK_TRAPS_DOORS, SK_UNARMED_COMBAT,
+ SK_INVOCATIONS, SK_EVOCATIONS };
+ const int num_not_rare_skills = sizeof(not_rare_skills) / sizeof(int);
+
+ const int all_skills[] =
+ { SK_SUMMONINGS, SK_NECROMANCY, SK_TRANSLOCATIONS, SK_TRANSMIGRATION,
+ SK_DIVINATIONS, SK_POISON_MAGIC,
+ SK_SLINGS, SK_BOWS, SK_CROSSBOWS,
+ SK_SPELLCASTING, SK_CONJURATIONS, SK_ENCHANTMENTS,
+ SK_FIRE_MAGIC, SK_ICE_MAGIC, SK_AIR_MAGIC, SK_EARTH_MAGIC,
+ SK_FIGHTING, SK_SHORT_BLADES, SK_LONG_SWORDS, SK_AXES,
+ SK_MACES_FLAILS, SK_POLEARMS, SK_STAVES,
+ SK_DARTS, SK_THROWING, SK_ARMOUR, SK_DODGING, SK_STEALTH,
+ SK_STABBING, SK_SHIELDS, SK_TRAPS_DOORS, SK_UNARMED_COMBAT,
+ SK_INVOCATIONS, SK_EVOCATIONS };
+ const int num_all_skills = sizeof(all_skills) / sizeof(int);
+
+ int skill;
+
+ for (int i = 0; i < 2; i++)
+ {
+ do
+ {
+ skill = random2( num_util_skills );
+ }
+ while (you.skills[ util_skills[ skill ]] >= 2);
+
+ you.skills[ util_skills[ skill ]] += 1;
+ }
+
+ for (int i = 0; i < 3; i++)
+ {
+ do
+ {
+ skill = random2( num_fight_util_skills );
+ }
+ while (you.skills[ fight_util_skills[ skill ]] >= 2);
+
+ you.skills[ fight_util_skills[ skill ]] += 1;
+ }
+
+ // Spell skills are possible past this point, but we won't
+ // allow two levels of any of them -- bwr
+ for (int i = 0; i < 3; i++)
+ {
+ do
+ {
+ skill = random2( num_not_rare_skills );
+ }
+ while (you.skills[ not_rare_skills[ skill ]] >= 2
+ || (not_rare_skills[ skill ] >= SK_SPELLCASTING
+ && you.skills[ not_rare_skills[ skill ]]));
+
+ you.skills[ not_rare_skills[ skill ]] += 1;
+ }
+
+ for (int i = 0; i < 2; i++)
+ {
+ do
+ {
+ skill = random2( num_all_skills );
+ }
+ while (you.skills[all_skills[ skill ]] >= 2
+ || (all_skills[ skill ] >= SK_SPELLCASTING
+ && you.skills[ all_skills[ skill ]]));
+
+ you.skills[ all_skills[ skill ]] += 1;
+ }
+
+ // Demigods can't use invocations so we'll swap it for something else
+ if (you.species == SP_DEMIGOD && you.skills[ SK_INVOCATIONS ])
+ {
+ you.skills[ SK_INVOCATIONS ] = 0;
+
+ do
+ {
+ skill = random2( num_all_skills );
+ }
+ while (skill == SK_INVOCATIONS && you.skills[all_skills[ skill ]]);
+
+ you.skills[ skill ] = 1;
+ }
+
+ int wpn_skill = SK_FIGHTING; // prefered weapon type
+ int wpn_skill_size = 0; // level of skill in prefered weapon type
+ int num_wpn_skills = 0; // used to choose prefered weapon
+ int total_wpn_skills = 0; // used to choose template
+
+ // This algorithm is the same as the one used to pick a random
+ // angry god for retribution, except that whenever a higher skill
+ // is found than the current one, we automatically take it and
+ // only consider skills at that level or higher from that point on,
+ // This should give a random wpn skill from the set of skills with
+ // the highest value. -- bwr
+ for (int i = SK_SHORT_BLADES; i <= SK_STAVES; i++)
+ {
+ if (you.skills[i] > 0)
+ {
+ total_wpn_skills++;
+
+ if (you.skills[i] > wpn_skill_size)
+ {
+ // switch to looking in the new set of better skills
+ num_wpn_skills = 1; // reset to one, because it's a new set
+ wpn_skill = i;
+ wpn_skill_size = you.skills[i];
+ }
+ else if (you.skills[i] == wpn_skill_size)
+ {
+ // still looking at the old level
+ num_wpn_skills++;
+ if (one_chance_in( num_wpn_skills ))
+ {
+ wpn_skill = i;
+ wpn_skill_size = you.skills[i];
+ }
+ }
+ }
+ }
+
+ // Let's try to make an appropriate weapon
+ // Start with a template for a weapon
+ you.inv[0].quantity = 1;
+ you.inv[0].base_type = OBJ_WEAPONS;
+ you.inv[0].sub_type = WPN_KNIFE;
+ you.inv[0].colour = LIGHTCYAN;
+ you.inv[0].plus = 0;
+ you.inv[0].plus2 = 0;
+ you.inv[0].special = 0;
+
+ // And a default armour template for a robe (leaving slot 1 open for
+ // a secondary weapon).
+ you.inv[2].quantity = 1;
+ you.inv[2].base_type = OBJ_ARMOUR;
+ you.inv[2].sub_type = ARM_ROBE;
+ you.inv[2].colour = BROWN;
+ you.inv[2].plus = 0;
+ you.inv[2].special = 0;
+
+ // Wanderers have at least seen one type of potion, and if they
+ // don't get anything else good, they'll get to keep this one...
+ // Note: even if this is taken away, the knowledge of the potion
+ // type is still given to the character.
+ give_random_potion(3);
+
+ if (you.skills[SK_FIGHTING] || total_wpn_skills >= 3)
+ {
+ // Fighter style wanderer
+ if (you.skills[SK_ARMOUR])
+ {
+ you.inv[2].sub_type = ARM_RING_MAIL;
+ you.inv[2].colour = LIGHTCYAN;
+
+ you.inv[3].quantity = 0; // remove potion
+ }
+ else if (you.skills[SK_SHIELDS] && wpn_skill != SK_STAVES)
+ {
+ you.inv[4].quantity = 1;
+ you.inv[4].base_type = OBJ_ARMOUR;
+ you.inv[4].sub_type = ARM_BUCKLER;
+ you.inv[4].plus = 0;
+ you.inv[4].special = 0;
+ you.inv[4].colour = LIGHTCYAN;
+ you.equip[EQ_SHIELD] = 4;
+
+ you.inv[3].quantity = 0; // remove potion
+ }
+ else
+ {
+ give_random_secondary_armour(5);
+ }
+
+ // remove potion if good weapon is given:
+ if (give_wanderer_weapon( 0, wpn_skill ))
+ you.inv[3].quantity = 0;
+ }
+#ifdef USE_SPELLCASTER_AND_RANGER_WANDERER_TEMPLATES
+ else if (you.skills[ SK_SPELLCASTING ])
+ {
+ // Spellcaster style wanderer
+
+ // Could only have learned spells in common schools...
+ const int school_list[5] =
+ { SK_CONJURATIONS,
+ SK_ENCHANTMENTS, SK_ENCHANTMENTS,
+ SK_TRANSLOCATIONS, SK_NECROMANCY };
+
+ //jmf: Two of those spells are gone due to their munchkinicity.
+ // crush() and arc() are like having good melee capability.
+ // Therefore giving them to "harder" class makes less-than-
+ // zero sense, and they're now gone.
+ const int spell_list[5] =
+ { SPELL_MAGIC_DART,
+ SPELL_CONFUSING_TOUCH, SPELL_BACKLIGHT,
+ SPELL_APPORTATION, SPELL_ANIMATE_SKELETON };
+
+ // Choose one of the schools we have at random.
+ int school = SK_SPELLCASTING;
+ int num_schools = 0;
+ for (int i = 0; i < 5; i++)
+ {
+ if (you.skills[ school_list[ i ]])
+ {
+ num_schools++;
+ if (one_chance_in( num_schools ))
+ school = i;
+ }
+ }
+
+ // Magic dart is quite a good spell, so if the player only has
+ // spellcasting and conjurations, we sometimes hold off... and
+ // treat them like an unskilled spellcaster.
+ if (school == SK_SPELLCASTING
+ || (num_schools == 1 && school == SK_CONJURATIONS && coinflip()))
+ {
+ // Not much melee potential and no common spell school,
+ // we'll give the player a dagger.
+ you.inv[0].sub_type = WPN_DAGGER;
+
+ // ... and a random scroll
+ give_random_scroll(4);
+
+ // ... and knowledge of another
+ give_random_scroll(5);
+ you.inv[5].quantity = 0;
+
+ // ... and a wand.
+ give_random_wand(6);
+ }
+ else
+ {
+ // Give them an appropriate spell
+ add_spell_to_memory( spell_list[ school ] );
+ }
+ }
+ else if (you.skills[ SK_THROWING ] && one_chance_in(3)) // these are rare
+ {
+ // Ranger style wanderer
+ // Rare since starting with a throwing weapon is very good
+
+ // Create a default launcher template, but the
+ // quantity may be reset to 0 if we don't want one -- bwr
+ // thorwing weapons are lowered to -1 to make them
+ // not as good as the one's hunters get, ammo is
+ // also much smaller -- bwr
+ you.inv[1].quantity = 1;
+ you.inv[1].base_type = OBJ_WEAPONS;
+ you.inv[1].sub_type = WPN_BOW;
+ you.inv[1].plus = -1;
+ you.inv[1].plus2 = -1;
+ you.inv[1].special = 0;
+ you.inv[1].colour = BROWN;
+
+ // Create default ammo template (darts) (armour is slot 2)
+ you.inv[4].base_type = OBJ_MISSILES;
+ you.inv[4].sub_type = MI_DART;
+ you.inv[4].quantity = 10 + roll_dice( 2, 6 );
+ you.inv[4].plus = 0;
+ you.inv[4].plus2 = 0;
+ you.inv[4].special = 0;
+ you.inv[4].colour = LIGHTCYAN;
+
+ if (you.skills[ SK_SLINGS ])
+ {
+ // slingers get some extra ammo
+ you.inv[4].quantity += random2avg(20,5);
+ you.inv[4].sub_type = MI_STONE;
+ you.inv[4].colour = BROWN;
+ you.inv[1].sub_type = WPN_SLING;
+ you.inv[1].plus = 0; // slings aren't so good
+ you.inv[1].plus2 = 0; // so we'll make them +0
+
+ you.inv[3].quantity = 0; // remove potion
+ you.inv[3].base_type = 0; // forget potion
+ you.inv[3].sub_type = 0;
+ }
+ else if (you.skills[ SK_BOWS ])
+ {
+ you.inv[4].sub_type = MI_ARROW;
+ you.inv[4].colour = BROWN;
+ you.inv[1].sub_type = WPN_BOW;
+
+ you.inv[3].quantity = 0; // remove potion
+ you.inv[3].base_type = 0; // forget potion
+ you.inv[3].sub_type = 0;
+ }
+ else if (you.skills[ SK_CROSSBOWS ])
+ {
+ // Hand crossbows want the darts.
+ you.inv[1].sub_type = WPN_HAND_CROSSBOW;
+
+ you.inv[3].quantity = 0; // remove potion
+ you.inv[3].base_type = 0; // forget potion
+ you.inv[3].sub_type = 0;
+ }
+ else
+ {
+ // little extra poisoned darts for throwers
+ you.inv[4].quantity += random2avg(10,5);
+ set_item_ego_type( you.inv[4], OBJ_MISSILES, SPMSL_POISONED );
+
+ you.inv[0].sub_type = WPN_DAGGER; // up knife to dagger
+ you.inv[1].quantity = 0; // remove bow
+ }
+ }
+#endif
+ else
+ {
+ // Generic wanderer
+ give_wanderer_weapon( 0, wpn_skill );
+ give_random_secondary_armour(5);
+ }
+
+ you.equip[EQ_WEAPON] = 0;
+ you.equip[EQ_BODY_ARMOUR] = 2;
+}
+
+// choose_race returns true if the player should also pick a class.
+// This is done because of the '*' option which will pick a random
+// character, obviating the necessity of choosing a class.
+
+bool choose_race()
+{
+ char keyn;
+
+ bool printed = false;
+ if (Options.race != 0)
+ printed = true;
+
+spec_query:
+ if (!printed)
+ {
+ clrscr();
+
+ textcolor( WHITE );
+ cprintf("You must be new here!" EOL EOL);
+
+ textcolor( CYAN );
+ cprintf("You can be:" EOL EOL);
+ textcolor( LIGHTGREY );
+
+ cprintf("a - Human b - Elf" EOL);
+ cprintf("c - High Elf d - Grey Elf" EOL);
+ cprintf("e - Deep Elf f - Sludge Elf" EOL);
+ cprintf("g - Hill Dwarf h - Mountain Dwarf" EOL);
+ cprintf("i - Halfling j - Hill Orc" EOL);
+ cprintf("k - Kobold l - Mummy" EOL);
+ cprintf("m - Naga n - Gnome" EOL);
+ cprintf("o - Ogre p - Troll" EOL);
+ cprintf("q - Ogre-Mage r - Draconian" EOL);
+ cprintf("s - Centaur t - Demigod" EOL);
+ cprintf("u - Spriggan v - Minotaur" EOL);
+ cprintf("w - Demonspawn x - Ghoul" EOL);
+ cprintf("y - Kenku z - Merfolk" EOL);
+
+ textcolor( BROWN );
+ cprintf(EOL "? - Random Species * - Random Character" EOL);
+ cprintf( "X - Quit" EOL);
+
+ textcolor( CYAN );
+ cprintf(EOL "Which one? ");
+ textcolor( LIGHTGREY );
+
+ printed = true;
+ }
+
+ if (Options.race != 0)
+ {
+ keyn = Options.race;
+ }
+ else
+ {
+ keyn = getch();
+ if (keyn == 0)
+ {
+ getch();
+ goto spec_query;
+ }
+ }
+
+ if (keyn == '?')
+ keyn = 'a' + random2(26);
+ else if (keyn == '*')
+ {
+ pick_random_species_and_class();
+ Options.random_pick = true; // used to give random weapon/god as well
+ return false;
+ }
+
+
+ switch (keyn)
+ {
+ case 'a':
+ you.species = SP_HUMAN;
+ break;
+ case 'b':
+ you.species = SP_ELF;
+ break;
+ case 'c':
+ you.species = SP_HIGH_ELF;
+ break;
+ case 'd':
+ you.species = SP_GREY_ELF;
+ break;
+ case 'e':
+ you.species = SP_DEEP_ELF;
+ break;
+ case 'f':
+ you.species = SP_SLUDGE_ELF;
+ break;
+ case 'g':
+ you.species = SP_HILL_DWARF;
+ break;
+ case 'h':
+ you.species = SP_MOUNTAIN_DWARF;
+ break;
+ case 'i':
+ you.species = SP_HALFLING;
+ break;
+ case 'j':
+ you.species = SP_HILL_ORC;
+ break;
+ case 'k':
+ you.species = SP_KOBOLD;
+ break;
+ case 'l':
+ you.species = SP_MUMMY;
+ break;
+ case 'm':
+ you.species = SP_NAGA;
+ break;
+ case 'n':
+ you.species = SP_GNOME;
+ break;
+ case 'o':
+ you.species = SP_OGRE;
+ break;
+ case 'p':
+ you.species = SP_TROLL;
+ break;
+ case 'q':
+ you.species = SP_OGRE_MAGE;
+ break;
+ case 'r': // draconian
+ you.species = SP_RED_DRACONIAN + random2(9); // random drac
+ break;
+ case 's':
+ you.species = SP_CENTAUR;
+ break;
+ case 't':
+ you.species = SP_DEMIGOD;
+ break;
+ case 'u':
+ you.species = SP_SPRIGGAN;
+ break;
+ case 'v':
+ you.species = SP_MINOTAUR;
+ break;
+ case 'w':
+ you.species = SP_DEMONSPAWN;
+ break;
+ case 'x':
+ you.species = SP_GHOUL;
+ break;
+ case 'y':
+ you.species = SP_KENKU;
+ break;
+ case 'z':
+ you.species = SP_MERFOLK;
+ break;
+ case 'X':
+ cprintf(EOL "Goodbye!");
+ end(0);
+ break;
+ default:
+ if (Options.race != 0)
+ {
+ Options.race = 0;
+ printed = false;
+ }
+ goto spec_query;
+ }
+
+ // set to 0 in case we come back from choose_class()
+ Options.race = 0;
+
+ return true;
+}
+
+// returns true if a class was chosen, false if we should go back to
+// race selection.
+
+bool choose_class(void)
+{
+ char keyn;
+ int i,j;
+
+ bool printed = false;
+ if (Options.cls != 0)
+ printed = true;
+job_query:
+ if (!printed)
+ {
+ clrscr();
+
+ textcolor( BROWN );
+ cprintf(EOL EOL);
+ cprintf("Welcome, ");
+ textcolor( YELLOW );
+ if (strlen(you.your_name) > 0)
+ {
+ cprintf(you.your_name);
+ cprintf(" the ");
+ }
+ cprintf(species_name(you.species,you.experience_level));
+ cprintf("." EOL EOL);
+
+ textcolor( CYAN );
+ cprintf("You can be any of the following :" EOL);
+ textcolor( LIGHTGREY );
+
+ j = 0; // used within for loop to determine newline {dlb}
+
+ for (i = 0; i < NUM_JOBS; i++)
+ {
+ if (!class_allowed(you.species, i))
+ continue;
+
+ putch( index_to_letter(i) );
+ cprintf( " - " );
+ cprintf( get_class_name(i) );
+
+ if (j % 2)
+ cprintf(EOL);
+ else
+ gotoxy(40, wherey());
+
+ j++;
+ }
+
+ if (wherex() >= 40)
+ cprintf(EOL);
+
+ textcolor( BROWN );
+ cprintf(EOL "? - Random; x - Back to species selection; X - Quit" EOL);
+
+ textcolor( CYAN );
+ cprintf(EOL "What kind of character are you? ");
+ textcolor( LIGHTGREY );
+
+ printed = true;
+ }
+
+ if (Options.cls != 0)
+ {
+ keyn = Options.cls;
+ }
+ else
+ {
+ keyn = getch();
+ if (keyn == 0)
+ {
+ getch();
+ goto job_query;
+ }
+ }
+
+ if (keyn == 'a')
+ you.char_class = JOB_FIGHTER;
+ else if (keyn == 'b')
+ you.char_class = JOB_WIZARD;
+ else if (keyn == 'c')
+ you.char_class = JOB_PRIEST;
+ else if (keyn == 'd')
+ you.char_class = JOB_THIEF;
+ else if (keyn == 'e')
+ you.char_class = JOB_GLADIATOR;
+ else if (keyn == 'f')
+ you.char_class = JOB_NECROMANCER;
+ else if (keyn == 'g')
+ you.char_class = JOB_PALADIN;
+ else if (keyn == 'h')
+ you.char_class = JOB_ASSASSIN;
+ else if (keyn == 'i')
+ you.char_class = JOB_BERSERKER;
+ else if (keyn == 'j')
+ you.char_class = JOB_HUNTER;
+ else if (keyn == 'k')
+ you.char_class = JOB_CONJURER;
+ else if (keyn == 'l')
+ you.char_class = JOB_ENCHANTER;
+ else if (keyn == 'm')
+ you.char_class = JOB_FIRE_ELEMENTALIST;
+ else if (keyn == 'n')
+ you.char_class = JOB_ICE_ELEMENTALIST;
+ else if (keyn == 'o')
+ you.char_class = JOB_SUMMONER;
+ else if (keyn == 'p')
+ you.char_class = JOB_AIR_ELEMENTALIST;
+ else if (keyn == 'q')
+ you.char_class = JOB_EARTH_ELEMENTALIST;
+ else if (keyn == 'r')
+ you.char_class = JOB_CRUSADER;
+ else if (keyn == 's')
+ you.char_class = JOB_DEATH_KNIGHT;
+ else if (keyn == 't')
+ you.char_class = JOB_VENOM_MAGE;
+ else if (keyn == 'u')
+ you.char_class = JOB_CHAOS_KNIGHT;
+ else if (keyn == 'v')
+ you.char_class = JOB_TRANSMUTER;
+ else if (keyn == 'w')
+ you.char_class = JOB_HEALER;
+ else if (keyn == 'y')
+ you.char_class = JOB_REAVER;
+ else if (keyn == 'z')
+ you.char_class = JOB_STALKER;
+ else if (keyn == 'A')
+ you.char_class = JOB_MONK;
+ else if (keyn == 'B')
+ you.char_class = JOB_WARPER;
+ else if (keyn == 'C')
+ you.char_class = JOB_WANDERER;
+ else if (keyn == '?')
+ {
+ // pick a job at random... see god retribution for proof this
+ // is uniform. -- bwr
+ int job_count = 0;
+ int job = -1;
+
+ for (int i = 0; i < NUM_JOBS; i++)
+ {
+ if (class_allowed(you.species, i))
+ {
+ job_count++;
+ if (one_chance_in( job_count ))
+ job = i;
+ }
+ }
+
+ ASSERT( job != -1 ); // at least one class should have been allowed
+ you.char_class = job;
+ }
+ else if (keyn == 'x' || keyn == ESCAPE)
+ {
+ return false;
+ }
+ else if (keyn == 'X')
+ {
+ cprintf(EOL "Goodbye!");
+ end(0);
+ }
+ else
+ {
+ if (Options.cls != 0)
+ {
+ Options.cls = 0;
+ printed = false;
+ }
+ goto job_query;
+ }
+
+ if (!class_allowed(you.species, you.char_class))
+ {
+ if (Options.cls != 0)
+ {
+ Options.cls = 0;
+ printed = false;
+ }
+ goto job_query;
+ }
+
+ return true;
+}
+
+
+void give_items_skills()
+{
+ char keyn;
+ int weap_skill = 0;
+ int to_hit_bonus; // used for assigning primary weapons {dlb}
+ int choice; // used for third-screen choices
+ int tmp;
+
+ switch (you.char_class)
+ {
+ case JOB_FIGHTER:
+ you.inv[0].quantity = 1;
+ you.inv[0].base_type = OBJ_WEAPONS;
+ you.inv[0].sub_type = WPN_SHORT_SWORD;
+ you.inv[0].plus = 0;
+ you.inv[0].plus2 = 0;
+ you.inv[0].special = 0;
+ you.inv[0].colour = LIGHTCYAN;
+
+ if (you.species == SP_OGRE || you.species == SP_TROLL
+ || player_genus(GENPC_DRACONIAN))
+ {
+ you.inv[1].quantity = 1;
+ you.inv[1].base_type = OBJ_ARMOUR;
+ you.inv[1].sub_type = ARM_ANIMAL_SKIN;
+ you.inv[1].plus = 0;
+ you.inv[1].special = 0;
+ you.inv[1].colour = BROWN;
+
+ if (you.species == SP_OGRE)
+ {
+ you.inv[0].quantity = 1;
+ you.inv[0].base_type = OBJ_WEAPONS;
+ you.inv[0].sub_type = WPN_CLUB;
+ you.inv[0].plus = 0;
+ you.inv[0].special = 0;
+ you.inv[0].colour = BROWN;
+
+ }
+ else if (you.species == SP_TROLL)
+ {
+ you.inv[0].quantity = 0;
+ you.inv[0].base_type = OBJ_WEAPONS;
+ you.inv[0].sub_type = WPN_CLUB;
+ you.inv[0].plus = 0;
+ you.inv[0].special = 0;
+ you.inv[0].colour = BROWN;
+
+ }
+ else if (player_genus(GENPC_DRACONIAN))
+ {
+ you.inv[2].quantity = 1;
+ you.inv[2].base_type = OBJ_ARMOUR;
+ you.inv[2].sub_type = ARM_SHIELD;
+ you.inv[2].plus = 0;
+ you.inv[2].special = 0;
+ you.inv[2].colour = LIGHTCYAN;
+ }
+ }
+ else if (you.species == SP_GHOUL || you.species == SP_MUMMY)
+ {
+ you.inv[1].quantity = 1;
+ you.inv[1].base_type = OBJ_ARMOUR;
+ you.inv[1].sub_type = ARM_ROBE;
+ you.inv[1].plus = 0;
+ you.inv[1].special = 0;
+ you.inv[1].colour = WHITE; // grave shroud
+
+ if (you.species == SP_MUMMY)
+ {
+ you.inv[2].quantity = 1;
+ you.inv[2].base_type = OBJ_ARMOUR;
+ you.inv[2].sub_type = ARM_SHIELD;
+ you.inv[2].plus = 0;
+ you.inv[2].special = 0;
+ you.inv[2].colour = LIGHTCYAN;
+ }
+ }
+ else if (you.species == SP_KOBOLD)
+ {
+ you.inv[1].quantity = 1;
+ you.inv[1].base_type = OBJ_ARMOUR;
+ you.inv[1].sub_type = ARM_LEATHER_ARMOUR;
+ you.inv[1].plus = 0;
+ you.inv[1].special = 0;
+ you.inv[1].colour = BROWN;
+
+ you.inv[2].base_type = OBJ_MISSILES;
+ you.inv[2].sub_type = MI_DART;
+ you.inv[2].quantity = 10 + roll_dice( 2, 10 );
+ you.inv[2].plus = 0;
+ you.inv[2].special = 0;
+ you.inv[2].colour = LIGHTCYAN;
+
+ }
+ else
+ {
+ you.inv[1].quantity = 1;
+ you.inv[1].base_type = OBJ_ARMOUR;
+ you.inv[1].sub_type = ARM_SCALE_MAIL;
+ you.inv[1].plus = 0;
+ you.inv[1].special = 0;
+ you.inv[1].colour = LIGHTCYAN;
+
+ you.inv[2].quantity = 1;
+ you.inv[2].base_type = OBJ_ARMOUR;
+ you.inv[2].sub_type = ARM_SHIELD;
+ you.inv[2].plus = 0;
+ you.inv[2].special = 0;
+ you.inv[2].colour = LIGHTCYAN;
+
+ choose_weapon();
+ }
+
+ if (you.species != SP_TROLL)
+ you.equip[EQ_WEAPON] = 0;
+
+ you.equip[EQ_BODY_ARMOUR] = 1;
+
+ if (you.species != SP_KOBOLD && you.species != SP_OGRE
+ && you.species != SP_TROLL && you.species != SP_GHOUL)
+ {
+ you.equip[EQ_SHIELD] = 2;
+ }
+
+ you.skills[SK_FIGHTING] = 3;
+
+ weap_skill = 2;
+
+ if (you.species == SP_KOBOLD)
+ {
+ you.skills[SK_THROWING] = 1;
+ you.skills[SK_DARTS] = 1;
+ you.skills[SK_DODGING] = 1;
+ you.skills[SK_STEALTH] = 1;
+ you.skills[SK_STABBING] = 1;
+ you.skills[SK_DODGING + random2(3)] += 1;
+ }
+ else if (you.species == SP_OGRE || you.species == SP_TROLL)
+ {
+ if (you.species == SP_TROLL) //jmf: these guys get no weapon!
+ you.skills[SK_UNARMED_COMBAT] += 3;
+ else
+ you.skills[SK_FIGHTING] += 2;
+
+ // BWR sez Ogres & Trolls should probably start w/ Dodge 2 -- GDL
+ you.skills[SK_DODGING] = 3;
+ }
+ else
+ {
+ // Players get dodging or armour skill depending on their
+ // starting armour now (note: the armour has to be quiped
+ // for this function to work)
+
+ you.skills[(player_light_armour()? SK_DODGING : SK_ARMOUR)] = 2;
+
+ you.skills[SK_SHIELDS] = 2;
+ you.skills[SK_THROWING] = 2;
+ you.skills[(coinflip() ? SK_STABBING : SK_SHIELDS)]++;
+ }
+ break;
+
+ case JOB_WIZARD:
+ you.inv[0].quantity = 1;
+ you.inv[0].base_type = OBJ_WEAPONS;
+
+ if (you.species == SP_OGRE_MAGE)
+ {
+ you.inv[0].sub_type = WPN_QUARTERSTAFF;
+ you.inv[0].colour = BROWN;
+ }
+ else if (player_genus(GENPC_DWARVEN))
+ {
+ you.inv[0].sub_type = WPN_HAMMER;
+ you.inv[0].colour = CYAN;
+ }
+ else
+ {
+ you.inv[0].sub_type = WPN_DAGGER;
+ you.inv[0].colour = LIGHTCYAN;
+ }
+
+ you.inv[0].plus = 0;
+ you.inv[0].plus2 = 0;
+ you.inv[0].special = 0;
+
+ you.inv[1].quantity = 1;
+ you.inv[1].base_type = OBJ_ARMOUR;
+ you.inv[1].sub_type = ARM_ROBE;
+ you.inv[1].plus = 0;
+
+ switch (random2(7))
+ {
+ case 0:
+ case 1:
+ default:
+ set_equip_desc( you.inv[1], ISFLAG_EMBROIDERED_SHINY );
+ break;
+ case 2:
+ case 3:
+ set_equip_desc( you.inv[1], ISFLAG_GLOWING );
+ break;
+ case 4:
+ case 5:
+ set_equip_desc( you.inv[1], ISFLAG_RUNED );
+ break;
+ case 6:
+ set_equip_race( you.inv[1], ISFLAG_ELVEN );
+ break;
+ }
+
+
+ you.inv[1].colour = random_colour();
+ you.equip[EQ_WEAPON] = 0;
+ you.equip[EQ_BODY_ARMOUR] = 1;
+
+ // extra items being tested:
+ you.inv[2].base_type = OBJ_BOOKS;
+ you.inv[2].sub_type = BOOK_MINOR_MAGIC_I + random2(3);
+ you.inv[2].quantity = 1;
+ you.inv[2].plus = 0; // = 127
+ you.inv[2].special = 1;
+ you.inv[2].colour = CYAN;
+
+ you.skills[SK_DODGING] = 1;
+ you.skills[SK_STEALTH] = 1;
+ you.skills[(coinflip() ? SK_DODGING : SK_STEALTH)]++;
+ you.skills[SK_SPELLCASTING] = 2;
+ you.skills[SK_CONJURATIONS] = 1;
+ you.skills[SK_ENCHANTMENTS] = 1;
+ you.skills[SK_SPELLCASTING + random2(3)]++;
+ you.skills[SK_SUMMONINGS + random2(5)]++;
+
+ if (player_genus(GENPC_DWARVEN))
+ you.skills[SK_MACES_FLAILS] = 1;
+ else
+ you.skills[SK_SHORT_BLADES] = 1;
+
+ you.skills[SK_STAVES] = 1;
+ break;
+
+ case JOB_PRIEST:
+ you.piety = 45;
+
+ you.inv[0].quantity = 1;
+ you.inv[0].base_type = OBJ_WEAPONS;
+ you.inv[0].sub_type = WPN_MACE; //jmf: moved from "case 'b'" below
+ you.inv[0].plus = 0;
+ you.inv[0].plus2 = 0;
+ you.inv[0].special = 0;
+ you.inv[0].colour = LIGHTCYAN;
+
+ you.inv[1].quantity = 1;
+ you.inv[1].base_type = OBJ_ARMOUR;
+ you.inv[1].sub_type = ARM_ROBE;
+ you.inv[1].plus = 0;
+ you.inv[1].special = 0;
+ you.inv[1].colour = WHITE;
+
+ you.inv[2].base_type = OBJ_POTIONS;
+ you.inv[2].sub_type = POT_HEALING;
+ you.inv[2].quantity = 2;
+ you.inv[2].plus = 0;
+
+ you.equip[EQ_WEAPON] = 0;
+
+ you.equip[EQ_BODY_ARMOUR] = 1;
+
+ you.skills[SK_FIGHTING] = 2;
+ you.skills[SK_DODGING] = 1;
+ you.skills[SK_SHIELDS] = 1;
+ you.skills[SK_MACES_FLAILS] = 2;
+ you.skills[SK_STAVES] = 1;
+
+ you.skills[SK_INVOCATIONS] = 4;
+
+ if (Options.priest != GOD_NO_GOD && Options.priest != GOD_RANDOM)
+ you.religion = Options.priest;
+ else if (Options.random_pick || Options.priest == GOD_RANDOM)
+ you.religion = coinflip() ? GOD_YREDELEMNUL : GOD_ZIN;
+ else
+ {
+ clrscr();
+
+ textcolor( CYAN );
+ cprintf(EOL " Which god do you wish to serve?" EOL);
+
+ textcolor( LIGHTGREY );
+ cprintf("a - Zin (for traditional priests)" EOL);
+ cprintf("b - Yredelemnul (for priests of death)" EOL);
+
+ getkey:
+ keyn = get_ch();
+
+ switch (keyn)
+ {
+ case 'a':
+ you.religion = GOD_ZIN;
+ break;
+ case 'b':
+ you.religion = GOD_YREDELEMNUL;
+ break;
+ default:
+ goto getkey;
+ }
+ }
+ break;
+
+ case JOB_THIEF:
+ you.inv[0].quantity = 1;
+ you.inv[0].base_type = OBJ_WEAPONS;
+ you.inv[0].sub_type = WPN_SHORT_SWORD;
+
+ you.inv[0].plus = 0;
+ you.inv[0].plus2 = 0;
+ you.inv[0].special = 0;
+ you.inv[0].colour = LIGHTCYAN;
+
+ you.inv[1].quantity = 1;
+ you.inv[1].base_type = OBJ_WEAPONS;
+ you.inv[1].sub_type = WPN_DAGGER;
+
+ you.inv[1].plus = 0;
+ you.inv[1].plus2 = 0;
+ you.inv[1].special = 0;
+ you.inv[1].colour = LIGHTCYAN;
+
+ you.inv[2].quantity = 1;
+ you.inv[2].base_type = OBJ_ARMOUR;
+ you.inv[2].sub_type = ARM_ROBE;
+ you.inv[2].plus = 0;
+ you.inv[2].special = 0;
+ you.inv[2].colour = BROWN;
+
+ you.inv[3].quantity = 1;
+ you.inv[3].base_type = OBJ_ARMOUR;
+ you.inv[3].sub_type = ARM_CLOAK;
+ you.inv[3].plus = 0;
+ you.inv[3].special = 0;
+ you.inv[3].colour = DARKGREY;
+
+ you.inv[4].base_type = OBJ_MISSILES;
+ you.inv[4].sub_type = MI_DART;
+ you.inv[4].quantity = 10 + roll_dice( 2, 10 );
+ you.inv[4].plus = 0;
+ you.inv[4].special = 0;
+ you.inv[4].colour = LIGHTCYAN;
+
+ you.equip[EQ_WEAPON] = 0;
+ you.equip[EQ_BODY_ARMOUR] = 2;
+ you.equip[EQ_CLOAK] = 3;
+
+ you.skills[SK_FIGHTING] = 1;
+ you.skills[SK_SHORT_BLADES] = 2;
+ you.skills[SK_DODGING] = 2;
+ you.skills[SK_STEALTH] = 2;
+ you.skills[SK_STABBING] = 1;
+ you.skills[SK_DODGING + random2(3)]++;
+ you.skills[SK_THROWING] = 1;
+ you.skills[SK_DARTS] = 1;
+ you.skills[SK_TRAPS_DOORS] = 2;
+ break;
+
+ case JOB_GLADIATOR:
+ you.inv[0].quantity = 1;
+ you.inv[0].base_type = OBJ_WEAPONS;
+ you.inv[0].sub_type = WPN_SHORT_SWORD;
+ choose_weapon();
+
+ you.inv[0].plus = 0;
+ you.inv[0].plus2 = 0;
+ you.inv[0].special = 0;
+ you.inv[0].colour = LIGHTCYAN;
+
+ if (player_genus(GENPC_DRACONIAN))
+ {
+ you.inv[1].quantity = 1;
+ you.inv[1].base_type = OBJ_ARMOUR;
+ you.inv[1].sub_type = ARM_ANIMAL_SKIN;
+ you.inv[1].plus = 0;
+ you.inv[1].special = 0;
+ you.inv[1].colour = BROWN;
+
+ you.inv[2].quantity = 1;
+ you.inv[2].base_type = OBJ_ARMOUR;
+ you.inv[2].sub_type = ARM_SHIELD;
+ you.inv[2].plus = 0;
+ you.inv[2].special = 0;
+ you.inv[2].colour = LIGHTCYAN;
+ }
+ else
+ {
+ you.inv[1].quantity = 1;
+ you.inv[1].base_type = OBJ_ARMOUR;
+ you.inv[1].sub_type = ARM_RING_MAIL;
+ you.inv[1].plus = 0;
+ you.inv[1].special = 0;
+ you.inv[1].colour = LIGHTCYAN;
+
+ you.inv[2].quantity = 1;
+ you.inv[2].base_type = OBJ_ARMOUR;
+ you.inv[2].sub_type = ARM_BUCKLER;
+ you.inv[2].plus = 0;
+ you.inv[2].special = 0;
+ you.inv[2].colour = LIGHTCYAN;
+ }
+
+ you.equip[EQ_WEAPON] = 0;
+ you.equip[EQ_BODY_ARMOUR] = 1;
+ you.equip[EQ_SHIELD] = 2;
+
+ you.skills[SK_FIGHTING] = 3;
+ weap_skill = 3;
+
+ if (player_genus(GENPC_DRACONIAN))
+ you.skills[SK_DODGING] = 2;
+ else
+ you.skills[SK_ARMOUR] = 2;
+
+ you.skills[SK_SHIELDS] = 1;
+ you.skills[SK_UNARMED_COMBAT] = 2;
+ break;
+
+
+ case JOB_NECROMANCER:
+ you.inv[0].quantity = 1;
+ you.inv[0].base_type = OBJ_WEAPONS;
+ you.inv[0].sub_type = WPN_DAGGER;
+ you.inv[0].plus = 0;
+ you.inv[0].plus2 = 0;
+ you.inv[0].special = 0;
+ you.inv[0].colour = LIGHTCYAN;
+ you.inv[1].quantity = 1;
+ you.inv[1].base_type = OBJ_ARMOUR;
+ you.inv[1].sub_type = ARM_ROBE;
+ you.inv[1].plus = 0;
+ you.inv[1].special = 0;
+ you.inv[1].colour = DARKGREY;
+ you.equip[EQ_WEAPON] = 0;
+ you.equip[EQ_BODY_ARMOUR] = 1;
+
+ you.inv[2].base_type = OBJ_BOOKS;
+ you.inv[2].sub_type = BOOK_NECROMANCY;
+ you.inv[2].quantity = 1;
+ you.inv[2].plus = 0; // = 127
+ you.inv[2].special = 0; // = 1;
+ you.inv[2].colour = DARKGREY;
+
+ you.skills[SK_DODGING] = 1;
+ you.skills[SK_STEALTH] = 1;
+ you.skills[(coinflip()? SK_DODGING : SK_STEALTH)]++;
+ you.skills[SK_SPELLCASTING] = 1;
+ you.skills[SK_NECROMANCY] = 4;
+ you.skills[SK_SHORT_BLADES] = 1;
+ you.skills[SK_STAVES] = 1;
+ break;
+
+ case JOB_PALADIN:
+ you.religion = GOD_SHINING_ONE;
+ you.piety = 28;
+
+ you.inv[0].quantity = 1;
+ you.inv[0].base_type = OBJ_WEAPONS;
+ you.inv[0].sub_type = WPN_FALCHION;
+ you.inv[0].plus = 0;
+ you.inv[0].plus2 = 0;
+ you.inv[0].special = 0;
+ you.inv[0].colour = LIGHTCYAN;
+
+ you.inv[1].quantity = 1;
+ you.inv[1].base_type = OBJ_ARMOUR;
+ you.inv[1].sub_type = ARM_ROBE;
+ you.inv[1].plus = 0;
+ you.inv[1].special = 0;
+ you.inv[1].colour = WHITE;
+
+ you.inv[2].quantity = 1;
+ you.inv[2].base_type = OBJ_ARMOUR;
+ you.inv[2].sub_type = ARM_SHIELD;
+ you.inv[2].plus = 0;
+ you.inv[2].special = 0;
+ you.inv[2].colour = LIGHTCYAN;
+
+ you.equip[EQ_WEAPON] = 0;
+ you.equip[EQ_BODY_ARMOUR] = 1;
+ you.equip[EQ_SHIELD] = 2;
+
+ you.inv[3].base_type = OBJ_POTIONS;
+ you.inv[3].sub_type = POT_HEALING;
+ you.inv[3].quantity = 1;
+ you.inv[3].plus = 0;
+
+ you.skills[SK_FIGHTING] = 2;
+ you.skills[SK_ARMOUR] = 1;
+ you.skills[SK_DODGING] = 1;
+ you.skills[(coinflip()? SK_ARMOUR : SK_DODGING)]++;
+ you.skills[SK_SHIELDS] = 2;
+ you.skills[SK_LONG_SWORDS] = 3;
+ you.skills[SK_INVOCATIONS] = 2;
+ break;
+
+ case JOB_ASSASSIN:
+ you.inv[0].quantity = 1;
+ you.inv[0].base_type = OBJ_WEAPONS;
+ you.inv[0].sub_type = WPN_DAGGER;
+ to_hit_bonus = random2(3);
+ you.inv[0].plus = 1 + to_hit_bonus;
+ you.inv[0].plus2 = 1 + (2 - to_hit_bonus);
+ you.inv[0].special = 0;
+ you.inv[0].colour = LIGHTCYAN;
+
+ you.inv[1].quantity = 1;
+ you.inv[1].base_type = OBJ_WEAPONS;
+ you.inv[1].sub_type = WPN_BLOWGUN;
+ you.inv[1].plus = 0;
+ you.inv[1].plus2 = 0;
+ you.inv[1].special = 0;
+ you.inv[1].colour = LIGHTGREY;
+
+ you.inv[2].quantity = 1;
+ you.inv[2].base_type = OBJ_ARMOUR;
+ you.inv[2].sub_type = ARM_ROBE;
+ you.inv[2].plus = 0;
+ you.inv[2].special = 0;
+ you.inv[2].colour = DARKGREY;
+
+ you.inv[3].quantity = 1;
+ you.inv[3].base_type = OBJ_ARMOUR;
+ you.inv[3].sub_type = ARM_CLOAK;
+ you.inv[3].plus = 0;
+ you.inv[3].special = 0;
+ you.inv[3].colour = DARKGREY;
+
+ you.inv[4].base_type = OBJ_MISSILES;
+ you.inv[4].sub_type = MI_NEEDLE;
+ you.inv[4].quantity = 10 + roll_dice( 2, 10 );
+ you.inv[4].plus = 0;
+ you.inv[4].colour = WHITE;
+ set_item_ego_type( you.inv[4], OBJ_MISSILES, SPMSL_POISONED );
+
+ // deep elves get hand crossbows, everyone else gets blowguns
+ // (deep elves tend to suck at melee and need something that
+ // can do ranged damage)
+ if (you.species == SP_DEEP_ELF)
+ {
+ you.inv[1].sub_type = WPN_HAND_CROSSBOW;
+ you.inv[1].colour = BROWN;
+
+ you.inv[4].sub_type = MI_DART;
+ you.inv[4].colour = LIGHTCYAN;
+ }
+
+
+ you.equip[EQ_WEAPON] = 0;
+ you.equip[EQ_BODY_ARMOUR] = 2;
+ you.equip[EQ_CLOAK] = 3;
+
+ you.skills[SK_FIGHTING] = 2;
+ you.skills[SK_SHORT_BLADES] = 2;
+ you.skills[SK_DODGING] = 1;
+ you.skills[SK_STEALTH] = 3;
+ you.skills[SK_STABBING] = 2;
+ you.skills[SK_THROWING] = 1;
+ you.skills[SK_DARTS] = 1;
+ if (you.species == SP_DEEP_ELF)
+ you.skills[SK_CROSSBOWS] = 1;
+ else
+ you.skills[SK_THROWING] += 1;
+
+ break;
+
+ case JOB_BERSERKER:
+ you.religion = GOD_TROG;
+ you.piety = 35;
+
+ // WEAPONS
+ if (you.species == SP_OGRE)
+ {
+ you.inv[0].quantity = 1;
+ you.inv[0].base_type = OBJ_WEAPONS;
+ you.inv[0].sub_type = WPN_CLUB;
+ you.inv[0].plus = 0;
+ you.inv[0].plus2 = 0;
+ you.inv[0].special = 0;
+ you.inv[0].colour = LIGHTCYAN;
+ you.equip[EQ_WEAPON] = 0;
+ }
+ else if (you.species == SP_TROLL)
+ {
+ you.equip[EQ_WEAPON] = -1;
+ }
+ else
+ {
+ you.inv[0].quantity = 1;
+ you.inv[0].base_type = OBJ_WEAPONS;
+ you.inv[0].sub_type = WPN_HAND_AXE;
+ you.inv[0].plus = 0;
+ you.inv[0].plus2 = 0;
+ you.inv[0].special = 0;
+ you.inv[0].colour = LIGHTCYAN;
+ you.equip[EQ_WEAPON] = 0;
+
+ for (unsigned char i = 1; i <= 3; i++)
+ {
+ you.inv[i].quantity = 1;
+ you.inv[i].base_type = OBJ_WEAPONS;
+ you.inv[i].sub_type = WPN_SPEAR;
+ you.inv[i].plus = 0;
+ you.inv[i].plus2 = 0;
+ you.inv[i].special = 0;
+ you.inv[i].colour = LIGHTCYAN;
+ }
+ }
+
+ // ARMOUR
+
+ if (you.species == SP_OGRE || you.species == SP_TROLL
+ || player_genus(GENPC_DRACONIAN))
+ {
+ you.inv[1].quantity = 1;
+ you.inv[1].base_type = OBJ_ARMOUR;
+ you.inv[1].sub_type = ARM_ANIMAL_SKIN;
+ you.inv[1].plus = 0;
+ you.inv[1].special = 0;
+ you.inv[1].colour = BROWN;
+ you.equip[EQ_BODY_ARMOUR] = 1;
+ }
+ else
+ {
+ you.inv[4].quantity = 1;
+ you.inv[4].base_type = OBJ_ARMOUR;
+ you.inv[4].sub_type = ARM_LEATHER_ARMOUR;
+ you.inv[4].plus = 0;
+ you.inv[4].special = 0;
+ you.inv[4].colour = BROWN;
+ you.equip[EQ_BODY_ARMOUR] = 4;
+ }
+
+ // SKILLS
+ you.skills[SK_FIGHTING] = 2;
+
+ if (you.species == SP_TROLL)
+ {
+ // no wep - give them unarmed.
+ you.skills[SK_FIGHTING] += 3;
+ you.skills[SK_DODGING] = 2;
+ you.skills[SK_UNARMED_COMBAT] = 2;
+ }
+ else if (you.species == SP_OGRE)
+ {
+ you.skills[SK_FIGHTING] += 3;
+ you.skills[SK_AXES] = 1;
+ you.skills[SK_MACES_FLAILS] = 3;
+ }
+ else
+ {
+ you.skills[SK_AXES] = 3;
+ you.skills[SK_POLEARMS] = 1;
+ you.skills[SK_ARMOUR] = 2;
+ you.skills[SK_DODGING] = 2;
+ you.skills[SK_THROWING] = 2;
+ }
+ break;
+
+ case JOB_HUNTER:
+ you.inv[0].quantity = 1;
+ you.inv[0].base_type = OBJ_WEAPONS;
+ you.inv[0].sub_type = WPN_DAGGER;
+ you.inv[0].plus = 0;
+ you.inv[0].plus2 = 0;
+ you.inv[0].special = 0;
+ you.inv[0].colour = LIGHTCYAN;
+
+ you.inv[4].quantity = 1;
+ you.inv[4].base_type = OBJ_ARMOUR;
+ you.inv[4].sub_type = ARM_LEATHER_ARMOUR;
+ you.inv[4].plus = 0;
+ you.inv[4].special = 0;
+ you.inv[4].colour = BROWN;
+
+ if (you.species != SP_MERFOLK)
+ {
+ you.inv[2].quantity = 15 + random2avg(21, 5);
+ you.inv[2].base_type = OBJ_MISSILES;
+ you.inv[2].sub_type = MI_ARROW;
+ you.inv[2].plus = 0;
+ you.inv[2].plus2 = 0;
+ you.inv[2].special = 0;
+ you.inv[2].colour = BROWN;
+
+ you.inv[1].quantity = 1;
+ you.inv[1].base_type = OBJ_WEAPONS;
+ you.inv[1].sub_type = WPN_BOW;
+ you.inv[1].plus = 0;
+ you.inv[1].plus2 = 0;
+ you.inv[1].special = 0;
+ you.inv[1].colour = BROWN;
+ }
+ else
+ {
+ // Merfolk are spear hunters -- clobber bow, give three spears
+ for (unsigned char i = 1; i <= 3; i++)
+ {
+ you.inv[i].quantity = 1;
+ you.inv[i].base_type = OBJ_WEAPONS;
+ you.inv[i].sub_type = WPN_SPEAR;
+ you.inv[i].plus = 0;
+ you.inv[i].plus2 = 0;
+ you.inv[i].special = 0;
+ you.inv[i].colour = LIGHTCYAN;
+ }
+ }
+
+ if (player_genus(GENPC_DRACONIAN))
+ {
+ you.inv[4].sub_type = ARM_ROBE;
+ you.inv[4].colour = GREEN;
+ }
+
+ you.equip[EQ_WEAPON] = 0;
+ you.equip[EQ_BODY_ARMOUR] = 4;
+
+ you.skills[SK_FIGHTING] = 2;
+ you.skills[SK_THROWING] = 3;
+
+ // Removing spellcasting -- bwr
+ // you.skills[SK_SPELLCASTING] = 1;
+
+ switch (you.species)
+ {
+ case SP_HALFLING:
+ case SP_GNOME:
+ you.inv[2].quantity += random2avg(15, 2);
+ you.inv[2].sub_type = MI_STONE;
+ you.inv[2].colour = BROWN;
+ you.inv[1].sub_type = WPN_SLING;
+
+ you.skills[SK_DODGING] = 2;
+ you.skills[SK_STEALTH] = 2;
+ you.skills[SK_SLINGS] = 2;
+ break;
+
+ case SP_HILL_DWARF:
+ case SP_MOUNTAIN_DWARF:
+ case SP_HILL_ORC:
+ you.inv[2].sub_type = MI_BOLT;
+ you.inv[2].colour = LIGHTCYAN;
+ you.inv[1].sub_type = WPN_CROSSBOW;
+
+ if (you.species == SP_HILL_ORC)
+ {
+ you.inv[0].sub_type = WPN_SHORT_SWORD;
+ you.skills[SK_SHORT_BLADES] = 1;
+ }
+ else
+ {
+ you.inv[0].sub_type = WPN_HAND_AXE;
+ you.skills[SK_AXES] = 1;
+ }
+
+ you.skills[SK_DODGING] = 1;
+ you.skills[SK_SHIELDS] = 1;
+ you.skills[SK_CROSSBOWS] = 2;
+ break;
+
+ case SP_MERFOLK:
+ you.inv[0].sub_type = WPN_TRIDENT;
+
+ you.skills[SK_POLEARMS] = 2;
+ you.skills[SK_DODGING] = 2;
+ you.skills[SK_THROWING] += 1;
+ break;
+
+ default:
+ you.skills[SK_DODGING] = 1;
+ you.skills[SK_STEALTH] = 1;
+ you.skills[(coinflip() ? SK_STABBING : SK_SHIELDS)]++;
+ you.skills[SK_BOWS] = 2;
+ break;
+ }
+ break;
+
+ case JOB_CONJURER:
+ case JOB_ENCHANTER:
+ case JOB_SUMMONER:
+ case JOB_FIRE_ELEMENTALIST:
+ case JOB_ICE_ELEMENTALIST:
+ case JOB_AIR_ELEMENTALIST:
+ case JOB_EARTH_ELEMENTALIST:
+ case JOB_VENOM_MAGE:
+ you.inv[0].quantity = 1;
+ you.inv[0].base_type = OBJ_WEAPONS;
+ you.inv[0].sub_type = WPN_DAGGER;
+ you.inv[0].colour = LIGHTCYAN;
+ you.inv[0].plus = 0;
+ you.inv[0].plus2 = 0;
+ you.inv[0].special = 0;
+
+ you.inv[1].quantity = 1;
+ you.inv[1].base_type = OBJ_ARMOUR;
+ you.inv[1].sub_type = ARM_ROBE;
+ you.inv[1].plus = 0;
+
+ if (you.char_class == JOB_ENCHANTER)
+ {
+ you.inv[0].plus = 1;
+ you.inv[0].plus2 = 1;
+ you.inv[1].plus = 1;
+ }
+
+ you.inv[1].special = 0;
+
+ you.equip[EQ_WEAPON] = 0;
+ you.equip[EQ_BODY_ARMOUR] = 1;
+ you.inv[2].base_type = OBJ_BOOKS;
+ you.inv[2].sub_type = give_first_conjuration_book();
+ you.inv[2].plus = 0;
+
+ switch (you.char_class)
+ {
+ case JOB_SUMMONER:
+ you.inv[2].sub_type = BOOK_CALLINGS;
+
+ you.skills[SK_SUMMONINGS] = 4;
+
+ // gets some darts - this class is difficult to start off with
+ you.inv[3].base_type = OBJ_MISSILES;
+ you.inv[3].sub_type = MI_DART;
+ you.inv[3].quantity = 8 + roll_dice( 2, 8 );
+ you.inv[3].plus = 0;
+ you.inv[3].special = 0;
+ you.inv[3].colour = LIGHTCYAN;
+ break;
+
+ case JOB_CONJURER:
+ you.skills[SK_CONJURATIONS] = 4;
+ break;
+
+ case JOB_ENCHANTER:
+ you.inv[2].sub_type = BOOK_CHARMS;
+
+ you.skills[SK_ENCHANTMENTS] = 4;
+
+ // gets some darts - this class is difficult to start off with
+ you.inv[3].base_type = OBJ_MISSILES;
+ you.inv[3].sub_type = MI_DART;
+ you.inv[3].quantity = 8 + roll_dice( 2, 8 );
+ you.inv[3].plus = 1;
+ you.inv[3].special = 0;
+ you.inv[3].colour = LIGHTCYAN;
+
+ if (you.species == SP_SPRIGGAN)
+ {
+ you.inv[0].base_type = OBJ_STAVES;
+ you.inv[0].sub_type = STAFF_STRIKING;
+ you.inv[0].colour = BROWN;
+ }
+ break;
+
+ case JOB_FIRE_ELEMENTALIST:
+ you.inv[2].sub_type = BOOK_FLAMES;
+
+ you.skills[SK_CONJURATIONS] = 1;
+ you.skills[SK_FIRE_MAGIC] = 3;
+ //you.skills [SK_ENCHANTMENTS] = 1;
+ break;
+
+ case JOB_ICE_ELEMENTALIST:
+ you.inv[2].sub_type = BOOK_FROST;
+
+ you.skills[SK_CONJURATIONS] = 1;
+ you.skills[SK_ICE_MAGIC] = 3;
+ //you.skills [SK_ENCHANTMENTS] = 1;
+ break;
+
+ case JOB_AIR_ELEMENTALIST:
+ you.inv[2].sub_type = BOOK_AIR;
+
+ you.skills[SK_CONJURATIONS] = 1;
+ you.skills[SK_AIR_MAGIC] = 3;
+ //you.skills [SK_ENCHANTMENTS] = 1;
+ break;
+
+ case JOB_EARTH_ELEMENTALIST:
+ you.inv[2].sub_type = BOOK_GEOMANCY;
+
+ you.inv[3].quantity = random2avg(12, 2) + 6;
+ you.inv[3].base_type = OBJ_MISSILES;
+ you.inv[3].sub_type = MI_STONE;
+ you.inv[3].plus = 0;
+ you.inv[3].plus2 = 0;
+ you.inv[3].special = 0;
+ you.inv[3].colour = BROWN;
+
+ if (you.species == SP_GNOME)
+ {
+ you.inv[1].quantity = 1;
+ you.inv[1].base_type = OBJ_WEAPONS;
+ you.inv[1].sub_type = WPN_SLING;
+ you.inv[1].plus = 0;
+ you.inv[1].plus2 = 0;
+ you.inv[1].special = 0;
+ you.inv[1].colour = BROWN;
+
+ you.inv[4].quantity = 1;
+ you.inv[4].base_type = OBJ_ARMOUR;
+ you.inv[4].sub_type = ARM_ROBE;
+ you.inv[4].plus = 0;
+ you.inv[4].plus2 = 0;
+ you.inv[4].special = 0;
+ you.inv[4].colour = BROWN;
+ you.equip[EQ_BODY_ARMOUR] = 4;
+
+ }
+ you.skills[SK_TRANSMIGRATION] = 1;
+ you.skills[SK_EARTH_MAGIC] = 3;
+ break;
+
+ case JOB_VENOM_MAGE:
+ you.inv[2].sub_type = BOOK_YOUNG_POISONERS;
+ you.skills[SK_POISON_MAGIC] = 4;
+ break;
+ }
+
+ if (you.species == SP_OGRE_MAGE)
+ {
+ you.inv[0].sub_type = WPN_QUARTERSTAFF;
+ you.inv[0].colour = BROWN;
+ }
+ else if (player_genus(GENPC_DWARVEN))
+ {
+ you.inv[0].sub_type = WPN_HAMMER;
+ you.inv[0].colour = CYAN;
+ }
+
+ you.inv[2].quantity = 1;
+ you.inv[2].special = 0;
+
+ switch (you.char_class)
+ {
+ case JOB_FIRE_ELEMENTALIST: tmp = RED; break;
+ case JOB_ICE_ELEMENTALIST: tmp = LIGHTCYAN; break;
+ case JOB_AIR_ELEMENTALIST: tmp = LIGHTBLUE; break;
+ case JOB_EARTH_ELEMENTALIST: tmp = BROWN; break;
+ case JOB_VENOM_MAGE: tmp = GREEN; break;
+ default: tmp = random_colour(); break;
+ }
+
+ you.inv[1].colour = tmp; // robe
+ you.inv[2].colour = tmp; // book
+
+ you.skills[SK_SPELLCASTING] = 1;
+
+ // These summoner races start with polearms and should they
+ // get their hands on a polearm of reaching they should have
+ // lots of fun... -- bwr
+ if (you.char_class == JOB_SUMMONER
+ && (you.species == SP_MERFOLK || you.species == SP_HILL_ORC ||
+ you.species == SP_KENKU || you.species == SP_MINOTAUR))
+ {
+ if (you.species == SP_MERFOLK)
+ you.inv[0].sub_type = WPN_TRIDENT;
+ else
+ you.inv[0].sub_type = WPN_SPEAR;
+
+ you.skills[SK_POLEARMS] = 1;
+ }
+ else if (player_genus(GENPC_DWARVEN))
+ {
+ you.skills[SK_MACES_FLAILS] = 1;
+ }
+ else if (you.char_class == JOB_ENCHANTER && you.species == SP_SPRIGGAN)
+ {
+ you.skills[SK_EVOCATIONS] = 1;
+ }
+ else
+ {
+ you.skills[SK_SHORT_BLADES] = 1;
+ }
+
+ if (you.species == SP_GNOME)
+ you.skills[SK_SLINGS]++;
+ else
+ you.skills[SK_STAVES]++;
+
+ you.skills[SK_DODGING] = 1;
+ you.skills[SK_STEALTH] = 1;
+
+ if (you.species == SP_GNOME && you.char_class == JOB_EARTH_ELEMENTALIST)
+ you.skills[SK_THROWING]++;
+ else
+ you.skills[ coinflip() ? SK_DODGING : SK_STEALTH ]++;
+ break;
+
+ case JOB_TRANSMUTER:
+ // some sticks for sticks to snakes:
+ you.inv[1].quantity = 6 + roll_dice( 3, 4 );
+ you.inv[1].base_type = OBJ_MISSILES;
+ you.inv[1].sub_type = MI_ARROW;
+ you.inv[1].plus = 0;
+ you.inv[1].plus2 = 0;
+ you.inv[1].special = 0;
+ you.inv[1].colour = BROWN;
+
+ you.inv[2].base_type = OBJ_ARMOUR;
+ you.inv[2].sub_type = ARM_ROBE;
+ you.inv[2].plus = 0;
+ you.inv[2].special = 0;
+ you.inv[2].quantity = 1;
+ you.inv[2].colour = BROWN;
+
+ you.inv[3].base_type = OBJ_BOOKS;
+ you.inv[3].sub_type = BOOK_CHANGES;
+ you.inv[3].quantity = 1;
+ you.inv[3].plus = 0;
+ you.inv[3].special = 0;
+ you.inv[3].colour = random_colour();
+
+ // A little bit of starting ammo for evaporate... don't need too
+ // much now that the character can make their own. -- bwr
+ //
+ // some ammo for evaporate:
+ you.inv[4].base_type = OBJ_POTIONS;
+ you.inv[4].sub_type = POT_CONFUSION;
+ you.inv[4].quantity = 2;
+ you.inv[4].plus = 0;
+
+ // some more ammo for evaporate:
+ you.inv[5].base_type = OBJ_POTIONS;
+ you.inv[5].sub_type = POT_POISON;
+ you.inv[5].quantity = 1;
+ you.inv[5].plus = 0;
+
+ you.equip[EQ_WEAPON] = -1;
+ you.equip[EQ_BODY_ARMOUR] = 2;
+
+ you.skills[SK_FIGHTING] = 1;
+ you.skills[SK_UNARMED_COMBAT] = 3;
+ you.skills[SK_THROWING] = 2;
+ you.skills[SK_DODGING] = 2;
+ you.skills[SK_SPELLCASTING] = 2;
+ you.skills[SK_TRANSMIGRATION] = 2;
+
+ if (you.species == SP_SPRIGGAN)
+ {
+ you.inv[0].base_type = OBJ_STAVES;
+ you.inv[0].sub_type = STAFF_STRIKING;
+ you.inv[0].quantity = 1;
+ you.inv[0].plus = 0;
+ you.inv[0].plus2 = 0;
+ you.inv[0].special = 0;
+ you.inv[0].colour = BROWN;
+
+ you.skills[SK_EVOCATIONS] = 2;
+ you.skills[SK_FIGHTING] = 0;
+
+ you.equip[EQ_WEAPON] = 0;
+ }
+ break;
+
+ case JOB_WARPER:
+ you.inv[0].quantity = 1;
+ you.inv[0].plus = 0;
+ you.inv[0].plus2 = 0;
+ you.inv[0].special = 0;
+ you.inv[0].colour = LIGHTCYAN;
+
+ if (you.species == SP_SPRIGGAN)
+ {
+ you.inv[0].base_type = OBJ_STAVES;
+ you.inv[0].sub_type = STAFF_STRIKING;
+ you.inv[0].colour = BROWN;
+
+ you.skills[SK_EVOCATIONS] = 3;
+ }
+ else
+ {
+ you.inv[0].base_type = OBJ_WEAPONS;
+ you.inv[0].sub_type = WPN_SHORT_SWORD;
+
+ if (you.species == SP_OGRE_MAGE)
+ {
+ you.inv[0].sub_type = WPN_QUARTERSTAFF;
+ you.inv[0].colour = BROWN;
+ }
+
+ weap_skill = 2;
+ you.skills[SK_FIGHTING] = 1;
+ }
+
+ you.inv[1].base_type = OBJ_ARMOUR;
+ you.inv[1].sub_type = ARM_LEATHER_ARMOUR;
+ you.inv[1].quantity = 1;
+ you.inv[1].plus = 0;
+ you.inv[1].special = 0;
+ you.inv[1].colour = BROWN;
+
+ if (you.species == SP_SPRIGGAN || you.species == SP_OGRE_MAGE)
+ you.inv[1].sub_type = ARM_ROBE;
+
+ you.inv[2].base_type = OBJ_BOOKS;
+ you.inv[2].sub_type = BOOK_SPATIAL_TRANSLOCATIONS;
+ you.inv[2].quantity = 1;
+ you.inv[2].plus = 0;
+ you.inv[2].special = 0;
+ you.inv[2].colour = random_colour();
+
+ // one free escape:
+ you.inv[3].base_type = OBJ_SCROLLS;
+ you.inv[3].sub_type = SCR_BLINKING;
+ you.inv[3].quantity = 1;
+ you.inv[3].plus = 0;
+ you.inv[3].special = 0;
+ you.inv[3].colour = WHITE;
+
+ you.inv[4].base_type = OBJ_MISSILES;
+ you.inv[4].sub_type = MI_DART;
+ you.inv[4].quantity = 10 + roll_dice( 2, 10 );
+ you.inv[4].plus = 0;
+ you.inv[4].special = 0;
+ you.inv[4].colour = LIGHTCYAN;
+
+ you.equip[EQ_WEAPON] = 0;
+ you.equip[EQ_BODY_ARMOUR] = 1;
+
+ you.skills[SK_THROWING] = 1;
+ you.skills[SK_DARTS] = 2;
+ you.skills[SK_DODGING] = 2;
+ you.skills[SK_STEALTH] = 1;
+ you.skills[SK_SPELLCASTING] = 2;
+ you.skills[SK_TRANSLOCATIONS] = 2;
+ break;
+
+ case JOB_CRUSADER:
+ you.inv[0].quantity = 1;
+ you.inv[0].base_type = OBJ_WEAPONS;
+ you.inv[0].sub_type = WPN_SHORT_SWORD;
+
+ //if (you.species == SP_OGRE_MAGE) you.inv_sub_type [0] = WPN_GLAIVE;
+
+ you.inv[0].plus = 0;
+ you.inv[0].plus2 = 0;
+ you.inv[0].special = 0;
+ you.inv[0].colour = LIGHTCYAN;
+ choose_weapon();
+ weap_skill = 2;
+ you.inv[1].quantity = 1;
+ you.inv[1].base_type = OBJ_ARMOUR;
+ you.inv[1].sub_type = ARM_ROBE;
+ you.inv[1].plus = 0;
+ you.inv[1].special = 0;
+ you.inv[1].colour = random_colour();
+
+ you.inv[2].base_type = OBJ_BOOKS;
+ you.inv[2].sub_type = BOOK_WAR_CHANTS;
+ you.inv[2].quantity = 1;
+ you.inv[2].plus = 0;
+ you.inv[2].special = 0;
+ you.inv[2].colour = random_colour();
+
+ you.equip[EQ_WEAPON] = 0;
+ you.equip[EQ_BODY_ARMOUR] = 1;
+
+ you.skills[SK_FIGHTING] = 3;
+ you.skills[SK_ARMOUR] = 1;
+ you.skills[SK_DODGING] = 1;
+ you.skills[SK_STEALTH] = 1;
+ you.skills[SK_SPELLCASTING] = 2;
+ you.skills[SK_ENCHANTMENTS] = 2;
+ break;
+
+
+ case JOB_DEATH_KNIGHT:
+ you.inv[0].quantity = 1;
+ you.inv[0].base_type = OBJ_WEAPONS;
+ you.inv[0].sub_type = WPN_SHORT_SWORD;
+ you.inv[0].plus = 0;
+ you.inv[0].plus2 = 0;
+ you.inv[0].special = 0;
+ you.inv[0].colour = LIGHTCYAN;
+ choose_weapon();
+ weap_skill = 2;
+
+ you.inv[1].quantity = 1;
+ you.inv[1].base_type = OBJ_ARMOUR;
+ you.inv[1].sub_type = ARM_ROBE;
+ you.inv[1].plus = 0;
+ you.inv[1].special = 0;
+ you.inv[1].colour = DARKGREY;
+
+ you.inv[2].base_type = OBJ_BOOKS;
+ you.inv[2].sub_type = BOOK_NECROMANCY;
+ you.inv[2].quantity = 1;
+ you.inv[2].plus = 0;
+ you.inv[2].special = 0;
+ you.inv[2].colour = DARKGREY;
+
+ you.equip[EQ_WEAPON] = 0;
+ you.equip[EQ_BODY_ARMOUR] = 1;
+
+ choice = DK_NO_SELECTION;
+
+ // order is important here -- bwr
+ if (you.species == SP_DEMIGOD)
+ choice = DK_NECROMANCY;
+ else if (Options.death_knight != DK_NO_SELECTION
+ && Options.death_knight != DK_RANDOM)
+ {
+ choice = Options.death_knight;
+ }
+ else if (Options.random_pick || Options.death_knight == DK_RANDOM)
+ choice = (coinflip() ? DK_NECROMANCY : DK_YREDELEMNUL);
+ else
+ {
+ clrscr();
+
+ textcolor( CYAN );
+ cprintf(EOL " From where do you draw your power?" EOL);
+
+ textcolor( LIGHTGREY );
+ cprintf("a - Necromantic magic" EOL);
+ cprintf("b - the god Yredelemnul" EOL);
+
+ getkey1:
+ keyn = get_ch();
+
+ switch (keyn)
+ {
+ case 'a':
+ cprintf(EOL "Very well.");
+ choice = DK_NECROMANCY;
+ break;
+ case 'b':
+ choice = DK_YREDELEMNUL;
+ break;
+ default:
+ goto getkey1;
+ }
+ }
+
+ switch (choice)
+ {
+ default: // this shouldn't happen anyways -- bwr
+ case DK_NECROMANCY:
+ you.skills[SK_SPELLCASTING] = 1;
+ you.skills[SK_NECROMANCY] = 2;
+ break;
+ case DK_YREDELEMNUL:
+ you.religion = GOD_YREDELEMNUL;
+ you.piety = 28;
+ you.inv[0].plus = 1;
+ you.inv[0].plus2 = 1;
+ you.inv[2].quantity = 0;
+ you.skills[SK_INVOCATIONS] = 3;
+ break;
+ }
+
+ you.skills[SK_FIGHTING] = 2;
+ you.skills[SK_ARMOUR] = 1;
+ you.skills[SK_DODGING] = 1;
+ you.skills[SK_STEALTH] = 1;
+ //you.skills [SK_SHORT_BLADES] = 2;
+ you.skills[SK_STABBING] = 1;
+ break;
+
+ case JOB_CHAOS_KNIGHT:
+ you.piety = 25; // irrelevant for Xom, of course
+ you.inv[0].quantity = 1;
+ you.inv[0].base_type = OBJ_WEAPONS;
+ you.inv[0].sub_type = WPN_SHORT_SWORD;
+ you.inv[0].plus = random2(3);
+ you.inv[0].plus2 = random2(3);
+ you.inv[0].special = 0;
+
+ if (one_chance_in(5))
+ set_equip_desc( you.inv[0], ISFLAG_RUNED );
+
+ if (one_chance_in(5))
+ set_equip_desc( you.inv[0], ISFLAG_GLOWING );
+
+ you.inv[0].colour = LIGHTCYAN;
+ choose_weapon();
+ weap_skill = 2;
+ you.inv[1].quantity = 1;
+ you.inv[1].base_type = OBJ_ARMOUR;
+ you.inv[1].sub_type = ARM_ROBE;
+ you.inv[1].plus = random2(3);
+ you.inv[1].special = 0;
+ you.inv[1].colour = random_colour();
+
+ you.equip[EQ_WEAPON] = 0;
+ you.equip[EQ_BODY_ARMOUR] = 1;
+
+ you.skills[SK_FIGHTING] = 3;
+ you.skills[SK_ARMOUR] = 1;
+ you.skills[SK_DODGING] = 1;
+ you.skills[(coinflip()? SK_ARMOUR : SK_DODGING)]++;
+ you.skills[SK_STABBING] = 1;
+
+ if (Options.chaos_knight != GOD_NO_GOD
+ && Options.chaos_knight != GOD_RANDOM)
+ {
+ you.religion = Options.chaos_knight;
+ }
+ else if (Options.random_pick || Options.chaos_knight == GOD_RANDOM)
+ you.religion = coinflip() ? GOD_XOM : GOD_MAKHLEB;
+ else
+ {
+ clrscr();
+
+ textcolor( CYAN );
+ cprintf(EOL " Which god of chaos do you wish to serve?" EOL);
+
+ textcolor( LIGHTGREY );
+ cprintf("a - Xom of Chaos" EOL);
+ cprintf("b - Makhleb the Destroyer" EOL);
+
+ getkey2:
+
+ keyn = get_ch();
+
+ switch (keyn)
+ {
+ case 'a':
+ you.religion = GOD_XOM;
+ break;
+ case 'b':
+ you.religion = GOD_MAKHLEB;
+ break;
+ default:
+ goto getkey2;
+ }
+ }
+
+ if (you.religion == GOD_XOM)
+ you.skills[SK_FIGHTING]++;
+ else // you.religion == GOD_MAKHLEB
+ you.skills[SK_INVOCATIONS] = 2;
+
+ break;
+
+ case JOB_HEALER:
+ you.religion = GOD_ELYVILON;
+ you.piety = 45;
+
+ you.inv[0].quantity = 1;
+ you.inv[0].base_type = OBJ_WEAPONS;
+ you.inv[0].sub_type = WPN_QUARTERSTAFF;
+ you.inv[0].colour = BROWN;
+ you.inv[0].plus = 0;
+ you.inv[0].plus2 = 0;
+ you.inv[0].special = 0;
+
+ // Robe
+ you.inv[1].quantity = 1;
+ you.inv[1].base_type = OBJ_ARMOUR;
+ you.inv[1].sub_type = ARM_ROBE;
+ you.inv[1].plus = 0;
+ you.inv[1].special = 0;
+ you.inv[1].colour = WHITE;
+
+ you.inv[2].base_type = OBJ_POTIONS;
+ you.inv[2].sub_type = POT_HEALING;
+ you.inv[2].quantity = 1;
+ you.inv[2].plus = 0;
+
+ you.inv[3].base_type = OBJ_POTIONS;
+ you.inv[3].sub_type = POT_HEAL_WOUNDS;
+ you.inv[3].quantity = 1;
+ you.inv[3].plus = 0;
+
+ you.equip[EQ_WEAPON] = 0;
+ you.equip[EQ_BODY_ARMOUR] = 1;
+
+ you.skills[SK_FIGHTING] = 2;
+ you.skills[SK_DODGING] = 1;
+ you.skills[SK_SHIELDS] = 1;
+ you.skills[SK_THROWING] = 2;
+ you.skills[SK_STAVES] = 3;
+ you.skills[SK_INVOCATIONS] = 2;
+ break;
+
+ case JOB_REAVER:
+ you.inv[0].quantity = 1;
+ you.inv[0].base_type = OBJ_WEAPONS;
+ you.inv[0].sub_type = WPN_SHORT_SWORD;
+ you.inv[0].plus = 0;
+ you.inv[0].plus2 = 0;
+ you.inv[0].special = 0;
+ you.inv[0].colour = LIGHTCYAN;
+ choose_weapon();
+ weap_skill = 3;
+
+ you.inv[1].quantity = 1;
+ you.inv[1].base_type = OBJ_ARMOUR;
+ you.inv[1].sub_type = ARM_ROBE;
+ you.inv[1].plus = 0;
+ you.inv[1].special = 0;
+ you.inv[1].colour = RED;
+
+ you.inv[2].base_type = OBJ_BOOKS;
+ you.inv[2].sub_type = give_first_conjuration_book();
+ you.inv[2].quantity = 1;
+ you.inv[2].plus = 0; // = 127
+ you.inv[2].special = 0;
+ you.inv[2].colour = RED;
+
+ you.equip[EQ_WEAPON] = 0;
+ you.equip[EQ_BODY_ARMOUR] = 1;
+
+ you.skills[SK_FIGHTING] = 2;
+ you.skills[SK_ARMOUR] = 1;
+ you.skills[SK_DODGING] = 1;
+
+ you.skills[SK_SPELLCASTING] = 1;
+ you.skills[SK_CONJURATIONS] = 2;
+ break;
+
+ case JOB_STALKER:
+ you.inv[0].quantity = 1;
+ you.inv[0].base_type = OBJ_WEAPONS;
+ you.inv[0].sub_type = WPN_DAGGER;
+ to_hit_bonus = random2(3);
+ you.inv[0].plus = 1 + to_hit_bonus;
+ you.inv[0].plus2 = 1 + (2 - to_hit_bonus);
+ you.inv[0].special = 0;
+ you.inv[0].colour = LIGHTCYAN;
+
+ you.inv[1].quantity = 1;
+ you.inv[1].base_type = OBJ_ARMOUR;
+ you.inv[1].sub_type = ARM_ROBE;
+ you.inv[1].plus = 0;
+ you.inv[1].special = 0;
+ you.inv[1].colour = GREEN;
+
+ you.inv[2].quantity = 1;
+ you.inv[2].base_type = OBJ_ARMOUR;
+ you.inv[2].sub_type = ARM_CLOAK;
+ you.inv[2].plus = 0;
+ you.inv[2].special = 0;
+ you.inv[2].colour = DARKGREY;
+
+ you.inv[3].base_type = OBJ_BOOKS;
+ //you.inv[3].sub_type = BOOK_YOUNG_POISONERS;
+ you.inv[3].sub_type = BOOK_STALKING; //jmf: new book!
+ you.inv[3].quantity = 1;
+ you.inv[3].plus = 0;
+ you.inv[3].special = 0;
+ you.inv[3].colour = GREEN;
+
+ you.equip[EQ_WEAPON] = 0;
+ you.equip[EQ_BODY_ARMOUR] = 1;
+ you.equip[EQ_CLOAK] = 2;
+
+ you.skills[SK_FIGHTING] = 1;
+ you.skills[SK_SHORT_BLADES] = 1;
+ you.skills[SK_POISON_MAGIC] = 1;
+ you.skills[SK_DODGING] = 1;
+ you.skills[SK_STEALTH] = 2;
+ you.skills[SK_STABBING] = 2;
+ you.skills[SK_DODGING + random2(3)]++;
+ //you.skills[SK_THROWING] = 1; //jmf: removed these, added magic below
+ //you.skills[SK_DARTS] = 1;
+ you.skills[SK_SPELLCASTING] = 1;
+ you.skills[SK_ENCHANTMENTS] = 1;
+ break;
+
+ case JOB_MONK:
+ you.inv[0].base_type = OBJ_ARMOUR;
+ you.inv[0].sub_type = ARM_ROBE;
+ you.inv[0].plus = 0;
+ you.inv[0].special = 0;
+ you.inv[0].quantity = 1;
+ you.inv[0].colour = BROWN;
+
+ you.equip[EQ_WEAPON] = -1;
+ you.equip[EQ_BODY_ARMOUR] = 0;
+
+ you.skills[SK_FIGHTING] = 3;
+ you.skills[SK_UNARMED_COMBAT] = 4;
+ you.skills[SK_DODGING] = 3;
+ you.skills[SK_STEALTH] = 2;
+ break;
+
+ case JOB_WANDERER:
+ create_wanderer();
+ break;
+ }
+
+ if (weap_skill)
+ you.skills[weapon_skill(OBJ_WEAPONS, you.inv[0].sub_type)] = weap_skill;
+
+ init_skill_order();
+
+ if (you.religion != GOD_NO_GOD)
+ {
+ you.worshipped[you.religion] = 1;
+ set_god_ability_slots();
+ }
+}
diff --git a/trunk/source/newgame.h b/trunk/source/newgame.h
new file mode 100644
index 0000000000..6b71e483ba
--- /dev/null
+++ b/trunk/source/newgame.h
@@ -0,0 +1,24 @@
+/*
+ * File: newgame.cc
+ * Summary: Functions used when starting a new game.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef NEWGAME_H
+#define NEWGAME_H
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+bool new_game();
+
+int give_first_conjuration_book();
+
+#endif
diff --git a/trunk/source/ouch.cc b/trunk/source/ouch.cc
new file mode 100644
index 0000000000..5fa2cfa136
--- /dev/null
+++ b/trunk/source/ouch.cc
@@ -0,0 +1,996 @@
+/*
+ * File: ouch.cc
+ * Summary: Functions used when Bad Things happen to the player.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <8> 7/30/00 JDJ Fixed end_game so that it works with filenames longer than 6 characters.
+ * <7> 19 June 2000 GDL Changed handle to FILE *
+ * <6> 11/23/99 LRH Fixed file purging for DOS?
+ * <5> 9/29/99 BCR Fixed highscore so that it
+ * doesn't take so long. Also
+ * added some whitespace to the scores.
+ * Fixed problem with uniques and 'a'.
+ * <4> 6/13/99 BWR applied a mix of DML and my tmp
+ * file purging improvements.
+ * <3> 5/26/99 JDJ highscore() will print more scores on
+ * larger windows.
+ * <2> 5/21/99 BWR Added SCORE_FILE_ENTRIES, so
+ * that more top scores can be
+ * saved.
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "ouch.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <time.h>
+
+#ifdef DOS
+#include <conio.h>
+#include <file.h>
+#endif
+
+#ifdef LINUX
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+
+#ifdef USE_EMX
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+
+#ifdef OS9
+#include <stat.h>
+#else
+#include <sys/stat.h>
+#endif
+
+#include "externs.h"
+
+#include "chardump.h"
+#include "delay.h"
+#include "files.h"
+#include "hiscores.h"
+#include "invent.h"
+#include "itemname.h"
+#include "items.h"
+#include "macro.h"
+#include "mon-util.h"
+#include "player.h"
+#include "randart.h"
+#include "religion.h"
+#include "shopping.h"
+#include "skills2.h"
+#include "spells4.h"
+#include "stuff.h"
+#include "view.h"
+
+
+void end_game( struct scorefile_entry &se );
+void item_corrode( char itco );
+
+
+/* NOTE: DOES NOT check for hellfire!!! */
+int check_your_resists(int hurted, int flavour)
+{
+ int resist;
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "checking resistance: flavour=%d", flavour );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ if (flavour == BEAM_FIRE || flavour == BEAM_LAVA
+ || flavour == BEAM_HELLFIRE || flavour == BEAM_EXPLOSION
+ || flavour == BEAM_FRAG)
+ {
+ if (you.duration[DUR_CONDENSATION_SHIELD] > 0)
+ {
+ mpr( "Your icy shield dissipates!", MSGCH_DURATION );
+ you.duration[DUR_CONDENSATION_SHIELD] = 0;
+ you.redraw_armour_class = 1;
+ }
+ }
+
+ switch (flavour)
+ {
+ case BEAM_FIRE:
+ resist = player_res_fire();
+ if (resist > 0)
+ {
+ canned_msg(MSG_YOU_RESIST);
+ hurted /= (1 + (resist * resist));
+ }
+ else if (resist < 0)
+ {
+ mpr("It burns terribly!");
+ hurted *= 15;
+ hurted /= 10;
+ }
+ break;
+
+ case BEAM_COLD:
+ resist = player_res_cold();
+ if (resist > 0)
+ {
+ canned_msg(MSG_YOU_RESIST);
+ hurted /= (1 + (resist * resist));
+ }
+ else if (resist < 0)
+ {
+ mpr("You feel a terrible chill!");
+ hurted *= 15;
+ hurted /= 10;
+ }
+ break;
+
+ case BEAM_ELECTRICITY:
+ resist = player_res_electricity();
+ if (resist >= 3)
+ {
+ canned_msg(MSG_YOU_RESIST);
+ hurted = 0;
+ }
+ else if (resist > 0)
+ {
+ canned_msg(MSG_YOU_RESIST);
+ hurted /= 3;
+ }
+ break;
+
+
+ case BEAM_POISON:
+ resist = player_res_poison();
+
+ if (!resist)
+ poison_player( coinflip() ? 2 : 1 );
+ else
+ {
+ canned_msg(MSG_YOU_RESIST);
+ hurted /= 3;
+ }
+ break;
+
+ case BEAM_POISON_ARROW:
+ resist = player_res_poison();
+
+ if (!resist)
+ poison_player( 6 + random2(3), true );
+ else
+ {
+ mpr("You partially resist.");
+ hurted /= 2;
+
+ if (!you.is_undead)
+ poison_player( coinflip() ? 2 : 3, true );
+ }
+ break;
+
+ case BEAM_NEG:
+ resist = player_prot_life();
+
+ if (resist > 0)
+ {
+ hurted -= (resist * hurted) / 3;
+ }
+
+ drain_exp();
+ break;
+
+ case BEAM_ICE:
+ resist = player_res_cold();
+
+ if (resist > 0)
+ {
+ mpr("You partially resist.");
+ hurted /= 2;
+ }
+ else if (resist < 0)
+ {
+ mpr("You feel a painful chill!");
+ hurted *= 13;
+ hurted /= 10;
+ }
+ break;
+
+ case BEAM_LAVA:
+ resist = player_res_fire();
+
+ if (resist > 1)
+ {
+ mpr("You partially resist.");
+ hurted /= (1 + resist);
+ }
+ else if (resist < 0)
+ {
+ mpr("It burns terribly!");
+ hurted *= 15;
+ hurted /= 10;
+ }
+ break;
+ } /* end switch */
+
+ return (hurted);
+} // end check_your_resists()
+
+void splash_with_acid( char acid_strength )
+{
+ /* affects equip only?
+ assume that a message has already been sent, also that damage has
+ already been done
+ */
+ char splc = 0;
+ int dam = 0;
+
+ const bool wearing_cloak = (you.equip[EQ_CLOAK] == -1);
+
+ for (splc = EQ_CLOAK; splc <= EQ_BODY_ARMOUR; splc++)
+ {
+ if (you.equip[splc] == -1)
+ {
+ if (!wearing_cloak || coinflip())
+ dam += roll_dice( 1, acid_strength );
+
+ continue;
+ }
+
+ if (random2(20) <= acid_strength)
+ item_corrode( you.equip[splc] );
+ }
+
+ if (dam)
+ {
+ mpr( "The acid burns!" );
+ ouch( dam, 0, KILLED_BY_ACID );
+ }
+} // end splash_with_acid()
+
+void weapon_acid( char acid_strength )
+{
+ char hand_thing = you.equip[EQ_WEAPON];
+
+ if (hand_thing == -1)
+ hand_thing = you.equip[EQ_GLOVES];
+
+ if (hand_thing == -1)
+ {
+ snprintf( info, INFO_SIZE, "Your %s burn!", your_hand(true) );
+ mpr( info );
+
+ ouch( roll_dice( 1, acid_strength ), 0, KILLED_BY_ACID );
+ }
+ else if (random2(20) <= acid_strength)
+ {
+ item_corrode( hand_thing );
+ }
+} // end weapon_acid()
+
+void item_corrode( char itco )
+{
+ int chance_corr = 0; // no idea what its full range is {dlb}
+ bool it_resists = false; // code simplifier {dlb}
+ bool suppress_msg = false; // code simplifier {dlb}
+ int how_rusty = ((you.inv[itco].base_type == OBJ_WEAPONS)
+ ? you.inv[itco].plus2 : you.inv[itco].plus);
+
+ // early return for "oRC and cloak/preservation {dlb}:
+ if (wearing_amulet(AMU_RESIST_CORROSION) && !one_chance_in(10))
+ {
+#if DEBUG_DIAGNOSTICS
+ mpr( "Amulet protects.", MSGCH_DIAGNOSTICS );
+#endif
+ return;
+ }
+
+ // early return for items already pretty d*** rusty {dlb}:
+ if (how_rusty < -5)
+ return;
+
+ // determine possibility of resistance by object type {dlb}:
+ switch (you.inv[itco].base_type)
+ {
+ case OBJ_ARMOUR:
+ if (is_random_artefact( you.inv[itco] ))
+ {
+ it_resists = true;
+ suppress_msg = true;
+ }
+ else if ((you.inv[itco].sub_type == ARM_CRYSTAL_PLATE_MAIL
+ || cmp_equip_race( you.inv[itco], ISFLAG_DWARVEN ))
+ && !one_chance_in(5))
+ {
+ it_resists = true;
+ suppress_msg = false;
+ }
+ break;
+
+ case OBJ_WEAPONS:
+ if (is_fixed_artefact(you.inv[itco])
+ || is_random_artefact(you.inv[itco]))
+ {
+ it_resists = true;
+ suppress_msg = true;
+ }
+ else if (cmp_equip_race( you.inv[itco], ISFLAG_DWARVEN )
+ && !one_chance_in(5))
+ {
+ it_resists = true;
+ suppress_msg = false;
+ }
+ break;
+
+ case OBJ_MISSILES:
+ if (cmp_equip_race( you.inv[itco], ISFLAG_DWARVEN ) && !one_chance_in(5))
+ {
+ it_resists = true;
+ suppress_msg = false;
+ }
+ break;
+ }
+
+ // determine chance of corrosion {dlb}:
+ if (!it_resists)
+ {
+ chance_corr = abs( how_rusty );
+
+ // ---------------------------- but it needs to stay this way
+ // (as it *was* this way)
+
+ // the embedded equation may look funny, but it actually works well
+ // to generate a pretty probability ramp {6%, 18%, 34%, 58%, 98%}
+ // for values [0,4] which closely matches the original, ugly switch
+ // {dlb}
+ if (chance_corr >= 0 && chance_corr <= 4)
+ {
+ it_resists = (random2(100) <
+ 2 + (2 << (1 + chance_corr)) + (chance_corr * 8));
+ }
+ else
+ it_resists = true; // no idea how often this occurs {dlb}
+
+ // if the checks get this far, you should hear about it {dlb}
+ suppress_msg = false;
+ }
+
+ // handle message output and item damage {dlb}:
+ if (!suppress_msg)
+ {
+ char str_pass[ ITEMNAME_SIZE ];
+ in_name(itco, DESC_CAP_YOUR, str_pass);
+ strcpy(info, str_pass);
+ strcat(info, (it_resists) ? " resists." : " is eaten away!");
+ mpr(info);
+ }
+
+ if (!it_resists)
+ {
+ how_rusty--;
+
+ if (you.inv[itco].base_type == OBJ_WEAPONS)
+ you.inv[itco].plus2 = how_rusty;
+ else
+ you.inv[itco].plus = how_rusty;
+
+ you.redraw_armour_class = 1; // for armour, rings, etc. {dlb}
+
+ if (you.equip[EQ_WEAPON] == itco)
+ you.wield_change = true;
+ }
+
+ return;
+} // end item_corrode()
+
+void scrolls_burn(char burn_strength, char target_class)
+{
+
+ unsigned char burnc;
+ unsigned char burn2;
+ unsigned char burn_no = 0;
+
+ if (wearing_amulet(AMU_CONSERVATION) && !one_chance_in(10))
+ {
+#if DEBUG_DIAGNOSTICS
+ mpr( "Amulet conserves.", MSGCH_DIAGNOSTICS );
+#endif
+ return;
+ }
+
+ for (burnc = 0; burnc < ENDOFPACK; burnc++)
+ {
+ if (!you.inv[burnc].quantity)
+ continue;
+ if (you.inv[burnc].base_type != target_class)
+ continue;
+
+ for (burn2 = 0; burn2 < you.inv[burnc].quantity; burn2++)
+ {
+ if (random2(70) < burn_strength)
+ {
+ burn_no++;
+
+ if (burnc == you.equip[EQ_WEAPON])
+ you.wield_change = true;
+
+ if (dec_inv_item_quantity( burnc, 1 ))
+ break;
+ }
+ }
+ }
+
+ if (burn_no == 1)
+ {
+ if (target_class == OBJ_SCROLLS)
+ mpr("A scroll you are carrying catches fire!");
+ else if (target_class == OBJ_POTIONS)
+ mpr("A potion you are carrying freezes and shatters!");
+ else if (target_class == OBJ_FOOD)
+ mpr("Some of your food is covered with spores!");
+ }
+ else if (burn_no > 1)
+ {
+ if (target_class == OBJ_SCROLLS)
+ mpr("Some of the scrolls you are carrying catch fire!");
+ else if (target_class == OBJ_POTIONS)
+ mpr("Some of the potions you are carrying freeze and shatter!");
+ else if (target_class == OBJ_FOOD)
+ mpr("Some of your food is covered with spores!");
+ }
+ /* burn_no could be 0 */
+}
+
+ // end scrolls_burn()
+void lose_level(void)
+{
+ // because you.experience is unsigned long, if it's going to be -ve
+ // must die straightaway.
+ if (you.experience_level == 1)
+ ouch( -9999, 0, KILLED_BY_DRAINING );
+
+ you.experience = exp_needed( you.experience_level + 1 ) - 1;
+ you.experience_level--;
+
+ snprintf( info, INFO_SIZE, "You are now a level %d %s!",
+ you.experience_level, you.class_name );
+ mpr( info, MSGCH_WARN );
+
+ // Constant value to avoid grape jelly trick... see level_change() for
+ // where these HPs and MPs are given back. -- bwr
+ ouch( 4, 0, KILLED_BY_DRAINING );
+ dec_max_hp(4);
+
+ dec_mp(1);
+ dec_max_mp(1);
+
+ calc_hp();
+ calc_mp();
+
+ you.redraw_experience = 1;
+} // end lose_level()
+
+void drain_exp(void)
+{
+ int protection = player_prot_life();
+
+ if (you.duration[DUR_PRAYER]
+ && (you.religion == GOD_ZIN || you.religion == GOD_SHINING_ONE)
+ && random2(150) < you.piety)
+ {
+ simple_god_message(" protects your life force!");
+ return;
+ }
+
+ if (protection >= 3 || you.is_undead)
+ {
+ mpr("You fully resist.");
+ return;
+ }
+
+ if (you.experience == 0)
+ ouch(-9999, 0, KILLED_BY_DRAINING);
+
+ if (you.experience_level == 1)
+ {
+ you.experience = 0;
+ return;
+ }
+
+ unsigned long total_exp = exp_needed( you.experience_level + 2 )
+ - exp_needed( you.experience_level + 1 );
+ unsigned long exp_drained = total_exp * (10 + random2(11));
+
+ exp_drained /= 100;
+
+ if (protection > 0)
+ {
+ mpr("You partially resist.");
+ exp_drained -= (protection * exp_drained) / 3;
+ }
+
+ if (exp_drained > 0)
+ {
+ mpr("You feel drained.");
+ you.experience -= exp_drained;
+ you.exp_available -= exp_drained;
+
+ if (you.exp_available < 0)
+ you.exp_available = 0;
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "You lose %ld experience points.",
+ exp_drained );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ you.redraw_experience = 1;
+
+ if (you.experience < exp_needed(you.experience_level + 1))
+ lose_level();
+ }
+} // end drain_exp()
+
+// death_source should be set to zero for non-monsters {dlb}
+void ouch( int dam, int death_source, char death_type, const char *aux )
+{
+ int d = 0;
+ int e = 0;
+
+ if (you.deaths_door && death_type != KILLED_BY_LAVA
+ && death_type != KILLED_BY_WATER)
+ {
+ return;
+ }
+
+ // assumed bug for high damage amounts
+ if (dam > 300)
+ {
+ snprintf( info, INFO_SIZE,
+ "Potential bug: Unexpectedly high damage = %d", dam );
+ mpr( info, MSGCH_DANGER );
+ return;
+ }
+
+ if (you_are_delayed())
+ {
+ stop_delay();
+ }
+
+ if (dam > -9000) // that is, a "death" caused by hp loss {dlb}
+ {
+ switch (you.religion)
+ {
+ case GOD_XOM:
+ if (random2(you.hp_max) > you.hp && dam > random2(you.hp)
+ && one_chance_in(5))
+ {
+ simple_god_message( " protects you from harm!" );
+ return;
+ }
+ break;
+
+ case GOD_ZIN:
+ case GOD_SHINING_ONE:
+ case GOD_ELYVILON:
+ case GOD_OKAWARU:
+ case GOD_YREDELEMNUL:
+ if (dam >= you.hp && you.duration[DUR_PRAYER]
+ && random2(you.piety) >= 30)
+ {
+ simple_god_message( " protects you from harm!" );
+ return;
+ }
+ break;
+ }
+
+ // Damage applied here:
+ dec_hp( dam, true );
+
+ // Even if we have low HP messages off, we'll still give a
+ // big hit warning (in this case, a hit for half our HPs) -- bwr
+ if (dam > 0 && you.hp_max <= dam * 2)
+ mpr( "Ouch! That really hurt!", MSGCH_DANGER );
+
+ if (you.hp > 0 && Options.hp_warning
+ && you.hp <= (you.hp_max * Options.hp_warning) / 100)
+ {
+ mpr( "* * * LOW HITPOINT WARNING * * *", MSGCH_DANGER );
+ }
+
+ if (you.hp > 0)
+ return;
+ }
+
+#ifdef WIZARD
+ if (death_type != KILLED_BY_QUITTING
+ && death_type != KILLED_BY_WINNING
+ && death_type != KILLED_BY_LEAVING)
+ {
+ if (you.wizard)
+ {
+#ifdef USE_OPTIONAL_WIZARD_DEATH
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "Damage: %d; Hit points: %d", dam, you.hp );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif // DEBUG_DIAGNOSTICS
+
+ if (!yesno("Die?", false))
+ {
+ set_hp(you.hp_max, false);
+ return;
+ }
+#else // !def USE_OPTIONAL_WIZARD_DEATH
+ mpr("Since you're a debugger, I'll let you live.");
+ mpr("Be more careful next time, okay?");
+
+ set_hp(you.hp_max, false);
+ return;
+#endif // USE_OPTIONAL_WIZARD_DEATH
+ }
+ }
+#endif // WIZARD
+
+ //okay, so you're dead:
+
+ // do points first.
+ long points = you.gold;
+ points += (you.experience * 7) / 10;
+
+ //if (death_type == KILLED_BY_WINNING) points += points / 2;
+ //if (death_type == KILLED_BY_LEAVING) points += points / 10;
+ // these now handled by giving player the value of their inventory
+ char temp_id[4][50];
+
+ for (d = 0; d < 4; d++)
+ {
+ for (e = 0; e < 50; e++)
+ temp_id[d][e] = 1;
+ }
+
+ // CONSTRUCT SCOREFILE ENTRY
+ struct scorefile_entry se;
+
+ // Score file entry version:
+ //
+ // 4.0 - original versioned entry
+ // 4.1 - added real_time and num_turn fields
+ // 4.2 - stats and god info
+
+ se.version = 4;
+ se.release = 2;
+
+ strncpy( se.name, you.your_name, kNameLen );
+ se.name[ kNameLen - 1 ] = '\0';
+#ifdef MULTIUSER
+ se.uid = (int) getuid();
+#else
+ se.uid = 0;
+#endif
+
+ FixedVector< int, NUM_RUNE_TYPES > rune_array;
+
+ se.num_runes = 0;
+ se.num_diff_runes = 0;
+
+ for (int i = 0; i < NUM_RUNE_TYPES; i++)
+ rune_array[i] = 0;
+
+ // Calculate value of pack and runes when character leaves dungeon
+ if (death_type == KILLED_BY_LEAVING || death_type == KILLED_BY_WINNING)
+ {
+ for (d = 0; d < ENDOFPACK; d++)
+ {
+ if (is_valid_item( you.inv[d] ))
+ {
+ points += item_value( you.inv[d], temp_id, true );
+
+ if (you.inv[d].base_type == OBJ_MISCELLANY
+ && you.inv[d].sub_type == MISC_RUNE_OF_ZOT)
+ {
+ if (rune_array[ you.inv[d].plus ] == 0)
+ se.num_diff_runes++;
+
+ se.num_runes += you.inv[d].quantity;
+ rune_array[ you.inv[d].plus ] += you.inv[d].quantity;
+ }
+ }
+ }
+
+ // Bonus for exploring different areas, not for collecting a
+ // huge stack of demonic runes in Pandemonium (gold value
+ // is enough for those). -- bwr
+ if (se.num_diff_runes >= 3)
+ points += ((se.num_diff_runes + 2) * (se.num_diff_runes + 2) * 1000);
+ }
+
+ // Players will have a hard time getting 1/10 of this (see XP cap):
+ if (points > 99999999)
+ points = 99999999;
+
+ se.points = points;
+ se.race = you.species;
+ se.cls = you.char_class;
+
+ // strcpy(se.race_class_name, "");
+ se.race_class_name[0] = '\0';
+
+ se.lvl = you.experience_level;
+ se.best_skill = best_skill( SK_FIGHTING, NUM_SKILLS - 1, 99 );
+ se.best_skill_lvl = you.skills[ se.best_skill ];
+ se.death_type = death_type;
+
+ // for death by monster
+
+ // Set the default aux data value...
+ // If aux is passed in (ie for a trap), we'll default to that.
+ if (aux == NULL)
+ se.auxkilldata[0] = '\0';
+ else
+ {
+ strncpy( se.auxkilldata, aux, ITEMNAME_SIZE );
+ se.auxkilldata[ ITEMNAME_SIZE - 1 ] = '\0';
+ }
+
+ if ((death_type == KILLED_BY_MONSTER || death_type == KILLED_BY_BEAM)
+ && death_source >= 0 && death_source < MAX_MONSTERS)
+ {
+ struct monsters *monster = &menv[death_source];
+
+ if (monster->type > 0 || monster->type <= NUM_MONSTERS)
+ {
+ se.death_source = monster->type;
+ se.mon_num = monster->number;
+
+ // Previously the weapon was only used for dancing weapons,
+ // but now we pass it in as a string through the scorefile
+ // entry to be appended in hiscores_format_single in long or
+ // medium scorefile formats.
+ // It still isn't used in monam for anything but flying weapons
+ // though
+ if (death_type == KILLED_BY_MONSTER
+ && monster->inv[MSLOT_WEAPON] != NON_ITEM)
+ {
+#if HISCORE_WEAPON_DETAIL
+ set_ident_flags( mitm[monster->inv[MSLOT_WEAPON]],
+ ISFLAG_IDENT_MASK );
+#else
+ // changing this to ignore the pluses to keep it short
+ unset_ident_flags( mitm[monster->inv[MSLOT_WEAPON]],
+ ISFLAG_IDENT_MASK );
+
+ set_ident_flags( mitm[monster->inv[MSLOT_WEAPON]],
+ ISFLAG_KNOW_TYPE );
+
+ // clear "runed" description text to make shorter yet
+ set_equip_desc( mitm[monster->inv[MSLOT_WEAPON]], 0 );
+#endif
+
+ // Setting this is redundant for dancing weapons, however
+ // we do care about the above indentification. -- bwr
+ if (monster->type != MONS_DANCING_WEAPON)
+ {
+ it_name( monster->inv[MSLOT_WEAPON], DESC_NOCAP_A, info );
+ strncpy( se.auxkilldata, info, ITEMNAME_SIZE );
+ se.auxkilldata[ ITEMNAME_SIZE - 1 ] = '\0';
+ }
+ }
+
+ strcpy( info,
+ monam( monster->number, monster->type, true, DESC_NOCAP_A,
+ monster->inv[MSLOT_WEAPON] ) );
+
+ strncpy( se.death_source_name, info, 40 );
+ se.death_source_name[39] = '\0';
+ }
+ }
+ else
+ {
+ se.death_source = death_source;
+ se.mon_num = 0;
+ se.death_source_name[0] = '\0';
+ }
+
+ se.damage = dam;
+ se.final_hp = you.hp;
+ se.final_max_hp = you.hp_max;
+ se.final_max_max_hp = you.hp_max + player_rotted();
+ se.str = you.strength;
+ se.intel = you.intel;
+ se.dex = you.dex;
+
+ se.god = you.religion;
+ if (you.religion != GOD_NO_GOD)
+ {
+ se.piety = you.piety;
+ se.penance = you.penance[you.religion];
+ }
+
+ // main dungeon: level is simply level
+ se.dlvl = you.your_level + 1;
+ switch (you.where_are_you)
+ {
+ case BRANCH_ORCISH_MINES:
+ case BRANCH_HIVE:
+ case BRANCH_LAIR:
+ case BRANCH_SLIME_PITS:
+ case BRANCH_VAULTS:
+ case BRANCH_CRYPT:
+ case BRANCH_HALL_OF_BLADES:
+ case BRANCH_HALL_OF_ZOT:
+ case BRANCH_ECUMENICAL_TEMPLE:
+ case BRANCH_SNAKE_PIT:
+ case BRANCH_ELVEN_HALLS:
+ case BRANCH_TOMB:
+ case BRANCH_SWAMP:
+ se.dlvl = you.your_level - you.branch_stairs[you.where_are_you - 10];
+ break;
+
+ case BRANCH_DIS:
+ case BRANCH_GEHENNA:
+ case BRANCH_VESTIBULE_OF_HELL:
+ case BRANCH_COCYTUS:
+ case BRANCH_TARTARUS:
+ case BRANCH_INFERNO:
+ case BRANCH_THE_PIT:
+ se.dlvl = you.your_level - 26;
+ break;
+ }
+
+ se.branch = you.where_are_you; // no adjustments necessary.
+ se.level_type = you.level_type; // pandemonium, labyrinth, dungeon..
+
+ se.birth_time = you.birth_time; // start time of game
+ se.death_time = time( NULL ); // end time of game
+
+ if (you.real_time != -1)
+ se.real_time = you.real_time + (se.death_time - you.start_time);
+ else
+ se.real_time = -1;
+
+ se.num_turns = you.num_turns;
+
+#ifdef WIZARD
+ se.wiz_mode = (you.wizard ? 1 : 0);
+#else
+ se.wiz_mode = 0;
+#endif
+
+#ifdef SCORE_WIZARD_CHARACTERS
+ // add this highscore to the score file.
+ hiscores_new_entry(se);
+#else
+
+ // only add non-wizards to the score file.
+ // never generate bones files of wizard characters -- bwr
+ if (!you.wizard)
+ {
+ hiscores_new_entry(se);
+
+ if (death_type != KILLED_BY_LEAVING && death_type != KILLED_BY_WINNING)
+ save_ghost();
+ }
+
+#endif
+
+ end_game(se);
+}
+
+void end_game( struct scorefile_entry &se )
+{
+ int i;
+ char del_file[300]; // massive overkill!
+ bool dead = true;
+
+ if (se.death_type == KILLED_BY_LEAVING ||
+ se.death_type == KILLED_BY_WINNING)
+ {
+ dead = false;
+ }
+
+ // clean all levels that we think we have ever visited
+ for (int level = 0; level < MAX_LEVELS; level++)
+ {
+ for (int dungeon = 0; dungeon < MAX_BRANCHES; dungeon++)
+ {
+ if (tmp_file_pairs[level][dungeon])
+ {
+ make_filename( info, you.your_name, level, dungeon,
+ false, false );
+ unlink(info);
+ }
+ }
+ }
+
+ // temp level, if any
+ make_filename( info, you.your_name, 0, 0, true, false );
+ unlink(info);
+
+ // create base file name
+#ifdef SAVE_DIR_PATH
+ snprintf( info, INFO_SIZE, SAVE_DIR_PATH "%s%d", you.your_name, (int) getuid());
+#else
+ strncpy(info, you.your_name, kFileNameLen);
+ info[kFileNameLen] = '\0';
+#endif
+
+ // this is to catch the game package if it still exists.
+#ifdef PACKAGE_SUFFIX
+ strcpy(del_file, info);
+ strcat(del_file, "." PACKAGE_SUFFIX);
+ unlink(del_file);
+#endif
+
+ // last, but not least, delete player .sav file
+ strcpy(del_file, info);
+ strcat(del_file, ".sav");
+ unlink(del_file);
+
+ // death message
+ if (dead)
+ {
+ mpr("You die..."); // insert player name here? {dlb}
+ viewwindow(1, false); // don't do this for leaving/winning characters
+ }
+ more();
+
+ for (i = 0; i < ENDOFPACK; i++)
+ set_ident_flags( you.inv[i], ISFLAG_IDENT_MASK );
+
+ for (i = 0; i < ENDOFPACK; i++)
+ {
+ if (you.inv[i].base_type != 0)
+ {
+ set_ident_type( you.inv[i].base_type,
+ you.inv[i].sub_type, ID_KNOWN_TYPE );
+ }
+ }
+
+ invent( -1, !dead );
+ clrscr();
+
+ if (!dump_char( "morgue.txt", !dead ))
+ mpr("Char dump unsuccessful! Sorry about that.");
+#if DEBUG_DIAGNOSTICS
+ //jmf: switched logic and moved "success" message to debug-only
+ else
+ mpr("Char dump successful! (morgue.txt).");
+#endif // DEBUG
+
+ more();
+
+ clrscr();
+#ifdef DOS_TERM
+ window(1, 1, 80, 25);
+#endif
+
+ clrscr();
+ cprintf( "Goodbye, " );
+ cprintf( you.your_name );
+ cprintf( "." );
+ cprintf( EOL EOL " " ); // Space padding where # would go in list format
+
+ char scorebuff[ HIGHSCORE_SIZE ];
+
+ const int lines = hiscores_format_single_long( scorebuff, se, true );
+
+ // truncate
+ scorebuff[ HIGHSCORE_SIZE - 1 ] = '\0';
+ cprintf( scorebuff );
+
+ cprintf( EOL "Best Crawlers -" EOL );
+
+ // "- 5" gives us an extra line in case the description wraps on a line.
+ hiscores_print_list( get_number_of_lines() - lines - 5 );
+
+ // just to pause, actual value returned does not matter {dlb}
+ get_ch();
+ end(0);
+}
diff --git a/trunk/source/ouch.h b/trunk/source/ouch.h
new file mode 100644
index 0000000000..23894dade5
--- /dev/null
+++ b/trunk/source/ouch.h
@@ -0,0 +1,74 @@
+/*
+ * File: ouch.cc
+ * Summary: Functions used when Bad Things happen to the player.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <2> 9/29/99 BCR Added the DEATH_NAME_LENGTH define
+ * It determines how many characters of
+ * a long player name are printed in
+ * the score list.
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef OUCH_H
+#define OUCH_H
+
+
+#define DEATH_NAME_LENGTH 10
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: bang - beam - effects - spells
+ * *********************************************************************** */
+int check_your_resists(int hurted, int flavour);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: fight
+ * *********************************************************************** */
+void splash_with_acid(char acid_strength);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: fight
+ * *********************************************************************** */
+void weapon_acid(char acid_strength);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - bang - beam - effects - fight - misc - spells -
+ * spells2
+ * *********************************************************************** */
+void scrolls_burn(char burn_strength, char target_class);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - bang - beam - command - effects - fight - misc -
+ * ouch - output - religion - spells - spells2 - spells4
+ * *********************************************************************** */
+void ouch(int dam, int death_source, char death_type, const char *aux = NULL);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: decks - ouch
+ * *********************************************************************** */
+void lose_level(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: decks - fight - item_use - ouch - religion - spells
+ * *********************************************************************** */
+void drain_exp(void);
+
+
+#endif
diff --git a/trunk/source/output.cc b/trunk/source/output.cc
new file mode 100644
index 0000000000..40f1738534
--- /dev/null
+++ b/trunk/source/output.cc
@@ -0,0 +1,539 @@
+/*
+ * File: output.cc
+ * Summary: Functions used to print player related info.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <2> 5/20/99 BWR Efficiency changes for curses.
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "output.h"
+
+#include <stdlib.h>
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#include "externs.h"
+
+#include "itemname.h"
+#include "ouch.h"
+#include "player.h"
+
+static int bad_ench_colour( int lvl, int orange, int red )
+{
+ if (lvl > red)
+ return (RED);
+ else if (lvl > orange)
+ return (LIGHTRED);
+
+ return (YELLOW);
+}
+
+static void dur_colour( int colour, bool running_out )
+{
+ if (running_out)
+ textcolor( colour );
+ else
+ {
+ switch (colour)
+ {
+ case GREEN: textcolor( LIGHTGREEN ); break;
+ case BLUE: textcolor( LIGHTBLUE ); break;
+ case MAGENTA: textcolor( LIGHTMAGENTA ); break;
+ case LIGHTGREY: textcolor( WHITE ); break;
+ }
+ }
+}
+
+void print_stats(void)
+{
+ textcolor(LIGHTGREY);
+
+ if (you.redraw_hit_points)
+ {
+ const int max_max_hp = you.hp_max + player_rotted();
+ const int hp_warn = MAXIMUM( 25, Options.hp_warning );
+ const int hp_attent = MAXIMUM( 10, Options.hp_attention );
+
+ gotoxy(44, 3);
+
+ if (you.hp <= (you.hp_max * hp_warn) / 100)
+ textcolor(RED);
+ else if (you.hp <= (you.hp_max * hp_attent) / 100)
+ textcolor(YELLOW);
+
+ cprintf( "%d", you.hp );
+
+ textcolor(LIGHTGREY);
+ cprintf( "/%d", you.hp_max );
+
+ if (max_max_hp != you.hp_max)
+ cprintf( " (%d)", max_max_hp );
+
+#ifdef LINUX
+ clear_to_end_of_line();
+#else
+ cprintf(" ");
+#endif
+
+ you.redraw_hit_points = 0;
+ }
+
+ if (you.redraw_magic_points)
+ {
+ gotoxy(47, 4);
+
+ cprintf( "%d/%d", you.magic_points, you.max_magic_points );
+
+#ifdef LINUX
+ clear_to_end_of_line();
+#else
+ cprintf(" ");
+#endif
+
+ you.redraw_magic_points = 0;
+ }
+
+ if (you.redraw_strength)
+ {
+ if (you.strength < 0)
+ you.strength = 0;
+ else if (you.strength > 72)
+ you.strength = 72;
+
+ if (you.max_strength > 72)
+ you.max_strength = 72;
+
+ gotoxy(45, 7);
+
+ if (you.might)
+ textcolor(LIGHTBLUE); // no end of effect warning
+ else if (you.strength < you.max_strength)
+ textcolor(YELLOW);
+
+ cprintf( "%d", you.strength );
+ textcolor(LIGHTGREY);
+
+ if (you.strength != you.max_strength)
+ cprintf( " (%d)", you.max_strength );
+ else
+ cprintf( " " );
+
+ you.redraw_strength = 0;
+
+ if (you.strength < 1)
+ ouch(-9999, 0, KILLED_BY_WEAKNESS);
+
+ burden_change();
+ }
+
+ if (you.redraw_intelligence)
+ {
+ if (you.intel < 0)
+ you.intel = 0;
+ else if (you.intel > 72)
+ you.intel = 72;
+
+ if (you.max_intel > 72)
+ you.max_intel = 72;
+
+ gotoxy(45, 8);
+
+ if (you.intel < you.max_intel)
+ textcolor(YELLOW);
+
+ cprintf( "%d", you.intel );
+ textcolor(LIGHTGREY);
+
+ if (you.intel != you.max_intel)
+ cprintf( " (%d)", you.max_intel );
+ else
+ cprintf( " " );
+
+ you.redraw_intelligence = 0;
+
+ if (you.intel < 1)
+ ouch(-9999, 0, KILLED_BY_STUPIDITY);
+ }
+
+ if (you.redraw_dexterity)
+ {
+ if (you.dex < 0)
+ you.dex = 0;
+ else if (you.dex > 72)
+ you.dex = 72;
+
+ if (you.max_dex > 72)
+ you.max_dex = 72;
+
+ gotoxy(45, 9);
+
+ if (you.dex < you.max_dex)
+ textcolor(YELLOW);
+
+ cprintf( "%d", you.dex );
+ textcolor(LIGHTGREY);
+
+ if (you.dex != you.max_dex)
+ cprintf( " (%d)", you.max_dex );
+ else
+ cprintf( " " );
+
+ you.redraw_dexterity = 0;
+
+ if (you.dex < 1)
+ ouch(-9999, 0, KILLED_BY_CLUMSINESS);
+ }
+
+ if (you.redraw_armour_class)
+ {
+ gotoxy(44, 5);
+
+ if (you.duration[DUR_STONEMAIL])
+ dur_colour( BLUE, (you.duration[DUR_STONEMAIL] <= 6) );
+ else if (you.duration[DUR_ICY_ARMOUR] || you.duration[DUR_STONESKIN])
+ textcolor( LIGHTBLUE ); // no end of effect warning
+
+ cprintf( "%d ", player_AC() );
+ textcolor( LIGHTGREY );
+
+ gotoxy(50, 5);
+
+ if (you.duration[DUR_CONDENSATION_SHIELD]) //jmf: added 24mar2000
+ textcolor( LIGHTBLUE ); // no end of effect warning
+
+ cprintf( "(%d) ", player_shield_class() );
+ textcolor( LIGHTGREY );
+
+ you.redraw_armour_class = 0;
+ }
+
+ if (you.redraw_evasion)
+ {
+ gotoxy(44, 6);
+
+ if (you.duration[DUR_FORESCRY])
+ textcolor(LIGHTBLUE); // no end of effect warning
+
+ cprintf( "%d ", player_evasion() );
+ textcolor(LIGHTGREY);
+
+ you.redraw_evasion = 0;
+ }
+
+ if (you.redraw_gold)
+ {
+ gotoxy(46, 10);
+ cprintf( "%d ", you.gold );
+ you.redraw_gold = 0;
+ }
+
+ if (you.redraw_experience)
+ {
+ gotoxy(52, 11);
+
+#if DEBUG_DIAGNOSTICS
+ cprintf( "%d/%d (%d/%d)",
+ you.experience_level, you.experience,
+ you.skill_cost_level, you.exp_available );
+#else
+ cprintf( "%d/%d (%d)",
+ you.experience_level, you.experience, you.exp_available );
+#endif
+
+#ifdef LINUX
+ clear_to_end_of_line();
+#else
+ cprintf(" ");
+#endif
+ you.redraw_experience = 0;
+ }
+
+ if (you.wield_change)
+ {
+ gotoxy(40, 13);
+#ifdef LINUX
+ clear_to_end_of_line();
+#else
+ cprintf(" ");
+#endif
+
+ if (you.equip[EQ_WEAPON] != -1)
+ {
+ gotoxy(40, 13);
+ textcolor(you.inv[you.equip[EQ_WEAPON]].colour);
+
+ char str_pass[ ITEMNAME_SIZE ];
+ in_name( you.equip[EQ_WEAPON], DESC_INVENTORY, str_pass, Options.terse_hand );
+ str_pass[39] = '\0';
+
+ cprintf(str_pass);
+ textcolor(LIGHTGREY);
+ }
+ else
+ {
+ gotoxy(40, 13);
+
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_BLADE_HANDS)
+ {
+ textcolor(RED);
+ cprintf("Blade Hands");
+ textcolor(LIGHTGREY);
+ }
+ else
+ {
+ textcolor(LIGHTGREY);
+ cprintf("Nothing wielded");
+ }
+ }
+ you.wield_change = false;
+ }
+
+ // The colour scheme for these flags is currently:
+ //
+ // - yellow, "orange", red for bad conditions
+ // - light grey, white for god based conditions
+ // - green, light green for good conditions
+ // - blue, light blue for good enchantments
+ // - magenta, light magenta for "better" enchantments (deflect, fly)
+
+ if (you.redraw_status_flags & REDRAW_LINE_1_MASK)
+ {
+ gotoxy(40, 14);
+
+#ifdef LINUX
+ clear_to_end_of_line();
+#else
+ cprintf( " " );
+ gotoxy(40, 14);
+#endif
+
+ switch (you.burden_state)
+ {
+ case BS_OVERLOADED:
+ textcolor( RED );
+ cprintf( "Overloaded " );
+ break;
+
+ case BS_ENCUMBERED:
+ textcolor( LIGHTRED );
+ cprintf( "Encumbered " );
+ break;
+
+ case BS_UNENCUMBERED:
+ break;
+ }
+
+ switch (you.hunger_state)
+ {
+ case HS_ENGORGED:
+ textcolor( LIGHTGREEN );
+ cprintf( "Engorged" );
+ break;
+
+ case HS_FULL:
+ textcolor( GREEN );
+ cprintf( "Full" );
+ break;
+
+ case HS_SATIATED:
+ break;
+
+ case HS_HUNGRY:
+ textcolor( YELLOW );
+ cprintf( "Hungry" );
+ break;
+
+ case HS_STARVING:
+ textcolor( RED );
+ cprintf( "Starving" );
+ break;
+ }
+
+ textcolor( LIGHTGREY );
+
+#if DEBUG_DIAGNOSTICS
+ // debug mode hunger-o-meter
+ cprintf( " (%d:%d) ", you.hunger - you.old_hunger, you.hunger );
+#endif
+ }
+
+ if (you.redraw_status_flags & REDRAW_LINE_2_MASK)
+ {
+ gotoxy(40, 15);
+
+#ifdef LINUX
+ clear_to_end_of_line();
+#else
+ cprintf( " " );
+ gotoxy(40, 15);
+#endif
+
+ // Max length of this line = 8 * 5 - 1 = 39
+
+ if (you.duration[DUR_PRAYER])
+ {
+ textcolor( WHITE ); // no end of effect warning
+ cprintf( "Pray " );
+ }
+
+ if (you.duration[DUR_REPEL_UNDEAD])
+ {
+ dur_colour( LIGHTGREY, (you.duration[DUR_REPEL_UNDEAD] <= 4) );
+ cprintf( "Holy " );
+ }
+
+ if (you.duration[DUR_DEFLECT_MISSILES])
+ {
+
+ dur_colour( MAGENTA, (you.duration[DUR_DEFLECT_MISSILES] <= 6) );
+ cprintf( "DMsl " );
+ }
+ else if (you.duration[DUR_REPEL_MISSILES])
+ {
+ dur_colour( BLUE, (you.duration[DUR_REPEL_MISSILES] <= 6) );
+ cprintf( "RMsl " );
+ }
+
+ if (you.duration[DUR_REGENERATION])
+ {
+ dur_colour( BLUE, (you.duration[DUR_REGENERATION] <= 6) );
+ cprintf( "Regen " );
+ }
+
+ if (you.duration[DUR_INSULATION])
+ {
+ dur_colour( BLUE, (you.duration[DUR_INSULATION] <= 6) );
+ cprintf( "Ins " );
+ }
+
+ if (player_is_levitating())
+ {
+ bool perm = (you.species == SP_KENKU && you.experience_level >= 15)
+ || (player_equip_ego_type( EQ_BOOTS, SPARM_LEVITATION ))
+ || (you.attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON);
+
+ if (wearing_amulet( AMU_CONTROLLED_FLIGHT ))
+ {
+ dur_colour( MAGENTA, (you.levitation <= 10 && !perm) );
+ cprintf( "Fly " );
+ }
+ else
+ {
+ dur_colour( BLUE, (you.levitation <= 10 && !perm) );
+ cprintf( "Lev " );
+ }
+ }
+
+ if (you.invis)
+ {
+ dur_colour( BLUE, (you.invis <= 6) );
+ cprintf( "Invis " );
+ }
+
+ // Perhaps this should be reversed to show when it can be used?
+ // In that case, it should be probably be GREEN, and we'd have
+ // to check to see if the player does have a breath weapon. -- bwr
+ if (you.duration[DUR_BREATH_WEAPON])
+ {
+ textcolor( YELLOW ); // no warning
+ cprintf( "BWpn" );
+ }
+
+ textcolor( LIGHTGREY );
+ }
+
+ if (you.redraw_status_flags & REDRAW_LINE_3_MASK)
+ {
+ gotoxy(40, 16);
+
+#ifdef LINUX
+ clear_to_end_of_line();
+#else
+ cprintf( " " );
+ gotoxy(40, 16);
+#endif
+ // Max length of this line = 7 * 5 + 3 - 1 = 37
+
+ // Note the usage of bad_ench_colour() correspond to levels that
+ // can be found in player.cc, ie those that the player can tell by
+ // using the '@' command. Things like confusion and sticky flame
+ // hide their amounts and are thus always the same colour (so
+ // we're not really exposing any new information). --bwr
+ if (you.conf)
+ {
+ textcolor( RED ); // no different levels
+ cprintf( "Conf " );
+ }
+
+ if (you.duration[DUR_LIQUID_FLAMES])
+ {
+ textcolor( RED ); // no different levels
+ cprintf( "Fire " );
+ }
+
+ if (you.poison)
+ {
+ // We skip marking "quite" poisoned and instead mark the
+ // levels where the rules for dealing poison damage change
+ // significantly. See acr.cc for that code. -- bwr
+ textcolor( bad_ench_colour( you.poison, 5, 10 ) );
+ cprintf( "Pois " );
+ }
+
+ if (you.disease)
+ {
+ textcolor( bad_ench_colour( you.disease, 40, 120 ) );
+ cprintf( "Sick " );
+ }
+
+ if (you.rotting)
+ {
+ textcolor( bad_ench_colour( you.rotting, 4, 8 ) );
+ cprintf( "Rot " );
+ }
+
+ if (you.magic_contamination > 5)
+ {
+ textcolor( bad_ench_colour( you.magic_contamination, 15, 25 ) );
+ cprintf( "Glow " );
+ }
+
+ if (you.duration[DUR_SWIFTNESS])
+ {
+ dur_colour( BLUE, (you.duration[DUR_SWIFTNESS] <= 6) );
+ cprintf( "Swift " );
+ }
+
+ if (you.slow && !you.haste)
+ {
+ textcolor( RED ); // no end of effect warning
+ cprintf( "Slow" );
+ }
+ else if (you.haste && !you.slow)
+ {
+ dur_colour( BLUE, (you.haste <= 6) );
+ cprintf( "Fast" );
+ }
+
+ textcolor( LIGHTGREY );
+ }
+
+ you.redraw_status_flags = 0;
+
+#if DEBUG_DIAGNOSTICS
+ // debug mode GPS
+ gotoxy(40, 17);
+ cprintf( "Position (%2d,%2d)", you.x_pos, you.y_pos );
+#endif
+
+#ifdef LINUX
+ // get curses to redraw screen
+ update_screen();
+#endif
+} // end print_stats()
diff --git a/trunk/source/output.h b/trunk/source/output.h
new file mode 100644
index 0000000000..ab8f7e3c2d
--- /dev/null
+++ b/trunk/source/output.h
@@ -0,0 +1,22 @@
+/*
+ * File: output.cc
+ * Summary: Functions used to print player related info.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef OUTPUT_H
+#define OUTPUT_H
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - player - stuff
+ * *********************************************************************** */
+void print_stats(void);
+
+
+#endif
diff --git a/trunk/source/overmap.cc b/trunk/source/overmap.cc
new file mode 100644
index 0000000000..e271a25fdf
--- /dev/null
+++ b/trunk/source/overmap.cc
@@ -0,0 +1,539 @@
+/*
+ * File: overmap.cc
+ * Idea: allow player to make notes about levels. I don't know how
+ * to do this (I expect it will require some kind of dynamic
+ * memory management thing). - LH
+ * Summary: Records location of stairs etc
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <3> 30/7/00 MV Made Over-map full-screen
+ * <2> 8/10/99 BCR Changed Linley's macros
+ * to an enum in overmap.h
+ * <1> 29/8/99 LRH Created
+ */
+
+#include "AppHdr.h"
+#include "overmap.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "externs.h"
+
+// for #definitions of MAX_BRANCHES & MAX_LEVELS
+#include "files.h"
+// for #definitions of MAX_BRANCHES & MAX_LEVELS
+#include "religion.h"
+#include "stuff.h"
+#include "view.h"
+
+enum
+{
+ NO_FEATURE = 0x00,
+ FEATURE_SHOP = 0x01,
+ FEATURE_LABYRINTH = 0x02,
+ FEATURE_HELL = 0x04,
+ FEATURE_ABYSS = 0x08,
+ FEATURE_PANDEMONIUM = 0x10
+};
+
+// These variables need to become part of the player struct
+// and need to be stored in the .sav file:
+
+// 0 == no altars;
+// 100 == more than one altar; or
+// # == which god for remaining numbers.
+
+FixedArray<unsigned char, MAX_LEVELS, MAX_BRANCHES> altars_present;
+FixedVector<char, MAX_BRANCHES> stair_level;
+FixedArray<unsigned char, MAX_LEVELS, MAX_BRANCHES> feature;
+
+int map_lines = 0; //mv: number of lines already printed on "over-map" screen
+
+//mv: prints one line in specified colour
+// void print_one_map_line( const char *line, int colour );
+// void print_branch_entrance_line( const char *area );
+
+void print_one_simple_line( const char *line, int colour );
+void print_one_highlighted_line( const char *pre, const char *text,
+ const char *post, int colour );
+
+static void print_level_name( int branch, int depth,
+ bool &printed_branch, bool &printed_level );
+
+void init_overmap( void )
+{
+ for (int i = 0; i < MAX_LEVELS; i++)
+ {
+ for (int j = 0; j < MAX_BRANCHES; j++)
+ {
+ altars_present[i][j] = 0;
+ feature[i][j] = 0;
+ }
+ }
+
+ for (int i = 0; i < MAX_BRANCHES; i++)
+ stair_level[i] = -1;
+} // end init_overmap()
+
+void display_overmap( void )
+{
+#ifdef DOS_TERM
+ char buffer[4800];
+
+ window(1, 1, 80, 25);
+ gettext(1, 1, 80, 25, buffer);
+#endif
+
+ //mv: must be set to 0 so "More..." message appears really at the
+ // bottom of the screen
+ //Don't forget it could be changed since the last call of display_overmap
+ map_lines = 0;
+
+ clrscr();
+ bool pr_lev = false;
+ bool output = false;
+
+ print_one_simple_line(" Overview of the Dungeon", WHITE);
+
+ // This is a more sensible order than the order of the enums -- bwr
+ const int list_order[] =
+ {
+ BRANCH_MAIN_DUNGEON,
+ BRANCH_ECUMENICAL_TEMPLE,
+ BRANCH_ORCISH_MINES, BRANCH_ELVEN_HALLS,
+ BRANCH_LAIR, BRANCH_SWAMP, BRANCH_SLIME_PITS, BRANCH_SNAKE_PIT,
+ BRANCH_HIVE,
+ BRANCH_VAULTS, BRANCH_HALL_OF_BLADES, BRANCH_CRYPT, BRANCH_TOMB,
+ BRANCH_VESTIBULE_OF_HELL,
+ BRANCH_DIS, BRANCH_GEHENNA, BRANCH_COCYTUS, BRANCH_TARTARUS,
+ BRANCH_HALL_OF_ZOT
+ };
+
+ for (unsigned int index = 0; index < sizeof(list_order) / sizeof(int); index++)
+ {
+ const int i = list_order[index];
+ bool printed_branch = false;
+
+ for (int j = 0; j < MAX_LEVELS; j++)
+ {
+ bool printed_level = false;
+
+ if (altars_present[j][i] != 0)
+ {
+ print_level_name( i, j, printed_branch, printed_level );
+ output = true;
+
+ if (altars_present[j][i] == 100)
+ {
+ print_one_highlighted_line( " - some ",
+ "altars to the gods", ".",
+ WHITE );
+ }
+ else
+ {
+ snprintf( info, INFO_SIZE, "altar to %s",
+ god_name( altars_present[j][i] ) );
+
+ print_one_highlighted_line( " - an ", info, ".", WHITE );
+ }
+ }
+
+ if ( (feature[j][i] & FEATURE_SHOP) )
+ {
+ print_level_name( i, j, printed_branch, printed_level );
+
+ // print_one_simple_line(" - facilities for the purchase of goods.",LIGHTGREY);
+
+ print_one_highlighted_line( " - facilities for the ",
+ "purchase of goods", ".", LIGHTGREEN );
+ output = true;
+ }
+
+ if ( (feature[j][i] & FEATURE_ABYSS) )
+ {
+ print_level_name( i, j, printed_branch, printed_level );
+ // print_one_simple_line(" - a gateway into the Abyss.", LIGHTRED);
+ print_one_highlighted_line( " - a gateway into ",
+ "the Abyss", ".", MAGENTA );
+ output = true;
+ }
+
+ if ( (feature[j][i] & FEATURE_PANDEMONIUM) )
+ {
+ print_level_name( i, j, printed_branch, printed_level );
+ // print_one_simple_line(" - a link to Pandemonium.", LIGHTRED);
+
+ print_one_highlighted_line( " - a link to ", "Pandemonium",
+ ".", LIGHTBLUE );
+ output = true;
+ }
+
+ if ( (feature[j][i] & FEATURE_HELL) )
+ {
+ print_level_name( i, j, printed_branch, printed_level );
+ // print_one_simple_line(" - a mouth of Hell.", LIGHTRED);
+ print_one_highlighted_line( " - a mouth of ", "Hell", ".", RED );
+ output = true;
+ }
+
+ if ( (feature[j][i] & FEATURE_LABYRINTH) )
+ {
+ print_level_name( i, j, printed_branch, printed_level );
+ // print_one_simple_line(" - the entrance of a Labyrinth.", LIGHTRED);
+ print_one_highlighted_line( " - an entrance to ",
+ "a Labyrinth", ".", CYAN );
+ output = true;
+ }
+
+
+ // NB: k starts at 1 because there aren't any staircases
+ // to the main dungeon
+ for (int k = 1; k < MAX_BRANCHES; k++)
+ {
+ pr_lev = false;
+ // strcpy(info, " - a staircase leading to ");
+ info[0] = '\0';
+
+ if (stair_level[k] == j)
+ {
+ switch (i)
+ {
+ case BRANCH_LAIR:
+ switch (k)
+ {
+ case BRANCH_SLIME_PITS:
+ strcat(info, "the Slime Pits");
+ pr_lev = true;
+ break;
+ case BRANCH_SNAKE_PIT:
+ strcat(info, "the Snake Pit");
+ pr_lev = true;
+ break;
+ case BRANCH_SWAMP:
+ strcat(info, "the Swamp");
+ pr_lev = true;
+ break;
+ }
+ break;
+
+ case BRANCH_VAULTS:
+ switch (k)
+ {
+ case BRANCH_HALL_OF_BLADES:
+ strcat(info, "the Hall of Blades");
+ pr_lev = true;
+ break;
+ case BRANCH_CRYPT:
+ strcat(info, "the Crypt");
+ pr_lev = true;
+ break;
+ }
+ break;
+
+ case BRANCH_CRYPT:
+ switch (k)
+ {
+ case BRANCH_TOMB:
+ strcat(info, "the Tomb");
+ pr_lev = true;
+ break;
+ }
+ break;
+
+ case BRANCH_ORCISH_MINES:
+ switch (k)
+ {
+ case BRANCH_ELVEN_HALLS:
+ strcat(info, "the Elven Halls");
+ pr_lev = true;
+ break;
+ }
+ break;
+
+ case BRANCH_MAIN_DUNGEON:
+ switch (k)
+ {
+ case BRANCH_ORCISH_MINES:
+ strcat(info, "the Orcish Mines");
+ pr_lev = true;
+ break;
+ case BRANCH_HIVE:
+ strcat(info, "the Hive");
+ pr_lev = true;
+ break;
+ case BRANCH_LAIR:
+ strcat(info, "the Lair");
+ pr_lev = true;
+ break;
+ case BRANCH_VAULTS:
+ strcat(info, "the Vaults");
+ pr_lev = true;
+ break;
+ case BRANCH_HALL_OF_ZOT:
+ strcat(info, "the Hall of Zot");
+ pr_lev = true;
+ break;
+ case BRANCH_ECUMENICAL_TEMPLE:
+ strcat(info, "the Ecumenical Temple");
+ pr_lev = true;
+ break;
+ }
+ break;
+ }
+ }
+
+ if (pr_lev)
+ {
+ print_level_name( i, j, printed_branch, printed_level );
+ print_one_highlighted_line( " - the entrance to ", info,
+ ".", YELLOW );
+ output = true;
+ }
+ }
+ }
+ }
+
+ textcolor( LIGHTGREY );
+
+ if (!output)
+ cprintf( EOL "You have yet to discover anything worth noting." EOL );
+
+ getch();
+
+ redraw_screen();
+
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+#endif
+} // end display_overmap()
+
+
+static void print_level_name( int branch, int depth,
+ bool &printed_branch, bool &printed_level )
+{
+ if (!printed_branch)
+ {
+ printed_branch = true;
+
+ print_one_simple_line( "", YELLOW );
+ print_one_simple_line(
+ (branch == BRANCH_MAIN_DUNGEON) ? "Main Dungeon" :
+ (branch == BRANCH_ORCISH_MINES) ? "The Orcish Mines" :
+ (branch == BRANCH_HIVE) ? "The Hive" :
+ (branch == BRANCH_LAIR) ? "The Lair" :
+ (branch == BRANCH_SLIME_PITS) ? "The Slime Pits" :
+ (branch == BRANCH_VAULTS) ? "The Vaults" :
+ (branch == BRANCH_CRYPT) ? "The Crypt" :
+ (branch == BRANCH_HALL_OF_BLADES) ? "The Hall of Blades" :
+ (branch == BRANCH_HALL_OF_ZOT) ? "The Hall of Zot" :
+ (branch == BRANCH_ECUMENICAL_TEMPLE) ? "The Ecumenical Temple" :
+ (branch == BRANCH_SNAKE_PIT) ? "The Snake Pit" :
+ (branch == BRANCH_ELVEN_HALLS) ? "The Elven Halls" :
+ (branch == BRANCH_TOMB) ? "The Tomb" :
+ (branch == BRANCH_SWAMP) ? "The Swamp" :
+
+ (branch == BRANCH_DIS) ? "The Iron City of Dis" :
+ (branch == BRANCH_GEHENNA) ? "Gehenna" :
+ (branch == BRANCH_VESTIBULE_OF_HELL) ? "The Vestibule of Hell" :
+ (branch == BRANCH_COCYTUS) ? "Cocytus" :
+ (branch == BRANCH_TARTARUS) ? "Tartarus"
+ : "Unknown Area",
+
+ YELLOW );
+ }
+
+ if (!printed_level)
+ {
+ printed_level = true;
+
+ if (branch == BRANCH_ECUMENICAL_TEMPLE
+ || branch == BRANCH_HALL_OF_BLADES
+ || branch == BRANCH_VESTIBULE_OF_HELL)
+ {
+ // these areas only have one level... let's save the space
+ return;
+ }
+
+ // we need our own buffer in here (info is used):
+ char buff[ INFO_SIZE ] = "\0";;
+
+ if (branch == BRANCH_MAIN_DUNGEON)
+ depth += 1;
+ else if (branch >= BRANCH_ORCISH_MINES && branch <= BRANCH_SWAMP)
+ depth -= you.branch_stairs[ branch - BRANCH_ORCISH_MINES ];
+ else // branch is in hell (all of which start at depth 28)
+ depth -= 26;
+
+ snprintf( buff, INFO_SIZE, " Level %d:", depth );
+ print_one_simple_line( buff, LIGHTRED );
+ }
+}
+
+void seen_staircase( unsigned char which_staircase )
+{
+ // which_staircase holds the grid value of the stair, must be converted
+ // Only handles stairs, not gates or arches
+ // Don't worry about:
+ // - stairs returning to dungeon - predictable
+ // - entrances to the hells - always in vestibule
+
+ unsigned char which_branch = BRANCH_MAIN_DUNGEON;
+
+ switch ( which_staircase )
+ {
+ case DNGN_ENTER_ORCISH_MINES:
+ which_branch = BRANCH_ORCISH_MINES;
+ break;
+ case DNGN_ENTER_HIVE:
+ which_branch = BRANCH_HIVE;
+ break;
+ case DNGN_ENTER_LAIR:
+ which_branch = BRANCH_LAIR;
+ break;
+ case DNGN_ENTER_SLIME_PITS:
+ which_branch = BRANCH_SLIME_PITS;
+ break;
+ case DNGN_ENTER_VAULTS:
+ which_branch = BRANCH_VAULTS;
+ break;
+ case DNGN_ENTER_CRYPT:
+ which_branch = BRANCH_CRYPT;
+ break;
+ case DNGN_ENTER_HALL_OF_BLADES:
+ which_branch = BRANCH_HALL_OF_BLADES;
+ break;
+ case DNGN_ENTER_ZOT:
+ which_branch = BRANCH_HALL_OF_ZOT;
+ break;
+ case DNGN_ENTER_TEMPLE:
+ which_branch = BRANCH_ECUMENICAL_TEMPLE;
+ break;
+ case DNGN_ENTER_SNAKE_PIT:
+ which_branch = BRANCH_SNAKE_PIT;
+ break;
+ case DNGN_ENTER_ELVEN_HALLS:
+ which_branch = BRANCH_ELVEN_HALLS;
+ break;
+ case DNGN_ENTER_TOMB:
+ which_branch = BRANCH_TOMB;
+ break;
+ case DNGN_ENTER_SWAMP:
+ which_branch = BRANCH_SWAMP;
+ break;
+ default:
+ exit(-1); // shouldn't happen
+ }
+
+ stair_level[which_branch] = you.your_level;
+} // end seen_staircase()
+
+
+// if player has seen an altar; record it
+void seen_altar( unsigned char which_altar )
+{
+ // can't record in abyss or pan.
+ if ( you.level_type != LEVEL_DUNGEON )
+ return;
+
+ // portable; no point in recording
+ if ( which_altar == GOD_NEMELEX_XOBEH )
+ return;
+
+ // already seen
+ if ( altars_present[you.your_level][you.where_are_you] == which_altar )
+ return;
+
+ if ( altars_present[you.your_level][you.where_are_you] == 0 )
+ altars_present[you.your_level][you.where_are_you] = which_altar;
+ else
+ altars_present[you.your_level][you.where_are_you] = 100;
+} // end seen_altar()
+
+
+// if player has seen any other thing; record it
+void seen_other_thing( unsigned char which_thing )
+{
+ if ( you.level_type != LEVEL_DUNGEON ) // can't record in abyss or pan.
+ return;
+
+ switch ( which_thing )
+ {
+ case DNGN_ENTER_SHOP:
+ feature[you.your_level][you.where_are_you] |= FEATURE_SHOP;
+ break;
+ case DNGN_ENTER_LABYRINTH:
+ feature[you.your_level][you.where_are_you] |= FEATURE_LABYRINTH;
+ break;
+ case DNGN_ENTER_HELL:
+ feature[you.your_level][you.where_are_you] |= FEATURE_HELL;
+ break;
+ case DNGN_ENTER_ABYSS:
+ feature[you.your_level][you.where_are_you] |= FEATURE_ABYSS;
+ break;
+ case DNGN_ENTER_PANDEMONIUM:
+ feature[you.your_level][you.where_are_you] |= FEATURE_PANDEMONIUM;
+ break;
+ }
+} // end seen_other_thing()
+
+
+/* mv: this function prints one line at "Over-map screen" in specified colour.
+ * If map_lines = maximum number of lines (it means the screen is full) it
+ * prints "More..." message, read key, clear screen and after that prints new
+ * line
+ */
+void print_one_simple_line( const char *line , int colour)
+{
+ if (map_lines == (get_number_of_lines() - 2))
+ {
+ textcolor( LIGHTGREY );
+ cprintf(EOL);
+ cprintf("More...");
+ getch();
+ clrscr();
+ map_lines = 0;
+ }
+
+ textcolor( colour );
+ cprintf( line );
+ cprintf( EOL );
+
+ map_lines++;
+}
+
+void print_one_highlighted_line( const char *pre, const char *text,
+ const char *post, int colour )
+{
+ if (map_lines == (get_number_of_lines() - 2))
+ {
+ textcolor( LIGHTGREY );
+ cprintf(EOL);
+ cprintf("More...");
+ getch();
+ clrscr();
+ map_lines = 0;
+ }
+
+ if (pre[0] != '\0')
+ {
+ textcolor( LIGHTGREY );
+ cprintf( pre );
+ }
+
+ textcolor( colour );
+ cprintf( text );
+
+ if (post[0] != '\0')
+ {
+ textcolor( LIGHTGREY );
+ cprintf( post );
+ }
+
+ cprintf( EOL );
+
+ map_lines++;
+}
diff --git a/trunk/source/overmap.h b/trunk/source/overmap.h
new file mode 100644
index 0000000000..9d02b320e6
--- /dev/null
+++ b/trunk/source/overmap.h
@@ -0,0 +1,51 @@
+/*
+ * File: overmap.cc
+ * Summary: "Overmap" functionality
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> --/--/-- LRH Created
+ */
+
+
+#ifndef OVERMAP_H
+#define OVERMAP_H
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: view
+ * *********************************************************************** */
+void seen_altar(unsigned char which_altar);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void init_overmap(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void display_overmap(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: view
+ * *********************************************************************** */
+void seen_staircase(unsigned char which_staircase);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: view
+ * *********************************************************************** */
+void seen_other_thing(unsigned char which_thing);
+
+
+#endif
diff --git a/trunk/source/player.cc b/trunk/source/player.cc
new file mode 100644
index 0000000000..ed06fd4d18
--- /dev/null
+++ b/trunk/source/player.cc
@@ -0,0 +1,3885 @@
+/*
+ * File: player.cc
+ * Summary: Player related functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <6> 7/30/99 BWR Added player_spell_levels()
+ * <5> 7/13/99 BWR Added player_res_electricity()
+ * and player_hunger_rate()
+ * <4> 6/22/99 BWR Racial adjustments to stealth and Armour.
+ * <3> 5/20/99 BWR Fixed problems with random stat increases, added kobold
+ * stat increase. increased EV recovery for Armour.
+ * <2> 5/08/99 LRH display_char_status correctly handles magic_contamination.
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "player.h"
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <ctype.h>
+
+#include "externs.h"
+
+#include "itemname.h"
+#include "macro.h"
+#include "misc.h"
+#include "mon-util.h"
+#include "mutation.h"
+#include "output.h"
+#include "randart.h"
+#include "religion.h"
+#include "skills2.h"
+#include "spl-util.h"
+#include "spells4.h"
+#include "stuff.h"
+#include "view.h"
+#include "wpn-misc.h"
+
+
+/*
+ you.duration []: //jmf: obsolete, see enum.h instead
+ 0 - liquid flames
+ 1 - icy armour
+ 2 - repel missiles
+ 3 - prayer
+ 4 - regeneration
+ 5 - vorpal blade
+ 6 - fire brand
+ 7 - ice brand
+ 8 - lethal infusion
+ 9 - swiftness
+ 10 - insulation
+ 11 - stonemail
+ 12 - controlled flight
+ 13 - teleport
+ 14 - control teleport
+ 15 - poison weapon
+ 16 - resist poison
+ 17 - breathe something
+ 18 - transformation (duration)
+ 19 - death channel
+ 20 - deflect missiles
+ */
+
+/* attributes
+ 0 - resist lightning
+ 1 - spec_air
+ 2 - spec_earth
+ 3 - control teleport
+ 4 - walk slowly (eg naga)
+ 5 - transformation (form)
+ 6 - Nemelex card gift countdown
+ 7 - Nemelex has given you a card table
+ 8 - How many demonic powers a dspawn has
+ */
+
+/* armour list
+ 0 - wielded
+ 1 - cloak
+ 2 - helmet
+ 3 - gloves
+ 4 - boots
+ 5 - shield
+ 6 - body armour
+ 7 - ring 0
+ 8 - ring 1
+ 9 - amulet
+ */
+
+/* Contains functions which return various player state vars,
+ and other stuff related to the player. */
+
+int species_exp_mod(char species);
+void ability_increase(void);
+
+//void priest_spells(int priest_pass[10], char religious); // see actual function for reasoning here {dlb}
+bool player_in_branch( int branch )
+{
+ return (you.level_type == LEVEL_DUNGEON && you.where_are_you == branch);
+}
+
+bool player_in_hell( void )
+{
+ return (you.level_type == LEVEL_DUNGEON
+ && (you.where_are_you >= BRANCH_DIS
+ && you.where_are_you <= BRANCH_THE_PIT)
+ && you.where_are_you != BRANCH_VESTIBULE_OF_HELL);
+}
+
+bool player_in_water(void)
+{
+ return (!player_is_levitating()
+ && (grd[you.x_pos][you.y_pos] == DNGN_DEEP_WATER
+ || grd[you.x_pos][you.y_pos] == DNGN_SHALLOW_WATER));
+}
+
+bool player_is_swimming(void)
+{
+ return (player_in_water() && you.species == SP_MERFOLK);
+}
+
+bool player_under_penance(void)
+{
+ if (you.religion != GOD_NO_GOD)
+ return (you.penance[you.religion]);
+ else
+ return (false);
+}
+
+bool player_genus(unsigned char which_genus, unsigned char species)
+{
+ if (species == SP_UNKNOWN)
+ species = you.species;
+
+ switch (species)
+ {
+ case SP_RED_DRACONIAN:
+ case SP_WHITE_DRACONIAN:
+ case SP_GREEN_DRACONIAN:
+ case SP_GOLDEN_DRACONIAN:
+ case SP_GREY_DRACONIAN:
+ case SP_BLACK_DRACONIAN:
+ case SP_PURPLE_DRACONIAN:
+ case SP_MOTTLED_DRACONIAN:
+ case SP_PALE_DRACONIAN:
+ case SP_UNK0_DRACONIAN:
+ case SP_UNK1_DRACONIAN:
+ case SP_UNK2_DRACONIAN:
+ return (which_genus == GENPC_DRACONIAN);
+
+ case SP_ELF:
+ case SP_HIGH_ELF:
+ case SP_GREY_ELF:
+ case SP_DEEP_ELF:
+ case SP_SLUDGE_ELF:
+ return (which_genus == GENPC_ELVEN);
+
+ case SP_HILL_DWARF:
+ case SP_MOUNTAIN_DWARF:
+ return (which_genus == GENPC_DWARVEN);
+
+ default:
+ break;
+ }
+
+ return (false);
+} // end player_genus()
+
+// Looks in equipment "slot" to see if there is an equiped "sub_type".
+// Returns number of matches (in the case of rings, both are checked)
+int player_equip( int slot, int sub_type )
+{
+ int ret = 0;
+
+ switch (slot)
+ {
+ case EQ_WEAPON:
+ // Hands can have more than just weapons.
+ if (you.equip[EQ_WEAPON] != -1
+ && you.inv[you.equip[EQ_WEAPON]].base_type == OBJ_WEAPONS
+ && you.inv[you.equip[EQ_WEAPON]].sub_type == sub_type)
+ {
+ ret++;
+ }
+ break;
+
+ case EQ_STAFF:
+ // Like above, but must be magical stave.
+ if (you.equip[EQ_WEAPON] != -1
+ && you.inv[you.equip[EQ_WEAPON]].base_type == OBJ_STAVES
+ && you.inv[you.equip[EQ_WEAPON]].sub_type == sub_type)
+ {
+ ret++;
+ }
+ break;
+
+ case EQ_RINGS:
+ if (you.equip[EQ_LEFT_RING] != -1
+ && you.inv[you.equip[EQ_LEFT_RING]].sub_type == sub_type)
+ {
+ ret++;
+ }
+
+ if (you.equip[EQ_RIGHT_RING] != -1
+ && you.inv[you.equip[EQ_RIGHT_RING]].sub_type == sub_type)
+ {
+ ret++;
+ }
+ break;
+
+ case EQ_RINGS_PLUS:
+ if (you.equip[EQ_LEFT_RING] != -1
+ && you.inv[you.equip[EQ_LEFT_RING]].sub_type == sub_type)
+ {
+ ret += you.inv[you.equip[EQ_LEFT_RING]].plus;
+ }
+
+ if (you.equip[EQ_RIGHT_RING] != -1
+ && you.inv[you.equip[EQ_RIGHT_RING]].sub_type == sub_type)
+ {
+ ret += you.inv[you.equip[EQ_RIGHT_RING]].plus;
+ }
+ break;
+
+ case EQ_RINGS_PLUS2:
+ if (you.equip[EQ_LEFT_RING] != -1
+ && you.inv[you.equip[EQ_LEFT_RING]].sub_type == sub_type)
+ {
+ ret += you.inv[you.equip[EQ_LEFT_RING]].plus2;
+ }
+
+ if (you.equip[EQ_RIGHT_RING] != -1
+ && you.inv[you.equip[EQ_RIGHT_RING]].sub_type == sub_type)
+ {
+ ret += you.inv[you.equip[EQ_RIGHT_RING]].plus2;
+ }
+ break;
+
+ case EQ_ALL_ARMOUR:
+ // doesn't make much sense here... be specific. -- bwr
+ break;
+
+ default:
+ if (you.equip[slot] != -1
+ && you.inv[you.equip[slot]].sub_type == sub_type)
+ {
+ ret++;
+ }
+ break;
+ }
+
+ return (ret);
+}
+
+
+// Looks in equipment "slot" to see if equiped item has "special" ego-type
+// Returns number of matches (jewellery returns zero -- no ego type).
+int player_equip_ego_type( int slot, int special )
+{
+ int ret = 0;
+ int wpn;
+
+ switch (slot)
+ {
+ case EQ_WEAPON:
+ // This actually checks against the "branding", so it will catch
+ // randart brands, but not fixed artefacts. -- bwr
+
+ // Hands can have more than just weapons.
+ wpn = you.equip[EQ_WEAPON];
+ if (wpn != -1
+ && you.inv[wpn].base_type == OBJ_WEAPONS
+ && get_weapon_brand( you.inv[wpn] ) == special)
+ {
+ ret++;
+ }
+ break;
+
+ case EQ_LEFT_RING:
+ case EQ_RIGHT_RING:
+ case EQ_AMULET:
+ case EQ_STAFF:
+ case EQ_RINGS:
+ case EQ_RINGS_PLUS:
+ case EQ_RINGS_PLUS2:
+ // no ego types for these slots
+ break;
+
+ case EQ_ALL_ARMOUR:
+ // Check all armour slots:
+ for (int i = EQ_CLOAK; i <= EQ_BODY_ARMOUR; i++)
+ {
+ if (you.equip[i] != -1
+ && get_armour_ego_type( you.inv[you.equip[i]] ) == special)
+ {
+ ret++;
+ }
+ }
+ break;
+
+ default:
+ // Check a specific armour slot for an ego type:
+ if (you.equip[slot] != -1
+ && get_armour_ego_type( you.inv[you.equip[slot]] ) == special)
+ {
+ ret++;
+ }
+ break;
+ }
+
+ return (ret);
+}
+
+int player_damage_type( void )
+{
+ const int wpn = you.equip[ EQ_WEAPON ];
+
+ if (wpn != -1)
+ {
+ return (damage_type( you.inv[wpn].base_type, you.inv[wpn].sub_type ));
+ }
+ else if (you.attribute[ATTR_TRANSFORMATION] == TRAN_BLADE_HANDS
+ || you.attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON
+ || you.mutation[MUT_CLAWS]
+ || you.species == SP_TROLL
+ || you.species == SP_GHOUL)
+ {
+ return (DVORP_SLICING);
+ }
+
+ return (DVORP_CRUSHING);
+}
+
+// returns band of player's melee damage
+int player_damage_brand( void )
+{
+ int ret = SPWPN_NORMAL;
+ const int wpn = you.equip[ EQ_WEAPON ];
+
+ if (wpn != -1)
+ ret = get_weapon_brand( you.inv[wpn] );
+ else if (you.confusing_touch)
+ ret = SPWPN_CONFUSE;
+ else if (you.mutation[MUT_DRAIN_LIFE])
+ ret = SPWPN_DRAINING;
+ else
+ {
+ switch (you.attribute[ATTR_TRANSFORMATION])
+ {
+ case TRAN_SPIDER:
+ ret = SPWPN_VENOM;
+ break;
+
+ case TRAN_ICE_BEAST:
+ ret = SPWPN_FREEZING;
+ break;
+
+ case TRAN_LICH:
+ ret = SPWPN_DRAINING;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return (ret);
+}
+
+int player_teleport(void)
+{
+ int tp = 0;
+
+ /* rings */
+ tp += 8 * player_equip( EQ_RINGS, RING_TELEPORTATION );
+
+ /* mutations */
+ tp += you.mutation[MUT_TELEPORT] * 3;
+
+ /* randart weapons only */
+ if (you.equip[EQ_WEAPON] != -1
+ && you.inv[you.equip[EQ_WEAPON]].base_type == OBJ_WEAPONS
+ && is_random_artefact( you.inv[you.equip[EQ_WEAPON]] ))
+ {
+ tp += scan_randarts(RAP_CAUSE_TELEPORTATION);
+ }
+
+ return tp;
+} // end player_teleport()
+
+int player_regen(void)
+{
+ int rr = you.hp_max / 3;
+
+ if (rr > 20)
+ rr = 20 + ((rr - 20) / 2);
+
+ /* rings */
+ rr += 40 * player_equip( EQ_RINGS, RING_REGENERATION );
+
+ /* spell */
+ if (you.duration[DUR_REGENERATION])
+ rr += 100;
+
+ /* troll or troll leather -- trolls can't get both */
+ if (you.species == SP_TROLL)
+ rr += 40;
+ else if (player_equip( EQ_BODY_ARMOUR, ARM_TROLL_LEATHER_ARMOUR ))
+ rr += 30;
+
+ /* fast heal mutation */
+ rr += you.mutation[MUT_REGENERATION] * 20;
+
+ /* ghouls heal slowly */
+ // dematerialized people heal slowly
+ // dematerialized ghouls shouldn't heal any more slowly -- bwr
+ if ((you.species == SP_GHOUL
+ && (you.attribute[ATTR_TRANSFORMATION] == TRAN_NONE
+ || you.attribute[ATTR_TRANSFORMATION] == TRAN_BLADE_HANDS))
+ || you.attribute[ATTR_TRANSFORMATION] == TRAN_AIR)
+ {
+ rr /= 2;
+ }
+
+ if (rr < 1)
+ rr = 1;
+
+ return (rr);
+}
+
+int player_hunger_rate(void)
+{
+ int hunger = 3;
+
+ // jmf: hunger isn't fair while you can't eat
+ // Actually, it is since you can detransform any time you like -- bwr
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_AIR)
+ return 0;
+
+ switch (you.species)
+ {
+ case SP_HALFLING:
+ case SP_SPRIGGAN:
+ hunger--;
+ break;
+
+ case SP_OGRE:
+ case SP_OGRE_MAGE:
+ case SP_DEMIGOD:
+ hunger++;
+ break;
+
+ case SP_CENTAUR:
+ hunger += 2;
+ break;
+
+ case SP_TROLL:
+ hunger += 6;
+ break;
+ }
+
+ if (you.duration[DUR_REGENERATION] > 0)
+ hunger += 4;
+
+ // moved here from acr.cc... maintaining the >= 40 behaviour
+ if (you.hunger >= 40)
+ {
+ if (you.invis > 0)
+ hunger += 5;
+
+ // berserk has its own food penalty -- excluding berserk haste
+ if (you.haste > 0 && !you.berserker)
+ hunger += 5;
+ }
+
+ hunger += you.mutation[MUT_FAST_METABOLISM];
+
+ if (you.mutation[MUT_SLOW_METABOLISM] > 2)
+ hunger -= 2;
+ else if (you.mutation[MUT_SLOW_METABOLISM] > 0)
+ hunger--;
+
+ // rings
+ hunger += 2 * player_equip( EQ_RINGS, RING_REGENERATION );
+ hunger += 4 * player_equip( EQ_RINGS, RING_HUNGER );
+ hunger -= 2 * player_equip( EQ_RINGS, RING_SUSTENANCE );
+
+ // weapon ego types
+ hunger += 6 * player_equip_ego_type( EQ_WEAPON, SPWPN_VAMPIRICISM );
+ hunger += 9 * player_equip_ego_type( EQ_WEAPON, SPWPN_VAMPIRES_TOOTH );
+
+ // troll leather armour
+ hunger += player_equip( EQ_BODY_ARMOUR, ARM_TROLL_LEATHER_ARMOUR );
+
+ // randarts
+ hunger += scan_randarts(RAP_METABOLISM);
+
+ // burden
+ hunger += you.burden_state;
+
+ if (hunger < 1)
+ hunger = 1;
+
+ return (hunger);
+}
+
+int player_spell_levels(void)
+{
+ int sl = (you.experience_level - 1) + (you.skills[SK_SPELLCASTING] * 2);
+
+ bool fireball = false;
+ bool delayed_fireball = false;
+
+ if (sl > 99)
+ sl = 99;
+
+ for (int i = 0; i < 25; i++)
+ {
+ if (you.spells[i] == SPELL_FIREBALL)
+ fireball = true;
+ else if (you.spells[i] == SPELL_DELAYED_FIREBALL)
+ delayed_fireball = true;
+
+ if (you.spells[i] != SPELL_NO_SPELL)
+ sl -= spell_difficulty(you.spells[i]);
+ }
+
+ // Fireball is free for characters with delayed fireball
+ if (fireball && delayed_fireball)
+ sl += spell_difficulty( SPELL_FIREBALL );
+
+ // Note: This can happen because of level drain. Maybe we should
+ // force random spells out when that happens. -- bwr
+ if (sl < 0)
+ sl = 0;
+
+ return (sl);
+}
+
+int player_res_magic(void)
+{
+ int rm = 0;
+
+ switch (you.species)
+ {
+ default:
+ rm = you.experience_level * 3;
+ break;
+ case SP_HIGH_ELF:
+ case SP_GREY_ELF:
+ case SP_ELF:
+ case SP_SLUDGE_ELF:
+ case SP_HILL_DWARF:
+ case SP_MOUNTAIN_DWARF:
+ rm = you.experience_level * 4;
+ break;
+ case SP_NAGA:
+ rm = you.experience_level * 5;
+ break;
+ case SP_PURPLE_DRACONIAN:
+ case SP_GNOME:
+ case SP_DEEP_ELF:
+ rm = you.experience_level * 6;
+ break;
+ case SP_SPRIGGAN:
+ rm = you.experience_level * 7;
+ break;
+ }
+
+ /* armour */
+ rm += 30 * player_equip_ego_type( EQ_ALL_ARMOUR, SPARM_MAGIC_RESISTANCE );
+
+ /* rings of magic resistance */
+ rm += 40 * player_equip( EQ_RINGS, RING_PROTECTION_FROM_MAGIC );
+
+ /* randarts */
+ rm += scan_randarts(RAP_MAGIC);
+
+ /* Enchantment skill */
+ rm += 2 * you.skills[SK_ENCHANTMENTS];
+
+ /* Mutations */
+ rm += 30 * you.mutation[MUT_MAGIC_RESISTANCE];
+
+ /* transformations */
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_LICH)
+ rm += 50;
+
+ return rm;
+}
+
+int player_res_fire(void)
+{
+ int rf = 0;
+
+ /* rings of fire resistance/fire */
+ rf += player_equip( EQ_RINGS, RING_PROTECTION_FROM_FIRE );
+ rf += player_equip( EQ_RINGS, RING_FIRE );
+
+ /* rings of ice */
+ rf -= player_equip( EQ_RINGS, RING_ICE );
+
+ /* Staves */
+ rf += player_equip( EQ_STAFF, STAFF_FIRE );
+
+ // body armour:
+ rf += 2 * player_equip( EQ_BODY_ARMOUR, ARM_DRAGON_ARMOUR );
+ rf += player_equip( EQ_BODY_ARMOUR, ARM_GOLD_DRAGON_ARMOUR );
+ rf -= player_equip( EQ_BODY_ARMOUR, ARM_ICE_DRAGON_ARMOUR );
+
+ // ego armours
+ rf += player_equip_ego_type( EQ_ALL_ARMOUR, SPARM_FIRE_RESISTANCE );
+ rf += player_equip_ego_type( EQ_ALL_ARMOUR, SPARM_RESISTANCE );
+
+ // randart weapons:
+ rf += scan_randarts(RAP_FIRE);
+
+ // species:
+ if (you.species == SP_MUMMY)
+ rf--;
+ else if (you.species == SP_RED_DRACONIAN && you.experience_level > 17)
+ rf++;
+
+ // mutations:
+ rf += you.mutation[MUT_HEAT_RESISTANCE];
+
+ if (you.fire_shield)
+ rf += 2;
+
+ // transformations:
+ switch (you.attribute[ATTR_TRANSFORMATION])
+ {
+ case TRAN_ICE_BEAST:
+ rf--;
+ break;
+ case TRAN_DRAGON:
+ rf += 2;
+ break;
+ case TRAN_SERPENT_OF_HELL:
+ rf += 2;
+ break;
+ case TRAN_AIR:
+ rf -= 2;
+ break;
+ }
+
+ if (rf < -3)
+ rf = -3;
+ else if (rf > 3)
+ rf = 3;
+
+ return (rf);
+}
+
+int player_res_cold(void)
+{
+ int rc = 0;
+
+ /* rings of fire resistance/fire */
+ rc += player_equip( EQ_RINGS, RING_PROTECTION_FROM_COLD );
+ rc += player_equip( EQ_RINGS, RING_ICE );
+
+ /* rings of ice */
+ rc -= player_equip( EQ_RINGS, RING_FIRE );
+
+ /* Staves */
+ rc += player_equip( EQ_STAFF, STAFF_COLD );
+
+ // body armour:
+ rc += 2 * player_equip( EQ_BODY_ARMOUR, ARM_ICE_DRAGON_ARMOUR );
+ rc += player_equip( EQ_BODY_ARMOUR, ARM_GOLD_DRAGON_ARMOUR );
+ rc -= player_equip( EQ_BODY_ARMOUR, ARM_DRAGON_ARMOUR );
+
+ // ego armours
+ rc += player_equip_ego_type( EQ_ALL_ARMOUR, SPARM_COLD_RESISTANCE );
+ rc += player_equip_ego_type( EQ_ALL_ARMOUR, SPARM_RESISTANCE );
+
+ // randart weapons:
+ rc += scan_randarts(RAP_COLD);
+
+ // species:
+ if (you.species == SP_MUMMY || you.species == SP_GHOUL)
+ rc++;
+ else if (you.species == SP_WHITE_DRACONIAN && you.experience_level > 17)
+ rc++;
+
+ // mutations:
+ rc += you.mutation[MUT_COLD_RESISTANCE];
+
+ if (you.fire_shield)
+ rc -= 2;
+
+ // transformations:
+ switch (you.attribute[ATTR_TRANSFORMATION])
+ {
+ case TRAN_ICE_BEAST:
+ rc += 3;
+ break;
+ case TRAN_DRAGON:
+ rc--;
+ break;
+ case TRAN_LICH:
+ rc++;
+ break;
+ case TRAN_AIR:
+ rc -= 2;
+ break;
+ }
+
+ if (rc < -3)
+ rc = -3;
+ else if (rc > 3)
+ rc = 3;
+
+ return (rc);
+}
+
+int player_res_electricity(void)
+{
+ int re = 0;
+
+ if (you.duration[DUR_INSULATION])
+ re++;
+
+ // staff
+ re += player_equip( EQ_STAFF, STAFF_AIR );
+
+ // body armour:
+ re += player_equip( EQ_BODY_ARMOUR, ARM_STORM_DRAGON_ARMOUR );
+
+ // randart weapons:
+ re += scan_randarts(RAP_ELECTRICITY);
+
+ // species:
+ if (you.species == SP_BLACK_DRACONIAN && you.experience_level > 17)
+ re++;
+
+ // mutations:
+ if (you.mutation[MUT_SHOCK_RESISTANCE])
+ re++;
+
+ // transformations:
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_STATUE)
+ re += 1;
+
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_AIR)
+ re += 2; // mutliple levels currently meaningless
+
+ if (you.attribute[ATTR_DIVINE_LIGHTNING_PROTECTION] > 0)
+ re = 3;
+ else if (re > 1)
+ re = 1;
+
+ return (re);
+} // end player_res_electricity()
+
+// funny that no races are susceptible to poisons {dlb}
+int player_res_poison(void)
+{
+ int rp = 0;
+
+ /* rings of poison resistance */
+ rp += player_equip( EQ_RINGS, RING_POISON_RESISTANCE );
+
+ /* Staves */
+ rp += player_equip( EQ_STAFF, STAFF_POISON );
+
+ /* the staff of Olgreb: */
+ if (you.equip[EQ_WEAPON] != -1
+ && you.inv[you.equip[EQ_WEAPON]].base_type == OBJ_WEAPONS
+ && you.inv[you.equip[EQ_WEAPON]].special == SPWPN_STAFF_OF_OLGREB)
+ {
+ rp++;
+ }
+
+ // ego armour:
+ rp += player_equip_ego_type( EQ_ALL_ARMOUR, SPARM_POISON_RESISTANCE );
+
+ // body armour:
+ rp += player_equip( EQ_BODY_ARMOUR, ARM_GOLD_DRAGON_ARMOUR );
+ rp += player_equip( EQ_BODY_ARMOUR, ARM_SWAMP_DRAGON_ARMOUR );
+
+ // spells:
+ if (you.duration[DUR_RESIST_POISON] > 0)
+ rp++;
+
+ // randart weapons:
+ rp += scan_randarts(RAP_POISON);
+
+ // species:
+ if (you.species == SP_MUMMY || you.species == SP_NAGA
+ || you.species == SP_GHOUL
+ || (you.species == SP_GREEN_DRACONIAN && you.experience_level > 6))
+ {
+ rp++;
+ }
+
+ // mutations:
+ rp += you.mutation[MUT_POISON_RESISTANCE];
+
+ // transformations:
+ switch (you.attribute[ATTR_TRANSFORMATION])
+ {
+ case TRAN_LICH:
+ case TRAN_ICE_BEAST:
+ case TRAN_STATUE:
+ case TRAN_DRAGON:
+ case TRAN_SERPENT_OF_HELL:
+ case TRAN_AIR:
+ rp++;
+ break;
+ }
+
+ if (rp > 3)
+ rp = 3;
+
+ return (rp);
+} // end player_res_poison()
+
+unsigned char player_spec_death(void)
+{
+ int sd = 0;
+
+ /* Staves */
+ sd += player_equip( EQ_STAFF, STAFF_DEATH );
+
+ // body armour:
+ if (player_equip_ego_type( EQ_BODY_ARMOUR, SPARM_ARCHMAGI ))
+ sd++;
+
+ // species:
+ if (you.species == SP_MUMMY)
+ {
+ if (you.experience_level >= 13)
+ sd++;
+ if (you.experience_level >= 26)
+ sd++;
+ }
+
+ // transformations:
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_LICH)
+ sd++;
+
+ return sd;
+}
+
+unsigned char player_spec_holy(void)
+{
+ //if ( you.char_class == JOB_PRIEST || you.char_class == JOB_PALADIN )
+ // return 1;
+ return 0;
+}
+
+unsigned char player_spec_fire(void)
+{
+ int sf = 0;
+
+ // staves:
+ sf += player_equip( EQ_STAFF, STAFF_FIRE );
+
+ // rings of fire:
+ sf += player_equip( EQ_RINGS, RING_FIRE );
+
+ if (you.fire_shield)
+ sf++;
+
+ return sf;
+}
+
+unsigned char player_spec_cold(void)
+{
+ int sc = 0;
+
+ // staves:
+ sc += player_equip( EQ_STAFF, STAFF_COLD );
+
+ // rings of ice:
+ sc += player_equip( EQ_RINGS, RING_ICE );
+
+ return sc;
+}
+
+unsigned char player_spec_earth(void)
+{
+ int se = 0;
+
+ /* Staves */
+ se += player_equip( EQ_STAFF, STAFF_EARTH );
+
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_AIR)
+ se--;
+
+ return se;
+}
+
+unsigned char player_spec_air(void)
+{
+ int sa = 0;
+
+ /* Staves */
+ sa += player_equip( EQ_STAFF, STAFF_AIR );
+
+ //jmf: this was too good
+ //if (you.attribute[ATTR_TRANSFORMATION] == TRAN_AIR)
+ // sa++;
+ return sa;
+}
+
+unsigned char player_spec_conj(void)
+{
+ int sc = 0;
+
+ /* Staves */
+ sc += player_equip( EQ_STAFF, STAFF_CONJURATION );
+
+ // armour of the Archmagi
+ if (player_equip_ego_type( EQ_BODY_ARMOUR, SPARM_ARCHMAGI ))
+ sc++;
+
+ return sc;
+}
+
+unsigned char player_spec_ench(void)
+{
+ int se = 0;
+
+ /* Staves */
+ se += player_equip( EQ_STAFF, STAFF_ENCHANTMENT );
+
+ // armour of the Archmagi
+ if (player_equip_ego_type( EQ_BODY_ARMOUR, SPARM_ARCHMAGI ))
+ se++;
+
+ return se;
+}
+
+unsigned char player_spec_summ(void)
+{
+ int ss = 0;
+
+ /* Staves */
+ ss += player_equip( EQ_STAFF, STAFF_SUMMONING );
+
+ // armour of the Archmagi
+ if (player_equip_ego_type( EQ_BODY_ARMOUR, SPARM_ARCHMAGI ))
+ ss++;
+
+ return ss;
+}
+
+unsigned char player_spec_poison(void)
+{
+ int sp = 0;
+
+ /* Staves */
+ sp += player_equip( EQ_STAFF, STAFF_POISON );
+
+ if (you.equip[EQ_WEAPON] != -1
+ && you.inv[you.equip[EQ_WEAPON]].base_type == OBJ_WEAPONS
+ && you.inv[you.equip[EQ_WEAPON]].special == SPWPN_STAFF_OF_OLGREB)
+ {
+ sp++;
+ }
+
+ return sp;
+}
+
+unsigned char player_energy(void)
+{
+ unsigned char pe = 0;
+
+ // Staves
+ pe += player_equip( EQ_STAFF, STAFF_ENERGY );
+
+ return pe;
+}
+
+int player_prot_life(void)
+{
+ int pl = 0;
+
+ // rings
+ pl += player_equip( EQ_RINGS, RING_LIFE_PROTECTION );
+
+ // armour: (checks body armour only)
+ pl += player_equip_ego_type( EQ_ALL_ARMOUR, SPARM_POSITIVE_ENERGY );
+
+ if (you.is_undead)
+ pl += 3;
+
+ switch (you.attribute[ATTR_TRANSFORMATION])
+ {
+ case TRAN_STATUE:
+ pl += 1;
+ break;
+
+ case TRAN_SERPENT_OF_HELL:
+ pl += 2;
+ break;
+
+ case TRAN_LICH:
+ pl += 3;
+ break;
+
+ default:
+ break;
+ }
+
+ // randart wpns
+ pl += scan_randarts(RAP_NEGATIVE_ENERGY);
+
+ // demonic power
+ pl += you.mutation[MUT_NEGATIVE_ENERGY_RESISTANCE];
+
+ if (pl > 3)
+ pl = 3;
+
+ return (pl);
+}
+
+// New player movement speed system... allows for a bit more that
+// "player runs fast" and "player walks slow" in that the speed is
+// actually calculated (allowing for centaurs to get a bonus from
+// swiftness and other such things). Levels of the mutation now
+// also have meaning (before they all just meant fast). Most of
+// this isn't as fast as it used to be (6 for having anything), but
+// even a slight speed advantage is very good... and we certainly don't
+// want to go past 6 (see below). -- bwr
+int player_movement_speed(void)
+{
+ int mv = 10;
+
+ if (you.species == SP_MERFOLK && player_is_swimming())
+ {
+ // This is swimming... so it doesn't make sense to really
+ // apply the other things (the mutation is "cover ground",
+ // swiftness is an air spell, can't wear boots, can't be
+ // transformed).
+ mv = 6;
+ }
+ else
+ {
+ /* transformations */
+ if (!player_is_shapechanged())
+ {
+ // Centaurs and spriggans are only fast in their regular
+ // shape (ie untransformed, blade hands, lich form)
+ if (you.species == SP_CENTAUR)
+ mv = 8;
+ else if (you.species == SP_SPRIGGAN)
+ mv = 6;
+ }
+ else if (you.attribute[ATTR_TRANSFORMATION] == TRAN_SPIDER)
+ mv = 8;
+
+ /* armour */
+ if (player_equip_ego_type( EQ_BOOTS, SPARM_RUNNING ))
+ mv -= 2;
+
+ if (player_equip_ego_type( EQ_BODY_ARMOUR, SPARM_PONDEROUSNESS ))
+ mv += 2;
+
+ // Swiftness is an Air spell, it doesn't work in water...
+ // but levitating players will move faster. -- bwr
+ if (you.duration[DUR_SWIFTNESS] > 0 && !player_in_water())
+ mv -= (player_is_levitating() ? 4 : 2);
+
+ /* Mutations: -2, -3, -4 */
+ if (you.mutation[MUT_FAST] > 0)
+ mv -= (you.mutation[MUT_FAST] + 1);
+
+ // Burden
+ if (you.burden_state == BS_ENCUMBERED)
+ mv += 1;
+ else if (you.burden_state == BS_OVERLOADED)
+ mv += 3;
+ }
+
+ // We'll use the old value of six as a minimum, with haste this could
+ // end up as a speed of three, which is about as fast as we want
+ // the player to be able to go (since 3 is 3.33x as fast and 2 is 5x,
+ // which is a bit of a jump, and a bit too fast) -- bwr
+ if (mv < 6)
+ mv = 6;
+
+ // Nagas move slowly:
+ if (you.species == SP_NAGA && !player_is_shapechanged())
+ {
+ mv *= 14;
+ mv /= 10;
+ }
+
+ return (mv);
+}
+
+// This function differs from the above in that it's used to set the
+// initial time_taken value for the turn. Everything else (movement,
+// spellcasting, combat) applies a ratio to this value.
+int player_speed(void)
+{
+ int ps = 10;
+
+ if (you.haste)
+ ps /= 2;
+
+ switch (you.attribute[ATTR_TRANSFORMATION])
+ {
+ case TRAN_STATUE:
+ ps *= 15;
+ ps /= 10;
+ break;
+
+ case TRAN_SERPENT_OF_HELL:
+ ps *= 12;
+ ps /= 10;
+ break;
+
+ default:
+ break;
+ }
+
+ return ps;
+}
+
+int player_AC(void)
+{
+ int AC = 0;
+ int i; // loop variable
+
+ // get the armour race value that corresponds to the character's race:
+ const unsigned long racial_type
+ = ((player_genus(GENPC_DWARVEN)) ? ISFLAG_DWARVEN :
+ (player_genus(GENPC_ELVEN)) ? ISFLAG_ELVEN :
+ (you.species == SP_HILL_ORC) ? ISFLAG_ORCISH
+ : 0);
+
+ for (i = EQ_CLOAK; i <= EQ_BODY_ARMOUR; i++)
+ {
+ const int item = you.equip[i];
+
+ if (item == -1 || i == EQ_SHIELD)
+ continue;
+
+ AC += you.inv[ item ].plus;
+
+ // Note that helms and boots have a sub-sub classing system
+ // which uses "plus2"... since not all members have the same
+ // AC value, we use special cases. -- bwr
+ if (i == EQ_HELMET
+ && (cmp_helmet_type( you.inv[ item ], THELM_CAP )
+ || cmp_helmet_type( you.inv[ item ], THELM_WIZARD_HAT )
+ || cmp_helmet_type( you.inv[ item ], THELM_SPECIAL )))
+ {
+ continue;
+ }
+
+ if (i == EQ_BOOTS
+ && (you.inv[ item ].plus2 == TBOOT_NAGA_BARDING
+ || you.inv[ item ].plus2 == TBOOT_CENTAUR_BARDING))
+ {
+ AC += 3;
+ }
+
+ int racial_bonus = 0; // additional levels of armour skill
+ const unsigned long armour_race = get_equip_race( you.inv[ item ] );
+ const int ac_value = property( you.inv[ item ], PARM_AC );
+
+ // Dwarven armour is universally good -- bwr
+ if (armour_race == ISFLAG_DWARVEN)
+ racial_bonus += 2;
+
+ if (racial_type && armour_race == racial_type)
+ {
+ // Elven armour is light, but still gives one level
+ // to elves. Orcish and Dwarven armour are worth +2
+ // to the correct species, plus the plus that anyone
+ // gets with dwarven armour. -- bwr
+
+ if (racial_type == ISFLAG_ELVEN)
+ racial_bonus++;
+ else
+ racial_bonus += 2;
+ }
+
+ AC += ac_value * (15 + you.skills[SK_ARMOUR] + racial_bonus) / 15;
+
+ /* Nagas/Centaurs/the deformed don't fit into body armour very well */
+ if ((you.species == SP_NAGA || you.species == SP_CENTAUR
+ || you.mutation[MUT_DEFORMED] > 0) && i == EQ_BODY_ARMOUR)
+ {
+ AC -= ac_value / 2;
+ }
+ }
+
+ AC += player_equip( EQ_RINGS_PLUS, RING_PROTECTION );
+
+ if (player_equip_ego_type( EQ_WEAPON, SPWPN_PROTECTION ))
+ AC += 5;
+
+ if (player_equip_ego_type( EQ_SHIELD, SPARM_PROTECTION ))
+ AC += 3;
+
+ AC += scan_randarts(RAP_AC);
+
+ if (you.duration[DUR_ICY_ARMOUR])
+ AC += 4 + you.skills[SK_ICE_MAGIC] / 3; // max 13
+
+ if (you.duration[DUR_STONEMAIL])
+ AC += 5 + you.skills[SK_EARTH_MAGIC] / 2; // max 18
+
+ if (you.duration[DUR_STONESKIN])
+ AC += 2 + you.skills[SK_EARTH_MAGIC] / 5; // max 7
+
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_NONE
+ || you.attribute[ATTR_TRANSFORMATION] == TRAN_LICH
+ || you.attribute[ATTR_TRANSFORMATION] == TRAN_BLADE_HANDS)
+ {
+ // Being a lich doesn't preclude the benefits of hide/scales -- bwr
+ //
+ // Note: Even though necromutation is a high level spell, it does
+ // allow the character full armour (so the bonus is low). -- bwr
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_LICH)
+ AC += (3 + you.skills[SK_NECROMANCY] / 6); // max 7
+
+ //jmf: only give:
+ if (player_genus(GENPC_DRACONIAN))
+ {
+ if (you.experience_level < 8)
+ AC += 2;
+ else if (you.species == SP_GREY_DRACONIAN)
+ AC += 1 + (you.experience_level - 4) / 2; // max 12
+ else
+ AC += 1 + (you.experience_level / 4); // max 7
+ }
+ else
+ {
+ switch (you.species)
+ {
+ case SP_NAGA:
+ AC += you.experience_level / 3; // max 9
+ break;
+
+ case SP_OGRE:
+ AC++;
+ break;
+
+ case SP_TROLL:
+ case SP_CENTAUR:
+ AC += 3;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // Scales -- some evil uses of the fact that boolean "true" == 1...
+ // I'll spell things out with some comments -- bwr
+
+ // mutations:
+ // these give: +1, +2, +3
+ AC += you.mutation[MUT_TOUGH_SKIN];
+ AC += you.mutation[MUT_GREY_SCALES];
+ AC += you.mutation[MUT_SPECKLED_SCALES];
+ AC += you.mutation[MUT_IRIDESCENT_SCALES];
+ AC += you.mutation[MUT_PATTERNED_SCALES];
+ AC += you.mutation[MUT_BLUE_SCALES];
+
+ // these gives: +1, +3, +5
+ if (you.mutation[MUT_GREEN_SCALES] > 0)
+ AC += (you.mutation[MUT_GREEN_SCALES] * 2) - 1;
+ if (you.mutation[MUT_NACREOUS_SCALES] > 0)
+ AC += (you.mutation[MUT_NACREOUS_SCALES] * 2) - 1;
+ if (you.mutation[MUT_BLACK2_SCALES] > 0)
+ AC += (you.mutation[MUT_BLACK2_SCALES] * 2) - 1;
+ if (you.mutation[MUT_WHITE_SCALES] > 0)
+ AC += (you.mutation[MUT_WHITE_SCALES] * 2) - 1;
+
+ // these give: +2, +4, +6
+ AC += you.mutation[MUT_GREY2_SCALES] * 2;
+ AC += you.mutation[MUT_YELLOW_SCALES] * 2;
+ AC += you.mutation[MUT_PURPLE_SCALES] * 2;
+
+ // black gives: +3, +6, +9
+ AC += you.mutation[MUT_BLACK_SCALES] * 3;
+
+ // boney plates give: +2, +3, +4
+ if (you.mutation[MUT_BONEY_PLATES] > 0)
+ AC += you.mutation[MUT_BONEY_PLATES] + 1;
+
+ // red gives +1, +2, +4
+ AC += you.mutation[MUT_RED_SCALES]
+ + (you.mutation[MUT_RED_SCALES] == 3);
+
+ // indigo gives: +2, +3, +5
+ if (you.mutation[MUT_INDIGO_SCALES] > 0)
+ {
+ AC += 1 + you.mutation[MUT_INDIGO_SCALES]
+ + (you.mutation[MUT_INDIGO_SCALES] == 3);
+ }
+
+ // brown gives: +2, +4, +5
+ AC += (you.mutation[MUT_BROWN_SCALES] * 2)
+ - (you.mutation[MUT_METALLIC_SCALES] == 3);
+
+ // orange gives: +1, +3, +4
+ AC += you.mutation[MUT_ORANGE_SCALES]
+ + (you.mutation[MUT_ORANGE_SCALES] > 1);
+
+ // knobbly red gives: +2, +5, +7
+ AC += (you.mutation[MUT_RED2_SCALES] * 2)
+ + (you.mutation[MUT_RED2_SCALES] > 1);
+
+ // metallic gives +3, +7, +10
+ AC += you.mutation[MUT_METALLIC_SCALES] * 3
+ + (you.mutation[MUT_METALLIC_SCALES] > 1);
+ }
+ else
+ {
+ // transformations:
+ switch (you.attribute[ATTR_TRANSFORMATION])
+ {
+ case TRAN_NONE:
+ case TRAN_BLADE_HANDS:
+ case TRAN_LICH: // can wear normal body armour (small bonus)
+ break;
+
+
+ case TRAN_SPIDER: // low level (small bonus), also gets EV
+ AC += (2 + you.skills[SK_POISON_MAGIC] / 6); // max 6
+ break;
+
+ case TRAN_ICE_BEAST:
+ AC += (5 + (you.skills[SK_ICE_MAGIC] + 1) / 4); // max 12
+
+ if (you.duration[DUR_ICY_ARMOUR])
+ AC += (1 + you.skills[SK_ICE_MAGIC] / 4); // max +7
+ break;
+
+ case TRAN_DRAGON:
+ AC += (7 + you.skills[SK_FIRE_MAGIC] / 3); // max 16
+ break;
+
+ case TRAN_STATUE: // main ability is armour (high bonus)
+ AC += (17 + you.skills[SK_EARTH_MAGIC] / 2); // max 30
+
+ if (you.duration[DUR_STONESKIN] || you.duration[DUR_STONEMAIL])
+ AC += (1 + you.skills[SK_EARTH_MAGIC] / 4); // max +7
+ break;
+
+ case TRAN_SERPENT_OF_HELL:
+ AC += (10 + you.skills[SK_FIRE_MAGIC] / 3); // max 19
+ break;
+
+ case TRAN_AIR: // air - scales & species ought to be irrelevent
+ AC = (you.skills[SK_AIR_MAGIC] * 3) / 2; // max 40
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return AC;
+}
+
+bool is_light_armour( const item_def &item )
+{
+ if (cmp_equip_race( item, ISFLAG_ELVEN ))
+ return (true);
+
+ switch (item.sub_type)
+ {
+ case ARM_ROBE:
+ case ARM_ANIMAL_SKIN:
+ case ARM_LEATHER_ARMOUR:
+ case ARM_STEAM_DRAGON_HIDE:
+ case ARM_STEAM_DRAGON_ARMOUR:
+ case ARM_MOTTLED_DRAGON_HIDE:
+ case ARM_MOTTLED_DRAGON_ARMOUR:
+ //case ARM_TROLL_HIDE: //jmf: these are knobbly and stiff
+ //case ARM_TROLL_LEATHER_ARMOUR:
+ return (true);
+
+ default:
+ return (false);
+ }
+}
+
+bool player_light_armour(void)
+{
+ if (you.equip[EQ_BODY_ARMOUR] == -1)
+ return true;
+
+ return (is_light_armour( you.inv[you.equip[EQ_BODY_ARMOUR]] ));
+} // end player_light_armour()
+
+//
+// This function returns true if the player has a radically different
+// shape... minor changes like blade hands don't count, also note
+// that lich transformation doesn't change the character's shape
+// (so we end up with Naga-lichs, Spiggan-lichs, Minotaur-lichs)
+// it just makes the character undead (with the benefits that implies). --bwr
+//
+bool player_is_shapechanged(void)
+{
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_NONE
+ || you.attribute[ATTR_TRANSFORMATION] == TRAN_BLADE_HANDS
+ || you.attribute[ATTR_TRANSFORMATION] == TRAN_LICH)
+ {
+ return (false);
+ }
+
+ return (true);
+}
+
+int player_evasion(void)
+{
+ int ev = 10;
+
+ int armour_ev_penalty;
+
+ if (you.equip[EQ_BODY_ARMOUR] == -1)
+ armour_ev_penalty = 0;
+ else
+ {
+ armour_ev_penalty = property( you.inv[you.equip[EQ_BODY_ARMOUR]],
+ PARM_EVASION );
+ }
+
+ // We return 2 here to give the player some chance of not being hit,
+ // repulsion fields still work while paralysed
+ if (you.paralysis)
+ return (2 + you.mutation[MUT_REPULSION_FIELD] * 2);
+
+ if (you.species == SP_CENTAUR)
+ ev -= 3;
+
+ if (you.equip[EQ_BODY_ARMOUR] != -1)
+ {
+ int ev_change = 0;
+
+ ev_change = armour_ev_penalty;
+ ev_change += you.skills[SK_ARMOUR] / 3;
+
+ if (ev_change > armour_ev_penalty / 3)
+ ev_change = armour_ev_penalty / 3;
+
+ ev += ev_change; /* remember that it's negative */
+ }
+
+ ev += player_equip( EQ_RINGS_PLUS, RING_EVASION );
+
+ if (player_equip_ego_type( EQ_BODY_ARMOUR, SPARM_PONDEROUSNESS ))
+ ev -= 2;
+
+ if (you.duration[DUR_STONEMAIL])
+ ev -= 2;
+
+ if (you.duration[DUR_FORESCRY])
+ ev += 8; //jmf: is this a reasonable value?
+
+ int emod = 0;
+
+ if (!player_light_armour())
+ {
+ // meaning that the armour evasion modifier is often effectively
+ // applied twice, but not if you're wearing elven armour
+ emod += (armour_ev_penalty * 14) / 10;
+ }
+
+ emod += you.skills[SK_DODGING] / 2;
+
+ if (emod > 0)
+ ev += emod;
+
+ if (you.mutation[MUT_REPULSION_FIELD] > 0)
+ ev += (you.mutation[MUT_REPULSION_FIELD] * 2) - 1;
+
+ switch (you.attribute[ATTR_TRANSFORMATION])
+ {
+ case TRAN_DRAGON:
+ ev -= 3;
+ break;
+
+ case TRAN_STATUE:
+ case TRAN_SERPENT_OF_HELL:
+ ev -= 5;
+ break;
+
+ case TRAN_SPIDER:
+ ev += 3;
+ break;
+
+ case TRAN_AIR:
+ ev += 20;
+ break;
+
+ default:
+ break;
+ }
+
+ ev += scan_randarts(RAP_EVASION);
+
+ return ev;
+} // end player_evasion()
+
+int player_magical_power( void )
+{
+ int ret = 0;
+
+ ret += 13 * player_equip( EQ_STAFF, STAFF_POWER );
+ ret += 9 * player_equip( EQ_RINGS, RING_MAGICAL_POWER );
+
+ return (ret);
+}
+
+int player_mag_abil(bool is_weighted)
+{
+ int ma = 0;
+
+ ma += 3 * player_equip( EQ_RINGS, RING_WIZARDRY );
+
+ /* Staves */
+ ma += 4 * player_equip( EQ_STAFF, STAFF_WIZARDRY );
+
+ /* armour of the Archmagi (checks body armour only) */
+ ma += 2 * player_equip_ego_type( EQ_BODY_ARMOUR, SPARM_ARCHMAGI );
+
+ return ((is_weighted) ? ((ma * you.intel) / 10) : ma);
+} // end player_mag_abil()
+
+int player_shield_class(void) //jmf: changes for new spell
+{
+ int base_shield = 0;
+ const int shield = you.equip[EQ_SHIELD];
+
+ if (shield == -1)
+ {
+ if (!you.fire_shield && you.duration[DUR_CONDENSATION_SHIELD])
+ base_shield = 2 + (you.skills[SK_ICE_MAGIC] / 6); // max 6
+ else
+ return (0);
+ }
+ else
+ {
+ switch (you.inv[ shield ].sub_type)
+ {
+ case ARM_BUCKLER:
+ base_shield = 3; // +3/20 per skill level max 7
+ break;
+ case ARM_SHIELD:
+ base_shield = 5; // +5/20 per skill level max 11
+ break;
+ case ARM_LARGE_SHIELD:
+ base_shield = 7; // +7/20 per skill level max 16
+ break;
+ }
+
+ // bonus applied only to base, see above for effect:
+ base_shield *= (20 + you.skills[SK_SHIELDS]);
+ base_shield /= 20;
+
+ base_shield += you.inv[ shield ].plus;
+ }
+
+ return (base_shield);
+} // end player_shield_class()
+
+unsigned char player_see_invis(void)
+{
+ unsigned char si = 0;
+
+ si += player_equip( EQ_RINGS, RING_SEE_INVISIBLE );
+
+ /* armour: (checks head armour only) */
+ si += player_equip_ego_type( EQ_HELMET, SPARM_SEE_INVISIBLE );
+
+ /* Nagas & Spriggans have good eyesight */
+ if (you.species == SP_NAGA || you.species == SP_SPRIGGAN)
+ si++;
+
+ if (you.mutation[MUT_ACUTE_VISION] > 0)
+ si += you.mutation[MUT_ACUTE_VISION];
+
+ //jmf: added see_invisible spell
+ if (you.duration[DUR_SEE_INVISIBLE] > 0)
+ si++;
+
+ /* randart wpns */
+ int artefacts = scan_randarts(RAP_EYESIGHT);
+
+ if (artefacts > 0)
+ si += artefacts;
+
+ return si;
+}
+
+// This does NOT do line of sight! It checks the monster's visibility
+// with repect to the players perception, but doesn't do walls or range...
+// to find if the square the monster is in is visible see mons_near().
+bool player_monster_visible( struct monsters *mon )
+{
+ if (mons_has_ench( mon, ENCH_SUBMERGED )
+ || (mons_has_ench( mon, ENCH_INVIS ) && !player_see_invis()))
+ {
+ return (false);
+ }
+
+ return (true);
+}
+
+unsigned char player_sust_abil(void)
+{
+ unsigned char sa = 0;
+
+ sa += player_equip( EQ_RINGS, RING_SUSTAIN_ABILITIES );
+
+ return sa;
+} // end player_sust_abil()
+
+int carrying_capacity(void)
+{
+ // Originally: 1000 + you.strength * 200 + ( you.levitation ? 1000 : 0 )
+ return (3500 + (you.strength * 100) + (player_is_levitating() ? 1000 : 0));
+}
+
+int burden_change(void)
+{
+ char old_burdenstate = you.burden_state;
+
+ you.burden = 0;
+
+ int max_carried = carrying_capacity();
+
+ if (you.duration[DUR_STONEMAIL])
+ you.burden += 800;
+
+ for (unsigned char bu = 0; bu < ENDOFPACK; bu++)
+ {
+ if (you.inv[bu].quantity < 1)
+ continue;
+
+ if (you.inv[bu].base_type == OBJ_CORPSES)
+ {
+ if (you.inv[bu].sub_type == CORPSE_BODY)
+ you.burden += mons_weight(you.inv[bu].plus);
+ else if (you.inv[bu].sub_type == CORPSE_SKELETON)
+ you.burden += mons_weight(you.inv[bu].plus) / 2;
+ }
+ else
+ {
+ you.burden += mass_item( you.inv[bu] ) * you.inv[bu].quantity;
+ }
+ }
+
+ you.burden_state = BS_UNENCUMBERED;
+ set_redraw_status( REDRAW_BURDEN );
+
+ // changed the burdened levels to match the change to max_carried
+ if (you.burden < (max_carried * 5) / 6)
+ // (you.burden < max_carried - 1000)
+ {
+ you.burden_state = BS_UNENCUMBERED;
+
+ // this message may have to change, just testing {dlb}
+ if (old_burdenstate != you.burden_state)
+ mpr("Your possessions no longer seem quite so burdensome.");
+ }
+ else if (you.burden < (max_carried * 11) / 12)
+ // (you.burden < max_carried - 500)
+ {
+ you.burden_state = BS_ENCUMBERED;
+
+ if (old_burdenstate != you.burden_state)
+ mpr("You are being weighed down by all of your possessions.");
+ }
+ else
+ {
+ you.burden_state = BS_OVERLOADED;
+
+ if (old_burdenstate != you.burden_state)
+ mpr("You are being crushed by all of your possessions.");
+ }
+
+ return you.burden;
+} // end burden_change()
+
+bool you_resist_magic(int power)
+{
+ int ench_power = stepdown_value( power, 30, 40, 100, 120 );
+
+ int mrchance = 100 + player_res_magic();
+
+ mrchance -= ench_power;
+
+ int mrch2 = random2(100) + random2(101);
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "Power: %d, player's MR: %d, target: %d, roll: %d",
+ ench_power, player_res_magic(), mrchance, mrch2 );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ if (mrch2 < mrchance)
+ return true; // ie saved successfully
+
+ return false;
+/* if (random2(power) / 3 + random2(power) / 3 + random2(power) / 3 >= player_res_magic()) return 0;
+ return 1; */
+}
+
+void forget_map(unsigned char chance_forgotten)
+{
+ unsigned char xcount, ycount = 0;
+
+ for (xcount = 0; xcount < GXM; xcount++)
+ {
+ for (ycount = 0; ycount < GYM; ycount++)
+ {
+ if (random2(100) < chance_forgotten)
+ {
+ env.map[xcount][ycount] = 0;
+ }
+ }
+ }
+} // end forget_map()
+
+void gain_exp( unsigned int exp_gained )
+{
+
+ if (player_equip_ego_type( EQ_BODY_ARMOUR, SPARM_ARCHMAGI )
+ && !one_chance_in(20))
+ {
+ return;
+ }
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "gain_exp: %d", exp_gained );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ if (you.experience + exp_gained > 8999999)
+ you.experience = 8999999;
+ else
+ you.experience += exp_gained;
+
+ if (you.exp_available + exp_gained > 20000)
+ you.exp_available = 20000;
+ else
+ you.exp_available += exp_gained;
+
+ level_change();
+} // end gain_exp()
+
+void level_change(void)
+{
+ int hp_adjust = 0;
+ int mp_adjust = 0;
+
+ // necessary for the time being, as level_change() is called
+ // directly sometimes {dlb}
+ you.redraw_experience = 1;
+
+ while (you.experience_level < 27
+ && you.experience > exp_needed(you.experience_level + 2))
+ {
+ you.experience_level++;
+
+ if (you.experience_level <= you.max_level)
+ {
+ snprintf( info, INFO_SIZE, "Welcome back to level %d!",
+ you.experience_level );
+
+ mpr(info, MSGCH_INTRINSIC_GAIN);
+ more();
+
+ // Gain back the hp and mp we lose in lose_level(). -- bwr
+ inc_hp( 4, true );
+ inc_mp( 1, true );
+ }
+ else // character has gained a new level
+ {
+ snprintf( info, INFO_SIZE, "You are now a level %d %s!",
+ you.experience_level, you.class_name );
+
+ mpr(info, MSGCH_INTRINSIC_GAIN);
+ more();
+
+ int brek = 0;
+
+ if (you.experience_level > 21)
+ brek = (coinflip() ? 3 : 2);
+ else if (you.experience_level > 12)
+ brek = 3 + random2(3); // up from 2 + rand(3) -- bwr
+ else
+ brek = 4 + random2(4); // up from 3 + rand(4) -- bwr
+
+ inc_hp( brek, true );
+ inc_mp( 1, true );
+
+ if (!(you.experience_level % 3))
+ ability_increase();
+
+ switch (you.species)
+ {
+ case SP_HUMAN:
+ if (!(you.experience_level % 5))
+ modify_stat(STAT_RANDOM, 1, false);
+ break;
+
+ case SP_ELF:
+ if (you.experience_level % 3)
+ hp_adjust--;
+ else
+ mp_adjust++;
+
+ if (!(you.experience_level % 4))
+ {
+ modify_stat( (coinflip() ? STAT_INTELLIGENCE
+ : STAT_DEXTERITY), 1, false );
+ }
+ break;
+
+ case SP_HIGH_ELF:
+ if (you.experience_level == 15)
+ {
+ //jmf: got Glamour ability
+ mpr("You feel charming!", MSGCH_INTRINSIC_GAIN);
+ }
+
+ if (you.experience_level % 3)
+ hp_adjust--;
+
+ if (!(you.experience_level % 2))
+ mp_adjust++;
+
+ if (!(you.experience_level % 3))
+ {
+ modify_stat( (coinflip() ? STAT_INTELLIGENCE
+ : STAT_DEXTERITY), 1, false );
+ }
+ break;
+
+ case SP_GREY_ELF:
+ if (you.experience_level == 5)
+ {
+ //jmf: got Glamour ability
+ mpr("You feel charming!", MSGCH_INTRINSIC_GAIN);
+ mp_adjust++;
+ }
+
+ if (you.experience_level < 14)
+ hp_adjust--;
+
+ if (you.experience_level % 3)
+ mp_adjust++;
+
+ if (!(you.experience_level % 4))
+ {
+ modify_stat( (coinflip() ? STAT_INTELLIGENCE
+ : STAT_DEXTERITY), 1, false );
+ }
+
+ break;
+
+ case SP_DEEP_ELF:
+ if (you.experience_level < 17)
+ hp_adjust--;
+ if (!(you.experience_level % 3))
+ hp_adjust--;
+
+ mp_adjust++;
+
+ if (!(you.experience_level % 4))
+ modify_stat(STAT_INTELLIGENCE, 1, false);
+ break;
+
+ case SP_SLUDGE_ELF:
+ if (you.experience_level % 3)
+ hp_adjust--;
+ else
+ mp_adjust++;
+
+ if (!(you.experience_level % 4))
+ {
+ modify_stat( (coinflip() ? STAT_INTELLIGENCE
+ : STAT_DEXTERITY), 1, false );
+ }
+ break;
+
+ case SP_HILL_DWARF:
+ // lowered because of HD raise -- bwr
+ // if (you.experience_level < 14)
+ // hp_adjust++;
+
+ if (you.experience_level % 3)
+ hp_adjust++;
+
+ if (!(you.experience_level % 2))
+ mp_adjust--;
+
+ if (!(you.experience_level % 4))
+ modify_stat(STAT_STRENGTH, 1, false);
+ break;
+
+ case SP_MOUNTAIN_DWARF:
+ // lowered because of HD raise -- bwr
+ // if (you.experience_level < 14)
+ // hp_adjust++;
+
+ if (!(you.experience_level % 2))
+ hp_adjust++;
+
+ if (!(you.experience_level % 3))
+ mp_adjust--;
+
+ if (!(you.experience_level % 4))
+ modify_stat(STAT_STRENGTH, 1, false);
+ break;
+
+ case SP_HALFLING:
+ if (!(you.experience_level % 5))
+ modify_stat(STAT_DEXTERITY, 1, false);
+
+ if (you.experience_level < 17)
+ hp_adjust--;
+
+ if (!(you.experience_level % 2))
+ hp_adjust--;
+ break;
+
+ case SP_KOBOLD:
+ if (!(you.experience_level % 5))
+ {
+ modify_stat( (coinflip() ? STAT_STRENGTH
+ : STAT_DEXTERITY), 1, false );
+ }
+
+ if (you.experience_level < 17)
+ hp_adjust--;
+
+ if (!(you.experience_level % 2))
+ hp_adjust--;
+ break;
+
+ case SP_HILL_ORC:
+ // lower because of HD raise -- bwr
+ // if (you.experience_level < 17)
+ // hp_adjust++;
+
+ if (!(you.experience_level % 2))
+ hp_adjust++;
+
+ if (!(you.experience_level % 3))
+ mp_adjust--;
+
+ if (!(you.experience_level % 5))
+ modify_stat(STAT_STRENGTH, 1, false);
+ break;
+
+ case SP_MUMMY:
+ if (you.experience_level == 13 || you.experience_level == 26)
+ {
+ mpr( "You feel more in touch with the powers of death.",
+ MSGCH_INTRINSIC_GAIN );
+ }
+
+ if (you.experience_level == 13) // level 13 for now -- bwr
+ {
+ mpr( "You can now infuse your body with magic to restore decomposition.", MSGCH_INTRINSIC_GAIN );
+ }
+ break;
+
+ case SP_NAGA:
+ // lower because of HD raise -- bwr
+ // if (you.experience_level < 14)
+ // hp_adjust++;
+
+ hp_adjust++;
+
+ if (!(you.experience_level % 4))
+ modify_stat(STAT_RANDOM, 1, false);
+
+ if (!(you.experience_level % 3))
+ {
+ mpr("Your skin feels tougher.", MSGCH_INTRINSIC_GAIN);
+ you.redraw_armour_class = 1;
+ }
+ break;
+
+ case SP_GNOME:
+ if (you.experience_level < 13)
+ hp_adjust--;
+
+ if (!(you.experience_level % 3))
+ hp_adjust--;
+
+ if (!(you.experience_level % 4))
+ {
+ modify_stat( (coinflip() ? STAT_INTELLIGENCE
+ : STAT_DEXTERITY), 1, false );
+ }
+ break;
+
+ case SP_OGRE:
+ case SP_TROLL:
+ hp_adjust++;
+
+ // lowered because of HD raise -- bwr
+ // if (you.experience_level < 14)
+ // hp_adjust++;
+
+ if (!(you.experience_level % 2))
+ hp_adjust++;
+
+ if (you.experience_level % 3)
+ mp_adjust--;
+
+ if (!(you.experience_level % 3))
+ modify_stat(STAT_STRENGTH, 1, false);
+ break;
+
+ case SP_OGRE_MAGE:
+ hp_adjust++;
+
+ // lowered because of HD raise -- bwr
+ // if (you.experience_level < 14)
+ // hp_adjust++;
+
+ if (!(you.experience_level % 5))
+ {
+ modify_stat( (coinflip() ? STAT_INTELLIGENCE
+ : STAT_STRENGTH), 1, false );
+ }
+ break;
+
+ case SP_RED_DRACONIAN:
+ case SP_WHITE_DRACONIAN:
+ case SP_GREEN_DRACONIAN:
+ case SP_GOLDEN_DRACONIAN:
+/* Grey is later */
+ case SP_BLACK_DRACONIAN:
+ case SP_PURPLE_DRACONIAN:
+ case SP_MOTTLED_DRACONIAN:
+ case SP_PALE_DRACONIAN:
+ case SP_UNK0_DRACONIAN:
+ case SP_UNK1_DRACONIAN:
+ case SP_UNK2_DRACONIAN:
+ if (you.experience_level == 7)
+ {
+ switch (you.species)
+ {
+ case SP_RED_DRACONIAN:
+ mpr("Your scales start taking on a fiery red colour.",
+ MSGCH_INTRINSIC_GAIN);
+ break;
+ case SP_WHITE_DRACONIAN:
+ mpr("Your scales start taking on an icy white colour.",
+ MSGCH_INTRINSIC_GAIN);
+ break;
+ case SP_GREEN_DRACONIAN:
+ mpr("Your scales start taking on a green colour.",
+ MSGCH_INTRINSIC_GAIN);
+ mpr("You feel resistant to poison.", MSGCH_INTRINSIC_GAIN);
+ break;
+
+ case SP_GOLDEN_DRACONIAN:
+ mpr("Your scales start taking on a golden yellow colour.", MSGCH_INTRINSIC_GAIN);
+ break;
+ case SP_BLACK_DRACONIAN:
+ mpr("Your scales start turning black.", MSGCH_INTRINSIC_GAIN);
+ break;
+ case SP_PURPLE_DRACONIAN:
+ mpr("Your scales start taking on a rich purple colour.", MSGCH_INTRINSIC_GAIN);
+ break;
+ case SP_MOTTLED_DRACONIAN:
+ mpr("Your scales start taking on a weird mottled pattern.", MSGCH_INTRINSIC_GAIN);
+ break;
+ case SP_PALE_DRACONIAN:
+ mpr("Your scales start fading to a pale grey colour.", MSGCH_INTRINSIC_GAIN);
+ break;
+ case SP_UNK0_DRACONIAN:
+ case SP_UNK1_DRACONIAN:
+ case SP_UNK2_DRACONIAN:
+ mpr("");
+ break;
+ }
+ more();
+ redraw_screen();
+ }
+
+ if (you.experience_level == 18)
+ {
+ switch (you.species)
+ {
+ case SP_RED_DRACONIAN:
+ mpr("You feel resistant to fire.", MSGCH_INTRINSIC_GAIN);
+ break;
+ case SP_WHITE_DRACONIAN:
+ mpr("You feel resistant to cold.", MSGCH_INTRINSIC_GAIN);
+ break;
+ case SP_BLACK_DRACONIAN:
+ mpr("You feel resistant to electrical energy.",
+ MSGCH_INTRINSIC_GAIN);
+ break;
+ }
+ }
+
+ if (!(you.experience_level % 3))
+ hp_adjust++;
+
+ if (you.experience_level > 7 && !(you.experience_level % 4))
+ {
+ mpr("Your scales feel tougher.", MSGCH_INTRINSIC_GAIN);
+ you.redraw_armour_class = 1;
+ modify_stat(STAT_RANDOM, 1, false);
+ }
+ break;
+
+ case SP_GREY_DRACONIAN:
+ if (you.experience_level == 7)
+ {
+ mpr("Your scales start turning grey.", MSGCH_INTRINSIC_GAIN);
+ more();
+ redraw_screen();
+ }
+
+ if (!(you.experience_level % 3))
+ {
+ hp_adjust++;
+ if (you.experience_level > 7)
+ hp_adjust++;
+ }
+
+ if (you.experience_level > 7 && !(you.experience_level % 2))
+ {
+ mpr("Your scales feel tougher.", MSGCH_INTRINSIC_GAIN);
+ you.redraw_armour_class = 1;
+ }
+
+ if ((you.experience_level > 7 && !(you.experience_level % 3))
+ || you.experience_level == 4 || you.experience_level == 7)
+ {
+ modify_stat(STAT_RANDOM, 1, false);
+ }
+ break;
+
+ case SP_CENTAUR:
+ if (!(you.experience_level % 4))
+ {
+ modify_stat( (coinflip() ? STAT_DEXTERITY
+ : STAT_STRENGTH), 1, false );
+ }
+
+ // lowered because of HD raise -- bwr
+ // if (you.experience_level < 17)
+ // hp_adjust++;
+
+ if (!(you.experience_level % 2))
+ hp_adjust++;
+
+ if (!(you.experience_level % 3))
+ mp_adjust--;
+ break;
+
+ case SP_DEMIGOD:
+ if (!(you.experience_level % 3))
+ modify_stat(STAT_RANDOM, 1, false);
+
+ // lowered because of HD raise -- bwr
+ // if (you.experience_level < 17)
+ // hp_adjust++;
+
+ if (!(you.experience_level % 2))
+ hp_adjust++;
+
+ if (you.experience_level % 3)
+ mp_adjust++;
+ break;
+
+ case SP_SPRIGGAN:
+ if (you.experience_level < 17)
+ hp_adjust--;
+
+ if (you.experience_level % 3)
+ hp_adjust--;
+
+ mp_adjust++;
+
+ if (!(you.experience_level % 5))
+ {
+ modify_stat( (coinflip() ? STAT_INTELLIGENCE
+ : STAT_DEXTERITY), 1, false );
+ }
+ break;
+
+ case SP_MINOTAUR:
+ // lowered because of HD raise -- bwr
+ // if (you.experience_level < 17)
+ // hp_adjust++;
+
+ if (!(you.experience_level % 2))
+ hp_adjust++;
+
+ if (!(you.experience_level % 2))
+ mp_adjust--;
+
+ if (!(you.experience_level % 4))
+ {
+ modify_stat( (coinflip() ? STAT_DEXTERITY
+ : STAT_STRENGTH), 1, false );
+ }
+ break;
+
+ case SP_DEMONSPAWN:
+ if (you.attribute[ATTR_NUM_DEMONIC_POWERS] == 0
+ && (you.experience_level == 4
+ || (you.experience_level < 4 && one_chance_in(3))))
+ {
+ demonspawn();
+ }
+
+ if (you.attribute[ATTR_NUM_DEMONIC_POWERS] == 1
+ && you.experience_level > 4
+ && (you.experience_level == 9
+ || (you.experience_level < 9 && one_chance_in(3))))
+ {
+ demonspawn();
+ }
+
+ if (you.attribute[ATTR_NUM_DEMONIC_POWERS] == 2
+ && you.experience_level > 9
+ && (you.experience_level == 14
+ || (you.experience_level < 14 && one_chance_in(3))))
+ {
+ demonspawn();
+ }
+
+ if (you.attribute[ATTR_NUM_DEMONIC_POWERS] == 3
+ && you.experience_level > 14
+ && (you.experience_level == 19
+ || (you.experience_level < 19 && one_chance_in(3))))
+ {
+ demonspawn();
+ }
+
+ if (you.attribute[ATTR_NUM_DEMONIC_POWERS] == 4
+ && you.experience_level > 19
+ && (you.experience_level == 24
+ || (you.experience_level < 24 && one_chance_in(3))))
+ {
+ demonspawn();
+ }
+
+ if (you.attribute[ATTR_NUM_DEMONIC_POWERS] == 5
+ && you.experience_level == 27)
+ {
+ demonspawn();
+ }
+
+/*if (you.attribute [ATTR_NUM_DEMONIC_POWERS] == 6 && (you.experience_level == 8 || (you.experience_level < 8 && one_chance_in(3) ) )
+ demonspawn(); */
+ if (!(you.experience_level % 4))
+ modify_stat(STAT_RANDOM, 1, false);
+ break;
+
+ case SP_GHOUL:
+ // lowered because of HD raise -- bwr
+ // if (you.experience_level < 17)
+ // hp_adjust++;
+
+ if (!(you.experience_level % 2))
+ hp_adjust++;
+
+ if (!(you.experience_level % 3))
+ mp_adjust--;
+
+ if (!(you.experience_level % 5))
+ modify_stat(STAT_STRENGTH, 1, false);
+ break;
+
+ case SP_KENKU:
+ if (you.experience_level < 17)
+ hp_adjust--;
+
+ if (!(you.experience_level % 3))
+ hp_adjust--;
+
+ if (!(you.experience_level % 4))
+ modify_stat(STAT_RANDOM, 1, false);
+
+ if (you.experience_level == 5)
+ mpr("You have gained the ability to fly.", MSGCH_INTRINSIC_GAIN);
+ else if (you.experience_level == 15)
+ mpr("You can now fly continuously.", MSGCH_INTRINSIC_GAIN);
+ break;
+
+ case SP_MERFOLK:
+ if (you.experience_level % 3)
+ hp_adjust++;
+
+ if (!(you.experience_level % 5))
+ modify_stat(STAT_RANDOM, 1, false);
+ break;
+ }
+ }
+
+ // add hp and mp adjustments - GDL
+ inc_max_hp( hp_adjust );
+ inc_max_mp( mp_adjust );
+
+ deflate_hp( you.hp_max, false );
+
+ if (you.magic_points < 0)
+ you.magic_points = 0;
+
+ calc_hp();
+ calc_mp();
+
+ if (you.experience_level > you.max_level)
+ you.max_level = you.experience_level;
+
+ if (you.religion == GOD_XOM)
+ Xom_acts(true, you.experience_level, true);
+ }
+
+ redraw_skill( you.your_name, player_title() );
+} // end level_change()
+
+// here's a question for you: does the ordering of mods make a difference?
+// (yes) -- are these things in the right order of application to stealth?
+// - 12mar2000 {dlb}
+int check_stealth(void)
+{
+ if (you.special_wield == SPWLD_SHADOW)
+ return (0);
+
+ int stealth = you.dex * 3;
+
+ if (you.skills[SK_STEALTH])
+ {
+ if (player_genus(GENPC_DRACONIAN))
+ stealth += (you.skills[SK_STEALTH] * 12);
+ else
+ {
+ switch (you.species)
+ {
+ case SP_TROLL:
+ case SP_OGRE:
+ case SP_OGRE_MAGE:
+ case SP_CENTAUR:
+ stealth += (you.skills[SK_STEALTH] * 9);
+ break;
+ case SP_MINOTAUR:
+ stealth += (you.skills[SK_STEALTH] * 12);
+ break;
+ case SP_GNOME:
+ case SP_HALFLING:
+ case SP_KOBOLD:
+ case SP_SPRIGGAN:
+ case SP_NAGA: // not small but very good at stealth
+ stealth += (you.skills[SK_STEALTH] * 18);
+ break;
+ default:
+ stealth += (you.skills[SK_STEALTH] * 15);
+ break;
+ }
+ }
+ }
+
+ if (you.burden_state == BS_ENCUMBERED)
+ stealth /= 2;
+ else if (you.burden_state == BS_OVERLOADED)
+ stealth /= 5;
+
+ if (you.conf)
+ stealth /= 3;
+
+ const int arm = you.equip[EQ_BODY_ARMOUR];
+ const int cloak = you.equip[EQ_CLOAK];
+ const int boots = you.equip[EQ_BOOTS];
+
+ if (arm != -1 && !player_light_armour())
+ stealth -= (mass_item( you.inv[arm] ) / 10);
+
+ if (cloak != -1 && cmp_equip_race( you.inv[cloak], ISFLAG_ELVEN ))
+ stealth += 20;
+
+ if (boots != -1)
+ {
+ if (get_armour_ego_type( you.inv[boots] ) == SPARM_STEALTH)
+ stealth += 50;
+
+ if (cmp_equip_race( you.inv[boots], ISFLAG_ELVEN ))
+ stealth += 20;
+ }
+
+ stealth += scan_randarts( RAP_STEALTH );
+
+ if (player_is_levitating())
+ stealth += 10;
+ else if (player_in_water())
+ {
+ // Merfolk can sneak up on monsters underwater -- bwr
+ if (you.species == SP_MERFOLK)
+ stealth += 50;
+ else
+ stealth /= 2; // splashy-splashy
+ }
+
+ // Radiating silence is the negative compliment of shouting all the
+ // time... a sudden change from background noise to no noise is going
+ // to clue anything in to the fact that something is very wrong...
+ // a personal silence spell would naturally be different, but this
+ // silence radiates for a distance and prevents monster spellcasting,
+ // which pretty much gives away the stealth game.
+ if (you.duration[DUR_SILENCE])
+ stealth -= 50;
+
+ if (stealth < 0)
+ stealth = 0;
+
+ return (stealth);
+} // end check_stealth()
+
+void ability_increase(void)
+{
+ unsigned char keyin;
+
+ mpr("Your experience leads to an increase in your attributes!",
+ MSGCH_INTRINSIC_GAIN);
+
+ more();
+ mesclr();
+
+ mpr("Increase (S)trength, (I)ntelligence, or (D)exterity? ", MSGCH_PROMPT);
+
+ get_key:
+ keyin = getch();
+ if (keyin == 0)
+ {
+ getch();
+ goto get_key;
+ }
+
+ switch (keyin)
+ {
+ case 's':
+ case 'S':
+ modify_stat(STAT_STRENGTH, 1, false);
+ return;
+
+ case 'i':
+ case 'I':
+ modify_stat(STAT_INTELLIGENCE, 1, false);
+ return;
+
+ case 'd':
+ case 'D':
+ modify_stat(STAT_DEXTERITY, 1, false);
+ return;
+ }
+
+ goto get_key;
+/* this is an infinite loop because it is reasonable to assume that you're not going to want to leave it prematurely. */
+} // end ability_increase()
+
+void display_char_status(void)
+{
+ if (you.is_undead)
+ mpr( "You are undead." );
+ else if (you.deaths_door)
+ mpr( "You are standing in death's doorway." );
+ else
+ mpr( "You are alive." );
+
+ switch (you.attribute[ATTR_TRANSFORMATION])
+ {
+ case TRAN_SPIDER:
+ mpr( "You are in spider-form." );
+ break;
+ case TRAN_BLADE_HANDS:
+ mpr( "You have blades for hands." );
+ break;
+ case TRAN_STATUE:
+ mpr( "You are a statue." );
+ break;
+ case TRAN_ICE_BEAST:
+ mpr( "You are an ice creature." );
+ break;
+ case TRAN_DRAGON:
+ mpr( "You are in dragon-form." );
+ break;
+ case TRAN_LICH:
+ mpr( "You are in lich-form." );
+ break;
+ case TRAN_SERPENT_OF_HELL:
+ mpr( "You are a huge demonic serpent." );
+ break;
+ case TRAN_AIR:
+ mpr( "You are a cloud of diffuse gas." );
+ break;
+ }
+
+ if (you.duration[DUR_BREATH_WEAPON])
+ mpr( "You are short of breath." );
+
+ if (you.duration[DUR_REPEL_UNDEAD])
+ mpr( "You have a holy aura protecting you from undead." );
+
+ if (you.duration[DUR_LIQUID_FLAMES])
+ mpr( "You are covered in liquid flames." );
+
+ if (you.duration[DUR_ICY_ARMOUR])
+ mpr( "You are protected by an icy shield." );
+
+ if (you.duration[DUR_REPEL_MISSILES])
+ mpr( "You are protected from missiles." );
+
+ if (you.duration[DUR_DEFLECT_MISSILES])
+ mpr( "You deflect missiles." );
+
+ if (you.duration[DUR_PRAYER])
+ mpr( "You are praying." );
+
+ if (you.duration[DUR_REGENERATION])
+ mpr( "You are regenerating." );
+
+ if (you.duration[DUR_SWIFTNESS])
+ mpr( "You can move swiftly." );
+
+ if (you.duration[DUR_INSULATION])
+ mpr( "You are insulated." );
+
+ if (you.duration[DUR_STONEMAIL])
+ mpr( "You are covered in scales of stone." );
+
+ if (you.duration[DUR_CONTROLLED_FLIGHT])
+ mpr( "You can control your flight." );
+
+ if (you.duration[DUR_TELEPORT])
+ mpr( "You are about to teleport." );
+
+ if (you.duration[DUR_CONTROL_TELEPORT])
+ mpr( "You can control teleportation." );
+
+ if (you.duration[DUR_DEATH_CHANNEL])
+ mpr( "You are channeling the dead." );
+
+ if (you.duration[DUR_FORESCRY]) //jmf: added 19mar2000
+ mpr( "You are forewarned." );
+
+ if (you.duration[DUR_SILENCE]) //jmf: added 27mar2000
+ mpr( "You radiate silence." );
+
+ if (you.duration[DUR_INFECTED_SHUGGOTH_SEED]) //jmf: added 19mar2000
+ mpr( "You are infected with a shuggoth parasite." );
+
+ if (you.duration[DUR_STONESKIN])
+ mpr( "Your skin is tough as stone." );
+
+ if (you.duration[DUR_SEE_INVISIBLE])
+ mpr( "You can see invisible." );
+
+ if (you.invis)
+ mpr( "You are invisible." );
+
+ if (you.conf)
+ mpr( "You are confused." );
+
+ if (you.paralysis)
+ mpr( "You are paralysed." );
+
+ if (you.exhausted)
+ mpr( "You are exhausted." );
+
+ if (you.slow && you.haste)
+ mpr( "You are under both slowing and hasting effects." );
+ else if (you.slow)
+ mpr( "You are moving very slowly." );
+ else if (you.haste)
+ mpr( "You are moving very quickly." );
+
+ if (you.might)
+ mpr( "You are mighty." );
+
+ if (you.berserker)
+ mpr( "You are possessed by a berserker rage." );
+
+ if (player_is_levitating())
+ mpr( "You are hovering above the floor." );
+
+ if (you.poison)
+ {
+ snprintf( info, INFO_SIZE, "You are %s poisoned.",
+ (you.poison > 10) ? "extremely" :
+ (you.poison > 5) ? "very" :
+ (you.poison > 3) ? "quite"
+ : "mildly" );
+ mpr(info);
+ }
+
+ if (you.disease)
+ {
+ snprintf( info, INFO_SIZE, "You are %sdiseased.",
+ (you.disease > 120) ? "badly " :
+ (you.disease > 40) ? ""
+ : "mildly " );
+ mpr(info);
+ }
+
+ if (you.rotting || you.species == SP_GHOUL)
+ {
+ // I apologize in advance for the horrendous ugliness about to
+ // transpire. Avert your eyes!
+ snprintf( info, INFO_SIZE, "Your flesh is rotting%s",
+ (you.rotting > 15) ? " before your eyes!":
+ (you.rotting > 8) ? " away quickly.":
+ (you.rotting > 4) ? " badly."
+ : ((you.species == SP_GHOUL && you.rotting > 0)
+ ? " faster than usual." : ".") );
+ mpr(info);
+ }
+
+ contaminate_player( 0, true );
+
+ if (you.confusing_touch)
+ {
+ snprintf( info, INFO_SIZE, "Your hands are glowing %s red.",
+ (you.confusing_touch > 40) ? "an extremely bright" :
+ (you.confusing_touch > 20) ? "bright"
+ : "a soft" );
+ mpr(info);
+ }
+
+ if (you.sure_blade)
+ {
+ snprintf( info, INFO_SIZE, "You have a %sbond with your blade.",
+ (you.sure_blade > 15) ? "strong " :
+ (you.sure_blade > 5) ? ""
+ : "weak " );
+ mpr(info);
+ }
+} // end display_char_status()
+
+void redraw_skill(const char your_name[kNameLen], const char class_name[80])
+{
+ char print_it[80];
+
+ memset( print_it, ' ', sizeof(print_it) );
+ snprintf( print_it, sizeof(print_it), "%s the %s", your_name, class_name );
+
+ int in_len = strlen( print_it );
+ if (in_len > 40)
+ {
+ in_len -= 3; // what we're getting back from removing "the"
+
+ const int name_len = strlen(your_name);
+ char name_buff[kNameLen];
+ strncpy( name_buff, your_name, kNameLen );
+
+ // squeeze name if required, the "- 8" is too not squueze too much
+ if (in_len > 40 && (name_len - 8) > (in_len - 40))
+ name_buff[ name_len - (in_len - 40) - 1 ] = '\0';
+ else
+ name_buff[ kNameLen - 1 ] = '\0';
+
+ snprintf( print_it, sizeof(print_it), "%s, %s", name_buff, class_name );
+ }
+
+ for (int i = strlen(print_it); i < 41; i++)
+ print_it[i] = ' ';
+
+ print_it[40] = '\0';
+
+#ifdef DOS_TERM
+ window(1, 1, 80, 25);
+#endif
+ gotoxy(40, 1);
+
+ textcolor( LIGHTGREY );
+ cprintf( print_it );
+} // end redraw_skill()
+
+// Note that this function only has the one static buffer, so if you
+// want to use the results, you'll want to make a copy.
+char *species_name( int speci, int level, bool genus, bool adj, bool cap )
+// defaults: false false true
+{
+ static char species_buff[80];
+
+ if (player_genus( GENPC_DRACONIAN, speci ))
+ {
+ if (adj || genus) // adj doesn't care about exact species
+ strcpy( species_buff, "Draconian" );
+ else
+ {
+ // No longer have problems with ghosts here -- Sharp Aug2002
+ if (level < 7)
+ strcpy( species_buff, "Draconian" );
+ else
+ {
+ switch (speci)
+ {
+ case SP_RED_DRACONIAN:
+ strcpy( species_buff, "Red Draconian" );
+ break;
+ case SP_WHITE_DRACONIAN:
+ strcpy( species_buff, "White Draconian" );
+ break;
+ case SP_GREEN_DRACONIAN:
+ strcpy( species_buff, "Green Draconian" );
+ break;
+ case SP_GOLDEN_DRACONIAN:
+ strcpy( species_buff, "Yellow Draconian" );
+ break;
+ case SP_GREY_DRACONIAN:
+ strcpy( species_buff, "Grey Draconian" );
+ break;
+ case SP_BLACK_DRACONIAN:
+ strcpy( species_buff, "Black Draconian" );
+ break;
+ case SP_PURPLE_DRACONIAN:
+ strcpy( species_buff, "Purple Draconian" );
+ break;
+ case SP_MOTTLED_DRACONIAN:
+ strcpy( species_buff, "Mottled Draconian" );
+ break;
+ case SP_PALE_DRACONIAN:
+ strcpy( species_buff, "Pale Draconian" );
+ break;
+ case SP_UNK0_DRACONIAN:
+ case SP_UNK1_DRACONIAN:
+ case SP_UNK2_DRACONIAN:
+ default:
+ strcpy( species_buff, "Draconian" );
+ break;
+ }
+ }
+ }
+ }
+ else if (player_genus( GENPC_ELVEN, speci ))
+ {
+ if (adj) // doesn't care about species/genus
+ strcpy( species_buff, "Elven" );
+ else if (genus)
+ strcpy( species_buff, "Elf" );
+ else
+ {
+ switch (speci)
+ {
+ case SP_ELF:
+ default:
+ strcpy( species_buff, "Elf" );
+ break;
+ case SP_HIGH_ELF:
+ strcpy( species_buff, "High Elf" );
+ break;
+ case SP_GREY_ELF:
+ strcpy( species_buff, "Grey Elf" );
+ break;
+ case SP_DEEP_ELF:
+ strcpy( species_buff, "Deep Elf" );
+ break;
+ case SP_SLUDGE_ELF:
+ strcpy( species_buff, "Sludge Elf" );
+ break;
+ }
+ }
+ }
+ else if (player_genus( GENPC_DWARVEN, speci ))
+ {
+ if (adj) // doesn't care about species/genus
+ strcpy( species_buff, "Dwarven" );
+ else if (genus)
+ strcpy( species_buff, "Dwarf" );
+ else
+ {
+ switch (speci)
+ {
+ case SP_HILL_DWARF:
+ strcpy( species_buff, "Hill Dwarf" );
+ break;
+ case SP_MOUNTAIN_DWARF:
+ strcpy( species_buff, "Mountain Dwarf" );
+ break;
+ default:
+ strcpy( species_buff, "Dwarf" );
+ break;
+ }
+ }
+ }
+ else
+ {
+ switch (speci)
+ {
+ case SP_HUMAN:
+ strcpy( species_buff, "Human" );
+ break;
+ case SP_HALFLING:
+ strcpy( species_buff, "Halfling" );
+ break;
+ case SP_HILL_ORC:
+ strcpy( species_buff, (adj) ? "Orcish" : (genus) ? "Orc"
+ : "Hill Orc" );
+ break;
+ case SP_KOBOLD:
+ strcpy( species_buff, "Kobold" );
+ break;
+ case SP_MUMMY:
+ strcpy( species_buff, "Mummy" );
+ break;
+ case SP_NAGA:
+ strcpy( species_buff, "Naga" );
+ break;
+ case SP_GNOME:
+ strcpy( species_buff, (adj) ? "Gnomish" : "Gnome" );
+ break;
+ case SP_OGRE:
+ strcpy( species_buff, (adj) ? "Ogreish" : "Ogre" );
+ break;
+ case SP_TROLL:
+ strcpy( species_buff, (adj) ? "Trollish" : "Troll" );
+ break;
+ case SP_OGRE_MAGE:
+ // We've previously declared that these are radically
+ // different from Ogres... so we're not going to
+ // refer to them as Ogres. -- bwr
+ strcpy( species_buff, "Ogre-Mage" );
+ break;
+ case SP_CENTAUR:
+ strcpy( species_buff, "Centaur" );
+ break;
+ case SP_DEMIGOD:
+ strcpy( species_buff, (adj) ? "Divine" : "Demigod" );
+ break;
+ case SP_SPRIGGAN:
+ strcpy( species_buff, "Spriggan" );
+ break;
+ case SP_MINOTAUR:
+ strcpy( species_buff, "Minotaur" );
+ break;
+ case SP_DEMONSPAWN:
+ strcpy( species_buff, (adj) ? "Demonic" : "Demonspawn" );
+ break;
+ case SP_GHOUL:
+ strcpy( species_buff, (adj) ? "Ghoulish" : "Ghoul" );
+ break;
+ case SP_KENKU:
+ strcpy( species_buff, "Kenku" );
+ break;
+ case SP_MERFOLK:
+ strcpy( species_buff, (adj) ? "Merfolkian" : "Merfolk" );
+ break;
+ default:
+ strcpy( species_buff, (adj) ? "Yakish" : "Yak" );
+ break;
+ }
+ }
+
+ if (!cap)
+ strlwr( species_buff );
+
+ return (species_buff);
+} // end species_name()
+
+bool wearing_amulet(char amulet)
+{
+ if (amulet == AMU_CONTROLLED_FLIGHT
+ && (you.duration[DUR_CONTROLLED_FLIGHT]
+ || player_genus(GENPC_DRACONIAN)
+ || you.attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON))
+ {
+ return true;
+ }
+
+ if (amulet == AMU_CLARITY && you.mutation[MUT_CLARITY])
+ return true;
+
+ if (amulet == AMU_RESIST_CORROSION || amulet == AMU_CONSERVATION)
+ {
+ // this is hackish {dlb}
+ if (player_equip_ego_type( EQ_CLOAK, SPARM_PRESERVATION ))
+ return true;
+ }
+
+ if (you.equip[EQ_AMULET] == -1)
+ return false;
+
+ if (you.inv[you.equip[EQ_AMULET]].sub_type == amulet)
+ return true;
+
+ return false;
+} // end wearing_amulet()
+
+bool player_is_levitating(void)
+{
+ return (you.attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON || you.levitation);
+}
+
+bool player_has_spell( int spell )
+{
+ for (int i = 0; i < 25; i++)
+ {
+ if (you.spells[i] == spell)
+ return (true);
+ }
+
+ return (false);
+}
+
+int species_exp_mod(char species)
+{
+
+ if (player_genus(GENPC_DRACONIAN))
+ return 14;
+ else if (player_genus(GENPC_DWARVEN))
+ return 13;
+ {
+ switch (species)
+ {
+ case SP_HUMAN:
+ case SP_HALFLING:
+ case SP_HILL_ORC:
+ case SP_KOBOLD:
+ return 10;
+ case SP_GNOME:
+ return 11;
+ case SP_ELF:
+ case SP_SLUDGE_ELF:
+ case SP_NAGA:
+ case SP_GHOUL:
+ case SP_MERFOLK:
+ return 12;
+ case SP_SPRIGGAN:
+ case SP_KENKU:
+ return 13;
+ case SP_GREY_ELF:
+ case SP_DEEP_ELF:
+ case SP_OGRE:
+ case SP_CENTAUR:
+ case SP_MINOTAUR:
+ case SP_DEMONSPAWN:
+ return 14;
+ case SP_HIGH_ELF:
+ case SP_MUMMY:
+ case SP_TROLL:
+ case SP_OGRE_MAGE:
+ return 15;
+ case SP_DEMIGOD:
+ return 16;
+ default:
+ return 0;
+ }
+ }
+} // end species_exp_mod()
+
+unsigned long exp_needed(int lev)
+{
+ lev--;
+
+ unsigned long level = 0;
+
+#if 0
+ case 1: level = 1;
+ case 2: level = 10;
+ case 3: level = 35;
+ case 4: level = 70;
+ case 5: level = 120;
+ case 6: level = 250;
+ case 7: level = 510;
+ case 8: level = 900;
+ case 9: level = 1700;
+ case 10: level = 3500;
+ case 11: level = 8000;
+ case 12: level = 20000;
+
+ default: //return 14000 * (lev - 11);
+ level = 20000 * (lev - 11) + ((lev - 11) * (lev - 11) * (lev - 11)) * 130;
+ break;
+#endif
+
+ // This is a better behaved function than the above. The above looks
+ // really ugly when you consider the second derivative, its not smooth
+ // and has a horrible bump at level 12 followed by comparitively easy
+ // teen levels. This tries to sort out those issues.
+ //
+ // Basic plan:
+ // Section 1: levels 1- 5, second derivative goes 10-10-20-30.
+ // Section 2: levels 6-13, second derivative is exponential/doubling.
+ // Section 3: levels 14-27, second derivative is constant at 6000.
+ //
+ // Section three is constant so we end up with high levels at about
+ // their old values (level 27 at 850k), without delta2 ever decreasing.
+ // The values that are considerably different (ie level 13 is now 29000,
+ // down from 41040 are because the second derivative goes from 9040 to
+ // 1430 at that point in the original, and then slowly builds back
+ // up again). This function smoothes out the old level 10-15 area
+ // considerably.
+
+ // Here's a table:
+ //
+ // level xp delta delta2
+ // ===== ======= ===== ======
+ // 1 0 0 0
+ // 2 10 10 10
+ // 3 30 20 10
+ // 4 70 40 20
+ // 5 140 70 30
+ // 6 270 130 60
+ // 7 520 250 120
+ // 8 1010 490 240
+ // 9 1980 970 480
+ // 10 3910 1930 960
+ // 11 7760 3850 1920
+ // 12 15450 7690 3840
+ // 13 29000 13550 5860
+ // 14 48500 19500 5950
+ // 15 74000 25500 6000
+ // 16 105500 31500 6000
+ // 17 143000 37500 6000
+ // 18 186500 43500 6000
+ // 19 236000 49500 6000
+ // 20 291500 55500 6000
+ // 21 353000 61500 6000
+ // 22 420500 67500 6000
+ // 23 494000 73500 6000
+ // 24 573500 79500 6000
+ // 25 659000 85500 6000
+ // 26 750500 91500 6000
+ // 27 848000 97500 6000
+
+
+ switch (lev)
+ {
+ case 1:
+ level = 1;
+ break;
+ case 2:
+ level = 10;
+ break;
+ case 3:
+ level = 30;
+ break;
+ case 4:
+ level = 70;
+ break;
+
+ default:
+ if (lev < 13)
+ {
+ lev -= 4;
+ level = 10 + 10 * lev
+ + 30 * (static_cast<int>(pow( 2.0, lev + 1 )));
+ }
+ else
+ {
+ lev -= 12;
+ level = 15500 + 10500 * lev + 3000 * lev * lev;
+ }
+ break;
+ }
+
+ return ((level - 1) * species_exp_mod(you.species) / 10);
+} // end exp_needed()
+
+// returns bonuses from rings of slaying, etc.
+int slaying_bonus(char which_affected)
+{
+ int ret = 0;
+
+ if (which_affected == PWPN_HIT)
+ {
+ ret += player_equip( EQ_RINGS_PLUS, RING_SLAYING );
+ ret += scan_randarts(RAP_ACCURACY);
+ }
+ else if (which_affected == PWPN_DAMAGE)
+ {
+ ret += player_equip( EQ_RINGS_PLUS2, RING_SLAYING );
+ ret += scan_randarts(RAP_DAMAGE);
+ }
+
+ return (ret);
+} // end slaying_bonus()
+
+/* Checks each equip slot for a randart, and adds up all of those with
+ a given property. Slow if any randarts are worn, so avoid where possible. */
+int scan_randarts(char which_property)
+{
+ int i = 0;
+ int retval = 0;
+
+ for (i = EQ_WEAPON; i < NUM_EQUIP; i++)
+ {
+ const int eq = you.equip[i];
+
+ if (eq == -1)
+ continue;
+
+ // only weapons give their effects when in our hands
+ if (i == EQ_WEAPON && you.inv[ eq ].base_type != OBJ_WEAPONS)
+ continue;
+
+ if (!is_random_artefact( you.inv[ eq ] ))
+ continue;
+
+ retval += randart_wpn_property( you.inv[ eq ], which_property );
+ }
+
+ return (retval);
+} // end scan_randarts()
+
+void modify_stat(unsigned char which_stat, char amount, bool suppress_msg)
+{
+ char *ptr_stat = NULL;
+ char *ptr_stat_max = NULL;
+ char *ptr_redraw = NULL;
+
+ // sanity - is non-zero amount?
+ if (amount == 0)
+ return;
+
+ if (!suppress_msg)
+ strcpy(info, "You feel ");
+
+ if (which_stat == STAT_RANDOM)
+ which_stat = random2(NUM_STATS);
+
+ switch (which_stat)
+ {
+ case STAT_STRENGTH:
+ ptr_stat = &you.strength;
+ ptr_stat_max = &you.max_strength;
+ ptr_redraw = &you.redraw_strength;
+ if (!suppress_msg)
+ strcat(info, (amount > 0) ? "stronger." : "weaker.");
+ break;
+
+ case STAT_DEXTERITY:
+ ptr_stat = &you.dex;
+ ptr_stat_max = &you.max_dex;
+ ptr_redraw = &you.redraw_dexterity;
+ if (!suppress_msg)
+ strcat(info, (amount > 0) ? "agile." : "clumsy.");
+ break;
+
+ case STAT_INTELLIGENCE:
+ ptr_stat = &you.intel;
+ ptr_stat_max = &you.max_intel;
+ ptr_redraw = &you.redraw_intelligence;
+ if (!suppress_msg)
+ strcat(info, (amount > 0) ? "clever." : "stupid.");
+ break;
+ }
+
+ if (!suppress_msg)
+ mpr( info, (amount > 0) ? MSGCH_INTRINSIC_GAIN : MSGCH_WARN );
+
+ *ptr_stat += amount;
+ *ptr_stat_max += amount;
+ *ptr_redraw = 1;
+
+ if (ptr_stat == &you.strength)
+ burden_change();
+
+ return;
+} // end modify_stat()
+
+void dec_hp(int hp_loss, bool fatal)
+{
+ if (hp_loss < 1)
+ return;
+
+ you.hp -= hp_loss;
+
+ if (!fatal && you.hp < 1)
+ you.hp = 1;
+
+ you.redraw_hit_points = 1;
+
+ return;
+} // end dec_hp()
+
+void dec_mp(int mp_loss)
+{
+ if (mp_loss < 1)
+ return;
+
+ you.magic_points -= mp_loss;
+
+ if (you.magic_points < 0)
+ you.magic_points = 0;
+
+ you.redraw_magic_points = 1;
+
+ return;
+} // end dec_mp()
+
+bool enough_hp(int minimum, bool suppress_msg)
+{
+ // We want to at least keep 1 HP -- bwr
+ if (you.hp < minimum + 1)
+ {
+ if (!suppress_msg)
+ mpr("You haven't enough vitality at the moment.");
+
+ return false;
+ }
+
+ return true;
+} // end enough_hp()
+
+bool enough_mp(int minimum, bool suppress_msg)
+{
+ if (you.magic_points < minimum)
+ {
+ if (!suppress_msg)
+ mpr("You haven't enough magic at the moment.");
+
+ return false;
+ }
+
+ return true;
+} // end enough_mp()
+
+// Note that "max_too" refers to the base potential, the actual
+// resulting max value is subject to penalties, bonuses, and scalings.
+void inc_mp(int mp_gain, bool max_too)
+{
+ if (mp_gain < 1)
+ return;
+
+ you.magic_points += mp_gain;
+
+ if (max_too)
+ inc_max_mp( mp_gain );
+
+ if (you.magic_points > you.max_magic_points)
+ you.magic_points = you.max_magic_points;
+
+ you.redraw_magic_points = 1;
+
+ return;
+} // end inc_mp()
+
+// Note that "max_too" refers to the base potential, the actual
+// resulting max value is subject to penalties, bonuses, and scalings.
+void inc_hp(int hp_gain, bool max_too)
+{
+ if (hp_gain < 1)
+ return;
+
+ you.hp += hp_gain;
+
+ if (max_too)
+ inc_max_hp( hp_gain );
+
+ if (you.hp > you.hp_max)
+ you.hp = you.hp_max;
+
+ you.redraw_hit_points = 1;
+} // end inc_hp()
+
+void rot_hp( int hp_loss )
+{
+ you.base_hp -= hp_loss;
+ calc_hp();
+
+ you.redraw_hit_points = 1;
+}
+
+void unrot_hp( int hp_recovered )
+{
+ if (hp_recovered >= 5000 - you.base_hp)
+ you.base_hp = 5000;
+ else
+ you.base_hp += hp_recovered;
+
+ calc_hp();
+
+ you.redraw_hit_points = 1;
+}
+
+int player_rotted( void )
+{
+ return (5000 - you.base_hp);
+}
+
+void rot_mp( int mp_loss )
+{
+ you.base_magic_points -= mp_loss;
+ calc_mp();
+
+ you.redraw_magic_points = 1;
+}
+
+void inc_max_hp( int hp_gain )
+{
+ you.base_hp2 += hp_gain;
+ calc_hp();
+
+ you.redraw_hit_points = 1;
+}
+
+void dec_max_hp( int hp_loss )
+{
+ you.base_hp2 -= hp_loss;
+ calc_hp();
+
+ you.redraw_hit_points = 1;
+}
+
+void inc_max_mp( int mp_gain )
+{
+ you.base_magic_points2 += mp_gain;
+ calc_mp();
+
+ you.redraw_magic_points = 1;
+}
+
+void dec_max_mp( int mp_loss )
+{
+ you.base_magic_points2 -= mp_loss;
+ calc_mp();
+
+ you.redraw_magic_points = 1;
+}
+
+// use of floor: false = hp max, true = hp min {dlb}
+void deflate_hp(int new_level, bool floor)
+{
+ if (floor && you.hp < new_level)
+ you.hp = new_level;
+ else if (!floor && you.hp > new_level)
+ you.hp = new_level;
+
+ // must remain outside conditional, given code usage {dlb}
+ you.redraw_hit_points = 1;
+
+ return;
+} // end deflate_hp()
+
+// Note that "max_too" refers to the base potential, the actual
+// resulting max value is subject to penalties, bonuses, and scalings.
+void set_hp(int new_amount, bool max_too)
+{
+ if (you.hp != new_amount)
+ you.hp = new_amount;
+
+ if (max_too && you.hp_max != new_amount)
+ {
+ you.base_hp2 = 5000 + new_amount;
+ calc_hp();
+ }
+
+ if (you.hp > you.hp_max)
+ you.hp = you.hp_max;
+
+ // must remain outside conditional, given code usage {dlb}
+ you.redraw_hit_points = 1;
+
+ return;
+} // end set_hp()
+
+// Note that "max_too" refers to the base potential, the actual
+// resulting max value is subject to penalties, bonuses, and scalings.
+void set_mp(int new_amount, bool max_too)
+{
+ if (you.magic_points != new_amount)
+ you.magic_points = new_amount;
+
+ if (max_too && you.max_magic_points != new_amount)
+ {
+ // note that this gets scaled down for values > 18
+ you.base_magic_points2 = 5000 + new_amount;
+ calc_mp();
+ }
+
+ if (you.magic_points > you.max_magic_points)
+ you.magic_points = you.max_magic_points;
+
+ // must remain outside conditional, given code usage {dlb}
+ you.redraw_magic_points = 1;
+
+ return;
+} // end set_mp()
+
+
+static const char * Species_Abbrev_List[ NUM_SPECIES ] =
+ { "XX", "Hu", "El", "HE", "GE", "DE", "SE", "HD", "MD", "Ha",
+ "HO", "Ko", "Mu", "Na", "Gn", "Og", "Tr", "OM", "Dr", "Dr",
+ "Dr", "Dr", "Dr", "Dr", "Dr", "Dr", "Dr", "Dr", "Dr", "Dr",
+ "Ce", "DG", "Sp", "Mi", "DS", "Gh", "Ke", "Mf" };
+
+int get_species_index_by_abbrev( const char *abbrev )
+{
+ int i;
+ for (i = SP_HUMAN; i < NUM_SPECIES; i++)
+ {
+ if (tolower( abbrev[0] ) == tolower( Species_Abbrev_List[i][0] )
+ && tolower( abbrev[1] ) == tolower( Species_Abbrev_List[i][1] ))
+ {
+ break;
+ }
+ }
+
+ return ((i < NUM_SPECIES) ? i : -1);
+}
+
+int get_species_index_by_name( const char *name )
+{
+ int i;
+ int sp = -1;
+
+ char *ptr;
+ char lowered_buff[80];
+
+ strncpy( lowered_buff, name, sizeof( lowered_buff ) );
+ strlwr( lowered_buff );
+
+ for (i = SP_HUMAN; i < NUM_SPECIES; i++)
+ {
+ char *lowered_species = species_name( i, 0, false, false, false );
+ ptr = strstr( lowered_species, lowered_buff );
+ if (ptr != NULL)
+ {
+ sp = i;
+ if (ptr == lowered_species) // prefix takes preference
+ break;
+ }
+ }
+
+ return (sp);
+}
+
+const char *get_species_abbrev( int which_species )
+{
+ ASSERT( which_species > 0 && which_species < NUM_SPECIES );
+
+ return (Species_Abbrev_List[ which_species ]);
+}
+
+
+static const char * Class_Abbrev_List[ NUM_JOBS ] =
+ { "Fi", "Wz", "Pr", "Th", "Gl", "Ne", "Pa", "As", "Be", "Hu",
+ "Cj", "En", "FE", "IE", "Su", "AE", "EE", "Cr", "DK", "VM",
+ "CK", "Tm", "He", "XX", "Re", "St", "Mo", "Wr", "Wn" };
+
+static const char * Class_Name_List[ NUM_JOBS ] =
+ { "Fighter", "Wizard", "Priest", "Thief", "Gladiator", "Necromancer",
+ "Paladin", "Assassin", "Berserker", "Hunter", "Conjurer", "Enchanter",
+ "Fire Elementalist", "Ice Elementalist", "Summoner", "Air Elementalist",
+ "Earth Elementalist", "Crusader", "Death Knight", "Venom Mage",
+ "Chaos Knight", "Transmuter", "Healer", "Quitter", "Reaver", "Stalker",
+ "Monk", "Warper", "Wanderer" };
+
+int get_class_index_by_abbrev( const char *abbrev )
+{
+ int i;
+
+ for (i = 0; i < NUM_JOBS; i++)
+ {
+ if (i == JOB_QUITTER)
+ continue;
+
+ if (tolower( abbrev[0] ) == tolower( Class_Abbrev_List[i][0] )
+ && tolower( abbrev[1] ) == tolower( Class_Abbrev_List[i][1] ))
+ {
+ break;
+ }
+ }
+
+ return ((i < NUM_JOBS) ? i : -1);
+}
+
+const char *get_class_abbrev( int which_job )
+{
+ ASSERT( which_job < NUM_JOBS && which_job != JOB_QUITTER );
+
+ return (Class_Abbrev_List[ which_job ]);
+}
+
+int get_class_index_by_name( const char *name )
+{
+ int i;
+ int cl = -1;
+
+ char *ptr;
+ char lowered_buff[80];
+ char lowered_class[80];
+
+ strncpy( lowered_buff, name, sizeof( lowered_buff ) );
+ strlwr( lowered_buff );
+
+ for (i = 0; i < NUM_JOBS; i++)
+ {
+ if (i == JOB_QUITTER)
+ continue;
+
+ strncpy( lowered_class, Class_Name_List[i], sizeof( lowered_class ) );
+ strlwr( lowered_class );
+
+ ptr = strstr( lowered_class, lowered_buff );
+ if (ptr != NULL)
+ {
+ cl = i;
+ if (ptr == lowered_class) // prefix takes preference
+ break;
+ }
+ }
+
+ return (cl);
+}
+
+const char *get_class_name( int which_job )
+{
+ ASSERT( which_job < NUM_JOBS && which_job != JOB_QUITTER );
+
+ return (Class_Name_List[ which_job ]);
+}
+
+/* ******************************************************************
+
+// this function is solely called by a commented out portion of
+// player::level_change() and is a bit outta whack with the
+// current codebase - probably should be struck as well 19may2000 {dlb}
+
+void priest_spells( int priest_pass[10], char religious )
+{
+
+ switch ( religious )
+ {
+ case GOD_ZIN:
+ priest_pass[1] = SPELL_LESSER_HEALING;
+ priest_pass[2] = SPELL_REPEL_UNDEAD;
+ priest_pass[3] = SPELL_HEAL_OTHER;
+ priest_pass[4] = SPELL_PURIFICATION;
+ priest_pass[5] = SPELL_GREATER_HEALING;
+ priest_pass[6] = SPELL_SMITING;
+ priest_pass[7] = SPELL_HOLY_WORD;
+ priest_pass[8] = SPELL_REMOVE_CURSE;
+ priest_pass[9] = SPELL_GUARDIAN;
+ break;
+
+ case GOD_SHINING_ONE:
+ priest_pass[1] = SPELL_REPEL_UNDEAD;
+ priest_pass[2] = SPELL_LESSER_HEALING;
+ priest_pass[3] = SPELL_HEAL_OTHER;
+ priest_pass[4] = SPELL_PURIFICATION;
+ priest_pass[5] = SPELL_ABJURATION_II;
+ priest_pass[6] = SPELL_THUNDERBOLT;
+ priest_pass[7] = SPELL_SHINING_LIGHT;
+ priest_pass[8] = SPELL_SUMMON_DAEVA;
+ priest_pass[9] = SPELL_FLAME_OF_CLEANSING;
+ break;
+
+ case GOD_ELYVILON:
+ priest_pass[1] = SPELL_LESSER_HEALING;
+ priest_pass[2] = SPELL_HEAL_OTHER;
+ priest_pass[3] = SPELL_PURIFICATION;
+ priest_pass[4] = 93; // restore abilities
+ priest_pass[5] = SPELL_GREATER_HEALING;
+ priest_pass[6] = 94; // another healing spell
+ priest_pass[7] = 95; // something else
+ priest_pass[8] = -1; //
+ priest_pass[9] = -1; //
+ break;
+ }
+
+}
+
+// Spells to be added: (+ renamed!)
+// holy berserker
+// 87 Pestilence
+// 93 Restore Abilities
+// 94 something else healing
+// 95 something else
+
+****************************************************************** */
+
+void contaminate_player(int change, bool statusOnly)
+{
+ // get current contamination level
+ int old_level;
+ int new_level;
+
+
+#if DEBUG_DIAGNOSTICS
+ if (change > 0 || (change < 0 && you.magic_contamination))
+ {
+ snprintf( info, INFO_SIZE, "change: %d radiation: %d",
+ change, change + you.magic_contamination );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+ }
+#endif
+
+ old_level = (you.magic_contamination > 60)?(you.magic_contamination / 20 + 2) :
+ (you.magic_contamination > 40)?4 :
+ (you.magic_contamination > 25)?3 :
+ (you.magic_contamination > 15)?2 :
+ (you.magic_contamination > 5)?1 : 0;
+
+ // make the change
+ if (change + you.magic_contamination < 0)
+ you.magic_contamination = 0;
+ else
+ {
+ if (change + you.magic_contamination > 250)
+ you.magic_contamination = 250;
+ else
+ you.magic_contamination += change;
+ }
+
+ // figure out new level
+ new_level = (you.magic_contamination > 60)?(you.magic_contamination / 20 + 2) :
+ (you.magic_contamination > 40)?4 :
+ (you.magic_contamination > 25)?3 :
+ (you.magic_contamination > 15)?2 :
+ (you.magic_contamination > 5)?1 : 0;
+
+ if (statusOnly)
+ {
+ if (new_level > 0)
+ {
+ if (new_level > 3)
+ {
+ strcpy(info, (new_level == 4) ?
+ "Your entire body has taken on an eerie glow!" :
+ "You are engulfed in a nimbus of crackling magics!");
+ }
+ else
+ {
+ snprintf( info, INFO_SIZE, "You are %s with residual magics%c",
+ (new_level == 3) ? "practically glowing" :
+ (new_level == 2) ? "heavily infused"
+ : "contaminated",
+ (new_level == 3) ? '!' : '.');
+ }
+
+ mpr(info);
+ }
+ return;
+ }
+
+ if (new_level == old_level)
+ return;
+
+ snprintf( info, INFO_SIZE, "You feel %s contaminated with magical energies.",
+ (change < 0) ? "less" : "more" );
+
+ mpr( info, (change > 0) ? MSGCH_WARN : MSGCH_RECOVERY );
+}
+
+void poison_player( int amount, bool force )
+{
+ if ((!force && player_res_poison()) || amount <= 0)
+ return;
+
+ const int old_value = you.poison;
+ you.poison += amount;
+
+ if (you.poison > 40)
+ you.poison = 40;
+
+ if (you.poison > old_value)
+ {
+ snprintf( info, INFO_SIZE, "You are %spoisoned.",
+ (old_value > 0) ? "more " : "" );
+
+ // XXX: which message channel for this message?
+ mpr( info );
+ }
+}
+
+void reduce_poison_player( int amount )
+{
+ if (you.poison == 0 || amount <= 0)
+ return;
+
+ you.poison -= amount;
+
+ if (you.poison <= 0)
+ {
+ you.poison = 0;
+ mpr( "You feel better.", MSGCH_RECOVERY );
+ }
+ else
+ {
+ mpr( "You feel a little better.", MSGCH_RECOVERY );
+ }
+}
+
+void confuse_player( int amount, bool resistable )
+{
+ if (amount <= 0)
+ return;
+
+ if (resistable && wearing_amulet(AMU_CLARITY))
+ {
+ mpr( "You feel momentarily confused." );
+ return;
+ }
+
+ const int old_value = you.conf;
+ you.conf += amount;
+
+ if (you.conf > 40)
+ you.conf = 40;
+
+ if (you.conf > old_value)
+ {
+ snprintf( info, INFO_SIZE, "You are %sconfused.",
+ (old_value > 0) ? "more " : "" );
+
+ // XXX: which message channel for this message?
+ mpr( info );
+ }
+}
+
+void reduce_confuse_player( int amount )
+{
+ if (you.conf == 0 || amount <= 0)
+ return;
+
+ you.conf -= amount;
+
+ if (you.conf <= 0)
+ {
+ you.conf = 0;
+ mpr( "You feel less confused." );
+ }
+}
+
+void slow_player( int amount )
+{
+ if (amount <= 0)
+ return;
+
+ if (wearing_amulet( AMU_RESIST_SLOW ))
+ mpr("You feel momentarily lethargic.");
+ else if (you.slow >= 100)
+ mpr( "You already are as slow as you could be." );
+ else
+ {
+ if (you.slow == 0)
+ mpr( "You feel yourself slow down." );
+ else
+ mpr( "You feel as though you will be slow longer." );
+
+ you.slow += amount;
+
+ if (you.slow > 100)
+ you.slow = 100;
+ }
+}
+
+void dec_slow_player( void )
+{
+ if (you.slow > 1)
+ {
+ // BCR - Amulet of resist slow affects slow counter
+ if (wearing_amulet(AMU_RESIST_SLOW))
+ {
+ you.slow -= 5;
+ if (you.slow < 1)
+ you.slow = 1;
+ }
+ else
+ you.slow--;
+ }
+ else if (you.slow == 1)
+ {
+ mpr("You feel yourself speed up.", MSGCH_DURATION);
+ you.slow = 0;
+ }
+}
+
+void haste_player( int amount )
+{
+ bool amu_eff = wearing_amulet( AMU_RESIST_SLOW );
+
+ if (amount <= 0)
+ return;
+
+ if (amu_eff)
+ mpr( "Your amulet glows brightly." );
+
+ if (you.haste == 0)
+ mpr( "You feel yourself speed up." );
+ else if (you.haste > 80 + 20 * amu_eff)
+ mpr( "You already have as much speed as you can handle." );
+ else
+ {
+ mpr( "You feel as though your hastened speed will last longer." );
+ contaminate_player(1);
+ }
+
+ you.haste += amount;
+
+ if (you.haste > 80 + 20 * amu_eff)
+ you.haste = 80 + 20 * amu_eff;
+
+ naughty( NAUGHTY_STIMULANTS, 4 + random2(4) );
+}
+
+void dec_haste_player( void )
+{
+ if (you.haste > 1)
+ {
+ // BCR - Amulet of resist slow affects haste counter
+ if (!wearing_amulet(AMU_RESIST_SLOW) || coinflip())
+ you.haste--;
+
+ if (you.haste == 6)
+ {
+ mpr( "Your extra speed is starting to run out.", MSGCH_DURATION );
+ if (coinflip())
+ you.haste--;
+ }
+ }
+ else if (you.haste == 1)
+ {
+ mpr( "You feel yourself slow down.", MSGCH_DURATION );
+ you.haste = 0;
+ }
+}
+
+void disease_player( int amount )
+{
+ if (you.is_undead || amount <= 0)
+ return;
+
+ mpr( "You feel ill." );
+
+ const int tmp = you.disease + amount;
+ you.disease = (tmp > 210) ? 210 : tmp;
+}
+
+void dec_disease_player( void )
+{
+ if (you.disease > 0)
+ {
+ you.disease--;
+
+ if (you.disease > 5
+ && (you.species == SP_KOBOLD
+ || you.duration[ DUR_REGENERATION ]
+ || you.mutation[ MUT_REGENERATION ] == 3))
+ {
+ you.disease -= 2;
+ }
+
+ if (!you.disease)
+ mpr("You feel your health improve.", MSGCH_RECOVERY);
+ }
+}
+
+void rot_player( int amount )
+{
+ if (amount <= 0)
+ return;
+
+ if (you.rotting < 40)
+ {
+ // Either this, or the actual rotting message should probably
+ // be changed so that they're easier to tell apart. -- bwr
+ snprintf( info, INFO_SIZE, "You feel your flesh %s away!",
+ (you.rotting) ? "rotting" : "start to rot" );
+ mpr( info, MSGCH_WARN );
+
+ you.rotting += amount;
+ }
+}
diff --git a/trunk/source/player.h b/trunk/source/player.h
new file mode 100644
index 0000000000..fc99a8b1be
--- /dev/null
+++ b/trunk/source/player.h
@@ -0,0 +1,446 @@
+/*
+ * File: player.cc
+ * Summary: Player related functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef PLAYER_H
+#define PLAYER_H
+
+#include "externs.h"
+
+bool player_in_branch( int branch );
+bool player_in_hell( void );
+
+int player_equip( int slot, int sub_type );
+int player_equip_ego_type( int slot, int sub_type );
+int player_damage_type( void );
+int player_damage_brand( void );
+
+bool player_is_shapechanged(void);
+
+/* ***********************************************************************
+ * called from: player - item_use
+ * *********************************************************************** */
+bool is_light_armour( const item_def &item );
+
+/* ***********************************************************************
+ * called from: beam - fight - misc - newgame
+ * *********************************************************************** */
+bool player_light_armour(void);
+
+
+/* ***********************************************************************
+ * called from: acr.cc - fight.cc - misc.cc - player.cc
+ * *********************************************************************** */
+bool player_in_water(void);
+bool player_is_swimming(void);
+bool player_is_levitating(void);
+
+/* ***********************************************************************
+ * called from: ability - chardump - fight - religion - spell - spells -
+ * spells0 - spells2
+ * *********************************************************************** */
+bool player_under_penance(void);
+
+
+/* ***********************************************************************
+ * called from: ability - acr - fight - food - it_use2 - item_use - items -
+ * misc - mutation - ouch
+ * *********************************************************************** */
+bool wearing_amulet(char which_am);
+
+
+/* ***********************************************************************
+ * called from: acr - chardump - describe - newgame - view
+ * *********************************************************************** */
+char *species_name( int speci, int level, bool genus = false, bool adj = false, bool cap = true );
+
+
+/* ***********************************************************************
+ * called from: beam
+ * *********************************************************************** */
+bool you_resist_magic(int power);
+
+
+/* ***********************************************************************
+ * called from: acr - decks - effects - it_use2 - it_use3 - item_use -
+ * items - output - shopping - spells1 - spells3
+ * *********************************************************************** */
+int burden_change(void);
+
+
+/* ***********************************************************************
+ * called from: items - misc
+ * *********************************************************************** */
+int carrying_capacity(void);
+
+
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+int check_stealth(void);
+
+
+/* ***********************************************************************
+ * called from: bang - beam - chardump - fight - files - it_use2 -
+ * item_use - misc - output - spells - spells1
+ * *********************************************************************** */
+int player_AC(void);
+
+
+/* ***********************************************************************
+ * called from: spell
+ * *********************************************************************** */
+unsigned char player_energy(void);
+
+
+/* ***********************************************************************
+ * called from: beam - chardump - fight - files - misc - output
+ * *********************************************************************** */
+int player_evasion(void);
+
+
+#if 0
+/* ***********************************************************************
+ * called from: acr - spells1
+ * *********************************************************************** */
+unsigned char player_fast_run(void);
+#endif
+
+/* ***********************************************************************
+ * called from: acr - spells1
+ * *********************************************************************** */
+int player_movement_speed(void);
+
+
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+int player_hunger_rate(void);
+
+
+/* ***********************************************************************
+ * called from: debug - it_use3 - spells0
+ * *********************************************************************** */
+int player_mag_abil(bool is_weighted);
+int player_magical_power( void );
+
+/* ***********************************************************************
+ * called from: fight - misc - ouch - spells
+ * *********************************************************************** */
+int player_prot_life(void);
+
+
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+int player_regen(void);
+
+
+/* ***********************************************************************
+ * called from: fight - files - it_use2 - misc - ouch - spells - spells2
+ * *********************************************************************** */
+int player_res_cold(void);
+
+
+/* ***********************************************************************
+ * called from: fight - files - ouch
+ * *********************************************************************** */
+int player_res_electricity(void);
+
+
+/* ***********************************************************************
+ * called from: acr - fight - misc - ouch - spells
+ * *********************************************************************** */
+int player_res_fire(void);
+
+
+/* ***********************************************************************
+ * called from: beam - decks - fight - fod - it_use2 - misc - ouch -
+ * spells - spells2
+ * *********************************************************************** */
+int player_res_poison(void);
+
+int player_res_magic(void);
+
+/* ***********************************************************************
+ * called from: beam - chardump - fight - misc - output
+ * *********************************************************************** */
+int player_shield_class(void);
+
+
+/* ***********************************************************************
+ * called from: spell - spells0
+ * *********************************************************************** */
+unsigned char player_spec_air(void);
+
+
+/* ***********************************************************************
+ * called from: spell - spells0
+ * *********************************************************************** */
+unsigned char player_spec_cold(void);
+
+
+/* ***********************************************************************
+ * called from: spell - spells0
+ * *********************************************************************** */
+unsigned char player_spec_conj(void);
+
+
+/* ***********************************************************************
+ * called from: it_use3 - spell - spells0
+ * *********************************************************************** */
+unsigned char player_spec_death(void);
+
+
+/* ***********************************************************************
+ * called from: spell - spells0
+ * *********************************************************************** */
+unsigned char player_spec_earth(void);
+
+
+/* ***********************************************************************
+ * called from: spell - spells0
+ * *********************************************************************** */
+unsigned char player_spec_ench(void);
+
+
+/* ***********************************************************************
+ * called from: spell - spells0
+ * *********************************************************************** */
+unsigned char player_spec_fire(void);
+
+
+/* ***********************************************************************
+ * called from: spell - spells0
+ * *********************************************************************** */
+unsigned char player_spec_holy(void);
+
+
+/* ***********************************************************************
+ * called from: spell - spells0
+ * *********************************************************************** */
+unsigned char player_spec_poison(void);
+
+
+/* ***********************************************************************
+ * called from: spell - spells0
+ * *********************************************************************** */
+unsigned char player_spec_summ(void);
+
+
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+int player_speed(void);
+
+
+/* ***********************************************************************
+ * called from: chardump - spells
+ * *********************************************************************** */
+int player_spell_levels(void);
+
+
+// last updated 18may2000 {dlb}
+/* ***********************************************************************
+ * called from: effects
+ * *********************************************************************** */
+unsigned char player_sust_abil(void);
+
+
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+int player_teleport(void);
+
+
+/* ***********************************************************************
+ * called from: ability - acr - items - misc - spells1 - spells3
+ * *********************************************************************** */
+int scan_randarts(char which_property);
+
+
+/* ***********************************************************************
+ * called from: fight - item_use
+ * *********************************************************************** */
+int slaying_bonus(char which_affected);
+
+
+/* ***********************************************************************
+ * called from: beam - decks - direct - effects - fight - files - it_use2 -
+ * items - monstuff - mon-util - mstuff2 - spells1 - spells2 -
+ * spells3
+ * *********************************************************************** */
+unsigned char player_see_invis(void);
+bool player_monster_visible( struct monsters *mon );
+
+
+/* ***********************************************************************
+ * called from: acr - decks - it_use2 - ouch
+ * *********************************************************************** */
+unsigned long exp_needed(int lev);
+
+
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void display_char_status(void);
+
+
+/* ***********************************************************************
+ * called from: item_use - items - misc - spells - spells3
+ * *********************************************************************** */
+void forget_map(unsigned char chance_forgotten);
+
+
+// last updated 19may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - fight
+ * *********************************************************************** */
+void gain_exp(unsigned int exp_gained);
+
+
+// last updated 17dec2000 {gdl}
+/* ***********************************************************************
+ * called from: acr - it_use2 - item_use - mutation - transfor - player -
+ * misc - stuff
+ * *********************************************************************** */
+void modify_stat(unsigned char which_stat, char amount, bool suppress_msg);
+
+
+// last updated 19may2000 {dlb}
+/* ***********************************************************************
+ * called from: decks - it_use2 - player
+ * *********************************************************************** */
+void level_change(void);
+
+
+/* ***********************************************************************
+ * called from: skills
+ * *********************************************************************** */
+void redraw_skill(const char your_name[kNameLen], const char class_name[80]);
+
+
+/* ***********************************************************************
+ * called from: ability - fight - item_use - mutation - newgame - spells0 -
+ * transfor
+ * *********************************************************************** */
+bool player_genus( unsigned char which_genus,
+ unsigned char species = SP_UNKNOWN );
+
+
+/* ***********************************************************************
+ * called from: ability - effects - fight - it_use3 - ouch - spell -
+ * spells - spells2 - spells3 - spells4
+ * *********************************************************************** */
+void dec_hp(int hp_loss, bool fatal);
+
+
+/* ***********************************************************************
+ * called from: ability - it_use3 - spell - spells3
+ * *********************************************************************** */
+bool enough_hp (int minimum, bool suppress_msg);
+
+
+/* ***********************************************************************
+ * called from: ability - it_use3
+ * *********************************************************************** */
+bool enough_mp (int minimum, bool suppress_msg);
+
+
+/* ***********************************************************************
+ * called from: ability - fight - it_use3 - monstuff - ouch - spell
+ * *********************************************************************** */
+void dec_mp(int mp_loss);
+
+
+/* ***********************************************************************
+ * called from: ability - acr - fight - it_use2 - it_use3 - spells3
+ * *********************************************************************** */
+void inc_mp(int mp_gain, bool max_too);
+
+
+/* ***********************************************************************
+ * called from: acr - fight - food - spells1 - spells2
+ * *********************************************************************** */
+void inc_hp(int hp_gain, bool max_too);
+
+void rot_hp( int hp_loss );
+void unrot_hp( int hp_recovered );
+int player_rotted( void );
+void rot_mp( int mp_loss );
+
+void inc_max_hp( int hp_gain );
+void dec_max_hp( int hp_loss );
+
+void inc_max_mp( int mp_gain );
+void dec_max_mp( int mp_loss );
+
+/* ***********************************************************************
+ * called from: acr - misc - religion - skills2 - spells1 - transfor
+ * *********************************************************************** */
+void deflate_hp(int new_level, bool floor);
+
+
+/* ***********************************************************************
+ * called from: acr - it_use2 - newgame - ouch - religion - spell - spells1
+ * *********************************************************************** */
+void set_hp(int new_amount, bool max_too);
+
+
+/* ***********************************************************************
+ * called from: it_use3 - newgame
+ * *********************************************************************** */
+void set_mp(int new_amount, bool max_too);
+
+
+/* ***********************************************************************
+ * called from: newgame
+ * *********************************************************************** */
+int get_species_index_by_abbrev( const char *abbrev );
+int get_species_index_by_name( const char *name );
+const char *get_species_abbrev( int which_species );
+
+int get_class_index_by_abbrev( const char *abbrev );
+int get_class_index_by_name( const char *name );
+const char *get_class_abbrev( int which_job );
+const char *get_class_name( int which_job );
+
+
+// last updated 19apr2001 {gdl}
+/* ***********************************************************************
+ * called from:
+ * *********************************************************************** */
+void contaminate_player(int change, bool statusOnly = false);
+
+void poison_player( int amount, bool force = false );
+void reduce_poison_player( int amount );
+
+void confuse_player( int amount, bool resistable = true );
+void reduce_confuse_player( int amount );
+
+void slow_player( int amount );
+void dec_slow_player();
+
+void haste_player( int amount );
+void dec_haste_player();
+
+void disease_player( int amount );
+void dec_disease_player();
+
+void rot_player( int amount );
+
+// last updated 15sep2001 {bwr}
+/* ***********************************************************************
+ * called from:
+ * *********************************************************************** */
+bool player_has_spell( int spell );
+
+
+#endif
diff --git a/trunk/source/randart.cc b/trunk/source/randart.cc
new file mode 100644
index 0000000000..939cdfecaa
--- /dev/null
+++ b/trunk/source/randart.cc
@@ -0,0 +1,1988 @@
+/*
+ * File: randart.cc
+ * Summary: Random and unrandom artifact functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <8> 19 Jun 99 GDL added IBMCPP support
+ * <7> 14/12/99 LRH random2 -> random5
+ * <6> 11/06/99 cdl random4 -> random2
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "randart.h"
+
+#include <string.h>
+#include <stdio.h>
+
+#include "externs.h"
+#include "itemname.h"
+#include "stuff.h"
+#include "wpn-misc.h"
+
+/*
+ The initial generation of a randart is very simple - it occurs
+ in dungeon.cc and consists of giving it a few random things - plus & plus2
+ mainly.
+*/
+const char *rand_wpn_names[] = {
+ " of Blood",
+ " of Death",
+ " of Bloody Death",
+ " of Pain",
+ " of Painful Death",
+ " of Pain & Death",
+ " of Infinite Pain",
+ " of Eternal Torment",
+ " of Power",
+ " of Wrath",
+/* 10: */
+ " of Doom",
+ " of Tender Mercy",
+ " of the Apocalypse",
+ " of the Jester",
+ " of the Ring",
+ " of the Fool",
+ " of the Gods",
+ " of the Imperium",
+ " of Destruction",
+ " of Armageddon",
+/* 20: */
+ " of Cruel Justice",
+ " of Righteous Anger",
+ " of Might",
+ " of the Orb",
+ " of Makhleb",
+ " of Trog",
+ " of Xom",
+ " of the Ancients",
+ " of Mana",
+ " of Nemelex Xobeh",
+/* 30: */
+ " of the Magi",
+ " of the Archmagi",
+ " of the King",
+ " of the Queen",
+ " of the Spheres",
+ " of Circularity",
+ " of Linearity",
+ " of Conflict",
+ " of Battle",
+ " of Honour",
+/* 40: */
+ " of the Butterfly",
+ " of the Wasp",
+ " of the Frog",
+ " of the Weasel",
+ " of the Troglodytes",
+ " of the Pill-Bug",
+ " of Sin",
+ " of Vengeance",
+ " of Execution",
+ " of Arbitration",
+/* 50: */
+ " of the Seeker",
+ " of Truth",
+ " of Lies",
+ " of the Eggplant",
+ " of the Turnip",
+ " of Chance",
+ " of Curses",
+ " of Hell's Wrath",
+ " of the Undead",
+ " of Chaos",
+/* 60: */
+ " of Law",
+ " of Life",
+ " of the Old World",
+ " of the New World",
+ " of the Middle World",
+ " of Crawl",
+ " of Unpleasantness",
+ " of Discomfort",
+ " of Brutal Revenge",
+ " of Triumph",
+/* 70: */
+ " of Evisceration",
+ " of Dismemberment",
+ " of Terror",
+ " of Fear",
+ " of Pride",
+ " of the Volcano",
+ " of Blood-Lust",
+ " of Division",
+ " of Eternal Harmony",
+ " of Peace",
+/* 80: */
+ " of Quick Death",
+ " of Instant Death",
+ " of Misery",
+ " of the Whale",
+ " of the Lobster",
+ " of the Whelk",
+ " of the Penguin",
+ " of the Puffin",
+ " of the Mushroom",
+ " of the Toadstool",
+/* 90: */
+ " of the Little People",
+ " of the Puffball",
+ " of Spores",
+ " of Optimality",
+ " of Pareto-Optimality",
+ " of Greatest Utility",
+ " of Anarcho-Capitalism",
+ " of Ancient Evil",
+ " of the Revolution",
+ " of the People",
+/* 100: */
+ " of the Elves",
+ " of the Dwarves",
+ " of the Orcs",
+ " of the Humans",
+ " of Sludge",
+ " of the Naga",
+ " of the Trolls",
+ " of the Ogres",
+ " of Equitable Redistribution",
+ " of Wealth",
+/* 110: */
+ " of Poverty",
+ " of Reapportionment",
+ " of Fragile Peace",
+ " of Reinforcement",
+ " of Beauty",
+ " of the Slug",
+ " of the Snail",
+ " of the Gastropod",
+ " of Corporal Punishment",
+ " of Capital Punishment",
+/* 120: */
+ " of the Beast",
+ " of Light",
+ " of Darkness",
+ " of Day",
+ " of the Day",
+ " of Night",
+ " of the Night",
+ " of Twilight",
+ " of the Twilight",
+ " of Dawn",
+/* 130: */
+ " of the Dawn",
+ " of the Sun",
+ " of the Moon",
+ " of Distant Worlds",
+ " of the Unseen Realm",
+ " of Pandemonium",
+ " of the Abyss",
+ " of the Nexus",
+ " of the Gulag",
+ " of the Crusades",
+/* 140: */
+ " of Proximity",
+ " of Wounding",
+ " of Peril",
+ " of the Eternal Warrior",
+ " of the Eternal War",
+ " of Evil",
+ " of Pounding",
+ " of Oozing Pus",
+ " of Pestilence",
+ " of Plague",
+/* 150: */
+ " of Negation",
+ " of the Saviour",
+ " of Infection",
+ " of Defence",
+ " of Protection",
+ " of Defence by Offence",
+ " of Expedience",
+ " of Reason",
+ " of Unreason",
+ " of the Heart",
+/* 160: */
+ " of Offence",
+ " of the Leaf",
+ " of Leaves",
+ " of Winter",
+ " of Summer",
+ " of Autumn",
+ " of Spring",
+ " of Midsummer",
+ " of Midwinter",
+ " of Eternal Night",
+/* 170: */
+ " of Shrieking Terror",
+ " of the Lurker",
+ " of the Crawling Thing",
+ " of the Thing",
+ "\"Thing\"",
+ " of the Sea",
+ " of the Forest",
+ " of the Trees",
+ " of Earth",
+ " of the World",
+/* 180: */
+ " of Bread",
+ " of Yeast",
+ " of the Amoeba",
+ " of Deformation",
+ " of Guilt",
+ " of Innocence",
+ " of Ascent",
+ " of Descent",
+ " of Music",
+ " of Brilliance",
+/* 190: */
+ " of Disgust",
+ " of Feasting",
+ " of Sunlight",
+ " of Starshine",
+ " of the Stars",
+ " of Dust",
+ " of the Clouds",
+ " of the Sky",
+ " of Ash",
+ " of Slime",
+/* 200: */
+ " of Clarity",
+ " of Eternal Vigilance",
+ " of Purpose",
+ " of the Moth",
+ " of the Goat",
+ " of Fortitude",
+ " of Equivalence",
+ " of Balance",
+ " of Unbalance",
+ " of Harmony",
+/* 210: */
+ " of Disharmony",
+ " of the Inferno",
+ " of the Omega Point",
+ " of Inflation",
+ " of Deflation",
+ " of Supply",
+ " of Demand",
+ " of Gross Domestic Product",
+ " of Unjust Enrichment",
+ " of Detinue",
+/* 220: */
+ " of Conversion",
+ " of Anton Piller",
+ " of Mandamus",
+ " of Frustration",
+ " of Breach",
+ " of Fundamental Breach",
+ " of Termination",
+ " of Extermination",
+ " of Satisfaction",
+ " of Res Nullius",
+/* 230: */
+ " of Fee Simple",
+ " of Terra Nullius",
+ " of Context",
+ " of Prescription",
+ " of Freehold",
+ " of Tortfeasance",
+ " of Omission",
+ " of Negligence",
+ " of Pains",
+ " of Attainder",
+/* 240: */
+ " of Action",
+ " of Inaction",
+ " of Truncation",
+ " of Defenestration",
+ " of Desertification",
+ " of the Wilderness",
+ " of Psychosis",
+ " of Neurosis",
+ " of Fixation",
+ " of the Open Hand",
+/* 250: */
+ " of the Tooth",
+ " of Honesty",
+ " of Dishonesty",
+ " of Divine Compulsion",
+ " of the Invisible Hand",
+ " of Freedom",
+ " of Liberty",
+ " of Servitude",
+ " of Domination",
+ " of Tension",
+/* 260: */
+ " of Monotheism",
+ " of Atheism",
+ " of Agnosticism",
+ " of Existentialism",
+ " of the Good",
+ " of Relativism",
+ " of Absolutism",
+ " of Absolution",
+ " of Abstinence",
+ " of Abomination",
+/* 270: */
+ " of Mutilation",
+ " of Stasis",
+ " of Wonder",
+ " of Dullness",
+ " of Dim Light",
+ " of the Shining Light",
+ " of Immorality",
+ " of Amorality",
+ " of Precise Incision",
+ " of Orthodoxy",
+/* 280: */
+ " of Faith",
+ " of Untruth",
+ " of the Augurer",
+ " of the Water Diviner",
+ " of the Soothsayer",
+ " of Punishment",
+ " of Amelioration",
+ " of Sulphur",
+ " of the Egg",
+ " of the Globe",
+/* 290: */
+ " of the Candle",
+ " of the Candelabrum",
+ " of the Vampires",
+ " of the Orcs",
+ " of the Halflings",
+ " of World's End",
+ " of Blue Skies",
+ " of Red Skies",
+ " of Orange Skies",
+ " of Purple Skies",
+/* 300: */
+ " of Articulation",
+ " of the Mind",
+ " of the Spider",
+ " of the Lamprey",
+ " of the Beginning",
+ " of the End",
+ " of Severance",
+ " of Sequestration",
+ " of Mourning",
+ " of Death's Door",
+/* 310: */
+ " of the Key",
+ " of Earthquakes",
+ " of Failure",
+ " of Success",
+ " of Intimidation",
+ " of the Mosquito",
+ " of the Gnat",
+ " of the Blowfly",
+ " of the Turtle",
+ " of the Tortoise",
+/* 320: */
+ " of the Pit",
+ " of the Grave",
+ " of Submission",
+ " of Dominance",
+ " of the Messenger",
+ " of Crystal",
+ " of Gravity",
+ " of Levity",
+ " of the Slorg",
+ " of Surprise",
+/* 330: */
+ " of the Maze",
+ " of the Labyrinth",
+ " of Divine Intervention",
+ " of Rotation",
+ " of the Spinneret",
+ " of the Scorpion",
+ " of Demonkind",
+ " of the Genius",
+ " of Bloodstone",
+ " of Grontol",
+/* 340: */
+ " \"Grim Tooth\"",
+ " \"Widowmaker\"",
+ " \"Widowermaker\"",
+ " \"Lifebane\"",
+ " \"Conservator\"",
+ " \"Banisher\"",
+ " \"Tormentor\"",
+ " \"Secret Weapon\"",
+ " \"String\"",
+ " \"Stringbean\"",
+/* 350: */
+ " \"Blob\"",
+ " \"Globulus\"",
+ " \"Hulk\"",
+ " \"Raisin\"",
+ " \"Starlight\"",
+ " \"Giant's Toothpick\"",
+ " \"Pendulum\"",
+ " \"Backscratcher\"",
+ " \"Brush\"",
+ " \"Murmur\"",
+/* 360: */
+ " \"Sarcophage\"",
+ " \"Concordance\"",
+ " \"Dragon's Tongue\"",
+ " \"Arbiter\"",
+ " \"Gram\"",
+ " \"Grom\"",
+ " \"Grim\"",
+ " \"Grum\"",
+ " \"Rummage\"",
+ " \"Omelette\"",
+/* 370: */
+ " \"Egg\"",
+ " \"Aubergine\"",
+ " \"Z\"",
+ " \"X\"",
+ " \"Q\"",
+ " \"Ox\"",
+ " \"Death Rattle\"",
+ " \"Tattletale\"",
+ " \"Fish\"",
+ " \"Bung\"",
+/* 380: */
+ " \"Arcanum\"",
+ " \"Mud Pie of Death\"",
+ " \"Transmigrator\"",
+ " \"Ultimatum\"",
+ " \"Earthworm\"",
+ " \"Worm\"",
+ " \"Worm's Wrath\"",
+ " \"Xom's Favour\"",
+ " \"Bingo\"",
+ " \"Leviticus\"",
+// Not yet possible...
+/* 390: */
+ " of Joyful Slaughter",
+ " of ",
+ " of ",
+ " of ",
+ " of ",
+ " of ",
+ " of ",
+ " of ",
+ " of ",
+ " of ",
+
+/* 390: */
+ "\"\"",
+ "\"\"",
+ "\"\"",
+ "\"\"",
+ "\"\"",
+ "\"\"",
+ "\"\"",
+ "\"\"",
+ "\"\"",
+ "\"\"",
+
+/* 340: */
+ " of ",
+ " of ",
+ " of ",
+ " of ",
+ " of ",
+ " of ",
+ " of ",
+ " of ",
+ " of ",
+ " of ",
+
+/* 200: */
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+};
+
+const char *rand_armour_names[] = {
+/* 0: */
+ " of Shielding",
+ " of Grace",
+ " of Impermeability",
+ " of the Onion",
+ " of Life",
+ " of Defence",
+ " of Nonsense",
+ " of Eternal Vigilance",
+ " of Fun",
+ " of Joy",
+/* 10: */
+ " of Death's Door",
+ " of the Gate",
+ " of Watchfulness",
+ " of Integrity",
+ " of Bodily Harmony",
+ " of Harmony",
+ " of the Untouchables",
+ " of Grot",
+ " of Grottiness",
+ " of Filth",
+/* 20: */
+ " of Wonder",
+ " of Wondrous Power",
+ " of Power",
+ " of Vlad",
+ " of the Eternal Fruit",
+ " of Invincibility",
+ " of Hide-and-Seek",
+ " of the Mouse",
+ " of the Saviour",
+ " of Plasticity",
+/* 30: */
+ " of Baldness",
+ " of Terror",
+ " of the Arcane",
+ " of Resist Death",
+ " of Anaesthesia",
+ " of the Guardian",
+ " of Inviolability",
+ " of the Tortoise",
+ " of the Turtle",
+ " of the Armadillo",
+/* 40: */
+ " of the Echidna",
+ " of the Armoured One",
+ " of Weirdness",
+ " of Pathos",
+ " of Serendipity",
+ " of Loss",
+ " of Hedging",
+ " of Indemnity",
+ " of Limitation",
+ " of Exclusion",
+/* 50: */
+ " of Repulsion",
+ " of Untold Secrets",
+ " of the Earth",
+ " of the Turtledove",
+ " of Limited Liability",
+ " of Responsibility",
+ " of Hadjma",
+ " of Glory",
+ " of Preservation",
+ " of Conservation",
+/* 60: */
+ " of Protective Custody",
+ " of the Clam",
+ " of the Barnacle",
+ " of the Lobster",
+ " of Hairiness",
+ " of Supple Strength",
+ " of Space",
+ " of the Vacuum",
+ " of Compression",
+ " of Decompression",
+
+/* 70: */
+ " of the Loofah",
+ " of ",
+ " of ",
+ " of ",
+ " of ",
+ " of ",
+ " of ",
+ " of ",
+ " of ",
+ " of ",
+// Sarcophagus
+};
+
+// Remember: disallow unrandart creation in abyss/pan
+
+/*
+ The following unrandart bits were taken from $pellbinder's mon-util code
+ (see mon-util.h & mon-util.cc) and modified (LRH). They're in randart.cc and
+ not randart.h because they're only used in this code module.
+*/
+
+#if defined(MAC) || defined(__IBMCPP__) || defined(__BCPLUSPLUS__)
+#define PACKED
+#else
+#define PACKED __attribute__ ((packed))
+#endif
+
+//int unranddatasize;
+
+#ifdef __IBMCPP__
+#pragma pack(push)
+#pragma pack(1)
+#endif
+
+struct unrandart_entry
+{
+ const char *name; // true name of unrandart (max 31 chars)
+ const char *unid_name; // un-id'd name of unrandart (max 31 chars)
+
+ int ura_cl; // class of ura
+ int ura_ty; // type of ura
+ int ura_pl; // plus of ura
+ int ura_pl2; // plus2 of ura
+ int ura_col; // colour of ura
+ short prpty[RA_PROPERTIES];
+
+ // special description added to 'v' command output (max 31 chars)
+ const char *spec_descrip1;
+ // special description added to 'v' command output (max 31 chars)
+ const char *spec_descrip2;
+ // special description added to 'v' command output (max 31 chars)
+ const char *spec_descrip3;
+};
+
+#ifdef __IBMCPP__
+#pragma pack(pop)
+#endif
+
+static struct unrandart_entry unranddata[] = {
+#include "unrand.h"
+};
+
+char *art_n;
+static FixedVector < char, NO_UNRANDARTS > unrandart_exist;
+
+static int random5( int randmax );
+static struct unrandart_entry *seekunrandart( const item_def &item );
+
+static int random5( int randmax )
+{
+ if (randmax <= 0)
+ return (0);
+
+ //return rand() % randmax;
+ return ((int) rand() / (RAND_MAX / randmax + 1));
+ // must use random (not rand) for the predictable-results-from-known
+ // -srandom-seeds thing to work.
+}
+
+void set_unrandart_exist(int whun, char is_exist)
+{
+ unrandart_exist[whun] = is_exist;
+}
+
+char does_unrandart_exist(int whun)
+{
+ return (unrandart_exist[whun]);
+}
+
+// returns true is item is a pure randart or an unrandart
+bool is_random_artefact( const item_def &item )
+{
+ return (item.flags & ISFLAG_ARTEFACT_MASK);
+}
+
+// returns true if item in an unrandart
+bool is_unrandom_artefact( const item_def &item )
+{
+ return (item.flags & ISFLAG_UNRANDART);
+}
+
+// returns true if item is one of the origional fixed artefacts
+bool is_fixed_artefact( const item_def &item )
+{
+ if (!is_random_artefact( item )
+ && item.base_type == OBJ_WEAPONS
+ && item.special >= SPWPN_SINGING_SWORD)
+ {
+ return (true);
+ }
+
+ return (false);
+}
+
+int get_unique_item_status( int base_type, int art )
+{
+ // Note: for weapons "art" is in item.special,
+ // for orbs it's the sub_type.
+ if (base_type == OBJ_WEAPONS)
+ {
+ if (art >= SPWPN_SINGING_SWORD && art <= SPWPN_SWORD_OF_ZONGULDROK)
+ return (you.unique_items[ art - SPWPN_SINGING_SWORD ]);
+ else if (art >= SPWPN_SWORD_OF_POWER && art <= SPWPN_STAFF_OF_WUCAD_MU)
+ return (you.unique_items[ art - SPWPN_SWORD_OF_POWER + 24 ]);
+ }
+ else if (base_type == OBJ_ORBS)
+ {
+ if (art >= 4 && art <= 19)
+ return (you.unique_items[ art + 3 ]);
+
+ }
+
+ return (UNIQ_NOT_EXISTS);
+}
+
+void set_unique_item_status( int base_type, int art, int status )
+{
+ // Note: for weapons "art" is in item.special,
+ // for orbs it's the sub_type.
+ if (base_type == OBJ_WEAPONS)
+ {
+ if (art >= SPWPN_SINGING_SWORD && art <= SPWPN_SWORD_OF_ZONGULDROK)
+ you.unique_items[ art - SPWPN_SINGING_SWORD ] = status;
+ else if (art >= SPWPN_SWORD_OF_POWER && art <= SPWPN_STAFF_OF_WUCAD_MU)
+ you.unique_items[ art - SPWPN_SWORD_OF_POWER + 24 ] = status;
+ }
+ else if (base_type == OBJ_ORBS)
+ {
+ if (art >= 4 && art <= 19)
+ you.unique_items[ art + 3 ] = status;
+
+ }
+}
+
+static long calc_seed( const item_def &item )
+{
+ return (item.special & RANDART_SEED_MASK);
+}
+
+void randart_wpn_properties( const item_def &item,
+ FixedVector< char, RA_PROPERTIES > &proprt )
+{
+ ASSERT( is_random_artefact( item ) );
+
+ const int aclass = item.base_type;
+ const int atype = item.sub_type;
+
+ int i = 0;
+ int power_level = 0;
+
+ if (is_unrandom_artefact( item ))
+ {
+ struct unrandart_entry *unrand = seekunrandart( item );
+
+ for (i = 0; i < RA_PROPERTIES; i++)
+ proprt[i] = unrand->prpty[i];
+
+ return;
+ }
+
+ // long seed = aclass * adam + atype * (aplus % 100) + aplus2 * 100;
+ long seed = calc_seed( item );
+ long randstore = rand();
+ srand( seed );
+
+ if (aclass == OBJ_ARMOUR)
+ power_level = item.plus / 2 + 2;
+ else if (aclass == OBJ_JEWELLERY)
+ power_level = 1 + random5(3) + random5(2);
+ else // OBJ_WEAPON
+ power_level = item.plus / 3 + item.plus2 / 3;
+
+ if (power_level < 0)
+ power_level = 0;
+
+ for (i = 0; i < RA_PROPERTIES; i++)
+ proprt[i] = 0;
+
+ if (aclass == OBJ_WEAPONS) /* Only weapons get brands, of course */
+ {
+ proprt[RAP_BRAND] = SPWPN_FLAMING + random5(15); /* brand */
+
+ if (random5(6) == 0)
+ proprt[RAP_BRAND] = SPWPN_FLAMING + random5(2);
+
+ if (random5(6) == 0)
+ proprt[RAP_BRAND] = SPWPN_ORC_SLAYING + random5(4);
+
+ if (random5(6) == 0)
+ proprt[RAP_BRAND] = SPWPN_VORPAL;
+
+ if (proprt[RAP_BRAND] == SPWPN_FLAME
+ || proprt[RAP_BRAND] == SPWPN_FROST)
+ {
+ proprt[RAP_BRAND] = 0; /* missile wpns */
+ }
+
+ if (proprt[RAP_BRAND] == SPWPN_PROTECTION)
+ proprt[RAP_BRAND] = 0; /* no protection */
+
+ if (proprt[RAP_BRAND] == SPWPN_DISRUPTION
+ && !(atype == WPN_MACE || atype == WPN_GREAT_MACE
+ || atype == WPN_HAMMER))
+ {
+ proprt[RAP_BRAND] = SPWPN_NORMAL;
+ }
+
+ // is this happens, things might get broken -- bwr
+ if (proprt[RAP_BRAND] == SPWPN_SPEED && atype == WPN_QUICK_BLADE)
+ proprt[RAP_BRAND] = SPWPN_NORMAL;
+
+ if (launches_things(atype))
+ {
+ proprt[RAP_BRAND] = SPWPN_NORMAL;
+
+ if (random5(3) == 0)
+ {
+ int tmp = random5(20);
+
+ proprt[RAP_BRAND] = (tmp >= 18) ? SPWPN_SPEED :
+ (tmp >= 14) ? SPWPN_PROTECTION :
+ (tmp >= 10) ? SPWPN_VENOM
+ : SPWPN_FLAME + (tmp % 2);
+ }
+ }
+
+
+ if (is_demonic(atype))
+ {
+ switch (random5(9))
+ {
+ case 0:
+ proprt[RAP_BRAND] = SPWPN_DRAINING;
+ break;
+ case 1:
+ proprt[RAP_BRAND] = SPWPN_FLAMING;
+ break;
+ case 2:
+ proprt[RAP_BRAND] = SPWPN_FREEZING;
+ break;
+ case 3:
+ proprt[RAP_BRAND] = SPWPN_ELECTROCUTION;
+ break;
+ case 4:
+ proprt[RAP_BRAND] = SPWPN_VAMPIRICISM;
+ break;
+ case 5:
+ proprt[RAP_BRAND] = SPWPN_PAIN;
+ break;
+ case 6:
+ proprt[RAP_BRAND] = SPWPN_VENOM;
+ break;
+ default:
+ power_level -= 2;
+ }
+ power_level += 2;
+ }
+ else if (random5(3) == 0)
+ proprt[RAP_BRAND] = SPWPN_NORMAL;
+ else
+ power_level++;
+ }
+
+ if (random5(5) == 0)
+ goto skip_mods;
+
+ /* AC mod - not for armours or rings of protection */
+ if (random5(4 + power_level) == 0
+ && aclass != OBJ_ARMOUR
+ && (aclass != OBJ_JEWELLERY || atype != RING_PROTECTION))
+ {
+ proprt[RAP_AC] = 1 + random5(3) + random5(3) + random5(3);
+ power_level++;
+ if (random5(4) == 0)
+ {
+ proprt[RAP_AC] -= 1 + random5(3) + random5(3) + random5(3);
+ power_level--;
+ }
+ }
+
+ /* ev mod - not for rings of evasion */
+ if (random5(4 + power_level) == 0
+ && (aclass != OBJ_JEWELLERY || atype != RING_EVASION))
+ {
+ proprt[RAP_EVASION] = 1 + random5(3) + random5(3) + random5(3);
+ power_level++;
+ if (random5(4) == 0)
+ {
+ proprt[RAP_EVASION] -= 1 + random5(3) + random5(3) + random5(3);
+ power_level--;
+ }
+ }
+
+ /* str mod - not for rings of strength */
+ if (random5(4 + power_level) == 0
+ && (aclass != OBJ_JEWELLERY || atype != RING_STRENGTH))
+ {
+ proprt[RAP_STRENGTH] = 1 + random5(3) + random5(2);
+ power_level++;
+ if (random5(4) == 0)
+ {
+ proprt[RAP_STRENGTH] -= 1 + random5(3) + random5(3) + random5(3);
+ power_level--;
+ }
+ }
+
+ /* int mod - not for rings of intelligence */
+ if (random5(4 + power_level) == 0
+ && (aclass != OBJ_JEWELLERY || atype != RING_INTELLIGENCE))
+ {
+ proprt[RAP_INTELLIGENCE] = 1 + random5(3) + random5(2);
+ power_level++;
+ if (random5(4) == 0)
+ {
+ proprt[RAP_INTELLIGENCE] -= 1 + random5(3) + random5(3) + random5(3);
+ power_level--;
+ }
+ }
+
+ /* dex mod - not for rings of dexterity */
+ if (random5(4 + power_level) == 0
+ && (aclass != OBJ_JEWELLERY || atype != RING_DEXTERITY))
+ {
+ proprt[RAP_DEXTERITY] = 1 + random5(3) + random5(2);
+ power_level++;
+ if (random5(4) == 0)
+ {
+ proprt[RAP_DEXTERITY] -= 1 + random5(3) + random5(3) + random5(3);
+ power_level--;
+ }
+ }
+
+ skip_mods:
+ if (random5(15) < power_level
+ || aclass == OBJ_WEAPONS
+ || (aclass == OBJ_JEWELLERY && atype == RING_SLAYING))
+ {
+ goto skip_combat;
+ }
+
+ /* Weapons and rings of slaying can't get these */
+ if (random5(4 + power_level) == 0) /* to-hit */
+ {
+ proprt[RAP_ACCURACY] = 1 + random5(3) + random5(2);
+ power_level++;
+ if (random5(4) == 0)
+ {
+ proprt[RAP_ACCURACY] -= 1 + random5(3) + random5(3) + random5(3);
+ power_level--;
+ }
+ }
+
+ if (random5(4 + power_level) == 0) /* to-dam */
+ {
+ proprt[RAP_DAMAGE] = 1 + random5(3) + random5(2);
+ power_level++;
+ if (random5(4) == 0)
+ {
+ proprt[RAP_DAMAGE] -= 1 + random5(3) + random5(3) + random5(3);
+ power_level--;
+ }
+ }
+
+ skip_combat:
+ if (random5(12) < power_level)
+ goto finished_powers;
+
+/* res_fire */
+ if (random5(4 + power_level) == 0
+ && (aclass != OBJ_JEWELLERY
+ || (atype != RING_PROTECTION_FROM_FIRE
+ && atype != RING_FIRE
+ && atype != RING_ICE))
+ && (aclass != OBJ_ARMOUR
+ || (atype != ARM_DRAGON_ARMOUR
+ && atype != ARM_ICE_DRAGON_ARMOUR
+ && atype != ARM_GOLD_DRAGON_ARMOUR)))
+ {
+ proprt[RAP_FIRE] = 1;
+ if (random5(5) == 0)
+ proprt[RAP_FIRE]++;
+ power_level++;
+ }
+
+ /* res_cold */
+ if (random5(4 + power_level) == 0
+ && (aclass != OBJ_JEWELLERY
+ || (atype != RING_PROTECTION_FROM_COLD
+ && atype != RING_FIRE
+ && atype != RING_ICE))
+ && (aclass != OBJ_ARMOUR
+ || (atype != ARM_DRAGON_ARMOUR
+ && atype != ARM_ICE_DRAGON_ARMOUR
+ && atype != ARM_GOLD_DRAGON_ARMOUR)))
+ {
+ proprt[RAP_COLD] = 1;
+ if (random5(5) == 0)
+ proprt[RAP_COLD]++;
+ power_level++;
+ }
+
+ if (random5(12) < power_level || power_level > 7)
+ goto finished_powers;
+
+ /* res_elec */
+ if (random5(4 + power_level) == 0
+ && (aclass != OBJ_ARMOUR || atype != ARM_STORM_DRAGON_ARMOUR))
+ {
+ proprt[RAP_ELECTRICITY] = 1;
+ power_level++;
+ }
+
+/* res_poison */
+ if (random5(5 + power_level) == 0
+ && (aclass != OBJ_JEWELLERY || atype != RING_POISON_RESISTANCE)
+ && (aclass != OBJ_ARMOUR
+ || atype != ARM_GOLD_DRAGON_ARMOUR
+ || atype != ARM_SWAMP_DRAGON_ARMOUR))
+ {
+ proprt[RAP_POISON] = 1;
+ power_level++;
+ }
+
+ /* prot_life - no necromantic brands on weapons allowed */
+ if (random5(4 + power_level) == 0
+ && (aclass != OBJ_JEWELLERY || atype != RING_TELEPORTATION)
+ && proprt[RAP_BRAND] != SPWPN_DRAINING
+ && proprt[RAP_BRAND] != SPWPN_VAMPIRICISM
+ && proprt[RAP_BRAND] != SPWPN_PAIN)
+ {
+ proprt[RAP_NEGATIVE_ENERGY] = 1;
+ power_level++;
+ }
+
+ /* res magic */
+ if (random5(4 + power_level) == 0
+ && (aclass != OBJ_JEWELLERY || atype != RING_PROTECTION_FROM_MAGIC))
+ {
+ proprt[RAP_MAGIC] = 20 + random5(40);
+ power_level++;
+ }
+
+ /* see_invis */
+ if (random5(4 + power_level) == 0
+ && (aclass != OBJ_JEWELLERY || atype != RING_INVISIBILITY))
+ {
+ proprt[RAP_EYESIGHT] = 1;
+ power_level++;
+ }
+
+ if (random5(12) < power_level || power_level > 10)
+ goto finished_powers;
+
+ /* turn invis */
+ if (random5(10) == 0
+ && (aclass != OBJ_JEWELLERY || atype != RING_INVISIBILITY))
+ {
+ proprt[RAP_INVISIBLE] = 1;
+ power_level++;
+ }
+
+ /* levitate */
+ if (random5(10) == 0
+ && (aclass != OBJ_JEWELLERY || atype != RING_LEVITATION))
+ {
+ proprt[RAP_LEVITATE] = 1;
+ power_level++;
+ }
+
+ if (random5(10) == 0) /* blink */
+ {
+ proprt[RAP_BLINK] = 1;
+ power_level++;
+ }
+
+ /* teleport */
+ if (random5(10) == 0
+ && (aclass != OBJ_JEWELLERY || atype != RING_TELEPORTATION))
+ {
+ proprt[RAP_CAN_TELEPORT] = 1;
+ power_level++;
+ }
+
+ /* go berserk */
+ if (random5(10) == 0 && (aclass != OBJ_JEWELLERY || atype != AMU_RAGE))
+ {
+ proprt[RAP_BERSERK] = 1;
+ power_level++;
+ }
+
+ if (random5(10) == 0) /* sense surr */
+ {
+ proprt[RAP_MAPPING] = 1;
+ power_level++;
+ }
+
+
+ finished_powers:
+ /* Armours get less powers, and are also less likely to be
+ cursed that wpns */
+ if (aclass == OBJ_ARMOUR)
+ power_level -= 4;
+
+ if (random5(17) >= power_level || power_level < 2)
+ goto finished_curses;
+
+ switch (random5(9))
+ {
+ case 0: /* makes noise */
+ if (aclass != OBJ_WEAPONS)
+ break;
+ proprt[RAP_NOISES] = 1 + random5(4);
+ break;
+ case 1: /* no magic */
+ proprt[RAP_PREVENT_SPELLCASTING] = 1;
+ break;
+ case 2: /* random teleport */
+ if (aclass != OBJ_WEAPONS)
+ break;
+ proprt[RAP_CAUSE_TELEPORTATION] = 5 + random5(15);
+ break;
+ case 3: /* no teleport - doesn't affect some instantaneous teleports */
+ if (aclass == OBJ_JEWELLERY && atype == RING_TELEPORTATION)
+ break; /* already is a ring of tport */
+ if (aclass == OBJ_JEWELLERY && atype == RING_TELEPORT_CONTROL)
+ break; /* already is a ring of tport ctrl */
+ proprt[RAP_BLINK] = 0;
+ proprt[RAP_CAN_TELEPORT] = 0;
+ proprt[RAP_PREVENT_TELEPORTATION] = 1;
+ break;
+ case 4: /* berserk on attack */
+ if (aclass != OBJ_WEAPONS)
+ break;
+ proprt[RAP_ANGRY] = 1 + random5(8);
+ break;
+ case 5: /* susceptible to fire */
+ if (aclass == OBJ_JEWELLERY
+ && (atype == RING_PROTECTION_FROM_FIRE || atype == RING_FIRE
+ || atype == RING_ICE))
+ break; /* already does this or something */
+ if (aclass == OBJ_ARMOUR
+ && (atype == ARM_DRAGON_ARMOUR || atype == ARM_ICE_DRAGON_ARMOUR
+ || atype == ARM_GOLD_DRAGON_ARMOUR))
+ break;
+ proprt[RAP_FIRE] = -1;
+ break;
+ case 6: /* susceptible to cold */
+ if (aclass == OBJ_JEWELLERY
+ && (atype == RING_PROTECTION_FROM_COLD || atype == RING_FIRE
+ || atype == RING_ICE))
+ break; /* already does this or something */
+ if (aclass == OBJ_ARMOUR
+ && (atype == ARM_DRAGON_ARMOUR || atype == ARM_ICE_DRAGON_ARMOUR
+ || atype == ARM_GOLD_DRAGON_ARMOUR))
+ break;
+ proprt[RAP_COLD] = -1;
+ break;
+ case 7: /* speed metabolism */
+ if (aclass == OBJ_JEWELLERY && atype == RING_HUNGER)
+ break; /* already is a ring of hunger */
+ if (aclass == OBJ_JEWELLERY && atype == RING_SUSTENANCE)
+ break; /* already is a ring of sustenance */
+ proprt[RAP_METABOLISM] = 1 + random5(3);
+ break;
+ case 8: /* emits mutagenic radiation - increases magic_contamination */
+ /* property is chance (1 in ...) of increasing magic_contamination */
+ proprt[RAP_MUTAGENIC] = 2 + random5(4);
+ break;
+ }
+
+/*
+ 26 - +to-hit (no wpns)
+ 27 - +to-dam (no wpns)
+ */
+
+finished_curses:
+ if (random5(10) == 0
+ && (aclass != OBJ_ARMOUR
+ || atype != ARM_CLOAK
+ || !cmp_equip_race( item, ISFLAG_ELVEN ))
+ && (aclass != OBJ_ARMOUR
+ || atype != ARM_BOOTS
+ || !cmp_equip_race( item, ISFLAG_ELVEN )
+ && get_armour_ego_type( item ) != SPARM_STEALTH))
+ {
+ power_level++;
+ proprt[RAP_STEALTH] = 10 + random5(70);
+
+ if (random5(4) == 0)
+ {
+ proprt[RAP_STEALTH] = -proprt[RAP_STEALTH] - random5(20);
+ power_level--;
+ }
+ }
+
+ if ((power_level < 2 && random5(5) == 0) || random5(30) == 0)
+ proprt[RAP_CURSED] = 1;
+
+ srand(randstore);
+
+}
+
+int randart_wpn_property( const item_def &item, char prop )
+{
+ FixedVector< char, RA_PROPERTIES > proprt;
+
+ randart_wpn_properties( item, proprt );
+
+ return (proprt[prop]);
+}
+
+const char *randart_name( const item_def &item )
+{
+ ASSERT( item.base_type == OBJ_WEAPONS );
+
+ if (is_unrandom_artefact( item ))
+ {
+ struct unrandart_entry *unrand = seekunrandart( item );
+
+ return (item_ident(item, ISFLAG_KNOW_TYPE) ? unrand->name
+ : unrand->unid_name);
+ }
+
+ free(art_n);
+ art_n = (char *) malloc(sizeof(char) * 80);
+
+ if (art_n == NULL)
+ return ("Malloc Failed Error");
+
+ strcpy(art_n, "");
+
+ // long seed = aclass + adam * (aplus % 100) + atype * aplus2;
+ long seed = calc_seed( item );
+ long randstore = rand();
+ srand( seed );
+
+ if (item_not_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ switch (random5(21))
+ {
+ case 0: strcat(art_n, "brightly glowing "); break;
+ case 1: strcat(art_n, "runed "); break;
+ case 2: strcat(art_n, "smoking "); break;
+ case 3: strcat(art_n, "bloodstained "); break;
+ case 4: strcat(art_n, "twisted "); break;
+ case 5: strcat(art_n, "shimmering "); break;
+ case 6: strcat(art_n, "warped "); break;
+ case 7: strcat(art_n, "crystal "); break;
+ case 8: strcat(art_n, "jewelled "); break;
+ case 9: strcat(art_n, "transparent "); break;
+ case 10: strcat(art_n, "encrusted "); break;
+ case 11: strcat(art_n, "pitted "); break;
+ case 12: strcat(art_n, "slimy "); break;
+ case 13: strcat(art_n, "polished "); break;
+ case 14: strcat(art_n, "fine "); break;
+ case 15: strcat(art_n, "crude "); break;
+ case 16: strcat(art_n, "ancient "); break;
+ case 17: strcat(art_n, "ichor-stained "); break;
+ case 18: strcat(art_n, "faintly glowing "); break;
+ case 19: strcat(art_n, "steaming "); break;
+ case 20: strcat(art_n, "shiny "); break;
+ }
+
+ char st_p3[ITEMNAME_SIZE];
+
+ standard_name_weap( item.sub_type, st_p3 );
+ strcat(art_n, st_p3);
+ srand(randstore);
+ return (art_n);
+ }
+
+ char st_p[ITEMNAME_SIZE];
+
+ if (random5(2) == 0)
+ {
+ standard_name_weap( item.sub_type, st_p );
+ strcat(art_n, st_p);
+ strcat(art_n, rand_wpn_names[random5(390)]);
+ }
+ else
+ {
+ char st_p2[ITEMNAME_SIZE];
+
+ make_name(random5(250), random5(250), random5(250), 3, st_p);
+ standard_name_weap( item.sub_type, st_p2 );
+ strcat(art_n, st_p2);
+
+ if (random5(3) == 0)
+ {
+ strcat(art_n, " of ");
+ strcat(art_n, st_p);
+ }
+ else
+ {
+ strcat(art_n, " \"");
+ strcat(art_n, st_p);
+ strcat(art_n, "\"");
+ }
+ }
+
+ srand(randstore);
+
+ return (art_n);
+}
+
+const char *randart_armour_name( const item_def &item )
+{
+ ASSERT( item.base_type == OBJ_ARMOUR );
+
+ if (is_unrandom_artefact( item ))
+ {
+ struct unrandart_entry *unrand = seekunrandart( item );
+
+ return (item_ident(item, ISFLAG_KNOW_TYPE) ? unrand->name
+ : unrand->unid_name);
+ }
+
+ free(art_n);
+ art_n = (char *) malloc(sizeof(char) * 80);
+
+ if (art_n == NULL)
+ {
+ return ("Malloc Failed Error");
+ }
+
+ strcpy(art_n, "");
+
+ // long seed = aclass + adam * (aplus % 100) + atype * aplus2;
+ long seed = calc_seed( item );
+ long randstore = rand();
+ srand( seed );
+
+ if (item_not_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ switch (random5(21))
+ {
+ case 0: strcat(art_n, "brightly glowing "); break;
+ case 1: strcat(art_n, "runed "); break;
+ case 2: strcat(art_n, "smoking "); break;
+ case 3: strcat(art_n, "bloodstained "); break;
+ case 4: strcat(art_n, "twisted "); break;
+ case 5: strcat(art_n, "shimmering "); break;
+ case 6: strcat(art_n, "warped "); break;
+ case 7: strcat(art_n, "heavily runed "); break;
+ case 8: strcat(art_n, "jeweled "); break;
+ case 9: strcat(art_n, "transparent "); break;
+ case 10: strcat(art_n, "encrusted "); break;
+ case 11: strcat(art_n, "pitted "); break;
+ case 12: strcat(art_n, "slimy "); break;
+ case 13: strcat(art_n, "polished "); break;
+ case 14: strcat(art_n, "fine "); break;
+ case 15: strcat(art_n, "crude "); break;
+ case 16: strcat(art_n, "ancient "); break;
+ case 17: strcat(art_n, "ichor-stained "); break;
+ case 18: strcat(art_n, "faintly glowing "); break;
+ case 19: strcat(art_n, "steaming "); break;
+ case 20: strcat(art_n, "shiny "); break;
+ }
+ char st_p3[ITEMNAME_SIZE];
+
+ standard_name_armour(item, st_p3);
+ strcat(art_n, st_p3);
+ srand(randstore);
+ return (art_n);
+ }
+
+ char st_p[ITEMNAME_SIZE];
+
+ if (random5(2) == 0)
+ {
+ standard_name_armour(item, st_p);
+ strcat(art_n, st_p);
+ strcat(art_n, rand_armour_names[random5(71)]);
+ }
+ else
+ {
+ char st_p2[ITEMNAME_SIZE];
+
+ make_name(random5(250), random5(250), random5(250), 3, st_p);
+ standard_name_armour(item, st_p2);
+ strcat(art_n, st_p2);
+ if (random5(3) == 0)
+ {
+ strcat(art_n, " of ");
+ strcat(art_n, st_p);
+ }
+ else
+ {
+ strcat(art_n, " \"");
+ strcat(art_n, st_p);
+ strcat(art_n, "\"");
+ }
+ }
+
+ srand(randstore);
+
+ return (art_n);
+}
+
+const char *randart_ring_name( const item_def &item )
+{
+ ASSERT( item.base_type == OBJ_JEWELLERY );
+
+ int temp_rand = 0; // probability determination {dlb}
+
+ if (is_unrandom_artefact( item ))
+ {
+ struct unrandart_entry *unrand = seekunrandart( item );
+
+ return (item_ident(item, ISFLAG_KNOW_TYPE) ? unrand->name
+ : unrand->unid_name);
+ }
+
+ char st_p[ITEMNAME_SIZE];
+
+ free(art_n);
+ art_n = (char *) malloc(sizeof(char) * 80);
+
+ if (art_n == NULL)
+ return ("Malloc Failed Error");
+
+ strcpy(art_n, "");
+
+ // long seed = aclass + adam * (aplus % 100) + atype * aplus2;
+ long seed = calc_seed( item );
+ long randstore = rand();
+ srand( seed );
+
+ if (item_not_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ temp_rand = random5(21);
+
+ strcat(art_n, (temp_rand == 0) ? "brightly glowing" :
+ (temp_rand == 1) ? "runed" :
+ (temp_rand == 2) ? "smoking" :
+ (temp_rand == 3) ? "ruby" :
+ (temp_rand == 4) ? "twisted" :
+ (temp_rand == 5) ? "shimmering" :
+ (temp_rand == 6) ? "warped" :
+ (temp_rand == 7) ? "crystal" :
+ (temp_rand == 8) ? "diamond" :
+ (temp_rand == 9) ? "transparent" :
+ (temp_rand == 10) ? "encrusted" :
+ (temp_rand == 11) ? "pitted" :
+ (temp_rand == 12) ? "slimy" :
+ (temp_rand == 13) ? "polished" :
+ (temp_rand == 14) ? "fine" :
+ (temp_rand == 15) ? "crude" :
+ (temp_rand == 16) ? "ancient" :
+ (temp_rand == 17) ? "emerald" :
+ (temp_rand == 18) ? "faintly glowing" :
+ (temp_rand == 19) ? "steaming"
+ : "shiny");
+
+ strcat(art_n, " ");
+ strcat(art_n, (item.sub_type < AMU_RAGE) ? "ring" : "amulet");
+
+ srand(randstore);
+
+ return (art_n);
+ }
+
+ if (random5(5) == 0)
+ {
+ strcat(art_n, (item.sub_type < AMU_RAGE) ? "ring" : "amulet");
+ strcat(art_n, rand_armour_names[random5(71)]);
+ }
+ else
+ {
+ make_name(random5(250), random5(250), random5(250), 3, st_p);
+
+ strcat(art_n, (item.sub_type < AMU_RAGE) ? "ring" : "amulet");
+
+ if (random5(3) == 0)
+ {
+ strcat(art_n, " of ");
+ strcat(art_n, st_p);
+ }
+ else
+ {
+ strcat(art_n, " \"");
+ strcat(art_n, st_p);
+ strcat(art_n, "\"");
+ }
+ }
+
+ srand(randstore);
+
+ return (art_n);
+} // end randart_ring_name()
+
+static struct unrandart_entry *seekunrandart( const item_def &item )
+{
+ int x = 0;
+
+ while (x < NO_UNRANDARTS)
+ {
+ if (unranddata[x].ura_cl == item.base_type
+ && unranddata[x].ura_ty == item.sub_type
+ && unranddata[x].ura_pl == item.plus
+ && unranddata[x].ura_pl2 == item.plus2)
+ {
+ return (&unranddata[x]);
+ }
+
+ x++;
+ }
+
+ return (&unranddata[0]); // Dummy object
+} // end seekunrandart()
+
+int find_unrandart_index(int item_number)
+{
+ int x;
+
+ for(x=0; x < NO_UNRANDARTS; x++)
+ {
+ if (unranddata[x].ura_cl == mitm[item_number].base_type
+ && unranddata[x].ura_ty == mitm[item_number].sub_type
+ && unranddata[x].ura_pl == mitm[item_number].plus
+ && unranddata[x].ura_pl2 == mitm[item_number].plus2)
+ {
+ return (x);
+ }
+ }
+
+ return (-1);
+}
+
+int find_okay_unrandart(unsigned char aclass, unsigned char atype)
+{
+ int x, count;
+ int ret = -1;
+
+ for (x = 0, count = 0; x < NO_UNRANDARTS; x++)
+ {
+ if (unranddata[x].ura_cl == aclass
+ && does_unrandart_exist(x) == 0
+ && (atype == OBJ_RANDOM || unranddata[x].ura_ty == atype))
+ {
+ count++;
+
+ if (random5(count) == 0)
+ ret = x;
+ }
+ }
+
+ return (ret);
+} // end find_okay_unrandart()
+
+// which == 0 (default) gives random fixed artefact.
+// Returns true if successful.
+bool make_item_fixed_artefact( item_def &item, bool in_abyss, int which )
+{
+ bool force = true; // we force any one asked for specifically
+
+ if (!which)
+ {
+ // using old behaviour... try only once. -- bwr
+ force = false;
+
+ which = SPWPN_SINGING_SWORD + random2(12);
+ if (which >= SPWPN_SWORD_OF_CEREBOV)
+ which += 3; // skip over Cerebov's, Dispater's, and Asmodeus' weapons
+ }
+
+ int status = get_unique_item_status( OBJ_WEAPONS, which );
+
+ if ((status == UNIQ_EXISTS
+ || (in_abyss && status == UNIQ_NOT_EXISTS)
+ || (!in_abyss && status == UNIQ_LOST_IN_ABYSS))
+ && !force)
+ {
+ return (false);
+ }
+
+ switch (which)
+ {
+ case SPWPN_SINGING_SWORD:
+ item.base_type = OBJ_WEAPONS;
+ item.sub_type = WPN_LONG_SWORD;
+ item.plus = 7;
+ item.plus2 = 6;
+ break;
+
+ case SPWPN_WRATH_OF_TROG:
+ item.base_type = OBJ_WEAPONS;
+ item.sub_type = WPN_BATTLEAXE;
+ item.plus = 3;
+ item.plus2 = 11;
+ break;
+
+ case SPWPN_SCYTHE_OF_CURSES:
+ item.base_type = OBJ_WEAPONS;
+ item.sub_type = WPN_SCYTHE;
+ item.plus = 13;
+ item.plus2 = 13;
+ break;
+
+ case SPWPN_MACE_OF_VARIABILITY:
+ item.base_type = OBJ_WEAPONS;
+ item.sub_type = WPN_MACE;
+ item.plus = random2(16) - 4;
+ item.plus2 = random2(16) - 4;
+ break;
+
+ case SPWPN_GLAIVE_OF_PRUNE:
+ item.base_type = OBJ_WEAPONS;
+ item.sub_type = WPN_GLAIVE;
+ item.plus = 0;
+ item.plus2 = 12;
+ break;
+
+ case SPWPN_SCEPTRE_OF_TORMENT:
+ item.base_type = OBJ_WEAPONS;
+ item.sub_type = WPN_MACE;
+ item.plus = 7;
+ item.plus2 = 6;
+ break;
+
+ case SPWPN_SWORD_OF_ZONGULDROK:
+ item.base_type = OBJ_WEAPONS;
+ item.sub_type = WPN_LONG_SWORD;
+ item.plus = 9;
+ item.plus2 = 9;
+ break;
+
+ case SPWPN_SWORD_OF_POWER:
+ item.base_type = OBJ_WEAPONS;
+ item.sub_type = WPN_GREAT_SWORD;
+ item.plus = 0; // set on wield
+ item.plus2 = 0; // set on wield
+ break;
+
+ case SPWPN_KNIFE_OF_ACCURACY:
+ item.base_type = OBJ_WEAPONS;
+ item.sub_type = WPN_DAGGER;
+ item.plus = 27;
+ item.plus2 = -1;
+ break;
+
+ case SPWPN_STAFF_OF_OLGREB:
+ item.base_type = OBJ_WEAPONS;
+ item.sub_type = WPN_QUARTERSTAFF;
+ item.plus = 0; // set on wield
+ item.plus2 = 0; // set on wield
+ break;
+
+ case SPWPN_VAMPIRES_TOOTH:
+ item.base_type = OBJ_WEAPONS;
+ item.sub_type = WPN_DAGGER;
+ item.plus = 3;
+ item.plus2 = 4;
+ break;
+
+ case SPWPN_STAFF_OF_WUCAD_MU:
+ item.base_type = OBJ_WEAPONS;
+ item.sub_type = WPN_QUARTERSTAFF;
+ item.plus = 0; // set on wield
+ item.plus2 = 0; // set on wield
+ break;
+
+ case SPWPN_SWORD_OF_CEREBOV:
+ item.base_type = OBJ_WEAPONS;
+ item.sub_type = WPN_GREAT_SWORD;
+ item.plus = 6;
+ item.plus2 = 6;
+ item.colour = YELLOW;
+ do_curse_item( item );
+ break;
+
+ case SPWPN_STAFF_OF_DISPATER:
+ item.base_type = OBJ_WEAPONS;
+ item.sub_type = WPN_QUARTERSTAFF;
+ item.plus = 4;
+ item.plus2 = 4;
+ item.colour = YELLOW;
+ break;
+
+ case SPWPN_SCEPTRE_OF_ASMODEUS:
+ item.base_type = OBJ_WEAPONS;
+ item.sub_type = WPN_QUARTERSTAFF;
+ item.plus = 7;
+ item.plus2 = 7;
+ item.colour = RED;
+ break;
+
+ default:
+ DEBUGSTR( "Trying to create illegal fixed artefact!" );
+ return (false);
+ }
+
+ // If we get here, we've made the artefact
+ item.special = which;
+ item.quantity = 1;
+
+ // Items originally generated in the abyss and not found will be
+ // shifted to "lost in abyss", and will only be found there. -- bwr
+ set_unique_item_status( OBJ_WEAPONS, which, UNIQ_EXISTS );
+
+ return (true);
+}
+
+bool make_item_randart( item_def &item )
+{
+ if (item.base_type != OBJ_WEAPONS
+ && item.base_type != OBJ_ARMOUR
+ && item.base_type != OBJ_JEWELLERY)
+ {
+ return (false);
+ }
+
+ item.flags |= ISFLAG_RANDART;
+ item.special = (random() & RANDART_SEED_MASK);
+
+ return (true);
+}
+
+// void make_item_unrandart( int x, int ura_item )
+bool make_item_unrandart( item_def &item, int unrand_index )
+{
+ item.base_type = unranddata[unrand_index].ura_cl;
+ item.sub_type = unranddata[unrand_index].ura_ty;
+ item.plus = unranddata[unrand_index].ura_pl;
+ item.plus2 = unranddata[unrand_index].ura_pl2;
+ item.colour = unranddata[unrand_index].ura_col;
+
+ item.flags |= ISFLAG_UNRANDART;
+ item.special = unranddata[ unrand_index ].prpty[ RAP_BRAND ];
+
+ if (unranddata[ unrand_index ].prpty[ RAP_CURSED ])
+ do_curse_item( item );
+
+ set_unrandart_exist( unrand_index, 1 );
+
+ return (true);
+} // end make_item_unrandart()
+
+const char *unrandart_descrip( char which_descrip, const item_def &item )
+{
+/* Eventually it would be great to have randomly generated descriptions for
+ randarts. */
+ struct unrandart_entry *unrand = seekunrandart( item );
+
+ return ((which_descrip == 0) ? unrand->spec_descrip1 :
+ (which_descrip == 1) ? unrand->spec_descrip2 :
+ (which_descrip == 2) ? unrand->spec_descrip3 : "Unknown.");
+
+} // end unrandart_descrip()
+
+void standard_name_weap(unsigned char item_typ, char glorg[ITEMNAME_SIZE])
+{
+ strcpy(glorg, (item_typ == WPN_CLUB) ? "club" :
+ (item_typ == WPN_MACE) ? "mace" :
+ (item_typ == WPN_FLAIL) ? "flail" :
+ (item_typ == WPN_KNIFE) ? "knife" :
+ (item_typ == WPN_DAGGER) ? "dagger" :
+ (item_typ == WPN_MORNINGSTAR) ? "morningstar" :
+ (item_typ == WPN_SHORT_SWORD) ? "short sword" :
+ (item_typ == WPN_LONG_SWORD) ? "long sword" :
+ (item_typ == WPN_GREAT_SWORD) ? "great sword" :
+ (item_typ == WPN_SCIMITAR) ? "scimitar" :
+ (item_typ == WPN_HAND_AXE) ? "hand axe" :
+ (item_typ == WPN_BATTLEAXE) ? "battleaxe" :
+ (item_typ == WPN_SPEAR) ? "spear" :
+ (item_typ == WPN_TRIDENT) ? "trident" :
+ (item_typ == WPN_HALBERD) ? "halberd" :
+ (item_typ == WPN_SLING) ? "sling" :
+ (item_typ == WPN_BOW) ? "bow" :
+ (item_typ == WPN_BLOWGUN) ? "blowgun" :
+ (item_typ == WPN_CROSSBOW) ? "crossbow" :
+ (item_typ == WPN_HAND_CROSSBOW) ? "hand crossbow" :
+ (item_typ == WPN_GLAIVE) ? "glaive" :
+ (item_typ == WPN_QUARTERSTAFF) ? "quarterstaff" :
+ (item_typ == WPN_SCYTHE) ? "scythe" :
+ (item_typ == WPN_EVENINGSTAR) ? "eveningstar" :
+ (item_typ == WPN_QUICK_BLADE) ? "quick blade" :
+ (item_typ == WPN_KATANA) ? "katana" :
+ (item_typ == WPN_EXECUTIONERS_AXE) ? "executioner's axe" :
+ (item_typ == WPN_DOUBLE_SWORD) ? "double sword" :
+ (item_typ == WPN_TRIPLE_SWORD) ? "triple sword" :
+ (item_typ == WPN_HAMMER) ? "hammer" :
+ (item_typ == WPN_ANCUS) ? "ancus" :
+ (item_typ == WPN_WHIP) ? "whip" :
+ (item_typ == WPN_SABRE) ? "sabre" :
+ (item_typ == WPN_DEMON_BLADE) ? "demon blade" :
+ (item_typ == WPN_DEMON_WHIP) ? "demon whip" :
+ (item_typ == WPN_DEMON_TRIDENT) ? "demon trident" :
+ (item_typ == WPN_BROAD_AXE) ? "broad axe" :
+ (item_typ == WPN_WAR_AXE) ? "war axe" :
+ (item_typ == WPN_SPIKED_FLAIL) ? "spiked flail" :
+ (item_typ == WPN_GREAT_MACE) ? "great mace" :
+ (item_typ == WPN_GREAT_FLAIL) ? "great flail" :
+ (item_typ == WPN_FALCHION) ? "falchion" :
+
+ (item_typ == WPN_GIANT_CLUB)
+ ? (SysEnv.board_with_nail ? "two-by-four"
+ : "giant club") :
+
+ (item_typ == WPN_GIANT_SPIKED_CLUB)
+ ? (SysEnv.board_with_nail ? "board with nail"
+ : "giant spiked club")
+
+ : "unknown weapon");
+} // end standard_name_weap()
+
+void standard_name_armour( const item_def &item, char glorg[ITEMNAME_SIZE] )
+{
+ short helm_type;
+
+ glorg[0] = '\0';
+
+ switch (item.sub_type)
+ {
+ case ARM_ROBE:
+ strcat(glorg, "robe");
+ break;
+
+ case ARM_LEATHER_ARMOUR:
+ strcat(glorg, "leather armour");
+ break;
+
+ case ARM_RING_MAIL:
+ strcat(glorg, "ring mail");
+ break;
+
+ case ARM_SCALE_MAIL:
+ strcat(glorg, "scale mail");
+ break;
+
+ case ARM_CHAIN_MAIL:
+ strcat(glorg, "chain mail");
+ break;
+
+ case ARM_SPLINT_MAIL:
+ strcat(glorg, "splint mail");
+ break;
+
+ case ARM_BANDED_MAIL:
+ strcat(glorg, "banded mail");
+ break;
+
+ case ARM_PLATE_MAIL:
+ strcat(glorg, "plate mail");
+ break;
+
+ case ARM_SHIELD:
+ strcat(glorg, "shield");
+ break;
+
+ case ARM_CLOAK:
+ strcat(glorg, "cloak");
+ break;
+
+ case ARM_HELMET:
+ if (cmp_helmet_type( item, THELM_HELM )
+ || cmp_helmet_type( item, THELM_HELMET ))
+ {
+ short dhelm = get_helmet_desc( item );
+
+ if (dhelm != THELM_DESC_PLAIN)
+ {
+ strcat( glorg,
+ (dhelm == THELM_DESC_WINGED) ? "winged " :
+ (dhelm == THELM_DESC_HORNED) ? "horned " :
+ (dhelm == THELM_DESC_CRESTED) ? "crested " :
+ (dhelm == THELM_DESC_PLUMED) ? "plumed " :
+ (dhelm == THELM_DESC_SPIKED) ? "spiked " :
+ (dhelm == THELM_DESC_VISORED) ? "visored " :
+ (dhelm == THELM_DESC_JEWELLED) ? "jeweled "
+ : "buggy " );
+ }
+ }
+
+ helm_type = get_helmet_type( item );
+ if (helm_type == THELM_HELM)
+ strcat(glorg, "helm");
+ else if (helm_type == THELM_CAP)
+ strcat(glorg, "cap");
+ else if (helm_type == THELM_WIZARD_HAT)
+ strcat(glorg, "wizard's hat");
+ else
+ strcat(glorg, "helmet");
+ break;
+
+ case ARM_GLOVES:
+ strcat(glorg, "gloves");
+ break;
+
+ case ARM_BOOTS:
+ if (item.plus2 == TBOOT_NAGA_BARDING)
+ strcat(glorg, "naga barding");
+ else if (item.plus2 == TBOOT_CENTAUR_BARDING)
+ strcat(glorg, "centaur barding");
+ else
+ strcat(glorg, "boots");
+ break;
+
+ case ARM_BUCKLER:
+ strcat(glorg, "buckler");
+ break;
+
+ case ARM_LARGE_SHIELD:
+ strcat(glorg, "large shield");
+ break;
+
+ case ARM_DRAGON_HIDE:
+ strcat(glorg, "dragon hide");
+ break;
+
+ case ARM_TROLL_HIDE:
+ strcat(glorg, "troll hide");
+ break;
+
+ case ARM_CRYSTAL_PLATE_MAIL:
+ strcat(glorg, "crystal plate mail");
+ break;
+
+ case ARM_DRAGON_ARMOUR:
+ strcat(glorg, "dragon armour");
+ break;
+
+ case ARM_TROLL_LEATHER_ARMOUR:
+ strcat(glorg, "troll leather armour");
+ break;
+
+ case ARM_ICE_DRAGON_HIDE:
+ strcat(glorg, "ice dragon hide");
+ break;
+
+ case ARM_ICE_DRAGON_ARMOUR:
+ strcat(glorg, "ice dragon armour");
+ break;
+
+ case ARM_STEAM_DRAGON_HIDE:
+ strcat(glorg, "steam dragon hide");
+ break;
+
+ case ARM_STEAM_DRAGON_ARMOUR:
+ strcat(glorg, "steam dragon armour");
+ break;
+
+ case ARM_MOTTLED_DRAGON_HIDE:
+ strcat(glorg, "mottled dragon hide");
+ break;
+
+ case ARM_MOTTLED_DRAGON_ARMOUR:
+ strcat(glorg, "mottled dragon armour");
+ break;
+
+ case ARM_STORM_DRAGON_HIDE:
+ strcat(glorg, "storm dragon hide");
+ break;
+
+ case ARM_STORM_DRAGON_ARMOUR:
+ strcat(glorg, "storm dragon armour");
+ break;
+
+ case ARM_GOLD_DRAGON_HIDE:
+ strcat(glorg, "gold dragon hide");
+ break;
+
+ case ARM_GOLD_DRAGON_ARMOUR:
+ strcat(glorg, "gold dragon armour");
+ break;
+
+ case ARM_ANIMAL_SKIN:
+ strcat(glorg, "animal skin");
+ break;
+
+ case ARM_SWAMP_DRAGON_HIDE:
+ strcat(glorg, "swamp dragon hide");
+ break;
+
+ case ARM_SWAMP_DRAGON_ARMOUR:
+ strcat(glorg, "swamp dragon armour");
+ break;
+ }
+} // end standard_name_armour()
diff --git a/trunk/source/randart.h b/trunk/source/randart.h
new file mode 100644
index 0000000000..df175e0a62
--- /dev/null
+++ b/trunk/source/randart.h
@@ -0,0 +1,111 @@
+/*
+ * File: randart.cc
+ * Summary: Random and unrandom artifact functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef RANDART_H
+#define RANDART_H
+
+#include "enum.h"
+#include "externs.h"
+
+// used in files.cc, newgame.cc, randart.cc {dlb}
+#ifdef USE_NEW_UNRANDS
+#define NO_UNRANDARTS 52
+#else // USE_NEW_UNRANDS
+#define NO_UNRANDARTS 14
+#endif // USE_NEW_UNRANDS
+
+#define RA_PROPERTIES 30
+
+// Reserving the upper bits for later expansion/versioning.
+#define RANDART_SEED_MASK 0x00ffffff
+
+
+bool is_random_artefact( const item_def &item );
+bool is_unrandom_artefact( const item_def &item );
+bool is_fixed_artefact( const item_def &item );
+
+int get_unique_item_status( int base_type, int type );
+void set_unique_item_status( int base_type, int type, int status );
+
+/* ***********************************************************************
+ * called from: itemname
+ * *********************************************************************** */
+const char *randart_armour_name( const item_def &item );
+
+/* ***********************************************************************
+ * called from: itemname
+ * *********************************************************************** */
+const char *randart_name( const item_def &item );
+
+/* ***********************************************************************
+ * called from: itemname
+ * *********************************************************************** */
+const char *randart_ring_name( const item_def &item );
+
+/* ***********************************************************************
+ * called from: describe
+ * *********************************************************************** */
+const char *unrandart_descrip( char which_descrip, const item_def &item );
+
+/* ***********************************************************************
+ * called from: files
+ * *********************************************************************** */
+char does_unrandart_exist(int whun);
+
+
+/* ***********************************************************************
+ * called from: dungeon
+ * *********************************************************************** */
+int find_okay_unrandart(unsigned char aclass, unsigned char atype = OBJ_RANDOM);
+
+
+/* ***********************************************************************
+ * called from: describe - fight - it_use2 - item_use - player
+ * *********************************************************************** */
+void randart_wpn_properties( const item_def &item,
+ FixedVector< char, RA_PROPERTIES > &proprt );
+
+int randart_wpn_property( const item_def &item, char prop );
+
+
+/* ***********************************************************************
+ * called from: dungeon
+ * *********************************************************************** */
+bool make_item_fixed_artefact( item_def &item, bool in_abyss, int which = 0 );
+
+bool make_item_randart( item_def &item );
+bool make_item_unrandart( item_def &item, int unrand_index );
+
+
+/* ***********************************************************************
+ * called from: files - newgame
+ * *********************************************************************** */
+void set_unrandart_exist(int whun, char is_exist);
+
+
+/* ***********************************************************************
+ * called from: itemname
+ * *********************************************************************** */
+void standard_name_armour( const item_def &item, char glorg[ITEMNAME_SIZE] );
+
+
+/* ***********************************************************************
+ * called from: itemname
+ * *********************************************************************** */
+void standard_name_weap(unsigned char item_typ, char glog[ITEMNAME_SIZE]);
+
+
+/* ***********************************************************************
+ * called from: items
+ * *********************************************************************** */
+int find_unrandart_index(int item_index);
+
+#endif
diff --git a/trunk/source/religion.cc b/trunk/source/religion.cc
new file mode 100644
index 0000000000..090ad1533b
--- /dev/null
+++ b/trunk/source/religion.cc
@@ -0,0 +1,2569 @@
+/*
+ * File: religion.cc
+ * Summary: Misc religion related functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ *
+ * <7> 11jan2001 gdl added M. Valvoda's changes to
+ * god_colour() and god_name()
+ * <6> 06-Mar-2000 bwr added penance, gift_timeout,
+ * divine_retribution(), god_speaks()
+ * <5> 11/15/99 cdl Fixed Daniel's yellow Xom patch :)
+ * Xom will sometimes answer prayers
+ * <4> 10/11/99 BCR Added Daniel's yellow Xom patch
+ * <3> 6/13/99 BWR Vehumet book giving code.
+ * <2> 5/20/99 BWR Added screen redraws
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "religion.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "externs.h"
+
+#include "abl-show.h"
+#include "beam.h"
+#include "debug.h"
+#include "decks.h"
+#include "describe.h"
+#include "dungeon.h"
+#include "effects.h"
+#include "food.h"
+#include "it_use2.h"
+#include "itemname.h"
+#include "items.h"
+#include "misc.h"
+#include "monplace.h"
+#include "mutation.h"
+#include "newgame.h"
+#include "ouch.h"
+#include "player.h"
+#include "shopping.h"
+#include "skills2.h"
+#include "spells1.h"
+#include "spells2.h"
+#include "spells3.h"
+#include "spl-cast.h"
+#include "stuff.h"
+
+const char *sacrifice[] = {
+ {" glows silver and disappears."},
+ {" glows a brilliant golden colour and disappears."},
+ {" rots away in an instant."},
+ {" crumbles to dust."},
+ {" is eaten by a bug."}, /* Xom - no sacrifices */
+ {" explodes into nothingness."},
+ {" is consumed in a burst of flame."},
+ {" is consumed in a roaring column of flame."},
+ {" glows faintly for a moment, then is gone."},
+ {" is consumed in a roaring column of flame."},
+ {" glows with a rainbow of weird colours and disappears."},
+ {" evaporates."}
+};
+
+void altar_prayer(void);
+void dec_penance(int god, int val);
+void divine_retribution(int god);
+void inc_penance(int god, int val);
+void inc_penance(int val);
+
+void dec_penance(int god, int val)
+{
+ if (you.penance[god] > 0)
+ {
+ if (you.penance[god] <= val)
+ {
+ simple_god_message(" seems mollified.", god);
+ you.penance[god] = 0;
+ }
+ else
+ you.penance[god] -= val;
+ }
+} // end dec_penance()
+
+void dec_penance(int val)
+{
+ dec_penance(you.religion, val);
+} // end dec_penance()
+
+void inc_penance(int god, int val)
+{
+ if ((int) you.penance[god] + val > 200)
+ you.penance[god] = 200;
+ else
+ you.penance[god] += val;
+} // end inc_penance()
+
+void inc_penance(int val)
+{
+ inc_penance(you.religion, val);
+} // end inc_penance()
+
+static void inc_gift_timeout(int val)
+{
+ if ((int) you.gift_timeout + val > 200)
+ you.gift_timeout = 200;
+ else
+ you.gift_timeout += val;
+} // end inc_gift_timeout()
+
+void pray(void)
+{
+ int temp_rand = 0;
+ unsigned char was_praying = you.duration[DUR_PRAYER];
+ bool success = false;
+
+ if (silenced(you.x_pos, you.y_pos))
+ {
+ mpr("You are unable to make a sound!");
+ return;
+ }
+
+ // all prayers take time
+ you.turn_is_over = 1;
+
+ if (you.religion != GOD_NO_GOD
+ && grd[you.x_pos][you.y_pos] == 179 + you.religion)
+ {
+ altar_prayer();
+ }
+ else if (grd[you.x_pos][you.y_pos] >= 180
+ && grd[you.x_pos][you.y_pos] <= 199)
+ {
+ if (you.species == SP_DEMIGOD)
+ {
+ mpr("Sorry, a being of your status cannot worship here.");
+ return;
+ }
+ god_pitch(grd[you.x_pos][you.y_pos] - 179);
+ return;
+ }
+
+ if (you.religion == GOD_NO_GOD)
+ {
+ strcpy(info, "You spend a moment contemplating the meaning of ");
+
+ if (you.is_undead)
+ strcat(info, "un");
+
+ strcat(info, "life.");
+ mpr(info);
+ return;
+ }
+ else if (you.religion == GOD_XOM)
+ {
+ if (one_chance_in(100))
+ {
+ // Every now and then, Xom listens
+ // This is for flavour, not effect, so praying should not be
+ // encouraged.
+
+ // Xom is nicer to experienced players
+ bool nice = (27 <= random2( 27 + you.experience_level ));
+
+ // and he's not very nice even then
+ int sever = (nice) ? random2( random2( you.experience_level ) )
+ : you.experience_level;
+
+ // bad results are enforced, good are not
+ bool force = !nice;
+
+ Xom_acts( nice, 1 + sever, force );
+ }
+ else
+ mpr("Xom ignores you.");
+
+ return;
+ }
+
+ strcpy( info, "You offer a prayer to " );
+ strcat( info, god_name( you.religion ) );
+ strcat( info, "." );
+ mpr(info);
+
+ you.duration[DUR_PRAYER] = 9 + (random2(you.piety) / 20)
+ + (random2(you.piety) / 20);
+
+ if (player_under_penance())
+ simple_god_message(" demands penance!");
+ else
+ {
+ strcpy(info, god_name(you.religion));
+ strcat(info, " is ");
+
+ strcat(info, (you.piety > 130) ? "exalted by your worship" :
+ (you.piety > 100) ? "extremely pleased with you" :
+ (you.piety > 70) ? "greatly pleased with you" :
+ (you.piety > 40) ? "most pleased with you" :
+ (you.piety > 20) ? "pleased with you" :
+ (you.piety > 5) ? "noncommittal"
+ : "displeased");
+
+ strcat(info, ".");
+ god_speaks(you.religion, info);
+
+ if (you.piety > 130)
+ you.duration[DUR_PRAYER] *= 3;
+ else if (you.piety > 70)
+ you.duration[DUR_PRAYER] *= 2;
+ }
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "piety: %d", you.piety );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ // Consider a gift if we don't have a timeout and weren't
+ // already praying when we prayed.
+ if (!you.penance[you.religion] && !you.gift_timeout && !was_praying)
+ {
+ // Remember to check for water/lava
+ //jmf: "good" god will sometimes feed you (a la Nethack)
+ if (you.religion == GOD_ZIN
+ && you.hunger_state == HS_STARVING
+ && random2(250) <= you.piety)
+ {
+ god_speaks(you.religion, "Your stomach feels content.");
+ set_hunger(6000, true);
+ lose_piety(5 + random2avg(10, 2));
+ inc_gift_timeout(30 + random2avg(10, 2));
+ return;
+ }
+
+ if (you.religion == GOD_NEMELEX_XOBEH
+ && random2(200) <= you.piety
+ && (!you.attribute[ATTR_CARD_TABLE] || one_chance_in(3))
+ && !you.attribute[ATTR_CARD_COUNTDOWN]
+ && grd[you.x_pos][you.y_pos] != DNGN_LAVA
+ && grd[you.x_pos][you.y_pos] != DNGN_DEEP_WATER)
+ {
+ int thing_created = NON_ITEM;
+ unsigned char gift_type = MISC_DECK_OF_TRICKS;
+
+ if (!you.attribute[ATTR_CARD_TABLE])
+ {
+ thing_created = items( 1, OBJ_MISCELLANY,
+ MISC_PORTABLE_ALTAR_OF_NEMELEX,
+ true, 1, 250 );
+
+ if (thing_created != NON_ITEM)
+ you.attribute[ATTR_CARD_TABLE] = 1;
+ }
+ else
+ {
+ if (random2(200) <= you.piety && one_chance_in(4))
+ gift_type = MISC_DECK_OF_SUMMONINGS;
+ if (random2(200) <= you.piety && coinflip())
+ gift_type = MISC_DECK_OF_WONDERS;
+ if (random2(200) <= you.piety && one_chance_in(4))
+ gift_type = MISC_DECK_OF_POWER;
+
+ thing_created = items( 1, OBJ_MISCELLANY, gift_type,
+ true, 1, 250 );
+ }
+
+ if (thing_created != NON_ITEM)
+ {
+ move_item_to_grid( &thing_created, you.x_pos, you.y_pos );
+
+ simple_god_message(" grants you a gift!");
+ more();
+ canned_msg(MSG_SOMETHING_APPEARS);
+
+ you.attribute[ATTR_CARD_COUNTDOWN] = 10;
+ inc_gift_timeout(5 + random2avg(9, 2));
+ }
+ }
+
+ if ((you.religion == GOD_OKAWARU || you.religion == GOD_TROG)
+ && you.piety > 130
+ && random2(you.piety) > 120
+ && grd[you.x_pos][you.y_pos] != DNGN_LAVA
+ && grd[you.x_pos][you.y_pos] != DNGN_DEEP_WATER
+ && one_chance_in(4))
+ {
+ if (you.religion == GOD_TROG
+ || (you.religion == GOD_OKAWARU && coinflip()))
+ {
+ success = acquirement(OBJ_WEAPONS);
+ }
+ else
+ {
+ success = acquirement(OBJ_ARMOUR);
+ }
+
+ if (success)
+ {
+ simple_god_message(" has granted you a gift!");
+ more();
+
+ inc_gift_timeout(30 + random2avg(19, 2));
+ }
+ }
+
+ if (you.religion == GOD_YREDELEMNUL
+ && random2(you.piety) > 80 && one_chance_in(5))
+ {
+ int thing_called = MONS_PROGRAM_BUG; // error trapping {dlb}
+
+ temp_rand = random2(100);
+ thing_called = ((temp_rand > 66) ? MONS_WRAITH : // 33%
+ (temp_rand > 52) ? MONS_WIGHT : // 12%
+ (temp_rand > 40) ? MONS_SPECTRAL_WARRIOR : // 16%
+ (temp_rand > 31) ? MONS_ROTTING_HULK : // 9%
+ (temp_rand > 23) ? MONS_SKELETAL_WARRIOR : // 8%
+ (temp_rand > 16) ? MONS_VAMPIRE : // 7%
+ (temp_rand > 10) ? MONS_GHOUL : // 6%
+ (temp_rand > 4) ? MONS_MUMMY // 6%
+ : MONS_FLAYED_GHOST); // 5%
+
+ if (create_monster( thing_called, 0, BEH_FRIENDLY,
+ you.x_pos, you.y_pos,
+ you.pet_target, 250 ) != -1)
+ {
+ simple_god_message(" grants you an undead servant!");
+ more();
+ inc_gift_timeout(4 + random2avg(7, 2));
+ }
+ }
+
+ if ((you.religion == GOD_KIKUBAAQUDGHA
+ || you.religion == GOD_SIF_MUNA
+ || you.religion == GOD_VEHUMET)
+ && you.piety > 160 && random2(you.piety) > 100)
+ {
+ unsigned int gift = NUM_BOOKS;
+
+ switch (you.religion)
+ {
+ case GOD_KIKUBAAQUDGHA: // gives death books
+ if (!you.had_book[BOOK_NECROMANCY])
+ gift = BOOK_NECROMANCY;
+ else if (!you.had_book[BOOK_DEATH])
+ gift = BOOK_DEATH;
+ else if (!you.had_book[BOOK_UNLIFE])
+ gift = BOOK_UNLIFE;
+ else if (!you.had_book[BOOK_NECRONOMICON])
+ gift = BOOK_NECRONOMICON;
+ break;
+
+ case GOD_SIF_MUNA:
+ gift = OBJ_RANDOM; // Sif Muna - gives any
+ break;
+
+ // Vehumet - gives conj/summ. books (higher skill first)
+ case GOD_VEHUMET:
+ if (!you.had_book[BOOK_CONJURATIONS_I])
+ gift = give_first_conjuration_book();
+ else if (!you.had_book[BOOK_POWER])
+ gift = BOOK_POWER;
+ else if (!you.had_book[BOOK_ANNIHILATIONS])
+ gift = BOOK_ANNIHILATIONS; // conj books
+
+ if (you.skills[SK_CONJURATIONS] < you.skills[SK_SUMMONINGS]
+ || gift == NUM_BOOKS)
+ {
+ if (!you.had_book[BOOK_CALLINGS])
+ gift = BOOK_CALLINGS;
+ else if (!you.had_book[BOOK_SUMMONINGS])
+ gift = BOOK_SUMMONINGS;
+ else if (!you.had_book[BOOK_DEMONOLOGY])
+ gift = BOOK_DEMONOLOGY; // summoning bks
+ }
+ break;
+ }
+
+ if (gift != NUM_BOOKS
+ && (grd[you.x_pos][you.y_pos] != DNGN_LAVA
+ && grd[you.x_pos][you.y_pos] != DNGN_DEEP_WATER))
+ {
+ if (gift == OBJ_RANDOM)
+ success = acquirement(OBJ_BOOKS);
+ else
+ {
+ int thing_created = items(1, OBJ_BOOKS, gift, true, 1, 250);
+ if (thing_created == NON_ITEM)
+ return;
+
+ move_item_to_grid( &thing_created, you.x_pos, you.y_pos );
+
+ if (thing_created != NON_ITEM)
+ success = true;
+ }
+
+ if (success)
+ {
+ simple_god_message(" has granted you a gift!");
+ more();
+
+ inc_gift_timeout(40 + random2avg(19, 2));
+ }
+
+
+ // Vehumet gives books less readily
+ if (you.religion == GOD_VEHUMET && success)
+ inc_gift_timeout(10 + random2(10));
+ } // end of giving book
+ } // end of book gods
+ } // end of gift giving
+} // end pray()
+
+char *god_name( int which_god, bool long_name ) // mv - rewritten
+{
+ static char godname_buff[80];
+
+ switch (which_god)
+ {
+ case GOD_NO_GOD:
+ sprintf(godname_buff, "No God");
+ break;
+ case GOD_ZIN:
+ sprintf(godname_buff, "Zin%s", long_name ? " the Law-Giver" : "");
+ break;
+ case GOD_SHINING_ONE:
+ sprintf(godname_buff, "The Shining One");
+ break;
+ case GOD_KIKUBAAQUDGHA:
+ strcpy(godname_buff, "Kikubaaqudgha");
+ break;
+ case GOD_YREDELEMNUL:
+ sprintf(godname_buff, "Yredelemnul%s", long_name ? " the Dark" : "");
+ break;
+ case GOD_XOM:
+ strcpy(godname_buff, "Xom");
+ if (long_name)
+ {
+ strcat(godname_buff, " ");
+ switch(random2(1000))
+ {
+ default:
+ strcat(godname_buff, "of Chaos");
+ break;
+ case 1:
+ strcat(godname_buff, "the Random");
+ if (coinflip())
+ strcat(godname_buff, coinflip()?"master":" Number God");
+ break;
+ case 2:
+ strcat(godname_buff, "the Tricky");
+ break;
+ case 3:
+ sprintf( godname_buff, "Xom the %sredictible", coinflip() ? "Less-P"
+ : "Unp" );
+ break;
+ case 4:
+ strcat(godname_buff, "of Many Doors");
+ break;
+ case 5:
+ strcat(godname_buff, "the Capricious");
+ break;
+ case 6:
+ strcat(godname_buff, "of ");
+ strcat(godname_buff, coinflip() ? "Bloodstained" : "Enforced");
+ strcat(godname_buff, " Whimsey");
+ break;
+ case 7:
+ strcat(godname_buff, "\"What was your username?\" *clickity-click*");
+ break;
+ case 8:
+ strcat(godname_buff, "of Bone-Dry Humour");
+ break;
+ case 9:
+ strcat(godname_buff, "of ");
+ strcat(godname_buff, coinflip() ? "Malevolent" : "Malicious");
+ strcat(godname_buff, " Giggling");
+ break;
+ case 10:
+ strcat(godname_buff, "the Psycho");
+ strcat(godname_buff, coinflip() ? "tic" : "path");
+ break;
+ case 11:
+ strcat(godname_buff, "of ");
+ switch(random2(5))
+ {
+ case 0: strcat(godname_buff, "Gnomic"); break;
+ case 1: strcat(godname_buff, "Ineffable"); break;
+ case 2: strcat(godname_buff, "Fickle"); break;
+ case 3: strcat(godname_buff, "Swiftly Tilting"); break;
+ case 4: strcat(godname_buff, "Unknown"); break;
+ }
+ strcat(godname_buff, " Intent");
+ if (coinflip())
+ strcat(godname_buff, "ion");
+ break;
+ case 12:
+ sprintf(godname_buff, "The Xom-Meister");
+ if (coinflip())
+ strcat(godname_buff, ", Xom-a-lom-a-ding-dong");
+ else if (coinflip())
+ strcat(godname_buff, ", Xom-o-Rama");
+ else if (coinflip())
+ strcat(godname_buff, ", Xom-Xom-bo-Bom, Banana-Fana-fo-Fom");
+ break;
+ case 13:
+ strcat(godname_buff, "the Begetter of ");
+ strcat(godname_buff, coinflip() ? "Turbulence" : "Discontinuities");
+ break;
+ }
+ }
+ break;
+ case GOD_VEHUMET:
+ strcpy(godname_buff, "Vehumet");
+ break;
+ case GOD_OKAWARU:
+ sprintf(godname_buff, "%sOkawaru", long_name ? "Warmaster " : "");
+ break;
+ case GOD_MAKHLEB:
+ sprintf(godname_buff, "Makhleb%s", long_name ? " the Destroyer" : "");
+ break;
+ case GOD_SIF_MUNA:
+ sprintf(godname_buff, "Sif Muna%s", long_name ? " the Loreminder" : "");
+ break;
+ case GOD_TROG:
+ sprintf(godname_buff, "Trog%s", long_name ? " the Wrathful" : "");
+ break;
+ case GOD_NEMELEX_XOBEH:
+ strcpy(godname_buff, "Nemelex Xobeh");
+ break;
+ case GOD_ELYVILON:
+ sprintf(godname_buff, "Elyvilon%s", long_name ? " the Healer" : "");
+ break;
+ default:
+ sprintf(godname_buff, "The Buggy One (%d)", which_god);
+ }
+
+ return (godname_buff);
+} // end god_name()
+
+void god_speaks( int god, const char *mesg )
+{
+ mpr( mesg, MSGCH_GOD, god );
+} // end god_speaks()
+
+void Xom_acts(bool niceness, int sever, bool force_sever)
+{
+ // niceness = false - bad, true - nice
+ int temp_rand; // probability determination {dlb}
+ bool done_bad = false; // flag to clarify logic {dlb}
+ bool done_good = false; // flag to clarify logic {dlb}
+
+ struct bolt beam;
+
+ if (sever < 1)
+ sever = 1;
+
+ if (!force_sever)
+ sever = random2(sever);
+
+ if (sever == 0)
+ return;
+
+ okay_try_again:
+
+ if (!niceness || one_chance_in(3))
+ {
+ // begin "Bad Things"
+ done_bad = false;
+
+ // this should always be first - it will often be called
+ // deliberately, with a low sever value
+ if (random2(sever) <= 2)
+ {
+ temp_rand = random2(4);
+
+ god_speaks(GOD_XOM,
+ (temp_rand == 0) ? "Xom notices you." :
+ (temp_rand == 1) ? "Xom's attention turns to you for a moment.":
+ (temp_rand == 2) ? "Xom's power touches on you for a moment."
+ : "You hear Xom's maniacal laughter.");
+
+ miscast_effect( SPTYP_RANDOM, 5 + random2(10), random2(100), 0,
+ "the capriciousness of Xom" );
+
+ done_bad = true;
+ }
+ else if (random2(sever) <= 2)
+ {
+ temp_rand = random2(4);
+
+ god_speaks(GOD_XOM,
+ (temp_rand == 0) ? "\"Suffer!\"" :
+ (temp_rand == 1) ? "Xom's malign attention turns to you for a moment." :
+ (temp_rand == 2) ? "Xom's power touches on you for a moment."
+ : "You hear Xom's maniacal laughter.");
+
+ lose_stat(STAT_RANDOM, 1 + random2(3), true);
+
+ done_bad = true;
+ }
+ else if (random2(sever) <= 2)
+ {
+ temp_rand = random2(4);
+
+ god_speaks(GOD_XOM,
+ (temp_rand == 0) ? "Xom notices you." :
+ (temp_rand == 1) ? "Xom's attention turns to you for a moment.":
+ (temp_rand == 2) ? "Xom's power touches on you for a moment."
+ : "You hear Xom's maniacal laughter.");
+
+ miscast_effect( SPTYP_RANDOM, 5 + random2(15), random2(250), 0,
+ "the capriciousness of Xom" );
+
+ done_bad = true;
+ }
+ else if (!you.is_undead && random2(sever) <= 3)
+ {
+ temp_rand = random2(4);
+
+ god_speaks(GOD_XOM,
+ (temp_rand == 0) ? "\"You need some minor adjustments, mortal!\"" :
+ (temp_rand == 1) ? "\"Let me alter your pitiful body.\"" :
+ (temp_rand == 2) ? "Xom's power touches on you for a moment."
+ : "You hear Xom's maniacal laughter.");
+
+ mpr("Your body is suffused with distortional energy.");
+
+ set_hp(1 + random2(you.hp), false);
+ deflate_hp(you.hp_max / 2, true);
+
+ bool failMsg = true;
+ for (int i = 0; i < 4; i++)
+ {
+ if (!mutate(100, failMsg))
+ failMsg = false;
+ }
+
+ done_bad = true;
+ }
+ else if (!you.is_undead && random2(sever) <= 3)
+ {
+ temp_rand = random2(4);
+
+ god_speaks(GOD_XOM,
+ (temp_rand == 0) ? "\"You have displeased me, mortal.\"" :
+ (temp_rand == 1) ? "\"You have grown too confident for your meagre worth.\"" :
+ (temp_rand == 2) ? "Xom's power touches on you for a moment."
+ : "You hear Xom's maniacal laughter.");
+
+ if (one_chance_in(4))
+ {
+ drain_exp();
+ if (random2(sever) > 3)
+ drain_exp();
+ if (random2(sever) > 3)
+ drain_exp();
+ }
+ else
+ {
+ mpr("A wave of agony tears through your body!");
+ set_hp(1 + (you.hp / 2), false);
+ }
+
+ done_bad = true;
+ }
+ else if (random2(sever) <= 3)
+ {
+ temp_rand = random2(4);
+
+ god_speaks(GOD_XOM,
+ (temp_rand == 0) ? "\"Time to have some fun!\"" :
+ (temp_rand == 1) ? "\"Fight to survive, mortal.\"" :
+ (temp_rand == 2) ? "\"Let's see if it's strong enough to survive yet.\""
+ : "You hear Xom's maniacal laughter.");
+
+ if (one_chance_in(4))
+ dancing_weapon(100, true); // nasty, but fun
+ else
+ {
+ create_monster(MONS_NEQOXEC + random2(5), ENCH_ABJ_III,
+ BEH_HOSTILE, you.x_pos, you.y_pos, MHITNOT, 250);
+
+ if (one_chance_in(3))
+ create_monster(MONS_NEQOXEC + random2(5), ENCH_ABJ_III,
+ BEH_HOSTILE, you.x_pos, you.y_pos, MHITNOT, 250);
+
+ if (one_chance_in(4))
+ create_monster(MONS_NEQOXEC + random2(5), ENCH_ABJ_III,
+ BEH_HOSTILE, you.x_pos, you.y_pos, MHITNOT, 250);
+
+ if (one_chance_in(3))
+ create_monster(MONS_HELLION + random2(10), ENCH_ABJ_III,
+ BEH_HOSTILE, you.x_pos, you.y_pos, MHITNOT, 250);
+
+ if (one_chance_in(4))
+ create_monster(MONS_HELLION + random2(10), ENCH_ABJ_III,
+ BEH_HOSTILE, you.x_pos, you.y_pos, MHITNOT, 250);
+ }
+
+ done_bad = true;
+ }
+ else if (you.your_level == 0)
+ {
+ // this should remain the last possible outcome {dlb}
+ temp_rand = random2(3);
+
+ god_speaks(GOD_XOM,
+ (temp_rand == 0) ? "\"You have grown too comfortable in your little world, mortal!\"" :
+ (temp_rand == 1) ? "Xom casts you into the Abyss!"
+ : "The world seems to spin as Xom's maniacal laughter rings in your ears.");
+
+ banished(DNGN_ENTER_ABYSS);
+
+ done_bad = true;
+ }
+ } // end "Bad Things"
+ else
+ {
+ // begin "Good Things"
+ done_good = false;
+
+// Okay, now for the nicer stuff (note: these things are not necessarily nice):
+ if (random2(sever) <= 2)
+ {
+ temp_rand = random2(4);
+
+ god_speaks(GOD_XOM,
+ (temp_rand == 0) ? "\"Go forth and destroy!\"" :
+ (temp_rand == 1) ? "\"Go forth and destroy, mortal!\"" :
+ (temp_rand == 2) ? "Xom grants you a minor favour."
+ : "Xom smiles on you.");
+
+ switch (random2(7))
+ {
+ case 0:
+ potion_effect(POT_HEALING, 150);
+ break;
+ case 1:
+ potion_effect(POT_HEAL_WOUNDS, 150);
+ break;
+ case 2:
+ potion_effect(POT_SPEED, 150);
+ break;
+ case 3:
+ potion_effect(POT_MIGHT, 150);
+ break;
+ case 4:
+ potion_effect(POT_INVISIBILITY, 150);
+ break;
+ case 5:
+ if (one_chance_in(6))
+ potion_effect(POT_EXPERIENCE, 150);
+ else
+ {
+ you.berserk_penalty = NO_BERSERK_PENALTY;
+ potion_effect(POT_BERSERK_RAGE, 150);
+ }
+ break;
+ case 6:
+ you.berserk_penalty = NO_BERSERK_PENALTY;
+ potion_effect(POT_BERSERK_RAGE, 150);
+ break;
+ }
+
+ done_good = true;
+ }
+ else if (random2(sever) <= 4)
+ {
+ temp_rand = random2(3);
+
+ god_speaks(GOD_XOM,
+ (temp_rand == 0) ? "\"Serve the mortal, my children!\"" :
+ (temp_rand == 1) ? "Xom grants you some temporary aid."
+ : "Xom opens a gate.");
+
+ create_monster( MONS_NEQOXEC + random2(5), ENCH_ABJ_III,
+ BEH_FRIENDLY, you.x_pos, you.y_pos,
+ you.pet_target, 250 );
+
+ create_monster( MONS_NEQOXEC + random2(5), ENCH_ABJ_III,
+ BEH_FRIENDLY, you.x_pos, you.y_pos,
+ you.pet_target, 250 );
+
+ if (random2( you.experience_level ) >= 8)
+ {
+ create_monster( MONS_NEQOXEC + random2(5), ENCH_ABJ_III,
+ BEH_FRIENDLY, you.x_pos, you.y_pos,
+ you.pet_target, 250 );
+ }
+
+ if (random2( you.experience_level ) >= 8)
+ {
+ create_monster( MONS_HELLION + random2(10), ENCH_ABJ_III,
+ BEH_FRIENDLY, you.x_pos, you.y_pos,
+ you.pet_target, 250 );
+ }
+
+ if (random2( you.experience_level ) >= 8)
+ {
+ create_monster( MONS_HELLION + random2(10), ENCH_ABJ_III,
+ BEH_FRIENDLY, you.x_pos, you.y_pos,
+ you.pet_target, 250 );
+ }
+
+ done_good = true;
+ }
+ else if (random2(sever) <= 3)
+ {
+ temp_rand = random2(3);
+
+ god_speaks(GOD_XOM,
+ (temp_rand == 0) ? "\"Take this token of my esteem.\"" :
+ (temp_rand == 1) ? "Xom grants you a gift!"
+ : "Xom's generous nature manifests itself.");
+
+ if (grd[you.x_pos][you.y_pos] == DNGN_LAVA
+ || grd[you.x_pos][you.y_pos] == DNGN_DEEP_WATER)
+ {
+ // How unfortunate. I'll bet Xom feels sorry for you.
+ mpr("You hear a splash.");
+ }
+ else
+ {
+ int thing_created = items(1, OBJ_RANDOM, OBJ_RANDOM, true,
+ you.experience_level * 3, 250);
+
+ move_item_to_grid( &thing_created, you.x_pos, you.y_pos );
+
+ if (thing_created != NON_ITEM)
+ {
+ canned_msg(MSG_SOMETHING_APPEARS);
+ more();
+ }
+ }
+
+ done_good = true;
+ }
+ else if (random2(sever) <= 4)
+ {
+ const int demon = (random2(you.experience_level) < 6)
+ ? MONS_WHITE_IMP + random2(5)
+ : MONS_NEQOXEC + random2(5);
+
+ if (create_monster( demon, 0, BEH_FRIENDLY, you.x_pos, you.y_pos,
+ you.pet_target, 250 ) != -1)
+ {
+ temp_rand = random2(3);
+
+ god_speaks(GOD_XOM,
+ (temp_rand == 0) ? "\"Serve the mortal, my child!\"" :
+ (temp_rand == 1) ? "Xom grants you a demonic servitor."
+ : "Xom opens a gate.");
+ }
+
+ done_good = true; // well, for Xom, trying == doing {dlb}
+ }
+ else if (random2(sever) <= 4)
+ {
+ temp_rand = random2(4);
+
+ god_speaks(GOD_XOM,
+ (temp_rand == 0) ? "\"Take this instrument of destruction!\"" :
+ (temp_rand == 1) ? "\"You have earned yourself a gift.\"" :
+ (temp_rand == 2) ? "Xom grants you an implement of death."
+ : "Xom smiles on you.");
+
+ if (acquirement(OBJ_WEAPONS))
+ more();
+
+ done_good = true;
+ }
+ else if (!you.is_undead && random2(sever) <= 5)
+ {
+ temp_rand = random2(4);
+
+ god_speaks(GOD_XOM,
+ (temp_rand == 0) ? "\"You need some minor adjustments, mortal!\"" :
+ (temp_rand == 1) ? "\"Let me alter your pitiful body.\"" :
+ (temp_rand == 2) ? "Xom's power touches on you for a moment."
+ : "You hear Xom's maniacal chuckling.");
+
+ mpr("Your body is suffused with distortional energy.");
+
+ set_hp(1 + random2(you.hp), false);
+ deflate_hp(you.hp_max / 2, true);
+
+ if (coinflip() || !give_cosmetic_mutation())
+ give_good_mutation();
+
+ done_good = true;
+ }
+ else if (random2(sever) <= 2)
+ {
+ // this should remain the last possible outcome {dlb}
+ if (!one_chance_in(8))
+ you.attribute[ATTR_DIVINE_LIGHTNING_PROTECTION] = 1;
+
+ god_speaks(GOD_XOM, "The area is suffused with divine lightning!");
+
+ beam.beam_source = NON_MONSTER;
+ beam.type = SYM_BURST;
+ beam.damage = dice_def( 3, 30 );
+ beam.flavour = BEAM_ELECTRICITY;
+ beam.target_x = you.x_pos;
+ beam.target_y = you.y_pos;
+ strcpy(beam.beam_name, "blast of lightning");
+ beam.colour = LIGHTCYAN;
+ beam.thrower = KILL_YOU; // your explosion
+ beam.aux_source = "Xom's lightning strike";
+ beam.ex_size = 2;
+ beam.isTracer = false;
+
+ explosion(beam);
+
+ if (you.attribute[ATTR_DIVINE_LIGHTNING_PROTECTION] == 1)
+ {
+ mpr("Your divine protection wanes.");
+ you.attribute[ATTR_DIVINE_LIGHTNING_PROTECTION] = 0;
+ }
+
+ done_good = true;
+ }
+ } // end "Good Things"
+
+ if (done_bad || done_good || one_chance_in(4))
+ return;
+ else
+ goto okay_try_again;
+} // end Xom_acts()
+
+void done_good(char thing_done, int pgain)
+{
+ if (you.religion == GOD_NO_GOD)
+ return;
+
+ switch (thing_done)
+ {
+ case GOOD_KILLED_LIVING:
+ switch (you.religion)
+ {
+ case GOD_ELYVILON:
+ simple_god_message(" did not appreciate that!");
+ naughty(NAUGHTY_KILLING, 10);
+ break;
+ case GOD_KIKUBAAQUDGHA:
+ case GOD_YREDELEMNUL:
+ case GOD_VEHUMET:
+ case GOD_OKAWARU:
+ case GOD_MAKHLEB:
+ case GOD_TROG:
+ simple_god_message(" accepts your kill.");
+ if (random2(18 + pgain) > 5)
+ gain_piety(1);
+ break;
+ }
+ break;
+
+ case GOOD_KILLED_UNDEAD:
+ switch (you.religion)
+ {
+ case GOD_ZIN:
+ case GOD_SHINING_ONE:
+ case GOD_VEHUMET:
+ case GOD_MAKHLEB:
+ case GOD_OKAWARU:
+ simple_god_message(" accepts your kill.");
+ if (random2(18 + pgain) > 4)
+ gain_piety(1);
+ break;
+ }
+ break;
+
+ case GOOD_KILLED_DEMON:
+ switch (you.religion)
+ {
+ case GOD_ZIN:
+ case GOD_SHINING_ONE:
+ case GOD_VEHUMET:
+ case GOD_MAKHLEB:
+ case GOD_OKAWARU:
+ simple_god_message(" accepts your kill.");
+ if (random2(18 + pgain) > 3)
+ gain_piety(1);
+ break;
+ }
+ break;
+
+ case GOOD_KILLED_ANGEL_I:
+ case GOOD_KILLED_ANGEL_II:
+ switch (you.religion)
+ {
+ case GOD_ZIN:
+ case GOD_SHINING_ONE:
+ case GOD_ELYVILON:
+ simple_god_message(" did not appreciate that!");
+ naughty(NAUGHTY_ATTACK_HOLY, (you.conf ? 3 : pgain * 3));
+ break;
+ }
+ break;
+
+ case GOOD_KILLED_WIZARD:
+ // hooking this up, but is it too good?
+ // enjoy it while you can -- bwr
+ if (you.religion == GOD_TROG)
+ {
+ simple_god_message( " appreciates your killing of a magic user." );
+
+ if (random2( 5 + pgain ) > 5)
+ gain_piety(1);
+ }
+ break;
+
+ case GOOD_HACKED_CORPSE: // NB - pgain is you.experience_level (maybe)
+ switch (you.religion)
+ {
+ // case GOD_KIKUBAAQUDGHA:
+ case GOD_OKAWARU:
+ case GOD_MAKHLEB:
+ case GOD_TROG:
+ simple_god_message(" accepts your offering.");
+ if (random2(10 + pgain) > 5)
+ gain_piety(1);
+ break;
+
+ // case GOD_ZIN:
+ // case GOD_SHINING_ONE:
+ case GOD_ELYVILON:
+ simple_god_message(" did not appreciate that!");
+
+ naughty(NAUGHTY_BUTCHER, 8);
+ break;
+ }
+ break;
+
+ case GOOD_OFFER_STUFF:
+ simple_god_message(" is pleased with your offering.");
+
+ gain_piety(1);
+ break;
+
+ case GOOD_SLAVES_KILL_LIVING:
+ switch (you.religion)
+ {
+ case GOD_KIKUBAAQUDGHA:
+ case GOD_YREDELEMNUL:
+ case GOD_VEHUMET:
+ simple_god_message(" accepts your slave's kill.");
+
+ if (random2(pgain + 18) > 5)
+ gain_piety(1);
+ break;
+ }
+ break;
+
+ case GOOD_SERVANTS_KILL:
+ switch (you.religion)
+ {
+ case GOD_VEHUMET:
+ case GOD_MAKHLEB:
+ simple_god_message(" accepts your collateral kill.");
+
+ if (random2(pgain + 18) > 5)
+ gain_piety(1);
+ break;
+ }
+ break;
+
+ case GOOD_CARDS:
+ switch (you.religion)
+ {
+ case GOD_NEMELEX_XOBEH:
+ gain_piety(pgain);
+ break;
+ }
+ break;
+ // Offering at altars is covered in another function.
+ }
+} // end done_good()
+
+void gain_piety(char pgn)
+{
+ // check to see if we owe anything first
+ if (you.penance[you.religion] > 0)
+ {
+ dec_penance(pgn);
+ return;
+ }
+ else if (you.gift_timeout > 0)
+ {
+ if (you.gift_timeout > pgn)
+ you.gift_timeout -= pgn;
+ else
+ you.gift_timeout = 0;
+
+ // Slow down piety gain to account for the fact that gifts
+ // no longer have a piety cost for getting them
+ if (!one_chance_in(8))
+ return;
+ }
+
+ // slow down gain at upper levels of piety
+ if (you.piety > 199
+ || (you.piety > 150 && one_chance_in(3))
+ || (you.piety > 100 && one_chance_in(3)))
+ return;
+
+ int old_piety = you.piety;
+
+ you.piety += pgn;
+
+ if (you.piety >= 30 && old_piety < 30)
+ {
+ switch (you.religion)
+ {
+ case GOD_NO_GOD:
+ case GOD_XOM:
+ case GOD_NEMELEX_XOBEH:
+ case GOD_SIF_MUNA:
+ break;
+ default:
+ strcpy(info, "You can now ");
+ strcat(info,
+ (you.religion == GOD_ZIN || you.religion == GOD_SHINING_ONE)
+ ? "repel the undead" :
+
+ (you.religion == GOD_KIKUBAAQUDGHA)
+ ? "recall your undead slaves" :
+ (you.religion == GOD_YREDELEMNUL)
+ ? "animate corpses" :
+ (you.religion == GOD_VEHUMET)
+ ? "gain power from killing in Vehumet's name" :
+ (you.religion == GOD_MAKHLEB)
+ ? "gain power from killing in Makhleb's name" :
+ (you.religion == GOD_OKAWARU)
+ ? "give your great, but temporary, body strength" :
+ (you.religion == GOD_TROG)
+ ? "go berserk at will" :
+ (you.religion == GOD_ELYVILON)
+ ? "call upon Elyvilon for minor healing"
+ // Unknown god
+ : "endure this program bug @30");
+
+ strcat(info, ".");
+ god_speaks(you.religion, info);
+ break;
+ }
+ }
+
+ if (you.piety >= 50 && old_piety < 50)
+ {
+ switch (you.religion)
+ {
+ case GOD_NO_GOD:
+ case GOD_XOM:
+ case GOD_NEMELEX_XOBEH:
+ break;
+ case GOD_KIKUBAAQUDGHA:
+ simple_god_message(" is protecting you from some side-effects of death magic.");
+ break;
+
+ case GOD_VEHUMET:
+ god_speaks(you.religion, "You can call upon Vehumet to aid your destructive magics with prayer.");
+ break;
+
+ default:
+ strcpy(info, "You can now ");
+
+ strcat(info,
+ (you.religion == GOD_ZIN)
+ ? "call upon Zin for minor healing" :
+ (you.religion == GOD_SHINING_ONE)
+ ? "smite your foes" :
+ (you.religion == GOD_YREDELEMNUL)
+ ? "recall your undead slaves" :
+ (you.religion == GOD_OKAWARU)
+ ? "call upon Okawaru for minor healing" :
+ (you.religion == GOD_MAKHLEB)
+ ? "harness Makhleb's destructive might" :
+ (you.religion == GOD_SIF_MUNA)
+ ? "freely open your mind to new spells" :
+ (you.religion == GOD_TROG)
+ ? "give your body great, but temporary, strength" :
+ (you.religion == GOD_ELYVILON)
+ ? "call upon Elyvilon for purification"
+ // Unknown god
+ : "endure this program bug @50");
+
+ strcat(info, ".");
+ god_speaks(you.religion, info);
+ break;
+ }
+ }
+
+ if (you.piety >= 75 && old_piety < 75)
+ {
+ switch (you.religion)
+ {
+ case GOD_NO_GOD:
+ case GOD_XOM:
+ case GOD_OKAWARU:
+ case GOD_NEMELEX_XOBEH:
+ case GOD_SIF_MUNA:
+ case GOD_TROG:
+ break;
+ case GOD_VEHUMET:
+ god_speaks(you.religion,"During prayer you have some protection from summoned creatures.");
+ break;
+
+ default:
+ strcpy(info, "You can now ");
+ strcat(info,
+ (you.religion == GOD_ZIN)
+ ? "call down a plague" :
+ (you.religion == GOD_SHINING_ONE)
+ ? "dispel the undead" :
+ (you.religion == GOD_KIKUBAAQUDGHA)
+ ? "permanently enslave the undead" :
+ (you.religion == GOD_YREDELEMNUL)
+ ? "animate legions of the dead" :
+ (you.religion == GOD_MAKHLEB)
+ ? "summon a lesser servant of Makhleb" :
+ (you.religion == GOD_ELYVILON)
+ ? "call upon Elyvilon for moderate healing"
+ // Unknown god
+ : "endure this program bug @75");
+ strcat(info, ".");
+ god_speaks(you.religion, info);
+ break;
+ }
+ }
+
+ if (you.piety >= 100 && old_piety < 100)
+ {
+ switch (you.religion)
+ {
+ case GOD_NO_GOD:
+ case GOD_XOM:
+ case GOD_OKAWARU:
+ case GOD_NEMELEX_XOBEH:
+ case GOD_KIKUBAAQUDGHA:
+ break;
+ case GOD_SIF_MUNA:
+ simple_god_message
+ (" is protecting you from some side-effects of spellcasting.");
+ break;
+
+ default:
+ strcpy(info, "You can now ");
+
+ strcat(info,
+ (you.religion == GOD_ZIN)
+ ? "utter a Holy Word" :
+ (you.religion == GOD_SHINING_ONE)
+ ? "hurl bolts of divine anger" :
+ (you.religion == GOD_YREDELEMNUL)
+ ? "drain ambient lifeforce" :
+ (you.religion == GOD_VEHUMET)
+ ? "tap ambient magical fields" :
+ (you.religion == GOD_MAKHLEB)
+ ? "hurl Makhleb's greater destruction" :
+ (you.religion == GOD_TROG)
+ ? "haste yourself" :
+ (you.religion == GOD_ELYVILON)
+ ? "call upon Elyvilon to restore your abilities"
+ // Unknown god
+ : "endure this program bug @100");
+
+ strcat(info, ".");
+ god_speaks(you.religion, info);
+ break;
+ }
+ }
+
+ if (you.piety >= 120 && old_piety < 120)
+ {
+ switch (you.religion)
+ {
+ case GOD_NO_GOD:
+ case GOD_XOM:
+ case GOD_NEMELEX_XOBEH:
+ case GOD_VEHUMET:
+ case GOD_SIF_MUNA:
+ case GOD_TROG:
+ break;
+ default:
+ strcpy(info, "You can now ");
+
+ strcat(info,
+ (you.religion == GOD_ZIN)
+ ? "summon a guardian angel" :
+ (you.religion == GOD_SHINING_ONE)
+ ? "summon a divine warrior" :
+ (you.religion == GOD_KIKUBAAQUDGHA)
+ ? "summon an emissary of Death" :
+ (you.religion == GOD_YREDELEMNUL)
+ ? "control the undead" :
+ (you.religion == GOD_OKAWARU)
+ ? "haste yourself" :
+ (you.religion == GOD_MAKHLEB)
+ ? "summon a greater servant of Makhleb" :
+ (you.religion == GOD_ELYVILON)
+ ? "call upon Elyvilon for incredible healing"
+ // Unknown god
+ : "endure this program bug @120");
+
+ strcat(info, ".");
+ god_speaks(you.religion, info);
+ break;
+ }
+ }
+} // end gain_piety()
+
+void naughty(char type_naughty, int naughtiness)
+{
+ int penance = 0;
+ int piety_loss = 0;
+
+ // if you currently worship no deity in particular, exit function {dlb}
+ if (you.religion == GOD_NO_GOD)
+ return;
+
+ switch (you.religion)
+ {
+ case GOD_ZIN:
+ switch (type_naughty)
+ {
+ case NAUGHTY_NECROMANCY:
+ case NAUGHTY_UNHOLY:
+ case NAUGHTY_ATTACK_HOLY:
+ piety_loss = naughtiness;
+ penance = piety_loss * 2;
+ break;
+ case NAUGHTY_ATTACK_FRIEND:
+ piety_loss = naughtiness;
+ penance = piety_loss * 3;
+ break;
+ case NAUGHTY_FRIEND_DIES:
+ piety_loss = naughtiness;
+ break;
+ case NAUGHTY_BUTCHER:
+ piety_loss = naughtiness;
+ if (one_chance_in(3))
+ penance = piety_loss;
+ break;
+ }
+ break;
+
+ case GOD_SHINING_ONE:
+ switch (type_naughty)
+ {
+ case NAUGHTY_NECROMANCY:
+ case NAUGHTY_UNHOLY:
+ case NAUGHTY_ATTACK_HOLY:
+ piety_loss = naughtiness;
+ penance = piety_loss;
+ break;
+ case NAUGHTY_ATTACK_FRIEND:
+ piety_loss = naughtiness;
+ penance = piety_loss * 3;
+ break;
+ case NAUGHTY_FRIEND_DIES:
+ piety_loss = naughtiness;
+ break;
+ case NAUGHTY_BUTCHER:
+ piety_loss = naughtiness;
+ if (one_chance_in(3))
+ penance = piety_loss;
+ break;
+ case NAUGHTY_STABBING:
+ piety_loss = naughtiness;
+ if (one_chance_in(5)) // can be accidental so we're nice here
+ penance = piety_loss;
+ break;
+ case NAUGHTY_POISON:
+ piety_loss = naughtiness;
+ penance = piety_loss * 2;
+ break;
+ }
+ break;
+
+ case GOD_ELYVILON:
+ switch (type_naughty)
+ {
+ case NAUGHTY_NECROMANCY:
+ case NAUGHTY_UNHOLY:
+ case NAUGHTY_ATTACK_HOLY:
+ piety_loss = naughtiness;
+ penance = piety_loss;
+ break;
+ case NAUGHTY_KILLING:
+ piety_loss = naughtiness;
+ penance = piety_loss * 2;
+ break;
+ case NAUGHTY_ATTACK_FRIEND:
+ piety_loss = naughtiness;
+ penance = piety_loss * 3;
+ break;
+ // Healer god gets a bit more upset since you should have
+ // used your healing powers to save them.
+ case NAUGHTY_FRIEND_DIES:
+ piety_loss = naughtiness;
+ penance = piety_loss;
+ break;
+ case NAUGHTY_BUTCHER:
+ piety_loss = naughtiness;
+ if (one_chance_in(3))
+ penance = piety_loss;
+ break;
+ }
+ break;
+
+ case GOD_OKAWARU:
+ switch (type_naughty)
+ {
+ case NAUGHTY_ATTACK_FRIEND:
+ piety_loss = naughtiness;
+ penance = piety_loss * 3;
+ break;
+ case NAUGHTY_FRIEND_DIES:
+ piety_loss = naughtiness;
+ break;
+ }
+ break;
+
+ case GOD_TROG:
+ switch (type_naughty)
+ {
+ case NAUGHTY_SPELLCASTING:
+ piety_loss = naughtiness;
+ // This penance isn't so bad since its much easier to
+ // gain piety with Trog than the other gods in this function.
+ penance = piety_loss * 10;
+ break;
+ }
+ break;
+ }
+
+ // exit function early iff piety loss is zero:
+ if (piety_loss < 1)
+ return;
+
+ // output guilt message:
+ strcpy(info, "You feel");
+
+ strcat(info, (piety_loss == 1) ? " a little " :
+ (piety_loss < 5) ? " " :
+ (piety_loss < 10) ? " very "
+ : " extremely ");
+
+ strcat(info, "guilty.");
+ mpr(info);
+
+ lose_piety(piety_loss);
+
+ if (you.piety < 1)
+ excommunication();
+ else if (penance) // Don't bother unless we're not kicking them out
+ {
+ //jmf: FIXME: add randomness to following message:
+ god_speaks(you.religion, "\"You will pay for your transgression, mortal!\"");
+ inc_penance(penance);
+ }
+} // end naughty()
+
+void lose_piety(char pgn)
+{
+ int old_piety = you.piety;
+
+ if (you.piety - pgn < 0)
+ you.piety = 0;
+ else
+ you.piety -= pgn;
+
+ // Don't bother printing out these messages if you're under
+ // penance, you wouldn't notice since all these abilities
+ // are withheld.
+ if (!player_under_penance() && you.piety != old_piety)
+ {
+ if (you.piety < 120 && old_piety >= 120)
+ {
+ switch (you.religion)
+ {
+ case GOD_NO_GOD:
+ case GOD_XOM:
+ case GOD_NEMELEX_XOBEH:
+ case GOD_VEHUMET:
+ case GOD_SIF_MUNA:
+ case GOD_TROG:
+ break;
+ default:
+ strcpy(info, "You can no longer ");
+
+ strcat(info,
+ (you.religion == GOD_ZIN)
+ ? "summon guardian angels" :
+ (you.religion == GOD_SHINING_ONE)
+ ? "summon divine warriors" :
+ (you.religion == GOD_KIKUBAAQUDGHA)
+ ? "summon Death's emissaries" :
+ (you.religion == GOD_YREDELEMNUL)
+ ? "control undead beings" :
+ (you.religion == GOD_OKAWARU)
+ ? "haste yourself" :
+ (you.religion == GOD_MAKHLEB)
+ ? "summon a greater servant of Makhleb" :
+ (you.religion == GOD_ELYVILON)
+ ? "call upon Elyvilon for incredible healing"
+ // Unknown god
+ : "endure this program bug @120");
+
+ strcat(info, ".");
+ god_speaks(you.religion, info);
+ break;
+ }
+ }
+
+ if (you.piety < 100 && old_piety >= 100)
+ {
+ switch (you.religion)
+ {
+ case GOD_NO_GOD:
+ case GOD_XOM:
+ case GOD_OKAWARU:
+ case GOD_NEMELEX_XOBEH:
+ case GOD_KIKUBAAQUDGHA:
+ break;
+ case GOD_SIF_MUNA:
+ god_speaks(you.religion,"Sif Muna is no longer protecting you from miscast magic.");
+ break;
+ default:
+ strcpy(info, "You can no longer ");
+ strcat(info,
+ (you.religion == GOD_ZIN)
+ ? "utter a Holy Word" :
+ (you.religion == GOD_ELYVILON)
+ ? "call upon Elyvilon to restore your abilities" :
+ (you.religion == GOD_SHINING_ONE)
+ ? "hurl bolts of divine anger" :
+ (you.religion == GOD_YREDELEMNUL)
+ ? "drain ambient life force" :
+ (you.religion == GOD_VEHUMET)
+ ? "tap ambient magical fields" :
+ (you.religion == GOD_MAKHLEB)
+ ? "direct Makhleb's greater destructive powers" :
+ (you.religion == GOD_TROG)
+ ? "haste yourself"
+ // Unknown god
+ : "endure this program bug @100");
+
+ strcat(info, ".");
+ god_speaks(you.religion, info);
+ break;
+ }
+ }
+
+ if (you.piety < 75 && old_piety >= 75)
+ {
+ switch (you.religion)
+ {
+ case GOD_NO_GOD:
+ case GOD_XOM:
+ case GOD_OKAWARU:
+ case GOD_NEMELEX_XOBEH:
+ case GOD_SIF_MUNA:
+ case GOD_TROG:
+ break;
+ case GOD_VEHUMET:
+ simple_god_message(" will longer shield you from summoned creatures.");
+ break;
+ default:
+ strcpy(info, "You can no longer ");
+
+ strcat(info,
+ (you.religion == GOD_ZIN)
+ ? "call down a plague" :
+ (you.religion == GOD_SHINING_ONE)
+ ? "dispel undead" :
+ (you.religion == GOD_KIKUBAAQUDGHA)
+ ? "enslave undead" :
+ (you.religion == GOD_YREDELEMNUL)
+ ? "animate legions of the dead" :
+ (you.religion == GOD_MAKHLEB)
+ ? "summon a servant of Makhleb" :
+ (you.religion == GOD_ELYVILON)
+ ? "call upon Elyvilon for moderate healing"
+ // Unknown god
+ : "endure this program bug @75");
+
+ strcat(info, ".");
+ god_speaks(you.religion, info);
+ break;
+ }
+ }
+
+ if (you.piety < 50 && old_piety >= 50)
+ {
+ switch (you.religion)
+ {
+ case GOD_NO_GOD:
+ case GOD_XOM:
+ case GOD_NEMELEX_XOBEH:
+ break;
+ case GOD_KIKUBAAQUDGHA:
+ simple_god_message(" is no longer shielding you from miscast death magic.");
+ break;
+ case GOD_VEHUMET:
+ simple_god_message(" will no longer aid your destructive magics.");
+ break;
+
+ default:
+ strcpy(info, "You can no longer ");
+
+ strcat(info,
+ (you.religion == GOD_ZIN)
+ ? "call upon Zin for minor healing" :
+ (you.religion == GOD_SHINING_ONE)
+ ? "smite your foes" :
+ (you.religion == GOD_YREDELEMNUL)
+ ? "recall your undead slaves" :
+ (you.religion == GOD_OKAWARU)
+ ? "call upon Okawaru for minor healing" :
+ (you.religion == GOD_MAKHLEB)
+ ? "hurl Makhleb's destruction" :
+ (you.religion == GOD_SIF_MUNA)
+ ? "forget spells at will" :
+ (you.religion == GOD_TROG)
+ ? "give your body great, but temporary, strength" :
+ (you.religion == GOD_ELYVILON)
+ ? "call upon Elyvilon for Purification"
+ // Unknown god
+ : "endure this program bug @50");
+
+ strcat(info, ".");
+ god_speaks(you.religion, info);
+ break;
+ }
+ }
+
+ if (you.piety < 30 && old_piety >= 30)
+ {
+ switch (you.religion)
+ {
+ case GOD_NO_GOD:
+ case GOD_XOM:
+ case GOD_NEMELEX_XOBEH:
+ case GOD_SIF_MUNA:
+ break;
+ default:
+ strcpy(info, "You can no longer ");
+
+ strcat(info,
+ (you.religion == GOD_ZIN || you.religion == GOD_SHINING_ONE)
+ ? "repel the undead" :
+ (you.religion == GOD_KIKUBAAQUDGHA)
+ ? "recall your undead slaves" :
+ (you.religion == GOD_YREDELEMNUL)
+ ? "animate corpses" :
+ (you.religion == GOD_VEHUMET)
+ ? "gain power from killing in Vehumet's name" :
+ (you.religion == GOD_MAKHLEB)
+ ? "gain power from killing in Makhleb's name" :
+ (you.religion == GOD_OKAWARU)
+ ? "give your body great, but temporary, strength" :
+ (you.religion == GOD_TROG)
+ ? "go berserk at will" :
+ (you.religion == GOD_ELYVILON)
+ ? "call upon Elyvilon for minor healing."
+ // Unknown god
+ : "endure this program bug @30");
+
+ strcat(info, ".");
+ god_speaks(you.religion, info);
+ break;
+ }
+ }
+ }
+} // end lose_piety()
+
+void divine_retribution( int god )
+{
+ ASSERT(god != GOD_NO_GOD);
+
+ int loopy = 0; // general purpose loop variable {dlb}
+ int temp_rand = 0; // probability determination {dlb}
+ int punisher = MONS_PROGRAM_BUG;
+ bool success = false;
+ int how_many = 0;
+ int divine_hurt = 0;
+
+ // Good gods don't use divine retribution on their followers, they
+ // will consider it for those who have gone astray however.
+ if (god == you.religion)
+ {
+ if (god == GOD_SHINING_ONE || god == GOD_ZIN || god == GOD_ELYVILON)
+ return;
+ }
+
+ // Just the thought of retribution (getting this far) mollifies the
+ // god by a point... the punishment might reduce penance further.
+ dec_penance( god, 1 + random2(3) );
+
+ switch (god)
+ {
+ case GOD_XOM:
+ {
+ // One in ten chance that Xom might do something good...
+ // but that isn't forced, bad things are though
+ bool nice = one_chance_in(10);
+ bool force = !nice;
+
+ Xom_acts(nice, you.experience_level, force);
+ }
+ break;
+
+ case GOD_SHINING_ONE:
+ // daeva/smiting theme
+ // Doesn't care unless you've gone over to evil/destructive gods
+ if (you.religion == GOD_KIKUBAAQUDGHA || you.religion == GOD_MAKHLEB
+ || you.religion == GOD_YREDELEMNUL || you.religion == GOD_VEHUMET)
+ {
+ if (coinflip())
+ {
+ success = false;
+ how_many = 1 + random2(you.experience_level / 5) + random2(3);
+
+ for (loopy = 0; loopy < how_many; loopy++)
+ {
+ if (create_monster( MONS_DAEVA, 0, BEH_HOSTILE,
+ you.x_pos, you.y_pos, MHITYOU, 250) != -1)
+ {
+ success = true;
+ }
+ }
+
+ if (success)
+ {
+ simple_god_message( " sends the divine host to punish you for your evil ways!", god );
+ }
+ }
+ else
+ {
+ divine_hurt = 10 + random2(10);
+
+ for (loopy = 0; loopy < 5; loopy++)
+ divine_hurt += random2( you.experience_level );
+
+ if (!player_under_penance() && you.piety > random2(400))
+ {
+ strcpy(info, "Mortal, I have averted the wrath of "
+ "the Shining One... this time.");
+ god_speaks(you.religion, info);
+ }
+ else
+ {
+ simple_god_message( " smites you!", god );
+ ouch( divine_hurt, 0, KILLED_BY_TSO_SMITING );
+ dec_penance( GOD_SHINING_ONE, 1 );
+ }
+ }
+ }
+ break;
+
+ case GOD_ZIN:
+ // angels/creeping doom theme:
+ // Doesn't care unless you've gone over to evil
+ if (you.religion == GOD_KIKUBAAQUDGHA || you.religion == GOD_MAKHLEB
+ || you.religion == GOD_YREDELEMNUL || you.religion == GOD_VEHUMET)
+ {
+ if (random2(you.experience_level) > 7 && !one_chance_in(5))
+ {
+ success = false;
+ how_many = 1 + (you.experience_level / 10) + random2(3);
+
+ for (loopy = 0; loopy < how_many; loopy++)
+ {
+ if (create_monster(MONS_ANGEL, 0, BEH_HOSTILE,
+ you.x_pos, you.y_pos, MHITYOU, 250) != -1)
+ {
+ success = true;
+ }
+ }
+
+ if (success)
+ {
+ simple_god_message(" sends the divine host to punish you for your evil ways!", god);
+ }
+ }
+ else
+ {
+ // god_gift == false gives unfriendly
+ summon_swarm( you.experience_level * 20, true, false );
+ simple_god_message(" sends a plague down upon you!", god);
+ }
+ }
+ break;
+
+ case GOD_MAKHLEB:
+ // demonic servant theme
+ if (random2(you.experience_level) > 7 && !one_chance_in(5))
+ {
+ if (create_monster(MONS_EXECUTIONER + random2(5), 0,
+ BEH_HOSTILE, you.x_pos, you.y_pos,
+ MHITYOU, 250) != -1)
+ {
+ simple_god_message(" sends a greater servant after you!",
+ god);
+ }
+ }
+ else
+ {
+ success = false;
+ how_many = 1 + (you.experience_level / 7);
+
+ for (loopy = 0; loopy < how_many; loopy++)
+ {
+ if (create_monster(MONS_NEQOXEC + random2(5), 0, BEH_HOSTILE,
+ you.x_pos, you.y_pos, MHITYOU, 250) != -1)
+ {
+ success = true;
+ }
+ }
+
+ if (success)
+ simple_god_message(" sends minions to punish you.", god);
+ }
+ break;
+
+ case GOD_KIKUBAAQUDGHA:
+ // death/necromancy theme
+ if (random2(you.experience_level) > 7 && !one_chance_in(5))
+ {
+ success = false;
+ how_many = 1 + (you.experience_level / 5) + random2(3);
+
+ for (loopy = 0; loopy < how_many; loopy++)
+ {
+ if (create_monster(MONS_REAPER, 0, BEH_HOSTILE, you.x_pos,
+ you.y_pos, MHITYOU, 250) != -1)
+ {
+ success = true;
+ }
+ }
+
+ if (success)
+ simple_god_message(" unleashes Death upon you!", god);
+ }
+ else
+ {
+ god_speaks(god, (coinflip()) ? "You hear Kikubaaqudgha cackling."
+ : "Kikubaaqudgha's malice focuses upon you.");
+
+ miscast_effect( SPTYP_NECROMANCY, 5 + you.experience_level,
+ random2avg(88, 3), 100, "the malice of Kikubaaqudgha" );
+ }
+ break;
+
+ case GOD_YREDELEMNUL:
+ // undead theme
+ if (random2(you.experience_level) > 4)
+ {
+ success = false;
+ how_many = 1 + random2(1 + (you.experience_level / 5));
+
+ for (loopy = 0; loopy < how_many; loopy++)
+ {
+ temp_rand = random2(100);
+
+ punisher = ((temp_rand > 66) ? MONS_WRAITH : // 33%
+ (temp_rand > 52) ? MONS_WIGHT : // 12%
+ (temp_rand > 40) ? MONS_SPECTRAL_WARRIOR : // 16%
+ (temp_rand > 31) ? MONS_ROTTING_HULK : // 9%
+ (temp_rand > 23) ? MONS_SKELETAL_WARRIOR : // 8%
+ (temp_rand > 16) ? MONS_VAMPIRE : // 7%
+ (temp_rand > 10) ? MONS_GHOUL : // 6%
+ (temp_rand > 4) ? MONS_MUMMY // 6%
+ : MONS_FLAYED_GHOST); // 5%
+
+ if (create_monster( punisher, 0, BEH_HOSTILE,
+ you.x_pos, you.y_pos, MHITYOU, 250 ) != -1)
+ {
+ success = true;
+ }
+ }
+
+ if (success)
+ simple_god_message(" sends a servant to punish you.", god);
+ }
+ else
+ {
+ simple_god_message("'s anger turns toward you for a moment.",
+ god);
+
+ miscast_effect( SPTYP_NECROMANCY, 5 + you.experience_level,
+ random2avg(88, 3), 100, "the anger of Yredelemnul" );
+ }
+ break;
+
+ case GOD_TROG:
+ // physical/berserk theme
+ switch (random2(6))
+ {
+ case 0:
+ case 1:
+ case 2:
+ {
+ // Would be better if berserking monsters were available,
+ // we just send some big bruisers for now.
+ success = false;
+
+ int points = 3 + you.experience_level * 3;
+
+ while (points > 0)
+ {
+ if (points > 20 && coinflip())
+ {
+ // quick reduction for large values
+ punisher = MONS_DEEP_TROLL;
+ points -= 15;
+ break;
+ }
+ else
+ {
+ switch (random2(10))
+ {
+ case 0:
+ punisher = MONS_IRON_TROLL;
+ points -= 10;
+ break;
+
+ case 1:
+ punisher = MONS_ROCK_TROLL;
+ points -= 10;
+ break;
+
+ case 2:
+ punisher = MONS_TROLL;
+ points -= 6;
+ break;
+
+ case 3:
+ case 4:
+ punisher = MONS_MINOTAUR;
+ points -= 3;
+ break;
+
+ case 5:
+ case 6:
+ punisher = MONS_TWO_HEADED_OGRE;
+ points -= 4;
+ break;
+
+ case 7:
+ case 8:
+ case 9:
+ default:
+ punisher = MONS_OGRE;
+ points -= 3;
+ }
+ }
+
+ if (create_monster(punisher, 0, BEH_HOSTILE, you.x_pos,
+ you.y_pos, MHITYOU, 250) != -1)
+ {
+ success = true;
+ }
+ }
+
+ if (success)
+ simple_god_message(" sends monsters to punish you.", god);
+ }
+ break;
+
+ case 3:
+ case 4:
+ simple_god_message("'s voice booms out, \"Feel my wrath!\"", god );
+
+ // A collection of physical effects that might be better
+ // suited to Trog than wild fire magic... messages could
+ // be better here... something more along the lines of apathy
+ // or loss of rage to go with the anti-berzerk effect-- bwr
+ switch (random2(6))
+ {
+ case 0:
+ potion_effect( POT_DECAY, 100 );
+ break;
+
+ case 1:
+ case 2:
+ lose_stat(STAT_STRENGTH, 1 + random2(you.strength / 5), true);
+ break;
+
+ case 3:
+ if (!you.paralysis)
+ {
+ dec_penance(GOD_TROG, 3);
+ mpr( "You suddenly pass out!", MSGCH_WARN );
+ you.paralysis = 2 + random2(6);
+ }
+ break;
+
+ case 4:
+ case 5:
+ if (you.slow < 90)
+ {
+ dec_penance( GOD_TROG, 1 );
+ mpr( "You suddenly feel exhausted!", MSGCH_WARN );
+ you.exhausted = 100;
+ slow_player( 100 );
+ }
+ break;
+ };
+ break;
+ //jmf: returned Trog's old Fire damage
+ // -- actually, this function partially exists to remove that,
+ // we'll leave this effect in, but we'll remove the wild
+ // fire magic. -- bwr
+ case 5:
+ dec_penance(GOD_TROG, 2);
+ mpr( "You feel Trog's fiery rage upon you!", MSGCH_WARN );
+ miscast_effect( SPTYP_FIRE, 8 + you.experience_level,
+ random2avg(98, 3), 100, "the fiery rage of Trog" );
+ break;
+ }
+ break;
+
+ case GOD_OKAWARU:
+ {
+ // warrior theme:
+ success = false;
+ how_many = 1 + (you.experience_level / 5);
+
+ for (loopy = 0; loopy < how_many; loopy++)
+ {
+ temp_rand = random2(100);
+
+ punisher = ((temp_rand > 84) ? MONS_ORC_WARRIOR :
+ (temp_rand > 69) ? MONS_ORC_KNIGHT :
+ (temp_rand > 59) ? MONS_NAGA_WARRIOR :
+ (temp_rand > 49) ? MONS_CENTAUR_WARRIOR :
+ (temp_rand > 39) ? MONS_STONE_GIANT :
+ (temp_rand > 29) ? MONS_FIRE_GIANT :
+ (temp_rand > 19) ? MONS_FROST_GIANT :
+ (temp_rand > 9) ? MONS_CYCLOPS :
+ (temp_rand > 4) ? MONS_HILL_GIANT
+ : MONS_TITAN);
+
+ if (create_monster(punisher, 0, BEH_HOSTILE,
+ you.x_pos, you.y_pos, MHITYOU, 250) != -1)
+ {
+ success = true;
+ }
+ }
+
+ if (success)
+ simple_god_message(" sends forces against you!", god);
+ }
+ break;
+
+ case GOD_VEHUMET:
+ // conjuration and summoning theme
+ simple_god_message("'s vengence finds you.", god);
+ miscast_effect( coinflip() ? SPTYP_CONJURATION : SPTYP_SUMMONING,
+ 8 + you.experience_level, random2avg(98, 3), 100,
+ "the wrath of Vehumet" );
+ break;
+
+ case GOD_NEMELEX_XOBEH:
+ // like Xom, this might actually help the player -- bwr`
+ simple_god_message(" makes you to draw from the Deck of Punishment.",
+ god);
+ deck_of_cards(DECK_OF_PUNISHMENT);
+ break;
+
+ case GOD_SIF_MUNA:
+ simple_god_message("'s wrath finds you.", god);
+ dec_penance(GOD_SIF_MUNA, 1);
+
+ // magic and intelligence theme:
+ switch (random2(10))
+ {
+ case 0:
+ case 1:
+ lose_stat(STAT_INTELLIGENCE, 1 + random2( you.intel / 5 ), true);
+ break;
+
+ case 2:
+ case 3:
+ case 4:
+ confuse_player( 3 + random2(10), false );
+ break;
+
+ case 5:
+ case 6:
+ miscast_effect(SK_DIVINATIONS, 9, 90, 100, "the will of Sif Muna");
+ break;
+
+ case 7:
+ case 8:
+ if (you.magic_points)
+ {
+ dec_mp( 100 ); // this should zero it.
+ mpr( "You suddenly feel drained of magical energy!",
+ MSGCH_WARN );
+ }
+ break;
+
+ case 9:
+ // This will set all the extendable duration spells to
+ // a duration of one round, thus potentially exposing
+ // the player to real danger.
+ antimagic();
+ mpr( "You sense a dampening of magic.", MSGCH_WARN );
+ break;
+ }
+ break;
+
+ case GOD_ELYVILON: // Elyvilon doesn't seek revenge
+ default:
+ return;
+ }
+
+ // Sometimes divine experiences are overwelming...
+ if (one_chance_in(5) && you.experience_level < random2(37))
+ {
+ if (coinflip())
+ confuse_player( 3 + random2(10) );
+ else
+ {
+ if (you.slow < 90)
+ {
+ mpr( "The divine experience leaves you feeling exhausted!",
+ MSGCH_WARN );
+
+ slow_player( random2(20) );
+ }
+ }
+ }
+
+ return;
+} // end divine_retribution()
+
+void excommunication(void)
+{
+ const int old_god = you.religion;
+
+ you.duration[DUR_PRAYER] = 0;
+ you.religion = GOD_NO_GOD;
+ you.piety = 0;
+ redraw_skill( you.your_name, player_title() );
+
+ mpr("You have lost your religion!");
+ more();
+
+ switch (old_god)
+ {
+ case GOD_XOM:
+ Xom_acts( false, (you.experience_level * 2), true );
+ inc_penance( old_god, 50 );
+ break;
+
+ case GOD_KIKUBAAQUDGHA:
+ simple_god_message( " does not appreciate desertion!", old_god );
+ miscast_effect( SPTYP_NECROMANCY, 5 + you.experience_level,
+ random2avg(88, 3), 100, "the malice of Kikubaaqudgha" );
+ inc_penance( old_god, 30 );
+ break;
+
+ case GOD_YREDELEMNUL:
+ simple_god_message( " does not appreciate desertion!", old_god );
+ miscast_effect( SPTYP_NECROMANCY, 5 + you.experience_level,
+ random2avg(88, 3), 100, "the anger of Yredelemnul" );
+ inc_penance( old_god, 30 );
+ break;
+
+ case GOD_VEHUMET:
+ simple_god_message( " does not appreciate desertion!", old_god );
+ miscast_effect( (coinflip() ? SPTYP_CONJURATION : SPTYP_SUMMONING),
+ 8 + you.experience_level, random2avg(98, 3), 100,
+ "the wrath of Vehumet" );
+ inc_penance( old_god, 25 );
+ break;
+
+ case GOD_MAKHLEB:
+ simple_god_message( " does not appreciate desertion!", old_god );
+ miscast_effect( (coinflip() ? SPTYP_CONJURATION : SPTYP_SUMMONING),
+ 8 + you.experience_level, random2avg(98, 3), 100,
+ "the fury of Makhleb" );
+ inc_penance( old_god, 25 );
+ break;
+
+ case GOD_TROG:
+ simple_god_message( " does not appreciate desertion!", old_god );
+
+ // Penence has to come before retribution to prevent "mollify"
+ inc_penance( old_god, 50 );
+ divine_retribution( old_god );
+ break;
+
+ // these like to haunt players for a bit more than the standard
+ case GOD_NEMELEX_XOBEH:
+ case GOD_SIF_MUNA:
+ inc_penance( old_god, 50 );
+ break;
+
+ default:
+ inc_penance( old_god, 25 );
+ break;
+
+ case GOD_ELYVILON: // never seeks revenge
+ break;
+ }
+} // end excommunication()
+
+
+void altar_prayer(void)
+{
+ int i, j, next;
+ char subst_id[4][50];
+ char str_pass[ ITEMNAME_SIZE ];
+
+ for (i = 0; i < 4; i++)
+ {
+ for (j = 0; j < 50; j++)
+ {
+ subst_id[i][j] = 1;
+ }
+ }
+
+ mpr( "You kneel at the altar and pray." );
+
+ if (you.religion == GOD_SHINING_ONE || you.religion == GOD_XOM)
+ return;
+
+ i = igrd[you.x_pos][you.y_pos];
+ while (i != NON_ITEM)
+ {
+ if (one_chance_in(1000))
+ break;
+
+ next = mitm[i].link; // in case we can't get it later.
+
+ const int value = item_value( mitm[i], subst_id, true );
+
+ switch (you.religion)
+ {
+ case GOD_ZIN:
+ case GOD_OKAWARU:
+ case GOD_MAKHLEB:
+ case GOD_NEMELEX_XOBEH:
+ it_name(i, DESC_CAP_THE, str_pass);
+ strcpy(info, str_pass);
+ strcat(info, sacrifice[you.religion - 1]);
+ mpr(info);
+
+ if (mitm[i].base_type == OBJ_CORPSES
+ || random2(value) >= 50
+ || player_under_penance())
+ {
+ gain_piety(1);
+ }
+
+ destroy_item(i);
+ break;
+
+ case GOD_SIF_MUNA:
+ it_name(i, DESC_CAP_THE, str_pass);
+ strcpy(info, str_pass);
+ strcat(info, sacrifice[you.religion - 1]);
+ mpr(info);
+
+ if (value >= 150)
+ gain_piety(1 + random2(3));
+
+ destroy_item(i);
+ break;
+
+ case GOD_KIKUBAAQUDGHA:
+ case GOD_TROG:
+ if (mitm[i].base_type != OBJ_CORPSES)
+ break;
+
+ it_name(i, DESC_CAP_THE, str_pass);
+ strcpy(info, str_pass);
+ strcat(info, sacrifice[you.religion - 1]);
+ mpr(info);
+
+ gain_piety(1);
+ destroy_item(i);
+ break;
+
+ case GOD_ELYVILON:
+ if (mitm[i].base_type != OBJ_WEAPONS
+ && mitm[i].base_type != OBJ_MISSILES)
+ {
+ break;
+ }
+
+ it_name(i, DESC_CAP_THE, str_pass);
+ strcpy(info, str_pass);
+ strcat(info, sacrifice[you.religion - 1]);
+ mpr(info);
+
+ if (random2(value) >= random2(50)
+ || (mitm[i].base_type == OBJ_WEAPONS
+ && (you.piety < 30 || player_under_penance())))
+ {
+ gain_piety(1);
+ }
+
+ destroy_item(i);
+ break;
+
+ default:
+ break;
+ }
+
+ i = next;
+ }
+} // end altar_prayer()
+
+void god_pitch(unsigned char which_god)
+{
+ strcpy(info, "You kneel at the altar of ");
+ strcat(info, god_name(which_god));
+ strcat(info, ".");
+ mpr(info);
+
+ more();
+
+ // Note: using worship we could make some gods not allow followers to
+ // return, or not allow worshippers from other religions. -- bwr
+
+ if ((you.is_undead || you.species == SP_DEMONSPAWN)
+ && (which_god == GOD_ZIN || which_god == GOD_SHINING_ONE
+ || which_god == GOD_ELYVILON))
+ {
+ simple_god_message(" does not accept worship from those such as you!",
+ which_god);
+ return;
+ }
+
+ describe_god( which_god, false );
+
+ snprintf( info, INFO_SIZE, "Do you wish to %sjoin this religion?",
+ (you.worshipped[which_god]) ? "re" : "" );
+
+ if (!yesno( info ))
+ {
+ redraw_screen();
+ return;
+ }
+
+ if (!yesno("Are you sure?"))
+ {
+ redraw_screen();
+ return;
+ }
+
+ redraw_screen();
+ if (you.religion != GOD_NO_GOD)
+ excommunication();
+
+ you.religion = which_god; //jmf: moved up so god_speaks gives right colour
+ you.piety = 15; // to prevent near instant excommunication
+ you.gift_timeout = 0;
+ set_god_ability_slots(); // remove old god's slots, reserve new god's
+
+ snprintf( info, INFO_SIZE, " welcomes you%s!",
+ (you.worshipped[which_god]) ? " back" : "" );
+
+ simple_god_message( info );
+ more();
+
+ if (you.worshipped[you.religion] < 100)
+ you.worshipped[you.religion]++;
+
+ // Currently penance is just zeroed, this could be much more interesting.
+ you.penance[you.religion] = 0;
+
+ if (you.religion == GOD_KIKUBAAQUDGHA || you.religion == GOD_YREDELEMNUL
+ || you.religion == GOD_VEHUMET || you.religion == GOD_MAKHLEB)
+ {
+ // Note: Using worshipped[] we could make this sort of grudge
+ // permanent instead of based off of penance. -- bwr
+ if (you.penance[GOD_SHINING_ONE] > 0)
+ {
+ inc_penance(GOD_SHINING_ONE, 30);
+ god_speaks(GOD_SHINING_ONE, "\"You will pay for your evil ways, mortal!\"");
+ }
+ }
+ redraw_skill( you.your_name, player_title() );
+} // end god_pitch()
+
+void offer_corpse(int corpse)
+{
+ char str_pass[ ITEMNAME_SIZE ];
+ it_name(corpse, DESC_CAP_THE, str_pass);
+ strcpy(info, str_pass);
+ strcat(info, sacrifice[you.religion - 1]);
+ mpr(info);
+
+ done_good(GOOD_HACKED_CORPSE, 10);
+} // end offer_corpse()
+
+//jmf: moved stuff from items::handle_time()
+void handle_god_time(void)
+{
+ if (one_chance_in(100))
+ {
+ // Choose a god randomly from those to whom we owe penance.
+ //
+ // Proof: (By induction)
+ //
+ // 1) n = 1, probability of choosing god is one_chance_in(1)
+ // 2) Asuume true for n = k (ie. prob = 1 / n for all n)
+ // 3) For n = k + 1,
+ //
+ // P:new-found-god = 1 / n (see algorithm)
+ // P:other-gods = (1 - P:new-found-god) * P:god-at-n=k
+ // 1 1
+ // = (1 - -------) * ---
+ // k + 1 k
+ //
+ // k 1
+ // = ----------- * ---
+ // k + 1 k
+ //
+ // 1 1
+ // = ----- = ---
+ // k + 1 n
+ //
+ // Therefore, by induction the probability is uniform. As for
+ // why we do it this way... it requires only one pass and doesn't
+ // require an array.
+
+ int which_god = GOD_NO_GOD;
+ unsigned int count = 0;
+
+ for (int i = GOD_NO_GOD; i < NUM_GODS; i++)
+ {
+ if (you.penance[i])
+ {
+ count++;
+ if (one_chance_in(count))
+ which_god = i;
+ }
+ }
+
+ if (which_god != GOD_NO_GOD)
+ divine_retribution(which_god);
+ }
+
+ // Update the god's opinion of the player
+ if (you.religion != GOD_NO_GOD)
+ {
+ switch (you.religion)
+ {
+ case GOD_XOM:
+ if (one_chance_in(75))
+ Xom_acts(true, you.experience_level + random2(15), true);
+ break;
+
+ case GOD_ZIN: // These gods like long-standing worshippers
+ case GOD_ELYVILON:
+ if (you.piety < 150 && one_chance_in(20))
+ gain_piety(1);
+ break;
+
+ case GOD_SHINING_ONE:
+ if (you.piety < 150 && one_chance_in(15))
+ gain_piety(1);
+ break;
+
+ case GOD_YREDELEMNUL:
+ case GOD_KIKUBAAQUDGHA:
+ case GOD_VEHUMET:
+ if (one_chance_in(17))
+ lose_piety(1);
+ if (you.piety < 1)
+ excommunication();
+ break;
+
+ case GOD_OKAWARU: // These gods accept corpses, so they time-out faster
+ case GOD_TROG:
+ if (one_chance_in(14))
+ lose_piety(1);
+ if (you.piety < 1)
+ excommunication();
+ break;
+
+ case GOD_MAKHLEB:
+ if (one_chance_in(16))
+ lose_piety(1);
+ if (you.piety < 1)
+ excommunication();
+ break;
+
+ case GOD_SIF_MUNA:
+ if (one_chance_in(20))
+ lose_piety(1);
+ if (you.piety < 1)
+ excommunication();
+ break;
+
+ case GOD_NEMELEX_XOBEH: // relatively patient
+ if (one_chance_in(35))
+ lose_piety(1);
+ if (you.attribute[ATTR_CARD_COUNTDOWN] > 0 && coinflip())
+ you.attribute[ATTR_CARD_COUNTDOWN]--;
+ if (you.piety < 1)
+ excommunication();
+ break;
+
+ default:
+ DEBUGSTR("Bad god, no bishop!");
+ }
+ }
+} // end handle_god_time()
+
+// yet another wrapper for mpr() {dlb}:
+void simple_god_message(const char *event, int which_deity)
+{
+ char buff[ INFO_SIZE ];
+
+ if (which_deity == GOD_NO_GOD)
+ which_deity = you.religion;
+
+ snprintf( buff, sizeof(buff), "%s%s", god_name( which_deity ), event );
+
+ god_speaks( which_deity, buff );
+}
+
+char god_colour( char god ) //mv - added
+{
+ switch (god)
+ {
+ case GOD_SHINING_ONE:
+ case GOD_ZIN:
+ case GOD_ELYVILON:
+ case GOD_OKAWARU:
+ return(CYAN);
+
+ case GOD_YREDELEMNUL:
+ case GOD_KIKUBAAQUDGHA:
+ case GOD_MAKHLEB:
+ case GOD_VEHUMET:
+ case GOD_TROG:
+ return(LIGHTRED);
+
+ case GOD_XOM:
+ return(YELLOW);
+
+ case GOD_NEMELEX_XOBEH:
+ return(LIGHTMAGENTA);
+
+ case GOD_SIF_MUNA:
+ return(LIGHTBLUE);
+
+ case GOD_NO_GOD:
+ default:
+ break;
+ }
+
+ return(YELLOW);
+}
diff --git a/trunk/source/religion.h b/trunk/source/religion.h
new file mode 100644
index 0000000000..7ca62f4e03
--- /dev/null
+++ b/trunk/source/religion.h
@@ -0,0 +1,116 @@
+/*
+ * File: religion.cc
+ * Summary: Misc religion related functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef RELIGION_H
+#define RELIGION_H
+
+#include "enum.h"
+
+// last updated 03jun2000 {dlb}
+/* ***********************************************************************
+ * called from: ouch - religion
+ * *********************************************************************** */
+void simple_god_message( const char *event, int which_deity = GOD_NO_GOD );
+
+
+// last updated 11jan2001 {mv}
+/* ***********************************************************************
+ * called from: chardump - overmap - religion
+ * *********************************************************************** */
+char *god_name(int which_god,bool long_name=false); //mv
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: religion - spell
+ * *********************************************************************** */
+void dec_penance(int val);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - decks - fight - player - religion - spell
+ * *********************************************************************** */
+void Xom_acts(bool niceness, int sever, bool force_sever);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: beam - decks - fight - religion
+ * *********************************************************************** */
+void done_good(char thing_done, int pgain);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - religion
+ * *********************************************************************** */
+void excommunication(void);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - religion - spell
+ * *********************************************************************** */
+void gain_piety(char pgn);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: spell - religion
+ * *********************************************************************** */
+void god_speaks( int god, const char *mesg );
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - religion
+ * *********************************************************************** */
+void lose_piety(char pgn);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - beam - fight - it_use2 - item_use - religion - spell -
+ * spellbook - spells4
+ * *********************************************************************** */
+void naughty(char type_naughty, int naughtiness);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: food
+ * *********************************************************************** */
+void offer_corpse(int corpse);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void pray(void);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: items
+ * *********************************************************************** */
+void handle_god_time(void);
+
+// created 5jan2001 {mv}
+/* ***********************************************************************
+ * called from: message, describe
+ * *********************************************************************** */
+char god_colour(char god);
+
+void god_pitch(unsigned char which_god);
+
+#endif
diff --git a/trunk/source/shopping.cc b/trunk/source/shopping.cc
new file mode 100644
index 0000000000..8f3b3cf495
--- /dev/null
+++ b/trunk/source/shopping.cc
@@ -0,0 +1,1597 @@
+/*
+ * File: shopping.cc
+ * Summary: Shop keeper functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <3> Jul 30 00 JDJ in_a_shop uses shoppy instead of i when calling shop_set_id.
+ * <2> Oct 31 99 CDL right justify prices
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "shopping.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#include "externs.h"
+
+#include "describe.h"
+#include "invent.h"
+#include "items.h"
+#include "itemname.h"
+#include "macro.h"
+#include "player.h"
+#include "randart.h"
+#include "spl-book.h"
+#include "stuff.h"
+
+
+static char in_a_shop(char shoppy, char id[4][50]);
+static char more3(void);
+static void purchase( int shop, int item_got, int cost );
+static void shop_init_id(int i, FixedArray < int, 4, 50 > &shop_id);
+static void shop_print(const char *shoppy, char sh_line);
+static void shop_set_ident_type(int i, FixedArray < int, 4, 50 > &shop_id,
+ unsigned char base_type, unsigned char sub_type);
+static void shop_uninit_id(int i, FixedArray < int, 4, 50 > &shop_id);
+
+char in_a_shop( char shoppy, char id[4][50] )
+{
+ // easier to work with {dlb}
+ unsigned int greedy = env.shop[shoppy].greed;
+
+ FixedArray < int, 4, 50 > shop_id;
+ FixedVector < int, 20 > shop_items;
+
+ char st_pass[ ITEMNAME_SIZE ] = "";
+ unsigned int gp_value = 0;
+ char i;
+ unsigned char ft;
+
+#ifdef DOS_TERM
+ char buffer[4800];
+ gettext(1, 1, 80, 25, buffer);
+#endif
+
+#ifdef DOS_TERM
+ window(1, 1, 80, 25);
+#endif
+
+ clrscr();
+ int itty = 0;
+
+ snprintf( info, INFO_SIZE, "Welcome to %s!",
+ shop_name(env.shop[shoppy].x, env.shop[shoppy].y) );
+
+ shop_print(info, 20);
+
+ more3();
+ shop_init_id(shoppy, shop_id);
+
+ /* *************************************
+ THINGS TO DO:
+ Allow inventory
+ Remove id change for antique shops
+ selling?
+ ************************************* */
+
+ save_id(id);
+
+ print_stock:
+ clrscr();
+ itty = igrd[0][5 + shoppy];
+
+ if (itty == NON_ITEM)
+ {
+ shop_print("I'm sorry, my shop is empty now.", 20);
+ more3();
+ goto goodbye;
+ }
+
+ for (i = 1; i < 20; i++)
+ {
+ shop_items[i - 1] = itty;
+
+ if (itty == NON_ITEM) //mitm.link [itty] == NON_ITEM)
+ {
+ shop_items[i - 1] = NON_ITEM;
+ continue;
+ }
+
+ itty = mitm[itty].link;
+ }
+
+ itty = igrd[0][5 + shoppy];
+
+ for (i = 1; i < 18; i++)
+ {
+ gotoxy(1, i);
+
+ textcolor((i % 2) ? WHITE : LIGHTGREY);
+
+ it_name(itty, DESC_NOCAP_A, st_pass);
+ putch(i + 96);
+ cprintf(" - ");
+ cprintf(st_pass);
+
+ gp_value = greedy * item_value( mitm[itty], id );
+ gp_value /= 10;
+ if (gp_value <= 1)
+ gp_value = 1;
+
+ gotoxy(60, i);
+ // cdl - itoa(gp_value, st_pass, 10);
+ snprintf(st_pass, sizeof(st_pass), "%5d", gp_value);
+ cprintf(st_pass);
+ cprintf(" gold");
+ if (mitm[itty].link == NON_ITEM)
+ break;
+
+ itty = mitm[itty].link;
+ }
+
+ textcolor(LIGHTGREY);
+
+ shop_print("Type letter to buy item, x/Esc to leave, ?/* for inventory, v to examine.", 23);
+
+ purchase:
+ snprintf( info, INFO_SIZE, "You have %d gold piece%s.", you.gold,
+ (you.gold == 1) ? "" : "s" );
+
+ textcolor(YELLOW);
+ shop_print(info, 19);
+
+ textcolor(CYAN);
+ shop_print("What would you like to purchase?", 20);
+ textcolor(LIGHTGREY);
+
+ ft = get_ch();
+
+ if (ft == 'x' || ft == ESCAPE)
+ goto goodbye;
+
+ if (ft == 'v')
+ {
+ textcolor(CYAN);
+ shop_print("Examine which item?", 20);
+ textcolor(LIGHTGREY);
+ ft = get_ch();
+
+ // wonder whether this should be recoded to permit uppercase, too? {dlb}
+ if (ft < 'a' || ft > 'z')
+ goto huh;
+
+ ft -= 'a'; // see above comment {dlb}
+
+ if (ft > 18)
+ goto huh;
+
+ if (shop_items[ft] == NON_ITEM)
+ {
+ shop_print("I'm sorry, you seem to be confused.", 20);
+ more3();
+ goto purchase;
+ }
+
+ describe_item( mitm[shop_items[ft]] );
+
+ goto print_stock;
+ }
+
+ if (ft == '?' || ft == '*')
+ {
+ shop_uninit_id(shoppy, shop_id);
+ invent(-1, false);
+ shop_init_id(shoppy, shop_id);
+#ifdef DOS_TERM
+ window(1, 1, 80, 25);
+#endif
+ goto print_stock;
+ }
+
+ if (ft < 'a' || ft > 'z') // see earlier comments re: uppercase {dlb}
+ {
+ huh:
+ shop_print("Huh?", 20);
+ more3();
+ goto purchase;
+ }
+
+ ft -= 'a'; // see earlier comments re: uppercase {dlb}
+
+ if (ft > 18)
+ goto huh;
+
+ if (shop_items[ft] == NON_ITEM)
+ {
+ shop_print("I'm sorry, you seem to be confused.", 20);
+ more3();
+ goto purchase;
+ }
+
+ gp_value = greedy * item_value( mitm[shop_items[ft]], id ) / 10;
+
+ if (gp_value > you.gold)
+ {
+ shop_print("I'm sorry, you don't seem to have enough money.", 20);
+ more3();
+ goto purchase;
+ }
+
+ shop_set_ident_type( shoppy, shop_id, mitm[shop_items[ft]].base_type,
+ mitm[shop_items[ft]].sub_type );
+
+ purchase( shoppy, shop_items[ft], gp_value );
+
+ goto print_stock;
+
+ goodbye:
+ //clear_line();
+ shop_print("Goodbye!", 20);
+ more3();
+
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+ gotoxy(1, 1);
+ cprintf(" ");
+#endif
+
+ shop_uninit_id( shoppy, shop_id );
+ return 0;
+}
+
+void shop_init_id(int i, FixedArray < int, 4, 50 > &shop_id)
+{
+ unsigned char j = 0;
+
+ if (env.shop[i].type != SHOP_WEAPON_ANTIQUE
+ && env.shop[i].type != SHOP_ARMOUR_ANTIQUE
+ && env.shop[i].type != SHOP_GENERAL_ANTIQUE)
+ {
+ for (j = 0; j < 50; j++)
+ {
+ shop_id[ IDTYPE_WANDS ][j] = get_ident_type(OBJ_WANDS, j);
+ set_ident_type(OBJ_WANDS, j, ID_KNOWN_TYPE);
+
+ shop_id[ IDTYPE_SCROLLS ][j] = get_ident_type(OBJ_SCROLLS, j);
+ set_ident_type(OBJ_SCROLLS, j, ID_KNOWN_TYPE);
+
+ shop_id[ IDTYPE_JEWELLERY ][j] = get_ident_type(OBJ_JEWELLERY, j);
+ set_ident_type(OBJ_JEWELLERY, j, ID_KNOWN_TYPE);
+
+ shop_id[ IDTYPE_POTIONS ][j] = get_ident_type(OBJ_POTIONS, j);
+ set_ident_type(OBJ_POTIONS, j, ID_KNOWN_TYPE);
+ }
+ }
+}
+
+void shop_uninit_id(int i, FixedArray < int, 4, 50 > &shop_id)
+{
+ unsigned char j = 0;
+
+ if (env.shop[i].type != SHOP_WEAPON_ANTIQUE
+ && env.shop[i].type != SHOP_ARMOUR_ANTIQUE
+ && env.shop[i].type != SHOP_GENERAL_ANTIQUE)
+ {
+ for (j = 0; j < 50; j++)
+ {
+ set_ident_type( OBJ_WANDS, j, shop_id[ IDTYPE_WANDS ][j], true );
+ set_ident_type( OBJ_SCROLLS, j, shop_id[ IDTYPE_SCROLLS ][j], true );
+ set_ident_type( OBJ_JEWELLERY, j, shop_id[ IDTYPE_JEWELLERY ][j], true );
+ set_ident_type( OBJ_POTIONS, j, shop_id[ IDTYPE_POTIONS ][j], true );
+ }
+ }
+}
+
+void shop_set_ident_type( int i, FixedArray < int, 4, 50 > &shop_id,
+ unsigned char base_type, unsigned char sub_type )
+{
+ if (env.shop[i].type != SHOP_WEAPON_ANTIQUE
+ && env.shop[i].type != SHOP_ARMOUR_ANTIQUE
+ && env.shop[i].type != SHOP_GENERAL_ANTIQUE)
+ {
+ switch (base_type)
+ {
+ case OBJ_WANDS:
+ shop_id[ IDTYPE_WANDS ][sub_type] = ID_KNOWN_TYPE;
+ break;
+ case OBJ_SCROLLS:
+ shop_id[ IDTYPE_SCROLLS ][sub_type] = ID_KNOWN_TYPE;
+ break;
+ case OBJ_JEWELLERY:
+ shop_id[ IDTYPE_JEWELLERY ][sub_type] = ID_KNOWN_TYPE;
+ break;
+ case OBJ_POTIONS:
+ shop_id[ IDTYPE_POTIONS ][sub_type] = ID_KNOWN_TYPE;
+ break;
+ }
+ }
+}
+
+void shop_print( const char *shoppy, char sh_lines )
+{
+ gotoxy(1, sh_lines);
+
+ cprintf(shoppy);
+
+ for (int i = strlen(shoppy); i < 80; i++)
+ cprintf(" ");
+}
+
+char more3(void)
+{
+ char keyin = 0;
+
+ gotoxy(70, 20);
+ cprintf("-more-");
+ keyin = getch();
+ if (keyin == 0)
+ getch();
+ //clear_line();
+ return keyin;
+}
+
+static void purchase( int shop, int item_got, int cost )
+{
+ you.gold -= cost;
+
+ int num = move_item_to_player( item_got, mitm[item_got].quantity, true );
+
+ // Shopkeepers will now place goods you can't carry outside the shop.
+ if (num < mitm[item_got].quantity)
+ {
+ snprintf( info, INFO_SIZE, "I'll put %s outside for you.",
+ (mitm[item_got].quantity == 1) ? "it" :
+ (num > 0) ? "the rest"
+ : "these" );
+
+ shop_print( info, 20 );
+ more3();
+
+ move_item_to_grid( &item_got, env.shop[shop].x, env.shop[shop].y );
+ }
+} // end purchase()
+
+// This probably still needs some work. Rings used to be the only
+// artefacts which had a change in price, and that value corresponds
+// to returning 50 from this function. Good artefacts will probably
+// be returning just over 30 right now. Note that this isn't used
+// as a multiple, its used in the old ring way: 7 * ret is added to
+// the price of the artefact. -- bwr
+int randart_value( const item_def &item )
+{
+ ASSERT( is_random_artefact( item ) );
+
+ int ret = 10;
+ FixedVector< char, RA_PROPERTIES > prop;
+
+ randart_wpn_properties( item, prop );
+
+ // Brands are already accounted for via existing ego checks
+
+ // This should probably be more complex... but this isn't so bad:
+ ret += 3 * prop[ RAP_AC ] + 3 * prop[ RAP_EVASION ]
+ + 3 * prop[ RAP_ACCURACY ] + 3 * prop[ RAP_DAMAGE ]
+ + 6 * prop[ RAP_STRENGTH ] + 6 * prop[ RAP_INTELLIGENCE ]
+ + 6 * prop[ RAP_DEXTERITY ];
+
+ // These resistances have meaningful levels
+ if (prop[ RAP_FIRE ] > 0)
+ ret += 5 + 5 * (prop[ RAP_FIRE ] * prop[ RAP_FIRE ]);
+ else if (prop[ RAP_FIRE ] < 0)
+ ret -= 10;
+
+ if (prop[ RAP_COLD ] > 0)
+ ret += 5 + 5 * (prop[ RAP_COLD ] * prop[ RAP_COLD ]);
+ else if (prop[ RAP_COLD ] < 0)
+ ret -= 10;
+
+ // These normally come alone or in resist/susceptible pairs...
+ // we're making items a bit more expensive if they have both positive.
+ if (prop[ RAP_FIRE ] > 0 && prop[ RAP_COLD ] > 0)
+ ret += 20;
+
+ if (prop[ RAP_NEGATIVE_ENERGY ] > 0)
+ ret += 5 + 5 * (prop[RAP_NEGATIVE_ENERGY] * prop[RAP_NEGATIVE_ENERGY]);
+
+ // only one meaningful level:
+ if (prop[ RAP_POISON ])
+ ret += 15;
+
+ // only one meaningful level (hard to get):
+ if (prop[ RAP_ELECTRICITY ])
+ ret += 30;
+
+ // magic resistance is from 20-120
+ if (prop[ RAP_MAGIC ])
+ ret += 5 + prop[ RAP_MAGIC ] / 10;
+
+ if (prop[ RAP_EYESIGHT ])
+ ret += 10;
+
+ // abilities:
+ if (prop[ RAP_LEVITATE ])
+ ret += 3;
+
+ if (prop[ RAP_BLINK ])
+ ret += 3;
+
+ if (prop[ RAP_CAN_TELEPORT ])
+ ret += 5;
+
+ if (prop[ RAP_BERSERK ])
+ ret += 5;
+
+ if (prop[ RAP_MAPPING ])
+ ret += 15;
+
+ if (prop[ RAP_INVISIBLE ])
+ ret += 20;
+
+ if (prop[ RAP_ANGRY ])
+ ret -= 3;
+
+ if (prop[ RAP_CAUSE_TELEPORTATION ])
+ ret -= 3;
+
+ if (prop[ RAP_NOISES ])
+ ret -= 5;
+
+ if (prop[ RAP_PREVENT_TELEPORTATION ])
+ ret -= 8;
+
+ if (prop[ RAP_PREVENT_SPELLCASTING ])
+ ret -= 10;
+
+ // ranges from 2-5
+ if (prop[ RAP_MUTAGENIC ])
+ ret -= (5 + 3 * prop[ RAP_MUTAGENIC ]);
+
+ // ranges from 1-3
+ if (prop[ RAP_METABOLISM ])
+ ret -= (2 * prop[ RAP_METABOLISM ]);
+
+ return ((ret > 0) ? ret : 0);
+}
+
+unsigned int item_value( item_def item, char id[4][50], bool ident )
+{
+ // Note that we pass item in by value, since we want a local
+ // copy to mangle as neccessary... maybe that should be fixed,
+ // but this function isn't called too often.
+ item.flags = (ident) ? (item.flags | ISFLAG_IDENT_MASK) : (item.flags);
+
+ int valued = 0;
+ int charge_value = 0;
+
+ switch (item.base_type)
+ {
+ case OBJ_WEAPONS:
+ if (is_fixed_artefact( item ))
+ {
+ if (item_ident( item, ISFLAG_KNOW_PROPERTIES ))
+ {
+ switch (item.special)
+ {
+ case SPWPN_SWORD_OF_CEREBOV:
+ valued += 2000;
+ break;
+
+ case SPWPN_SCEPTRE_OF_ASMODEUS:
+ valued += 1500;
+ break;
+
+ case SPWPN_SWORD_OF_ZONGULDROK:
+ valued += 1250;
+ break;
+
+ case SPWPN_SCEPTRE_OF_TORMENT:
+ case SPWPN_SINGING_SWORD:
+ case SPWPN_STAFF_OF_DISPATER:
+ valued += 1200;
+ break;
+
+ case SPWPN_GLAIVE_OF_PRUNE:
+ case SPWPN_WRATH_OF_TROG:
+ valued += 1000;
+ break;
+
+ case SPWPN_SCYTHE_OF_CURSES:
+ valued += 800;
+ break;
+
+ case SPWPN_MACE_OF_VARIABILITY:
+ valued += 700;
+ break;
+
+ default:
+ valued += 1000;
+ break;
+ }
+ break;
+ }
+
+ } // end uniques
+
+ switch (item.sub_type)
+ {
+ case WPN_CLUB:
+ case WPN_KNIFE:
+ valued += 10;
+ break;
+
+ case WPN_SLING:
+ valued += 15;
+ break;
+
+ case WPN_GIANT_CLUB:
+ valued += 17;
+ break;
+
+ case WPN_GIANT_SPIKED_CLUB:
+ valued += 19;
+ break;
+
+ case WPN_DAGGER:
+ valued += 20;
+ break;
+
+ case WPN_WHIP:
+ case WPN_BLOWGUN:
+ valued += 25;
+ break;
+
+ case WPN_HAND_AXE:
+ valued += 28;
+ break;
+
+ case WPN_HAMMER:
+ case WPN_FALCHION:
+ case WPN_MACE:
+ case WPN_SCYTHE:
+ valued += 30;
+ break;
+
+ case WPN_BOW:
+ valued += 31;
+ break;
+
+ case WPN_QUARTERSTAFF:
+ case WPN_SHORT_SWORD:
+ case WPN_SPEAR:
+ valued += 32;
+ break;
+
+ case WPN_FLAIL:
+ valued += 35;
+ break;
+
+ case WPN_ANCUS:
+ case WPN_WAR_AXE:
+ case WPN_MORNINGSTAR:
+ case WPN_SABRE:
+ valued += 40;
+ break;
+
+ case WPN_CROSSBOW:
+ valued += 41;
+ break;
+
+ case WPN_TRIDENT:
+ valued += 42;
+ break;
+
+ case WPN_LONG_SWORD:
+ case WPN_SCIMITAR:
+ valued += 45;
+ break;
+
+ case WPN_SPIKED_FLAIL:
+ valued += 50;
+
+ case WPN_HAND_CROSSBOW:
+ valued += 51;
+ break;
+
+ case WPN_HALBERD:
+ valued += 52;
+ break;
+
+ case WPN_GLAIVE:
+ valued += 55;
+ break;
+
+ case WPN_BROAD_AXE:
+ case WPN_GREAT_SWORD:
+ valued += 60;
+ break;
+
+ case WPN_BATTLEAXE:
+ case WPN_GREAT_MACE:
+ valued += 65;
+ break;
+
+ case WPN_GREAT_FLAIL:
+ valued += 75;
+ break;
+
+ case WPN_EVENINGSTAR:
+ valued += 65;
+ break;
+
+ case WPN_EXECUTIONERS_AXE:
+ valued += 100;
+ break;
+
+ case WPN_DOUBLE_SWORD:
+ valued += 200;
+ break;
+
+ case WPN_DEMON_WHIP:
+ valued += 230;
+ break;
+
+ case WPN_QUICK_BLADE:
+ case WPN_DEMON_TRIDENT:
+ valued += 250;
+ break;
+
+ case WPN_KATANA:
+ case WPN_TRIPLE_SWORD:
+ case WPN_DEMON_BLADE:
+ valued += 300;
+ break;
+ }
+
+ if (item_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ switch (get_weapon_brand( item ))
+ {
+ case SPWPN_NORMAL:
+ default: // randart
+ valued *= 10;
+ break;
+
+ case SPWPN_DRAINING:
+ valued *= 64;
+ break;
+
+ case SPWPN_VAMPIRICISM:
+ valued *= 60;
+ break;
+
+ case SPWPN_DISRUPTION:
+ case SPWPN_FLAME:
+ case SPWPN_FROST:
+ case SPWPN_HOLY_WRATH:
+ case SPWPN_REACHING:
+ valued *= 50;
+ break;
+
+ case SPWPN_SPEED:
+ valued *= 40;
+ break;
+
+ case SPWPN_DISTORTION:
+ case SPWPN_ELECTROCUTION:
+ case SPWPN_PAIN:
+ case SPWPN_VORPAL:
+ valued *= 30;
+ break;
+
+ case SPWPN_FLAMING:
+ case SPWPN_FREEZING:
+ valued *= 25;
+ break;
+
+ case SPWPN_VENOM:
+ valued *= 23;
+ break;
+
+ case SPWPN_ORC_SLAYING:
+ valued *= 21;
+ break;
+
+ case SPWPN_PROTECTION:
+ valued *= 20;
+ break;
+ }
+
+ valued /= 10;
+ }
+
+ // elf/dwarf
+ if (cmp_equip_race( item, ISFLAG_ELVEN )
+ || cmp_equip_race( item, ISFLAG_DWARVEN ))
+ {
+ valued *= 12;
+ valued /= 10;
+ }
+
+ // value was "6" but comment read "orc", so I went with comment {dlb}
+ if (cmp_equip_race( item, ISFLAG_ORCISH ))
+ {
+ valued *= 8;
+ valued /= 10;
+ }
+
+ if (item_ident( item, ISFLAG_KNOW_PLUSES ))
+ {
+ if (item.plus >= 0)
+ {
+ valued += item.plus * 2;
+ valued *= 10 + 3 * item.plus;
+ valued /= 10;
+ }
+
+ if (item.plus2 >= 0)
+ {
+ valued += item.plus2 * 2;
+ valued *= 10 + 3 * item.plus2;
+ valued /= 10;
+ }
+
+ if (item.plus < 0)
+ {
+ valued -= 5;
+ valued += (item.plus * item.plus * item.plus);
+
+ if (valued < 1)
+ valued = 1;
+ //break;
+ }
+
+ if (item.plus2 < 0)
+ {
+ valued -= 5;
+ valued += (item.plus2 * item.plus2 * item.plus2);
+
+ if (valued < 1)
+ valued = 1;
+ }
+ }
+
+ if (is_random_artefact( item ))
+ {
+ if (item_ident( item, ISFLAG_KNOW_TYPE ))
+ valued += (7 * randart_value( item ));
+ else
+ valued += 50;
+ }
+ else if (item_ident( item, ISFLAG_KNOW_TYPE )
+ && !cmp_equip_desc( item, 0 ))
+ {
+ valued += 20;
+ }
+
+ if (item_cursed( item ))
+ {
+ valued *= 6;
+ valued /= 10;
+ }
+ break;
+
+ case OBJ_MISSILES: // ammunition
+ if (item_ident( item, ISFLAG_KNOW_PLUSES ))
+ {
+ // assume not cursed (can they be anyway?)
+ if (item.plus < 0)
+ valued -= 11150;
+
+ if (item.plus >= 0)
+ valued += (item.plus * 2);
+ }
+
+ switch (item.sub_type)
+ {
+ case MI_DART:
+ case MI_LARGE_ROCK:
+ case MI_STONE:
+ case MI_EGGPLANT:
+ valued++;
+ break;
+ case MI_ARROW:
+ case MI_BOLT:
+ case MI_NEEDLE:
+ valued += 2;
+ break;
+ default:
+ // was: cases 6 through 16 with empty strcat()'s 15jan2000 {dlb}
+ valued += 5;
+ break; //strcat(glog , ""); break;
+ }
+ break;
+
+ case OBJ_ARMOUR:
+ switch (item.sub_type)
+ {
+ case ARM_GOLD_DRAGON_ARMOUR:
+ valued += 1600;
+ break;
+
+ case ARM_GOLD_DRAGON_HIDE:
+ valued += 1400;
+ break;
+
+ case ARM_STORM_DRAGON_ARMOUR:
+ valued += 1050;
+ break;
+
+ case ARM_STORM_DRAGON_HIDE:
+ valued += 900;
+ break;
+
+ case ARM_DRAGON_ARMOUR:
+ case ARM_ICE_DRAGON_ARMOUR:
+ valued += 750;
+ break;
+
+ case ARM_SWAMP_DRAGON_ARMOUR:
+ valued += 650;
+ break;
+
+ case ARM_DRAGON_HIDE:
+ case ARM_CRYSTAL_PLATE_MAIL:
+ case ARM_TROLL_LEATHER_ARMOUR:
+ case ARM_ICE_DRAGON_HIDE:
+ valued += 500;
+ break;
+
+ case ARM_MOTTLED_DRAGON_ARMOUR:
+ case ARM_SWAMP_DRAGON_HIDE:
+ valued += 400;
+ break;
+
+ case ARM_STEAM_DRAGON_ARMOUR:
+ case ARM_MOTTLED_DRAGON_HIDE:
+ valued += 300;
+ break;
+
+ case ARM_PLATE_MAIL:
+ valued += 230;
+ break;
+
+ case ARM_STEAM_DRAGON_HIDE:
+ valued += 200;
+ break;
+
+ case ARM_BANDED_MAIL:
+ valued += 150;
+ break;
+
+ case ARM_SPLINT_MAIL:
+ valued += 140;
+ break;
+
+ case ARM_TROLL_HIDE:
+ valued += 130;
+ break;
+
+ case ARM_CHAIN_MAIL:
+ valued += 110;
+ break;
+
+ case ARM_SCALE_MAIL:
+ valued += 83;
+ break;
+
+ case ARM_LARGE_SHIELD:
+ valued += 75;
+ break;
+
+ case ARM_SHIELD:
+ valued += 45;
+ break;
+
+ case ARM_RING_MAIL:
+ valued += 40;
+ break;
+
+ case ARM_HELMET:
+ case ARM_BUCKLER:
+ valued += 25;
+ break;
+
+ case ARM_LEATHER_ARMOUR:
+ valued += 20;
+ break;
+
+ case ARM_BOOTS:
+ valued += 15;
+ break;
+
+ case ARM_GLOVES:
+ valued += 12;
+ break;
+
+ case ARM_CLOAK:
+ valued += 10;
+ break;
+
+ case ARM_ROBE:
+ valued += 7;
+ break;
+
+ case ARM_ANIMAL_SKIN:
+ valued += 3;
+ break;
+ }
+
+ if (item_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ const int sparm = get_armour_ego_type( item );
+ switch (sparm)
+ {
+ case SPARM_NORMAL:
+ default:
+ valued *= 10;
+ break;
+
+ case SPARM_ARCHMAGI:
+ valued *= 100;
+ break;
+
+ case SPARM_DARKNESS:
+ case SPARM_RESISTANCE:
+ valued *= 60;
+ break;
+
+ case SPARM_POSITIVE_ENERGY:
+ valued *= 50;
+ break;
+
+ case SPARM_MAGIC_RESISTANCE:
+ case SPARM_PROTECTION:
+ case SPARM_RUNNING:
+ valued *= 40;
+ break;
+
+ case SPARM_COLD_RESISTANCE:
+ case SPARM_DEXTERITY:
+ case SPARM_FIRE_RESISTANCE:
+ case SPARM_SEE_INVISIBLE:
+ case SPARM_INTELLIGENCE:
+ case SPARM_LEVITATION:
+ case SPARM_PRESERVATION:
+ case SPARM_STEALTH:
+ case SPARM_STRENGTH:
+ valued *= 30;
+ break;
+
+ case SPARM_POISON_RESISTANCE:
+ valued *= 20;
+ break;
+
+ case SPARM_PONDEROUSNESS:
+ valued *= 5;
+ break;
+ }
+
+ valued /= 10;
+ }
+
+ if (cmp_equip_race( item, ISFLAG_ELVEN )
+ || cmp_equip_race( item, ISFLAG_DWARVEN ))
+ {
+ valued *= 12;
+ valued /= 10;
+ }
+
+ if (cmp_equip_race( item, ISFLAG_ORCISH ))
+ {
+ valued *= 8;
+ valued /= 10;
+ }
+
+ if (item_ident( item, ISFLAG_KNOW_PLUSES ))
+ {
+ valued += 5;
+ if (item.plus >= 0)
+ {
+ valued += item.plus * 30;
+ valued *= 10 + 4 * item.plus;
+ valued /= 10;
+ }
+
+ if (item.plus < 0)
+ {
+ valued += item.plus * item.plus * item.plus;
+
+ if (valued < 1)
+ valued = 1;
+ }
+ }
+
+ if (is_random_artefact( item ))
+ {
+ if (item_ident( item, ISFLAG_KNOW_TYPE ))
+ valued += (7 * randart_value( item ));
+ else
+ valued += 50;
+ }
+ else if (item_ident( item, ISFLAG_KNOW_TYPE )
+ && !cmp_equip_desc( item, 0 ))
+ {
+ valued += 20;
+ }
+
+ if (item_cursed( item ))
+ {
+ valued *= 6;
+ valued /= 10;
+ }
+ break;
+
+ case OBJ_WANDS:
+ charge_value = 0;
+ if (id[0][item.sub_type])
+ {
+ switch (item.sub_type)
+ {
+ case WAND_FIREBALL:
+ case WAND_LIGHTNING:
+ valued += 20;
+ charge_value += 5;
+ break;
+
+ case WAND_DRAINING:
+ valued += 20;
+ charge_value += 4;
+ break;
+
+ case WAND_DISINTEGRATION:
+ valued += 17;
+ charge_value += 4;
+ break;
+
+ case WAND_POLYMORPH_OTHER:
+ valued += 15;
+ charge_value += 4;
+ break;
+
+ case WAND_COLD:
+ case WAND_ENSLAVEMENT:
+ case WAND_FIRE:
+ case WAND_HASTING:
+ valued += 15;
+ charge_value += 3;
+ break;
+
+ case WAND_INVISIBILITY:
+ valued += 15;
+ charge_value += 2;
+ break;
+
+ case WAND_RANDOM_EFFECTS:
+ valued += 13;
+ charge_value += 3;
+ break;
+
+ case WAND_PARALYSIS:
+ valued += 12;
+ charge_value += 3;
+ break;
+
+ case WAND_SLOWING:
+ valued += 10;
+ charge_value += 3;
+ break;
+
+ case WAND_CONFUSION:
+ case WAND_DIGGING:
+ case WAND_TELEPORTATION:
+ valued += 10;
+ charge_value += 2;
+ break;
+
+ case WAND_HEALING:
+ valued += 7;
+ charge_value += 3;
+ break;
+
+ case WAND_FLAME:
+ case WAND_FROST:
+ valued += 5;
+ charge_value += 2;
+ break;
+
+ case WAND_MAGIC_DARTS:
+ valued += 3;
+ charge_value++;
+ break;
+
+ default: // no default charge_value ??? 15jan2000 {dlb}
+ valued += 10;
+ break;
+ }
+
+ if (item_ident( item, ISFLAG_KNOW_PLUSES ))
+ {
+ valued += item.plus * charge_value;
+ }
+
+ valued *= 3;
+
+ if (item.plus == 0)
+ valued = 3; // change if wands are rechargeable!
+ }
+ else
+ valued = 35; // = 10;
+ break;
+
+ case OBJ_POTIONS:
+ if (!id[3][item.sub_type])
+ valued += 9;
+ else
+ {
+ switch (item.sub_type)
+ {
+ case POT_EXPERIENCE:
+ valued += 500;
+ break;
+ case POT_GAIN_DEXTERITY:
+ case POT_GAIN_INTELLIGENCE:
+ case POT_GAIN_STRENGTH:
+ valued += 350;
+ break;
+ case POT_CURE_MUTATION:
+ valued += 150;
+ break;
+ case POT_MAGIC:
+ valued += 120;
+ break;
+ case POT_INVISIBILITY:
+ valued += 55;
+ break;
+ case POT_MUTATION:
+ case POT_RESTORE_ABILITIES:
+ valued += 50;
+ break;
+ case POT_BERSERK_RAGE:
+ case POT_HEAL_WOUNDS:
+ valued += 30;
+ break;
+ case POT_MIGHT:
+ case POT_SPEED:
+ valued += 25;
+ break;
+ case POT_HEALING:
+ case POT_LEVITATION:
+ valued += 20;
+ break;
+ case POT_PORRIDGE:
+ valued += 10;
+ break;
+ case POT_CONFUSION:
+ case POT_DECAY:
+ case POT_DEGENERATION:
+ case POT_PARALYSIS:
+ case POT_POISON:
+ case POT_SLOWING:
+ case POT_STRONG_POISON:
+ case POT_WATER:
+ valued++;
+ break;
+ }
+ }
+ break;
+
+ case OBJ_FOOD:
+ switch (item.sub_type)
+ {
+ case FOOD_ROYAL_JELLY:
+ valued = 120;
+ break;
+
+ case FOOD_MEAT_RATION:
+ case FOOD_BREAD_RATION:
+ valued = 40;
+ break;
+
+ case FOOD_HONEYCOMB:
+ valued = 25;
+ break;
+
+ case FOOD_BEEF_JERKY:
+ case FOOD_PIZZA:
+ valued = 18;
+ break;
+
+ case FOOD_CHEESE:
+ case FOOD_SAUSAGE:
+ valued = 15;
+ break;
+
+ case FOOD_LEMON:
+ case FOOD_ORANGE:
+ case FOOD_BANANA:
+ valued = 12;
+ break;
+
+ case FOOD_APPLE:
+ case FOOD_APRICOT:
+ case FOOD_PEAR:
+ valued = 8;
+ break;
+
+ case FOOD_CHOKO:
+ case FOOD_LYCHEE:
+ case FOOD_RAMBUTAN:
+ case FOOD_SNOZZCUMBER:
+ case FOOD_CHUNK:
+ valued = 4;
+ break;
+
+ case FOOD_STRAWBERRY:
+ case FOOD_GRAPE:
+ case FOOD_SULTANA:
+ valued = 1;
+ break;
+ }
+ break;
+
+ case OBJ_SCROLLS:
+ if (!id[1][item.sub_type])
+ valued += 10;
+ else
+ switch (item.sub_type)
+ {
+ case SCR_ACQUIREMENT:
+ valued += 520;
+ break;
+ case SCR_ENCHANT_WEAPON_III:
+ case SCR_VORPALISE_WEAPON:
+ valued += 200;
+ break;
+ case SCR_SUMMONING:
+ valued += 95;
+ break;
+ case SCR_TORMENT:
+ valued += 75;
+ break;
+ case SCR_ENCHANT_WEAPON_II:
+ valued += 55;
+ break;
+ case SCR_RECHARGING:
+ valued += 50;
+ break;
+ case SCR_ENCHANT_ARMOUR:
+ case SCR_ENCHANT_WEAPON_I:
+ valued += 48;
+ break;
+ case SCR_FEAR:
+ valued += 45;
+ break;
+ case SCR_MAGIC_MAPPING:
+ valued += 35;
+ break;
+ case SCR_BLINKING:
+ case SCR_REMOVE_CURSE:
+ case SCR_TELEPORTATION:
+ valued += 30;
+ break;
+ case SCR_DETECT_CURSE:
+ case SCR_IDENTIFY:
+ valued += 20;
+ break;
+ case SCR_NOISE:
+ case SCR_RANDOM_USELESSNESS:
+ valued += 2;
+ break;
+ case SCR_CURSE_ARMOUR:
+ case SCR_CURSE_WEAPON:
+ case SCR_FORGETFULNESS:
+ case SCR_PAPER:
+ case SCR_IMMOLATION:
+ valued++;
+ break;
+ }
+ break;
+
+ case OBJ_JEWELLERY:
+ if (!id[2][item.sub_type])
+ valued += 50;
+
+ if (item_cursed( item ))
+ valued -= 10;
+
+ if (id[2][item.sub_type] > 0)
+ {
+ if (item_ident( item, ISFLAG_KNOW_PLUSES )
+ && (item.sub_type == RING_PROTECTION
+ || item.sub_type == RING_STRENGTH
+ || item.sub_type == RING_EVASION
+ || item.sub_type == RING_DEXTERITY
+ || item.sub_type == RING_INTELLIGENCE
+ || item.sub_type == RING_SLAYING))
+ {
+ if (item.plus > 0)
+ valued += 10 * item.plus;
+
+ if (item.sub_type == RING_SLAYING && item.plus2 > 0)
+ valued += 10 * item.plus;
+ }
+
+ switch (item.sub_type)
+ {
+ case RING_INVISIBILITY:
+ valued += 100;
+ break;
+ case RING_REGENERATION:
+ valued += 75;
+ break;
+ case RING_FIRE:
+ case RING_ICE:
+ valued += 62;
+ break;
+ case RING_LIFE_PROTECTION:
+ valued += 60;
+ break;
+ case RING_TELEPORT_CONTROL:
+ valued += 42;
+ break;
+ case RING_MAGICAL_POWER:
+ case RING_PROTECTION_FROM_MAGIC:
+ valued += 40;
+ break;
+ case RING_WIZARDRY:
+ valued += 35;
+ break;
+ case RING_LEVITATION:
+ case RING_POISON_RESISTANCE:
+ case RING_PROTECTION_FROM_COLD:
+ case RING_PROTECTION_FROM_FIRE:
+ case RING_SLAYING:
+ valued += 30;
+ break;
+ case RING_SUSTAIN_ABILITIES:
+ case RING_SUSTENANCE:
+ valued += 25;
+ break;
+ case RING_SEE_INVISIBLE:
+ valued += 20;
+ break;
+ case RING_DEXTERITY:
+ case RING_EVASION:
+ case RING_INTELLIGENCE:
+ case RING_PROTECTION:
+ case RING_STRENGTH:
+ valued += 10;
+ break;
+ case RING_TELEPORTATION:
+ valued -= 10;
+ break;
+ case RING_HUNGER:
+ valued -= 50;
+ break;
+ case AMU_THE_GOURMAND:
+ valued += 35;
+ break;
+ case AMU_CLARITY:
+ case AMU_RESIST_CORROSION:
+ case AMU_RESIST_MUTATION:
+ case AMU_RESIST_SLOW:
+ case AMU_WARDING:
+ valued += 30;
+ break;
+ case AMU_CONSERVATION:
+ case AMU_CONTROLLED_FLIGHT:
+ valued += 25;
+ break;
+ case AMU_RAGE:
+ valued += 20;
+ break;
+ case AMU_INACCURACY:
+ valued -= 50;
+ break;
+ // got to do delusion!
+ }
+
+ if (is_random_artefact(item))
+ {
+ if (item_ident(item, ISFLAG_KNOW_TYPE))
+ {
+ if (valued < 0)
+ valued = randart_value( item ) - 5;
+ else
+ valued += randart_value( item );
+ }
+ else
+ {
+ valued += 50;
+ }
+ }
+
+ valued *= 7;
+ }
+ break;
+
+ case OBJ_MISCELLANY:
+ if (item_ident( item, ISFLAG_KNOW_TYPE ))
+ {
+ switch (item.sub_type)
+ {
+ case MISC_RUNE_OF_ZOT: // upped from 1200 to encourage collecting
+ valued += 10000;
+ break;
+ case MISC_HORN_OF_GERYON:
+ valued += 5000;
+ break;
+ case MISC_DISC_OF_STORMS:
+ valued += 2000;
+ break;
+ case MISC_CRYSTAL_BALL_OF_SEEING:
+ valued += 500;
+ break;
+ case MISC_BOTTLED_EFREET:
+ valued += 400;
+ break;
+ case MISC_CRYSTAL_BALL_OF_FIXATION:
+ case MISC_EMPTY_EBONY_CASKET:
+ valued += 20;
+ break;
+ default:
+ valued += 500;
+ }
+ }
+ else
+ {
+ switch (item.sub_type)
+ {
+ case MISC_RUNE_OF_ZOT:
+ valued += 5000;
+ break;
+ case MISC_HORN_OF_GERYON:
+ valued += 1000;
+ break;
+ case MISC_CRYSTAL_BALL_OF_SEEING:
+ valued += 450;
+ break;
+ case MISC_BOTTLED_EFREET:
+ valued += 350;
+ break;
+ case MISC_DECK_OF_TRICKS:
+ valued += 100;
+ break;
+ default:
+ valued += 400;
+ }
+ }
+ break;
+
+ //case 10: break;
+
+ case OBJ_BOOKS:
+ valued = 150 + (item_ident( item, ISFLAG_KNOW_TYPE )
+ ? book_rarity(item.sub_type) * 50 : 0);
+ break;
+
+ case OBJ_STAVES:
+ if (item_not_ident( item, ISFLAG_KNOW_TYPE ))
+ valued = 120;
+ else if (item.sub_type == STAFF_SMITING
+ || item.sub_type == STAFF_STRIKING
+ || item.sub_type == STAFF_WARDING
+ || item.sub_type == STAFF_DISCOVERY)
+ {
+ valued = 150;
+ }
+ else
+ valued = 250;
+ break;
+
+ case OBJ_ORBS:
+ valued = 250000;
+ break;
+ } // end switch
+
+ if (valued < 1)
+ valued = 1;
+
+ valued *= item.quantity;
+
+ return (valued);
+} // end item_value()
+
+void shop(void)
+{
+ unsigned char i = 0;
+
+ for (i = 0; i < MAX_SHOPS; i++)
+ {
+ if (env.shop[i].x == you.x_pos && env.shop[i].y == you.y_pos)
+ break;
+ }
+
+ if (i == MAX_SHOPS)
+ {
+ mpr("Help! Non-existent shop.");
+ return;
+ }
+
+ char identy[4][50];
+
+ save_id(identy);
+
+ in_a_shop(i, identy);
+ you.redraw_gold = 1;
+ burden_change();
+
+ redraw_screen();
+} // end shop()
+
+const char *shop_name(int sx, int sy)
+{
+ static char sh_name[80];
+ int shoppy;
+
+ // paranoia
+ if (grd[sx][sy] != DNGN_ENTER_SHOP)
+ return ("");
+
+ // find shop
+ for(shoppy = 0; shoppy < MAX_SHOPS; shoppy ++)
+ {
+ // find shop index plus a little bit of paranoia
+ if (env.shop[shoppy].x == sx && env.shop[shoppy].y == sy &&
+ env.shop[shoppy].type != SHOP_UNASSIGNED)
+ {
+ break;
+ }
+ }
+
+ if (shoppy == MAX_SHOPS)
+ {
+ mpr("Help! Non-existent shop.");
+ return ("Buggy Shop");
+ }
+
+ int shop_type = env.shop[shoppy].type;
+
+ char st_p[ITEMNAME_SIZE];
+
+ make_name( env.shop[shoppy].keeper_name[0], env.shop[shoppy].keeper_name[1],
+ env.shop[shoppy].keeper_name[2], 3, st_p );
+
+ strcpy(sh_name, st_p);
+ strcat(sh_name, "'s ");
+
+ if (shop_type == SHOP_WEAPON_ANTIQUE || shop_type == SHOP_ARMOUR_ANTIQUE)
+ strcat( sh_name, "Antique " );
+
+ strcat(sh_name, (shop_type == SHOP_WEAPON
+ || shop_type == SHOP_WEAPON_ANTIQUE) ? "Weapon" :
+ (shop_type == SHOP_ARMOUR
+ || shop_type == SHOP_ARMOUR_ANTIQUE) ? "Armour" :
+
+ (shop_type == SHOP_JEWELLERY) ? "Jewellery" :
+ (shop_type == SHOP_WAND) ? "Magical Wand" :
+ (shop_type == SHOP_BOOK) ? "Book" :
+ (shop_type == SHOP_FOOD) ? "Food" :
+ (shop_type == SHOP_SCROLL) ? "Magic Scroll" :
+ (shop_type == SHOP_GENERAL_ANTIQUE) ? "Assorted Antiques" :
+ (shop_type == SHOP_DISTILLERY) ? "Distillery" :
+ (shop_type == SHOP_GENERAL) ? "General Store"
+ : "Bug");
+
+
+ if (shop_type != SHOP_GENERAL
+ && shop_type != SHOP_GENERAL_ANTIQUE && shop_type != SHOP_DISTILLERY)
+ {
+ int temp = sx + sy % 4;
+ strcat( sh_name, (temp == 0) ? " Shoppe" :
+ (temp == 1) ? " Boutique" :
+ (temp == 2) ? " Emporium"
+ : " Shop" );
+ }
+
+ return (sh_name);
+}
diff --git a/trunk/source/shopping.h b/trunk/source/shopping.h
new file mode 100644
index 0000000000..df6936deb0
--- /dev/null
+++ b/trunk/source/shopping.h
@@ -0,0 +1,43 @@
+/*
+ * File: shopping.cc
+ * Summary: Shop keeper functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef SHOPPING_H
+#define SHOPPING_H
+
+#include "externs.h"
+
+int randart_value( const item_def &item );
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: chardump - invent - ouch - religion - shopping
+ * *********************************************************************** */
+
+// ident == true overrides the item ident level and gives the price
+// as if the item was fully id'd
+unsigned int item_value( item_def item, char id[4][50], bool ident = false );
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: misc
+ * *********************************************************************** */
+void shop(void);
+
+
+
+// last updated 06mar2001 {gdl}
+/* ***********************************************************************
+ * called from: items direct
+ * *********************************************************************** */
+const char *shop_name(int sx, int sy);
+
+#endif
diff --git a/trunk/source/skills.cc b/trunk/source/skills.cc
new file mode 100644
index 0000000000..af7d88f49a
--- /dev/null
+++ b/trunk/source/skills.cc
@@ -0,0 +1,438 @@
+/*
+ * File: skills.cc
+ * Summary: Skill exercising functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <3> 8/08/99 BWR Increased skill cost in midgame
+ *
+ * <2> 7/31/99 BWR Inc skill_point granularity,
+ * added MAX_SPENDING_LIMIT
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "skills.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "externs.h"
+
+#include "macro.h"
+#include "player.h"
+#include "skills2.h"
+#include "stuff.h"
+
+
+// MAX_COST_LIMIT is the maximum XP amount it will cost to raise a skill
+// by 10 skill points (ie one standard practice).
+//
+// MAX_SPENDING_LIMIT is the maximum XP amount we allow the player to
+// spend on a skill in a single raise.
+//
+// Note that they don't have to be equal, but it is important to make
+// sure that they're set so that the spending limit will always allow
+// for 1 skill point to be earned.
+#define MAX_COST_LIMIT 250
+#define MAX_SPENDING_LIMIT 250
+
+static void exercise2( char exsk );
+
+// These values were calculated by running a simulation of gaining skills.
+// The goal is to try and match the old cost system which used the player's
+// experience level (which has a number of problems) so things shouldn't
+// seem too different to the player... but we still try to err on the
+// high side for the lower levels. -- bwr
+int skill_cost_needed( int level )
+{
+ // The average starting skill total is actually lower, but
+ // some classes get about 2200, and they would probably be
+ // start around skill cost level 3 if we used the average. -- bwr
+ int ret = 2200;
+
+ switch (level)
+ {
+ case 1: ret = 0; break;
+
+ case 2: ret += 250; break; // 250 -- big because of initial 25 pool
+ case 3: ret += 350; break; // 100
+ case 4: ret += 550; break; // 200
+ case 5: ret += 900; break; // 350
+ case 6: ret += 1300; break; // 400
+ case 7: ret += 1900; break; // 600
+ case 8: ret += 2800; break; // 900
+ case 9: ret += 4200; break; // 1400
+ case 10: ret += 5900; break; // 1700
+ case 11: ret += 9000; break; // 3100
+
+ default:
+ ret += 9000 + (4000 * (level - 11));
+ break;
+ }
+
+ return (ret);
+}
+
+void calc_total_skill_points( void )
+{
+ int i;
+
+ you.total_skill_points = 0;
+
+ for (i = 0; i < NUM_SKILLS; i++)
+ {
+ you.total_skill_points += you.skill_points[i];
+ }
+
+ for (i = 1; i <= 27; i++)
+ {
+ if (you.total_skill_points < skill_cost_needed(i))
+ break;
+ }
+
+ you.skill_cost_level = i - 1;
+
+#if DEBUG_DIAGNOSTICS
+ you.redraw_experience = 1;
+#endif
+}
+
+// skill_cost_level makes skills more expensive for more experienced characters
+// skill_level makes higher skills more expensive
+static int calc_skill_cost( int skill_cost_level, int skill_level )
+{
+ int ret = 1 + skill_level;
+
+ // does not yet allow for loss of skill levels.
+ if (skill_level > 9)
+ {
+ ret *= (skill_level - 7);
+ ret /= 3;
+ }
+
+ if (skill_cost_level > 4)
+ ret += skill_cost_level - 4;
+ if (skill_cost_level > 7)
+ ret += skill_cost_level - 7;
+ if (skill_cost_level > 10)
+ ret += skill_cost_level - 10;
+ if (skill_cost_level > 13)
+ ret += skill_cost_level - 13;
+ if (skill_cost_level > 16)
+ ret += skill_cost_level - 16;
+
+ if (skill_cost_level > 10)
+ {
+ ret *= (skill_cost_level - 5);
+ ret /= 5;
+ }
+
+ if (skill_level > 7)
+ ret += 1;
+ if (skill_level > 9)
+ ret += 2;
+ if (skill_level > 11)
+ ret += 3;
+ if (skill_level > 13)
+ ret += 4;
+ if (skill_level > 15)
+ ret += 5;
+
+ if (ret > MAX_COST_LIMIT)
+ ret = MAX_COST_LIMIT;
+
+ return (ret);
+}
+
+void exercise(char exsk, int deg)
+{
+ if (you.exp_available > 0 && you.skills[exsk] < 27)
+ {
+ while (deg > 0)
+ {
+ if (!you.practise_skill[exsk] && !one_chance_in(4))
+ break;
+
+ exercise2( exsk );
+ deg--;
+ }
+ }
+
+ return;
+} // end exercise()
+
+static void exercise2( char exsk )
+{
+ int deg = 1;
+ int bonus = 0;
+ char old_best_skill = best_skill(SK_FIGHTING, (NUM_SKILLS - 1), 99);
+
+ int skill_change = calc_skill_cost(you.skill_cost_level, you.skills[exsk]);
+ int i;
+
+ // being good at some weapons makes others easier to learn:
+ if (exsk < SK_SLINGS)
+ {
+ /* blades to blades */
+ if ((exsk == SK_SHORT_BLADES || exsk == SK_LONG_SWORDS)
+ && (you.skills[SK_SHORT_BLADES] > you.skills[exsk]
+ || you.skills[SK_LONG_SWORDS] > you.skills[exsk]))
+ {
+ bonus += random2(3);
+ }
+
+ /* Axes and Polearms */
+ if ((exsk == SK_AXES || exsk == SK_POLEARMS)
+ && (you.skills[SK_AXES] > you.skills[exsk]
+ || you.skills[SK_POLEARMS] > you.skills[exsk]))
+ {
+ bonus += random2(3);
+ }
+
+ /* Polearms and Staves */
+ if ((exsk == SK_POLEARMS || exsk == SK_STAVES)
+ && (you.skills[SK_POLEARMS] > you.skills[exsk]
+ || you.skills[SK_STAVES] > you.skills[exsk]))
+ {
+ bonus += random2(3);
+ }
+
+ /* Axes and Maces */
+ if ((exsk == SK_AXES || exsk == SK_MACES_FLAILS)
+ && (you.skills[SK_AXES] > you.skills[exsk]
+ || you.skills[SK_MACES_FLAILS] > you.skills[exsk]))
+ {
+ bonus += random2(3);
+ }
+ }
+
+ // Quick fix for the fact that stealth can't be gained fast enough to
+ // keep up with the monster levels, this should speed its advancement
+ if (exsk == SK_STEALTH)
+ bonus += random2(3);
+
+ // spell casting is cheaper early on, and elementals hinder each other
+ if (exsk >= SK_SPELLCASTING)
+ {
+ if (you.skill_cost_level < 5)
+ {
+ skill_change /= 2;
+ }
+ else if (you.skill_cost_level < 15)
+ {
+ skill_change *= (10 + (you.skill_cost_level - 5));
+ skill_change /= 20;
+ }
+
+ // being good at elemental magic makes other elements harder to learn:
+ if (exsk >= SK_FIRE_MAGIC && exsk <= SK_EARTH_MAGIC
+ && (you.skills[SK_FIRE_MAGIC] > you.skills[exsk]
+ || you.skills[SK_ICE_MAGIC] > you.skills[exsk]
+ || you.skills[SK_AIR_MAGIC] > you.skills[exsk]
+ || you.skills[SK_EARTH_MAGIC] > you.skills[exsk]))
+ {
+ if (one_chance_in(3))
+ return;
+ }
+
+ // some are direct opposites
+ if ((exsk == SK_FIRE_MAGIC || exsk == SK_ICE_MAGIC)
+ && (you.skills[SK_FIRE_MAGIC] > you.skills[exsk]
+ || you.skills[SK_ICE_MAGIC] > you.skills[exsk]))
+ {
+ // of course, this is cumulative with the one above.
+ if (!one_chance_in(3))
+ return;
+ }
+
+ if ((exsk == SK_AIR_MAGIC || exsk == SK_EARTH_MAGIC)
+ && (you.skills[SK_AIR_MAGIC] > you.skills[exsk]
+ || you.skills[SK_EARTH_MAGIC] > you.skills[exsk]))
+ {
+ if (!one_chance_in(3))
+ return;
+ }
+
+ // experimental restriction (too many spell schools) -- bwr
+ int skill_rank = 1;
+
+ for (i = SK_CONJURATIONS; i <= SK_DIVINATIONS; i++)
+ {
+ if (you.skills[exsk] < you.skills[i])
+ skill_rank++;
+ }
+
+ // Things get progressively harder, but not harder than
+ // the Fire-Air or Ice-Earth level.
+ if (skill_rank > 3 && one_chance_in(10 - skill_rank))
+ return;
+ }
+
+ int fraction = 0;
+ int spending_limit = (you.exp_available < MAX_SPENDING_LIMIT)
+ ? you.exp_available : MAX_SPENDING_LIMIT;
+
+ // handle fractional learning
+ if (skill_change > spending_limit)
+ {
+ // This system is a bit hard on missile weapons in the late game
+ // since they require expendable ammo in order to practise.
+ // Increasing the "deg"ree of exercise would make missile
+ // weapons too easy earlier on, so instead we're giving them
+ // a special case here.
+ if ((exsk != SK_DARTS && exsk != SK_BOWS && exsk != SK_CROSSBOWS)
+ || skill_change > you.exp_available)
+ {
+ fraction = (spending_limit * 10) / skill_change;
+ skill_change = (skill_change * fraction) / 10;
+
+ deg = (deg * fraction) / 10;
+
+ if (deg == 0)
+ bonus = (bonus * fraction) / 10;
+ }
+ else
+ {
+ if ((skill_change / 2) > MAX_SPENDING_LIMIT)
+ {
+ deg = 0;
+ fraction = 5;
+ }
+ else
+ {
+ deg = 1;
+ }
+
+ skill_change = spending_limit;
+ }
+ }
+
+ skill_change -= random2(5);
+
+ if (skill_change < 1)
+ {
+ // No free lunch, this is a problem now that we don't
+ // have overspending.
+ if (deg > 0 || fraction > 0 || bonus > 0)
+ skill_change = 1;
+ else
+ skill_change = 0;
+ }
+
+ // Can safely return at any stage before this
+ int skill_inc = (deg + bonus) * 10 + fraction;
+
+ // Starting to learn skills is easier if the appropriate stat is high
+ if (you.skills[exsk] == 0)
+ {
+ if ((exsk >= SK_FIGHTING && exsk <= SK_STAVES) || exsk == SK_ARMOUR)
+ {
+ // These skills are easier for the strong
+ skill_inc *= ((you.strength < 5) ? 5 : you.strength);
+ skill_inc /= 10;
+ }
+ else if (exsk >= SK_SLINGS && exsk <= SK_UNARMED_COMBAT)
+ {
+ // These skills are easier for the dexterous
+ // Note: Armour is handled above.
+ skill_inc *= ((you.dex < 5) ? 5 : you.dex);
+ skill_inc /= 10;
+ }
+ else if (exsk >= SK_SPELLCASTING && exsk <= SK_POISON_MAGIC)
+ {
+ // These skills are easier for the smart
+ skill_inc *= ((you.intel < 5) ? 5 : you.intel);
+ skill_inc /= 10;
+ }
+ }
+
+ you.skill_points[exsk] += skill_inc;
+ you.exp_available -= skill_change;
+
+ you.total_skill_points += skill_inc;
+ if (you.skill_cost_level < 27
+ && you.total_skill_points >= skill_cost_needed(you.skill_cost_level + 1))
+ {
+ you.skill_cost_level++;
+ }
+
+ if (you.exp_available < 0)
+ you.exp_available = 0;
+
+ you.redraw_experience = 1;
+
+/*
+ New (LH): debugging bit: when you exercise a skill, displays the skill
+ exercised and how much you spent on it. Too irritating to be a regular
+ WIZARD feature.
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "Exercised %s * %d for %d xp.",
+ skill_name(exsk), skill_inc, skill_change );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+*/
+
+ if (you.skill_points[exsk] >
+ (skill_exp_needed(you.skills[exsk] + 2)
+ * species_skills(exsk, you.species) / 100))
+ {
+ strcpy(info, "Your ");
+ strcat(info, skill_name(exsk));
+ strcat(info, " skill increases!");
+ mpr(info, MSGCH_INTRINSIC_GAIN);
+
+ you.skills[exsk]++;
+
+ // Recalculate this skill's order for tie breaking skills
+ // at its new level. See skills2.cc::init_skill_order()
+ // for more details. -- bwr
+ you.skill_order[exsk] = 0;
+ for (i = SK_FIGHTING; i < NUM_SKILLS; i++)
+ {
+ if (i == exsk)
+ continue;
+
+ if (you.skills[i] >= you.skills[exsk])
+ you.skill_order[exsk]++;
+ }
+
+ if (exsk == SK_FIGHTING)
+ calc_hp();
+
+ if (exsk == SK_INVOCATIONS || exsk == SK_EVOCATIONS
+ || exsk == SK_SPELLCASTING)
+ {
+ calc_mp();
+ }
+
+ if (exsk == SK_DODGING || exsk == SK_ARMOUR)
+ you.redraw_evasion = 1;
+
+ if (exsk == SK_ARMOUR || exsk == SK_SHIELDS
+ || exsk == SK_ICE_MAGIC || exsk == SK_EARTH_MAGIC
+ || you.duration[ DUR_TRANSFORMATION ] > 0)
+ {
+ you.redraw_armour_class = 1;
+ }
+
+ const unsigned char best = best_skill( SK_FIGHTING,
+ (NUM_SKILLS - 1), 99 );
+
+ const unsigned char best_spell = best_skill( SK_SPELLCASTING,
+ SK_POISON_MAGIC, 99 );
+
+ if ((exsk == SK_SPELLCASTING)
+ && (you.skills[exsk] == 1 && best_spell == SK_SPELLCASTING))
+ {
+ mpr("You're starting to get the hang of this magic thing.");
+ }
+
+ if (best != old_best_skill || old_best_skill == exsk)
+ {
+ redraw_skill( you.your_name, player_title() );
+ }
+ }
+} // end exercise2()
diff --git a/trunk/source/skills.h b/trunk/source/skills.h
new file mode 100644
index 0000000000..10afa1df8a
--- /dev/null
+++ b/trunk/source/skills.h
@@ -0,0 +1,26 @@
+/*
+ * File: skills.cc
+ * Summary: Skill exercising functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef SKILLS_H
+#define SKILLS_H
+
+int skill_cost_needed( int level );
+void calc_total_skill_points( void );
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - bang - beam - debug - fight - it_use3 - item_use -
+ * items - misc - spell
+ * *********************************************************************** */
+void exercise(char exsk, int deg);
+
+
+#endif
diff --git a/trunk/source/skills2.cc b/trunk/source/skills2.cc
new file mode 100644
index 0000000000..6eb53d6d53
--- /dev/null
+++ b/trunk/source/skills2.cc
@@ -0,0 +1,2365 @@
+/*
+ * File: skills2.cc
+ * Summary: More skill related functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * 01aug2000 jmf RESTORED TITLES TO THEIR FORMER GLORY! MUA-HA!
+ * <4> 22Jul2000 GDL added warning for low throwing skill
+ * Changed a few titles.
+ * <3> 5/20/99 BWR Changed Trapper titles, avoided
+ * overflow on the weapon skill
+ * column.
+ * <2> -/--/-- WL Extensive mods from Wladimir van der Laan.
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "skills2.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#include "externs.h"
+#include "fight.h"
+#include "player.h"
+#include "randart.h"
+#include "religion.h"
+#include "stuff.h"
+#include "wpn-misc.h"
+#include "view.h"
+
+/* jmf: some references for words I used below:
+ Peltast http://www.geocities.com/Athens/Aegean/9659/shields_main.htm
+ Phalangite http://www.users.cts.com/funtv/j/jjartist/EpiroteScenario1.htm
+ Yeoman: http://snt.student.utwente.nl/campus/sagi/artikel/longbow/longbow.html
+*/
+
+// Note: Even though %s could be used with most of these, remember that
+// the character's race will be listed on the next line. Its only really
+// intended for cases where things might be really awkward without it. -- bwr
+
+const char *skills[50][6] = {
+ {"Fighting", "Skirmisher", "Grunt", "Veteran", "Warrior", "Slayer"}, // 0
+ {"Short Blades", "Stabber", "Cutter", "Knifefighter", "Eviscerator", "Blademaster"},
+ {"Long Blades", "Slasher", "Slicer", "Fencer", "Swordfighter", "Swordmaster"},
+ {NULL}, // 3- was: great swords {dlb}
+ {"Axes", "Chopper", "Cleaver", "Hacker", "Severer", "Axe Maniac"},
+ {"Maces & Flails", "Basher", "Cudgeler", "Shatterer", "Bludgeoner", "Skullcrusher"}, // 5
+ {"Polearms", "Spear-Bearer", "Pike-%s", "Phalangite", "Lancer", "Halberdier"},
+ {"Staves", "Twirler", "Cruncher", "Smasher", "Stickfighter", "Skullbreaker"},
+
+ {"Slings", "Vandal", "Slinger", "Whirler", "Crazy %s", "Very Crazy %s"},
+ {"Bows", "Shooter", "Yeoman", "Archer", "Merry %s", "Merry %s"},
+ {"Crossbows", "Shooter", "Sharpshooter", "Archer", "%s Ballista", "%s Ballista"}, // 10
+ {"Darts", "Dart Thrower", "Hurler", "Hurler, First Class", "%s Darts Champion", "Universal Darts Champion"},
+ {"Throwing", "Chucker", "Thrower", "Deadly Accurate", "Hawkeye", "Sniper"},
+
+ {"Armour", "Covered", "Protected", "Tortoise", "Impregnable", "Invulnerable"},
+ {"Dodging", "Ducker", "Dodger", "Nimble", "Spry", "Acrobat"},
+ {"Stealth", "Footpad", "Sneak", "Covert", "Unseen", "Imperceptible"},
+ {"Stabbing", "Miscreant", "Blackguard", "Backstabber", "Cutthroat", "Politician"},
+ {"Shields", "Shield-Bearer", "Blocker", "%s Barricade", "Peltast", "Hoplite"},
+ {"Traps & Doors", "Disarmer", "Trapper", "Architect", "Engineer", "Dungeon Master"},
+
+ // STR based fighters, for DEX/martial arts titles see below
+ {"Unarmed Combat", "Ruffian", "Grappler", "Brawler", "Wrestler", "Boxer" },
+
+ {NULL}, // 20- empty
+ {NULL}, // 21- empty
+ {NULL}, // 22- empty
+ {NULL}, // 23- empty
+ {NULL}, // 24- empty
+
+ {"Spellcasting", "Magician", "Thaumaturge", "Eclecticist", "Sorcerer", "Archmage"}, // 25
+ {"Conjurations", "Ruinous", "Conjurer", "Destroyer", "Devastator", "Annihilator"},
+ {"Enchantments", "Charm-Maker", "Infuser", "Bewitcher", "Enchanter", "Spellbinder"},
+ {"Summonings", "Caller", "Summoner", "Convoker", "Demonologist", "Hellbinder"},
+ {"Necromancy", "Grave Robber", "Reanimator", "Necromancer", "Thanatomancer", "%s of Death"},
+ {"Translocations", "Jumper", "Blinker", "Shifter", "Portalist", "Plane Walker"}, // 30
+ {"Transmigration", "Changer", "Transmogrifier", "Transformer", "Alchemist", "Transmuter"},
+ {"Divinations", "Seer", "Soothsayer", "Diviner", "Augur", "Oracle"},
+
+ {"Fire Magic", "Firebug", "Arsonist", "Scorcher", "Pyromancer", "Infernalist"},
+ {"Ice Magic", "Chiller", "Frost Mage", "Ice Mage", "Cryomancer", "Englaciator"},
+ {"Air Magic", "Wind Mage", "Cloud Mage", "Air Mage", "Sky Mage", "Storm Mage"}, // 35
+ {"Earth Magic", "Digger", "Geomancer", "Earth Mage", "Metallomancer", "Petrodigitator"},
+ {"Poison Magic", "Stinger", "Tainter", "Polluter", "Poisoner", "Envenomancer"},
+
+ {"Invocations", "Believer", "Servant", "Worldly Agent", "Theurge", "Avatar"}, // 38
+ {"Evocations", "Charlatan", "Prestidigitator", "Fetichist", "Evocator", "Talismancer"}, // 39
+
+/*NOTE: If more skills are added, must change ranges in level_change() in player.cc */
+/*{"", "", "", "", ""}, */
+
+ {NULL}, // 40- empty
+ {NULL}, // 41- empty
+ {NULL}, // 42- empty
+ {NULL}, // 43- empty
+ {NULL}, // 44- empty
+ {NULL}, // 45- empty
+ {NULL}, // 46- empty
+ {NULL}, // 47- empty
+ {NULL}, // 48- empty
+ {NULL} // 49- empty {end of array}
+};
+
+const char *martial_arts_titles[6] =
+ {"Unarmed Combat", "Martial Artist", "Black Belt", "Sensei", "Master", "Grand Master"};
+
+
+/* Note that this (humans have 100 for all skills) is assumed in the
+ level_change function in player.cc, if CLASSES is def'd
+
+ 3.10: but it never is, and CLASSES is probably broken now. Anyway,
+ the Spellcasting skill (25) is actually about 130% of what is shown here.
+ */
+const int spec_skills[ NUM_SPECIES ][40] = {
+ { // SP_HUMAN (1)
+ 100, // SK_FIGHTING
+ 100, // SK_SHORT_BLADES
+ 100, // SK_LONG_SWORDS
+ 100, // SK_UNUSED_1
+ 100, // SK_AXES
+ 100, // SK_MACES_FLAILS
+ 100, // SK_POLEARMS
+ 100, // SK_STAVES
+ 100, // SK_SLINGS
+ 100, // SK_BOWS
+ 100, // SK_CROSSBOWS
+ 100, // SK_DARTS
+ 100, // SK_THROWING
+ 100, // SK_ARMOUR
+ 100, // SK_DODGING
+ 100, // SK_STEALTH
+ 100, // SK_STABBING
+ 100, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 100, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // SK_SPELLCASTING
+ 100, // SK_CONJURATIONS
+ 100, // SK_ENCHANTMENTS
+ 100, // SK_SUMMONINGS
+ 100, // SK_NECROMANCY
+ 100, // SK_TRANSLOCATIONS
+ 100, // SK_TRANSMIGRATION
+ 100, // SK_DIVINATIONS
+ 100, // SK_FIRE_MAGIC
+ 100, // SK_ICE_MAGIC
+ 100, // SK_AIR_MAGIC
+ 100, // SK_EARTH_MAGIC
+ 100, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 100, // SK_EVOCATIONS
+ },
+
+ { // SP_ELF (2)
+ 120, // SK_FIGHTING
+ 80, // SK_SHORT_BLADES
+ 80, // SK_LONG_SWORDS
+ 110, // SK_UNUSED_1
+ 120, // SK_AXES
+ 130, // SK_MACES_FLAILS
+ 130, // SK_POLEARMS
+ 100, // SK_STAVES
+ 120, // SK_SLINGS
+ 60, // SK_BOWS
+ 100, // SK_CROSSBOWS
+ 90, // SK_DARTS
+ 80, // SK_THROWING
+ 120, // SK_ARMOUR
+ 80, // SK_DODGING
+ 80, // SK_STEALTH
+ 100, // SK_STABBING
+ 120, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 110, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 80, // SK_SPELLCASTING
+ 105, // SK_CONJURATIONS
+ 70, // SK_ENCHANTMENTS
+ 100, // SK_SUMMONINGS
+ 120, // SK_NECROMANCY
+ 100, // SK_TRANSLOCATIONS
+ 100, // SK_TRANSMIGRATION
+ 100, // SK_DIVINATIONS
+ 100, // SK_FIRE_MAGIC
+ 100, // SK_ICE_MAGIC
+ 70, // SK_AIR_MAGIC
+ 130, // SK_EARTH_MAGIC
+ 110, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 80, // SK_EVOCATIONS
+ },
+
+ { // SP_HIGH_ELF (3)
+ 100, // SK_FIGHTING
+ 70, // SK_SHORT_BLADES
+ 70, // SK_LONG_SWORDS
+ 115, // SK_UNUSED_1
+ 130, // SK_AXES
+ 150, // SK_MACES_FLAILS
+ 150, // SK_POLEARMS
+ 100, // SK_STAVES
+ 140, // SK_SLINGS
+ 60, // SK_BOWS
+ 100, // SK_CROSSBOWS
+ 90, // SK_DARTS
+ 80, // SK_THROWING
+ 110, // SK_ARMOUR
+ 90, // SK_DODGING
+ 90, // SK_STEALTH
+ 110, // SK_STABBING
+ 110, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 130, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 70, // SK_SPELLCASTING
+ 90, // SK_CONJURATIONS
+ 70, // SK_ENCHANTMENTS
+ 110, // SK_SUMMONINGS
+ 130, // SK_NECROMANCY
+ 90, // SK_TRANSLOCATIONS
+ 90, // SK_TRANSMIGRATION
+ 110, // SK_DIVINATIONS
+ 100, // SK_FIRE_MAGIC
+ 100, // SK_ICE_MAGIC
+ 70, // SK_AIR_MAGIC
+ 130, // SK_EARTH_MAGIC
+ 130, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 100, // SK_EVOCATIONS
+ },
+
+ { // SP_GREY_ELF (4)
+ 140, // SK_FIGHTING
+ 90, // SK_SHORT_BLADES
+ 95, // SK_LONG_SWORDS
+ 120, // SK_UNUSED_1
+ 140, // SK_AXES
+ 160, // SK_MACES_FLAILS
+ 160, // SK_POLEARMS
+ 100, // SK_STAVES
+ 130, // SK_SLINGS
+ 70, // SK_BOWS
+ 100, // SK_CROSSBOWS
+ 90, // SK_DARTS
+ 80, // SK_THROWING
+ 140, // SK_ARMOUR
+ 75, // SK_DODGING
+ 70, // SK_STEALTH
+ 100, // SK_STABBING
+ 140, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 130, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 60, // SK_SPELLCASTING
+ 90, // SK_CONJURATIONS
+ 50, // SK_ENCHANTMENTS
+ 90, // SK_SUMMONINGS
+ 130, // SK_NECROMANCY
+ 80, // SK_TRANSLOCATIONS
+ 80, // SK_TRANSMIGRATION
+ 80, // SK_DIVINATIONS
+ 90, // SK_FIRE_MAGIC
+ 90, // SK_ICE_MAGIC
+ 60, // SK_AIR_MAGIC
+ 150, // SK_EARTH_MAGIC
+ 110, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 90, // SK_EVOCATIONS
+ },
+
+ { // SP_DEEP_ELF (5)
+ 150, // SK_FIGHTING
+ 100, // SK_SHORT_BLADES
+ 105, // SK_LONG_SWORDS
+ 120, // SK_UNUSED_1
+ 150, // SK_AXES
+ 165, // SK_MACES_FLAILS
+ 165, // SK_POLEARMS
+ 100, // SK_STAVES
+ 135, // SK_SLINGS
+ 74, // SK_BOWS
+ 75, // SK_CROSSBOWS
+ 75, // SK_DARTS
+ 80, // SK_THROWING
+ 140, // SK_ARMOUR
+ 70, // SK_DODGING
+ 65, // SK_STEALTH
+ 80, // SK_STABBING
+ 140, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 130, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 55, // SK_SPELLCASTING
+ 80, // SK_CONJURATIONS
+ 50, // SK_ENCHANTMENTS
+ 80, // SK_SUMMONINGS
+ 70, // SK_NECROMANCY
+ 75, // SK_TRANSLOCATIONS
+ 75, // SK_TRANSMIGRATION
+ 75, // SK_DIVINATIONS
+ 90, // SK_FIRE_MAGIC
+ 90, // SK_ICE_MAGIC
+ 80, // SK_AIR_MAGIC
+ 100, // SK_EARTH_MAGIC
+ 80, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 90, // SK_EVOCATIONS
+ },
+
+ { // SP_SLUDGE_ELF (6)
+ 80, // SK_FIGHTING
+ 110, // SK_SHORT_BLADES
+ 110, // SK_LONG_SWORDS
+ 110, // SK_UNUSED_1
+ 130, // SK_AXES
+ 140, // SK_MACES_FLAILS
+ 140, // SK_POLEARMS
+ 100, // SK_STAVES
+ 100, // SK_SLINGS
+ 100, // SK_BOWS
+ 100, // SK_CROSSBOWS
+ 100, // SK_DARTS
+ 70, // SK_THROWING
+ 140, // SK_ARMOUR
+ 70, // SK_DODGING
+ 75, // SK_STEALTH
+ 100, // SK_STABBING
+ 130, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 80, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 70, // SK_SPELLCASTING
+ 130, // SK_CONJURATIONS
+ 130, // SK_ENCHANTMENTS
+ 90, // SK_SUMMONINGS
+ 90, // SK_NECROMANCY
+ 100, // SK_TRANSLOCATIONS
+ 60, // SK_TRANSMIGRATION
+ 130, // SK_DIVINATIONS
+ 80, // SK_FIRE_MAGIC
+ 80, // SK_ICE_MAGIC
+ 80, // SK_AIR_MAGIC
+ 80, // SK_EARTH_MAGIC
+ 80, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 110, // SK_EVOCATIONS
+ },
+
+ { // SP_HILL_DWARF (7)
+ 70, // SK_FIGHTING
+ 80, // SK_SHORT_BLADES
+ 80, // SK_LONG_SWORDS
+ 90, // SK_UNUSED_1
+ 60, // SK_AXES
+ 70, // SK_MACES_FLAILS
+ 110, // SK_POLEARMS
+ 130, // SK_STAVES
+ 130, // SK_SLINGS
+ 150, // SK_BOWS
+ 120, // SK_CROSSBOWS
+ 120, // SK_DARTS
+ 120, // SK_THROWING
+ 70, // SK_ARMOUR
+ 120, // SK_DODGING
+ 150, // SK_STEALTH
+ 140, // SK_STABBING
+ 70, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 100, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 160, // SK_SPELLCASTING
+ 120, // SK_CONJURATIONS
+ 150, // SK_ENCHANTMENTS
+ 150, // SK_SUMMONINGS
+ 160, // SK_NECROMANCY
+ 150, // SK_TRANSLOCATIONS
+ 120, // SK_TRANSMIGRATION
+ 130, // SK_DIVINATIONS
+ 80, // SK_FIRE_MAGIC
+ 120, // SK_ICE_MAGIC
+ 150, // SK_AIR_MAGIC
+ 70, // SK_EARTH_MAGIC
+ 130, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 60, // SK_EVOCATIONS
+ },
+
+ { // SP_MOUNTAIN_DWARF (8)
+ 70, // SK_FIGHTING
+ 90, // SK_SHORT_BLADES
+ 90, // SK_LONG_SWORDS
+ 100, // SK_UNUSED_1
+ 70, // SK_AXES
+ 70, // SK_MACES_FLAILS
+ 110, // SK_POLEARMS
+ 120, // SK_STAVES
+ 125, // SK_SLINGS
+ 140, // SK_BOWS
+ 100, // SK_CROSSBOWS
+ 120, // SK_DARTS
+ 115, // SK_THROWING
+ 60, // SK_ARMOUR
+ 110, // SK_DODGING
+ 140, // SK_STEALTH
+ 130, // SK_STABBING
+ 70, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 100, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 140, // SK_SPELLCASTING
+ 115, // SK_CONJURATIONS
+ 135, // SK_ENCHANTMENTS
+ 150, // SK_SUMMONINGS
+ 160, // SK_NECROMANCY
+ 150, // SK_TRANSLOCATIONS
+ 120, // SK_TRANSMIGRATION
+ 130, // SK_DIVINATIONS
+ 70, // SK_FIRE_MAGIC
+ 130, // SK_ICE_MAGIC
+ 150, // SK_AIR_MAGIC
+ 70, // SK_EARTH_MAGIC
+ 130, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 70, // SK_EVOCATIONS
+ },
+
+ { // SP_HALFLING (9)
+ 120, // SK_FIGHTING
+ 60, // SK_SHORT_BLADES
+ 100, // SK_LONG_SWORDS
+ 130, // SK_UNUSED_1
+ 120, // SK_AXES
+ 150, // SK_MACES_FLAILS
+ 160, // SK_POLEARMS
+ 130, // SK_STAVES
+ 50, // SK_SLINGS
+ 70, // SK_BOWS
+ 90, // SK_CROSSBOWS
+ 50, // SK_DARTS
+ 60, // SK_THROWING
+ 150, // SK_ARMOUR
+ 70, // SK_DODGING
+ 60, // SK_STEALTH
+ 70, // SK_STABBING
+ 130, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 140, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 130, // SK_SPELLCASTING
+ 130, // SK_CONJURATIONS
+ 100, // SK_ENCHANTMENTS
+ 120, // SK_SUMMONINGS
+ 150, // SK_NECROMANCY
+ 100, // SK_TRANSLOCATIONS
+ 150, // SK_TRANSMIGRATION
+ 140, // SK_DIVINATIONS
+ 100, // SK_FIRE_MAGIC
+ 100, // SK_ICE_MAGIC
+ 90, // SK_AIR_MAGIC
+ 100, // SK_EARTH_MAGIC
+ 120, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 90, // SK_EVOCATIONS
+ },
+
+ { // SP_HILL_ORC (10)
+ 70, // SK_FIGHTING
+ 100, // SK_SHORT_BLADES
+ 80, // SK_LONG_SWORDS
+ 70, // SK_UNUSED_1
+ 70, // SK_AXES
+ 80, // SK_MACES_FLAILS
+ 80, // SK_POLEARMS
+ 110, // SK_STAVES
+ 130, // SK_SLINGS
+ 120, // SK_BOWS
+ 120, // SK_CROSSBOWS
+ 130, // SK_DARTS
+ 130, // SK_THROWING
+ 90, // SK_ARMOUR
+ 140, // SK_DODGING
+ 150, // SK_STEALTH
+ 100, // SK_STABBING
+ 80, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 90, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 150, // SK_SPELLCASTING
+ 100, // SK_CONJURATIONS
+ 120, // SK_ENCHANTMENTS
+ 120, // SK_SUMMONINGS
+ 100, // SK_NECROMANCY
+ 150, // SK_TRANSLOCATIONS
+ 160, // SK_TRANSMIGRATION
+ 160, // SK_DIVINATIONS
+ 100, // SK_FIRE_MAGIC
+ 100, // SK_ICE_MAGIC
+ 150, // SK_AIR_MAGIC
+ 100, // SK_EARTH_MAGIC
+ 110, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 100, // SK_EVOCATIONS
+ },
+
+ { // SP_KOBOLD (11)
+ 80, // SK_FIGHTING
+ 60, // SK_SHORT_BLADES
+ 100, // SK_LONG_SWORDS
+ 120, // SK_UNUSED_1
+ 110, // SK_AXES
+ 140, // SK_MACES_FLAILS
+ 150, // SK_POLEARMS
+ 110, // SK_STAVES
+ 70, // SK_SLINGS
+ 80, // SK_BOWS
+ 90, // SK_CROSSBOWS
+ 50, // SK_DARTS
+ 60, // SK_THROWING
+ 140, // SK_ARMOUR
+ 70, // SK_DODGING
+ 60, // SK_STEALTH
+ 70, // SK_STABBING
+ 130, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 100, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 110, // SK_SPELLCASTING
+ 110, // SK_CONJURATIONS
+ 110, // SK_ENCHANTMENTS
+ 105, // SK_SUMMONINGS
+ 105, // SK_NECROMANCY
+ 100, // SK_TRANSLOCATIONS
+ 110, // SK_TRANSMIGRATION
+ 130, // SK_DIVINATIONS
+ 100, // SK_FIRE_MAGIC
+ 100, // SK_ICE_MAGIC
+ 100, // SK_AIR_MAGIC
+ 100, // SK_EARTH_MAGIC
+ 100, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 80, // SK_EVOCATIONS
+ },
+
+ { // SP_MUMMY (12)
+ 100, // SK_FIGHTING
+ 140, // SK_SHORT_BLADES
+ 140, // SK_LONG_SWORDS
+ 140, // SK_UNUSED_1
+ 140, // SK_AXES
+ 140, // SK_MACES_FLAILS
+ 140, // SK_POLEARMS
+ 140, // SK_STAVES
+ 140, // SK_SLINGS
+ 140, // SK_BOWS
+ 140, // SK_CROSSBOWS
+ 140, // SK_DARTS
+ 140, // SK_THROWING
+ 140, // SK_ARMOUR
+ 140, // SK_DODGING
+ 140, // SK_STEALTH
+ 140, // SK_STABBING
+ 140, // SK_SHIELDS
+ 140, // SK_TRAPS_DOORS
+ 140, // SK_UNARMED_COMBAT
+ 140, // undefined
+ 140, // undefined
+ 140, // undefined
+ 140, // undefined
+ 140, // undefined
+ 100, // SK_SPELLCASTING
+ 140, // SK_CONJURATIONS
+ 140, // SK_ENCHANTMENTS
+ 140, // SK_SUMMONINGS
+ 100, // SK_NECROMANCY
+ 140, // SK_TRANSLOCATIONS
+ 140, // SK_TRANSMIGRATION
+ 140, // SK_DIVINATIONS
+ 140, // SK_FIRE_MAGIC
+ 140, // SK_ICE_MAGIC
+ 140, // SK_AIR_MAGIC
+ 140, // SK_EARTH_MAGIC
+ 140, // SK_POISON_MAGIC
+ 140, // SK_INVOCATIONS
+ 140, // SK_EVOCATIONS
+ },
+
+ { // SP_NAGA (13)
+ 100, // SK_FIGHTING
+ 100, // SK_SHORT_BLADES
+ 100, // SK_LONG_SWORDS
+ 100, // SK_UNUSED_1
+ 100, // SK_AXES
+ 100, // SK_MACES_FLAILS
+ 100, // SK_POLEARMS
+ 120, // SK_STAVES
+ 120, // SK_SLINGS
+ 120, // SK_BOWS
+ 120, // SK_CROSSBOWS
+ 120, // SK_DARTS
+ 120, // SK_THROWING
+ 150, // SK_ARMOUR
+ 150, // SK_DODGING
+ 40, // SK_STEALTH
+ 100, // SK_STABBING
+ 140, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 100, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // SK_SPELLCASTING
+ 100, // SK_CONJURATIONS
+ 100, // SK_ENCHANTMENTS
+ 100, // SK_SUMMONINGS
+ 100, // SK_NECROMANCY
+ 100, // SK_TRANSLOCATIONS
+ 100, // SK_TRANSMIGRATION
+ 100, // SK_DIVINATIONS
+ 100, // SK_FIRE_MAGIC
+ 100, // SK_ICE_MAGIC
+ 100, // SK_AIR_MAGIC
+ 100, // SK_EARTH_MAGIC
+ 60, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 100, // SK_EVOCATIONS
+ },
+
+ { // SP_GNOME (14)
+ 100, // SK_FIGHTING
+ 75, // SK_SHORT_BLADES
+ 100, // SK_LONG_SWORDS
+ 130, // SK_UNUSED_1
+ 100, // SK_AXES
+ 130, // SK_MACES_FLAILS
+ 140, // SK_POLEARMS
+ 130, // SK_STAVES
+ 80, // SK_SLINGS
+ 100, // SK_BOWS
+ 90, // SK_CROSSBOWS
+ 60, // SK_DARTS
+ 100, // SK_THROWING
+ 150, // SK_ARMOUR
+ 70, // SK_DODGING
+ 70, // SK_STEALTH
+ 80, // SK_STABBING
+ 120, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 110, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 120, // SK_SPELLCASTING
+ 100, // SK_CONJURATIONS
+ 100, // SK_ENCHANTMENTS
+ 110, // SK_SUMMONINGS
+ 130, // SK_NECROMANCY
+ 130, // SK_TRANSLOCATIONS
+ 120, // SK_TRANSMIGRATION
+ 120, // SK_DIVINATIONS
+ 100, // SK_FIRE_MAGIC
+ 100, // SK_ICE_MAGIC
+ 170, // SK_AIR_MAGIC
+ 60, // SK_EARTH_MAGIC
+ 130, // SK_POISON_MAGIC
+ 120, // SK_INVOCATIONS
+ 60, // SK_EVOCATIONS
+ },
+
+ { // SP_OGRE (15)
+ 100, // SK_FIGHTING
+ 140, // SK_SHORT_BLADES
+ 120, // SK_LONG_SWORDS
+ 110, // SK_UNUSED_1
+ 100, // SK_AXES
+ 100, // SK_MACES_FLAILS
+ 110, // SK_POLEARMS
+ 120, // SK_STAVES
+ 150, // SK_SLINGS
+ 150, // SK_BOWS
+ 180, // SK_CROSSBOWS
+ 150, // SK_DARTS
+ 100, // SK_THROWING
+ 140, // SK_ARMOUR
+ 150, // SK_DODGING
+ 200, // SK_STEALTH
+ 150, // SK_STABBING
+ 110, // SK_SHIELDS
+ 200, // SK_TRAPS_DOORS
+ 130, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 220, // SK_SPELLCASTING
+ 180, // SK_CONJURATIONS
+ 220, // SK_ENCHANTMENTS
+ 200, // SK_SUMMONINGS
+ 150, // SK_NECROMANCY
+ 200, // SK_TRANSLOCATIONS
+ 200, // SK_TRANSMIGRATION
+ 200, // SK_DIVINATIONS
+ 150, // SK_FIRE_MAGIC
+ 150, // SK_ICE_MAGIC
+ 200, // SK_AIR_MAGIC
+ 120, // SK_EARTH_MAGIC
+ 150, // SK_POISON_MAGIC
+ 130, // SK_INVOCATIONS
+ 170, // SK_EVOCATIONS
+ },
+
+ { // SP_TROLL (16)
+ 140, // SK_FIGHTING
+ 150, // SK_SHORT_BLADES
+ 150, // SK_LONG_SWORDS
+ 150, // SK_UNUSED_1
+ 150, // SK_AXES
+ 130, // SK_MACES_FLAILS
+ 150, // SK_POLEARMS
+ 150, // SK_STAVES
+ 180, // SK_SLINGS
+ 180, // SK_BOWS
+ 180, // SK_CROSSBOWS
+ 180, // SK_DARTS
+ 130, // SK_THROWING
+ 150, // SK_ARMOUR
+ 130, // SK_DODGING
+ 250, // SK_STEALTH
+ 150, // SK_STABBING
+ 150, // SK_SHIELDS
+ 200, // SK_TRAPS_DOORS
+ 100, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 200, // SK_SPELLCASTING
+ 160, // SK_CONJURATIONS
+ 200, // SK_ENCHANTMENTS
+ 160, // SK_SUMMONINGS
+ 150, // SK_NECROMANCY
+ 160, // SK_TRANSLOCATIONS
+ 160, // SK_TRANSMIGRATION
+ 200, // SK_DIVINATIONS
+ 160, // SK_FIRE_MAGIC
+ 160, // SK_ICE_MAGIC
+ 200, // SK_AIR_MAGIC
+ 120, // SK_EARTH_MAGIC
+ 160, // SK_POISON_MAGIC
+ 150, // SK_INVOCATIONS
+ 180, // SK_EVOCATIONS
+ },
+
+ { // SP_OGRE_MAGE (17)
+ 100, // SK_FIGHTING
+ 110, // SK_SHORT_BLADES
+ 100, // SK_LONG_SWORDS
+ 100, // SK_UNUSED_1
+ 100, // SK_AXES
+ 100, // SK_MACES_FLAILS
+ 100, // SK_POLEARMS
+ 100, // SK_STAVES
+ 150, // SK_SLINGS
+ 150, // SK_BOWS
+ 150, // SK_CROSSBOWS
+ 150, // SK_DARTS
+ 150, // SK_THROWING
+ 170, // SK_ARMOUR
+ 130, // SK_DODGING
+ 100, // SK_STEALTH
+ 130, // SK_STABBING
+ 150, // SK_SHIELDS
+ 150, // SK_TRAPS_DOORS
+ 100, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 70, // SK_SPELLCASTING
+ 100, // SK_CONJURATIONS
+ 80, // SK_ENCHANTMENTS
+ 100, // SK_SUMMONINGS
+ 100, // SK_NECROMANCY
+ 100, // SK_TRANSLOCATIONS
+ 100, // SK_TRANSMIGRATION
+ 100, // SK_DIVINATIONS
+ 100, // SK_FIRE_MAGIC
+ 100, // SK_ICE_MAGIC
+ 100, // SK_AIR_MAGIC
+ 100, // SK_EARTH_MAGIC
+ 100, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 100, // SK_EVOCATIONS
+ },
+
+ { // SP_RED_DRACONIAN (18)
+ 90, // SK_FIGHTING
+ 100, // SK_SHORT_BLADES
+ 100, // SK_LONG_SWORDS
+ 100, // SK_UNUSED_1
+ 100, // SK_AXES
+ 100, // SK_MACES_FLAILS
+ 100, // SK_POLEARMS
+ 100, // SK_STAVES
+ 120, // SK_SLINGS
+ 120, // SK_BOWS
+ 120, // SK_CROSSBOWS
+ 120, // SK_DARTS
+ 120, // SK_THROWING
+ 200, // SK_ARMOUR
+ 120, // SK_DODGING
+ 120, // SK_STEALTH
+ 100, // SK_STABBING
+ 100, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 100, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // SK_SPELLCASTING
+ 100, // SK_CONJURATIONS
+ 120, // SK_ENCHANTMENTS
+ 100, // SK_SUMMONINGS
+ 100, // SK_NECROMANCY
+ 100, // SK_TRANSLOCATIONS
+ 100, // SK_TRANSMIGRATION
+ 100, // SK_DIVINATIONS
+ 70, // SK_FIRE_MAGIC
+ 150, // SK_ICE_MAGIC
+ 100, // SK_AIR_MAGIC
+ 100, // SK_EARTH_MAGIC
+ 100, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 100, // SK_EVOCATIONS
+ },
+
+ { // SP_WHITE_DRACONIAN (19)
+ 90, // SK_FIGHTING
+ 100, // SK_SHORT_BLADES
+ 100, // SK_LONG_SWORDS
+ 100, // SK_UNUSED_1
+ 100, // SK_AXES
+ 100, // SK_MACES_FLAILS
+ 100, // SK_POLEARMS
+ 100, // SK_STAVES
+ 120, // SK_SLINGS
+ 120, // SK_BOWS
+ 120, // SK_CROSSBOWS
+ 120, // SK_DARTS
+ 120, // SK_THROWING
+ 200, // SK_ARMOUR
+ 120, // SK_DODGING
+ 120, // SK_STEALTH
+ 100, // SK_STABBING
+ 100, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 100, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // SK_SPELLCASTING
+ 100, // SK_CONJURATIONS
+ 120, // SK_ENCHANTMENTS
+ 100, // SK_SUMMONINGS
+ 100, // SK_NECROMANCY
+ 100, // SK_TRANSLOCATIONS
+ 100, // SK_TRANSMIGRATION
+ 100, // SK_DIVINATIONS
+ 150, // SK_FIRE_MAGIC
+ 70, // SK_ICE_MAGIC
+ 100, // SK_AIR_MAGIC
+ 100, // SK_EARTH_MAGIC
+ 100, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 100, // SK_EVOCATIONS
+ },
+
+ { // SP_GREEN_DRACONIAN (20)
+ 90, // SK_FIGHTING
+ 100, // SK_SHORT_BLADES
+ 100, // SK_LONG_SWORDS
+ 100, // SK_UNUSED_1
+ 100, // SK_AXES
+ 100, // SK_MACES_FLAILS
+ 100, // SK_POLEARMS
+ 100, // SK_STAVES
+ 120, // SK_SLINGS
+ 120, // SK_BOWS
+ 120, // SK_CROSSBOWS
+ 120, // SK_DARTS
+ 120, // SK_THROWING
+ 200, // SK_ARMOUR
+ 120, // SK_DODGING
+ 120, // SK_STEALTH
+ 100, // SK_STABBING
+ 100, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 100, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // SK_SPELLCASTING
+ 100, // SK_CONJURATIONS
+ 120, // SK_ENCHANTMENTS
+ 100, // SK_SUMMONINGS
+ 100, // SK_NECROMANCY
+ 100, // SK_TRANSLOCATIONS
+ 100, // SK_TRANSMIGRATION
+ 100, // SK_DIVINATIONS
+ 100, // SK_FIRE_MAGIC
+ 100, // SK_ICE_MAGIC
+ 100, // SK_AIR_MAGIC
+ 100, // SK_EARTH_MAGIC
+ 70, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 100, // SK_EVOCATIONS
+ },
+
+ { // SP_YELLOW_DRACONIAN (21)
+ 90, // SK_FIGHTING
+ 100, // SK_SHORT_BLADES
+ 100, // SK_LONG_SWORDS
+ 100, // SK_UNUSED_1
+ 100, // SK_AXES
+ 100, // SK_MACES_FLAILS
+ 100, // SK_POLEARMS
+ 100, // SK_STAVES
+ 120, // SK_SLINGS
+ 120, // SK_BOWS
+ 120, // SK_CROSSBOWS
+ 120, // SK_DARTS
+ 120, // SK_THROWING
+ 200, // SK_ARMOUR
+ 120, // SK_DODGING
+ 120, // SK_STEALTH
+ 100, // SK_STABBING
+ 100, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 100, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // SK_SPELLCASTING
+ 100, // SK_CONJURATIONS
+ 120, // SK_ENCHANTMENTS
+ 100, // SK_SUMMONINGS
+ 100, // SK_NECROMANCY
+ 100, // SK_TRANSLOCATIONS
+ 100, // SK_TRANSMIGRATION
+ 100, // SK_DIVINATIONS
+ 100, // SK_FIRE_MAGIC
+ 100, // SK_ICE_MAGIC
+ 100, // SK_AIR_MAGIC
+ 100, // SK_EARTH_MAGIC
+ 100, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 100, // SK_EVOCATIONS
+ },
+
+ { // SP_GREY_DRACONIAN (22)
+ 90, // SK_FIGHTING
+ 100, // SK_SHORT_BLADES
+ 100, // SK_LONG_SWORDS
+ 100, // SK_UNUSED_1
+ 100, // SK_AXES
+ 100, // SK_MACES_FLAILS
+ 100, // SK_POLEARMS
+ 100, // SK_STAVES
+ 120, // SK_SLINGS
+ 120, // SK_BOWS
+ 120, // SK_CROSSBOWS
+ 120, // SK_DARTS
+ 120, // SK_THROWING
+ 200, // SK_ARMOUR
+ 120, // SK_DODGING
+ 120, // SK_STEALTH
+ 100, // SK_STABBING
+ 100, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 100, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // SK_SPELLCASTING
+ 100, // SK_CONJURATIONS
+ 120, // SK_ENCHANTMENTS
+ 100, // SK_SUMMONINGS
+ 100, // SK_NECROMANCY
+ 100, // SK_TRANSLOCATIONS
+ 100, // SK_TRANSMIGRATION
+ 100, // SK_DIVINATIONS
+ 100, // SK_FIRE_MAGIC
+ 100, // SK_ICE_MAGIC
+ 100, // SK_AIR_MAGIC
+ 100, // SK_EARTH_MAGIC
+ 100, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 100, // SK_EVOCATIONS
+ },
+
+ { // SP_BLACK_DRACONIAN (23)
+ 90, // SK_FIGHTING
+ 100, // SK_SHORT_BLADES
+ 100, // SK_LONG_SWORDS
+ 100, // SK_UNUSED_1
+ 100, // SK_AXES
+ 100, // SK_MACES_FLAILS
+ 100, // SK_POLEARMS
+ 100, // SK_STAVES
+ 120, // SK_SLINGS
+ 120, // SK_BOWS
+ 120, // SK_CROSSBOWS
+ 120, // SK_DARTS
+ 120, // SK_THROWING
+ 200, // SK_ARMOUR
+ 120, // SK_DODGING
+ 120, // SK_STEALTH
+ 100, // SK_STABBING
+ 100, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 100, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // SK_SPELLCASTING
+ 100, // SK_CONJURATIONS
+ 120, // SK_ENCHANTMENTS
+ 100, // SK_SUMMONINGS
+ 100, // SK_NECROMANCY
+ 100, // SK_TRANSLOCATIONS
+ 100, // SK_TRANSMIGRATION
+ 100, // SK_DIVINATIONS
+ 100, // SK_FIRE_MAGIC
+ 100, // SK_ICE_MAGIC
+ 70, // SK_AIR_MAGIC
+ 150, // SK_EARTH_MAGIC
+ 100, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 100, // SK_EVOCATIONS
+ },
+
+ { // SP_PURPLE_DRACONIAN (24)
+ 90, // SK_FIGHTING
+ 100, // SK_SHORT_BLADES
+ 100, // SK_LONG_SWORDS
+ 100, // SK_UNUSED_1
+ 100, // SK_AXES
+ 100, // SK_MACES_FLAILS
+ 100, // SK_POLEARMS
+ 100, // SK_STAVES
+ 120, // SK_SLINGS
+ 120, // SK_BOWS
+ 120, // SK_CROSSBOWS
+ 120, // SK_DARTS
+ 120, // SK_THROWING
+ 200, // SK_ARMOUR
+ 120, // SK_DODGING
+ 120, // SK_STEALTH
+ 100, // SK_STABBING
+ 100, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 100, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 70, // SK_SPELLCASTING
+ 100, // SK_CONJURATIONS
+ 90, // SK_ENCHANTMENTS
+ 100, // SK_SUMMONINGS
+ 100, // SK_NECROMANCY
+ 100, // SK_TRANSLOCATIONS
+ 100, // SK_TRANSMIGRATION
+ 100, // SK_DIVINATIONS
+ 100, // SK_FIRE_MAGIC
+ 100, // SK_ICE_MAGIC
+ 100, // SK_AIR_MAGIC
+ 100, // SK_EARTH_MAGIC
+ 100, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 90, // SK_EVOCATIONS
+ },
+
+ { // SP_MOTTLED_DRACONIAN (25)
+ 90, // SK_FIGHTING
+ 100, // SK_SHORT_BLADES
+ 100, // SK_LONG_SWORDS
+ 100, // SK_UNUSED_1
+ 100, // SK_AXES
+ 100, // SK_MACES_FLAILS
+ 100, // SK_POLEARMS
+ 100, // SK_STAVES
+ 120, // SK_SLINGS
+ 120, // SK_BOWS
+ 120, // SK_CROSSBOWS
+ 120, // SK_DARTS
+ 120, // SK_THROWING
+ 200, // SK_ARMOUR
+ 120, // SK_DODGING
+ 120, // SK_STEALTH
+ 100, // SK_STABBING
+ 100, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 100, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // SK_SPELLCASTING
+ 100, // SK_CONJURATIONS
+ 120, // SK_ENCHANTMENTS
+ 100, // SK_SUMMONINGS
+ 100, // SK_NECROMANCY
+ 100, // SK_TRANSLOCATIONS
+ 100, // SK_TRANSMIGRATION
+ 100, // SK_DIVINATIONS
+ 80, // SK_FIRE_MAGIC
+ 100, // SK_ICE_MAGIC
+ 100, // SK_AIR_MAGIC
+ 100, // SK_EARTH_MAGIC
+ 100, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 100, // SK_EVOCATIONS
+ },
+
+ { // SP_PALE_DRACONIAN (26)
+ 90, // SK_FIGHTING
+ 100, // SK_SHORT_BLADES
+ 100, // SK_LONG_SWORDS
+ 100, // SK_UNUSED_1
+ 100, // SK_AXES
+ 100, // SK_MACES_FLAILS
+ 100, // SK_POLEARMS
+ 100, // SK_STAVES
+ 120, // SK_SLINGS
+ 120, // SK_BOWS
+ 120, // SK_CROSSBOWS
+ 120, // SK_DARTS
+ 120, // SK_THROWING
+ 200, // SK_ARMOUR
+ 120, // SK_DODGING
+ 120, // SK_STEALTH
+ 100, // SK_STABBING
+ 100, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 100, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // SK_SPELLCASTING
+ 100, // SK_CONJURATIONS
+ 120, // SK_ENCHANTMENTS
+ 100, // SK_SUMMONINGS
+ 100, // SK_NECROMANCY
+ 100, // SK_TRANSLOCATIONS
+ 100, // SK_TRANSMIGRATION
+ 100, // SK_DIVINATIONS
+ 90, // SK_FIRE_MAGIC
+ 100, // SK_ICE_MAGIC
+ 90, // SK_AIR_MAGIC
+ 100, // SK_EARTH_MAGIC
+ 100, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 90, // SK_EVOCATIONS
+ },
+
+ { // SP_UNK0_DRACONAIN (27)
+ 90, // SK_FIGHTING
+ 100, // SK_SHORT_BLADES
+ 100, // SK_LONG_SWORDS
+ 100, // SK_UNUSED_1
+ 100, // SK_AXES
+ 100, // SK_MACES_FLAILS
+ 100, // SK_POLEARMS
+ 100, // SK_STAVES
+ 120, // SK_SLINGS
+ 120, // SK_BOWS
+ 120, // SK_CROSSBOWS
+ 120, // SK_DARTS
+ 120, // SK_THROWING
+ 200, // SK_ARMOUR
+ 120, // SK_DODGING
+ 120, // SK_STEALTH
+ 100, // SK_STABBING
+ 100, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 100, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // SK_SPELLCASTING
+ 100, // SK_CONJURATIONS
+ 120, // SK_ENCHANTMENTS
+ 100, // SK_SUMMONINGS
+ 100, // SK_NECROMANCY
+ 100, // SK_TRANSLOCATIONS
+ 100, // SK_TRANSMIGRATION
+ 100, // SK_DIVINATIONS
+ 100, // SK_FIRE_MAGIC
+ 100, // SK_ICE_MAGIC
+ 100, // SK_AIR_MAGIC
+ 100, // SK_EARTH_MAGIC
+ 100, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 100, // SK_EVOCATIONS
+ },
+
+ { // SP_UNK1_DRACONIAN (28)
+ 90, // SK_FIGHTING
+ 100, // SK_SHORT_BLADES
+ 100, // SK_LONG_SWORDS
+ 100, // SK_UNUSED_1
+ 100, // SK_AXES
+ 100, // SK_MACES_FLAILS
+ 100, // SK_POLEARMS
+ 100, // SK_STAVES
+ 120, // SK_SLINGS
+ 120, // SK_BOWS
+ 120, // SK_CROSSBOWS
+ 120, // SK_DARTS
+ 120, // SK_THROWING
+ 200, // SK_ARMOUR
+ 120, // SK_DODGING
+ 120, // SK_STEALTH
+ 100, // SK_STABBING
+ 100, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 100, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // SK_SPELLCASTING
+ 100, // SK_CONJURATIONS
+ 120, // SK_ENCHANTMENTS
+ 100, // SK_SUMMONINGS
+ 100, // SK_NECROMANCY
+ 100, // SK_TRANSLOCATIONS
+ 100, // SK_TRANSMIGRATION
+ 100, // SK_DIVINATIONS
+ 100, // SK_FIRE_MAGIC
+ 100, // SK_ICE_MAGIC
+ 100, // SK_AIR_MAGIC
+ 100, // SK_EARTH_MAGIC
+ 100, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 100, // SK_EVOCATIONS
+ },
+
+ { // SP_UNK2_DRACONIAN (29)
+ 90, // SK_FIGHTING
+ 100, // SK_SHORT_BLADES
+ 100, // SK_LONG_SWORDS
+ 100, // SK_UNUSED_1
+ 100, // SK_AXES
+ 100, // SK_MACES_FLAILS
+ 100, // SK_POLEARMS
+ 100, // SK_STAVES
+ 120, // SK_SLINGS
+ 120, // SK_BOWS
+ 120, // SK_CROSSBOWS
+ 120, // SK_DARTS
+ 120, // SK_THROWING
+ 200, // SK_ARMOUR
+ 120, // SK_DODGING
+ 120, // SK_STEALTH
+ 100, // SK_STABBING
+ 100, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 100, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // SK_SPELLCASTING
+ 100, // SK_CONJURATIONS
+ 120, // SK_ENCHANTMENTS
+ 100, // SK_SUMMONINGS
+ 100, // SK_NECROMANCY
+ 100, // SK_TRANSLOCATIONS
+ 100, // SK_TRANSMIGRATION
+ 100, // SK_DIVINATIONS
+ 100, // SK_FIRE_MAGIC
+ 100, // SK_ICE_MAGIC
+ 100, // SK_AIR_MAGIC
+ 100, // SK_EARTH_MAGIC
+ 100, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 100, // SK_EVOCATIONS
+ },
+
+ { // SP_CENTAUR (30)
+ 100, // SK_FIGHTING
+ 120, // SK_SHORT_BLADES
+ 110, // SK_LONG_SWORDS
+ 110, // SK_UNUSED_1
+ 110, // SK_AXES
+ 110, // SK_MACES_FLAILS
+ 110, // SK_POLEARMS
+ 110, // SK_STAVES
+ 75, // SK_SLINGS
+ 60, // SK_BOWS
+ 85, // SK_CROSSBOWS
+ 80, // SK_DARTS
+ 60, // SK_THROWING
+ 180, // SK_ARMOUR
+ 170, // SK_DODGING
+ 200, // SK_STEALTH
+ 170, // SK_STABBING
+ 180, // SK_SHIELDS
+ 150, // SK_TRAPS_DOORS
+ 100, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 140, // SK_SPELLCASTING
+ 120, // SK_CONJURATIONS
+ 110, // SK_ENCHANTMENTS
+ 120, // SK_SUMMONINGS
+ 120, // SK_NECROMANCY
+ 120, // SK_TRANSLOCATIONS
+ 120, // SK_TRANSMIGRATION
+ 130, // SK_DIVINATIONS
+ 120, // SK_FIRE_MAGIC
+ 120, // SK_ICE_MAGIC
+ 120, // SK_AIR_MAGIC
+ 120, // SK_EARTH_MAGIC
+ 130, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 130, // SK_EVOCATIONS
+ },
+
+ { // SP_DEMIGOD (31)
+ 110, // SK_FIGHTING
+ 110, // SK_SHORT_BLADES
+ 110, // SK_LONG_SWORDS
+ 110, // SK_UNUSED_1
+ 110, // SK_AXES
+ 110, // SK_MACES_FLAILS
+ 110, // SK_POLEARMS
+ 110, // SK_STAVES
+ 110, // SK_SLINGS
+ 110, // SK_BOWS
+ 110, // SK_CROSSBOWS
+ 110, // SK_DARTS
+ 110, // SK_THROWING
+ 110, // SK_ARMOUR
+ 110, // SK_DODGING
+ 110, // SK_STEALTH
+ 110, // SK_STABBING
+ 110, // SK_SHIELDS
+ 110, // SK_TRAPS_DOORS
+ 110, // SK_UNARMED_COMBAT
+ 110, // undefined
+ 110, // undefined
+ 110, // undefined
+ 110, // undefined
+ 110, // undefined
+ 110, // SK_SPELLCASTING
+ 110, // SK_CONJURATIONS
+ 110, // SK_ENCHANTMENTS
+ 110, // SK_SUMMONINGS
+ 110, // SK_NECROMANCY
+ 110, // SK_TRANSLOCATIONS
+ 110, // SK_TRANSMIGRATION
+ 110, // SK_DIVINATIONS
+ 110, // SK_FIRE_MAGIC
+ 110, // SK_ICE_MAGIC
+ 110, // SK_AIR_MAGIC
+ 110, // SK_EARTH_MAGIC
+ 110, // SK_POISON_MAGIC
+ 110, // SK_INVOCATIONS
+ 110, // SK_EVOCATIONS
+ },
+
+ { // SP_SPRIGGAN (32)
+ 150, // SK_FIGHTING
+ 90, // SK_SHORT_BLADES
+ 140, // SK_LONG_SWORDS
+ 160, // SK_UNUSED_1
+ 150, // SK_AXES
+ 160, // SK_MACES_FLAILS
+ 180, // SK_POLEARMS
+ 150, // SK_STAVES
+ 70, // SK_SLINGS
+ 70, // SK_BOWS
+ 100, // SK_CROSSBOWS
+ 70, // SK_DARTS
+ 90, // SK_THROWING
+ 170, // SK_ARMOUR
+ 50, // SK_DODGING
+ 50, // SK_STEALTH
+ 50, // SK_STABBING
+ 180, // SK_SHIELDS
+ 60, // SK_TRAPS_DOORS
+ 130, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 60, // SK_SPELLCASTING
+ 160, // SK_CONJURATIONS
+ 50, // SK_ENCHANTMENTS
+ 150, // SK_SUMMONINGS
+ 120, // SK_NECROMANCY
+ 50, // SK_TRANSLOCATIONS
+ 60, // SK_TRANSMIGRATION
+ 70, // SK_DIVINATIONS
+ 140, // SK_FIRE_MAGIC
+ 140, // SK_ICE_MAGIC
+ 120, // SK_AIR_MAGIC
+ 120, // SK_EARTH_MAGIC
+ 100, // SK_POISON_MAGIC
+ 130, // SK_INVOCATIONS
+ 70, // SK_EVOCATIONS
+ },
+
+ { // SP_MINOTAUR (33)
+ 70, // SK_FIGHTING
+ 70, // SK_SHORT_BLADES
+ 70, // SK_LONG_SWORDS
+ 70, // SK_UNUSED_1
+ 70, // SK_AXES
+ 70, // SK_MACES_FLAILS
+ 70, // SK_POLEARMS
+ 70, // SK_STAVES
+ 90, // SK_SLINGS
+ 90, // SK_BOWS
+ 90, // SK_CROSSBOWS
+ 90, // SK_DARTS
+ 90, // SK_THROWING
+ 80, // SK_ARMOUR
+ 80, // SK_DODGING
+ 130, // SK_STEALTH
+ 100, // SK_STABBING
+ 80, // SK_SHIELDS
+ 120, // SK_TRAPS_DOORS
+ 80, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 180, // SK_SPELLCASTING
+ 170, // SK_CONJURATIONS
+ 170, // SK_ENCHANTMENTS
+ 170, // SK_SUMMONINGS
+ 170, // SK_NECROMANCY
+ 170, // SK_TRANSLOCATIONS
+ 170, // SK_TRANSMIGRATION
+ 170, // SK_DIVINATIONS
+ 170, // SK_FIRE_MAGIC
+ 170, // SK_ICE_MAGIC
+ 170, // SK_AIR_MAGIC
+ 170, // SK_EARTH_MAGIC
+ 170, // SK_POISON_MAGIC
+ 130, // SK_INVOCATIONS
+ 170, // SK_EVOCATIONS
+ },
+
+ { // SP_DEMONSPAN (34)
+ 100, // SK_FIGHTING
+ 110, // SK_SHORT_BLADES
+ 110, // SK_LONG_SWORDS
+ 110, // SK_UNUSED_1
+ 110, // SK_AXES
+ 110, // SK_MACES_FLAILS
+ 110, // SK_POLEARMS
+ 110, // SK_STAVES
+ 110, // SK_SLINGS
+ 110, // SK_BOWS
+ 110, // SK_CROSSBOWS
+ 110, // SK_DARTS
+ 110, // SK_THROWING
+ 110, // SK_ARMOUR
+ 110, // SK_DODGING
+ 110, // SK_STEALTH
+ 110, // SK_STABBING
+ 110, // SK_SHIELDS
+ 110, // SK_TRAPS_DOORS
+ 110, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // SK_SPELLCASTING
+ 100, // SK_CONJURATIONS
+ 110, // SK_ENCHANTMENTS
+ 100, // SK_SUMMONINGS
+ 90, // SK_NECROMANCY
+ 110, // SK_TRANSLOCATIONS
+ 110, // SK_TRANSMIGRATION
+ 110, // SK_DIVINATIONS
+ 100, // SK_FIRE_MAGIC
+ 110, // SK_ICE_MAGIC
+ 110, // SK_AIR_MAGIC
+ 110, // SK_EARTH_MAGIC
+ 100, // SK_POISON_MAGIC
+ 80, // SK_INVOCATIONS
+ 110, // SK_EVOCATIONS
+ },
+
+ { // SP_GHOUL (35)
+ 80, // SK_FIGHTING
+ 110, // SK_SHORT_BLADES
+ 110, // SK_LONG_SWORDS
+ 110, // SK_UNUSED_1
+ 110, // SK_AXES
+ 110, // SK_MACES_FLAILS
+ 110, // SK_POLEARMS
+ 110, // SK_STAVES
+ 130, // SK_SLINGS
+ 130, // SK_BOWS
+ 130, // SK_CROSSBOWS
+ 130, // SK_DARTS
+ 130, // SK_THROWING
+ 110, // SK_ARMOUR
+ 110, // SK_DODGING
+ 80, // SK_STEALTH
+ 100, // SK_STABBING
+ 110, // SK_SHIELDS
+ 120, // SK_TRAPS_DOORS
+ 80, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 120, // SK_SPELLCASTING
+ 130, // SK_CONJURATIONS
+ 130, // SK_ENCHANTMENTS
+ 120, // SK_SUMMONINGS
+ 100, // SK_NECROMANCY
+ 120, // SK_TRANSLOCATIONS
+ 120, // SK_TRANSMIGRATION
+ 120, // SK_DIVINATIONS
+ 150, // SK_FIRE_MAGIC
+ 90, // SK_ICE_MAGIC
+ 150, // SK_AIR_MAGIC
+ 90, // SK_EARTH_MAGIC
+ 100, // SK_POISON_MAGIC
+ 110, // SK_INVOCATIONS
+ 130, // SK_EVOCATIONS
+ },
+
+ { // SP_KENKU (36)
+ 100, // SK_FIGHTING
+ 75, // SK_SHORT_BLADES
+ 75, // SK_LONG_SWORDS
+ 75, // SK_UNUSED_1
+ 75, // SK_AXES
+ 75, // SK_MACES_FLAILS
+ 75, // SK_POLEARMS
+ 75, // SK_STAVES
+ 100, // SK_SLINGS
+ 80, // SK_BOWS
+ 80, // SK_CROSSBOWS
+ 90, // SK_DARTS
+ 90, // SK_THROWING
+ 90, // SK_ARMOUR
+ 90, // SK_DODGING
+ 100, // SK_STEALTH
+ 80, // SK_STABBING
+ 100, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 80, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // SK_SPELLCASTING
+ 60, // SK_CONJURATIONS
+ 160, // SK_ENCHANTMENTS
+ 70, // SK_SUMMONINGS
+ 80, // SK_NECROMANCY
+ 150, // SK_TRANSLOCATIONS
+ 150, // SK_TRANSMIGRATION
+ 180, // SK_DIVINATIONS
+ 90, // SK_FIRE_MAGIC
+ 120, // SK_ICE_MAGIC
+ 90, // SK_AIR_MAGIC
+ 120, // SK_EARTH_MAGIC
+ 100, // SK_POISON_MAGIC
+ 160, // SK_INVOCATIONS
+ 100, // SK_EVOCATIONS
+ },
+
+ { // SP_MERFOLK (37)
+ 80, // SK_FIGHTING
+ 70, // SK_SHORT_BLADES
+ 90, // SK_LONG_SWORDS
+ 100, // SK_UNUSED_1
+ 140, // SK_AXES
+ 150, // SK_MACES_FLAILS
+ 50, // SK_POLEARMS
+ 130, // SK_STAVES
+ 150, // SK_SLINGS
+ 140, // SK_BOWS
+ 140, // SK_CROSSBOWS
+ 100, // SK_DARTS
+ 100, // SK_THROWING
+ 160, // SK_ARMOUR
+ 60, // SK_DODGING
+ 90, // SK_STEALTH
+ 70, // SK_STABBING
+ 100, // SK_SHIELDS
+ 120, // SK_TRAPS_DOORS
+ 90, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // SK_SPELLCASTING
+ 140, // SK_CONJURATIONS
+ 90, // SK_ENCHANTMENTS
+ 100, // SK_SUMMONINGS
+ 150, // SK_NECROMANCY
+ 140, // SK_TRANSLOCATIONS
+ 60, // SK_TRANSMIGRATION
+ 80, // SK_DIVINATIONS
+ 160, // SK_FIRE_MAGIC
+ 80, // SK_ICE_MAGIC
+ 150, // SK_AIR_MAGIC
+ 150, // SK_EARTH_MAGIC
+ 80, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 100, // SK_EVOCATIONS
+ },
+
+
+
+/* ******************************************************
+
+// base draconian
+ {
+ 90, // SK_FIGHTING
+ 100, // SK_SHORT_BLADES
+ 100, // SK_LONG_SWORDS
+ 100, // SK_UNUSED_1
+ 100, // SK_AXES
+ 100, // SK_MACES_FLAILS
+ 100, // SK_POLEARMS
+ 100, // SK_STAVES
+ 120, // SK_SLINGS
+ 120, // SK_BOWS
+ 120, // SK_CROSSBOWS
+ 120, // SK_DARTS
+ 120, // SK_THROWING
+ 200, // SK_ARMOUR
+ 120, // SK_DODGING
+ 120, // SK_STEALTH
+ 100, // SK_STABBING
+ 100, // SK_SHIELDS
+ 100, // SK_TRAPS_DOORS
+ 100, // SK_UNARMED_COMBAT
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // undefined
+ 100, // SK_SPELLCASTING
+ 100, // SK_CONJURATIONS
+ 120, // SK_ENCHANTMENTS
+ 100, // SK_SUMMONINGS
+ 100, // SK_NECROMANCY
+ 100, // SK_TRANSLOCATIONS
+ 100, // SK_TRANSMIGRATION
+ 100, // SK_DIVINATIONS
+ 100, // SK_FIRE_MAGIC
+ 100, // SK_ICE_MAGIC
+ 100, // SK_AIR_MAGIC
+ 100, // SK_EARTH_MAGIC
+ 100, // SK_POISON_MAGIC
+ 100, // SK_INVOCATIONS
+ 100, // SK_EVOCATIONS
+ },
+
+****************************************************** */
+
+};
+
+
+
+
+/* *************************************************************
+
+// these were unimplemented "level titles" for two classes {dlb}
+
+JOB_PRIEST
+ "Preacher";
+ "Priest";
+ "Evangelist";
+ "Pontifex";
+
+JOB_PALADIN:
+ "Holy Warrior";
+ "Holy Crusader";
+ "Paladin";
+ "Scourge of Evil";
+
+************************************************************* */
+
+void show_skills(void)
+{
+ int i;
+ int x;
+ char lcount;
+
+ const int num_lines = get_number_of_lines();
+
+#ifdef DOS_TERM
+ window(1, 1, 80, 25);
+ char buffer[4600];
+
+ gettext(1, 1, 80, 25, buffer);
+#endif
+
+ clrscr();
+
+ reprint_stuff:
+ lcount = 'a';
+
+ gotoxy(1, 1);
+ textcolor(LIGHTGREY);
+
+#if DEBUG_DIAGNOSTICS
+ cprintf( "You have %d points of unallocated experience (cost lvl %d; total %d)." EOL EOL,
+ you.exp_available, you.skill_cost_level, you.total_skill_points );
+#else
+ cprintf(" You have %d points of unallocated experience." EOL EOL,
+ you.exp_available );
+#endif
+
+ char scrln = 3, scrcol = 1;
+
+ // Don't want the help line to appear too far down a big window.
+ int bottom_line = ((num_lines > 30) ? 30 : num_lines);
+
+ for (x = 0; x < NUM_SKILLS; x++)
+ {
+ /* spells in second column */
+ if ((x == SK_SPELLCASTING && scrcol != 40) || scrln > bottom_line - 3)
+ {
+ scrln = 3;
+ scrcol = 40;
+ }
+
+ gotoxy(scrcol, scrln);
+
+#if DEBUG_DIAGNOSTICS
+ // In diagnostic mode we show skills at 0, but only real skills
+ if (x != SK_UNUSED_1 && (x <= SK_UNARMED_COMBAT || x >= SK_SPELLCASTING))
+#else
+ if (you.skills[x] > 0)
+#endif
+ {
+ if (you.practise_skill[x] == 0 || you.skills[x] == 0)
+ textcolor(DARKGREY);
+ else
+ textcolor(LIGHTGREY);
+
+ if (you.skills[x] == 27)
+ textcolor(YELLOW);
+
+#if DEBUG_DIAGNOSTICS
+ if (you.skills[x] == 0)
+ putch(' ');
+ else
+ {
+ putch(lcount);
+ if (lcount == 'z')
+ lcount = 'A';
+ else
+ lcount++;
+ }
+#else
+ putch(lcount);
+ if (lcount == 'z')
+ lcount = 'A';
+ else
+ lcount++;
+#endif
+
+ cprintf( " %c %-14s Skill %2d",
+ (you.skills[x] == 0) ? ' ' :
+ (you.practise_skill[x] == 0) ? '-' : '+',
+ skills[x][0], you.skills[x] );
+
+ textcolor(BLUE);
+
+#if DEBUG_DIAGNOSTICS
+ cprintf( " %5d", you.skill_points[x] );
+#endif
+
+ if (you.skills[x] < 27)
+ {
+ const int needed = skill_exp_needed(you.skills[x] + 2);
+ const int prev_needed = skill_exp_needed(you.skills[x] + 1);
+ const int spec_abil = species_skills(x, you.species);
+
+ cprintf( " (%d)",
+ (((needed * spec_abil) / 100 - you.skill_points[x]) * 10) /
+ (((needed - prev_needed) * spec_abil) / 100) );
+ }
+
+ scrln++;
+ }
+
+ /* Extra CR between classes of weapons and such things */
+ if (x == SK_STAVES || x == SK_THROWING || x == SK_TRAPS_DOORS
+ || x == SK_UNARMED_COMBAT || x == SK_POISON_MAGIC)
+ {
+ scrln++;
+ }
+ }
+
+ // if any more skills added, must adapt letters to go into caps
+ gotoxy(1, bottom_line);
+ textcolor(LIGHTGREY);
+ cprintf("Press the letter of a skill to choose whether you want to practise it.");
+
+ char get_thing;
+
+ get_thing = getch();
+
+ if (get_thing == 0)
+ getch();
+ else
+ {
+ if ((get_thing >= 'a' && get_thing <= 'z')
+ || (get_thing >= 'A' && get_thing <= 'Z'))
+ {
+ lcount = 'a'; // toggle skill practise
+
+ for (i = 0; i < 50; i++)
+ {
+ if (you.skills[i] == 0)
+ continue;
+
+ if (get_thing == lcount)
+ {
+ you.practise_skill[i] = (you.practise_skill[i]) ? 0 : 1;
+ break;
+ }
+
+ if (lcount == 'z')
+ lcount = 'A';
+ else
+ lcount++;
+ }
+
+ goto reprint_stuff;
+ }
+ }
+
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+#endif
+ return;
+}
+
+
+const char *skill_name(unsigned char which_skill)
+{
+ return (skills[which_skill][0]);
+} // end skill_name()
+
+
+const char *skill_title( unsigned char best_skill, unsigned char skill_lev,
+ int species, int str, int dex, int god )
+{
+ unsigned char skill_rank;
+ const char *tempstr = NULL;
+
+ static char title_buff[80];
+
+ // paranoia
+ if (best_skill == SK_UNUSED_1
+ || (best_skill > SK_UNARMED_COMBAT && best_skill < SK_SPELLCASTING)
+ || best_skill >= NUM_SKILLS)
+ {
+ return ("Adventurer");
+ }
+
+ if (species == -1)
+ species = you.species;
+
+ if (str == -1)
+ str = you.strength;
+
+ if (dex == -1)
+ dex = you.dex;
+
+ if (god == -1)
+ god = you.religion;
+
+ // translate skill level into skill ranking {dlb}:
+ // increment rank by one to "skip" skill name in array {dlb}:
+ skill_rank = ((skill_lev <= 7) ? 1 :
+ (skill_lev <= 14) ? 2 :
+ (skill_lev <= 20) ? 3 :
+ (skill_lev <= 26) ? 4
+ /* level 27 */ : 5);
+
+ if (best_skill < NUM_SKILLS)
+ {
+ // Note that ghosts default to (dex == str) and god == no_god, due
+ // to a current lack of that information... the god case is probably
+ // suitable for most cases (TSO/Zin/Ely at the very least). -- bwr
+ switch (best_skill)
+ {
+ case SK_UNARMED_COMBAT:
+ tempstr = (dex >= str) ? martial_arts_titles[skill_rank]
+ : skills[best_skill][skill_rank];
+
+ break;
+
+ case SK_INVOCATIONS:
+ if (god == GOD_NO_GOD)
+ tempstr = "Godless";
+ else
+ tempstr = skills[best_skill][skill_rank];
+ break;
+
+ default:
+ tempstr = skills[best_skill][skill_rank];
+ break;
+ }
+ }
+
+ const char *const ptr = strchr( tempstr, '%' );
+ const bool species_found = (ptr != NULL);
+
+ if (species_found)
+ {
+ // need species name
+ snprintf( title_buff, sizeof(title_buff), tempstr,
+ species_name(species, 0, true,
+ (ptr == tempstr && best_skill != SK_NECROMANCY)) );
+ // The above code only capitalises start-of-string racenames
+ tempstr = title_buff;
+ }
+
+ return ((tempstr == NULL) ? "Invalid Title" : tempstr);
+} // end skill_title()
+
+const char *player_title( void )
+{
+ const unsigned char best = best_skill( SK_FIGHTING, (NUM_SKILLS - 1), 99 );
+
+ return (skill_title( best, you.skills[ best ] ));
+} // end player_title()
+
+unsigned char best_skill( unsigned char min_skill, unsigned char max_skill,
+ unsigned char excl_skill )
+{
+ unsigned char ret = SK_FIGHTING;
+ unsigned int best_skill_level = 0;
+ unsigned int best_position = 1000;
+
+ for (int i = min_skill; i <= max_skill; i++) // careful!!!
+ {
+ if (i == excl_skill
+ || i == SK_UNUSED_1
+ || (i > SK_UNARMED_COMBAT && i < SK_SPELLCASTING))
+ {
+ continue;
+ }
+
+ if (you.skills[i] > best_skill_level)
+ {
+ ret = i;
+ best_skill_level = you.skills[i];
+ best_position = you.skill_order[i];
+
+ }
+ else if (you.skills[i] == best_skill_level
+ && you.skill_order[i] < best_position)
+ {
+ ret = i;
+ best_position = you.skill_order[i];
+ }
+ }
+
+ return (ret);
+} // end best_skill()
+
+// Calculate the skill_order array from scratch.
+//
+// The skill order array is used for breaking ties in best_skill.
+// This is done by ranking each skill by the order in which it
+// has attained its current level (the values are the number of
+// skills at or above that level when the current skill reached it).
+//
+// In this way, the skill which has been at a level for the longest
+// is judged to be the best skill (thus, nicknames are sticky)...
+// other skills will have to attain the next level higher to be
+// considered a better skill (thus, the first skill to reach level 27
+// becomes the characters final nickname).
+//
+// As for other uses of best_skill: this method is still appropriate
+// in that there is no additional advantage anywhere else in the game
+// for partial skill levels. Besides, its probably best if the player
+// isn't able to micromanage at that level. -- bwr
+void init_skill_order( void )
+{
+ for (int i = SK_FIGHTING; i < NUM_SKILLS; i++)
+ {
+ if (i == SK_UNUSED_1
+ || (i > SK_UNARMED_COMBAT && i < SK_SPELLCASTING))
+ {
+ you.skill_order[i] = MAX_SKILL_ORDER;
+ continue;
+ }
+
+ const int i_diff = species_skills( i, you.species );
+ const unsigned int i_points = (you.skill_points[i] * 100) / i_diff;
+
+ you.skill_order[i] = 0;
+
+ for (int j = SK_FIGHTING; j < NUM_SKILLS; j++)
+ {
+ if (i == j
+ || j == SK_UNUSED_1
+ || (j > SK_UNARMED_COMBAT && j < SK_SPELLCASTING))
+ {
+ continue;
+ }
+
+ const int j_diff = species_skills( j, you.species );
+ const unsigned int j_points = (you.skill_points[j] * 100) / j_diff;
+
+ if (you.skills[j] == you.skills[i]
+ && (j_points > i_points
+ || (j_points == i_points && j > i)))
+ {
+ you.skill_order[i]++;
+ }
+ }
+ }
+}
+
+int calc_hp(void)
+{
+ int hitp;
+
+ hitp = (you.base_hp - 5000) + (you.base_hp2 - 5000);
+ hitp += (you.experience_level * you.skills[SK_FIGHTING]) / 5;
+
+ // being berserk makes you resistant to damage. I don't know why.
+ if (you.berserker)
+ {
+ hitp *= 15;
+ hitp /= 10;
+ }
+
+ // some transformations give you extra hp
+ switch (you.attribute[ATTR_TRANSFORMATION])
+ {
+ case TRAN_STATUE:
+ hitp *= 15;
+ hitp /= 10;
+ break;
+ case TRAN_ICE_BEAST:
+ hitp *= 12;
+ hitp /= 10;
+ break;
+ case TRAN_DRAGON:
+ hitp *= 16;
+ hitp /= 10;
+ break;
+ }
+
+ // frail and robust mutations
+ hitp *= (10 + you.mutation[MUT_ROBUST] - you.mutation[MUT_FRAIL]);
+ hitp /= 10;
+
+ you.hp_max = hitp;
+
+ deflate_hp( you.hp_max, false );
+
+ return (hitp);
+} // end calc_hp()
+
+
+int calc_mp(void)
+{
+ int enp;
+
+ // base_magic_points2 accounts for species and magic potions
+ enp = (you.base_magic_points2 - 5000);
+
+ int spell_extra = (you.experience_level * you.skills[SK_SPELLCASTING]) / 4;
+ int invoc_extra = (you.experience_level * you.skills[SK_INVOCATIONS]) / 6;
+ int evoc_extra = (you.experience_level * you.skills[SK_EVOCATIONS]) / 6;
+
+ if (spell_extra > invoc_extra && spell_extra > evoc_extra)
+ enp += spell_extra;
+ else if (invoc_extra > evoc_extra)
+ enp += invoc_extra;
+ else
+ enp += evoc_extra;
+
+ you.max_magic_points = stepdown_value( enp, 9, 18, 45, 100 );
+
+ // this is our "rotted" base (applied after scaling):
+ you.max_magic_points += (you.base_magic_points - 5000);
+
+ // Yes, we really do want this duplication... this is so the stepdown
+ // doesn't truncate before we apply the rotted base. We're doing this
+ // the nice way. -- bwr
+ if (you.max_magic_points > 50)
+ you.max_magic_points = 50;
+
+ // now applied after scaling so that power items are more useful -- bwr
+ you.max_magic_points += player_magical_power();
+
+ if (you.max_magic_points > 50)
+ you.max_magic_points = 50 + ((you.max_magic_points - 50) / 2);
+
+ if (you.max_magic_points < 0)
+ you.max_magic_points = 0;
+
+ if (you.magic_points > you.max_magic_points)
+ you.magic_points = you.max_magic_points;
+
+ you.redraw_magic_points = 1;
+
+ return (you.max_magic_points);
+} // end calc_mp()
+
+
+unsigned int skill_exp_needed(int lev)
+{
+ lev--;
+ switch (lev)
+ {
+ case 0:
+ return 0; // old: 0
+ case 1:
+ return 200; // old: 20
+ case 2:
+ return 300; // old: 30
+ case 3:
+ return 500; // old: 50
+ case 4:
+ return 750; // old: 75
+ case 5:
+ return 1050; // old: 105
+ case 6:
+ return 1350; // old: 145
+ case 7:
+ return 1700; // old: 200
+ case 8:
+ return 2100; // old: 275
+ case 9:
+ return 2550; // old: 355
+ case 10:
+ return 3150; // old: 440
+ case 11:
+ return 3750; // old: 560
+ case 12:
+ return 4400; // old: 680
+ case 13:
+ return 5250; // old: 850
+ default:
+ return 6200 + 1800 * (lev - 14);
+ // old: 1100 + 300 * (lev - 14)
+ // older: 1200 * (lev - 11) + ((lev - 11) * (lev - 11));// * (lev - 11))
+ }
+
+ return 0;
+}
+
+
+int species_skills(char skill, char species)
+{
+ // Spellcasting is more expensive, invocations and evocations are cheaper
+ if (skill == SK_SPELLCASTING)
+ return (spec_skills[species - 1][skill] * 130) / 100;
+ else if (skill == SK_INVOCATIONS || skill == SK_EVOCATIONS)
+ return (spec_skills[species - 1][skill] * 75) / 100;
+ else
+ return (spec_skills[species - 1][skill]);
+} // end species_skills()
+
+// new: inform player if they need more throwing skill (GDL)
+void wield_warning(bool newWeapon)
+{
+ // hold weapon name
+ char wepstr[ITEMNAME_SIZE];
+ char wepstr2[ITEMNAME_SIZE];
+
+ // early out - no weapon
+ if (you.equip[EQ_WEAPON] == -1)
+ return;
+
+ if (newWeapon)
+ strcpy(wepstr, "this ");
+ else
+ strcpy(wepstr, "your ");
+
+ int wepType = you.inv[you.equip[EQ_WEAPON]].sub_type;
+
+ // early out - don't warn for non-weapons
+ if (you.inv[you.equip[EQ_WEAPON]].base_type != OBJ_WEAPONS)
+ return;
+
+ // put the standard wep name in.
+ standard_name_weap(wepType, wepstr2);
+ strcat(wepstr, wepstr2);
+
+ // only warn about str/dex for non-launcher weapons
+ if (!launches_things(wepType))
+ {
+#ifdef USE_NEW_COMBAT_STATS
+ const int stat_bonus = effective_stat_bonus();
+
+ if (stat_bonus <= -4)
+ {
+ if (you.strength < you.dex)
+ {
+ if (you.strength < 11)
+ snprintf( info, INFO_SIZE, "You have %strouble swinging %s.",
+ (you.strength < 7)?"":"a little ", wepstr);
+ else
+ snprintf( info, INFO_SIZE, "You'd be more effective with "
+ "%s if you were stronger.", wepstr);
+ }
+ else
+ {
+ if (you.dex < 11)
+ {
+ snprintf( info, INFO_SIZE, "Wielding %s is %s awkward.",
+ wepstr, (you.dex < 7) ? "fairly" : "a little" );
+ }
+ else
+ {
+ snprintf( info, INFO_SIZE, "You'd be more effective with "
+ "%s if you were nimbler.", wepstr );
+ }
+ }
+
+ mpr( info, MSGCH_WARN );
+ }
+#endif
+ return;
+ }
+
+ // must be a launcher
+ int effSkill = you.skills[SK_THROWING] * 2 + 1;
+ int shoot_skill = 0;
+
+ switch (wepType)
+ {
+ case WPN_SLING:
+ shoot_skill = you.skills[SK_SLINGS];
+ break;
+ case WPN_BOW:
+ shoot_skill = you.skills[SK_BOWS];
+ break;
+ case WPN_CROSSBOW:
+ case WPN_HAND_CROSSBOW:
+ shoot_skill = you.skills[SK_CROSSBOWS];
+ break;
+ case WPN_BLOWGUN:
+ shoot_skill = you.skills[SK_DARTS];
+ break;
+ default:
+ shoot_skill = 0;
+ break;
+ }
+
+ if (shoot_skill > effSkill)
+ {
+ strcpy( info, "Your low throwing skill limits the effectiveness of ");
+ strcat( info, wepstr );
+ mpr( info, MSGCH_WARN );
+ }
+}
diff --git a/trunk/source/skills2.h b/trunk/source/skills2.h
new file mode 100644
index 0000000000..606a95a17d
--- /dev/null
+++ b/trunk/source/skills2.h
@@ -0,0 +1,95 @@
+/*
+ * File: skills2.cc
+ * Summary: More skill related functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <2> -/--/-- WL Extensive mods from Wladimir van der Laan.
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef SKILLS2_H
+#define SKILLS2_H
+
+#include <stddef.h> // For NULL
+
+#define MAX_SKILL_ORDER 100
+
+// last_updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: chardump - it_use3 - itemname - skills
+ * *********************************************************************** */
+const char *skill_name(unsigned char which_skill);
+
+
+// last_updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: describe
+ * *********************************************************************** */
+const char * skill_title( unsigned char best_skill, unsigned char skill_lev,
+ // these used for ghosts and hiscores:
+ int species = -1, int str = -1, int dex = -1, int god = -1 );
+
+// last_updated Sept 20 -- bwr
+/* ***********************************************************************
+ * called from: acr - chardump - player - skills - stuff
+ * *********************************************************************** */
+const char *player_title( void );
+
+
+// last_updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - chardump - effects - files - player - skills -
+ * skills2 - stuff
+ * *********************************************************************** */
+unsigned char best_skill(unsigned char min_skill, unsigned char max_skill, unsigned char excl_skill);
+
+void init_skill_order( void );
+
+
+// last_updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - it_use2 - item_use - newgame - ouch - player - skills
+ * *********************************************************************** */
+int calc_mp(void);
+
+
+// last_updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - acr - food - it_use2 - misc - mutation -
+ * newgame - ouch - player - skills - spells1 - transfor
+ * *********************************************************************** */
+int calc_hp(void);
+
+
+// last_updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: newgame - skills - skills2
+ * *********************************************************************** */
+int species_skills(char skill, char species);
+
+
+// last_updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: newgame - skills - skills2
+ * *********************************************************************** */
+unsigned int skill_exp_needed(int lev);
+
+
+// last_updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void show_skills(void);
+
+
+// last_updated 14jan2001 {gdl}
+/* ***********************************************************************
+ * called from: item_use
+ * *********************************************************************** */
+void wield_warning(bool newWeapon = true);
+
+
+#endif
diff --git a/trunk/source/spells1.cc b/trunk/source/spells1.cc
new file mode 100644
index 0000000000..64bb5630f0
--- /dev/null
+++ b/trunk/source/spells1.cc
@@ -0,0 +1,1058 @@
+/*
+ * File: spells1.cc
+ * Summary: Implementations of some additional spells.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <4> 06-mar-2000 bwr confusing_touch, sure_blade
+ * <3> 9/11/99 LRH Can't blink in the Abyss
+ * <3> 6/22/99 BWR Removed teleport control from
+ * random_blink().
+ * <2> 5/20/99 BWR Increased greatest healing.
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "spells1.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "externs.h"
+
+#include "abyss.h"
+#include "beam.h"
+#include "cloud.h"
+#include "direct.h"
+#include "invent.h"
+#include "it_use2.h"
+#include "itemname.h"
+#include "misc.h"
+#include "monplace.h"
+#include "monstuff.h"
+#include "mon-util.h"
+#include "player.h"
+#include "skills2.h"
+#include "spells3.h"
+#include "spells4.h"
+#include "spl-util.h"
+#include "stuff.h"
+#include "view.h"
+#include "wpn-misc.h"
+
+void blink(void)
+{
+ struct dist beam;
+
+ // yes, there is a logic to this ordering {dlb}:
+ if (scan_randarts(RAP_PREVENT_TELEPORTATION))
+ mpr("You feel a weird sense of stasis.");
+ else if (you.level_type == LEVEL_ABYSS && !one_chance_in(3))
+ mpr("The power of the Abyss keeps you in your place!");
+ else if (you.conf)
+ random_blink(false);
+ else if (!allow_control_teleport(true))
+ {
+ mpr("A powerful magic interferes with your control of the blink.");
+ random_blink(false);
+ }
+ else
+ {
+ // query for location {dlb}:
+ for (;;)
+ {
+ mpr("Blink to where?", MSGCH_PROMPT);
+
+ direction( beam, DIR_TARGET );
+
+ if (!beam.isValid)
+ {
+ canned_msg(MSG_SPELL_FIZZLES);
+ return; // early return {dlb}
+ }
+
+ if (see_grid(beam.tx, beam.ty))
+ break;
+ else
+ {
+ mesclr();
+ mpr("You can't blink there!");
+ }
+ }
+
+ if (grd[beam.tx][beam.ty] <= DNGN_LAST_SOLID_TILE
+ || mgrd[beam.tx][beam.ty] != NON_MONSTER)
+ {
+ mpr("Oops! Maybe something was there already.");
+ random_blink(false);
+ }
+ else if (you.level_type == LEVEL_ABYSS)
+ {
+ abyss_teleport( false );
+ you.pet_target = MHITNOT;
+ }
+ else
+ {
+ you.x_pos = beam.tx;
+ you.y_pos = beam.ty;
+
+ // controlling teleport contaminates the player -- bwr
+ contaminate_player( 1 );
+ }
+
+ if (you.duration[DUR_CONDENSATION_SHIELD] > 0)
+ {
+ you.duration[DUR_CONDENSATION_SHIELD] = 0;
+ you.redraw_armour_class = 1;
+ }
+ }
+
+ return;
+} // end blink()
+
+void random_blink(bool allow_partial_control)
+{
+ int tx, ty;
+ bool succ = false;
+
+ if (scan_randarts(RAP_PREVENT_TELEPORTATION))
+ mpr("You feel a weird sense of stasis.");
+ else if (you.level_type == LEVEL_ABYSS && !one_chance_in(3))
+ {
+ mpr("The power of the Abyss keeps you in your place!");
+ }
+ else if (!random_near_space(you.x_pos, you.y_pos, tx, ty))
+ {
+ mpr("You feel jittery for a moment.");
+ }
+
+#ifdef USE_SEMI_CONTROLLED_BLINK
+ //jmf: add back control, but effect is cast_semi_controlled_blink(pow)
+ else if (you.attribute[ATTR_CONTROL_TELEPORT] && !you.conf
+ && allow_partial_control && allow_control_teleport())
+ {
+ mpr("You may select the general direction of your translocation.");
+ cast_semi_controlled_blink(100);
+ succ = true;
+ }
+#endif
+
+ else
+ {
+ mpr("You blink.");
+
+ succ = true;
+ you.x_pos = tx;
+ you.y_pos = ty;
+
+ if (you.level_type == LEVEL_ABYSS)
+ {
+ abyss_teleport( false );
+ you.pet_target = MHITNOT;
+ }
+ }
+
+ if (succ && you.duration[DUR_CONDENSATION_SHIELD] > 0)
+ {
+ you.duration[DUR_CONDENSATION_SHIELD] = 0;
+ you.redraw_armour_class = 1;
+ }
+
+ return;
+} // end random_blink()
+
+void fireball(int power)
+{
+ struct dist fire_ball;
+
+ mpr( STD_DIRECTION_PROMPT, MSGCH_PROMPT );
+
+ message_current_target();
+
+ direction( fire_ball, DIR_NONE, TARG_ENEMY );
+
+ if (!fire_ball.isValid)
+ canned_msg(MSG_SPELL_FIZZLES);
+ else
+ {
+ struct bolt beam;
+
+ beam.source_x = you.x_pos;
+ beam.source_y = you.y_pos;
+ beam.target_x = fire_ball.tx;
+ beam.target_y = fire_ball.ty;
+
+ zapping(ZAP_FIREBALL, power, beam);
+ }
+
+ return;
+} // end fireball()
+
+void cast_fire_storm(int powc)
+{
+ struct bolt beam;
+ struct dist targ;
+
+ mpr("Where?");
+
+ direction( targ, DIR_TARGET, TARG_ENEMY );
+
+ beam.target_x = targ.tx;
+ beam.target_y = targ.ty;
+
+ if (!targ.isValid)
+ {
+ canned_msg(MSG_SPELL_FIZZLES);
+ return;
+ }
+
+ beam.ex_size = 2 + (random2(powc) > 75);
+ beam.flavour = BEAM_LAVA;
+ beam.type = SYM_ZAP;
+ beam.colour = RED;
+ beam.beam_source = MHITYOU;
+ beam.thrower = KILL_YOU_MISSILE;
+ beam.aux_source = NULL;
+ beam.obviousEffect = false;
+ beam.isBeam = false;
+ beam.isTracer = false;
+ beam.ench_power = powc; // used for radius
+ strcpy( beam.beam_name, "great blast of fire" );
+ beam.hit = 20 + powc / 10;
+ beam.damage = calc_dice( 6, 15 + powc );
+
+ explosion( beam );
+ mpr("A raging storm of fire appears!");
+
+ viewwindow(1, false);
+} // end cast_fire_storm()
+
+void identify(int power)
+{
+ int id_used = 1;
+ int item_slot;
+ char str_pass[ ITEMNAME_SIZE ];
+
+ // scrolls of identify *may* produce "extra" identifications {dlb}:
+ if (power == -1 && one_chance_in(5))
+ id_used += (coinflip()? 1 : 2);
+
+ do
+ {
+ item_slot = prompt_invent_item( "Identify which item?", -1, true,
+ false, false );
+ if (item_slot == PROMPT_ABORT)
+ {
+ canned_msg( MSG_OK );
+ return;
+ }
+
+ set_ident_type( you.inv[item_slot].base_type,
+ you.inv[item_slot].sub_type, ID_KNOWN_TYPE );
+
+ set_ident_flags( you.inv[item_slot], ISFLAG_IDENT_MASK );
+
+ // output identified item
+ in_name( item_slot, DESC_INVENTORY_EQUIP, str_pass );
+ mpr( str_pass );
+
+ if (item_slot == you.equip[EQ_WEAPON])
+ you.wield_change = true;
+
+ id_used--;
+ }
+ while (id_used > 0);
+} // end identify()
+
+void conjure_flame(int pow)
+{
+ struct dist spelld;
+
+ bool done_first_message = false;
+
+ for (;;)
+ {
+ if (done_first_message)
+ mpr("Where would you like to place the cloud?", MSGCH_PROMPT);
+ else
+ {
+ mpr("You cast a flaming cloud spell! But where?", MSGCH_PROMPT);
+ done_first_message = true;
+ }
+
+ direction( spelld, DIR_TARGET, TARG_ENEMY );
+
+ if (!spelld.isValid)
+ {
+ canned_msg(MSG_SPELL_FIZZLES);
+ return;
+ }
+
+ if (!see_grid(spelld.tx, spelld.ty))
+ {
+ mpr("You can't see that place!");
+ continue;
+ }
+
+ if (grd[ spelld.tx ][ spelld.ty ] <= DNGN_LAST_SOLID_TILE
+ || mgrd[ spelld.tx ][ spelld.ty ] != NON_MONSTER
+ || env.cgrid[ spelld.tx ][ spelld.ty ] != EMPTY_CLOUD)
+ {
+ mpr( "There's already something there!" );
+ continue;
+ }
+
+ break;
+ }
+
+ int durat = 5 + (random2(pow) / 2) + (random2(pow) / 2);
+
+ if (durat > 23)
+ durat = 23;
+
+ place_cloud( CLOUD_FIRE, spelld.tx, spelld.ty, durat );
+} // end cast_conjure_flame()
+
+void stinking_cloud( int pow )
+{
+ struct dist spelld;
+ struct bolt beem;
+
+ mpr( STD_DIRECTION_PROMPT, MSGCH_PROMPT );
+
+ message_current_target();
+
+ direction( spelld, DIR_NONE, TARG_ENEMY );
+
+ if (!spelld.isValid)
+ {
+ canned_msg(MSG_SPELL_FIZZLES);
+ return;
+ }
+
+ beem.target_x = spelld.tx;
+ beem.target_y = spelld.ty;
+
+ beem.source_x = you.x_pos;
+ beem.source_y = you.y_pos;
+
+ strcpy(beem.beam_name, "ball of vapour");
+ beem.colour = GREEN;
+ beem.range = 6;
+ beem.rangeMax = 6;
+ beem.damage = dice_def( 1, 0 );
+ beem.hit = 20;
+ beem.type = SYM_ZAP;
+ beem.flavour = BEAM_MMISSILE;
+ beem.ench_power = pow;
+ beem.beam_source = MHITYOU;
+ beem.thrower = KILL_YOU;
+ beem.aux_source = NULL;
+ beem.isBeam = false;
+ beem.isTracer = false;
+
+ fire_beam(beem);
+} // end stinking_cloud()
+
+void cast_big_c(int pow, char cty)
+{
+ struct dist cdis;
+
+ mpr("Where do you want to put it?", MSGCH_PROMPT);
+ direction( cdis, DIR_TARGET, TARG_ENEMY );
+
+ if (!cdis.isValid)
+ {
+ canned_msg(MSG_SPELL_FIZZLES);
+ return;
+ }
+
+ big_cloud( cty, cdis.tx, cdis.ty, pow, 8 + random2(3) );
+} // end cast_big_c()
+
+void big_cloud(char clouds, char cl_x, char cl_y, int pow, int size)
+{
+ apply_area_cloud(make_a_normal_cloud, cl_x, cl_y, pow, size, clouds);
+} // end big_cloud()
+
+static char healing_spell( int healed )
+{
+ int mgr = 0;
+ struct monsters *monster = 0; // NULL {dlb}
+ struct dist bmove;
+
+ mpr("Which direction?", MSGCH_PROMPT);
+ direction( bmove, DIR_DIR, TARG_FRIEND );
+
+ if (!bmove.isValid)
+ {
+ canned_msg( MSG_HUH );
+ return 0;
+ }
+
+ mgr = mgrd[you.x_pos + bmove.dx][you.y_pos + bmove.dy];
+
+ if (bmove.dx == 0 && bmove.dy == 0)
+ {
+ mpr("You are healed.");
+ inc_hp(healed, false);
+ return 1;
+ }
+
+ if (mgr == NON_MONSTER)
+ {
+ mpr("There isn't anything there!");
+ return -1;
+ }
+
+ monster = &menv[mgr];
+
+ if (heal_monster(monster, healed, false))
+ {
+ strcpy(info, "You heal ");
+ strcat(info, ptr_monam( monster, DESC_NOCAP_THE ));
+ strcat(info, ".");
+ mpr(info);
+
+ if (monster->hit_points == monster->max_hit_points)
+ simple_monster_message( monster, " is completely healed." );
+ else
+ print_wounds(monster);
+ }
+ else
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ }
+
+ return 1;
+} // end healing_spell()
+
+#if 0
+char cast_lesser_healing( int pow )
+{
+ return healing_spell(5 + random2avg(7, 2));
+} // end lesser healing()
+
+char cast_greater_healing( int pow )
+{
+ return healing_spell(15 + random2avg(29, 2));
+} // end cast_greater_healing()
+
+char cast_greatest_healing( int pow )
+{
+ return healing_spell(50 + random2avg(49, 2));
+} // end cast_greatest_healing()
+#endif
+
+char cast_healing( int pow )
+{
+ if (pow > 50)
+ pow = 50;
+
+ return (healing_spell( pow + roll_dice( 2, pow ) - 2 ));
+}
+
+bool cast_revivification(int power)
+{
+ int loopy = 0; // general purpose loop variable {dlb}
+ bool success = false;
+ int loss = 0;
+
+ if (you.hp == you.hp_max)
+ canned_msg(MSG_NOTHING_HAPPENS);
+ else if (you.hp_max < 21)
+ mpr("You lack the resilience to cast this spell.");
+ else
+ {
+ mpr("Your body is healed in an amazingly painful way.");
+
+ loss = 2;
+ for (loopy = 0; loopy < 9; loopy++)
+ {
+ if (random2(power) < 8)
+ loss++;
+ }
+
+ dec_max_hp( loss );
+ set_hp( you.hp_max, false );
+ success = true;
+ }
+
+ return (success);
+} // end cast_revivification()
+
+void cast_cure_poison(int mabil)
+{
+ if (!you.poison)
+ canned_msg(MSG_NOTHING_HAPPENS);
+ else
+ reduce_poison_player( 2 + random2(mabil) + random2(3) );
+
+ return;
+} // end cast_cure_poison()
+
+void purification(void)
+{
+ mpr("You feel purified!");
+
+ you.poison = 0;
+ you.rotting = 0;
+ you.conf = 0;
+ you.slow = 0;
+ you.disease = 0;
+ you.paralysis = 0; // can't currently happen -- bwr
+} // end purification()
+
+int allowed_deaths_door_hp(void)
+{
+ int hp = you.skills[SK_NECROMANCY] / 2;
+
+ if (you.religion == GOD_KIKUBAAQUDGHA && !player_under_penance())
+ hp += you.piety / 15;
+
+ return (hp);
+}
+
+void cast_deaths_door(int pow)
+{
+ if (you.is_undead)
+ mpr("You're already dead!");
+ else if (you.deaths_door)
+ mpr("Your appeal for an extension has been denied.");
+ else
+ {
+ mpr("You feel invincible!");
+ mpr("You seem to hear sand running through an hourglass...");
+
+ set_hp( allowed_deaths_door_hp(), false );
+ deflate_hp( you.hp_max, false );
+
+ you.deaths_door = 10 + random2avg(13, 3) + (random2(pow) / 10);
+
+ if (you.deaths_door > 25)
+ you.deaths_door = 23 + random2(5);
+ }
+
+ return;
+}
+
+// can't use beam variables here, because of monster_die and the puffs of smoke
+void abjuration(int pow)
+{
+ struct monsters *monster = 0; // NULL {dlb}
+
+ mpr("Send 'em back where they came from!");
+
+ for (int ab = 0; ab < MAX_MONSTERS; ab++)
+ {
+ monster = &menv[ab];
+
+ int abjLevel;
+
+ if (monster->type == -1 || !mons_near(monster))
+ continue;
+
+ if (mons_friendly(monster))
+ continue;
+
+ abjLevel = mons_del_ench(monster, ENCH_ABJ_I, ENCH_ABJ_VI);
+ if (abjLevel != ENCH_NONE)
+ {
+ abjLevel -= 1 + (random2(pow) / 8);
+
+ if (abjLevel < ENCH_ABJ_I)
+ monster_die(monster, KILL_RESET, 0);
+ else
+ {
+ simple_monster_message(monster, " shudders.");
+ mons_add_ench(monster, abjLevel);
+ }
+ }
+ }
+} // end abjuration()
+
+// Antimagic is sort of an anti-extension... it sets a lot of magical
+// durations to 1 so it's very nasty at times (and potentially lethal,
+// that's why we reduce levitation to 2, so that the player has a chance
+// to stop insta-death... sure the others could lead to death, but that's
+// not as direct as falling into deep water) -- bwr
+void antimagic( void )
+{
+ if (you.haste)
+ you.haste = 1;
+
+ if (you.slow)
+ you.slow = 1;
+
+ if (you.paralysis)
+ you.paralysis = 1;
+
+ if (you.conf)
+ you.conf = 1;
+
+ if (you.might)
+ you.might = 1;
+
+ if (you.levitation > 2)
+ you.levitation = 2;
+
+ if (you.invis)
+ you.invis = 1;
+
+ if (you.duration[DUR_WEAPON_BRAND])
+ you.duration[DUR_WEAPON_BRAND] = 1;
+
+ if (you.duration[DUR_ICY_ARMOUR])
+ you.duration[DUR_ICY_ARMOUR] = 1;
+
+ if (you.duration[DUR_REPEL_MISSILES])
+ you.duration[DUR_REPEL_MISSILES] = 1;
+
+ if (you.duration[DUR_REGENERATION])
+ you.duration[DUR_REGENERATION] = 1;
+
+ if (you.duration[DUR_DEFLECT_MISSILES])
+ you.duration[DUR_DEFLECT_MISSILES] = 1;
+
+ if (you.fire_shield)
+ you.fire_shield = 1;
+
+ if (you.duration[DUR_SWIFTNESS])
+ you.duration[DUR_SWIFTNESS] = 1;
+
+ if (you.duration[DUR_INSULATION])
+ you.duration[DUR_INSULATION] = 1;
+
+ if (you.duration[DUR_STONEMAIL])
+ you.duration[DUR_STONEMAIL] = 1;
+
+ if (you.duration[DUR_CONTROLLED_FLIGHT])
+ you.duration[DUR_CONTROLLED_FLIGHT] = 1;
+
+ if (you.duration[DUR_CONTROL_TELEPORT])
+ you.duration[DUR_CONTROL_TELEPORT] = 1;
+
+ if (you.duration[DUR_RESIST_POISON])
+ you.duration[DUR_RESIST_POISON] = 1;
+
+ if (you.duration[DUR_TRANSFORMATION])
+ you.duration[DUR_TRANSFORMATION] = 1;
+
+ //jmf: added following
+ if (you.duration[DUR_STONESKIN])
+ you.duration[DUR_STONESKIN] = 1;
+
+ if (you.duration[DUR_FORESCRY])
+ you.duration[DUR_FORESCRY] = 1;
+
+ if (you.duration[DUR_SEE_INVISIBLE])
+ you.duration[DUR_SEE_INVISIBLE] = 1;
+
+ if (you.duration[DUR_SILENCE])
+ you.duration[DUR_SILENCE] = 1;
+
+ if (you.duration[DUR_CONDENSATION_SHIELD])
+ you.duration[DUR_CONDENSATION_SHIELD] = 1;
+
+ contaminate_player( -1 * (1+random2(5)));
+} // end antimagic()
+
+void extension(int pow)
+{
+ int contamination = random2(2);
+
+ if (you.haste)
+ {
+ potion_effect(POT_SPEED, pow);
+ contamination++;
+ }
+
+ if (you.slow)
+ potion_effect(POT_SLOWING, pow);
+
+#if 0
+ if (you.paralysis)
+ potion_effect(POT_PARALYSIS, pow); // how did you cast extension?
+
+ if (you.conf)
+ potion_effect(POT_CONFUSION, pow); // how did you cast extension?
+#endif
+
+ if (you.might)
+ {
+ potion_effect(POT_MIGHT, pow);
+ contamination++;
+ }
+
+ if (you.levitation)
+ potion_effect(POT_LEVITATION, pow);
+
+ if (you.invis)
+ {
+ potion_effect(POT_INVISIBILITY, pow);
+ contamination++;
+ }
+
+ if (you.duration[DUR_ICY_ARMOUR])
+ ice_armour(pow, true);
+
+ if (you.duration[DUR_REPEL_MISSILES])
+ missile_prot(pow);
+
+ if (you.duration[DUR_REGENERATION])
+ cast_regen(pow);
+
+ if (you.duration[DUR_DEFLECT_MISSILES])
+ deflection(pow);
+
+ if (you.fire_shield)
+ {
+ you.fire_shield += random2(pow / 20);
+
+ if (you.fire_shield > 50)
+ you.fire_shield = 50;
+
+ mpr("Your ring of flames roars with new vigour!");
+ }
+
+ if ( !(you.duration[DUR_WEAPON_BRAND] < 1
+ || you.duration[DUR_WEAPON_BRAND] > 80) )
+ {
+ you.duration[DUR_WEAPON_BRAND] += 5 + random2(8);
+ }
+
+ if (you.duration[DUR_SWIFTNESS])
+ cast_swiftness(pow);
+
+ if (you.duration[DUR_INSULATION])
+ cast_insulation(pow);
+
+ if (you.duration[DUR_STONEMAIL])
+ stone_scales(pow);
+
+ if (you.duration[DUR_CONTROLLED_FLIGHT])
+ cast_fly(pow);
+
+ if (you.duration[DUR_CONTROL_TELEPORT])
+ cast_teleport_control(pow);
+
+ if (you.duration[DUR_RESIST_POISON])
+ cast_resist_poison(pow);
+
+ if (you.duration[DUR_TRANSFORMATION])
+ {
+ mpr("Your transformation has been extended.");
+ you.duration[DUR_TRANSFORMATION] += random2(pow);
+ if (you.duration[DUR_TRANSFORMATION] > 100)
+ you.duration[DUR_TRANSFORMATION] = 100;
+ }
+
+ //jmf: added following
+ if (you.duration[DUR_STONESKIN])
+ cast_stoneskin(pow);
+
+ if (you.duration[DUR_FORESCRY])
+ cast_forescry(pow);
+
+ if (you.duration[DUR_SEE_INVISIBLE])
+ cast_see_invisible(pow);
+
+ if (you.duration[DUR_SILENCE]) //how precisely did you cast extension?
+ cast_silence(pow);
+
+ if (you.duration[DUR_CONDENSATION_SHIELD])
+ cast_condensation_shield(pow);
+
+ if (contamination)
+ contaminate_player( contamination );
+} // end extension()
+
+void ice_armour(int pow, bool extending)
+{
+ if (!player_light_armour())
+ {
+ if (!extending)
+ mpr("You are wearing too much armour.");
+
+ return;
+ }
+
+ if (you.duration[DUR_STONEMAIL] || you.duration[DUR_STONESKIN])
+ {
+ if (!extending)
+ mpr("The spell conflicts with another spell still in effect.");
+
+ return;
+ }
+
+ if (you.duration[DUR_ICY_ARMOUR])
+ mpr( "Your icy armour thickens." );
+ else
+ {
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_ICE_BEAST)
+ mpr( "Your icy body feels more resilient." );
+ else
+ mpr( "A film of ice covers your body!" );
+
+ you.redraw_armour_class = 1;
+ }
+
+ you.duration[DUR_ICY_ARMOUR] += 20 + random2(pow) + random2(pow);
+
+ if (you.duration[DUR_ICY_ARMOUR] > 50)
+ you.duration[DUR_ICY_ARMOUR] = 50;
+} // end ice_armour()
+
+void stone_scales(int pow)
+{
+ int dur_change = 0;
+
+ if (you.duration[DUR_ICY_ARMOUR] || you.duration[DUR_STONESKIN])
+ {
+ mpr("The spell conflicts with another spell still in effect.");
+ return;
+ }
+
+ if (you.duration[DUR_STONEMAIL])
+ mpr("Your scaly armour looks firmer.");
+ else
+ {
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_STATUE)
+ mpr( "Your stone body feels more resilient." );
+ else
+ mpr( "A set of stone scales covers your body!" );
+
+ you.redraw_evasion = 1;
+ you.redraw_armour_class = 1;
+ }
+
+ dur_change = 20 + random2(pow) + random2(pow);
+
+ if (dur_change + you.duration[DUR_STONEMAIL] >= 100)
+ you.duration[DUR_STONEMAIL] = 100;
+ else
+ you.duration[DUR_STONEMAIL] += dur_change;
+
+ burden_change();
+} // end stone_scales()
+
+void missile_prot(int pow)
+{
+ mpr("You feel protected from missiles.");
+
+ you.duration[DUR_REPEL_MISSILES] += 8 + roll_dice( 2, pow );
+
+ if (you.duration[DUR_REPEL_MISSILES] > 100)
+ you.duration[DUR_REPEL_MISSILES] = 100;
+} // end missile_prot()
+
+void deflection(int pow)
+{
+ mpr("You feel very safe from missiles.");
+
+ you.duration[DUR_DEFLECT_MISSILES] += 15 + random2(pow);
+
+ if (you.duration[DUR_DEFLECT_MISSILES] > 100)
+ you.duration[DUR_DEFLECT_MISSILES] = 100;
+} // end cast_deflection()
+
+void cast_regen(int pow)
+{
+ //if (pow > 150) pow = 150;
+ mpr("Your skin crawls.");
+
+ you.duration[DUR_REGENERATION] += 5 + roll_dice( 2, pow / 3 + 1 );
+
+ if (you.duration[DUR_REGENERATION] > 100)
+ you.duration[DUR_REGENERATION] = 100;
+} // end cast_regen()
+
+void cast_berserk(void)
+{
+ go_berserk(true);
+} // end cast_berserk()
+
+void cast_swiftness(int power)
+{
+ int dur_incr = 0;
+
+ if (player_in_water())
+ {
+ if (you.species == SP_MERFOLK)
+ mpr("This spell will not benefit you while you're swimming!");
+ else
+ mpr("This spell will not benefit you while you're in water!");
+
+ return;
+ }
+
+ if (!you.duration[DUR_SWIFTNESS] && player_movement_speed() <= 6)
+ {
+ mpr( "You can't move any more quickly." );
+ return;
+ }
+
+ // Reduced the duration: -- bwr
+ // dur_incr = random2(power) + random2(power) + 20;
+ dur_incr = 20 + random2( power );
+
+ // Centaurs do have feet and shouldn't get here anyways -- bwr
+ snprintf( info, INFO_SIZE, "You feel quick%s",
+ (you.species == SP_NAGA) ? "." : " on your feet." );
+
+ mpr(info);
+
+ if (dur_incr + you.duration[DUR_SWIFTNESS] > 100)
+ you.duration[DUR_SWIFTNESS] = 100;
+ else
+ you.duration[DUR_SWIFTNESS] += dur_incr;
+} // end cast_swiftness()
+
+void cast_fly(int power)
+{
+ int dur_change = 25 + random2(power) + random2(power);
+
+ if (!player_is_levitating())
+ mpr("You fly up into the air.");
+ else
+ mpr("You feel more buoyant.");
+
+ if (you.levitation + dur_change > 100)
+ you.levitation = 100;
+ else
+ you.levitation += dur_change;
+
+ if (you.duration[DUR_CONTROLLED_FLIGHT] + dur_change > 100)
+ you.duration[DUR_CONTROLLED_FLIGHT] = 100;
+ else
+ you.duration[DUR_CONTROLLED_FLIGHT] += dur_change;
+
+ // duration[DUR_CONTROLLED_FLIGHT] makes the game think player
+ // wears an amulet of controlled flight
+
+ burden_change();
+}
+
+void cast_insulation(int power)
+{
+ int dur_incr = 10 + random2(power);
+
+ mpr("You feel insulated.");
+
+ if (dur_incr + you.duration[DUR_INSULATION] > 100)
+ you.duration[DUR_INSULATION] = 100;
+ else
+ you.duration[DUR_INSULATION] += dur_incr;
+} // end cast_insulation()
+
+void cast_resist_poison(int power)
+{
+ int dur_incr = 10 + random2(power);
+
+ mpr("You feel resistant to poison.");
+
+ if (dur_incr + you.duration[DUR_RESIST_POISON] > 100)
+ you.duration[DUR_RESIST_POISON] = 100;
+ else
+ you.duration[DUR_RESIST_POISON] += dur_incr;
+} // end cast_resist_poison()
+
+void cast_teleport_control(int power)
+{
+ int dur_incr = 10 + random2(power);
+
+ if (you.duration[DUR_CONTROL_TELEPORT] == 0)
+ you.attribute[ATTR_CONTROL_TELEPORT]++;
+
+ mpr("You feel in control.");
+
+ if (dur_incr + you.duration[DUR_CONTROL_TELEPORT] >= 50)
+ you.duration[DUR_CONTROL_TELEPORT] = 50;
+ else
+ you.duration[DUR_CONTROL_TELEPORT] += dur_incr;
+} // end cast_teleport_control()
+
+void cast_ring_of_flames(int power)
+{
+ you.fire_shield += 5 + (power / 10) + (random2(power) / 5);
+
+ if (you.fire_shield > 50)
+ you.fire_shield = 50;
+
+ mpr("The air around you leaps into flame!");
+
+ manage_fire_shield();
+} // end cast_ring_of_flames()
+
+void cast_confusing_touch(int power)
+{
+ snprintf( info, INFO_SIZE, "Your %s begin to glow %s.",
+ your_hand(true), (you.confusing_touch ? "brighter" : "red") );
+
+ mpr( info );
+
+ you.confusing_touch += 5 + (random2(power) / 5);
+
+ if (you.confusing_touch > 50)
+ you.confusing_touch = 50;
+
+} // end cast_confusing_touch()
+
+bool cast_sure_blade(int power)
+{
+ bool success = false;
+
+ if (you.equip[EQ_WEAPON] == -1)
+ mpr("You aren't wielding a weapon!");
+ else if (weapon_skill( you.inv[you.equip[EQ_WEAPON]].base_type,
+ you.inv[you.equip[EQ_WEAPON]].sub_type) != SK_SHORT_BLADES)
+ {
+ mpr("You cannot bond with this weapon.");
+ }
+ else
+ {
+ if (!you.sure_blade)
+ mpr("You become one with your weapon.");
+ else if (you.sure_blade < 25)
+ mpr("Your bond becomes stronger.");
+
+ you.sure_blade += 8 + (random2(power) / 10);
+
+ if (you.sure_blade > 25)
+ you.sure_blade = 25;
+
+ success = true;
+ }
+
+ return (success);
+} // end cast_sure_blade()
+
+void manage_fire_shield(void)
+{
+ you.fire_shield--;
+
+ if (!you.fire_shield)
+ return;
+
+ char stx = 0, sty = 0;
+
+ for (stx = -1; stx < 2; stx++)
+ {
+ for (sty = -1; sty < 2; sty++)
+ {
+ if (sty == 0 && stx == 0)
+ continue;
+
+ //if ( one_chance_in(3) ) beam.range ++;
+
+ if (grd[you.x_pos + stx][you.y_pos + sty] > DNGN_LAST_SOLID_TILE
+ && env.cgrid[you.x_pos + stx][you.y_pos + sty] == EMPTY_CLOUD)
+ {
+ place_cloud( CLOUD_FIRE, you.x_pos + stx, you.y_pos + sty,
+ 1 + random2(6) );
+ }
+ }
+ }
+} // end manage_fire_shield()
diff --git a/trunk/source/spells1.h b/trunk/source/spells1.h
new file mode 100644
index 0000000000..dc98a1b133
--- /dev/null
+++ b/trunk/source/spells1.h
@@ -0,0 +1,142 @@
+/*
+ * File: spells1.cc
+ * Summary: Implementations of some additional spells.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef SPELLS1_H
+#define SPELLS1_H
+
+
+#include "externs.h"
+#include "direct.h"
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: spell
+ * *********************************************************************** */
+bool cast_sure_blade(int power);
+
+
+#if 0
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - spell
+ * *********************************************************************** */
+char cast_greater_healing(void);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability
+ * *********************************************************************** */
+char cast_greatest_healing(void);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - spell
+ * *********************************************************************** */
+char cast_lesser_healing(void);
+#endif
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - spell
+ * *********************************************************************** */
+char cast_healing(int power);
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: beam - it_use3 - spells - spells1
+ * *********************************************************************** */
+void big_cloud(char clouds, char cl_x, char cl_y, int pow, int size);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr (WIZARD only) - item_use - spell
+ * *********************************************************************** */
+void blink(void);
+
+
+/* ***********************************************************************
+ * called from: spell
+ * *********************************************************************** */
+void cast_big_c(int pow, char cty);
+void cast_confusing_touch(int power);
+void cast_cure_poison(int mabil);
+int allowed_deaths_door_hp(void);
+void cast_deaths_door(int pow);
+void cast_fire_storm(int powc);
+bool cast_revivification(int power);
+void cast_berserk(void);
+void cast_ring_of_flames(int power);
+void conjure_flame(int pow);
+void extension(int pow);
+void fireball(int power);
+void stinking_cloud(int pow);
+void abjuration(int pow);
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - spell - spells1
+ * *********************************************************************** */
+void cast_fly(int power);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: spell - spells1
+ * *********************************************************************** */
+void cast_insulation(int power);
+void cast_regen(int pow);
+void cast_resist_poison(int power);
+void cast_swiftness(int power);
+void cast_teleport_control(int power);
+void deflection(int pow);
+void ice_armour(int pow, bool extending);
+void missile_prot(int pow);
+void stone_scales(int pow);
+
+// last updated sept 18
+/* ***********************************************************************
+ * called from: religion
+ * *********************************************************************** */
+void antimagic(void);
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr (WIZARD only) - item_use - spell
+ * *********************************************************************** */
+void identify(int power);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - spells1
+ * *********************************************************************** */
+void manage_fire_shield(void);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - spell
+ * *********************************************************************** */
+void purification(void);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - decks - fight - spell - spells - spells1
+ * *********************************************************************** */
+void random_blink(bool);
+
+
+#endif
diff --git a/trunk/source/spells2.cc b/trunk/source/spells2.cc
new file mode 100644
index 0000000000..588ade57c8
--- /dev/null
+++ b/trunk/source/spells2.cc
@@ -0,0 +1,1516 @@
+/*
+ * File: spells2.cc
+ * Summary: Implementations of some additional spells.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <4> 03jan1999 jmf Changed summon_small_mammals so at
+ * higher levels it indeed summons in plural.
+ * Removed some IMHO unnecessary failure msgs.
+ * (from e.g. animate_dead).
+ * Added protection by special deities.
+ * <3> 10/11/99 BCR fixed range bug in burn_freeze,
+ * vamp_drain, and summon_elemental
+ * <2> 5/26/99 JDJ detect_items uses '~' instead of '*'.
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "spells2.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "externs.h"
+
+#include "beam.h"
+#include "cloud.h"
+#include "direct.h"
+#include "effects.h"
+#include "itemname.h"
+#include "items.h"
+#include "misc.h"
+#include "monplace.h"
+#include "monstuff.h"
+#include "mon-util.h"
+#include "ouch.h"
+#include "player.h"
+#include "randart.h"
+#include "spells4.h"
+#include "spl-cast.h"
+#include "stuff.h"
+#include "view.h"
+#include "wpn-misc.h"
+
+int raise_corpse( int corps, int corx, int cory, int corps_beh,
+ int corps_hit, int actual );
+
+unsigned char detect_traps( int pow )
+{
+ unsigned char traps_found = 0;
+
+ if (pow > 50)
+ pow = 50;
+
+ const int range = 8 + random2(8) + pow;
+
+ for (int count_x = 0; count_x < MAX_TRAPS; count_x++)
+ {
+ const int etx = env.trap[ count_x ].x;
+ const int ety = env.trap[ count_x ].y;
+
+ // Used to just be visible screen:
+ // if (etx > you.x_pos - 15 && etx < you.x_pos + 15
+ // && ety > you.y_pos - 8 && ety < you.y_pos + 8)
+
+ if (grid_distance( you.x_pos, you.y_pos, etx, ety ) < range)
+ {
+ if (grd[ etx ][ ety ] == DNGN_UNDISCOVERED_TRAP)
+ {
+ traps_found++;
+
+ grd[ etx ][ ety ] = trap_category( env.trap[count_x].type );
+ env.map[etx - 1][ety - 1] = '^';
+ }
+ }
+ }
+
+ return (traps_found);
+} // end detect_traps()
+
+unsigned char detect_items( int pow )
+{
+ if (pow > 50)
+ pow = 50;
+
+ unsigned char items_found = 0;
+ const int map_radius = 8 + random2(8) + pow;
+
+ mpr("You detect items!");
+
+ for (int i = you.x_pos - map_radius; i < you.x_pos + map_radius; i++)
+ {
+ for (int j = you.y_pos - map_radius; j < you.y_pos + map_radius; j++)
+ {
+ if (i < 5 || j < 5 || i > (GXM - 5) || j > (GYM - 5))
+ continue;
+
+ if (igrd[i][j] != NON_ITEM)
+ {
+ env.map[i - 1][j - 1] = '~';
+ }
+ }
+ }
+
+ return (items_found);
+} // end detect_items()
+
+unsigned char detect_creatures( int pow )
+{
+ if (pow > 50)
+ pow = 50;
+
+ unsigned char creatures_found = 0;
+ const int map_radius = 8 + random2(8) + pow;
+
+ mpr("You detect creatures!");
+
+ for (int i = you.x_pos - map_radius; i < you.x_pos + map_radius; i++)
+ {
+ for (int j = you.y_pos - map_radius; j < you.y_pos + map_radius; j++)
+ {
+ if (i < 5 || j < 5 || i > (GXM - 5) || j > (GYM - 5))
+ continue;
+
+ if (mgrd[i][j] != NON_MONSTER)
+ {
+ struct monsters *mon = &menv[ mgrd[i][j] ];
+
+ env.map[i - 1][j - 1] = mons_char( mon->type );
+
+ // Assuming that highly intelligent spellcasters can
+ // detect scyring. -- bwr
+ if (mons_intel( mon->type ) == I_HIGH
+ && mons_flag( mon->type, M_SPELLCASTER ))
+ {
+ behaviour_event( mon, ME_DISTURB, MHITYOU,
+ you.x_pos, you.y_pos );
+ }
+ }
+ }
+ }
+
+ return (creatures_found);
+} // end detect_creatures()
+
+int corpse_rot(int power)
+{
+ UNUSED( power );
+
+ char adx = 0;
+ char ady = 0;
+
+ char minx = you.x_pos - 6;
+ char maxx = you.x_pos + 7;
+ char miny = you.y_pos - 6;
+ char maxy = you.y_pos + 6;
+ char xinc = 1;
+ char yinc = 1;
+
+ if (coinflip())
+ {
+ minx = you.x_pos + 6;
+ maxx = you.x_pos - 7;
+ xinc = -1;
+ }
+
+ if (coinflip())
+ {
+ miny = you.y_pos + 6;
+ maxy = you.y_pos - 7;
+ yinc = -1;
+ }
+
+ for (adx = minx; adx != maxx; adx += xinc)
+ {
+ if (adx == 7 || adx == -7)
+ return 0;
+
+ for (ady = miny; ady != maxy; ady += yinc)
+ {
+ if (see_grid(adx, ady))
+ {
+ if (igrd[adx][ady] == NON_ITEM
+ || env.cgrid[adx][ady] != EMPTY_CLOUD)
+ {
+ continue;
+ }
+
+ int objl = igrd[adx][ady];
+ int hrg = 0;
+
+ while (objl != NON_ITEM)
+ {
+ if (mitm[objl].base_type == OBJ_CORPSES
+ && mitm[objl].sub_type == CORPSE_BODY)
+ {
+ if (!mons_skeleton(mitm[objl].plus))
+ destroy_item(objl);
+ else
+ {
+ mitm[objl].sub_type = CORPSE_SKELETON;
+ mitm[objl].special = 200;
+ mitm[objl].colour = LIGHTGREY;
+ }
+
+ place_cloud(CLOUD_MIASMA, adx, ady,
+ 4 + random2avg(16, 3));
+
+ goto out_of_raise;
+ }
+ hrg = mitm[objl].link;
+ objl = hrg;
+ }
+
+ out_of_raise:
+ objl = 1;
+ }
+ }
+ }
+
+ if (you.species != SP_MUMMY) // josh declares mummies cannot smell {dlb}
+ mpr("You smell decay.");
+
+ // should make zombies decay into skeletons
+
+ return 0;
+} // end corpse_rot()
+
+int animate_dead( int power, int corps_beh, int corps_hit, int actual )
+{
+ UNUSED( power );
+
+ int adx = 0;
+ int ady = 0;
+
+ int minx = you.x_pos - 6;
+ int maxx = you.x_pos + 7;
+ int miny = you.y_pos - 6;
+ int maxy = you.y_pos + 6;
+ int xinc = 1;
+ int yinc = 1;
+
+ int number_raised = 0;
+
+ if (coinflip())
+ {
+ minx = you.x_pos + 6;
+ maxx = you.x_pos - 7;
+ xinc = -1;
+ }
+
+ if (coinflip())
+ {
+ miny = you.y_pos + 6;
+ maxy = you.y_pos - 7;
+ yinc = -1;
+ }
+
+ for (adx = minx; adx != maxx; adx += xinc)
+ {
+ if ((adx == 7) || (adx == -7))
+ return 0;
+
+ for (ady = miny; ady != maxy; ady += yinc)
+ {
+ if (see_grid(adx, ady))
+ {
+ if (igrd[adx][ady] != NON_ITEM)
+ {
+ int objl = igrd[adx][ady];
+ int hrg = 0;
+
+ //this searches all the items on the ground for a corpse
+ while (objl != NON_ITEM)
+ {
+ if (mitm[objl].base_type == OBJ_CORPSES)
+ {
+ number_raised += raise_corpse(objl, adx, ady,
+ corps_beh, corps_hit, actual);
+ break;
+ }
+
+ hrg = mitm[objl].link;
+ objl = hrg;
+ }
+
+ objl = 1;
+ }
+ }
+ }
+ }
+
+ if (actual == 0)
+ return number_raised;
+
+ if (number_raised > 0)
+ {
+ mpr("The dead are walking!");
+ //else
+ // mpr("The dark energy consumes the dead!"); - no, this
+ // means that no corpses were found. Better to say:
+ // mpr("You receive no reply.");
+ //jmf: Why do I have to get an uninformative message when some random
+ //jmf: monster fails to do something?
+ // IMHO there's too much noise already.
+ }
+
+ return number_raised;
+} // end animate_dead()
+
+int animate_a_corpse( int axps, int ayps, int corps_beh, int corps_hit,
+ int class_allowed )
+{
+ if (igrd[axps][ayps] == NON_ITEM)
+ return 0;
+ else if (mitm[igrd[axps][ayps]].base_type != OBJ_CORPSES)
+ return 0;
+ else if (class_allowed == CORPSE_SKELETON
+ && mitm[igrd[axps][ayps]].sub_type != CORPSE_SKELETON)
+ return 0;
+ else
+ if (raise_corpse( igrd[axps][ayps], axps, ayps,
+ corps_beh, corps_hit, 1 ) > 0)
+ {
+ mpr("The dead are walking!");
+ }
+
+ return 0;
+} // end animate_a_corpse()
+
+int raise_corpse( int corps, int corx, int cory,
+ int corps_beh, int corps_hit, int actual )
+{
+ int returnVal = 1;
+
+ if (!mons_zombie_size(mitm[corps].plus))
+ returnVal = 0;
+ else if (actual != 0)
+ {
+ int type;
+ if (mitm[corps].sub_type == CORPSE_BODY)
+ {
+ if (mons_zombie_size(mitm[corps].plus) == Z_SMALL)
+ type = MONS_ZOMBIE_SMALL;
+ else
+ type = MONS_ZOMBIE_LARGE;
+ }
+ else
+ {
+ if (mons_zombie_size(mitm[corps].plus) == Z_SMALL)
+ type = MONS_SKELETON_SMALL;
+ else
+ type = MONS_SKELETON_LARGE;
+ }
+
+ create_monster( type, 0, corps_beh, corx, cory, corps_hit,
+ mitm[corps].plus );
+
+ destroy_item(corps);
+ }
+
+ return returnVal;
+} // end raise_corpse()
+
+void cast_twisted(int power, int corps_beh, int corps_hit)
+{
+ int total_mass = 0;
+ int num_corpses = 0;
+ int type_resurr = MONS_ABOMINATION_SMALL;
+ char colour;
+
+ unsigned char rotted = 0;
+
+ if (igrd[you.x_pos][you.y_pos] == NON_ITEM)
+ {
+ mpr("There's nothing here!");
+ return;
+ }
+
+ int objl = igrd[you.x_pos][you.y_pos];
+ int next;
+
+ while (objl != NON_ITEM)
+ {
+ next = mitm[objl].link;
+
+ if (mitm[objl].base_type == OBJ_CORPSES
+ && mitm[objl].sub_type == CORPSE_BODY)
+ {
+ total_mass += mons_weight( mitm[objl].plus );
+
+ num_corpses++;
+ if (mitm[objl].special < 100)
+ rotted++;
+
+ destroy_item( objl );
+ }
+
+ objl = next;
+ }
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "Mass for abomination: %d", total_mass);
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ // This is what the old statement pretty much boils down to,
+ // the average will be approximately 10 * power (or about 1000
+ // at the practical maximum). That's the same as the mass
+ // of a hippogriff, a spiny frog, or a steam dragon. Thus,
+ // material components are far more important to this spell. -- bwr
+ total_mass += roll_dice( 20, power );
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "Mass including power bonus: %d", total_mass);
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ if (total_mass < 400 + roll_dice( 2, 500 )
+ || num_corpses < (coinflip() ? 3 : 2))
+ {
+ mpr("The spell fails.");
+ mpr("The corpses collapse into a pulpy mess.");
+ return;
+ }
+
+ if (total_mass > 500 + roll_dice( 3, 1000 ))
+ type_resurr = MONS_ABOMINATION_LARGE;
+
+ if (rotted == num_corpses)
+ colour = BROWN;
+ else if (rotted >= random2( num_corpses ))
+ colour = RED;
+ else
+ colour = LIGHTRED;
+
+ int mon = create_monster( type_resurr, 0, corps_beh, you.x_pos, you.y_pos,
+ corps_hit, colour );
+
+ if (mon == -1)
+ mpr("The corpses collapse into a pulpy mess.");
+ else
+ {
+ mpr("The heap of corpses melds into an agglomeration of writhing flesh!");
+ if (type_resurr == MONS_ABOMINATION_LARGE)
+ {
+ menv[mon].hit_dice = 8 + total_mass / ((colour == LIGHTRED) ? 500 :
+ (colour == RED) ? 1000
+ : 2500);
+
+ if (menv[mon].hit_dice > 30)
+ menv[mon].hit_dice = 30;
+
+ // XXX: No convenient way to get the hit dice size right now.
+ menv[mon].hit_points = hit_points( menv[mon].hit_dice, 2, 5 );
+ menv[mon].max_hit_points = menv[mon].hit_points;
+
+ if (colour == LIGHTRED)
+ menv[mon].armour_class += total_mass / 1000;
+ }
+ }
+} // end cast_twisted()
+
+bool brand_weapon(int which_brand, int power)
+{
+ int temp_rand; // probability determination {dlb}
+ int duration_affected = 0; //jmf: NB: now HOW LONG, not WHICH BRAND.
+
+ const int wpn = you.equip[EQ_WEAPON];
+
+ if (you.duration[DUR_WEAPON_BRAND])
+ return false;
+
+ if (wpn == -1)
+ return false;
+
+ if (you.inv[wpn].base_type != OBJ_WEAPONS
+ || launches_things(you.inv[wpn].sub_type))
+ {
+ return false;
+ }
+
+ if (is_fixed_artefact( you.inv[wpn] )
+ || is_random_artefact( you.inv[wpn] )
+ || get_weapon_brand( you.inv[wpn] ) != SPWPN_NORMAL )
+ {
+ return false;
+ }
+
+ char str_pass[ ITEMNAME_SIZE ];
+ in_name( wpn, DESC_CAP_YOUR, str_pass );
+ strcpy( info, str_pass );
+
+ const int wpn_type = damage_type( you.inv[wpn].base_type,
+ you.inv[wpn].sub_type );
+
+ switch (which_brand) // use SPECIAL_WEAPONS here?
+ {
+ case SPWPN_FLAMING:
+ strcat(info, " bursts into flame!");
+ duration_affected = 7;
+ break;
+
+ case SPWPN_FREEZING:
+ strcat(info, " glows blue.");
+ duration_affected = 7;
+ break;
+
+ case SPWPN_VENOM:
+ if (wpn_type == DVORP_CRUSHING)
+ return false;
+
+ strcat(info, " starts dripping with poison.");
+ duration_affected = 15;
+ break;
+
+ case SPWPN_DRAINING:
+ strcat(info, " crackles with unholy energy.");
+ duration_affected = 12;
+ break;
+
+ case SPWPN_VORPAL:
+ if (wpn_type != DVORP_SLICING)
+ return false;
+
+ strcat(info, " glows silver and looks extremely sharp.");
+ duration_affected = 10;
+ break;
+
+ case SPWPN_DISTORTION: //jmf: added for Warp Weapon
+ strcat(info, " seems to ");
+
+ temp_rand = random2(6);
+ strcat(info, (temp_rand == 0) ? "twist" :
+ (temp_rand == 1) ? "bend" :
+ (temp_rand == 2) ? "vibrate" :
+ (temp_rand == 3) ? "flex" :
+ (temp_rand == 4) ? "wobble"
+ : "twang");
+
+ strcat( info, coinflip() ? " oddly." : " strangely." );
+ duration_affected = 5;
+
+ // This brand is insanely powerful, this isn't even really
+ // a start to balancing it, but it needs something. -- bwr
+ miscast_effect(SPTYP_TRANSLOCATION, 9, 90, 100, "a distortion effect");
+ break;
+
+ case SPWPN_DUMMY_CRUSHING: //jmf: added for Maxwell's Silver Hammer
+ if (wpn_type != DVORP_CRUSHING)
+ return false;
+
+ which_brand = SPWPN_VORPAL;
+ strcat(info, " glows silver and feels heavier.");
+ duration_affected = 7;
+ break;
+ }
+
+ set_item_ego_type( you.inv[wpn], OBJ_WEAPONS, which_brand );
+
+ mpr(info);
+ you.wield_change = true;
+
+ int dur_change = duration_affected + roll_dice( 2, power );
+
+ you.duration[DUR_WEAPON_BRAND] += dur_change;
+
+ if (you.duration[DUR_WEAPON_BRAND] > 50)
+ you.duration[DUR_WEAPON_BRAND] = 50;
+
+ return true;
+} // end brand_weapon()
+
+bool restore_stat(unsigned char which_stat, bool suppress_msg)
+{
+ bool statRestored = false;
+
+ // a bit hackish, but cut me some slack, man! --
+ // besides, a little recursion never hurt anyone {dlb}:
+ if (which_stat == STAT_ALL)
+ {
+ for (unsigned char loopy = STAT_STRENGTH; loopy < NUM_STATS; loopy++)
+ {
+ if (restore_stat(loopy, suppress_msg) == true)
+ statRestored = true;
+ }
+ return statRestored; // early return {dlb}
+ }
+
+ // the real function begins here {dlb}:
+ char *ptr_stat = 0; // NULL {dlb}
+ char *ptr_stat_max = 0; // NULL {dlb}
+ char *ptr_redraw = 0; // NULL {dlb}
+
+ if (!suppress_msg)
+ strcpy(info, "You feel your ");
+
+ if (which_stat == STAT_RANDOM)
+ which_stat = random2(NUM_STATS);
+
+ switch (which_stat)
+ {
+ case STAT_STRENGTH:
+ if (!suppress_msg)
+ strcat(info, "strength");
+
+ ptr_stat = &you.strength;
+ ptr_stat_max = &you.max_strength;
+ ptr_redraw = &you.redraw_strength;
+ break;
+
+ case STAT_DEXTERITY:
+ if (!suppress_msg)
+ strcat(info, "dexterity");
+
+ ptr_stat = &you.dex;
+ ptr_stat_max = &you.max_dex;
+ ptr_redraw = &you.redraw_dexterity;
+ break;
+
+ case STAT_INTELLIGENCE:
+ if (!suppress_msg)
+ strcat(info, "intelligence");
+
+ ptr_stat = &you.intel;
+ ptr_stat_max = &you.max_intel;
+ ptr_redraw = &you.redraw_intelligence;
+ break;
+ }
+
+ if (*ptr_stat < *ptr_stat_max)
+ {
+ if (!suppress_msg)
+ {
+ strcat(info, " returning.");
+ mpr(info);
+ }
+
+ *ptr_stat = *ptr_stat_max;
+ *ptr_redraw = 1;
+ statRestored = true;
+
+ if (ptr_stat == &you.strength)
+ burden_change();
+ }
+
+ return statRestored;
+} // end restore_stat()
+
+void turn_undead(int pow)
+{
+ struct monsters *monster;
+
+ mpr("You attempt to repel the undead.");
+
+ for (int tu = 0; tu < MAX_MONSTERS; tu++)
+ {
+ monster = &menv[tu];
+
+ if (monster->type == -1 || !mons_near(monster))
+ continue;
+
+ // used to inflict random2(5) + (random2(pow) / 20) damage,
+ // in addition {dlb}
+ if (mons_holiness(monster->type) == MH_UNDEAD)
+ {
+ if (check_mons_resist_magic( monster, pow ))
+ {
+ simple_monster_message( monster, " resists." );
+ continue;
+ }
+
+ if (!mons_add_ench(monster, ENCH_FEAR))
+ continue;
+
+ simple_monster_message( monster, " is repelled!" );
+
+ //mv: must be here to work
+ behaviour_event( monster, ME_SCARE, MHITYOU );
+
+ // reduce power based on monster turned
+ pow -= monster->hit_dice * 3;
+ if (pow <= 0)
+ break;
+
+ } // end "if mons_holiness"
+ } // end "for tu"
+} // end turn_undead()
+
+void holy_word(int pow)
+{
+ struct monsters *monster;
+
+ mpr("You speak a Word of immense power!");
+
+ // doubt this will ever happen, but it's here as a safety -- bwr
+ if (pow > 300)
+ pow = 300;
+
+ for (int tu = 0; tu < MAX_MONSTERS; tu++)
+ {
+ monster = &menv[tu];
+
+ if (monster->type == -1 || !mons_near(monster))
+ continue;
+
+ if (mons_holiness(monster->type) == MH_UNDEAD
+ || mons_holiness(monster->type) == MH_DEMONIC)
+ {
+ simple_monster_message(monster, " convulses!");
+
+ hurt_monster( monster, roll_dice( 2, 15 ) + (random2(pow) / 3) );
+
+ if (monster->hit_points < 1)
+ {
+ monster_die(monster, KILL_YOU, 0);
+ continue;
+ }
+
+ if (monster->speed_increment >= 25)
+ monster->speed_increment -= 20;
+
+ mons_add_ench(monster, ENCH_FEAR);
+ } // end "if mons_holiness"
+ } // end "for tu"
+} // end holy_word()
+
+// poisonous light passes right through invisible players
+// and monsters, and so, they are unaffected by this spell --
+// assumes only you can cast this spell (or would want to)
+void cast_toxic_radiance(void)
+{
+ struct monsters *monster;
+
+ mpr("You radiate a sickly green light!");
+
+ show_green = GREEN;
+ viewwindow(1, false);
+ more();
+ mesclr();
+
+ // determine whether the player is hit by the radiance: {dlb}
+ if (you.invis)
+ {
+ mpr("The light passes straight through your body.");
+ }
+ else if (!player_res_poison())
+ {
+ mpr("You feel rather sick.");
+ poison_player(2);
+ }
+
+ // determine which monsters are hit by the radiance: {dlb}
+ for (int toxy = 0; toxy < MAX_MONSTERS; toxy++)
+ {
+ monster = &menv[toxy];
+
+ if (monster->type != -1 && mons_near(monster))
+ {
+ if (!mons_has_ench(monster, ENCH_INVIS))
+ {
+ poison_monster(monster, true);
+
+ if (coinflip()) // 50-50 chance for a "double hit" {dlb}
+ poison_monster(monster, true);
+
+ }
+ else if (player_see_invis())
+ {
+ // message player re:"miss" where appropriate {dlb}
+ strcpy(info, "The light passes through ");
+ strcat(info, ptr_monam( monster, DESC_NOCAP_THE ));
+ strcat(info, ".");
+ mpr(info);
+ }
+ }
+ }
+} // end cast_toxic_radiance()
+
+void cast_refrigeration(int pow)
+{
+ struct monsters *monster = 0; // NULL {dlb}
+ int hurted = 0;
+ struct bolt beam;
+ int toxy;
+
+ beam.flavour = BEAM_COLD;
+
+ const dice_def dam_dice( 3, 5 + pow / 10 );
+
+ mpr("The heat is drained from your surroundings.");
+
+ show_green = LIGHTCYAN;
+ viewwindow(1, false);
+ more();
+ mesclr();
+
+ // Do the player:
+ hurted = roll_dice( dam_dice );
+ hurted = check_your_resists( hurted, beam.flavour );
+
+ if (hurted > 0)
+ {
+ mpr("You feel very cold.");
+ ouch( hurted, 0, KILLED_BY_FREEZING );
+
+ // Note: this used to be 12!... and it was also applied even if
+ // the player didn't take damage from the cold, so we're being
+ // a lot nicer now. -- bwr
+ scrolls_burn( 5, OBJ_POTIONS );
+ }
+
+ // Now do the monsters:
+ for (toxy = 0; toxy < MAX_MONSTERS; toxy++)
+ {
+ monster = &menv[toxy];
+
+ if (monster->type == -1)
+ continue;
+
+ if (mons_near(monster))
+ {
+ snprintf( info, INFO_SIZE, "You freeze %s.",
+ ptr_monam( monster, DESC_NOCAP_THE ));
+
+ mpr(info);
+
+ hurted = roll_dice( dam_dice );
+ hurted = mons_adjust_flavoured( monster, beam, hurted );
+
+ if (hurted > 0)
+ {
+ hurt_monster( monster, hurted );
+
+ if (monster->hit_points < 1)
+ monster_die(monster, KILL_YOU, 0);
+ else
+ {
+ print_wounds(monster);
+
+ //jmf: "slow snakes" finally available
+ if (mons_flag( monster->type, M_COLD_BLOOD ) && coinflip())
+ mons_add_ench(monster, ENCH_SLOW);
+ }
+ }
+ }
+ }
+} // end cast_refrigeration()
+
+void drain_life(int pow)
+{
+ int hp_gain = 0;
+ int hurted = 0;
+ struct monsters *monster = 0; // NULL {dlb}
+
+ mpr("You draw life from your surroundings.");
+
+ // Incoming power to this function is skill in INVOCATIONS, so
+ // we'll add an assert here to warn anyone who tries to use
+ // this function with spell level power.
+ ASSERT( pow <= 27 );
+
+ show_green = DARKGREY;
+ viewwindow(1, false);
+ more();
+ mesclr();
+
+ for (int toxy = 0; toxy < MAX_MONSTERS; toxy++)
+ {
+ monster = &menv[toxy];
+
+ if (monster->type == -1)
+ continue;
+
+ if (mons_holiness( monster->type ) != MH_NATURAL)
+ continue;
+
+ if (mons_res_negative_energy( monster ))
+ continue;
+
+ if (mons_near(monster))
+ {
+ strcpy(info, "You draw life from ");
+ strcat(info, ptr_monam( monster, DESC_NOCAP_THE ));
+ strcat(info, ".");
+ mpr(info);
+
+ hurted = 3 + random2(7) + random2(pow);
+
+ hurt_monster(monster, hurted);
+
+ hp_gain += hurted;
+
+ if (monster->hit_points < 1)
+ monster_die(monster, KILL_YOU, 0);
+ else
+ print_wounds(monster);
+ }
+ }
+
+ hp_gain /= 2;
+
+ if (hp_gain > pow * 2)
+ hp_gain = pow * 2;
+
+ if (hp_gain)
+ {
+ mpr( "You feel life flooding into your body." );
+ inc_hp( hp_gain, false );
+ }
+} // end drain_life()
+
+int vampiric_drain(int pow)
+{
+ int inflicted = 0;
+ int mgr = 0;
+ struct monsters *monster = 0; // NULL
+ struct dist vmove;
+
+ dirc:
+ mpr("Which direction?", MSGCH_PROMPT);
+ direction( vmove, DIR_DIR, TARG_ENEMY );
+
+ if (!vmove.isValid)
+ {
+ canned_msg(MSG_SPELL_FIZZLES);
+ return -1;
+ }
+
+ mgr = mgrd[you.x_pos + vmove.dx][you.y_pos + vmove.dy];
+
+ if (vmove.dx == 0 && vmove.dy == 0)
+ {
+ mpr("You can't do that.");
+ goto dirc;
+ }
+
+ if (mgr == NON_MONSTER)
+ {
+ mpr("There isn't anything there!");
+ return -1;
+ }
+
+ monster = &menv[mgr];
+
+ const int holy = mons_holiness(monster->type);
+
+ if (holy == MH_UNDEAD || holy == MH_DEMONIC)
+ {
+ mpr("Aaaarggghhhhh!");
+ dec_hp(random2avg(39, 2) + 10, false);
+ return -1;
+ }
+
+ if (mons_res_negative_energy( monster ))
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ return -1;
+ }
+
+ // The practical maximum of this is about 25 (pow @ 100). -- bwr
+ inflicted = 3 + random2avg( 9, 2 ) + random2(pow) / 7;
+
+ if (inflicted >= monster->hit_points)
+ inflicted = monster->hit_points;
+
+ if (inflicted >= you.hp_max - you.hp)
+ inflicted = you.hp_max - you.hp;
+
+ if (inflicted == 0)
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ return -1;
+ }
+
+ hurt_monster(monster, inflicted);
+
+ strcpy(info, "You feel life coursing from ");
+ strcat(info, ptr_monam( monster, DESC_NOCAP_THE ));
+ strcat(info, " into your body!");
+ mpr(info);
+
+ print_wounds(monster);
+
+ if (monster->hit_points < 1)
+ monster_die(monster, KILL_YOU, 0);
+
+ inc_hp(inflicted / 2, false);
+
+ return 1;
+} // end vampiric_drain()
+
+// Note: this function is currently only used for Freeze. -- bwr
+char burn_freeze(int pow, char flavour)
+{
+ int mgr = NON_MONSTER;
+ struct monsters *monster = 0; // NULL {dlb}
+ struct dist bmove;
+
+ if (pow > 25)
+ pow = 25;
+
+ while (mgr == NON_MONSTER)
+ {
+ mpr("Which direction?", MSGCH_PROMPT);
+ direction( bmove, DIR_DIR, TARG_ENEMY );
+
+ if (!bmove.isValid)
+ {
+ canned_msg(MSG_SPELL_FIZZLES);
+ return -1;
+ }
+
+ if (bmove.isMe)
+ {
+ canned_msg(MSG_UNTHINKING_ACT);
+ return -1;
+ }
+
+ mgr = mgrd[you.x_pos + bmove.dx][you.y_pos + bmove.dy];
+
+ // Yes, this is strange, but it does maintain the original behaviour
+ if (mgr == NON_MONSTER)
+ {
+ mpr("There isn't anything close enough!");
+ return -1;
+ }
+ }
+
+ monster = &menv[mgr];
+
+ strcpy(info, "You ");
+ strcat(info, (flavour == BEAM_FIRE) ? "burn" :
+ (flavour == BEAM_COLD) ? "freeze" :
+ (flavour == BEAM_MISSILE) ? "crush" :
+ (flavour == BEAM_ELECTRICITY) ? "zap"
+ : "______");
+
+ strcat(info, " ");
+ strcat(info, ptr_monam( monster, DESC_NOCAP_THE ));
+ strcat(info, ".");
+ mpr(info);
+
+ int hurted = roll_dice( 1, 3 + pow / 3 );
+
+ struct bolt beam;
+
+ beam.flavour = flavour;
+
+ if (flavour != BEAM_MISSILE)
+ hurted = mons_adjust_flavoured(monster, beam, hurted);
+
+ if (hurted)
+ {
+ hurt_monster(monster, hurted);
+
+ if (monster->hit_points < 1)
+ monster_die(monster, KILL_YOU, 0);
+ else
+ {
+ print_wounds(monster);
+
+ if (flavour == BEAM_COLD)
+ {
+ if (mons_flag( monster->type, M_COLD_BLOOD ) && coinflip())
+ mons_add_ench(monster, ENCH_SLOW);
+
+ const int cold_res = mons_res_cold( monster );
+ if (cold_res <= 0)
+ {
+ const int stun = (1 - cold_res) * random2( 2 + pow / 5 );
+ monster->speed_increment -= stun;
+ }
+ }
+ }
+ }
+
+ return 1;
+} // end burn_freeze()
+
+// 'unfriendly' is percentage chance summoned elemental goes
+// postal on the caster (after taking into account
+// chance of that happening to unskilled casters
+// anyway)
+int summon_elemental(int pow, unsigned char restricted_type,
+ unsigned char unfriendly)
+{
+ int type_summoned = MONS_PROGRAM_BUG; // error trapping {dlb}
+ char summ_success = 0;
+ struct dist smove;
+
+ int dir_x;
+ int dir_y;
+ int targ_x;
+ int targ_y;
+
+ int numsc = ENCH_ABJ_II + (random2(pow) / 5);
+
+ if (numsc > ENCH_ABJ_VI)
+ numsc = ENCH_ABJ_VI;
+
+ for (;;)
+ {
+ mpr("Summon from material in which direction?", MSGCH_PROMPT);
+
+ direction( smove, DIR_DIR );
+
+ if (!smove.isValid)
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ return (-1);
+ }
+
+ dir_x = smove.dx;
+ dir_y = smove.dy;
+ targ_x = you.x_pos + dir_x;
+ targ_y = you.y_pos + dir_y;
+
+ if (mgrd[ targ_x ][ targ_y ] != NON_MONSTER)
+ mpr("Not there!");
+ else if (dir_x == 0 && dir_y == 0)
+ mpr("You can't summon an elemental from yourself!");
+ else
+ break;
+ }
+
+ if (grd[ targ_x ][ targ_y ] == DNGN_ROCK_WALL
+ && (restricted_type == 0 || restricted_type == MONS_EARTH_ELEMENTAL))
+ {
+ type_summoned = MONS_EARTH_ELEMENTAL;
+
+ if (targ_x > 6 && targ_x < 74 && targ_y > 6 && targ_y < 64)
+ grd[ targ_x ][ targ_y ] = DNGN_FLOOR;
+ }
+ else if ((env.cgrid[ targ_x ][ targ_y ] != EMPTY_CLOUD
+ && (env.cloud[env.cgrid[ targ_x ][ targ_y ]].type == CLOUD_FIRE
+ || env.cloud[env.cgrid[ targ_x ][ targ_y ]].type == CLOUD_FIRE_MON))
+ && (restricted_type == 0 || restricted_type == MONS_FIRE_ELEMENTAL))
+ {
+ type_summoned = MONS_FIRE_ELEMENTAL;
+ delete_cloud( env.cgrid[ targ_x ][ targ_y ] );
+ }
+ else if ((grd[ targ_x ][ targ_y ] == DNGN_LAVA)
+ && (restricted_type == 0 || restricted_type == MONS_FIRE_ELEMENTAL))
+ {
+ type_summoned = MONS_FIRE_ELEMENTAL;
+ }
+ else if ((grd[ targ_x ][ targ_y ] == DNGN_DEEP_WATER
+ || grd[ targ_x ][ targ_y ] == DNGN_SHALLOW_WATER
+ || grd[ targ_x ][ targ_y ] == DNGN_BLUE_FOUNTAIN)
+ && (restricted_type == 0 || restricted_type == MONS_WATER_ELEMENTAL))
+ {
+ type_summoned = MONS_WATER_ELEMENTAL;
+ }
+ else if ((grd[ targ_x ][ targ_y ] >= DNGN_FLOOR
+ && env.cgrid[ targ_x ][ targ_y ] == EMPTY_CLOUD)
+ && (restricted_type == 0 || restricted_type == MONS_AIR_ELEMENTAL))
+ {
+ type_summoned = MONS_AIR_ELEMENTAL;
+ }
+
+ // found something to summon
+ if (type_summoned == MONS_PROGRAM_BUG)
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ return (-1);
+ }
+
+ // silly - ice for water? 15jan2000 {dlb}
+ // little change here to help with the above... and differentiate
+ // elements a bit... {bwr}
+ // - Water elementals are now harder to be made reliably friendly
+ // - Air elementals are harder because they're more dynamic/dangerous
+ // - Earth elementals are more static and easy to tame (as before)
+ // - Fire elementals fall in between the two (10 is still fairly easy)
+ if ((type_summoned == MONS_FIRE_ELEMENTAL
+ && random2(10) >= you.skills[SK_FIRE_MAGIC])
+
+ || (type_summoned == MONS_WATER_ELEMENTAL
+ && random2((you.species == SP_MERFOLK) ? 5 : 15)
+ >= you.skills[SK_ICE_MAGIC])
+
+ || (type_summoned == MONS_AIR_ELEMENTAL
+ && random2(15) >= you.skills[SK_AIR_MAGIC])
+
+ || (type_summoned == MONS_EARTH_ELEMENTAL
+ && random2(5) >= you.skills[SK_EARTH_MAGIC])
+
+ || random2(100) < unfriendly)
+ {
+ summ_success = create_monster( type_summoned, numsc, BEH_HOSTILE,
+ targ_x, targ_y, MHITYOU, 250 );
+
+ if (summ_success >= 0)
+ mpr( "The elemental doesn't seem to appreciate being summoned." );
+ }
+ else
+ {
+ summ_success = create_monster( type_summoned, numsc, BEH_FRIENDLY,
+ targ_x, targ_y, you.pet_target, 250 );
+ }
+
+ return (summ_success >= 0);
+} // end summon_elemental()
+
+//jmf: beefed up higher-level casting of this (formerly lame) spell
+void summon_small_mammals(int pow)
+{
+ int thing_called = MONS_PROGRAM_BUG; // error trapping{dlb}
+
+ int pow_spent = 0;
+ int pow_left = pow + 1;
+ int summoned = 0;
+ int summoned_max = pow / 16;
+
+ if (summoned_max > 5)
+ summoned_max = 5;
+ if (summoned_max < 1)
+ summoned_max = 1;
+
+ while (pow_left > 0 && summoned < summoned_max)
+ {
+ summoned++;
+ pow_spent = 1 + random2(pow_left);
+ pow_left -= pow_spent;
+
+ switch (pow_spent)
+ {
+ case 75:
+ case 74:
+ case 38:
+ thing_called = MONS_ORANGE_RAT;
+ break;
+
+ case 65:
+ case 64:
+ case 63:
+ case 27:
+ case 26:
+ case 25:
+ thing_called = MONS_GREEN_RAT;
+ break;
+
+ case 57:
+ case 56:
+ case 55:
+ case 54:
+ case 53:
+ case 52:
+ case 20:
+ case 18:
+ case 16:
+ case 14:
+ case 12:
+ case 10:
+ thing_called = coinflip() ? MONS_QUOKKA : MONS_GREY_RAT;
+ break;
+
+ default:
+ thing_called = coinflip() ? MONS_GIANT_BAT : MONS_RAT;
+ break;
+ }
+
+ create_monster( thing_called, ENCH_ABJ_III, BEH_FRIENDLY,
+ you.x_pos, you.y_pos, you.pet_target, 250 );
+ }
+} // end summon_small_mammals()
+
+void summon_scorpions(int pow)
+{
+ int numsc = 1 + random2(pow) / 10 + random2(pow) / 10;
+
+ numsc = stepdown_value(numsc, 2, 2, 6, 8); //see stuff.cc - 12jan2000 {dlb}
+
+ for (int scount = 0; scount < numsc; scount++)
+ {
+ if (random2(pow) <= 3)
+ {
+ if (create_monster( MONS_SCORPION, ENCH_ABJ_III, BEH_HOSTILE,
+ you.x_pos, you.y_pos, MHITYOU, 250 ) != -1)
+ {
+ mpr("A scorpion appears. It doesn't look very happy.");
+ }
+ }
+ else
+ {
+ if (create_monster( MONS_SCORPION, ENCH_ABJ_III, BEH_FRIENDLY,
+ you.x_pos, you.y_pos,
+ you.pet_target, 250 ) != -1)
+ {
+ mpr("A scorpion appears.");
+ }
+ }
+ }
+} // end summon_scorpions()
+
+void summon_ice_beast_etc(int pow, int ibc)
+{
+ int numsc = ENCH_ABJ_II + (random2(pow) / 4);
+ int beha = BEH_FRIENDLY;
+
+ if (numsc > ENCH_ABJ_VI)
+ numsc = ENCH_ABJ_VI;
+
+ switch (ibc)
+ {
+ case MONS_ICE_BEAST:
+ mpr("A chill wind blows around you.");
+ break;
+
+ case MONS_IMP:
+ mpr("A beastly little devil appears in a puff of flame.");
+ break;
+
+ case MONS_WHITE_IMP:
+ mpr("A beastly little devil appears in a puff of frigid air.");
+ break;
+
+ case MONS_SHADOW_IMP:
+ mpr("A shadowy apparition takes form in the air.");
+ break;
+
+ case MONS_ANGEL:
+ mpr("You open a gate to the realm of Zin!");
+ break;
+
+ case MONS_DAEVA:
+ mpr("You are momentarily dazzled by a brilliant golden light.");
+ break;
+
+ default:
+ mpr("A demon appears!");
+ if (random2(pow) < 4)
+ {
+ beha = BEH_HOSTILE;
+ mpr("It doesn't look very happy.");
+ }
+ break;
+
+ }
+
+ create_monster( ibc, numsc, beha, you.x_pos, you.y_pos, MHITYOU, 250 );
+} // end summon_ice_beast_etc()
+
+bool summon_swarm( int pow, bool unfriendly, bool god_gift )
+{
+ int thing_called = MONS_PROGRAM_BUG; // error trapping {dlb}
+ int numsc = 2 + random2(pow) / 10 + random2(pow) / 25;
+ bool summoned = false;
+
+ // see stuff.cc - 12jan2000 {dlb}
+ numsc = stepdown_value( numsc, 2, 2, 6, 8 );
+
+ for (int scount = 0; scount < numsc; scount++)
+ {
+ switch (random2(14))
+ {
+ case 0:
+ case 1: // prototypical swarming creature {dlb}
+ thing_called = MONS_KILLER_BEE;
+ break;
+
+ case 2: // comment said "larva", code read scorpion {dlb}
+ thing_called = MONS_SCORPION;
+ break; // think: "The Arrival" {dlb}
+
+ case 3: //jmf: technically not insects but still cool
+ thing_called = MONS_WORM;
+ break; // but worms kinda "swarm" so s'ok {dlb}
+
+ case 4: // comment read "larva", code was for scorpion
+ thing_called = MONS_GIANT_MOSQUITO;
+ break; // changed into giant mosquito 12jan2000 {dlb}
+
+ case 5: // think: scarabs in "The Mummy" {dlb}
+ thing_called = MONS_GIANT_BEETLE;
+ break;
+
+ case 6: //jmf: blowfly instead of queen bee
+ thing_called = MONS_GIANT_BLOWFLY;
+ break;
+
+ // queen bee added if more than x bees in swarm? {dlb}
+ // the above would require code rewrite - worth it? {dlb}
+
+ case 8: //jmf: changed to red wasp; was wolf spider
+ thing_called = MONS_WOLF_SPIDER; //jmf: spiders aren't insects
+ break; // think: "Kingdom of the Spiders" {dlb}
+ // not just insects!!! - changed back {dlb}
+
+ case 9:
+ thing_called = MONS_BUTTERFLY; // comic relief? {dlb}
+ break;
+
+ case 10: // change into some kind of snake -- {dlb}
+ thing_called = MONS_YELLOW_WASP; // do wasps swarm? {dlb}
+ break; // think: "Indiana Jones" and snakepit? {dlb}
+
+ default: // 3 in 14 chance, 12jan2000 {dlb}
+ thing_called = MONS_GIANT_ANT;
+ break;
+ } // end switch
+
+ int behaviour = BEH_HOSTILE; // default to unfriendly
+
+ // Note: friendly, non-god_gift means spell.
+ if (god_gift)
+ behaviour = BEH_GOD_GIFT;
+ else if (!unfriendly && random2(pow) > 7)
+ behaviour = BEH_FRIENDLY;
+
+ if (create_monster( thing_called, ENCH_ABJ_III, behaviour,
+ you.x_pos, you.y_pos, MHITYOU, 250 ))
+ {
+ summoned = true;
+ }
+ }
+
+ return (summoned);
+} // end summon_swarm()
+
+void summon_undead(int pow)
+{
+ int temp_rand = 0;
+ int thing_called = MONS_PROGRAM_BUG; // error trapping {dlb}
+
+ int numsc = 1 + random2(pow) / 30 + random2(pow) / 30;
+ numsc = stepdown_value(numsc, 2, 2, 6, 8); //see stuff.cc {dlb}
+
+ mpr("You call on the undead to aid you!");
+
+ for (int scount = 0; scount < numsc; scount++)
+ {
+ temp_rand = random2(25);
+
+ thing_called = ((temp_rand > 8) ? MONS_WRAITH : // 64%
+ (temp_rand > 3) ? MONS_SPECTRAL_WARRIOR // 20%
+ : MONS_FREEZING_WRAITH); // 16%
+
+ if (random2(pow) < 6)
+ {
+ if (create_monster( thing_called, ENCH_ABJ_V, BEH_HOSTILE,
+ you.x_pos, you.y_pos, MHITYOU, 250 ) != -1)
+ {
+ mpr("You sense a hostile presence.");
+ }
+ }
+ else
+ {
+ if (create_monster( thing_called, ENCH_ABJ_V, BEH_FRIENDLY,
+ you.x_pos, you.y_pos, you.pet_target, 250 ) != -1)
+ {
+ mpr("An insubstantial figure forms in the air.");
+ }
+ }
+ } // end for loop
+
+ //jmf: Kiku sometimes deflects this
+ if (!you.is_undead
+ && !(you.religion == GOD_KIKUBAAQUDGHA
+ && (!player_under_penance()
+ && you.piety >= 100 && random2(200) <= you.piety)))
+ {
+ disease_player( 25 + random2(50) );
+ }
+} // end summon_undead()
+
+void summon_things( int pow )
+{
+ int big_things = 0;
+ int numsc = 2 + (random2(pow) / 10) + (random2(pow) / 10);
+
+ if (one_chance_in(3) && !lose_stat( STAT_INTELLIGENCE, 1, true ))
+ mpr("Your call goes unanswered.");
+ else
+ {
+ numsc = stepdown_value( numsc, 2, 2, 6, -1 );
+
+ while (numsc > 2)
+ {
+ if (one_chance_in(4))
+ break;
+
+ numsc -= 2;
+ big_things++;
+ }
+
+ if (numsc > 8)
+ numsc = 8;
+
+ if (big_things > 8)
+ big_things = 8;
+
+ while (big_things > 0)
+ {
+ create_monster( MONS_TENTACLED_MONSTROSITY, 0, BEH_FRIENDLY,
+ you.x_pos, you.y_pos, you.pet_target, 250 );
+ big_things--;
+ }
+
+ while (numsc > 0)
+ {
+ create_monster( MONS_ABOMINATION_LARGE, 0, BEH_FRIENDLY,
+ you.x_pos, you.y_pos, you.pet_target, 250 );
+ numsc--;
+ }
+
+ snprintf( info, INFO_SIZE, "Some Thing%s answered your call!",
+ (numsc + big_things > 1) ? "s" : "" );
+
+ mpr(info);
+ }
+
+ return;
+}
diff --git a/trunk/source/spells2.h b/trunk/source/spells2.h
new file mode 100644
index 0000000000..492fe62022
--- /dev/null
+++ b/trunk/source/spells2.h
@@ -0,0 +1,177 @@
+/*
+ * File: spells2.cc
+ * Summary: Implementations of some additional spells.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+#ifndef SPELLS2_H
+#define SPELLS2_H
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: spell
+ * *********************************************************************** */
+bool brand_weapon(int which_brand, int power);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - spell
+ * *********************************************************************** */
+int animate_a_corpse(int axps, int ayps, int corps_beh, int corps_hit, int class_allowed);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - it_use3 - monstuff - mstuff2 - spell
+ * *********************************************************************** */
+int animate_dead(int power, int corps_beh, int corps_hit, int actual);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: spell
+ * *********************************************************************** */
+char burn_freeze(int pow, char b_f);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: spell
+ * *********************************************************************** */
+int corpse_rot(int power);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: it_use3 - spell
+ * *********************************************************************** */
+int summon_elemental(int pow, unsigned char restricted_type, unsigned char unfriendly);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: spell
+ * *********************************************************************** */
+int vampiric_drain(int pow);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: spell
+ * *********************************************************************** */
+unsigned char detect_creatures( int pow );
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: spell
+ * *********************************************************************** */
+unsigned char detect_items( int pow );
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: spell
+ * *********************************************************************** */
+unsigned char detect_traps( int pow );
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: item_use - spell
+ * *********************************************************************** */
+void cast_refrigeration(int pow);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: item_use - spell
+ * *********************************************************************** */
+void cast_toxic_radiance(void);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: spell
+ * *********************************************************************** */
+void cast_twisted(int power, int corps_beh, int corps_hit);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability
+ * *********************************************************************** */
+void drain_life(int pow);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - spell
+ * *********************************************************************** */
+void holy_word(int pow);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - food - it_use2 - spell
+ * returns TRUE if a stat was restored.
+ * *********************************************************************** */
+bool restore_stat(unsigned char which_stat, bool suppress_msg);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - spell
+ * *********************************************************************** */
+void summon_ice_beast_etc(int pow, int ibc);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: spell
+ * *********************************************************************** */
+void summon_scorpions(int pow);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: spell
+ * *********************************************************************** */
+void summon_small_mammals(int pow);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - religion - spell
+ * *********************************************************************** */
+bool summon_swarm( int pow, bool unfriendly, bool god_gift );
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: spell
+ * *********************************************************************** */
+void summon_things(int pow);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: spell
+ * *********************************************************************** */
+void summon_undead(int pow);
+
+
+// last updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - spell
+ * *********************************************************************** */
+void turn_undead(int pow); // what should I use for pow?
+
+
+#endif
diff --git a/trunk/source/spells3.cc b/trunk/source/spells3.cc
new file mode 100644
index 0000000000..fd6ea6043e
--- /dev/null
+++ b/trunk/source/spells3.cc
@@ -0,0 +1,1090 @@
+/*
+ * File: spells3.cc
+ * Summary: Implementations of some additional spells.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <2> 9/11/99 LRH Teleportation takes longer in the Abyss
+ * <2> 8/05/99 BWR Added allow_control_teleport
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "spells3.h"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "externs.h"
+
+#include "abyss.h"
+#include "beam.h"
+#include "cloud.h"
+#include "direct.h"
+#include "debug.h"
+#include "delay.h"
+#include "itemname.h"
+#include "items.h"
+#include "it_use2.h"
+#include "misc.h"
+#include "monplace.h"
+#include "mon-pick.h"
+#include "monstuff.h"
+#include "mon-util.h"
+#include "player.h"
+#include "randart.h"
+#include "spells1.h"
+#include "spl-cast.h"
+#include "spl-util.h"
+#include "stuff.h"
+#include "view.h"
+#include "wpn-misc.h"
+
+static bool monster_on_level(int monster);
+
+void cast_selective_amnesia(bool force)
+{
+ char ep_gain = 0;
+ unsigned char keyin = 0;
+
+ if (you.spell_no == 0)
+ mpr("You don't know any spells."); // re: sif muna {dlb}
+ else
+ {
+ // query - conditional ordering is important {dlb}:
+ for (;;)
+ {
+ mpr( "Forget which spell ([?*] list [ESC] exit)? ", MSGCH_PROMPT );
+
+ keyin = (unsigned char) get_ch();
+
+ if (keyin == ESCAPE)
+ return; // early return {dlb}
+
+ if (keyin == '?' || keyin == '*')
+ {
+ // this reassignment is "key" {dlb}
+ keyin = (unsigned char) list_spells();
+
+ redraw_screen();
+ }
+
+ if (!isalpha( keyin ))
+ mesclr( true );
+ else
+ break;
+ }
+
+ // actual handling begins here {dlb}:
+ const int spell = get_spell_by_letter( keyin );
+ const int slot = get_spell_slot_by_letter( keyin );
+
+ if (spell == SPELL_NO_SPELL)
+ mpr( "You don't know that spell." );
+ else
+ {
+ if (!force
+ && (you.religion != GOD_SIF_MUNA
+ && random2(you.skills[SK_SPELLCASTING])
+ < random2(spell_difficulty( spell ))))
+ {
+ mpr("Oops! This spell sure is a blunt instrument.");
+ forget_map(20 + random2(50));
+ }
+ else
+ {
+ ep_gain = spell_mana( spell );
+ del_spell_from_memory_by_slot( slot );
+
+ if (ep_gain > 0)
+ {
+ inc_mp(ep_gain, false);
+ mpr( "The spell releases its latent energy back to you as "
+ "it unravels." );
+ }
+ }
+ }
+ }
+
+ return;
+} // end cast_selective_amnesia()
+
+bool remove_curse(bool suppress_msg)
+{
+ int loopy = 0; // general purpose loop variable {dlb}
+ bool success = false; // whether or not curse(s) removed {dlb}
+
+ // special "wield slot" case - see if you can figure out why {dlb}:
+ // because only cursed weapons in hand only count as cursed -- bwr
+ if (you.equip[EQ_WEAPON] != -1
+ && you.inv[you.equip[EQ_WEAPON]].base_type == OBJ_WEAPONS)
+ {
+ if (item_cursed( you.inv[you.equip[EQ_WEAPON]] ))
+ {
+ do_uncurse_item( you.inv[you.equip[EQ_WEAPON]] );
+ success = true;
+ you.wield_change = true;
+ }
+ }
+
+ // everything else uses the same paradigm - are we certain?
+ // what of artefact rings and amulets? {dlb}:
+ for (loopy = EQ_CLOAK; loopy < NUM_EQUIP; loopy++)
+ {
+ if (you.equip[loopy] != -1 && item_cursed(you.inv[you.equip[loopy]]))
+ {
+ do_uncurse_item( you.inv[you.equip[loopy]] );
+ success = true;
+ }
+ }
+
+ // messaging output {dlb}:
+ if (!suppress_msg)
+ {
+ if (success)
+ mpr("You feel as if something is helping you.");
+ else
+ canned_msg(MSG_NOTHING_HAPPENS);
+ }
+
+ return (success);
+} // end remove_curse()
+
+bool detect_curse(bool suppress_msg)
+{
+ int loopy = 0; // general purpose loop variable {dlb}
+ bool success = false; // whether or not any curses found {dlb}
+
+ for (loopy = 0; loopy < ENDOFPACK; loopy++)
+ {
+ if (you.inv[loopy].quantity
+ && (you.inv[loopy].base_type == OBJ_WEAPONS
+ || you.inv[loopy].base_type == OBJ_ARMOUR
+ || you.inv[loopy].base_type == OBJ_JEWELLERY))
+ {
+ if (item_not_ident( you.inv[loopy], ISFLAG_KNOW_CURSE ))
+ success = true;
+
+ set_ident_flags( you.inv[loopy], ISFLAG_KNOW_CURSE );
+ }
+ }
+
+ // messaging output {dlb}:
+ if (!suppress_msg)
+ {
+ if (success)
+ mpr("You sense the presence of curses on your possessions.");
+ else
+ canned_msg(MSG_NOTHING_HAPPENS);
+ }
+
+ return (success);
+} // end detect_curse()
+
+bool cast_smiting(int power)
+{
+ bool success = false;
+ struct dist beam;
+ struct monsters *monster = 0; // NULL {dlb}
+
+ mpr("Smite whom?", MSGCH_PROMPT);
+
+ direction( beam, DIR_TARGET, TARG_ENEMY );
+
+ if (!beam.isValid
+ || mgrd[beam.tx][beam.ty] == NON_MONSTER
+ || beam.isMe)
+ {
+ canned_msg(MSG_SPELL_FIZZLES);
+ }
+ else
+ {
+ monster = &menv[mgrd[beam.tx][beam.ty]];
+
+ strcpy(info, "You smite ");
+ strcat(info, ptr_monam( monster, DESC_NOCAP_THE ));
+ strcat(info, "!");
+ mpr(info);
+
+ hurt_monster(monster, random2(8) + (random2(power) / 3));
+
+ if (monster->hit_points < 1)
+ monster_die(monster, KILL_YOU, 0);
+ else
+ print_wounds(monster);
+
+ success = true;
+ }
+
+ return (success);
+} // end cast_smiting()
+
+bool airstrike(int power)
+{
+ bool success = false;
+ struct dist beam;
+ struct monsters *monster = 0; // NULL {dlb}
+ int hurted = 0;
+
+ mpr("Strike whom?", MSGCH_PROMPT);
+
+ direction( beam, DIR_TARGET, TARG_ENEMY );
+
+ if (!beam.isValid
+ || mgrd[beam.tx][beam.ty] == NON_MONSTER
+ || beam.isMe)
+ {
+ canned_msg(MSG_SPELL_FIZZLES);
+ }
+ else
+ {
+ monster = &menv[mgrd[beam.tx][beam.ty]];
+
+ strcpy(info, "The air twists around and strikes ");
+ strcat(info, ptr_monam( monster, DESC_NOCAP_THE ));
+ strcat(info, "!");
+ mpr(info);
+
+ hurted = random2( random2(12) + (random2(power) / 6)
+ + (random2(power) / 7) );
+ hurted -= random2(1 + monster->armour_class);
+
+ if (hurted < 0)
+ hurted = 0;
+ else
+ {
+ hurt_monster(monster, hurted);
+
+ if (monster->hit_points < 1)
+ monster_die(monster, KILL_YOU, 0);
+ else
+ print_wounds(monster);
+ }
+
+ success = true;
+ }
+
+ return (success);
+} // end airstrike()
+
+bool cast_bone_shards(int power)
+{
+ bool success = false;
+ struct bolt beam;
+ struct dist spelld;
+
+ if (you.equip[EQ_WEAPON] == -1
+ || you.inv[you.equip[EQ_WEAPON]].base_type != OBJ_CORPSES)
+ {
+ canned_msg(MSG_SPELL_FIZZLES);
+ }
+ else if (you.inv[you.equip[EQ_WEAPON]].sub_type != CORPSE_SKELETON)
+ mpr("The corpse collapses into a mass of pulpy flesh.");
+ else if (spell_direction(spelld, beam) != -1)
+ {
+ // practical max of 100 * 15 + 3000 = 4500
+ // actual max of 200 * 15 + 3000 = 6000
+ power *= 15;
+ power += mons_weight( you.inv[you.equip[EQ_WEAPON]].plus );
+
+ mpr("The skeleton explodes into sharp fragments of bone!");
+
+ dec_inv_item_quantity( you.equip[EQ_WEAPON], 1 );
+ zapping(ZAP_BONE_SHARDS, power, beam);
+
+ success = true;
+ }
+
+ return (success);
+} // end cast_bone_shards()
+
+void sublimation(int power)
+{
+ unsigned char loopy = 0; // general purpose loop variable {dlb}
+
+ if (you.equip[EQ_WEAPON] == -1
+ || you.inv[you.equip[EQ_WEAPON]].base_type != OBJ_FOOD
+ || you.inv[you.equip[EQ_WEAPON]].sub_type != FOOD_CHUNK)
+ {
+ if (you.deaths_door)
+ {
+ mpr( "A conflicting enchantment prevents the spell from "
+ "coming into effect." );
+ }
+ else if (!enough_hp( 2, true ))
+ {
+ mpr("Your attempt to draw power from your own body fails.");
+ }
+ else
+ {
+ mpr("You draw magical energy from your own body!");
+
+ while (you.magic_points < you.max_magic_points && you.hp > 1)
+ {
+ inc_mp(1, false);
+ dec_hp(1, false);
+
+ for (loopy = 0; loopy < (you.hp > 1 ? 3 : 0); loopy++)
+ {
+ if (random2(power) < 6)
+ dec_hp(1, false);
+ }
+
+ if (random2(power) < 6)
+ break;
+ }
+ }
+ }
+ else
+ {
+ mpr("The chunk of flesh you are holding crumbles to dust.");
+ mpr("A flood of magical energy pours into your mind!");
+
+ inc_mp( 7 + random2(7), false );
+
+ dec_inv_item_quantity( you.equip[EQ_WEAPON], 1 );
+ }
+
+ return;
+} // end sublimation()
+
+// Simulacrum
+//
+// This spell extends creating undead to Ice mages, as such it's high
+// level, requires wielding of the material component, and the undead
+// aren't overly powerful (they're also vulnerable to fire). I've put
+// back the abjuration level in order to keep down the army sizes again.
+//
+// As for what it offers necromancers considering all the downsides
+// above... it allows the turning of a single corpse into an army of
+// monsters (one per food chunk)... which is also a good reason for
+// why it's high level.
+//
+// Hides and other "animal part" items are intentionally left out, it's
+// unrequired complexity, and fresh flesh makes more "sense" for a spell
+// reforming the original monster out of ice anyways.
+void simulacrum(int power)
+{
+ int max_num = 4 + random2(power) / 20;
+ if (max_num > 8)
+ max_num = 8;
+
+ const int chunk = you.equip[EQ_WEAPON];
+
+ if (chunk != -1
+ && is_valid_item( you.inv[ chunk ] )
+ && (you.inv[ chunk ].base_type == OBJ_CORPSES
+ || (you.inv[ chunk ].base_type == OBJ_FOOD
+ && you.inv[ chunk ].sub_type == FOOD_CHUNK)))
+ {
+ const int mons_type = you.inv[ chunk ].plus;
+
+ // Can't create more than the available chunks
+ if (you.inv[ chunk ].quantity < max_num)
+ max_num = you.inv[ chunk ].quantity;
+
+ dec_inv_item_quantity( chunk, max_num );
+
+ int summoned = 0;
+
+ for (int i = 0; i < max_num; i++)
+ {
+ if (create_monster( MONS_SIMULACRUM_SMALL, ENCH_ABJ_VI,
+ BEH_FRIENDLY, you.x_pos, you.y_pos,
+ you.pet_target, mons_type ) != -1)
+ {
+ summoned++;
+ }
+ }
+
+ if (summoned)
+ {
+ strcpy( info, (summoned == 1) ? "An icy figure forms "
+ : "Some icy figures form " );
+ strcat( info, "before you!" );
+ mpr( info );
+ }
+ else
+ mpr( "You feel cold for a second." );
+ }
+ else
+ {
+ mpr( "You need to wield a piece of raw flesh for this spell "
+ "to be effective!" );
+ }
+} // end sublimation()
+
+void dancing_weapon(int pow, bool force_hostile)
+{
+ int numsc = ENCH_ABJ_II + (random2(pow) / 5);
+ char str_pass[ ITEMNAME_SIZE ];
+
+ if (numsc > ENCH_ABJ_VI)
+ numsc = ENCH_ABJ_VI;
+
+ int i;
+ int summs = 0;
+ char behavi = BEH_FRIENDLY;
+
+ const int wpn = you.equip[EQ_WEAPON];
+
+ // See if weilded item is appropriate:
+ if (wpn == -1
+ || you.inv[wpn].base_type != OBJ_WEAPONS
+ || launches_things( you.inv[wpn].sub_type )
+ || is_fixed_artefact( you.inv[wpn] ))
+ {
+ goto failed_spell;
+ }
+
+ // See if we can get an mitm for the dancing weapon:
+ i = get_item_slot();
+ if (i == NON_ITEM)
+ goto failed_spell;
+
+ // cursed weapons become hostile
+ if (item_cursed( you.inv[wpn] ) || force_hostile)
+ behavi = BEH_HOSTILE;
+
+ summs = create_monster( MONS_DANCING_WEAPON, numsc, behavi,
+ you.x_pos, you.y_pos, you.pet_target, 1 );
+
+ if (summs < 0)
+ {
+ // must delete the item before failing!
+ mitm[i].base_type = OBJ_UNASSIGNED;
+ mitm[i].quantity = 0;
+ goto failed_spell;
+ }
+
+ // We are successful:
+ unwield_item( wpn ); // remove wield effects
+
+ // copy item (done here after any wield effects are removed)
+ mitm[i] = you.inv[wpn];
+ mitm[i].quantity = 1;
+ mitm[i].x = 0;
+ mitm[i].y = 0;
+ mitm[i].link = NON_ITEM;
+
+ in_name( wpn, DESC_CAP_YOUR, str_pass );
+ strcpy( info, str_pass );
+ strcat( info, " dances into the air!" );
+ mpr( info );
+
+ you.inv[ wpn ].quantity = 0;
+ you.equip[EQ_WEAPON] = -1;
+
+ menv[summs].inv[MSLOT_WEAPON] = i;
+ menv[summs].number = mitm[i].colour;
+
+ return;
+
+failed_spell:
+ mpr("Your weapon vibrates crazily for a second.");
+} // end dancing_weapon()
+
+static bool monster_on_level(int monster)
+{
+ for (int i = 0; i < MAX_MONSTERS; i++)
+ {
+ if (menv[i].type == monster)
+ return true;
+ }
+
+ return false;
+} // end monster_on_level()
+
+//
+// This function returns true if the player can use controlled
+// teleport here.
+//
+bool allow_control_teleport( bool silent )
+{
+ bool ret = true;
+
+ if (you.level_type == LEVEL_ABYSS || you.level_type == LEVEL_LABYRINTH)
+ ret = false;
+ else
+ {
+ switch (you.where_are_you)
+ {
+ case BRANCH_TOMB:
+ // The tomb is a laid out maze, it'd be a shame if the player
+ // just teleports through any of it... so we only allow
+ // teleport once they have the rune.
+ ret = false;
+ for (int i = 0; i < ENDOFPACK; i++)
+ {
+ if (is_valid_item( you.inv[i] )
+ && you.inv[i].base_type == OBJ_MISCELLANY
+ && you.inv[i].sub_type == MISC_RUNE_OF_ZOT
+ && you.inv[i].plus == BRANCH_TOMB)
+ {
+ ret = true;
+ break;
+ }
+ }
+ break;
+
+ case BRANCH_SLIME_PITS:
+ // Cannot teleport into the slime pit vaults until
+ // royal jelly is gone.
+ if (monster_on_level(MONS_ROYAL_JELLY))
+ ret = false;
+ break;
+
+ case BRANCH_ELVEN_HALLS:
+ // Cannot raid the elven halls vaults until fountain drained
+ if (you.branch_stairs[STAIRS_ELVEN_HALLS] +
+ branch_depth(STAIRS_ELVEN_HALLS) == you.your_level)
+ {
+ for (int x = 5; x < GXM - 5; x++)
+ {
+ for (int y = 5; y < GYM - 5; y++)
+ {
+ if (grd[x][y] == DNGN_SPARKLING_FOUNTAIN)
+ ret = false;
+ }
+ }
+ }
+ break;
+
+ case BRANCH_HALL_OF_ZOT:
+ // Cannot control teleport until the Orb is picked up
+ if (you.branch_stairs[STAIRS_HALL_OF_ZOT] +
+ branch_depth(STAIRS_HALL_OF_ZOT) == you.your_level
+ && you.char_direction != DIR_ASCENDING)
+ {
+ ret = false;
+ }
+ break;
+ }
+ }
+
+ // Tell the player why if they have teleport control.
+ if (!ret && you.attribute[ATTR_CONTROL_TELEPORT] && !silent)
+ mpr("A powerful magic prevents control of your teleportation.");
+
+ return ret;
+} // end allow_control_teleport()
+
+void you_teleport(void)
+{
+ if (scan_randarts(RAP_PREVENT_TELEPORTATION))
+ mpr("You feel a weird sense of stasis.");
+ else if (you.duration[DUR_TELEPORT])
+ {
+ mpr("You feel strangely stable.");
+ you.duration[DUR_TELEPORT] = 0;
+ }
+ else
+ {
+ mpr("You feel strangely unstable.");
+
+ you.duration[DUR_TELEPORT] = 3 + random2(3);
+
+ if (you.level_type == LEVEL_ABYSS && !one_chance_in(5))
+ {
+ mpr("You have a feeling this translocation may take a while to kick in...");
+ you.duration[DUR_TELEPORT] += 5 + random2(10);
+ }
+ }
+
+ return;
+} // end you_teleport()
+
+void you_teleport2( bool allow_control, bool new_abyss_area )
+{
+ bool is_controlled = (allow_control && !you.conf
+ && you.attribute[ATTR_CONTROL_TELEPORT]
+ && allow_control_teleport());
+
+ if (scan_randarts(RAP_PREVENT_TELEPORTATION))
+ {
+ mpr("You feel a strange sense of stasis.");
+ return;
+ }
+
+ // after this point, we're guaranteed to teleport. Turn off auto-butcher.
+ // corpses still get butchered, but at least we don't get a silly message.
+ if (current_delay_action() == DELAY_BUTCHER)
+ stop_delay();
+
+ if (you.duration[DUR_CONDENSATION_SHIELD] > 0)
+ {
+ you.duration[DUR_CONDENSATION_SHIELD] = 0;
+ you.redraw_armour_class = 1;
+ }
+
+ if (you.level_type == LEVEL_ABYSS)
+ {
+ abyss_teleport( new_abyss_area );
+ you.pet_target = MHITNOT;
+ return;
+ }
+
+ FixedVector < int, 2 > plox;
+
+ plox[0] = 1;
+ plox[1] = 0;
+
+ if (is_controlled)
+ {
+ mpr("You may choose your destination (press '.' or delete to select).");
+ mpr("Expect minor deviation.");
+ more();
+
+ show_map(plox);
+
+ redraw_screen();
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "Target square (%d,%d)", plox[0], plox[1] );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ plox[0] += random2(3) - 1;
+ plox[1] += random2(3) - 1;
+
+ if (one_chance_in(4))
+ {
+ plox[0] += random2(3) - 1;
+ plox[1] += random2(3) - 1;
+ }
+
+ if (plox[0] < 6 || plox[1] < 6 || plox[0] > (GXM - 5)
+ || plox[1] > (GYM - 5))
+ {
+ mpr("Nearby solid objects disrupt your rematerialisation!");
+ is_controlled = false;
+ }
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "Scattered target square (%d,%d)", plox[0], plox[1] );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ if (is_controlled)
+ {
+ you.x_pos = plox[0];
+ you.y_pos = plox[1];
+
+ if ((grd[you.x_pos][you.y_pos] != DNGN_FLOOR
+ && grd[you.x_pos][you.y_pos] != DNGN_SHALLOW_WATER)
+ || mgrd[you.x_pos][you.y_pos] != NON_MONSTER
+ || env.cgrid[you.x_pos][you.y_pos] != EMPTY_CLOUD)
+ {
+ is_controlled = false;
+ }
+ else
+ {
+ // controlling teleport contaminates the player -- bwr
+ contaminate_player(1);
+ }
+ }
+ } // end "if is_controlled"
+
+ if (!is_controlled)
+ {
+ mpr("Your surroundings suddenly seem different.");
+
+ do
+ {
+ you.x_pos = 5 + random2( GXM - 10 );
+ you.y_pos = 5 + random2( GYM - 10 );
+ }
+ while ((grd[you.x_pos][you.y_pos] != DNGN_FLOOR
+ && grd[you.x_pos][you.y_pos] != DNGN_SHALLOW_WATER)
+ || mgrd[you.x_pos][you.y_pos] != NON_MONSTER
+ || env.cgrid[you.x_pos][you.y_pos] != EMPTY_CLOUD);
+ }
+} // end you_teleport()
+
+bool entomb(void)
+{
+ int loopy = 0; // general purpose loop variable {dlb}
+ bool proceed = false; // loop management varaiable {dlb}
+ int which_trap = 0; // used in clearing out certain traps {dlb}
+ char srx = 0, sry = 0;
+ char number_built = 0;
+
+ FixedVector < unsigned char, 7 > safe_to_overwrite;
+
+ // hack - passing chars through '...' promotes them to ints, which
+ // barfs under gcc in fixvec.h. So don't.
+ safe_to_overwrite[0] = DNGN_FLOOR;
+ safe_to_overwrite[1] = DNGN_SHALLOW_WATER;
+ safe_to_overwrite[2] = DNGN_OPEN_DOOR;
+ safe_to_overwrite[3] = DNGN_TRAP_MECHANICAL;
+ safe_to_overwrite[4] = DNGN_TRAP_MAGICAL;
+ safe_to_overwrite[5] = DNGN_TRAP_III;
+ safe_to_overwrite[6] = DNGN_UNDISCOVERED_TRAP;
+
+
+ for (srx = you.x_pos - 1; srx < you.x_pos + 2; srx++)
+ {
+ for (sry = you.y_pos - 1; sry < you.y_pos + 2; sry++)
+ {
+ proceed = false;
+
+ // tile already occupied by monster or yourself {dlb}:
+ if (mgrd[srx][sry] != NON_MONSTER
+ || (srx == you.x_pos && sry == you.y_pos))
+ {
+ continue;
+ }
+
+ // the break here affects innermost containing loop {dlb}:
+ for (loopy = 0; loopy < 7; loopy++)
+ {
+ if (grd[srx][sry] == safe_to_overwrite[loopy])
+ {
+ proceed = true;
+ break;
+ }
+ }
+
+ // checkpoint one - do we have a legitimate tile? {dlb}
+ if (!proceed)
+ continue;
+
+ int objl = igrd[srx][sry];
+ int hrg = 0;
+
+ while (objl != NON_ITEM)
+ {
+ // hate to see the orb get detroyed by accident {dlb}:
+ if (mitm[objl].base_type == OBJ_ORBS)
+ {
+ proceed = false;
+ break;
+ }
+
+ hrg = mitm[objl].link;
+ objl = hrg;
+ }
+
+ // checkpoint two - is the orb resting in the tile? {dlb}:
+ if (!proceed)
+ continue;
+
+ objl = igrd[srx][sry];
+ hrg = 0;
+
+ while (objl != NON_ITEM)
+ {
+ hrg = mitm[objl].link;
+ destroy_item(objl);
+ objl = hrg;
+ }
+
+ // deal with clouds {dlb}:
+ if (env.cgrid[srx][sry] != EMPTY_CLOUD)
+ delete_cloud( env.cgrid[srx][sry] );
+
+ // mechanical traps are destroyed {dlb}:
+ if ((which_trap = trap_at_xy(srx, sry)) != -1)
+ {
+ if (trap_category(env.trap[which_trap].type)
+ == DNGN_TRAP_MECHANICAL)
+ {
+ env.trap[which_trap].type = TRAP_UNASSIGNED;
+ env.trap[which_trap].x = 1;
+ env.trap[which_trap].y = 1;
+ }
+ }
+
+ // finally, place the wall {dlb}:
+ grd[srx][sry] = DNGN_ROCK_WALL;
+ number_built++;
+ } // end "for srx,sry"
+ }
+
+ if (number_built > 0)
+ mpr("Walls emerge from the floor!");
+ else
+ canned_msg(MSG_NOTHING_HAPPENS);
+
+ return (number_built > 0);
+} // end entomb()
+
+void cast_poison_ammo(void)
+{
+ const int ammo = you.equip[EQ_WEAPON];
+ char str_pass[ ITEMNAME_SIZE ];
+
+ if (ammo == -1
+ || you.inv[ammo].base_type != OBJ_MISSILES
+ || get_ammo_brand( you.inv[ammo] ) != SPMSL_NORMAL
+ || you.inv[ammo].sub_type == MI_STONE
+ || you.inv[ammo].sub_type == MI_LARGE_ROCK)
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ return;
+ }
+
+ if (set_item_ego_type( you.inv[ammo], OBJ_MISSILES, SPMSL_POISONED ))
+ {
+ in_name(ammo, DESC_CAP_YOUR, str_pass);
+ strcpy(info, str_pass);
+ strcat(info, (you.inv[ammo].quantity == 1) ? " is" : " are");
+ strcat(info, " covered in a thin film of poison.");
+ mpr(info);
+
+ you.wield_change = true;
+ }
+ else
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ }
+} // end cast_poison_ammo()
+
+bool project_noise(void)
+{
+ bool success = false;
+ FixedVector < int, 2 > plox;
+
+ plox[0] = 1;
+ plox[1] = 0;
+
+ mpr( "Choose the noise's source (press '.' or delete to select)." );
+ more();
+ show_map(plox);
+
+ redraw_screen();
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "Target square (%d,%d)", plox[0], plox[1] );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ if (!silenced( plox[0], plox[1] ))
+ {
+ // player can use this spell to "sound out" the dungeon -- bwr
+ if (plox[0] > 1 && plox[0] < (GXM - 2)
+ && plox[1] > 1 && plox[1] < (GYM - 2)
+ && grd[ plox[0] ][ plox[1] ] > DNGN_LAST_SOLID_TILE)
+ {
+ noisy( 30, plox[0], plox[1] );
+ success = true;
+ }
+
+ if (!silenced( you.x_pos, you.y_pos ))
+ {
+ if (!success)
+ mpr("You hear a dull thud.");
+ else
+ {
+ snprintf( info, INFO_SIZE, "You hear a %svoice call your name.",
+ (see_grid( plox[0], plox[1] ) ? "distant " : "") );
+ mpr( info );
+ }
+ }
+ }
+
+ return (success);
+} // end project_noise()
+
+/*
+ Type recalled:
+ 0 = anything
+ 1 = undead only (Kiku religion ability)
+ */
+bool recall(char type_recalled)
+{
+ int loopy = 0; // general purpose looping variable {dlb}
+ bool success = false; // more accurately: "apparent success" {dlb}
+ int start_count = 0;
+ int step_value = 1;
+ int end_count = (MAX_MONSTERS - 1);
+ FixedVector < char, 2 > empty;
+ struct monsters *monster = 0; // NULL {dlb}
+
+ empty[0] = empty[1] = 0;
+
+// someone really had to make life difficult {dlb}:
+// sometimes goes through monster list backwards
+ if (coinflip())
+ {
+ start_count = (MAX_MONSTERS - 1);
+ end_count = 0;
+ step_value = -1;
+ }
+
+ for (loopy = start_count; loopy != end_count; loopy += step_value)
+ {
+ monster = &menv[loopy];
+
+ if (monster->type == -1)
+ continue;
+
+ if (!mons_friendly(monster))
+ continue;
+
+ if (monster_habitat(monster->type) != DNGN_FLOOR)
+ continue;
+
+ if (type_recalled == 1)
+ {
+ /* abomin created by twisted res, although it gets others too */
+ if ( !((monster->type == MONS_ABOMINATION_SMALL
+ || monster->type == MONS_ABOMINATION_LARGE)
+ && (monster->number == BROWN
+ || monster->number == RED
+ || monster->number == LIGHTRED)) )
+ {
+ if (monster->type != MONS_REAPER
+ && mons_holiness(monster->type) != MH_UNDEAD)
+ {
+ continue;
+ }
+ }
+ }
+
+ if (empty_surrounds(you.x_pos, you.y_pos, DNGN_FLOOR, false, empty))
+ {
+ // clear old cell pointer -- why isn't there a function for moving a monster?
+ mgrd[monster->x][monster->y] = NON_MONSTER;
+ // set monster x,y to new value
+ monster->x = empty[0];
+ monster->y = empty[1];
+ // set new monster grid pointer to this monster.
+ mgrd[monster->x][monster->y] = monster_index(monster);
+
+ // only informed if monsters recalled are visible {dlb}:
+ if (simple_monster_message(monster, " is recalled."))
+ success = true;
+ }
+ else
+ {
+ break; // no more room to place monsters {dlb}
+ }
+ }
+
+ if (!success)
+ mpr("Nothing appears to have answered your call.");
+
+ return (success);
+} // end recall()
+
+void portal(void)
+{
+ char dir_sign = 0;
+ unsigned char keyi;
+ int target_level = 0;
+ int old_level = you.your_level;
+
+ if (!player_in_branch( BRANCH_MAIN_DUNGEON ))
+ {
+ mpr("This spell doesn't work here.");
+ }
+ else if (grd[you.x_pos][you.y_pos] != DNGN_FLOOR)
+ {
+ mpr("You must find a clear area in which to cast this spell.");
+ }
+ else
+ {
+ // the first query {dlb}:
+ mpr("Which direction ('<' for up, '>' for down, 'x' to quit)?", MSGCH_PROMPT);
+
+ for (;;)
+ {
+ keyi = (unsigned char) get_ch();
+
+ if (keyi == '<')
+ {
+ if (you.your_level == 0)
+ mpr("You can't go any further upwards with this spell.");
+ else
+ {
+ dir_sign = -1;
+ break;
+ }
+ }
+
+ if (keyi == '>')
+ {
+ if (you.your_level == 35)
+ mpr("You can't go any further downwards with this spell.");
+ else
+ {
+ dir_sign = 1;
+ break;
+ }
+ }
+
+ if (keyi == 'x')
+ {
+ canned_msg(MSG_OK);
+ return; // an early return {dlb}
+ }
+ }
+
+ // the second query {dlb}:
+ mpr("How many levels (1 - 9, 'x' to quit)?", MSGCH_PROMPT);
+
+ for (;;)
+ {
+ keyi = (unsigned char) get_ch();
+
+ if (keyi == 'x')
+ {
+ canned_msg(MSG_OK);
+ return; // another early return {dlb}
+ }
+
+ if (!(keyi < '1' || keyi > '9'))
+ {
+ target_level = you.your_level + ((keyi - '0') * dir_sign);
+ break;
+ }
+ }
+
+ // actual handling begins here {dlb}:
+ if (player_in_branch( BRANCH_MAIN_DUNGEON ))
+ {
+ if (target_level < 0)
+ target_level = 0;
+ else if (target_level > 26)
+ target_level = 26;
+ }
+
+ mpr( "You fall through a mystic portal, and materialise at the "
+ "foot of a staircase." );
+ more();
+
+ you.your_level = target_level - 1;
+ grd[you.x_pos][you.y_pos] = DNGN_STONE_STAIRS_DOWN_I;
+
+ down_stairs( true, old_level );
+ untag_followers();
+ }
+
+ return;
+} // end portal()
+
+bool cast_death_channel(int power)
+{
+ bool success = false;
+
+ if (you.duration[DUR_DEATH_CHANNEL] < 30)
+ {
+ mpr("Malign forces permeate your being, awaiting release.");
+
+ you.duration[DUR_DEATH_CHANNEL] += 15 + random2(1 + (power / 3));
+
+ if (you.duration[DUR_DEATH_CHANNEL] > 100)
+ you.duration[DUR_DEATH_CHANNEL] = 100;
+
+ success = true;
+ }
+ else
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ }
+
+ return (success);
+} // end cast_death_channel()
diff --git a/trunk/source/spells3.h b/trunk/source/spells3.h
new file mode 100644
index 0000000000..5b10dd3026
--- /dev/null
+++ b/trunk/source/spells3.h
@@ -0,0 +1,142 @@
+/*
+ * File: spells3.cc
+ * Summary: Implementations of some additional spells.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef SPELLS3_H
+#define SPELLS3_H
+
+
+// updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: spells1 - spells3
+ * *********************************************************************** */
+bool allow_control_teleport( bool silent = false );
+
+
+// updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: spell
+ * *********************************************************************** */
+bool airstrike(int power);
+
+
+// updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: spell
+ * *********************************************************************** */
+bool cast_bone_shards(int power);
+
+
+// updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: spell - spells1
+ * *********************************************************************** */
+bool cast_death_channel(int power);
+
+
+// updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: spell
+ * *********************************************************************** */
+void cast_poison_ammo(void);
+
+
+// updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - spell
+ * *********************************************************************** */
+void cast_selective_amnesia(bool force);
+
+
+// updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - spell
+ * *********************************************************************** */
+bool cast_smiting(int power);
+
+
+// updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: spell
+ * *********************************************************************** */
+bool project_noise(void);
+
+
+// updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: religion - spell
+ * *********************************************************************** */
+void dancing_weapon(int pow, bool force_hostile);
+
+
+// updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: item_use - spell
+ * *********************************************************************** */
+bool detect_curse(bool suppress_msg);
+
+
+// updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: decks - spell
+ * *********************************************************************** */
+bool entomb(void);
+
+
+// updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: spell
+ * *********************************************************************** */
+void portal(void);
+
+
+// updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - spell
+ * *********************************************************************** */
+bool recall(char type_recalled);
+
+
+// updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: item_use - spell
+ * *********************************************************************** */
+bool remove_curse(bool suppress_msg);
+
+
+// updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: spell
+ * *********************************************************************** */
+void sublimation(int power);
+
+
+// updated Oct 2 -- bwr
+/* ***********************************************************************
+ * called from: spell
+ * *********************************************************************** */
+void simulacrum(int power);
+
+
+// updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - beam - decks - fight - item_use - spell
+ * *********************************************************************** */
+void you_teleport(void);
+
+
+// updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - acr - decks - effects - fight - misc - spells
+ * *********************************************************************** */
+void you_teleport2( bool allow_control, bool new_abyss_area = false );
+
+
+#endif
diff --git a/trunk/source/spells4.cc b/trunk/source/spells4.cc
new file mode 100644
index 0000000000..46ac36ebd0
--- /dev/null
+++ b/trunk/source/spells4.cc
@@ -0,0 +1,3211 @@
+/*
+ * File: spells4.cc
+ * Summary: new spells, focusing on transmigration, divination and
+ * other neglected areas of Crawl magic ;^)
+ * Written by: Copyleft Josh Fishman 1999-2000, All Rights Preserved
+ *
+ * Change History (most recent first):
+ *
+ * <2> 29jul2000 jdj Made a zillion functions static.
+ * <1> 06jan2000 jmf Created
+ */
+
+#include "AppHdr.h"
+
+#include <string>
+#include <stdio.h>
+
+#include "externs.h"
+
+#include "abyss.h"
+#include "beam.h"
+#include "cloud.h"
+#include "debug.h"
+#include "delay.h"
+#include "describe.h"
+#include "direct.h"
+#include "dungeon.h"
+#include "effects.h"
+#include "it_use2.h"
+#include "itemname.h"
+#include "items.h"
+#include "invent.h"
+#include "misc.h"
+#include "monplace.h"
+#include "monstuff.h"
+#include "mon-util.h"
+#include "mstuff2.h"
+#include "ouch.h"
+#include "player.h"
+#include "randart.h"
+#include "religion.h"
+#include "skills.h"
+#include "spells1.h"
+#include "spells4.h"
+#include "spl-cast.h"
+#include "spl-util.h"
+#include "stuff.h"
+#include "view.h"
+
+enum DEBRIS // jmf: add for shatter, dig, and Giants to throw
+{
+ DEBRIS_METAL, // 0
+ DEBRIS_ROCK,
+ DEBRIS_STONE,
+ DEBRIS_WOOD,
+ DEBRIS_CRYSTAL,
+ NUM_DEBRIS
+}; // jmf: ...and I'll actually implement the items Real Soon Now...
+
+static bool mons_can_host_shuggoth(int type);
+// static int make_a_random_cloud(int x, int y, int pow, int ctype);
+static int make_a_rot_cloud(int x, int y, int pow, int ctype);
+static int quadrant_blink(int x, int y, int pow, int garbage);
+
+//void cast_animate_golem(int pow); // see actual function for reasoning {dlb}
+//void cast_detect_magic(int pow); //jmf: as above...
+//void cast_eringyas_surprising_bouquet(int powc);
+void do_monster_rot(int mon);
+
+//jmf: FIXME: put somewhere else (misc.cc?)
+// A feeble attempt at Nethack-like completeness for cute messages.
+const char *your_hand( bool plural )
+{
+ static char hand_buff[80];
+
+ switch (you.attribute[ATTR_TRANSFORMATION])
+ {
+ default:
+ mpr("ERROR: unknown transformation in your_hand() (spells4.cc)");
+ case TRAN_NONE:
+ case TRAN_STATUE:
+ if (you.species == SP_TROLL || you.species == SP_GHOUL)
+ {
+ strcpy(hand_buff, "claw");
+ break;
+ }
+ // or fall-through
+ case TRAN_ICE_BEAST:
+ case TRAN_LICH:
+ strcpy(hand_buff, "hand");
+ break;
+ case TRAN_SPIDER:
+ strcpy(hand_buff, "front leg");
+ break;
+ case TRAN_SERPENT_OF_HELL:
+ case TRAN_DRAGON:
+ strcpy(hand_buff, "foreclaw");
+ break;
+ case TRAN_BLADE_HANDS:
+ strcpy(hand_buff, "scythe-like blade");
+ break;
+ case TRAN_AIR:
+ strcpy(hand_buff, "misty tendril");
+ break;
+ }
+
+ if (plural)
+ strcat(hand_buff, "s");
+
+ return (hand_buff);
+}
+
+// I need to make some debris for metal, crystal and stone.
+// They could go in OBJ_MISSILES, but I think I'd rather move
+// MI_LARGE_ROCK into OBJ_DEBRIS and code giants to throw any
+// OBJ_DEBRIS they get their meaty mits on.
+static void place_debris(int x, int y, int debris_type)
+{
+#ifdef USE_DEBRIS_CODE
+ switch (debris_type)
+ {
+ // hate to say this, but the first parameter only allows specific quantity
+ // for *food* and nothing else -- and I would hate to see that parameter
+ // (force_unique) abused any more than it already has been ... {dlb}:
+ case DEBRIS_STONE:
+ large = items( random2(3), OBJ_MISSILES, MI_LARGE_ROCK, true, 1, 250 );
+ small = items( 3 + random2(6) + random2(6) + random2(6),
+ OBJ_MISSILES, MI_STONE, true, 1, 250 );
+ break;
+ case DEBRIS_METAL:
+ case DEBRIS_WOOD:
+ case DEBRIS_CRYSTAL:
+ break;
+ }
+
+ if (small != NON_ITEM)
+ move_item_to_grid( &small, x, y );
+
+ if (large != NON_ITEM)
+ move_item_to_grid( &large, x, y );
+
+#else
+ UNUSED( x );
+ UNUSED( y );
+ UNUSED( debris_type );
+ return;
+#endif
+} // end place_debris()
+
+// just to avoid typing this over and over
+// now returns true if monster died -- bwr
+inline bool player_hurt_monster(int monster, int damage)
+{
+ ASSERT( monster != NON_MONSTER );
+
+ if (damage > 0)
+ {
+ hurt_monster( &menv[monster], damage );
+
+ if (menv[monster].hit_points > 0)
+ print_wounds( &menv[monster] );
+ else
+ {
+ monster_die( &menv[monster], KILL_YOU, 0 );
+ return (true);
+ }
+ }
+
+ return (false);
+} // end player_hurt_monster()
+
+
+// Here begin the actual spells:
+static int shatter_monsters(int x, int y, int pow, int garbage)
+{
+ UNUSED( garbage );
+
+ dice_def dam_dice( 0, 5 + pow / 4 ); // number of dice set below
+ const int monster = mgrd[x][y];
+
+ if (monster == NON_MONSTER)
+ return (0);
+
+ // Removed a lot of silly monsters down here... people, just because
+ // it says ice, rock, or iron in the name doesn't mean it's actually
+ // made out of the substance. -- bwr
+ switch (menv[monster].type)
+ {
+ case MONS_ICE_BEAST: // 3/2 damage
+ case MONS_SIMULACRUM_SMALL:
+ case MONS_SIMULACRUM_LARGE:
+ dam_dice.num = 4;
+ break;
+
+ case MONS_SKELETON_SMALL: // double damage
+ case MONS_SKELETON_LARGE:
+ case MONS_CURSE_SKULL:
+ case MONS_CLAY_GOLEM:
+ case MONS_STONE_GOLEM:
+ case MONS_IRON_GOLEM:
+ case MONS_CRYSTAL_GOLEM:
+ case MONS_EARTH_ELEMENTAL:
+ case MONS_GARGOYLE:
+ case MONS_SKELETAL_DRAGON:
+ case MONS_SKELETAL_WARRIOR:
+ dam_dice.num = 6;
+ break;
+
+ case MONS_VAPOUR:
+ case MONS_INSUBSTANTIAL_WISP:
+ case MONS_AIR_ELEMENTAL:
+ case MONS_FIRE_ELEMENTAL:
+ case MONS_WATER_ELEMENTAL:
+ case MONS_SPECTRAL_WARRIOR:
+ case MONS_FREEZING_WRAITH:
+ case MONS_WRAITH:
+ case MONS_PHANTOM:
+ case MONS_PLAYER_GHOST:
+ case MONS_SHADOW:
+ case MONS_HUNGRY_GHOST:
+ case MONS_FLAYED_GHOST:
+ case MONS_SMOKE_DEMON: //jmf: I hate these bastards...
+ dam_dice.num = 0;
+ break;
+
+ case MONS_PULSATING_LUMP:
+ case MONS_JELLY:
+ case MONS_SLIME_CREATURE:
+ case MONS_BROWN_OOZE:
+ case MONS_AZURE_JELLY:
+ case MONS_DEATH_OOZE:
+ case MONS_ACID_BLOB:
+ case MONS_ROYAL_JELLY:
+ case MONS_OOZE:
+ case MONS_SPECTRAL_THING:
+ case MONS_JELLYFISH:
+ dam_dice.num = 1;
+ dam_dice.size /= 2;
+ break;
+
+ case MONS_DANCING_WEAPON: // flies, but earth based
+ case MONS_MOLTEN_GARGOYLE:
+ case MONS_QUICKSILVER_DRAGON:
+ // Soft, earth creatures... would normally resist to 1 die, but
+ // are sensitive to this spell. -- bwr
+ dam_dice.num = 2;
+ break;
+
+ default: // normal damage
+ if (mons_flies( &menv[monster] ))
+ dam_dice.num = 1;
+ else
+ dam_dice.num = 3;
+ break;
+ }
+
+ int damage = roll_dice( dam_dice ) - random2( menv[monster].armour_class );
+
+ if (damage > 0)
+ player_hurt_monster( monster, damage );
+ else
+ damage = 0;
+
+ return (damage);
+} // end shatter_monsters()
+
+static int shatter_items(int x, int y, int pow, int garbage)
+{
+ UNUSED( pow );
+ UNUSED( garbage );
+
+ int broke_stuff = 0, next, obj = igrd[x][y];
+
+ if (obj == NON_ITEM)
+ return 0;
+
+ while (obj != NON_ITEM)
+ {
+ next = mitm[obj].link;
+
+ switch (mitm[obj].base_type)
+ {
+ case OBJ_POTIONS:
+ if (!one_chance_in(10))
+ {
+ broke_stuff++;
+ destroy_item(obj);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ obj = next;
+ }
+
+ if (broke_stuff)
+ {
+ if (!silenced(x, y) && !silenced(you.x_pos, you.y_pos))
+ mpr("You hear glass break.");
+
+ return 1;
+ }
+
+ return 0;
+} // end shatter_items()
+
+static int shatter_walls(int x, int y, int pow, int garbage)
+{
+ UNUSED( garbage );
+
+ int chance = 0;
+ int stuff = 0;
+
+ // if not in-bounds then we can't really shatter it -- bwr
+ if (x <= 5 || x >= GXM - 5 || y <= 5 || y >= GYM - 5)
+ return (0);
+
+ switch (grd[x][y])
+ {
+ case DNGN_SECRET_DOOR:
+ if (see_grid(x, y))
+ mpr("A secret door shatters!");
+ grd[x][y] = DNGN_FLOOR;
+ stuff = DEBRIS_WOOD;
+ chance = 100;
+ break;
+
+ case DNGN_CLOSED_DOOR:
+ case DNGN_OPEN_DOOR:
+ if (see_grid(x, y))
+ mpr("A door shatters!");
+ grd[x][y] = DNGN_FLOOR;
+ stuff = DEBRIS_WOOD;
+ chance = 100;
+ break;
+
+ case DNGN_METAL_WALL:
+ case DNGN_SILVER_STATUE:
+ stuff = DEBRIS_METAL;
+ chance = pow / 10;
+ break;
+
+ case DNGN_ORCISH_IDOL:
+ case DNGN_GRANITE_STATUE:
+ chance = 50;
+ stuff = DEBRIS_STONE;
+ break;
+
+ case DNGN_STONE_WALL:
+ chance = pow / 6;
+ stuff = DEBRIS_STONE;
+ break;
+
+ case DNGN_ROCK_WALL:
+ chance = pow / 4;
+ stuff = DEBRIS_ROCK;
+ break;
+
+ case DNGN_ORANGE_CRYSTAL_STATUE:
+ chance = pow / 6;
+ stuff = DEBRIS_CRYSTAL;
+ break;
+
+ case DNGN_GREEN_CRYSTAL_WALL:
+ chance = 50;
+ stuff = DEBRIS_CRYSTAL;
+ break;
+
+ default:
+ break;
+ }
+
+ if (stuff && random2(100) < chance)
+ {
+ if (!silenced( x, y ))
+ noisy( 30, x, y );
+
+ grd[x][y] = DNGN_FLOOR;
+ place_debris(x, y, stuff);
+ return (1);
+ }
+
+ return (0);
+} // end shatter_walls()
+
+void cast_shatter(int pow)
+{
+ int damage = 0;
+ const bool sil = silenced( you.x_pos, you.y_pos );
+
+ if (!sil)
+ noisy( 30, you.x_pos, you.y_pos );
+
+ snprintf(info, INFO_SIZE, "The dungeon %s!", (sil ? "shakes" : "rumbles"));
+ mpr(info);
+
+ switch (you.attribute[ATTR_TRANSFORMATION])
+ {
+ case TRAN_NONE:
+ case TRAN_SPIDER:
+ case TRAN_LICH:
+ case TRAN_DRAGON:
+ case TRAN_AIR:
+ case TRAN_SERPENT_OF_HELL:
+ break;
+
+ case TRAN_STATUE: // full damage
+ damage = 15 + random2avg( (pow / 5), 4 );
+ break;
+
+ case TRAN_ICE_BEAST: // 1/2 damage
+ damage = 10 + random2avg( (pow / 5), 4 ) / 2;
+ break;
+
+ case TRAN_BLADE_HANDS: // 2d3 damage
+ mpr("Your scythe-like blades vibrate painfully!");
+ damage = 2 + random2avg(5, 2);
+ break;
+
+ default:
+ mpr("cast_shatter(): unknown transformation in spells4.cc");
+ }
+
+ if (damage)
+ ouch(damage, 0, KILLED_BY_TARGETTING);
+
+ int rad = 3 + (you.skills[SK_EARTH_MAGIC] / 5);
+
+ apply_area_within_radius(shatter_items, you.x_pos, you.y_pos, pow, rad, 0);
+ apply_area_within_radius(shatter_monsters, you.x_pos, you.y_pos, pow, rad, 0);
+ int dest = apply_area_within_radius( shatter_walls, you.x_pos, you.y_pos,
+ pow, rad, 0 );
+
+ if (dest && !sil)
+ mpr("Ka-crash!");
+} // end cast_shatter()
+
+// cast_forescry: raises evasion (by 8 currently) via divination
+void cast_forescry(int pow)
+{
+ if (!you.duration[DUR_FORESCRY])
+ mpr("You begin to receive glimpses of the immediate future...");
+
+ you.duration[DUR_FORESCRY] += 5 + random2(pow);
+
+ if (you.duration[DUR_FORESCRY] > 30)
+ you.duration[DUR_FORESCRY] = 30;
+
+ you.redraw_evasion = 1;
+} // end cast_forescry()
+
+void cast_see_invisible(int pow)
+{
+ if (player_see_invis())
+ mpr("Nothing seems to happen.");
+ else
+ mpr("Your vision seems to sharpen.");
+
+ // no message if you already are under the spell
+ you.duration[DUR_SEE_INVISIBLE] += 10 + random2(2 + (pow / 2));
+
+ if (you.duration[DUR_SEE_INVISIBLE] > 100)
+ you.duration[DUR_SEE_INVISIBLE] = 100;
+} // end cast_see_invisible()
+
+#if 0
+// FIXME: This would be kinda cool if implemented right.
+// The idea is that, like detect_secret_doors, the spell gathers all
+// sorts of information about a thing and then tells the caster a few
+// cryptic hints. So for a (+3,+5) Mace of Flaming, one might detect
+// "enchantment and heat", but for a cursed ring of hunger, one might
+// detect "enchantment and ice" (since it gives you a 'deathly cold'
+// feeling when you put it on) or "necromancy" (since it's evil).
+// A weapon of Divine Wrath and a randart that makes you angry might
+// both give similar messages. The key would be to not tell more than
+// hints about whether an item is benign or cursed, but give info
+// on how strong its enchantment is (and therefore how valuable it
+// probably is).
+static void cast_detect_magic(int pow)
+{
+ struct dist bmove;
+ int x, y;
+ int monster = 0, item = 0, next; //int max;
+ FixedVector < int, NUM_SPELL_TYPES > found;
+ int strong = 0; // int curse = 0;
+
+ for (next = 0; next < NUM_SPELL_TYPES; next++)
+ {
+ found[next] = 0;
+ }
+
+ mpr("Which direction?", MSGCH_PROMPT);
+ direction( bmove, DIR_DIR );
+
+ if (!bmove.isValid)
+ {
+ canned_msg(MSG_SPELL_FIZZLES);
+ return;
+ }
+
+ if (bmove.dx == 0 && bmove.dy == 0)
+ {
+ mpr("You detect a divination in progress.");
+ return;
+ }
+
+ x = you.x_pos + bmove.dx;
+ y = you.y_pos + bmove.dy;
+
+ monster = mgrd[x][y];
+ if (monster == NON_MONSTER)
+ goto do_items;
+ else
+ goto all_done;
+
+ do_items:
+ item = igrd[x][y];
+
+ if (item == NON_ITEM)
+ goto all_done;
+
+ while (item != NON_ITEM)
+ {
+ next = mitm[item].link;
+ if (is_dumpable_artifact
+ (mitm[item].base_type, mitm[item].sub_type, mitm[item].plus,
+ mitm[item].plus2, mitm[item].special, 0, 0))
+ {
+ strong++;
+ //FIXME: do checks for randart properties
+ }
+ else
+ {
+ switch (mitm[item].base_type)
+ {
+ case OBJ_WEAPONS:
+ found[SPTYP_ENCHANTMENT] += (mitm[item].plus > 50);
+ found[SPTYP_ENCHANTMENT] += (mitm[item].plus2 > 50);
+ break;
+
+ case OBJ_MISSILES:
+ found[SPTYP_ENCHANTMENT] += (mitm[item].plus > 50);
+ found[SPTYP_ENCHANTMENT] += (mitm[item].plus2 > 50);
+ break;
+
+ case OBJ_ARMOUR:
+ found[SPTYP_ENCHANTMENT] += mitm[item].plus;
+ }
+ }
+ }
+
+ all_done:
+ if (monster)
+ {
+ mpr("You detect a morphogenic field, such as a monster might have.");
+ }
+ if (strong)
+ {
+ mpr("You detect very strong enchantments.");
+ return;
+ }
+ else
+ {
+ //FIXME:
+ }
+ return;
+}
+#endif
+
+// The description idea was okay, but this spell just isn't that exciting.
+// So I'm converting it to the more practical expose secret doors. -- bwr
+void cast_detect_secret_doors(int pow)
+{
+ int found = 0;
+
+ for (int x = you.x_pos - 8; x <= you.x_pos + 8; x++)
+ {
+ for (int y = you.y_pos - 8; y <= you.y_pos + 8; y++)
+ {
+ if (x < 5 || x > GXM - 5 || y < 5 || y > GYM - 5)
+ continue;
+
+ if (!see_grid(x, y))
+ continue;
+
+ if (grd[x][y] == DNGN_SECRET_DOOR && random2(pow) > random2(15))
+ {
+ grd[x][y] = DNGN_CLOSED_DOOR;
+ found++;
+ }
+ }
+ }
+
+ if (found)
+ {
+ redraw_screen();
+
+ snprintf( info, INFO_SIZE, "You detect %s secret door%s.",
+ (found > 1) ? "some" : "a", (found > 1) ? "s" : "" );
+ mpr( info );
+ }
+} // end cast_detect_secret_doors()
+
+void cast_summon_butterflies(int pow)
+{
+ // explicitly limiting the number
+ int num = 4 + random2(3) + random2( pow ) / 10;
+ if (num > 16)
+ num = 16;
+
+ for (int scount = 1; scount < num; scount++)
+ {
+ create_monster( MONS_BUTTERFLY, ENCH_ABJ_III, BEH_FRIENDLY,
+ you.x_pos, you.y_pos, MHITYOU, 250 );
+ }
+}
+
+void cast_summon_large_mammal(int pow)
+{
+ int mon;
+ int temp_rand = random2(pow);
+
+ if (temp_rand < 10)
+ mon = MONS_JACKAL;
+ else if (temp_rand < 15)
+ mon = MONS_HOUND;
+ else
+ {
+ switch (temp_rand % 7)
+ {
+ case 0:
+ if (you.species == SP_HILL_ORC && one_chance_in(3))
+ mon = MONS_WARG;
+ else
+ mon = MONS_WOLF;
+ break;
+ case 1:
+ case 2:
+ mon = MONS_WAR_DOG;
+ break;
+ case 3:
+ case 4:
+ mon = MONS_HOUND;
+ break;
+ default:
+ mon = MONS_JACKAL;
+ break;
+ }
+ }
+
+ create_monster( mon, ENCH_ABJ_III, BEH_FRIENDLY, you.x_pos, you.y_pos,
+ you.pet_target, 250 );
+}
+
+void cast_sticks_to_snakes(int pow)
+{
+ int mon, i, behaviour;
+
+ int how_many = 0;
+
+ int max = 1 + random2( 1 + you.skills[SK_TRANSMIGRATION] ) / 4;
+
+ int dur = ENCH_ABJ_III + random2(pow) / 20;
+ if (dur > ENCH_ABJ_V)
+ dur = ENCH_ABJ_V;
+
+ const int weapon = you.equip[EQ_WEAPON];
+
+ if (weapon == -1)
+ {
+ snprintf( info, INFO_SIZE, "Your %s feel slithery!", your_hand(true));
+ mpr(info);
+ return;
+ }
+
+ behaviour = item_cursed( you.inv[ weapon ] ) ? BEH_HOSTILE
+ : BEH_FRIENDLY;
+
+ if ((you.inv[ weapon ].base_type == OBJ_MISSILES
+ && (you.inv[ weapon ].sub_type == MI_ARROW)))
+ {
+ if (you.inv[ weapon ].quantity < max)
+ max = you.inv[ weapon ].quantity;
+
+ for (i = 0; i <= max; i++)
+ {
+ //jmf: perhaps also check for poison ammo?
+ if (pow > 50 || (pow > 25 && one_chance_in(3)))
+ mon = MONS_SNAKE;
+ else
+ mon = MONS_SMALL_SNAKE;
+
+ if (create_monster( mon, dur, behaviour, you.x_pos, you.y_pos,
+ MHITYOU, 250 ) != -1)
+ {
+ how_many++;
+ }
+ }
+ }
+
+ if (you.inv[ weapon ].base_type == OBJ_WEAPONS
+ && (you.inv[ weapon ].sub_type == WPN_CLUB
+ || you.inv[ weapon ].sub_type == WPN_SPEAR
+ || you.inv[ weapon ].sub_type == WPN_QUARTERSTAFF
+ || you.inv[ weapon ].sub_type == WPN_SCYTHE
+ || you.inv[ weapon ].sub_type == WPN_GIANT_CLUB
+ || you.inv[ weapon ].sub_type == WPN_GIANT_SPIKED_CLUB
+ || you.inv[ weapon ].sub_type == WPN_BOW
+ || you.inv[ weapon ].sub_type == WPN_ANCUS
+ || you.inv[ weapon ].sub_type == WPN_HALBERD
+ || you.inv[ weapon ].sub_type == WPN_GLAIVE
+ || you.inv[ weapon ].sub_type == WPN_BLOWGUN))
+ {
+ how_many = 1;
+
+ // Upsizing Snakes to Brown Snakes as the base class for using
+ // the really big sticks (so bonus applies really only to trolls,
+ // ogres, and most importantly ogre magi). Still it's unlikely
+ // any character is strong enough to bother lugging a few of
+ // these around. -- bwr
+ if (mass_item( you.inv[ weapon ] ) < 500)
+ mon = MONS_SNAKE;
+ else
+ mon = MONS_BROWN_SNAKE;
+
+ if (pow > 90 && one_chance_in(3))
+ mon = MONS_GREY_SNAKE;
+
+ if (pow > 70 && one_chance_in(3))
+ mon = MONS_BLACK_SNAKE;
+
+ if (pow > 40 && one_chance_in(3))
+ mon = MONS_YELLOW_SNAKE;
+
+ if (pow > 20 && one_chance_in(3))
+ mon = MONS_BROWN_SNAKE;
+
+ create_monster(mon, dur, behaviour, you.x_pos, you.y_pos, MHITYOU, 250);
+ }
+
+#ifdef USE_DEBRIS_CODE
+ if (you.inv[ weapon ].base_type == OBJ_DEBRIS
+ && (you.inv[ weapon ].sub_type == DEBRIS_WOOD))
+ {
+ // this is how you get multiple big snakes
+ how_many = 1;
+ mpr("FIXME: implement OBJ_DEBRIS conversion! (spells4.cc)");
+ }
+#endif // USE_DEBRIS_CODE
+
+ if (how_many > you.inv[you.equip[EQ_WEAPON]].quantity)
+ how_many = you.inv[you.equip[EQ_WEAPON]].quantity;
+
+ if (how_many)
+ {
+ dec_inv_item_quantity( you.equip[EQ_WEAPON], how_many );
+
+ snprintf( info, INFO_SIZE, "You create %s snake%s!",
+ how_many > 1 ? "some" : "a", how_many > 1 ? "s" : "");
+ }
+ else
+ {
+ snprintf( info, INFO_SIZE, "Your %s feel slithery!", your_hand(true));
+ }
+
+ mpr(info);
+ return;
+} // end cast_sticks_to_snakes()
+
+void cast_summon_dragon(int pow)
+{
+ int happy;
+
+ // Removed the chance of multiple dragons... one should be more
+ // than enough, and if it isn't, the player can cast again...
+ // especially since these aren't on the Abjuration plan... they'll
+ // last until they die (maybe that should be changed, but this is
+ // a very high level spell so it might be okay). -- bwr
+ happy = (random2(pow) > 5);
+
+ if (create_monster( MONS_DRAGON, ENCH_ABJ_III,
+ (happy ? BEH_FRIENDLY : BEH_HOSTILE),
+ you.x_pos, you.y_pos, MHITYOU, 250 ) != -1)
+ {
+ strcpy(info, "A dragon appears.");
+
+ if (!happy)
+ strcat(info, " It doesn't look very happy.");
+ }
+ else
+ strcpy(info, "Nothing happens.");
+
+ mpr(info);
+} // end cast_summon_dragon()
+
+void cast_conjure_ball_lightning( int pow )
+{
+ int num = 3 + random2( 2 + pow / 50 );
+
+ // but restricted so that the situation doesn't get too gross.
+ // Each of these will explode for 3d20 damage. -- bwr
+ if (num > 8)
+ num = 8;
+
+ bool summoned = false;
+
+ for (int i = 0; i < num; i++)
+ {
+ int tx = -1, ty = -1;
+
+ for (int j = 0; j < 10; j++)
+ {
+ if (!random_near_space( you.x_pos, you.y_pos, tx, ty, true, true)
+ && distance( you.x_pos, you.y_pos, tx, ty ) <= 5)
+ {
+ break;
+ }
+ }
+
+ // if we fail, we'll try the ol' summon next to player trick.
+ if (tx == -1 || ty == -1)
+ {
+ tx = you.x_pos;
+ ty = you.y_pos;
+ }
+
+ int mon = mons_place( MONS_BALL_LIGHTNING, BEH_FRIENDLY, MHITNOT,
+ true, tx, ty );
+
+ // int mon = create_monster( MONS_BALL_LIGHTNING, 0, BEH_FRIENDLY,
+ // tx, ty, MHITNOT, 250 );
+
+ if (mon != -1)
+ {
+ mons_add_ench( &menv[mon], ENCH_SHORT_LIVED );
+ summoned = true;
+ }
+ }
+
+ if (summoned)
+ mpr( "You create some ball lightning!" );
+ else
+ canned_msg( MSG_NOTHING_HAPPENS );
+}
+
+static int sleep_monsters(int x, int y, int pow, int garbage)
+{
+ UNUSED( garbage );
+ int mnstr = mgrd[x][y];
+
+ if (mnstr == NON_MONSTER) return 0;
+ if (mons_holiness( menv[mnstr].type ) != MH_NATURAL) return 0;
+ if (check_mons_resist_magic( &menv[mnstr], pow )) return 0;
+
+ // Why shouldn't we be able to sleep friendly monsters? -- bwr
+ // if (mons_friendly( &menv[mnstr] )) return 0;
+
+ //jmf: now that sleep == hibernation:
+ if (mons_res_cold( &menv[mnstr] ) > 0 && coinflip()) return 0;
+ if (mons_has_ench( &menv[mnstr], ENCH_SLEEP_WARY )) return 0;
+
+ menv[mnstr].behaviour = BEH_SLEEP;
+ mons_add_ench( &menv[mnstr], ENCH_SLEEP_WARY );
+
+ if (mons_flag( menv[mnstr].type, M_COLD_BLOOD ) && coinflip())
+ mons_add_ench( &menv[mnstr], ENCH_SLOW );
+
+ return 1;
+} // end sleep_monsters()
+
+void cast_mass_sleep(int pow)
+{
+ apply_area_visible(sleep_monsters, pow);
+} // end cast_mass_sleep()
+
+static int tame_beast_monsters(int x, int y, int pow, int garbage)
+{
+ UNUSED( garbage );
+ int which_mons = mgrd[x][y];
+
+ if (which_mons == NON_MONSTER) return 0;
+
+ struct monsters *monster = &menv[which_mons];
+
+ if (mons_holiness(monster->type) != MH_NATURAL) return 0;
+ if (mons_intel_type(monster->type) != I_ANIMAL) return 0;
+ if (mons_friendly(monster)) return 0;
+
+ // 50% bonus for dogs, add cats if they get implemented
+ if (monster->type == MONS_HOUND || monster->type == MONS_WAR_DOG
+ || monster->type == MONS_BLACK_BEAR)
+ {
+ pow += (pow / 2);
+ }
+
+ if (you.species == SP_HILL_ORC && monster->type == MONS_WARG)
+ pow += (pow / 2);
+
+ if (check_mons_resist_magic(monster, pow))
+ return 0;
+
+ // I'd like to make the monsters affected permanently, but that's
+ // pretty powerful. Maybe a small (pow/10) chance of being permanently
+ // tamed, large chance of just being enslaved.
+ simple_monster_message(monster, " is tamed!");
+
+ if (random2(100) < random2(pow / 10))
+ monster->attitude = ATT_FRIENDLY; // permanent, right?
+ else
+ mons_add_ench(monster, ENCH_CHARM);
+
+ return 1;
+} // end tame_beast_monsters()
+
+void cast_tame_beasts(int pow)
+{
+ apply_area_visible(tame_beast_monsters, pow);
+} // end cast_tame_beasts()
+
+static int ignite_poison_objects(int x, int y, int pow, int garbage)
+{
+ UNUSED( pow );
+ UNUSED( garbage );
+
+ int obj = igrd[x][y], next, strength = 0;
+
+ if (obj == NON_ITEM)
+ return (0);
+
+ while (obj != NON_ITEM)
+ {
+ next = mitm[obj].link;
+ if (mitm[obj].base_type == OBJ_POTIONS)
+ {
+ switch (mitm[obj].sub_type)
+ {
+ // intentional fall-through all the way down
+ case POT_STRONG_POISON:
+ strength += 20;
+ case POT_DEGENERATION:
+ strength += 10;
+ case POT_POISON:
+ strength += 10;
+ destroy_item(obj);
+ default:
+ break;
+ }
+ }
+
+ // FIXME: impliment burning poisoned ammo
+ // else if ( it's ammo that's poisoned) {
+ // strength += number_of_ammo;
+ // destroy_item(ammo);
+ // }
+ obj = next;
+ }
+
+ if (strength > 0)
+ place_cloud(CLOUD_FIRE, x, y, strength + roll_dice(3, strength / 4) );
+
+ return (strength);
+} // end ignite_poison_objects()
+
+static int ignite_poison_clouds( int x, int y, int pow, int garbage )
+{
+ UNUSED( pow );
+ UNUSED( garbage );
+
+ bool did_anything = false;
+
+ const int cloud = env.cgrid[x][y];
+
+ if (cloud != EMPTY_CLOUD)
+ {
+ if (env.cloud[ cloud ].type == CLOUD_STINK
+ || env.cloud[ cloud ].type == CLOUD_STINK_MON)
+ {
+ did_anything = true;
+ env.cloud[ cloud ].type = CLOUD_FIRE;
+
+ env.cloud[ cloud ].decay /= 2;
+
+ if (env.cloud[ cloud ].decay < 1)
+ env.cloud[ cloud ].decay = 1;
+ }
+ else if (env.cloud[ cloud ].type == CLOUD_POISON
+ || env.cloud[ cloud ].type == CLOUD_POISON_MON)
+ {
+ did_anything = true;
+ env.cloud[ cloud ].type = CLOUD_FIRE;
+ }
+ }
+
+ return ((int) did_anything);
+} // end ignite_poison_clouds()
+
+static int ignite_poison_monsters(int x, int y, int pow, int garbage)
+{
+ UNUSED( garbage );
+
+ struct bolt beam;
+ beam.flavour = BEAM_FIRE; // this is dumb, only used for adjust!
+
+ dice_def dam_dice( 0, 5 + pow / 7 ); // dice added below if applicable
+
+ const int mon_index = mgrd[x][y];
+ if (mon_index == NON_MONSTER)
+ return (0);
+
+ struct monsters *const mon = &menv[ mon_index ];
+
+ // Monsters which have poison corpses or poisonous attacks:
+ if (mons_corpse_thingy( mon->type ) == CE_POISONOUS
+ || mon->type == MONS_GIANT_ANT
+ || mon->type == MONS_SMALL_SNAKE
+ || mon->type == MONS_SNAKE
+ || mon->type == MONS_JELLYFISH
+ || mons_is_mimic( mon->type ))
+ {
+ dam_dice.num = 3;
+ }
+
+ // Monsters which are poisoned:
+ int strength = 0;
+
+ // first check for player poison:
+ int ench = mons_has_ench( mon, ENCH_YOUR_POISON_I, ENCH_YOUR_POISON_IV );
+ if (ench != ENCH_NONE)
+ strength += ench - ENCH_YOUR_POISON_I + 1;
+
+ // ... now monster poison:
+ ench = mons_has_ench( mon, ENCH_POISON_I, ENCH_POISON_IV );
+ if (ench != ENCH_NONE)
+ strength += ench - ENCH_POISON_I + 1;
+
+ // strength is now the sum of both poison types (although only
+ // one should actually be present at a given time):
+ dam_dice.num += strength;
+
+ int damage = roll_dice( dam_dice );
+ if (damage > 0)
+ {
+ damage = mons_adjust_flavoured( mon, beam, damage );
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "Dice: %dd%d; Damage: %d",
+ dam_dice.num, dam_dice.size, damage );
+
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ if (!player_hurt_monster( mon_index, damage ))
+ {
+ // Monster survived, remove any poison.
+ mons_del_ench( mon, ENCH_POISON_I, ENCH_POISON_IV );
+ mons_del_ench( mon, ENCH_YOUR_POISON_I, ENCH_YOUR_POISON_IV );
+ }
+
+ return (1);
+ }
+
+ return (0);
+}
+
+void cast_ignite_poison(int pow)
+{
+ int damage = 0, strength = 0, pcount = 0, acount = 0, totalstrength = 0;
+ char item;
+ bool wasWielding = false;
+ char str_pass[ ITEMNAME_SIZE ];
+
+ // temp weapon of venom => temp fire brand
+ const int wpn = you.equip[EQ_WEAPON];
+
+ if (wpn != -1
+ && you.duration[DUR_WEAPON_BRAND]
+ && get_weapon_brand( you.inv[wpn] ) == SPWPN_VENOM)
+ {
+ if (set_item_ego_type( you.inv[wpn], OBJ_WEAPONS, SPWPN_FLAMING ))
+ {
+ in_name( wpn, DESC_CAP_YOUR, str_pass );
+ strcpy( info, str_pass );
+ strcat( info, " bursts into flame!" );
+ mpr(info);
+
+ you.wield_change = true;
+ you.duration[DUR_WEAPON_BRAND] += 1 + you.duration[DUR_WEAPON_BRAND] / 2;
+ if (you.duration[DUR_WEAPON_BRAND] > 80)
+ you.duration[DUR_WEAPON_BRAND] = 80;
+ }
+ }
+
+ totalstrength = 0;
+
+ for (item = 0; item < ENDOFPACK; item++)
+ {
+ if (!you.inv[item].quantity)
+ continue;
+
+ strength = 0;
+
+ if (you.inv[item].base_type == OBJ_MISSILES)
+ {
+ if (you.inv[item].special == 3)
+ { // burn poison ammo
+ strength = you.inv[item].quantity;
+ acount += you.inv[item].quantity;
+ }
+ }
+
+ if (you.inv[item].base_type == OBJ_POTIONS)
+ {
+ switch (you.inv[item].sub_type)
+ {
+ case POT_STRONG_POISON:
+ strength += 20 * you.inv[item].quantity;
+ break;
+ case POT_DEGENERATION:
+ case POT_POISON:
+ strength += 10 * you.inv[item].quantity;
+ break;
+ default:
+ break;
+ } // end switch
+
+ if (strength)
+ pcount += you.inv[item].quantity;
+ }
+
+ if (strength)
+ {
+ you.inv[item].quantity = 0;
+ if (item == you.equip[EQ_WEAPON])
+ {
+ you.equip[EQ_WEAPON] = -1;
+ wasWielding = true;
+ }
+ }
+
+ totalstrength += strength;
+ }
+
+ if (acount > 0)
+ mpr("Some ammo you are carrying burns!");
+
+ if (pcount > 0)
+ {
+ snprintf( info, INFO_SIZE, "%s potion%s you are carrying explode%s!",
+ pcount > 1 ? "Some" : "A",
+ pcount > 1 ? "s" : "",
+ pcount > 1 ? "" : "s");
+ mpr(info);
+ }
+
+ if (wasWielding == true)
+ canned_msg( MSG_EMPTY_HANDED );
+
+ if (totalstrength)
+ {
+ place_cloud(CLOUD_FIRE, you.x_pos, you.y_pos,
+ random2(totalstrength / 4 + 1) + random2(totalstrength / 4 + 1) +
+ random2(totalstrength / 4 + 1) + random2(totalstrength / 4 + 1) + 1);
+ }
+
+ // player is poisonous
+ if (you.mutation[MUT_SPIT_POISON] || you.mutation[MUT_STINGER]
+ || you.attribute[ATTR_TRANSFORMATION] == TRAN_SPIDER // poison attack
+ || (!player_is_shapechanged()
+ && (you.species == SP_GREEN_DRACONIAN // poison breath
+ || you.species == SP_KOBOLD // poisonous corpse
+ || you.species == SP_NAGA))) // spit poison
+ {
+ damage = roll_dice( 3, 5 + pow / 7 );
+ }
+
+ // player is poisoned
+ damage += roll_dice( you.poison, 6 );
+
+ if (damage)
+ {
+ const int resist = player_res_fire();
+
+ if (resist > 0)
+ {
+ mpr("You feel like your blood is boiling!");
+ damage = damage / 3;
+ }
+ else if (resist < 0)
+ {
+ damage *= 3;
+ mpr("The poison in your system burns terribly!");
+ }
+ else
+ {
+ mpr("The poison in your system burns!");
+ }
+
+ ouch( damage, 0, KILLED_BY_TARGETTING );
+
+ if (you.poison > 0)
+ {
+ mpr( "You feel that the poison has left your system." );
+ you.poison = 0;
+ }
+ }
+
+ apply_area_visible(ignite_poison_clouds, pow);
+ apply_area_visible(ignite_poison_objects, pow);
+ apply_area_visible(ignite_poison_monsters, pow);
+} // end cast_ignite_poison()
+
+void cast_silence(int pow)
+{
+ if (!you.attribute[ATTR_WAS_SILENCED])
+ mpr("A profound silence engulfs you.");
+
+ you.attribute[ATTR_WAS_SILENCED] = 1;
+
+ you.duration[DUR_SILENCE] += 10 + random2avg( pow, 2 );
+
+ if (you.duration[DUR_SILENCE] > 100)
+ you.duration[DUR_SILENCE] = 100;
+} // end cast_silence()
+
+
+/* ******************************************************************
+// no hooks for this anywhere {dlb}:
+
+void cast_animate_golem(int pow)
+{
+ // must have more than 20 max_hitpoints
+
+ // must be wielding a Scroll of Paper (for chem)
+
+ // must be standing on a pile of <foo> (for foo in: wood, metal, rock, stone)
+
+ // Will cost you 5-10% of max_hitpoints, or 20 + some, whichever is more
+ mpr("You imbue the inanimate form with a portion of your life force.");
+
+ naughty(NAUGHTY_CREATED_LIFE, 10);
+}
+
+****************************************************************** */
+
+static int discharge_monsters( int x, int y, int pow, int garbage )
+{
+ UNUSED( garbage );
+
+ const int mon = mgrd[x][y];
+ int damage = 0;
+
+ struct bolt beam;
+ beam.flavour = BEAM_ELECTRICITY; // used for mons_adjust_flavoured
+
+ if (x == you.x_pos && y == you.y_pos)
+ {
+ mpr( "You are struck by lightning." );
+ damage = 3 + random2( 5 + pow / 10 );
+ damage = check_your_resists( damage, BEAM_ELECTRICITY );
+ ouch( damage, 0, KILLED_BY_WILD_MAGIC );
+ }
+ else if (mon == NON_MONSTER)
+ return (0);
+ else if (mons_res_elec(&menv[mon]) > 0 || mons_flies(&menv[mon]))
+ return (0);
+ else
+ {
+ damage = 3 + random2( 5 + pow / 10 );
+ damage = mons_adjust_flavoured( &menv[mon], beam, damage );
+
+ if (damage)
+ {
+ strcpy( info, ptr_monam( &(menv[mon]), DESC_CAP_THE ) );
+ strcat( info, " is struck by lightning." );
+ mpr( info );
+
+ player_hurt_monster( mon, damage );
+ }
+ }
+
+ // Recursion to give us chain-lightning -- bwr
+ // Low power slight chance added for low power characters -- bwr
+ if ((pow >= 10 && !one_chance_in(3)) || (pow >= 3 && one_chance_in(10)))
+ {
+ mpr( "The lightning arcs!" );
+ pow /= (coinflip() ? 2 : 3);
+ damage += apply_random_around_square( discharge_monsters, x, y,
+ true, pow, 1 );
+ }
+ else if (damage > 0)
+ {
+ // Only printed if we did damage, so that the messages in
+ // cast_discharge() are clean. -- bwr
+ mpr( "The lightning grounds out." );
+ }
+
+ return (damage);
+} // end discharge_monsters()
+
+void cast_discharge( int pow )
+{
+ int num_targs = 1 + random2( 1 + pow / 25 );
+ int dam;
+
+ dam = apply_random_around_square( discharge_monsters, you.x_pos, you.y_pos,
+ true, pow, num_targs );
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "Arcs: %d Damage: %d", num_targs, dam );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ if (dam == 0)
+ {
+ if (coinflip())
+ mpr("The air around you crackles with electrical energy.");
+ else
+ {
+ bool plural = coinflip();
+ snprintf( info, INFO_SIZE, "%s blue arc%s ground%s harmlessly %s you.",
+ plural ? "Some" : "A",
+ plural ? "s" : "",
+ plural ? " themselves" : "s itself",
+ plural ? "around" : (coinflip() ? "beside" :
+ coinflip() ? "behind" : "before")
+ );
+
+ mpr(info);
+ }
+ }
+} // end cast_discharge()
+
+// NB: this must be checked against the same effects
+// in fight.cc for all forms of attack !!! {dlb}
+// This function should be currently unused (the effect is too powerful)
+static int distortion_monsters(int x, int y, int pow, int message)
+{
+ int specdam = 0;
+ int monster_attacked = mgrd[x][y];
+
+ if (monster_attacked == NON_MONSTER)
+ return 0;
+
+ struct monsters *defender = &menv[monster_attacked];
+
+ if (pow > 100)
+ pow = 100;
+
+ if (x == you.x_pos && y == you.y_pos)
+ {
+ if (you.skills[SK_TRANSLOCATIONS] < random2(8))
+ {
+ miscast_effect( SPTYP_TRANSLOCATION, pow / 9 + 1, pow, 100,
+ "a distortion effect" );
+ }
+ else
+ {
+ miscast_effect( SPTYP_TRANSLOCATION, 1, 1, 100,
+ "a distortion effect" );
+ }
+
+ return 1;
+ }
+
+ if (defender->type == MONS_BLINK_FROG) // any others resist?
+ {
+ int hp = defender->hit_points;
+ int max_hp = defender->max_hit_points;
+
+ mpr("The blink frog basks in the translocular energy.");
+
+ if (hp < max_hp)
+ hp += 1 + random2(1 + pow / 4) + random2(1 + pow / 7);
+
+ if (hp > max_hp)
+ hp = max_hp;
+
+ defender->hit_points = hp;
+ return 1;
+ }
+ else if (coinflip())
+ {
+ strcpy(info, "Space bends around ");
+ strcat(info, ptr_monam(defender, DESC_NOCAP_THE));
+ strcat(info, ".");
+ mpr(info);
+ specdam += 1 + random2avg( 7, 2 ) + random2(pow) / 40;
+ }
+ else if (coinflip())
+ {
+ strcpy(info, "Space warps horribly around ");
+ strcat(info, ptr_monam( defender, DESC_NOCAP_THE ));
+ strcat(info, "!");
+ mpr(info);
+
+ specdam += 3 + random2avg( 12, 2 ) + random2(pow) / 25;
+ }
+ else if (one_chance_in(3))
+ {
+ monster_blink(defender);
+ return 1;
+ }
+ else if (one_chance_in(3))
+ {
+ monster_teleport(defender, coinflip());
+ return 1;
+ }
+ else if (one_chance_in(3))
+ {
+ monster_die(defender, KILL_RESET, 0);
+ return 1;
+ }
+ else if (message)
+ {
+ mpr("Nothing seems to happen.");
+ return 1;
+ }
+
+ player_hurt_monster(monster_attacked, specdam);
+
+ return (specdam);
+} // end distortion_monsters()
+
+void cast_bend(int pow)
+{
+ apply_one_neighbouring_square( distortion_monsters, pow );
+} // end cast_bend()
+
+// Really this is just applying the best of Band/Warp weapon/Warp field
+// into a spell that gives the "make monsters go away" benefit without
+// the insane damage potential. -- bwr
+int disperse_monsters(int x, int y, int pow, int message)
+{
+ UNUSED( message );
+
+ const int monster_attacked = mgrd[x][y];
+
+ if (monster_attacked == NON_MONSTER)
+ return 0;
+
+ struct monsters *defender = &menv[monster_attacked];
+
+ if (defender->type == MONS_BLINK_FROG)
+ {
+ simple_monster_message(defender, " resists.");
+ return 1;
+ }
+ else if (check_mons_resist_magic(defender, pow))
+ {
+ if (coinflip())
+ {
+ simple_monster_message(defender, " partially resists.");
+ monster_blink(defender);
+ }
+ else
+ simple_monster_message(defender, " resists.");
+
+ return 1;
+ }
+ else
+ {
+ monster_teleport( defender, true );
+ return 1;
+ }
+
+ return 0;
+}
+
+void cast_dispersal(int pow)
+{
+ if (apply_area_around_square( disperse_monsters,
+ you.x_pos, you.y_pos, pow ) == 0)
+ {
+ mpr( "There is a brief shimmering in the air around you." );
+ }
+}
+
+static int spell_swap_func(int x, int y, int pow, int message)
+{
+ UNUSED( message );
+
+ int monster_attacked = mgrd[x][y];
+
+ if (monster_attacked == NON_MONSTER)
+ return 0;
+
+ struct monsters *defender = &menv[monster_attacked];
+
+ if (defender->type == MONS_BLINK_FROG
+ || check_mons_resist_magic( defender, pow ))
+ {
+ simple_monster_message( defender, " resists." );
+ }
+ else
+ {
+ // Swap doesn't seem to actually swap, but just sets the
+ // monster's location equal to the players... this being because
+ // the acr.cc call is going to move the player afterwards (for
+ // the regular friendly monster swap). So we'll go through
+ // standard swap procedure here... since we really want to apply
+ // the same swap_places function as with friendly monsters...
+ // see note over there. -- bwr
+ int old_x = defender->x;
+ int old_y = defender->y;
+
+ if (swap_places( defender ))
+ {
+ you.x_pos = old_x;
+ you.y_pos = old_y;
+ }
+ }
+
+ return 1;
+}
+
+void cast_swap(int pow)
+{
+ apply_one_neighbouring_square( spell_swap_func, pow );
+}
+
+static int make_a_rot_cloud(int x, int y, int pow, int ctype)
+{
+ int next = 0, obj = mgrd[x][y];
+
+ if (obj == NON_MONSTER)
+ return 0;
+
+ while (obj != NON_ITEM)
+ {
+ next = mitm[obj].link;
+
+ if (mitm[obj].base_type == OBJ_CORPSES
+ && mitm[obj].sub_type == CORPSE_BODY)
+ {
+ if (!mons_skeleton(mitm[obj].plus))
+ destroy_item(obj);
+ else
+ {
+ mitm[obj].sub_type = CORPSE_SKELETON;
+ mitm[obj].special = 200;
+ mitm[obj].colour = LIGHTGREY;
+ }
+
+ place_cloud(ctype, x, y,
+ (3 + random2(pow / 4) + random2(pow / 4) +
+ random2(pow / 4)));
+ return 1;
+ }
+
+ obj = next;
+ }
+
+ return 0;
+} // end make_a_rot_cloud()
+
+int make_a_normal_cloud(int x, int y, int pow, int ctype)
+{
+ place_cloud( ctype, x, y,
+ (3 + random2(pow / 4) + random2(pow / 4) + random2(pow / 4)) );
+
+ return 1;
+} // end make_a_normal_cloud()
+
+#if 0
+
+static int make_a_random_cloud(int x, int y, int pow, int ctype)
+{
+ if (ctype == CLOUD_NONE)
+ ctype = CLOUD_BLACK_SMOKE;
+
+ unsigned char cloud_material;
+
+ switch (random2(9))
+ {
+ case 0:
+ cloud_material = CLOUD_FIRE;
+ break;
+ case 1:
+ cloud_material = CLOUD_STINK;
+ break;
+ case 2:
+ cloud_material = CLOUD_COLD;
+ break;
+ case 3:
+ cloud_material = CLOUD_POISON;
+ break;
+ case 4:
+ cloud_material = CLOUD_BLUE_SMOKE;
+ break;
+ case 5:
+ cloud_material = CLOUD_STEAM;
+ break;
+ case 6:
+ cloud_material = CLOUD_PURP_SMOKE;
+ break;
+ default:
+ cloud_material = ctype;
+ break;
+ }
+
+ // that last bit is equivalent to "random2(pow/4) + random2(pow/4)
+ // + random2(pow/4)" {dlb}
+ // can you see the pattern? {dlb}
+ place_cloud(cloud_material, x, y, 3 + random2avg(3 * (pow / 4) - 2, 3));
+
+ return 1;
+} // end make_a_random_cloud()
+
+#endif
+
+static int passwall(int x, int y, int pow, int garbage)
+{
+ UNUSED( garbage );
+
+ char dx, dy, nx = x, ny = y;
+ int howdeep = 0;
+ bool done = false;
+ int shallow = 1 + (you.skills[SK_EARTH_MAGIC] / 8);
+
+ // allow statues as entry points?
+ if (grd[x][y] != DNGN_ROCK_WALL)
+ // Irony: you can start on a secret door but not a door.
+ // Worked stone walls are out, they're not diggable and
+ // are used for impassable walls... I'm not sure we should
+ // even allow statues (should be contiguous rock) -- bwr
+ {
+ mpr("That's not a passable wall.");
+ return 0;
+ }
+
+ dx = x - you.x_pos;
+ dy = y - you.y_pos;
+
+ while (!done)
+ {
+ // I'm trying to figure proper borders out {dlb}
+ // FIXME: dungeon border?
+ if (nx > (GXM - 1) || ny > (GYM - 1) || nx < 2 || ny < 2)
+ {
+ mpr("You sense an overwhelming volume of rock.");
+ return 0;
+ }
+
+ switch (grd[nx][ny])
+ {
+ default:
+ done = true;
+ break;
+ case DNGN_ROCK_WALL:
+ case DNGN_ORCISH_IDOL:
+ case DNGN_GRANITE_STATUE:
+ case DNGN_SECRET_DOOR:
+ nx += dx;
+ ny += dy;
+ howdeep++;
+ break;
+ }
+ }
+
+ int range = shallow + random2(pow) / 25;
+
+ if (howdeep > shallow)
+ {
+ mpr("This rock feels deep.");
+
+ if (yesno("Try anyway?"))
+ {
+ if (howdeep > range)
+ {
+ ouch(1 + you.hp, 0, KILLED_BY_PETRIFICATION);
+ //jmf: not return; if wizard, successful transport is option
+ }
+ }
+ else
+ {
+ if (one_chance_in(30))
+ mpr("Wuss.");
+ else
+ canned_msg(MSG_OK);
+ return 1;
+ }
+ }
+
+ // Note that the delay was (1 + howdeep * 2), but now that the
+ // delay is stopped when the player is attacked it can be much
+ // shorter since its harder to use for quick escapes. -- bwr
+ start_delay( DELAY_PASSWALL, 2 + howdeep, nx, ny );
+
+ return 1;
+} // end passwall()
+
+void cast_passwall(int pow)
+{
+ apply_one_neighbouring_square(passwall, pow);
+} // end cast_passwall()
+
+static int intoxicate_monsters(int x, int y, int pow, int garbage)
+{
+ UNUSED( pow );
+ UNUSED( garbage );
+
+ int mon = mgrd[x][y];
+
+ if (mon == NON_MONSTER)
+ return 0;
+ if (mons_intel(menv[mon].type) < I_NORMAL)
+ return 0;
+ if (mons_holiness(menv[mon].type) != MH_NATURAL)
+ return 0;
+ if (mons_res_poison(&menv[mon]) > 0)
+ return 0;
+
+ mons_add_ench(&menv[mon], ENCH_CONFUSION);
+ return 1;
+} // end intoxicate_monsters()
+
+void cast_intoxicate(int pow)
+{
+ potion_effect( POT_CONFUSION, 10 + (100 - pow) / 10);
+
+ if (one_chance_in(20) && lose_stat( STAT_INTELLIGENCE, 1 + random2(3) ))
+ mpr("Your head spins!");
+
+ apply_area_visible(intoxicate_monsters, pow);
+} // end cast_intoxicate()
+
+// intended as a high-level Elven (a)bility
+static int glamour_monsters(int x, int y, int pow, int garbage)
+{
+ UNUSED( garbage );
+
+ int mon = mgrd[x][y];
+
+ // Power in this function is already limited by a function of
+ // experience level (10 + level / 2) since it's only an ability,
+ // never an actual spell. -- bwr
+
+ if (mon == NON_MONSTER)
+ return (0);
+
+ if (one_chance_in(5))
+ return (0);
+
+ if (mons_intel(menv[mon].type) < I_NORMAL)
+ return (0);
+
+ if (mons_holiness(mon) != MH_NATURAL)
+ return (0);
+
+ if (!mons_is_humanoid( menv[mon].type ))
+ return (0);
+
+ const char show_char = mons_char( menv[mon].type );
+
+ // gargoyles are immune.
+ if (menv[mon].type == MONS_GARGOYLE
+ || menv[mon].type == MONS_METAL_GARGOYLE
+ || menv[mon].type == MONS_MOLTEN_GARGOYLE)
+ {
+ return (0);
+ }
+
+ // orcs resist thru hatred of elves
+ // elves resist cause they're elves
+ // boggarts are malevolent highly magical wee-folk
+ if (show_char == 'o' || show_char == 'e' || menv[mon].type == MONS_BOGGART)
+ pow = (pow / 2) + 1;
+
+ if (check_mons_resist_magic(&menv[mon], pow))
+ return (0);
+
+ switch (random2(6))
+ {
+ case 0:
+ mons_add_ench(&menv[mon], ENCH_FEAR);
+ break;
+ case 1:
+ case 4:
+ mons_add_ench(&menv[mon], ENCH_CONFUSION);
+ break;
+ case 2:
+ case 5:
+ mons_add_ench(&menv[mon], ENCH_CHARM);
+ break;
+ case 3:
+ menv[mon].behaviour = BEH_SLEEP;
+ break;
+ }
+
+ // why no, there's no message as to which effect happened >:^)
+ if (!one_chance_in(4))
+ {
+ strcpy(info, ptr_monam( &(menv[mon]), DESC_CAP_THE));
+
+ switch (random2(4))
+ {
+ case 0:
+ strcat(info, " looks dazed.");
+ break;
+ case 1:
+ strcat(info, " blinks several times.");
+ break;
+ case 2:
+ strcat(info, " rubs its eye");
+ if (menv[mon].type != MONS_CYCLOPS)
+ strcat(info, "s");
+ strcat(info, ".");
+ break;
+ case 4:
+ strcat(info, " tilts its head.");
+ break;
+ }
+
+ mpr(info);
+ }
+
+ return (1);
+} // end glamour_monsters()
+
+void cast_glamour(int pow)
+{
+ apply_area_visible(glamour_monsters, pow);
+} // end cast_glamour()
+
+bool backlight_monsters(int x, int y, int pow, int garbage)
+{
+ UNUSED( pow );
+ UNUSED( garbage );
+
+ int mon = mgrd[x][y];
+
+ if (mon == NON_MONSTER)
+ return (false);
+
+ switch (menv[mon].type)
+ {
+ //case MONS_INSUBSTANTIAL_WISP: //jmf: I'm not sure if these glow or not
+ //case MONS_VAPOUR:
+ case MONS_UNSEEN_HORROR: // consider making this visible? probably not.
+ return (false);
+
+ case MONS_FIRE_VORTEX:
+ case MONS_ANGEL:
+ case MONS_FIEND:
+ case MONS_SHADOW:
+ case MONS_EFREET:
+ case MONS_HELLION:
+ case MONS_GLOWING_SHAPESHIFTER:
+ case MONS_FIRE_ELEMENTAL:
+ case MONS_AIR_ELEMENTAL:
+ case MONS_SHADOW_FIEND:
+ case MONS_SPECTRAL_WARRIOR:
+ case MONS_ORANGE_RAT:
+ case MONS_BALRUG:
+ case MONS_SPATIAL_VORTEX:
+ case MONS_PIT_FIEND:
+ case MONS_SHINING_EYE:
+ case MONS_DAEVA:
+ case MONS_SPECTRAL_THING:
+ case MONS_ORB_OF_FIRE:
+ case MONS_EYE_OF_DEVASTATION:
+ return (false); // already glowing or invisible
+ default:
+ break;
+ }
+
+ int lvl = mons_has_ench( &menv[mon], ENCH_BACKLIGHT_I, ENCH_BACKLIGHT_IV );
+
+ if (lvl == ENCH_NONE)
+ simple_monster_message( &menv[mon], " is outlined in light." );
+ else if (lvl == ENCH_BACKLIGHT_IV)
+ simple_monster_message( &menv[mon], " glows brighter for a moment." );
+ else
+ {
+ // remove old level
+ mons_del_ench( &menv[mon], ENCH_BACKLIGHT_I, ENCH_BACKLIGHT_III, true );
+ simple_monster_message( &menv[mon], " glows brighter." );
+ }
+
+ // this enchantment wipes out invisibility (neat)
+ mons_del_ench( &menv[mon], ENCH_INVIS );
+ mons_add_ench( &menv[mon], ENCH_BACKLIGHT_IV );
+
+ return (true);
+} // end backlight_monsters()
+
+void cast_evaporate(int pow)
+{
+ // experimenting with allowing the potion to be thrown... we're
+ // still making it have to be "in hands" at this point. -- bwr
+ struct dist spelld;
+ struct bolt beem;
+
+ const int potion = prompt_invent_item( "Throw which potion?", OBJ_POTIONS );
+
+ if (potion == -1)
+ {
+ snprintf( info, INFO_SIZE, "Wisps of steam play over your %s!",
+ your_hand(true) );
+
+ mpr(info);
+ return;
+ }
+ else if (you.inv[potion].base_type != OBJ_POTIONS)
+ {
+ mpr( "This spell works only on potions!" );
+ canned_msg(MSG_SPELL_FIZZLES);
+ return;
+ }
+
+ mpr( STD_DIRECTION_PROMPT, MSGCH_PROMPT );
+
+ message_current_target();
+
+ direction( spelld, DIR_NONE, TARG_ENEMY );
+
+ if (!spelld.isValid)
+ {
+ canned_msg(MSG_SPELL_FIZZLES);
+ return;
+ }
+
+ beem.target_x = spelld.tx;
+ beem.target_y = spelld.ty;
+
+ beem.source_x = you.x_pos;
+ beem.source_y = you.y_pos;
+
+ strcpy( beem.beam_name, "potion" );
+ beem.colour = you.inv[potion].colour;
+ beem.range = 9;
+ beem.rangeMax = 9;
+ beem.type = SYM_FLASK;
+ beem.beam_source = MHITYOU;
+ beem.thrower = KILL_YOU_MISSILE;
+ beem.aux_source = NULL;
+ beem.isBeam = false;
+ beem.isTracer = false;
+
+ beem.hit = you.dex / 2 + roll_dice( 2, you.skills[SK_THROWING] / 2 + 1 );
+ beem.damage = dice_def( 1, 0 ); // no damage, just producing clouds
+ beem.ench_power = pow; // used for duration only?
+
+ beem.flavour = BEAM_POTION_STINKING_CLOUD;
+
+ switch (you.inv[potion].sub_type)
+ {
+ case POT_STRONG_POISON:
+ beem.flavour = BEAM_POTION_POISON;
+ beem.ench_power *= 2;
+ break;
+
+ case POT_DEGENERATION:
+ beem.flavour = (coinflip() ? BEAM_POTION_POISON : BEAM_POTION_MIASMA);
+ beem.ench_power *= 2;
+ break;
+
+ case POT_POISON:
+ beem.flavour = BEAM_POTION_POISON;
+ break;
+
+ case POT_DECAY:
+ beem.flavour = BEAM_POTION_MIASMA;
+ beem.ench_power *= 2;
+ break;
+
+ case POT_PARALYSIS:
+ beem.ench_power *= 2;
+ // fall through
+ case POT_CONFUSION:
+ case POT_SLOWING:
+ beem.flavour = BEAM_POTION_STINKING_CLOUD;
+ break;
+
+ case POT_WATER:
+ case POT_PORRIDGE:
+ beem.flavour = BEAM_POTION_STEAM;
+ break;
+
+ case POT_BERSERK_RAGE:
+ beem.flavour = (coinflip() ? BEAM_POTION_FIRE : BEAM_POTION_STEAM);
+ break;
+
+ case POT_MUTATION:
+ case POT_GAIN_STRENGTH:
+ case POT_GAIN_DEXTERITY:
+ case POT_GAIN_INTELLIGENCE:
+ case POT_EXPERIENCE:
+ case POT_MAGIC:
+ switch (random2(5))
+ {
+ case 0: beem.flavour = BEAM_POTION_FIRE; break;
+ case 1: beem.flavour = BEAM_POTION_COLD; break;
+ case 2: beem.flavour = BEAM_POTION_POISON; break;
+ case 3: beem.flavour = BEAM_POTION_MIASMA; break;
+ default: beem.flavour = BEAM_POTION_RANDOM; break;
+ }
+ break;
+
+ default:
+ switch (random2(12))
+ {
+ case 0: beem.flavour = BEAM_POTION_FIRE; break;
+ case 1: beem.flavour = BEAM_POTION_STINKING_CLOUD; break;
+ case 2: beem.flavour = BEAM_POTION_COLD; break;
+ case 3: beem.flavour = BEAM_POTION_POISON; break;
+ case 4: beem.flavour = BEAM_POTION_RANDOM; break;
+ case 5: beem.flavour = BEAM_POTION_BLUE_SMOKE; break;
+ case 6: beem.flavour = BEAM_POTION_BLACK_SMOKE; break;
+ case 7: beem.flavour = BEAM_POTION_PURP_SMOKE; break;
+ default: beem.flavour = BEAM_POTION_STEAM; break;
+ }
+ break;
+ }
+
+ if (coinflip())
+ exercise( SK_THROWING, 1 );
+
+ fire_beam(beem);
+
+ // both old and new code use up a potion:
+ dec_inv_item_quantity( potion, 1 );
+
+ return;
+} // end cast_evaporate()
+
+// The intent of this spell isn't to produce helpful potions
+// for drinking, but rather to provide ammo for the Evaporate
+// spell out of corpses, thus potentially making it useful.
+// Producing helpful potions would break game balance here...
+// and producing more than one potion from a corpse, or not
+// using up the corpse might also lead to game balance problems. -- bwr
+void cast_fulsome_distillation( int powc )
+{
+ char str_pass[ ITEMNAME_SIZE ];
+
+ if (powc > 50)
+ powc = 50;
+
+ int corpse = -1;
+
+ // Search items at the players location for corpses.
+ // XXX: Turn this into a separate function and merge with
+ // the messes over in butchery, animating, and maybe even
+ // item pickup from stacks (which would make it easier to
+ // create a floor stack menu system later) -- bwr
+ for (int curr_item = igrd[you.x_pos][you.y_pos];
+ curr_item != NON_ITEM;
+ curr_item = mitm[curr_item].link)
+ {
+ if (mitm[curr_item].base_type == OBJ_CORPSES
+ && mitm[curr_item].sub_type == CORPSE_BODY)
+ {
+ it_name( curr_item, DESC_NOCAP_THE, str_pass );
+ snprintf( info, INFO_SIZE, "Distill a potion from %s?", str_pass );
+
+ if (yesno( info, true, false ))
+ {
+ corpse = curr_item;
+ break;
+ }
+ }
+ }
+
+ if (corpse == -1)
+ {
+ canned_msg(MSG_SPELL_FIZZLES);
+ return;
+ }
+
+ const bool rotten = (mitm[corpse].special < 100);
+ const bool big_monster = (mons_type_hit_dice( mitm[corpse].plus ) >= 5);
+ const bool power_up = (rotten && big_monster);
+
+ int potion_type = POT_WATER;
+
+ switch (mitm[corpse].plus)
+ {
+ case MONS_GIANT_BAT: // extracting batty behaviour : 1
+ case MONS_UNSEEN_HORROR: // extracting batty behaviour : 7
+ case MONS_GIANT_BLOWFLY: // extracting batty behaviour : 5
+ potion_type = POT_CONFUSION;
+ break;
+
+ case MONS_RED_WASP: // paralysis attack : 8
+ case MONS_YELLOW_WASP: // paralysis attack : 4
+ potion_type = POT_PARALYSIS;
+ break;
+
+ case MONS_SNAKE: // clean meat, but poisonous attack : 2
+ case MONS_GIANT_ANT: // clean meat, but poisonous attack : 3
+ potion_type = (power_up ? POT_POISON : POT_CONFUSION);
+ break;
+
+ case MONS_ORANGE_RAT: // poisonous meat, but draining attack : 3
+ potion_type = (power_up ? POT_DECAY : POT_POISON);
+ break;
+
+ case MONS_SPINY_WORM: // 12
+ potion_type = (power_up ? POT_DECAY : POT_STRONG_POISON);
+ break;
+
+ default:
+ switch (mons_corpse_thingy( mitm[corpse].plus ))
+ {
+ case CE_CLEAN:
+ potion_type = (power_up ? POT_CONFUSION : POT_WATER);
+ break;
+
+ case CE_CONTAMINATED:
+ potion_type = (power_up ? POT_DEGENERATION : POT_POISON);
+ break;
+
+ case CE_POISONOUS:
+ potion_type = (power_up ? POT_STRONG_POISON : POT_POISON);
+ break;
+
+ case CE_MUTAGEN_RANDOM:
+ case CE_MUTAGEN_GOOD: // unused
+ case CE_RANDOM: // unused
+ potion_type = POT_MUTATION;
+ break;
+
+ case CE_MUTAGEN_BAD: // unused
+ case CE_ROTTEN: // actually this only occurs via mangling
+ case CE_HCL: // necrophage
+ potion_type = (power_up ? POT_DECAY : POT_STRONG_POISON);
+ break;
+
+ case CE_NOCORPSE: // shouldn't occur
+ default:
+ break;
+ }
+ break;
+ }
+
+ // If not powerful enough, we downgrade the potion
+ if (random2(50) > powc + 10 * rotten)
+ {
+ switch (potion_type)
+ {
+ case POT_DECAY:
+ case POT_DEGENERATION:
+ case POT_STRONG_POISON:
+ potion_type = POT_POISON;
+ break;
+
+ case POT_MUTATION:
+ case POT_POISON:
+ potion_type = POT_CONFUSION;
+ break;
+
+ case POT_PARALYSIS:
+ potion_type = POT_SLOWING;
+ break;
+
+ case POT_CONFUSION:
+ case POT_SLOWING:
+ default:
+ potion_type = POT_WATER;
+ break;
+ }
+ }
+
+ // We borrow the corpse's object to make our potion:
+ mitm[corpse].base_type = OBJ_POTIONS;
+ mitm[corpse].sub_type = potion_type;
+ mitm[corpse].quantity = 1;
+ mitm[corpse].plus = 0;
+ mitm[corpse].plus2 = 0;
+ item_colour( mitm[corpse] ); // sets special as well
+
+ it_name( corpse, DESC_NOCAP_A, str_pass );
+ snprintf( info, INFO_SIZE, "You extract %s from the corpse.",
+ str_pass );
+ mpr( info );
+
+ // try to move the potion to the player (for convenience)
+ if (move_item_to_player( corpse, 1 ) != 1)
+ {
+ mpr( "Unfortunately, you can't carry it right now!" );
+ }
+}
+
+void make_shuggoth(int x, int y, int hp)
+{
+ int mon = create_monster( MONS_SHUGGOTH, 100 + random2avg(58, 3),
+ BEH_HOSTILE, x, y, MHITNOT, 250 );
+
+ if (mon != -1)
+ {
+ menv[mon].hit_points = hp;
+ menv[mon].max_hit_points = hp;
+ }
+
+ return;
+} // end make_shuggoth()
+
+static int rot_living(int x, int y, int pow, int message)
+{
+ UNUSED( message );
+
+ int mon = mgrd[x][y];
+ int ench;
+
+ if (mon == NON_MONSTER)
+ return 0;
+
+ if (mons_holiness(menv[mon].type) != MH_NATURAL)
+ return 0;
+
+ if (check_mons_resist_magic(&menv[mon], pow))
+ return 0;
+
+ ench = ((random2(pow) + random2(pow) + random2(pow) + random2(pow)) / 4);
+
+ if (ench >= 50)
+ ench = ENCH_YOUR_ROT_IV;
+ else if (ench >= 35)
+ ench = ENCH_YOUR_ROT_III;
+ else if (ench >= 20)
+ ench = ENCH_YOUR_ROT_II;
+ else
+ ench = ENCH_YOUR_ROT_I;
+
+ mons_add_ench(&menv[mon], ench);
+
+ return 1;
+} // end rot_living()
+
+static int rot_undead(int x, int y, int pow, int garbage)
+{
+ UNUSED( garbage );
+
+ int mon = mgrd[x][y];
+ int ench;
+
+ if (mon == NON_MONSTER)
+ return 0;
+
+ if (mons_holiness(menv[mon].type) != MH_UNDEAD)
+ return 0;
+
+ if (check_mons_resist_magic(&menv[mon], pow))
+ return 0;
+
+ // this does not make sense -- player mummies are
+ // immune to rotting (or have been) -- so what is
+ // the schema in use here to determine rotting??? {dlb}
+
+ //jmf: up for discussion. it is clearly unfair to
+ // rot player mummies.
+ // the `shcema' here is: corporeal non-player undead
+ // rot, discorporeal undead don't rot. if you wanna
+ // insist that monsters get the same treatment as
+ // players, I demand my player mummies get to worship
+ // the evil mummy & orc god.
+ switch (menv[mon].type)
+ {
+ case MONS_NECROPHAGE:
+ case MONS_ZOMBIE_SMALL:
+ case MONS_LICH:
+ case MONS_MUMMY:
+ case MONS_VAMPIRE:
+ case MONS_ZOMBIE_LARGE:
+ case MONS_WIGHT:
+ case MONS_GHOUL:
+ case MONS_BORIS:
+ case MONS_ANCIENT_LICH:
+ case MONS_VAMPIRE_KNIGHT:
+ case MONS_VAMPIRE_MAGE:
+ case MONS_GUARDIAN_MUMMY:
+ case MONS_GREATER_MUMMY:
+ case MONS_MUMMY_PRIEST:
+ break;
+ case MONS_ROTTING_HULK:
+ default:
+ return 0; // immune (no flesh) or already rotting
+ }
+
+ ench = ((random2(pow) + random2(pow) + random2(pow) + random2(pow)) / 4);
+
+ if (ench >= 50)
+ ench = ENCH_YOUR_ROT_IV;
+ else if (ench >= 35)
+ ench = ENCH_YOUR_ROT_III;
+ else if (ench >= 20)
+ ench = ENCH_YOUR_ROT_II;
+ else
+ ench = ENCH_YOUR_ROT_I;
+
+ mons_add_ench(&menv[mon], ench);
+
+ return 1;
+} // end rot_undead()
+
+static int rot_corpses(int x, int y, int pow, int garbage)
+{
+ UNUSED( garbage );
+
+ return make_a_rot_cloud(x, y, pow, CLOUD_MIASMA);
+} // end rot_corpses()
+
+void cast_rotting(int pow)
+{
+ apply_area_visible(rot_living, pow);
+ apply_area_visible(rot_undead, pow);
+ apply_area_visible(rot_corpses, pow);
+ return;
+} // end cast_rotting()
+
+void do_monster_rot(int mon)
+{
+ int damage = 1 + random2(3);
+
+ if (mons_holiness(menv[mon].type) == MH_UNDEAD && random2(5))
+ {
+ apply_area_cloud(make_a_normal_cloud, menv[mon].x, menv[mon].y,
+ 10, 1, CLOUD_MIASMA);
+ }
+
+ player_hurt_monster( mon, damage );
+ return;
+} // end do_monster_rot()
+
+static int snake_charm_monsters(int x, int y, int pow, int message)
+{
+ UNUSED( message );
+
+ int mon = mgrd[x][y];
+
+ if (mon == NON_MONSTER) return 0;
+ if (mons_friendly(&menv[mon])) return 0;
+ if (one_chance_in(4)) return 0;
+ if (mons_char(menv[mon].type) != 'S') return 0;
+ if (check_mons_resist_magic(&menv[mon], pow)) return 0;
+
+ menv[mon].attitude = ATT_FRIENDLY;
+ snprintf( info, INFO_SIZE, "%s sways back and forth.", ptr_monam( &(menv[mon]), DESC_CAP_THE ));
+ mpr(info);
+
+ return 1;
+}
+
+void cast_snake_charm(int pow)
+{
+ // powc = (you.experience_level * 2) + (you.skills[SK_INVOCATIONS] * 3);
+ apply_one_neighbouring_square(snake_charm_monsters, pow);
+}
+
+void cast_fragmentation(int pow) // jmf: ripped idea from airstrike
+{
+ struct dist beam;
+ struct bolt blast;
+ int debris = 0;
+ int trap;
+ bool explode = false;
+ bool hole = true;
+ const char *what = NULL;
+
+ mpr("Fragment what (e.g. a wall)?", MSGCH_PROMPT);
+ direction( beam, DIR_TARGET, TARG_ENEMY );
+
+ if (!beam.isValid)
+ {
+ canned_msg(MSG_SPELL_FIZZLES);
+ return;
+ }
+
+ //FIXME: if (player typed '>' to attack floor) goto do_terrain;
+ blast.beam_source = MHITYOU;
+ blast.thrower = KILL_YOU;
+ blast.aux_source = NULL;
+ blast.ex_size = 1; // default
+ blast.type = '#';
+ blast.colour = 0;
+ blast.target_x = beam.tx;
+ blast.target_y = beam.ty;
+ blast.isTracer = false;
+ blast.flavour = BEAM_FRAG;
+
+ // Number of dice vary... 3 is easy/common, but it can get as high as 6.
+ blast.damage = dice_def( 0, 5 + pow / 10 );
+
+ const int grid = grd[beam.tx][beam.ty];
+ const int mon = mgrd[beam.tx][beam.ty];
+
+ const bool okay_to_dest = ((beam.tx > 5 && beam.tx < GXM - 5)
+ && (beam.ty > 5 && beam.ty < GYM - 5));
+
+ if (mon != NON_MONSTER)
+ {
+ // This needs its own hand_buff... we also need to do it first
+ // in case the target dies. -- bwr
+ char explode_msg[80];
+
+ snprintf( explode_msg, sizeof( explode_msg ), "%s explodes!",
+ ptr_monam( &(menv[mon]), DESC_CAP_THE ) );
+
+ switch (menv[mon].type)
+ {
+ case MONS_ICE_BEAST: // blast of ice fragments
+ case MONS_SIMULACRUM_SMALL:
+ case MONS_SIMULACRUM_LARGE:
+ explode = true;
+ strcpy(blast.beam_name, "icy blast");
+ blast.colour = WHITE;
+ blast.damage.num = 2;
+ blast.flavour = BEAM_ICE;
+ if (player_hurt_monster(mon, roll_dice( blast.damage )))
+ blast.damage.num += 1;
+ break;
+
+ case MONS_FLYING_SKULL:
+ case MONS_SKELETON_SMALL:
+ case MONS_SKELETON_LARGE: // blast of bone
+ explode = true;
+
+ snprintf( info, INFO_SIZE, "The sk%s explodes into sharp fragments of bone!",
+ (menv[mon].type == MONS_FLYING_SKULL) ? "ull" : "eleton");
+
+ strcpy(blast.beam_name, "blast of bone shards");
+
+ blast.colour = LIGHTGREY;
+
+ if (random2(50) < (pow / 5)) // potential insta-kill
+ {
+ monster_die(&menv[mon], KILL_YOU, 0);
+ blast.damage.num = 4;
+ }
+ else
+ {
+ blast.damage.num = 2;
+ if (player_hurt_monster(mon, roll_dice( blast.damage )))
+ blast.damage.num = 4;
+ }
+ goto all_done; // i.e. no "Foo Explodes!"
+
+ case MONS_WOOD_GOLEM:
+ explode = false;
+ simple_monster_message(&menv[mon], " shudders violently!");
+
+ // We use blast.damage not only for inflicting damage here,
+ // but so that later on we'll know that the spell didn't
+ // fizzle (since we don't actually explode wood golems). -- bwr
+ blast.damage.num = 2;
+ player_hurt_monster( mon, roll_dice( blast.damage ) );
+ break;
+
+ case MONS_IRON_GOLEM:
+ case MONS_METAL_GARGOYLE:
+ explode = true;
+ strcpy( blast.beam_name, "blast of metal fragments" );
+ blast.colour = CYAN;
+ blast.damage.num = 4;
+ if (player_hurt_monster(mon, roll_dice( blast.damage )))
+ blast.damage.num += 2;
+ break;
+
+ case MONS_CLAY_GOLEM: // assume baked clay and not wet loam
+ case MONS_STONE_GOLEM:
+ case MONS_EARTH_ELEMENTAL:
+ case MONS_GARGOYLE:
+ explode = true;
+ blast.ex_size = 2;
+ strcpy(blast.beam_name, "blast of rock fragments");
+ blast.colour = BROWN;
+ blast.damage.num = 3;
+ if (player_hurt_monster(mon, roll_dice( blast.damage )))
+ blast.damage.num += 1;
+ break;
+
+ case MONS_CRYSTAL_GOLEM:
+ explode = true;
+ blast.ex_size = 2;
+ strcpy(blast.beam_name, "blast of crystal shards");
+ blast.colour = WHITE;
+ blast.damage.num = 4;
+ if (player_hurt_monster(mon, roll_dice( blast.damage )))
+ blast.damage.num += 2;
+ break;
+
+ default:
+ blast.damage.num = 1; // to mark that a monster was targetted
+
+ // Yes, this spell does lousy damage if the
+ // monster isn't susceptable. -- bwr
+ player_hurt_monster( mon, roll_dice( 1, 5 + pow / 25 ) );
+ goto do_terrain;
+ }
+
+ mpr( explode_msg );
+ goto all_done;
+ }
+
+ do_terrain:
+ // FIXME: do nothing in Abyss & Pandemonium?
+
+ switch (grid)
+ {
+ //
+ // Stone and rock terrain
+ //
+ case DNGN_ROCK_WALL:
+ case DNGN_SECRET_DOOR:
+ blast.colour = env.rock_colour;
+ // fall-through
+ case DNGN_STONE_WALL:
+ what = "wall";
+ if (player_in_branch( BRANCH_HALL_OF_ZOT ))
+ blast.colour = env.rock_colour;
+ // fall-through
+ case DNGN_ORCISH_IDOL:
+ if (what == NULL)
+ what = "stone idol";
+ if (blast.colour == 0)
+ blast.colour = DARKGREY;
+ // fall-through
+ case DNGN_GRANITE_STATUE: // normal rock -- big explosion
+ if (what == NULL)
+ what = "statue";
+
+ explode = true;
+
+ strcpy(blast.beam_name, "blast of rock fragments");
+ blast.damage.num = 3;
+ if (blast.colour == 0)
+ blast.colour = LIGHTGREY;
+
+ if (okay_to_dest
+ && (grid == DNGN_ORCISH_IDOL
+ || grid == DNGN_GRANITE_STATUE
+ || (pow >= 40 && grid == DNGN_ROCK_WALL && one_chance_in(3))
+ || (pow >= 60 && grid == DNGN_STONE_WALL && one_chance_in(10))))
+ {
+ // terrain blew up real good:
+ blast.ex_size = 2;
+ grd[beam.tx][beam.ty] = DNGN_FLOOR;
+ debris = DEBRIS_ROCK;
+ }
+ break;
+
+ //
+ // Metal -- small but nasty explosion
+ //
+
+ case DNGN_METAL_WALL:
+ what = "metal wall";
+ blast.colour = CYAN;
+ // fallthru
+ case DNGN_SILVER_STATUE:
+ if (what == NULL)
+ {
+ what = "silver statue";
+ blast.colour = WHITE;
+ }
+
+ explode = true;
+ strcpy( blast.beam_name, "blast of metal fragments" );
+ blast.damage.num = 4;
+
+ if (okay_to_dest && pow >= 80 && random2(500) < pow / 5)
+ {
+ blast.damage.num += 2;
+ grd[beam.tx][beam.ty] = DNGN_FLOOR;
+ debris = DEBRIS_METAL;
+ }
+ break;
+
+ //
+ // Crystal
+ //
+
+ case DNGN_GREEN_CRYSTAL_WALL: // crystal -- large & nasty explosion
+ what = "crystal wall";
+ blast.colour = GREEN;
+ // fallthru
+ case DNGN_ORANGE_CRYSTAL_STATUE:
+ if (what == NULL)
+ {
+ what = "crystal statue";
+ blast.colour = LIGHTRED; //jmf: == orange, right?
+ }
+
+ explode = true;
+ blast.ex_size = 2;
+ strcpy(blast.beam_name, "blast of crystal shards");
+ blast.damage.num = 5;
+
+ if (okay_to_dest
+ && ((grid == DNGN_GREEN_CRYSTAL_WALL && coinflip())
+ || (grid == DNGN_ORANGE_CRYSTAL_STATUE
+ && pow >= 50 && one_chance_in(10))))
+ {
+ blast.ex_size = coinflip() ? 3 : 2;
+ grd[beam.tx][beam.ty] = DNGN_FLOOR;
+ debris = DEBRIS_CRYSTAL;
+ }
+ break;
+
+ //
+ // Traps
+ //
+
+ case DNGN_UNDISCOVERED_TRAP:
+ case DNGN_TRAP_MECHANICAL:
+ trap = trap_at_xy( beam.tx, beam.ty );
+ if (trap != -1
+ && trap_category( env.trap[trap].type ) != DNGN_TRAP_MECHANICAL)
+ {
+ // non-mechanical traps don't explode with this spell -- bwr
+ break;
+ }
+
+ // undiscovered traps appear as exploding from the floor -- bwr
+ what = ((grid == DNGN_UNDISCOVERED_TRAP) ? "floor" : "trap");
+
+ explode = true;
+ hole = false; // to hit monsters standing on traps
+ strcpy( blast.beam_name, "blast of fragments" );
+ blast.colour = env.floor_colour; // in order to blend in
+ blast.damage.num = 2;
+
+ // Exploded traps are nonfunctional, ammo is also ruined -- bwr
+ if (okay_to_dest)
+ {
+ grd[beam.tx][beam.ty] = DNGN_FLOOR;
+ env.trap[trap].type = TRAP_UNASSIGNED;
+ }
+ break;
+
+ //
+ // Stone doors and arches
+ //
+
+ case DNGN_OPEN_DOOR:
+ case DNGN_CLOSED_DOOR:
+ // Doors always blow up, stone arches never do (would cause problems)
+ if (okay_to_dest)
+ grd[beam.tx][beam.ty] = DNGN_FLOOR;
+
+ // fall-through
+ case DNGN_STONE_ARCH: // floor -- small explosion
+ explode = true;
+ hole = false; // to hit monsters standing on doors
+ strcpy( blast.beam_name, "blast of rock fragments" );
+ blast.colour = LIGHTGREY;
+ blast.damage.num = 2;
+ break;
+
+ //
+ // Permarock and floor are unaffected -- bwr
+ //
+ case DNGN_PERMAROCK_WALL:
+ case DNGN_FLOOR:
+ explode = false;
+ snprintf( info, INFO_SIZE, "%s seems to be unnaturally hard.",
+ (grid == DNGN_PERMAROCK_WALL) ? "That wall"
+ : "The dungeon floor" );
+ explode = false;
+ break;
+
+ case DNGN_TRAP_III: // What are these? Should they explode? -- bwr
+ default:
+ // FIXME: cute message for water?
+ break;
+ }
+
+ all_done:
+ if (explode && blast.damage.num > 0)
+ {
+ if (what != NULL)
+ {
+ snprintf( info, INFO_SIZE, "The %s explodes!", what);
+ mpr(info);
+ }
+
+ explosion( blast, hole );
+ }
+ else if (blast.damage.num == 0)
+ {
+ // if damage dice are zero we assume that nothing happened at all.
+ canned_msg(MSG_SPELL_FIZZLES);
+ }
+
+ if (debris)
+ place_debris(beam.tx, beam.ty, debris);
+} // end cast_fragmentation()
+
+void cast_twist(int pow)
+{
+ struct dist targ;
+ struct bolt tmp; // used, but ignored
+
+ // level one power cap -- bwr
+ if (pow > 25)
+ pow = 25;
+
+ // Get target, using DIR_TARGET for targetting only,
+ // since we don't use fire_beam() for this spell.
+ if (spell_direction(targ, tmp, DIR_TARGET) == -1)
+ return;
+
+ const int mons = mgrd[ targ.tx ][ targ.ty ];
+
+ // anything there?
+ if (mons == NON_MONSTER || targ.isMe)
+ {
+ mpr("There is no monster there!");
+ return;
+ }
+
+ // Monster can magically save vs attack.
+ if (check_mons_resist_magic( &menv[ mons ], pow * 2 ))
+ {
+ simple_monster_message( &menv[ mons ], " resists." );
+ return;
+ }
+
+ // Roll the damage... this spell is pretty low on damage, because
+ // it can target any monster in LOS (high utility). This is
+ // similar to the damage done by Magic Dart (although, the
+ // distribution is much more uniform). -- bwr
+ int damage = 1 + random2( 3 + pow / 5 );
+
+ // Inflict the damage
+ player_hurt_monster( mons, damage );
+ return;
+} // end cast_twist()
+
+//
+// This version of far strike is a bit too creative for level one, in
+// order to make it work we needed to put a lot of restrictions on it
+// (like the damage limitation), which wouldn't be necessary if it were
+// a higher level spell. This code might come back as a high level
+// translocation spell later (maybe even with special effects if it's
+// using some of Josh's ideas about occasionally losing the weapon).
+// Would potentially make a good high-level, second book Warper spell
+// (since Translocations is a utility school, it should be higher level
+// that usual... especially if it turns into a flavoured smiting spell).
+// This can all wait until after the next release (as it would be better
+// to have a proper way to do a single weapon strike here (you_attack
+// does far more than we need or want here)). --bwr
+//
+
+void cast_far_strike(int pow)
+{
+ struct dist targ;
+ struct bolt tmp; // used, but ignored
+
+ // Get target, using DIR_TARGET for targetting only,
+ // since we don't use fire_beam() for this spell.
+ if (spell_direction(targ, tmp, DIR_TARGET) == -1)
+ return;
+
+ // Get the target monster...
+ if (mgrd[targ.tx][targ.ty] == NON_MONSTER
+ || targ.isMe)
+ {
+ mpr("There is no monster there!");
+ return;
+ }
+
+ // Start with weapon base damage...
+ const int weapon = you.equip[ EQ_WEAPON ];
+
+ int damage = 3; // default unarmed damage
+ int speed = 10; // default unarmed time
+
+ if (weapon != -1) // if not unarmed
+ {
+ // look up the damage base
+ if (you.inv[ weapon ].base_type == OBJ_WEAPONS)
+ {
+ damage = property( you.inv[ weapon ], PWPN_DAMAGE );
+ speed = property( you.inv[ weapon ], PWPN_SPEED );
+
+ if (get_weapon_brand( you.inv[ weapon ] ) == SPWPN_SPEED)
+ {
+ speed *= 5;
+ speed /= 10;
+ }
+ }
+ else if (item_is_staff( you.inv[ weapon ] ))
+ {
+ damage = property( you.inv[ weapon ], PWPN_DAMAGE );
+ speed = property( you.inv[ weapon ], PWPN_SPEED );
+ }
+ }
+
+ // Because we're casting a spell (and don't want to make this level
+ // one spell too good), we're not applying skill speed bonuses and at
+ // the very least guaranteeing one full turn (speed == 10) like the
+ // other spells (if any thing else related to speed is changed, at
+ // least leave this right before the application to you.time_taken).
+ // Leaving skill out of the speed bonus is an important part of
+ // keeping this spell from becoming a "better than actual melee"
+ // spell... although, it's fine if that's the case for early Warpers,
+ // Fighter types, and such that pick up this trivial first level spell,
+ // shouldn't be using it instead of melee (but rather as an accessory
+ // long range plinker). Therefore, we tone things down to try and
+ // guarantee that the spell is never begins to approach real combat
+ // (although the magic resistance check might end up with a higher
+ // hit rate than attacking against EV for high level Warpers). -- bwr
+ if (speed < 10)
+ speed = 10;
+
+ you.time_taken *= speed;
+ you.time_taken /= 10;
+
+ // Apply strength only to damage (since we're only interested in
+ // force here, not finesse... the dex/to-hit part of combat is
+ // instead handled via magical ability). This part could probably
+ // just be removed, as it's unlikely to make any real difference...
+ // if it is, the Warper stats in newgame.cc should be changed back
+ // to the standard 6 int-4 dex of spellcasters. -- bwr
+ int dammod = 78;
+ const int dam_stat_val = you.strength;
+
+ if (dam_stat_val > 11)
+ dammod += (random2(dam_stat_val - 11) * 2);
+ else if (dam_stat_val < 9)
+ dammod -= (random2(9 - dam_stat_val) * 3);
+
+ damage *= dammod;
+ damage /= 78;
+
+ struct monsters *monster = &menv[ mgrd[targ.tx][targ.ty] ];
+
+ // apply monster's AC
+ if (monster->armour_class > 0)
+ damage -= random2( 1 + monster->armour_class );
+
+#if 0
+ // Removing damage limiter since it's categorized at level 4 right now.
+
+ // Force transmitted is limited by skill...
+ const int limit = (you.skills[SK_TRANSLOCATIONS] + 1) / 2 + 3;
+ if (damage > limit)
+ damage = limit;
+#endif
+
+ // Roll the damage...
+ damage = 1 + random2( damage );
+
+ // Monster can magically save vs attack (this could be replaced or
+ // augmented with an EV check).
+ if (check_mons_resist_magic( monster, pow * 2 ))
+ {
+ simple_monster_message( monster, " resists." );
+ return;
+ }
+
+ // Inflict the damage
+ hurt_monster( monster, damage );
+ if (monster->hit_points < 1)
+ monster_die( monster, KILL_YOU, 0 );
+ else
+ print_wounds( monster );
+
+ return;
+} // end cast_far_strike()
+
+void cast_apportation(int pow)
+{
+ struct dist beam;
+
+ mpr("Pull items from where?");
+
+ direction( beam, DIR_TARGET );
+
+ if (!beam.isValid)
+ {
+ canned_msg(MSG_SPELL_FIZZLES);
+ return;
+ }
+
+ // it's already here!
+ if (beam.isMe)
+ {
+ mpr( "That's just silly." );
+ return;
+ }
+
+ // Protect the player from destroying the item
+ const int grid = grd[ you.x_pos ][ you.y_pos ];
+
+ if (grid == DNGN_LAVA || grid == DNGN_DEEP_WATER)
+ {
+ mpr( "That would be silly while over this terrain!" );
+ return;
+ }
+
+ // If this is ever changed to allow moving objects that can't
+ // be seen, it should at least only allow moving from squares
+ // that have been phyisically (and maybe magically) seen and
+ // should probably have a range check as well. In these cases
+ // the spell should probably be upped to at least two, or three
+ // if magic mapped squares are allowed. Right now it's okay
+ // at one... it has a few uses, but you still have to get line
+ // of sight to the object first so it will only help a little
+ // with snatching runes or the orb (although it can be quite
+ // useful for getting items out of statue rooms or the abyss). -- bwr
+ if (!see_grid( beam.tx, beam.ty ))
+ {
+ mpr( "You cannot see there!" );
+ return;
+ }
+
+ // Let's look at the top item in that square...
+ const int item = igrd[ beam.tx ][ beam.ty ];
+ if (item == NON_ITEM)
+ {
+ const int mon = mgrd[ beam.tx ][ beam.ty ];
+
+ if (mon == NON_MONSTER)
+ mpr( "There are no items there." );
+ else if (mons_is_mimic( menv[ mon ].type ))
+ {
+ snprintf( info, INFO_SIZE, "%s twitches.",
+ ptr_monam( &(menv[ mon ]), DESC_CAP_THE ) );
+ mpr( info );
+ }
+ else
+ mpr( "This spell does not work on creatures." );
+
+ return;
+ }
+
+ // mass of one unit
+ const int unit_mass = mass_item( mitm[ item ] );
+ // assume we can pull everything
+ int max_units = mitm[ item ].quantity;
+
+ // item has mass: might not move all of them
+ if (unit_mass > 0)
+ {
+ const int max_mass = pow * 30 + random2( pow * 20 );
+
+ // most units our power level will allow
+ max_units = max_mass / unit_mass;
+ }
+
+ if (max_units <= 0)
+ {
+ mpr( "The mass is resisting your pull." );
+ return;
+ }
+
+ // Failure should never really happen after all the above checking,
+ // but we'll handle it anyways...
+ if (move_top_item( beam.tx, beam.ty, you.x_pos, you.y_pos ))
+ {
+ if (max_units < mitm[ item ].quantity)
+ {
+ mitm[ item ].quantity = max_units;
+ mpr( "You feel that some mass got lost in the cosmic void." );
+ }
+ else
+ {
+ mpr( "Yoink!" );
+ snprintf( info, INFO_SIZE, "You pull the item%s to yourself.",
+ (mitm[ item ].quantity > 1) ? "s" : "" );
+ mpr( info );
+ }
+ }
+ else
+ mpr( "The spell fails." );
+}
+
+void cast_sandblast(int pow)
+{
+ bool big = true;
+ struct dist spd;
+ struct bolt beam;
+
+ // this type of power manipulation should be done with the others,
+ // currently over in it_use2.cc (ack) -- bwr
+ // int hurt = 2 + random2(5) + random2(4) + random2(pow) / 20;
+
+ big = false;
+
+ if (you.equip[EQ_WEAPON] != -1)
+ {
+ int wep = you.equip[EQ_WEAPON];
+ if (you.inv[wep].base_type == OBJ_MISSILES
+ && (you.inv[wep].sub_type == MI_STONE || you.inv[wep].sub_type == MI_LARGE_ROCK))
+ big = true;
+ }
+
+ if (spell_direction(spd, beam) == -1)
+ return;
+
+ if (spd.isMe)
+ {
+ canned_msg(MSG_UNTHINKING_ACT);
+ return;
+ }
+
+ if (big)
+ {
+ dec_inv_item_quantity( you.equip[EQ_WEAPON], 1 );
+ zapping(ZAP_SANDBLAST, pow, beam);
+ }
+ else
+ {
+ zapping(ZAP_SMALL_SANDBLAST, pow, beam);
+ }
+} // end cast_sandblast()
+
+static bool mons_can_host_shuggoth(int type) //jmf: simplified
+{
+ if (mons_holiness(type) != MH_NATURAL)
+ return false;
+ if (mons_flag(type, M_WARM_BLOOD))
+ return true;
+
+ return false;
+}
+
+void cast_shuggoth_seed(int powc)
+{
+ struct dist beam;
+ int i;
+
+ mpr("Sow seed in whom?", MSGCH_PROMPT);
+
+ direction( beam, DIR_TARGET, TARG_ENEMY );
+
+ if (!beam.isValid)
+ {
+ mpr("You feel a distant frustration.");
+ return;
+ }
+
+ if (beam.isMe)
+ {
+ if (!you.is_undead)
+ {
+ you.duration[DUR_INFECTED_SHUGGOTH_SEED] = 10;
+ mpr("A deathly dread twitches in your chest.");
+ }
+ else
+ mpr("You feel a distant frustration.");
+ }
+
+ i = mgrd[beam.tx][beam.ty];
+
+ if (i == NON_MONSTER)
+ {
+ mpr("You feel a distant frustration.");
+ return;
+ }
+
+ if (mons_can_host_shuggoth(menv[i].type))
+ {
+ if (random2(powc) > 100)
+ mons_add_ench(&menv[i], ENCH_YOUR_SHUGGOTH_III);
+ else
+ mons_add_ench(&menv[i], ENCH_YOUR_SHUGGOTH_IV);
+
+ simple_monster_message(&menv[i], " twitches.");
+ }
+
+ return;
+}
+
+void cast_condensation_shield(int pow)
+{
+ if (you.equip[EQ_SHIELD] != -1 || you.fire_shield)
+ canned_msg(MSG_SPELL_FIZZLES);
+ else
+ {
+ if (you.duration[DUR_CONDENSATION_SHIELD] > 0)
+ you.duration[DUR_CONDENSATION_SHIELD] += 5 + roll_dice(2, 3);
+ else
+ {
+ mpr("A crackling disc of dense vapour forms in the air!");
+ you.redraw_armour_class = 1;
+
+ you.duration[DUR_CONDENSATION_SHIELD] = 10 + roll_dice(2, pow / 5);
+ }
+
+ if (you.duration[DUR_CONDENSATION_SHIELD] > 30)
+ you.duration[DUR_CONDENSATION_SHIELD] = 30;
+ }
+
+ return;
+} // end cast_condensation_shield()
+
+static int quadrant_blink(int x, int y, int pow, int garbage)
+{
+ UNUSED( garbage );
+
+ if (x == you.x_pos && y == you.y_pos)
+ return (0);
+
+ if (you.level_type == LEVEL_ABYSS)
+ {
+ abyss_teleport( false );
+ you.pet_target = MHITNOT;
+ return (1);
+ }
+
+ if (pow > 100)
+ pow = 100;
+
+ // setup: Brent's new algorithm
+ // we are interested in two things: distance of a test point from
+ // the ideal 'line', and the distance of a test point from two
+ // actual points, one in the 'correct' direction and one in the
+ // 'incorrect' direction.
+
+ // scale distance by 10 for more interesting numbers.
+ int l,m; // for line equation lx + my = 0
+ l = (x - you.x_pos);
+ m = (you.y_pos - y);
+
+ int tx, ty; // test x,y
+ int rx, ry; // x,y relative to you.
+ int sx, sy; // test point in the correct direction
+ int bx = x; // best x
+ int by = y; // best y
+
+ int best_dist = 10000;
+
+ sx = l;
+ sy = -m;
+
+ // for each point (a,b), distance from the line is | la + mb |
+
+ for(int tries = pow * pow / 500 + 1; tries > 0; tries--)
+ {
+ if (!random_near_space(you.x_pos, you.y_pos, tx, ty))
+ return 0;
+
+ rx = tx - you.x_pos;
+ ry = ty - you.y_pos;
+
+ int dist = l * rx + m * ry;
+ dist *= 10 * dist; // square and multiply by 10
+
+ // check distance to test points
+ int dist1 = distance(rx, ry, sx, sy) * 10;
+ int dist2 = distance(rx, ry, -sx, -sy) * 10;
+
+ // 'good' points will always be closer to test point 1
+ if (dist2 < dist1)
+ dist += 80; // make the point less attractive
+
+ if (dist < best_dist)
+ {
+ best_dist = dist;
+ bx = tx;
+ by = ty;
+ }
+ }
+
+ you.x_pos = bx;
+ you.y_pos = by;
+
+ return (1);
+}
+
+void cast_semi_controlled_blink(int pow)
+{
+ apply_one_neighbouring_square(quadrant_blink, pow);
+ return;
+}
+
+void cast_stoneskin(int pow)
+{
+ if (you.is_undead)
+ {
+ mpr("This spell does not affect your undead flesh.");
+ return;
+ }
+
+ if (you.attribute[ATTR_TRANSFORMATION] != TRAN_NONE
+ && you.attribute[ATTR_TRANSFORMATION] != TRAN_STATUE
+ && you.attribute[ATTR_TRANSFORMATION] != TRAN_BLADE_HANDS)
+ {
+ mpr("This spell does not affect your current form.");
+ return;
+ }
+
+ if (you.duration[DUR_STONEMAIL] || you.duration[DUR_ICY_ARMOUR])
+ {
+ mpr("This spell conflicts with another spell still in effect.");
+ return;
+ }
+
+ if (you.duration[DUR_STONESKIN])
+ mpr( "Your skin feels harder." );
+ else
+ {
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_STATUE)
+ mpr( "Your stone body feels more resilient." );
+ else
+ mpr( "Your skin hardens." );
+
+ you.redraw_armour_class = 1;
+ }
+
+ you.duration[DUR_STONESKIN] += 10 + random2(pow) + random2(pow);
+
+ if (you.duration[DUR_STONESKIN] > 50)
+ you.duration[DUR_STONESKIN] = 50;
+}
diff --git a/trunk/source/spells4.h b/trunk/source/spells4.h
new file mode 100644
index 0000000000..94cc74fcac
--- /dev/null
+++ b/trunk/source/spells4.h
@@ -0,0 +1,61 @@
+/*
+ * File: spells4.cc
+ * Summary: Yet More Spell Function Declarations
+ * Written by: Josh Fishman
+ *
+ * Change History (most recent first):
+ * <2> 12jul2000 jmf Fixed random (undocumented) damage
+ * <1> 07jan2000 jmf Created
+ */
+
+
+#ifndef SPELLS4_H
+#define SPELLS4_H
+
+#include "externs.h"
+
+const char *your_hand(bool plural);
+bool backlight_monsters(int x, int y, int pow, int garbage);
+int make_a_normal_cloud(int x, int y, int pow, int ctype);
+int disperse_monsters(int x, int y, int pow, int message);
+
+void cast_bend(int pow);
+void cast_condensation_shield(int pow);
+void cast_detect_secret_doors(int pow);
+void cast_discharge(int pow);
+void cast_evaporate(int pow);
+void cast_fulsome_distillation(int powc);
+void cast_forescry(int pow);
+void cast_fragmentation(int powc);
+void cast_twist(int powc);
+void cast_far_strike(int powc);
+void cast_swap(int powc);
+void cast_apportation(int powc);
+void cast_glamour(int pow);
+void cast_ignite_poison(int pow);
+void cast_intoxicate(int pow);
+void cast_mass_sleep(int pow);
+void cast_passwall(int pow);
+void cast_rotting(int pow);
+void cast_sandblast(int powc);
+void cast_see_invisible(int pow);
+
+void cast_shatter(int pow);
+void cast_silence(int pow);
+void cast_sticks_to_snakes(int pow);
+void cast_summon_butterflies(int pow);
+void cast_summon_dragon(int pow);
+void cast_conjure_ball_lightning(int pow);
+void cast_summon_large_mammal(int pow);
+void cast_tame_beasts(int pow);
+void cast_dispersal(int pow);
+void cast_snake_charm(int pow);
+void cast_stoneskin(int pow);
+
+void cast_shuggoth_seed(int powc);
+void make_shuggoth(int x, int y, int hp);
+
+void cast_semi_controlled_blink(int pow);
+
+
+#endif
diff --git a/trunk/source/spl-book.cc b/trunk/source/spl-book.cc
new file mode 100644
index 0000000000..bab93b9600
--- /dev/null
+++ b/trunk/source/spl-book.cc
@@ -0,0 +1,1524 @@
+/*
+ * File: spl-book.cc
+ * Summary: Spellbook/Staff contents array and management functions
+ * Written by: Josh Fishman
+ *
+ * Change History (most recent first):
+ *
+ * 24jun2000 jmf Changes to many books; addition of Assassinations;
+ * alteration of type-printout to match new bitfield.
+ * <1> 19mar2000 jmf Created by taking stuff from dungeon.cc, spells0.cc,
+ * spells.cc, shopping.cc
+ */
+
+#include "AppHdr.h"
+#include "spl-book.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#include "externs.h"
+
+#include "debug.h"
+#include "delay.h"
+#include "invent.h"
+#include "itemname.h"
+#include "items.h"
+#include "it_use3.h"
+#include "player.h"
+#include "religion.h"
+#include "spl-cast.h"
+#include "spl-util.h"
+#include "stuff.h"
+
+static int spellbook_template_array[NUMBER_SPELLBOOKS][SPELLBOOK_SIZE] =
+{
+ // 0 - Minor Magic I
+ {0,
+ SPELL_MAGIC_DART,
+ SPELL_SUMMON_SMALL_MAMMAL,
+ SPELL_THROW_FLAME,
+ SPELL_BLINK,
+ SPELL_SLOW,
+ SPELL_MEPHITIC_CLOUD,
+ SPELL_CONJURE_FLAME,
+ SPELL_NO_SPELL,
+ },
+ // 1 - Minor Magic II
+ {0,
+ SPELL_MAGIC_DART,
+ SPELL_THROW_FROST,
+ SPELL_BLINK,
+ SPELL_STICKS_TO_SNAKES,
+ SPELL_SLOW,
+ SPELL_MEPHITIC_CLOUD,
+ SPELL_OZOCUBUS_ARMOUR,
+ SPELL_NO_SPELL,
+ },
+ // 2 - Minor Magic III
+ {0,
+ SPELL_MAGIC_DART,
+ SPELL_SUMMON_SMALL_MAMMAL,
+ SPELL_BLINK,
+ SPELL_REPEL_MISSILES,
+ SPELL_SLOW,
+ SPELL_SUMMON_LARGE_MAMMAL,
+ SPELL_MEPHITIC_CLOUD,
+ SPELL_NO_SPELL,
+ },
+ // 3 - Book of Conjurations I - Fire and Earth
+ {0,
+ SPELL_MAGIC_DART,
+ SPELL_THROW_FLAME,
+ SPELL_STONE_ARROW,
+ SPELL_CONJURE_FLAME,
+ SPELL_BOLT_OF_MAGMA,
+ SPELL_FIREBALL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 4 - Book of Conjurations II - Air and Ice
+ {0,
+ SPELL_MAGIC_DART,
+ SPELL_THROW_FROST,
+ SPELL_MEPHITIC_CLOUD,
+ SPELL_DISCHARGE,
+ SPELL_BOLT_OF_COLD,
+ SPELL_FREEZING_CLOUD,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 5 - Book of Flames
+ {0,
+ SPELL_FLAME_TONGUE,
+ SPELL_THROW_FLAME,
+ SPELL_CONJURE_FLAME,
+ SPELL_STICKY_FLAME,
+ SPELL_BOLT_OF_FIRE,
+ SPELL_FIREBALL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 6 - Book of Frost
+ {0,
+ SPELL_FREEZE,
+ SPELL_THROW_FROST,
+ SPELL_OZOCUBUS_ARMOUR,
+ SPELL_ICE_BOLT,
+ SPELL_SUMMON_ICE_BEAST,
+ SPELL_FREEZING_CLOUD,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 7 - Book of Summonings
+ {0,
+ SPELL_ABJURATION_I,
+ SPELL_RECALL,
+ SPELL_SUMMON_LARGE_MAMMAL,
+ SPELL_SHADOW_CREATURES,
+ SPELL_SUMMON_WRAITHS,
+ SPELL_SUMMON_HORRIBLE_THINGS,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 8 - Book of Fire
+ {0,
+ SPELL_EVAPORATE,
+ SPELL_FIRE_BRAND,
+ SPELL_SUMMON_ELEMENTAL,
+ SPELL_BOLT_OF_MAGMA,
+ SPELL_DELAYED_FIREBALL,
+ SPELL_IGNITE_POISON,
+ SPELL_RING_OF_FLAMES,
+ SPELL_NO_SPELL,
+ },
+ // 9 - Book of Ice
+ {0,
+ SPELL_FREEZING_AURA,
+ SPELL_SLEEP,
+ SPELL_CONDENSATION_SHIELD,
+ SPELL_BOLT_OF_COLD,
+ SPELL_OZOCUBUS_REFRIGERATION,
+ SPELL_MASS_SLEEP,
+ SPELL_SIMULACRUM,
+ SPELL_NO_SPELL,
+ },
+
+ // 10 - Book of Surveyances
+ {0,
+ SPELL_DETECT_SECRET_DOORS,
+ SPELL_DETECT_TRAPS,
+ SPELL_DETECT_ITEMS,
+ SPELL_MAGIC_MAPPING,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL
+ },
+ // 11 - Book of Spatial Translocations
+ {0,
+ SPELL_APPORTATION,
+ SPELL_BLINK,
+ SPELL_RECALL,
+ SPELL_TELEPORT_OTHER,
+ SPELL_TELEPORT_SELF,
+ SPELL_CONTROL_TELEPORT,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 12 - Book of Enchantments (fourth one)
+ {0,
+ SPELL_LEVITATION,
+ SPELL_SELECTIVE_AMNESIA,
+ SPELL_REMOVE_CURSE,
+ SPELL_CAUSE_FEAR,
+ SPELL_EXTENSION,
+ SPELL_DEFLECT_MISSILES,
+ SPELL_HASTE,
+ SPELL_NO_SPELL,
+ },
+ // 13 - Young Poisoner's Handbook
+ {0,
+ SPELL_STING,
+ SPELL_CURE_POISON_II,
+ SPELL_MEPHITIC_CLOUD,
+ SPELL_POISON_WEAPON,
+ SPELL_VENOM_BOLT,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 14 - Book of the Tempests
+ {0,
+ SPELL_DISCHARGE,
+ SPELL_LIGHTNING_BOLT,
+ SPELL_FIREBALL,
+ SPELL_SHATTER,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 15 - Book of Death
+ {0,
+ SPELL_CORPSE_ROT,
+ SPELL_BONE_SHARDS,
+ SPELL_LETHAL_INFUSION,
+ SPELL_AGONY,
+ SPELL_BOLT_OF_DRAINING,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 16 - Book of Hinderance
+ {0,
+ SPELL_CONFUSING_TOUCH,
+ SPELL_SLOW,
+ SPELL_CONFUSE,
+ SPELL_PARALYZE,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 17 - Book of Changes
+ {0,
+ SPELL_FULSOME_DISTILLATION,
+ SPELL_STICKS_TO_SNAKES,
+ SPELL_EVAPORATE,
+ SPELL_SPIDER_FORM,
+ SPELL_ICE_FORM,
+ SPELL_DIG,
+ SPELL_BLADE_HANDS,
+ SPELL_NO_SPELL,
+ },
+ // 18 - Book of Transfigurations
+ {0,
+ SPELL_SANDBLAST,
+ SPELL_POLYMORPH_OTHER,
+ SPELL_STATUE_FORM,
+ SPELL_ALTER_SELF,
+ SPELL_DRAGON_FORM,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 19 - Book of Practical Magic
+ {0,
+ SPELL_PROJECTED_NOISE,
+ SPELL_SELECTIVE_AMNESIA,
+ SPELL_DETECT_CURSE,
+ SPELL_DIG,
+ SPELL_REMOVE_CURSE,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+
+ // 20 - Book of War Chants
+ {0,
+ SPELL_FIRE_BRAND,
+ SPELL_FREEZING_AURA,
+ SPELL_REPEL_MISSILES,
+ SPELL_BERSERKER_RAGE,
+ SPELL_REGENERATION,
+ SPELL_HASTE,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 21 - Book of Clouds
+ {0,
+ SPELL_EVAPORATE,
+ SPELL_MEPHITIC_CLOUD,
+ SPELL_CONJURE_FLAME,
+ SPELL_POISONOUS_CLOUD,
+ SPELL_FREEZING_CLOUD,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 22 - Book of Healing
+ {0,
+ SPELL_CURE_POISON_I,
+ SPELL_LESSER_HEALING,
+ SPELL_GREATER_HEALING,
+ SPELL_PURIFICATION,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 23 - Book of Necromancy
+ {0,
+ SPELL_PAIN,
+ SPELL_ANIMATE_SKELETON,
+ SPELL_VAMPIRIC_DRAINING,
+ SPELL_REGENERATION,
+ SPELL_DISPEL_UNDEAD,
+ SPELL_ANIMATE_DEAD,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 24 - Necronomicon -- Kikubaaqudgha special
+ {0,
+ SPELL_SYMBOL_OF_TORMENT,
+ SPELL_CONTROL_UNDEAD,
+ SPELL_SUMMON_WRAITHS,
+ SPELL_DEATHS_DOOR,
+ SPELL_NECROMUTATION,
+ SPELL_DEATH_CHANNEL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 25 - Book of Callings
+ {0,
+ SPELL_SUMMON_SMALL_MAMMAL,
+ SPELL_STICKS_TO_SNAKES,
+ SPELL_CALL_IMP,
+ SPELL_SUMMON_ELEMENTAL,
+ SPELL_SUMMON_SCORPIONS,
+ SPELL_SUMMON_ICE_BEAST,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 26 - Book of Charms
+ {0,
+ SPELL_BACKLIGHT,
+ SPELL_REPEL_MISSILES,
+ SPELL_SLEEP,
+#ifdef USE_SILENCE_CODE
+ SPELL_SILENCE,
+#endif
+ SPELL_CONFUSE,
+ SPELL_ENSLAVEMENT,
+ SPELL_INVISIBILITY,
+#ifndef USE_SILENCE_CODE
+ SPELL_NO_SPELL,
+#endif
+ SPELL_NO_SPELL,
+ },
+ // 27 - Book of Demonology -- Vehumet special
+ {0,
+ SPELL_ABJURATION_I,
+ SPELL_RECALL,
+ SPELL_CALL_IMP,
+ SPELL_SUMMON_DEMON,
+ SPELL_DEMONIC_HORDE,
+ SPELL_SUMMON_GREATER_DEMON,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 28 - Book of Air
+ {0,
+ SPELL_SHOCK,
+ SPELL_SWIFTNESS,
+ SPELL_REPEL_MISSILES,
+ SPELL_LEVITATION,
+ SPELL_MEPHITIC_CLOUD,
+ SPELL_DISCHARGE,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+
+ // Removing Air Walk... it's currently broken in a number or ways:
+ // - the AC/EV bonus probably means very little to any character
+ // capable of casting a level nine spell
+ // - the penalty of dropping inventory is a bit harsh considering
+ // the above
+ // - the fire/ice susceptibility doesn't work... the AC/EV bonus
+ // cancel it out (so you'd hardly be wary of them since they
+ // can't really do any damage).
+ // - there is no need for another invulnerability spell (which is
+ // what this spell is trying to be), one is more than enough...
+ // let people use necromancy.
+ // - there is no need for another air spell... air spells are
+ // already very common (ie. this level nine spell occured in
+ // two books!)
+
+ // 29 - Book of the Sky
+ {0,
+#ifdef USE_SILENCE_CODE
+ SPELL_SILENCE,
+#endif
+ SPELL_SUMMON_ELEMENTAL,
+ SPELL_INSULATION,
+ SPELL_AIRSTRIKE,
+ SPELL_FLY,
+ SPELL_DEFLECT_MISSILES,
+ SPELL_LIGHTNING_BOLT,
+ SPELL_CONJURE_BALL_LIGHTNING,
+#ifndef USE_SILENCE_CODE
+ SPELL_NO_SPELL,
+#endif
+ },
+
+ // 30 - Book of Divinations
+ {0,
+ SPELL_DETECT_SECRET_DOORS,
+ SPELL_DETECT_CREATURES,
+ SPELL_DETECT_ITEMS,
+ SPELL_DETECT_CURSE,
+ SPELL_SEE_INVISIBLE,
+ SPELL_FORESCRY,
+ SPELL_IDENTIFY,
+ SPELL_NO_SPELL,
+ },
+ // 31 - Book of the Warp
+ {0,
+ SPELL_CONTROLLED_BLINK,
+ SPELL_BANISHMENT,
+ SPELL_DISPERSAL,
+ SPELL_PORTAL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 32 - Book of Envenomations
+ {0,
+ SPELL_SPIDER_FORM,
+ SPELL_POISON_AMMUNITION,
+ SPELL_SUMMON_SCORPIONS,
+ SPELL_RESIST_POISON,
+ SPELL_OLGREBS_TOXIC_RADIANCE,
+ SPELL_POISONOUS_CLOUD,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 33 - Book of Annihilations -- Vehumet special
+ {0,
+ SPELL_ISKENDERUNS_MYSTIC_BLAST,
+ SPELL_POISON_ARROW,
+ SPELL_ORB_OF_ELECTROCUTION, // XXX: chain lightning?
+ SPELL_LEHUDIBS_CRYSTAL_SPEAR,
+ SPELL_ICE_STORM,
+ SPELL_FIRE_STORM,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 34 - Book of Unlife
+ {0,
+ SPELL_SUBLIMATION_OF_BLOOD,
+ SPELL_ANIMATE_DEAD,
+ SPELL_TWISTED_RESURRECTION,
+ SPELL_BORGNJORS_REVIVIFICATION,
+ SPELL_SIMULACRUM,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+
+ // 35 - Tome of Destruction
+ {0,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 36 - Book of Control
+ {0,
+ SPELL_ENSLAVEMENT,
+ SPELL_TAME_BEASTS,
+ SPELL_MASS_CONFUSION,
+ SPELL_CONTROL_UNDEAD,
+ SPELL_CONTROL_TELEPORT,
+ SPELL_MASS_SLEEP,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 37 - Book of Mutations //jmf: now Morphology
+ {0,
+ SPELL_FRAGMENTATION,
+ SPELL_POLYMORPH_OTHER,
+ SPELL_ALTER_SELF,
+ SPELL_CIGOTUVIS_DEGENERATION,
+ // SPELL_IGNITE_POISON, // moved to Fire which was a bit slim -- bwr
+ SPELL_SHATTER,
+ // SPELL_AIR_WALK,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 38 - Book of Tukima
+ {0,
+ SPELL_SURE_BLADE,
+ SPELL_TUKIMAS_VORPAL_BLADE,
+ SPELL_TUKIMAS_DANCE,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 39 - Book of Geomancy
+ {0,
+ SPELL_SANDBLAST,
+ SPELL_STONESKIN,
+ SPELL_PASSWALL,
+ SPELL_STONE_ARROW,
+ SPELL_SUMMON_ELEMENTAL,
+ SPELL_FRAGMENTATION,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+
+ // 40 - Book of Earth
+ {0,
+ SPELL_MAXWELLS_SILVER_HAMMER,
+ SPELL_MAGIC_MAPPING,
+ SPELL_DIG,
+ SPELL_STATUE_FORM,
+ SPELL_BOLT_OF_IRON,
+ SPELL_TOMB_OF_DOROKLOHE,
+ SPELL_SHATTER,
+ SPELL_NO_SPELL,
+ },
+ // 41 - manuals of all kinds
+ {0,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 42 - Book of Wizardry
+ {0,
+ SPELL_DETECT_CREATURES,
+ SPELL_SUMMON_ELEMENTAL,
+ SPELL_MAGIC_MAPPING,
+ SPELL_TELEPORT_SELF,
+ SPELL_FIREBALL,
+ SPELL_IDENTIFY,
+ SPELL_HASTE,
+ SPELL_NO_SPELL,
+ },
+ // 43 - Book of Power
+ {0,
+ SPELL_ANIMATE_DEAD,
+ SPELL_TELEPORT_OTHER,
+ SPELL_VENOM_BOLT,
+ SPELL_BOLT_OF_IRON,
+ SPELL_INVISIBILITY,
+ SPELL_MASS_CONFUSION,
+ SPELL_POISONOUS_CLOUD,
+ SPELL_NO_SPELL,
+ },
+ // 44 - Book of Cantrips //jmf: added 04jan2000
+ {0,
+ SPELL_CONFUSING_TOUCH,
+ SPELL_ANIMATE_SKELETON,
+ SPELL_SUMMON_SMALL_MAMMAL,
+ SPELL_DETECT_SECRET_DOORS,
+ SPELL_APPORTATION,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+
+ // 45 - Book of Party Tricks //jmf: added 04jan2000
+ {0,
+ SPELL_SUMMON_BUTTERFLIES,
+ SPELL_APPORTATION,
+ SPELL_PROJECTED_NOISE,
+ SPELL_BLINK,
+ SPELL_LEVITATION,
+ SPELL_INTOXICATE,
+ SPELL_NO_SPELL, //jmf: SPELL_ERINGYAS_SURPRISING_BOUQUET, when finished
+ SPELL_NO_SPELL,
+ },
+
+ // 46 - Book of Beasts //jmf: added 19mar2000
+ {0,
+ SPELL_SUMMON_SMALL_MAMMAL,
+ SPELL_STICKS_TO_SNAKES,
+ SPELL_DETECT_CREATURES,
+ SPELL_SUMMON_LARGE_MAMMAL,
+ SPELL_TAME_BEASTS,
+ SPELL_DRAGON_FORM,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+
+ // 47 - Book of Stalking //jmf: 24jun2000
+ {0,
+ SPELL_STING,
+ SPELL_SURE_BLADE,
+ SPELL_PROJECTED_NOISE,
+ SPELL_MEPHITIC_CLOUD,
+ SPELL_POISON_WEAPON,
+ SPELL_PARALYZE,
+ SPELL_INVISIBILITY,
+ SPELL_NO_SPELL,
+ },
+
+ // 48 -- unused
+ {0,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+
+ // 49 - unused
+ {0,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+
+ // 50 - Staff of Smiting //jmf: totally obsolete --- no longer looks here.
+ {0,
+ SPELL_SMITING,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 51 - Staff of Summoning
+ {0,
+ SPELL_ABJURATION_I,
+ SPELL_RECALL,
+ SPELL_SUMMON_ELEMENTAL,
+ SPELL_SWARM,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 52 - Staff of Destruction
+ {0,
+ SPELL_THROW_FLAME,
+ SPELL_BOLT_OF_FIRE,
+ SPELL_FIREBALL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 53 - Staff of Destruction
+ {0,
+ SPELL_THROW_FROST,
+ SPELL_ICE_BOLT,
+ SPELL_FREEZING_CLOUD,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 54 - Staff of Destruction
+ {0,
+ SPELL_BOLT_OF_IRON,
+ SPELL_FIREBALL,
+ SPELL_LIGHTNING_BOLT,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 55 - Staff of Destruction
+ {0,
+ SPELL_BOLT_OF_INACCURACY,
+ SPELL_BOLT_OF_MAGMA,
+ SPELL_BOLT_OF_COLD,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 56 - Staff of Warding
+ {0,
+ SPELL_ABJURATION_I,
+ SPELL_CONDENSATION_SHIELD,
+ SPELL_CAUSE_FEAR,
+ SPELL_DEFLECT_MISSILES,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 57 - Staff of Exploration
+ {0,
+ SPELL_DETECT_SECRET_DOORS,
+ SPELL_DETECT_TRAPS,
+ SPELL_DETECT_ITEMS,
+ SPELL_MAGIC_MAPPING,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 58 - Staff of Demonology
+ {0,
+ SPELL_ABJURATION_I,
+ SPELL_RECALL,
+ SPELL_CALL_IMP,
+ SPELL_SUMMON_DEMON,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+ // 59 - Staff of Striking -- unused like Smiting
+ {0,
+ SPELL_STRIKING,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ },
+};
+
+static void spellbook_template( int sbook_type,
+ FixedVector < int, SPELLBOOK_SIZE > &sbtemplate_pass )
+{
+ ASSERT( sbook_type >= 0 );
+ ASSERT( sbook_type < NUMBER_SPELLBOOKS );
+
+ // no point doing anything if tome of destruction or a manual
+ if (sbook_type == BOOK_DESTRUCTION || sbook_type == BOOK_MANUAL)
+ return;
+
+ for (int i = 0; i < SPELLBOOK_SIZE; i++) //jmf: was i = 1
+ {
+ sbtemplate_pass[i] = spellbook_template_array[sbook_type][i];
+ }
+} // end spellbook_template()
+
+int which_spell_in_book(int sbook_type, int spl)
+{
+ FixedVector < int, SPELLBOOK_SIZE > wsib_pass; // was 10 {dlb}
+
+ spellbook_template(sbook_type, wsib_pass);
+
+ return (wsib_pass[ spl + 1 ]);
+} // end which_spell_in_book()
+
+static unsigned char spellbook_contents( item_def &book, int action )
+{
+ FixedVector<int, SPELLBOOK_SIZE> spell_types; // was 10 {dlb}
+ int spelcount = 0;
+ int i, j;
+
+ const int spell_levels = player_spell_levels();
+
+ // special case for staves
+ const int type = (book.base_type == OBJ_STAVES) ? book.sub_type + 40
+ : book.sub_type;
+
+ bool spell_skills = false;
+
+ for (i = SK_SPELLCASTING; i <= SK_POISON_MAGIC; i++)
+ {
+ if (you.skills[i])
+ {
+ spell_skills = true;
+ break;
+ }
+ }
+
+ set_ident_flags( book, ISFLAG_KNOW_TYPE );
+
+#ifdef DOS_TERM
+ char buffer[4800];
+ gettext(1, 1, 80, 25, buffer);
+ window(1, 1, 80, 25);
+#endif
+
+ spellbook_template( type, spell_types );
+
+ clrscr();
+ textcolor(LIGHTGREY);
+
+ char str_pass[ ITEMNAME_SIZE ];
+ item_name( book, DESC_CAP_THE, str_pass );
+ cprintf( str_pass );
+
+ cprintf( EOL EOL " Spells Type Level" EOL );
+
+ for (j = 1; j < SPELLBOOK_SIZE; j++)
+ {
+ if (spell_types[j] == SPELL_NO_SPELL)
+ continue;
+
+ cprintf(" ");
+
+ bool knowsSpell = false;
+ for (i = 0; i < 25 && !knowsSpell; i++)
+ {
+ knowsSpell = (you.spells[i] == spell_types[j]);
+ }
+
+ const int level_diff = spell_difficulty( spell_types[j] );
+ const int levels_req = spell_levels_required( spell_types[j] );
+
+ int colour = DARKGREY;
+ if (action == RBOOK_USE_STAFF)
+ {
+ if (you.experience_level >= level_diff
+ && you.magic_points >= level_diff)
+ {
+ colour = LIGHTGREY;
+ }
+ }
+ else
+ {
+ if (knowsSpell)
+ colour = LIGHTGREY;
+ else if (you.experience_level >= level_diff
+ && spell_levels >= levels_req
+ && spell_skills)
+ {
+ colour = LIGHTBLUE;
+ }
+ }
+
+ textcolor( colour );
+
+ // Old:
+ // textcolor(knowsSpell ? DARKGREY : LIGHTGREY);
+ // was: ? LIGHTGREY : LIGHTBLUE
+
+ char strng[2];
+
+ strng[0] = index_to_letter(spelcount);
+ strng[1] = '\0';
+
+ cprintf(strng);
+ cprintf(" - ");
+
+ cprintf( spell_title(spell_types[j]) );
+ gotoxy( 35, wherey() );
+
+
+ if (action == RBOOK_USE_STAFF)
+ cprintf( "Evocations" );
+ else
+ {
+ bool already = false;
+
+ for (i = 0; i <= SPTYP_LAST_EXPONENT; i++)
+ {
+ if (spell_typematch( spell_types[j], 1 << i ))
+ {
+ if (already)
+ cprintf( "/" );
+
+ cprintf( spelltype_name( 1 << i ) );
+ already = true;
+ }
+ }
+ }
+
+ gotoxy( 65, wherey() );
+
+ char sval[3];
+
+ itoa( level_diff, sval, 10 );
+ cprintf( sval );
+ cprintf( EOL );
+ spelcount++;
+ }
+
+ textcolor(LIGHTGREY);
+ cprintf(EOL);
+
+ switch (action)
+ {
+ case RBOOK_USE_STAFF:
+ cprintf( "Select a spell to cast." EOL );
+ break;
+
+ case RBOOK_MEMORIZE:
+ cprintf( "Select a spell to memorise (%d level%s available)." EOL,
+ spell_levels, (spell_levels == 1) ? "" : "s" );
+ break;
+
+ case RBOOK_READ_SPELL:
+ cprintf( "Select a spell to read its description." EOL );
+ break;
+
+ default:
+ break;
+ }
+
+ unsigned char keyn = getch();
+
+ if (keyn == 0)
+ getch();
+
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+ window(1, 18, 80, 25);
+#endif
+
+ return (keyn); // try to figure out that for which this is used {dlb}
+}
+
+//jmf: was in shopping.cc
+char book_rarity(unsigned char which_book)
+{
+ switch (which_book)
+ {
+ case BOOK_MINOR_MAGIC_I:
+ case BOOK_MINOR_MAGIC_II:
+ case BOOK_MINOR_MAGIC_III:
+ case BOOK_SURVEYANCES:
+ case BOOK_HINDERANCE:
+ case BOOK_CANTRIPS: //jmf: added 04jan2000
+ return 1;
+
+ case BOOK_CHANGES:
+ case BOOK_CHARMS:
+ return 2;
+
+ case BOOK_CONJURATIONS_I:
+ case BOOK_CONJURATIONS_II:
+ case BOOK_PRACTICAL_MAGIC:
+ case BOOK_NECROMANCY:
+ case BOOK_CALLINGS:
+ case BOOK_WIZARDRY:
+ return 3;
+
+ case BOOK_FLAMES:
+ case BOOK_FROST:
+ case BOOK_AIR:
+ case BOOK_GEOMANCY:
+ return 4;
+
+ case BOOK_YOUNG_POISONERS:
+ case BOOK_STALKING: //jmf: added 24jun2000
+ case BOOK_WAR_CHANTS:
+ return 5;
+
+ case BOOK_CLOUDS:
+ case BOOK_POWER:
+ return 6;
+
+ case BOOK_ENCHANTMENTS:
+ case BOOK_PARTY_TRICKS: //jmf: added 04jan2000
+ return 7;
+
+ case BOOK_TRANSFIGURATIONS:
+ case BOOK_DIVINATIONS:
+ return 8;
+
+ case BOOK_FIRE:
+ case BOOK_ICE:
+ case BOOK_SKY:
+ case BOOK_EARTH:
+ case BOOK_UNLIFE:
+ case BOOK_CONTROL:
+ case BOOK_SPATIAL_TRANSLOCATIONS:
+ return 10;
+
+ case BOOK_TEMPESTS:
+ case BOOK_DEATH:
+ return 11;
+
+ case BOOK_MUTATIONS:
+ case BOOK_BEASTS: //jmf: added 23mar2000
+ return 12;
+
+ case BOOK_ENVENOMATIONS:
+ case BOOK_WARP:
+ return 15;
+
+ case BOOK_TUKIMA:
+ return 16;
+
+ case BOOK_SUMMONINGS:
+ return 18;
+
+ case BOOK_ANNIHILATIONS: // Vehumet special
+ case BOOK_DEMONOLOGY: // Vehumet special
+ case BOOK_NECRONOMICON: // Kikubaaqudgha special
+ case BOOK_MANUAL:
+ return 20;
+
+ case BOOK_DESTRUCTION:
+ return 30;
+
+ case BOOK_HEALING:
+ return 100;
+
+ default:
+ return 1;
+ }
+} // end book_rarity()
+
+bool is_valid_spell_in_book( unsigned int splbook, int spell )
+{
+ FixedVector< int, SPELLBOOK_SIZE > spells;
+
+ spellbook_template( you.inv[ splbook ].sub_type, spells );
+
+ if (spells[ spell ] != SPELL_NO_SPELL)
+ return true;
+
+ return false;
+} // end is_valid_spell_in_book()
+
+static bool which_spellbook( int &book, int &spell )
+{
+ const int avail_levels = player_spell_levels();
+
+ // Knowing delayed fireball will allow Fireball to be learned for free -bwr
+ if (avail_levels < 1 && !player_has_spell(SPELL_DELAYED_FIREBALL))
+ {
+ mpr("You can't memorise any more spells yet.");
+ return (false);
+ }
+ else if (inv_count() < 1)
+ {
+ canned_msg(MSG_NOTHING_CARRIED);
+ return (false);
+ }
+
+ snprintf( info, INFO_SIZE, "You can memorise %d more level%s of spells.",
+ avail_levels, (avail_levels > 1) ? "s" : "" );
+
+ mpr( info );
+
+ book = prompt_invent_item( "Memorise from which spellbook?", OBJ_BOOKS );
+ if (book == PROMPT_ABORT)
+ {
+ canned_msg( MSG_OK );
+ return (false);
+ }
+
+ if (you.inv[book].base_type != OBJ_BOOKS
+ || you.inv[book].sub_type == BOOK_MANUAL)
+ {
+ mpr("That isn't a spellbook!");
+ return (false);
+ }
+
+ if (you.inv[book].sub_type == BOOK_DESTRUCTION)
+ {
+ tome_of_power( book );
+ return (false);
+ }
+
+ spell = read_book( you.inv[book], RBOOK_MEMORIZE );
+ clrscr();
+
+ return (true);
+} // end which_spellbook()
+
+// Returns false if the player cannot read/memorize from the book,
+// and true otherwise. -- bwr
+static bool player_can_read_spellbook( const item_def &book )
+{
+ if (book.base_type != OBJ_BOOKS)
+ return (true);
+
+ if ((book.sub_type == BOOK_ANNIHILATIONS
+ && you.religion != GOD_VEHUMET
+ && (you.skills[SK_CONJURATIONS] < 10
+ || you.skills[SK_SPELLCASTING] < 10))
+ || (book.sub_type == BOOK_DEMONOLOGY
+ && you.religion != GOD_VEHUMET
+ && (you.skills[SK_SUMMONINGS] < 10
+ || you.skills[SK_SPELLCASTING] < 10))
+ || (book.sub_type == BOOK_NECRONOMICON
+ && you.religion != GOD_KIKUBAAQUDGHA
+ && (you.skills[SK_NECROMANCY] < 10
+ || you.skills[SK_SPELLCASTING] < 10)))
+ {
+ return (false);
+ }
+
+ return (true);
+}
+
+unsigned char read_book( item_def &book, int action )
+{
+ unsigned char key2 = 0;
+
+ if (book.base_type == OBJ_BOOKS && !player_can_read_spellbook( book ))
+ {
+ mpr( "This book is beyond your current level of understanding." );
+ more();
+ return (0);
+ }
+
+ // remember that this function is called from staff spells as well:
+ key2 = spellbook_contents( book, action );
+
+ if (book.base_type == OBJ_BOOKS)
+ {
+ you.had_book[ book.sub_type ] = 1;
+
+ if ( book.sub_type == BOOK_MINOR_MAGIC_I
+ || book.sub_type == BOOK_MINOR_MAGIC_II
+ || book.sub_type == BOOK_MINOR_MAGIC_III)
+ {
+ you.had_book[BOOK_MINOR_MAGIC_I] = 1;
+ you.had_book[BOOK_MINOR_MAGIC_II] = 1;
+ you.had_book[BOOK_MINOR_MAGIC_III] = 1;
+ }
+ else if (book.sub_type == BOOK_CONJURATIONS_I
+ || book.sub_type == BOOK_CONJURATIONS_II)
+ {
+ you.had_book[BOOK_CONJURATIONS_I] = 1;
+ you.had_book[BOOK_CONJURATIONS_II] = 1;
+ }
+ }
+
+ redraw_screen();
+
+ /* Put special book effects in another function which can be called from
+ memorise as well */
+
+ // reading spell descriptions doesn't take time:
+ if (action != RBOOK_READ_SPELL)
+ you.turn_is_over = 1;
+
+ set_ident_flags( book, ISFLAG_KNOW_TYPE );
+
+ return (key2);
+} // end read_book()
+
+// recoded to answer whether an UNDEAD_STATE is
+// barred from a particular spell passed to the
+// function - note that the function can be expanded
+// to prevent memorisation of certain spells by
+// the living by setting up an US_ALIVE case returning
+// a value of false for a set of spells ... might be
+// an idea worth further consideration - 12mar2000 {dlb}
+bool undead_cannot_memorise(unsigned char spell, unsigned char being)
+{
+ switch (being)
+ {
+ case US_HUNGRY_DEAD:
+ switch (spell)
+ {
+ //case SPELL_REGENERATION:
+ case SPELL_BORGNJORS_REVIVIFICATION:
+ case SPELL_CURE_POISON_II:
+ case SPELL_DEATHS_DOOR:
+ case SPELL_NECROMUTATION:
+ case SPELL_RESIST_POISON:
+ case SPELL_SYMBOL_OF_TORMENT:
+ case SPELL_TAME_BEASTS:
+ case SPELL_BERSERKER_RAGE:
+ return true;
+ }
+ break;
+
+ case US_UNDEAD:
+ switch (spell)
+ {
+ case SPELL_AIR_WALK:
+ case SPELL_ALTER_SELF:
+ case SPELL_BLADE_HANDS:
+ case SPELL_BORGNJORS_REVIVIFICATION:
+ case SPELL_CURE_POISON_II:
+ case SPELL_DEATHS_DOOR:
+ case SPELL_DRAGON_FORM:
+ case SPELL_GLAMOUR:
+ case SPELL_ICE_FORM:
+ case SPELL_INTOXICATE:
+ case SPELL_NECROMUTATION:
+ case SPELL_PASSWALL:
+ case SPELL_REGENERATION:
+ case SPELL_RESIST_POISON:
+ case SPELL_SPIDER_FORM:
+ case SPELL_STATUE_FORM:
+ case SPELL_SUMMON_HORRIBLE_THINGS:
+ case SPELL_SYMBOL_OF_TORMENT:
+ case SPELL_TAME_BEASTS:
+ case SPELL_BERSERKER_RAGE:
+ return true;
+ }
+ break;
+ }
+
+ return false;
+} // end undead_cannot_memorise()
+
+bool learn_spell(void)
+{
+ int chance = 0;
+ int levels_needed = 0;
+ unsigned char keyin;
+ int book, spell;
+ int index;
+
+ int i;
+ int j = 0;
+
+ for (i = SK_SPELLCASTING; i <= SK_POISON_MAGIC; i++)
+ {
+ if (you.skills[i])
+ j++;
+ }
+
+ if (j == 0)
+ {
+ mpr("You can't use spell magic! I'm afraid it's scrolls only for now.");
+ return (false);
+ }
+
+ if (!which_spellbook( book, spell ))
+ return (false);
+
+ if (spell < 'A' || (spell > 'Z' && spell < 'a') || spell > 'z')
+ {
+ whatt:
+ redraw_screen();
+ mpr("What?");
+ return (false);
+ }
+
+ index = letter_to_index( spell );
+
+ if (index > SPELLBOOK_SIZE)
+ goto whatt;
+
+ if (!is_valid_spell_in_book( book, index ))
+ goto whatt;
+
+ unsigned int specspell = which_spell_in_book(you.inv[book].sub_type,index);
+
+ if (specspell == SPELL_NO_SPELL)
+ goto whatt;
+
+ // You can always memorise selective amnesia:
+ if (you.spell_no == 21 && specspell != SPELL_SELECTIVE_AMNESIA)
+ {
+ redraw_screen();
+ mpr("Your head is already too full of spells!");
+ return (false);
+ }
+
+ if (you.is_undead && spell_typematch(specspell, SPTYP_HOLY))
+ {
+ redraw_screen();
+ mpr("You cannot use this type of magic!");
+ return (false);
+ }
+
+ if (undead_cannot_memorise(specspell, you.is_undead))
+ {
+ redraw_screen();
+ mpr("You cannot use this spell.");
+ return (false);
+ }
+
+ for (i = 0; i < 25; i++)
+ {
+ if (you.spells[i] == specspell)
+ {
+ redraw_screen();
+ mpr("You already know that spell!");
+ you.turn_is_over = 1;
+ return (false);
+ }
+ }
+
+ levels_needed = spell_levels_required( specspell );
+
+ if (player_spell_levels() < levels_needed)
+ {
+ redraw_screen();
+ mpr("You can't memorise that many levels of magic yet!");
+ you.turn_is_over = 1;
+ return (false);
+ }
+
+ if (you.experience_level < spell_difficulty(specspell))
+ {
+ redraw_screen();
+ mpr("You're too inexperienced to learn that spell!");
+ you.turn_is_over = 1;
+ return (false);
+ }
+
+ redraw_screen();
+
+ chance = spell_fail(specspell);
+
+ strcpy(info, "This spell is ");
+
+ strcat(info, (chance >= 80) ? "very" :
+ (chance >= 60) ? "quite" :
+ (chance >= 45) ? "rather" :
+ (chance >= 30) ? "somewhat"
+ : "not that");
+
+ strcat(info, " ");
+
+ int temp_rand = random2(3);
+
+ strcat(info, (temp_rand == 0) ? "difficult" :
+ (temp_rand == 1) ? "tricky" :
+ (temp_rand == 2) ? "challenging"
+ : "");
+
+ strcat(info, " to ");
+
+ temp_rand = random2(4);
+
+ strcat(info, (temp_rand == 0) ? "memorise" :
+ (temp_rand == 1) ? "commit to memory" :
+ (temp_rand == 2) ? "learn" :
+ (temp_rand == 3) ? "absorb"
+ : "");
+
+ strcat(info, ".");
+
+ mpr(info);
+
+ strcpy(info, "Memorise ");
+ strcat(info, spell_title(specspell));
+ strcat(info, "?");
+ mpr(info);
+
+ for (;;)
+ {
+ keyin = getch();
+
+ if (keyin == 'n' || keyin == 'N')
+ {
+ redraw_screen();
+ return (false);
+ }
+
+ if (keyin == 'y' || keyin == 'Y')
+ break;
+ }
+
+ mesclr( true );
+
+ if (you.mutation[MUT_BLURRY_VISION] > 0
+ && random2(4) < you.mutation[MUT_BLURRY_VISION])
+ {
+ mpr("The writing blurs into unreadable gibberish.");
+ you.turn_is_over = 1;
+ return (false);
+ }
+
+ if (random2(40) + random2(40) + random2(40) < chance)
+ {
+ redraw_screen();
+ mpr("You fail to memorise the spell.");
+ you.turn_is_over = 1;
+
+ if (you.inv[ book ].sub_type == BOOK_NECRONOMICON)
+ {
+ mpr("The pages of the Necronomicon glow with a dark malevolence...");
+ miscast_effect( SPTYP_NECROMANCY, 8, random2avg(88, 3), 100,
+ "reading the Necronomicon" );
+ }
+ else if (you.inv[ book ].sub_type == BOOK_DEMONOLOGY)
+ {
+ mpr("This book does not appreciate being disturbed by one of your ineptitude!");
+ miscast_effect( SPTYP_SUMMONING, 7, random2avg(88, 3), 100,
+ "reading the book of Demonology" );
+ }
+ else if (you.inv[ book ].sub_type == BOOK_ANNIHILATIONS)
+ {
+ mpr("This book does not appreciate being disturbed by one of your ineptitude!");
+ miscast_effect( SPTYP_CONJURATION, 8, random2avg(88, 3), 100,
+ "reading the book of Annihilations" );
+ }
+
+#if WIZARD
+ if (!you.wizard)
+ return (false);
+ else if (!yesno("Memorize anyway?"))
+ return (false);
+#else
+ return (false);
+#endif
+ }
+
+ start_delay( DELAY_MEMORIZE, spell_difficulty( specspell ), specspell );
+
+ you.turn_is_over = 1;
+ redraw_screen();
+
+ naughty( NAUGHTY_SPELLCASTING, 2 + random2(5) );
+
+ return (true);
+} // end which_spell()
+
+int staff_spell( int staff )
+{
+ int spell;
+ unsigned char specspell;
+ int mana, diff;
+ FixedVector< int, SPELLBOOK_SIZE > spell_list;
+
+ // converting sub_type into book index type
+ const int type = you.inv[staff].sub_type + 40;
+
+ // Spell staves are mostly for the benefit of non-spellcasters, so we're
+ // not going to involve INT or Spellcasting skills for power. -- bwr
+ const int powc = 5 + you.skills[SK_EVOCATIONS]
+ + roll_dice( 2, you.skills[SK_EVOCATIONS] );
+
+ if (you.inv[staff].sub_type < STAFF_SMITING
+ || you.inv[staff].sub_type >= STAFF_AIR)
+ {
+ //mpr("That staff has no spells in it.");
+ canned_msg(MSG_NOTHING_HAPPENS);
+ return (0);
+ }
+
+ if (item_not_ident( you.inv[staff], ISFLAG_KNOW_TYPE ))
+ {
+ set_ident_flags( you.inv[staff], ISFLAG_KNOW_TYPE );
+ you.wield_change = true;
+ }
+
+ spellbook_template( type, spell_list );
+
+ unsigned char num_spells;
+ for (num_spells = 0; num_spells < SPELLBOOK_SIZE - 1; num_spells++)
+ {
+ if (spell_list[ num_spells + 1 ] == SPELL_NO_SPELL)
+ break;
+ }
+
+ if (num_spells == 0)
+ {
+ canned_msg(MSG_NOTHING_HAPPENS); // shouldn't happen
+ return (0);
+ }
+ else if (num_spells == 1)
+ spell = 'a'; // automatically selected if its the only option
+ else
+ {
+ snprintf( info, INFO_SIZE,
+ "Evoke which spell from the rod ([a-%c] spell [?*] list)? ",
+ 'a' + num_spells - 1 );
+
+ mpr( info, MSGCH_PROMPT );
+ spell = get_ch();
+
+ if (spell == '?' || spell == '*')
+ spell = read_book( you.inv[staff], RBOOK_USE_STAFF );
+ }
+
+ if (spell < 'A' || (spell > 'Z' && spell < 'a') || spell > 'z')
+ {
+ goto whattt;
+ }
+
+ spell = letter_to_index( spell );
+
+ if (spell > SPELLBOOK_SIZE)
+ goto whattt;
+
+ if (!is_valid_spell_in_book( staff, spell ))
+ goto whattt;
+
+ specspell = which_spell_in_book( type, spell );
+
+ if (specspell == SPELL_NO_SPELL)
+ goto whattt;
+
+ mana = spell_mana( specspell );
+ diff = spell_difficulty( specspell );
+
+ if (you.magic_points < mana || you.experience_level < diff)
+ {
+ mpr("Your brain hurts!");
+ confuse_player( 2 + random2(4) );
+ you.turn_is_over = 1;
+ return (0);
+ }
+
+ // Exercising the spell skills doesn't make very much sense given
+ // that spell staves are largely intended to supply spells to
+ // non-spellcasters, and they don't use spell skills to determine
+ // power in the same way that spellcasting does. -- bwr
+ //
+ // exercise_spell(specspell, true, true);
+
+ your_spells(specspell, powc, false);
+
+ dec_mp(spell_mana(specspell));
+
+ you.turn_is_over = 1;
+
+ return (roll_dice( 1, 1 + spell_difficulty(specspell) / 2 ));
+
+ whattt:
+ mpr("What?");
+
+ return (0);
+} // end staff_spell()
diff --git a/trunk/source/spl-book.h b/trunk/source/spl-book.h
new file mode 100644
index 0000000000..359f2c052c
--- /dev/null
+++ b/trunk/source/spl-book.h
@@ -0,0 +1,63 @@
+/*
+ * File: spl-book.h
+ * Summary: Some spellbook related functions.
+ * Written by: Josh Fishman
+ *
+ * Change History (most recent first):
+ *
+ * 22mar2000 jmf Created
+ */
+
+
+#ifndef SPL_BOOK_H
+#define SPL_BOOK_H
+
+#include "externs.h"
+#include "FixVec.h"
+
+
+// used in dungeon.cc, it_use3.cc, spl-book.cc, spl-book.h - {dlb}
+#define SPELLBOOK_SIZE 9
+// used in spl-book.cc, spl-book.h - {dlb}
+#define NUMBER_SPELLBOOKS 60
+
+
+// updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: dungeon - effects - shopping
+ * *********************************************************************** */
+char book_rarity(unsigned char which_book);
+
+
+// updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: it_use3 - item_use - spl-book
+ * *********************************************************************** */
+bool is_valid_spell_in_book( unsigned int splbook, int spell );
+
+
+// updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: it_use3 - item_use - spl-book
+ * *********************************************************************** */
+unsigned char read_book( item_def &item, int action );
+
+
+// updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+bool learn_spell(void);
+
+
+// updated 24may2000 {dlb}
+/* ***********************************************************************
+ * called from: it_use3 - item_use - spl-book
+ * *********************************************************************** */
+int which_spell_in_book(int sbook_type, int spl);
+
+int staff_spell( int zap_device_2 );
+
+bool undead_cannot_memorise(unsigned char spell, unsigned char being);
+
+#endif
diff --git a/trunk/source/spl-cast.cc b/trunk/source/spl-cast.cc
new file mode 100644
index 0000000000..135d831af9
--- /dev/null
+++ b/trunk/source/spl-cast.cc
@@ -0,0 +1,3542 @@
+/*
+ * File: spl-cast.cc
+ * Summary: Spell casting and miscast functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <4> 1/02/00 jmf changed values, marked //jmf:
+ * <3> 6/13/99 BWR Added Staff auto identify code
+ * <2> 5/20/99 BWR Added some screen redraws
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "spl-cast.h"
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "externs.h"
+
+#include "beam.h"
+#include "cloud.h"
+#include "effects.h"
+#include "fight.h"
+#include "food.h"
+#include "it_use2.h"
+#include "itemname.h"
+#include "macro.h"
+#include "monplace.h"
+#include "monstuff.h"
+#include "mutation.h"
+#include "ouch.h"
+#include "player.h"
+#include "religion.h"
+#include "skills.h"
+#include "spells1.h"
+#include "spells2.h"
+#include "spells3.h"
+#include "spells4.h"
+#include "spl-book.h"
+#include "spl-util.h"
+#include "stuff.h"
+#include "transfor.h"
+#include "view.h"
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#define WILD_MAGIC_NASTINESS 150
+
+static void surge_power(int spell)
+{
+ int enhanced = 0;
+
+ //jmf: simplified
+ enhanced += spell_enhancement(spell_type(spell));
+
+ if (enhanced) // one way or the other {dlb}
+ {
+ strcpy(info, "You feel a");
+
+ strcat(info, (enhanced < -2) ? "n extraordinarily" :
+ (enhanced == -2) ? "n extremely" :
+ (enhanced == 2) ? " strong" :
+ (enhanced > 2) ? " huge"
+ : "");
+
+ strcat(info, (enhanced < 0) ? " numb sensation."
+ : " surge of power!");
+ mpr(info);
+ }
+} // end surge_power()
+
+char list_spells(void)
+{
+ int j;
+ int lines = 0;
+ unsigned int anything = 0;
+ unsigned int i;
+ int ki;
+ bool already = false;
+
+ const int num_lines = get_number_of_lines();
+
+#ifdef DOS_TERM
+ char buffer[4800];
+
+ gettext(1, 1, 80, 25, buffer);
+#endif
+
+#ifdef DOS_TERM
+ window(1, 1, 80, 25);
+#endif
+
+ clrscr();
+
+ cprintf( " Your Spells Type Success Level" );
+ lines++;
+
+ for (j = 0; j < 52; j++)
+ {
+ if (lines > num_lines - 2)
+ {
+ gotoxy(1, num_lines);
+ cprintf("-more-");
+
+ ki = getch();
+
+ if (ki == ESCAPE)
+ {
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+#endif
+ return (ESCAPE);
+ }
+
+ if (isalpha( ki ))
+ {
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+#endif
+ return (ki);
+ }
+
+ if (ki == 0)
+ ki = getch();
+
+ lines = 0;
+ clrscr();
+ gotoxy(1, 1);
+ anything = 0;
+ }
+
+ const char letter = index_to_letter(j);
+ const int spell = get_spell_by_letter(letter);
+
+ if (spell != SPELL_NO_SPELL)
+ {
+ anything++;
+
+ if (lines > 0)
+ cprintf(EOL);
+
+ lines++;
+
+ cprintf( " %c - %s", letter, spell_title( spell ) );
+ gotoxy(35, wherey());
+
+ already = false;
+
+ for (i = 0; i <= SPTYP_LAST_EXPONENT; i++)
+ {
+ if (spell_typematch( spell, (1 << i) ))
+ {
+ if (already)
+ cprintf( "/" );
+
+ cprintf( spelltype_name( 1 << i ) );
+ already = true;
+ }
+ }
+
+ char sval[16];
+
+ //gotoxy(58, wherey());
+ gotoxy(65, wherey());
+
+ int spell_f = spell_fail( spell );
+
+ cprintf( (spell_f == 100) ? "Useless" :
+ (spell_f > 90) ? "Terrible" :
+ (spell_f > 80) ? "Cruddy" :
+ (spell_f > 70) ? "Bad" :
+ (spell_f > 60) ? "Very Poor" :
+ (spell_f > 50) ? "Poor" :
+ (spell_f > 40) ? "Fair" :
+ (spell_f > 30) ? "Good" :
+ (spell_f > 20) ? "Very Good" :
+ (spell_f > 10) ? "Great" :
+ (spell_f > 0) ? "Excellent"
+ : "Perfect" );
+
+ gotoxy(77, wherey());
+
+ itoa( (int) spell_difficulty( spell ), sval, 10 );
+ cprintf(sval);
+ }
+ } // end of j loop
+
+ if (anything > 0)
+ {
+ ki = getch();
+
+ if (ki >= 'A' && ki <= 'z')
+ {
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+#endif
+ return (ki);
+ }
+
+ if (ki == 0)
+ ki = getch();
+
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+#endif
+
+ return (anything);
+ }
+
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+#endif
+ // was 35
+ ki = getch();
+
+ return (ki);
+} // end list_spells()
+
+int spell_fail(int spell)
+{
+ int chance = 60;
+ int chance2 = 0, armour = 0;
+
+ chance -= 6 * calc_spell_power( spell, false );
+ chance -= (you.intel * 2);
+
+ //chance -= (you.intel - 10) * abs(you.intel - 10);
+ //chance += spell_difficulty(spell) * spell_difficulty(spell) * 3; //spell_difficulty(spell);
+
+ if (you.equip[EQ_BODY_ARMOUR] != -1)
+ {
+
+ int ev_penalty = abs(property( you.inv[you.equip[EQ_BODY_ARMOUR]],
+ PARM_EVASION ));
+
+ // The minus 15 is to make the -1 light armours not so bad
+ armour += (20 * ev_penalty) - 15;
+
+ //jmf: armour skill now reduces failure due to armour
+ //bwr: this was far too good, an armour skill of 5 was
+ // completely negating plate mail. Plate mail should
+ // hardly be completely negated, it should still be
+ // an important consideration for even high level characters.
+ // Truth is, even a much worse penalty than the above can
+ // easily be overcome by gaining spell skills... and a lot
+ // faster than any reasonable rate of bonus here.
+ int lim_str = (you.strength > 30) ? 30 :
+ (you.strength < 10) ? 10 : you.strength;
+
+ armour -= ((you.skills[SK_ARMOUR] * lim_str) / 15);
+
+ int race_arm = get_equip_race( you.inv[you.equip[EQ_BODY_ARMOUR]] );
+ int racial_type = 0;
+
+ if (player_genus(GENPC_DWARVEN))
+ racial_type = ISFLAG_DWARVEN;
+ else if (player_genus(GENPC_ELVEN))
+ racial_type = ISFLAG_ELVEN;
+ else if (you.species == SP_HILL_ORC)
+ racial_type = ISFLAG_ORCISH;
+
+ // Elven armour gives everyone some benefit to spellcasting,
+ // Dwarven armour hinders everyone.
+ switch (race_arm)
+ {
+ case ISFLAG_ELVEN:
+ armour -= 20;
+ break;
+ case ISFLAG_DWARVEN:
+ armour += 10;
+ break;
+ default:
+ break;
+ }
+
+ // Armour of the same racial type reduces penalty.
+ if (racial_type && race_arm == racial_type)
+ armour -= 10;
+
+ if (armour > 0)
+ chance += armour;
+ }
+
+ if (you.equip[EQ_WEAPON] != -1
+ && you.inv[you.equip[EQ_WEAPON]].base_type == OBJ_WEAPONS)
+ {
+ int wpn_penalty = (3 * (property( you.inv[you.equip[EQ_WEAPON]], PWPN_SPEED ) - 12)) / 2;
+
+ if (wpn_penalty > 0)
+ chance += wpn_penalty;
+ }
+
+ if (you.equip[EQ_SHIELD] != -1)
+ {
+ switch (you.inv[you.equip[EQ_SHIELD]].sub_type)
+ {
+ case ARM_BUCKLER:
+ chance += 5;
+ break;
+
+ case ARM_SHIELD:
+ chance += 15;
+ break;
+
+ case ARM_LARGE_SHIELD:
+ // *BCR* Large chars now get a lower penalty for large shields
+ if ((you.species >= SP_OGRE && you.species <= SP_OGRE_MAGE)
+ || player_genus(GENPC_DRACONIAN))
+ {
+ chance += 20;
+ }
+ else
+ chance += 30;
+ break;
+ }
+ }
+
+ switch (spell_difficulty(spell))
+ {
+ case 1: chance += 3; break;
+ case 2: chance += 15; break;
+ case 3: chance += 35; break;
+ case 4: chance += 70; break;
+ case 5: chance += 100; break;
+ case 6: chance += 150; break;
+ case 7: chance += 200; break;
+ case 8: chance += 260; break;
+ case 9: chance += 330; break;
+ case 10: chance += 420; break;
+ case 11: chance += 500; break;
+ case 12: chance += 600; break;
+ default: chance += 750; break;
+ }
+
+ //if (chance < 1 ) chance = 0;
+ if (chance > 100)
+ chance = 100;
+
+ chance2 = chance;
+
+ if (chance < 45)
+ chance2 = 45;
+ if (chance < 42)
+ chance2 = 43;
+ if (chance < 38)
+ chance2 = 41;
+ if (chance < 35)
+ chance2 = 40;
+ if (chance < 32)
+ chance2 = 38;
+ if (chance < 28)
+ chance2 = 36;
+ if (chance < 22)
+ chance2 = 34;
+ if (chance < 16)
+ chance2 = 32;
+ if (chance < 10)
+ chance2 = 30;
+ if (chance < 2)
+ chance2 = 28;
+ if (chance < -7)
+ chance2 = 26;
+ if (chance < -12)
+ chance2 = 24;
+ if (chance < -18)
+ chance2 = 22;
+ if (chance < -24)
+ chance2 = 20;
+ if (chance < -30)
+ chance2 = 18;
+ if (chance < -38)
+ chance2 = 16;
+ if (chance < -46)
+ chance2 = 14;
+ if (chance < -60)
+ chance2 = 12;
+ if (chance < -80)
+ chance2 = 10;
+ if (chance < -100)
+ chance2 = 8;
+ if (chance < -120)
+ chance2 = 6;
+ if (chance < -140)
+ chance2 = 4;
+ if (chance < -160)
+ chance2 = 2;
+ if (chance < -180)
+ chance2 = 0;
+
+ if (you.religion == GOD_VEHUMET
+ && you.duration[DUR_PRAYER]
+ && (!player_under_penance() && you.piety >= 50)
+ && (spell_typematch(spell, SPTYP_CONJURATION)
+ || spell_typematch(spell, SPTYP_SUMMONING)))
+ {
+ chance2 /= 2;
+ }
+
+ if (you.duration[DUR_TRANSFORMATION] > 0)
+ {
+ switch (you.attribute[ATTR_TRANSFORMATION])
+ {
+ case TRAN_BLADE_HANDS:
+ chance2 += 20;
+ break;
+
+ case TRAN_SPIDER:
+ chance2 += 10;
+ break;
+ }
+ }
+
+ return (chance2);
+} // end spell_fail()
+
+
+int calc_spell_power( int spell, bool apply_intel )
+{
+ unsigned int bit;
+ int ndx;
+ int power = (you.skills[SK_SPELLCASTING] / 2) + player_mag_abil(false);
+ int enhanced = 0;
+
+ unsigned int disciplines = spell_type( spell );
+
+ //jmf: evil evil evil -- exclude HOLY bit
+ disciplines &= (~SPTYP_HOLY);
+
+ int skillcount = count_bits( disciplines );
+ if (skillcount)
+ {
+ for (ndx = 0; ndx <= SPTYP_LAST_EXPONENT; ndx++)
+ {
+ bit = 1 << ndx;
+ if ((bit != SPTYP_HOLY) && (disciplines & bit))
+ {
+ int skill = spell_type2skill( bit );
+
+ power += (you.skills[skill] * 2) / skillcount;
+ }
+ }
+ }
+
+ if (apply_intel)
+ power = (power * you.intel) / 10;
+
+ enhanced = spell_enhancement( disciplines );
+
+ if (enhanced > 0)
+ {
+ for (ndx = 0; ndx < enhanced; ndx++)
+ {
+ power *= 15;
+ power /= 10;
+ }
+ }
+ else if (enhanced < 0)
+ {
+ for (ndx = enhanced; ndx < 0; ndx++)
+ power /= 2;
+ }
+
+ power = stepdown_value( power, 50, 50, 150, 200 );
+
+ return (power);
+} // end calc_spell_power()
+
+
+int spell_enhancement( unsigned int typeflags )
+{
+ int enhanced = 0;
+
+ if (typeflags & SPTYP_CONJURATION)
+ enhanced += player_spec_conj();
+
+ if (typeflags & SPTYP_ENCHANTMENT)
+ enhanced += player_spec_ench();
+
+ if (typeflags & SPTYP_SUMMONING)
+ enhanced += player_spec_summ();
+
+ if (typeflags & SPTYP_POISON)
+ enhanced += player_spec_poison();
+
+ if (typeflags & SPTYP_NECROMANCY)
+ enhanced += player_spec_death() - player_spec_holy();
+
+ if (typeflags & SPTYP_FIRE)
+ enhanced += player_spec_fire() - player_spec_cold();
+
+ if (typeflags & SPTYP_ICE)
+ enhanced += player_spec_cold() - player_spec_fire();
+
+ if (typeflags & SPTYP_EARTH)
+ enhanced += player_spec_earth() - player_spec_air();
+
+ if (typeflags & SPTYP_AIR)
+ enhanced += player_spec_air() - player_spec_earth();
+
+ if (you.special_wield == SPWLD_SHADOW)
+ enhanced -= 2;
+
+ // These are used in an exponential way, so we'll limit them a bit. -- bwr
+ if (enhanced > 3)
+ enhanced = 3;
+ else if (enhanced < -3)
+ enhanced = -3;
+
+ return (enhanced);
+} // end spell_enhancement()
+
+// returns false if spell failed, and true otherwise
+bool cast_a_spell(void)
+{
+ char spc = 0;
+ char spc2 = 0;
+ int spellh = 0;
+ unsigned char keyin = 0;
+ char unthing = 0;
+
+ if (!you.spell_no)
+ {
+ mpr("You don't know any spells.");
+ return (false);
+ }
+
+ if (you.berserker)
+ {
+ canned_msg(MSG_TOO_BERSERK);
+ return (false);
+ }
+
+ if (silenced(you.x_pos, you.y_pos))
+ {
+ mpr("You cannot cast spells when silenced!");
+ return (false);
+ }
+
+ // first query {dlb}:
+ for (;;)
+ {
+ //jmf: FIXME: change to reflect range of known spells
+ mpr( "Cast which spell ([?*] list)? ", MSGCH_PROMPT );
+
+ keyin = get_ch();
+
+ if (keyin == '?' || keyin == '*')
+ {
+ unthing = list_spells();
+
+ redraw_screen();
+ if (unthing == 2)
+ return (false);
+
+ if (unthing >= 'a' && unthing <= 'y')
+ {
+ keyin = unthing;
+ break;
+ }
+ else
+ mesclr();
+ }
+ else
+ {
+ break;
+ }
+
+ }
+
+ if (keyin == ESCAPE)
+ return (false);
+
+ spc = (int) keyin;
+
+ if (!isalpha(spc))
+ {
+ mpr("You don't know that spell.");
+ return (false);
+ }
+
+ const int spell = get_spell_by_letter( spc );
+
+ spc2 = letter_to_index(spc);
+
+ if (spell == SPELL_NO_SPELL)
+ {
+ mpr("You don't know that spell.");
+ return (false);
+ }
+
+ if (spell_mana( spell ) > you.magic_points)
+ {
+ mpr("You don't have enough magic to cast that spell.");
+ return (false);
+ }
+
+ if (you.is_undead != US_UNDEAD
+ && (you.hunger_state < HS_HUNGRY
+ || you.hunger <= spell_hunger( spell )))
+ {
+ mpr("You don't have the energy to cast that spell.");
+ return (false);
+ }
+
+ dec_mp( spell_mana(spell) );
+
+ if (!player_energy() && you.is_undead != US_UNDEAD)
+ {
+ spellh = spell_hunger( spell );
+
+ // I wonder if a better algorithm is called for? {dlb}
+ spellh -= you.intel * you.skills[SK_SPELLCASTING];
+
+ if (spellh < 1)
+ spellh = 1;
+ else
+ make_hungry(spellh, true);
+ }
+
+ you.turn_is_over = 1;
+ alert_nearby_monsters();
+
+ if (you.conf)
+ random_uselessness( 2 + random2(7), 0 );
+ else
+ {
+ exercise_spell( spell, true, your_spells( spell ) );
+ naughty( NAUGHTY_SPELLCASTING, 1 + random2(5) );
+ }
+
+ return (true);
+} // end cast_a_spell()
+
+// returns true if spell if spell is successfully cast for purposes of
+// exercising and false otherwise (note: false == less exercise, not none).
+bool your_spells( int spc2, int powc, bool allow_fail )
+{
+ int dem_hor = 0;
+ int dem_hor2 = 0;
+ int total_skill = 0;
+ struct dist spd;
+ struct bolt beam;
+
+ alert_nearby_monsters();
+
+ // Added this so that the passed in powc can have meaning -- bwr
+ if (powc == 0)
+ powc = calc_spell_power( spc2, true );
+
+ if (you.equip[EQ_WEAPON] != -1
+ && item_is_staff( you.inv[you.equip[EQ_WEAPON]] )
+ && item_not_ident( you.inv[you.equip[EQ_WEAPON]], ISFLAG_KNOW_TYPE ))
+ {
+ switch (you.inv[you.equip[EQ_WEAPON]].sub_type)
+ {
+ case STAFF_ENERGY:
+ case STAFF_WIZARDRY:
+ total_skill = you.skills[SK_SPELLCASTING];
+ break;
+ case STAFF_FIRE:
+ if (spell_typematch(spc2, SPTYP_FIRE))
+ total_skill = you.skills[SK_FIRE_MAGIC];
+ else if (spell_typematch(spc2, SPTYP_ICE))
+ total_skill = you.skills[SK_ICE_MAGIC];
+ break;
+ case STAFF_COLD:
+ if (spell_typematch(spc2, SPTYP_ICE))
+ total_skill = you.skills[SK_ICE_MAGIC];
+ else if (spell_typematch(spc2, SPTYP_FIRE))
+ total_skill = you.skills[SK_FIRE_MAGIC];
+ break;
+ case STAFF_AIR:
+ if (spell_typematch(spc2, SPTYP_AIR))
+ total_skill = you.skills[SK_AIR_MAGIC];
+ else if (spell_typematch(spc2, SPTYP_EARTH))
+ total_skill = you.skills[SK_EARTH_MAGIC];
+ break;
+ case STAFF_EARTH:
+ if (spell_typematch(spc2, SPTYP_EARTH))
+ total_skill = you.skills[SK_EARTH_MAGIC];
+ else if (spell_typematch(spc2, SPTYP_AIR))
+ total_skill = you.skills[SK_AIR_MAGIC];
+ break;
+ case STAFF_POISON:
+ if (spell_typematch(spc2, SPTYP_POISON))
+ total_skill = you.skills[SK_POISON_MAGIC];
+ break;
+ case STAFF_DEATH:
+ if (spell_typematch(spc2, SPTYP_NECROMANCY))
+ total_skill = you.skills[SK_NECROMANCY];
+ break;
+ case STAFF_CONJURATION:
+ if (spell_typematch(spc2, SPTYP_CONJURATION))
+ total_skill = you.skills[SK_CONJURATIONS];
+ break;
+ case STAFF_ENCHANTMENT:
+ if (spell_typematch(spc2, SPTYP_ENCHANTMENT))
+ total_skill = you.skills[SK_ENCHANTMENTS];
+ break;
+ case STAFF_SUMMONING:
+ if (spell_typematch(spc2, SPTYP_SUMMONING))
+ total_skill = you.skills[SK_SUMMONINGS];
+ break;
+ }
+
+ if (you.skills[SK_SPELLCASTING] > total_skill)
+ total_skill = you.skills[SK_SPELLCASTING];
+
+ if (random2(100) < total_skill)
+ {
+ char str_pass[ ITEMNAME_SIZE ];
+
+ set_ident_flags( you.inv[you.equip[EQ_WEAPON]], ISFLAG_KNOW_TYPE );
+
+ strcpy(info, "You are wielding ");
+ in_name(you.equip[EQ_WEAPON], DESC_NOCAP_A, str_pass);
+ strcat(info, str_pass);
+ strcat(info, ".");
+ mpr(info);
+
+ more();
+
+ you.wield_change = true;
+ }
+ }
+
+ surge_power(spc2);
+
+ if (allow_fail)
+ {
+ int spfl = random2avg(100, 3);
+
+ if (you.religion != GOD_SIF_MUNA
+ && you.penance[GOD_SIF_MUNA] && one_chance_in(40))
+ {
+ god_speaks(GOD_SIF_MUNA, "You feel a surge of divine spite.");
+
+ // This will cause failure and increase the miscast effect.
+ spfl = -you.penance[GOD_SIF_MUNA];
+
+ // Reduced penenance reduction here because casting spells
+ // is a player controllable act. -- bwr
+ if (one_chance_in(7))
+ dec_penance(1);
+ }
+
+ if (spfl < spell_fail(spc2))
+ {
+ mpr( "You miscast the spell." );
+ flush_input_buffer( FLUSH_ON_FAILURE );
+
+ if (you.religion == GOD_SIF_MUNA
+ && (!player_under_penance()
+ && you.piety >= 100 && random2(150) <= you.piety))
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ return (false);
+ }
+
+ unsigned int sptype = 0;
+
+ do
+ {
+ sptype = 1 << (random2(SPTYP_LAST_EXPONENT+1));
+ } while (!spell_typematch(spc2, sptype));
+
+ // all spell failures give a bit of magical radiation..
+ // failure is a function of power squared multiplied
+ // by how badly you missed the spell. High power
+ // spells can be quite nasty: 9 * 9 * 90 / 500 = 15
+ // points of contamination!
+ int nastiness = spell_mana(spc2) * spell_mana(spc2)
+ * (spell_fail(spc2) - spfl) + 250;
+
+ int cont_points = nastiness / 500;
+ // handle fraction
+ if (random2(500) < (nastiness % 500))
+ cont_points++;
+
+ contaminate_player( cont_points );
+
+ miscast_effect( sptype, spell_mana(spc2), spell_fail(spc2) - spfl, 100 );
+
+ if (you.religion == GOD_XOM && random2(75) < spell_mana(spc2))
+ Xom_acts(coinflip(), spell_mana(spc2), false);
+
+ return (false);
+ }
+ }
+
+ if (you.is_undead && spell_typematch( spc2, SPTYP_HOLY ))
+ {
+ mpr( "You can't use this type of magic!" );
+ return (false); // XXX: still gets trained!
+ }
+
+ // Normally undead can't memorize these spells, so this check is
+ // to catch those in Lich form. As such, we allow the Lich form
+ // to be extended here. -- bwr
+ if (spc2 != SPELL_NECROMUTATION
+ && undead_cannot_memorise( spc2, you.is_undead ))
+ {
+ mpr( "You cannot cast that spell in your current form!" );
+ return (false); // XXX: still gets trained!
+ }
+
+ // Linley says: Condensation Shield needs some disadvantages to keep
+ // it from being a no-brainer... this isn't much, but its a start -- bwr
+ if (you.duration[DUR_CONDENSATION_SHIELD] > 0
+ && spell_typematch( spc2, SPTYP_FIRE ))
+ {
+ mpr( "Your icy shield dissipates!", MSGCH_DURATION );
+ you.duration[DUR_CONDENSATION_SHIELD] = 0;
+ you.redraw_armour_class = 1;
+ }
+
+ if (spc2 == SPELL_SUMMON_HORRIBLE_THINGS
+ || spc2 == SPELL_CALL_IMP
+ || spc2 == SPELL_SUMMON_DEMON
+ || spc2 == SPELL_DEMONIC_HORDE
+ || spc2 == SPELL_SUMMON_GREATER_DEMON || spc2 == SPELL_HELLFIRE)
+ {
+ naughty(NAUGHTY_UNHOLY, 10 + spell_difficulty(spc2));
+ }
+
+ if (spell_typematch( spc2, SPTYP_NECROMANCY ))
+ naughty( NAUGHTY_NECROMANCY, 10 + spell_difficulty(spc2) );
+
+ if (spc2 == SPELL_NECROMUTATION
+ && (you.religion == GOD_ELYVILON
+ || you.religion == GOD_SHINING_ONE
+ || you.religion == GOD_ZIN))
+ {
+ excommunication();
+ }
+
+ if (you.religion == GOD_SIF_MUNA
+ && you.piety < 200 && random2(12) <= spell_difficulty(spc2))
+ {
+ gain_piety(1);
+ }
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "Spell #%d, power=%d", spc2, powc );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ switch (spc2)
+ {
+ case SPELL_IDENTIFY:
+ identify(powc);
+ break;
+
+ case SPELL_TELEPORT_SELF:
+ you_teleport();
+ break;
+
+ case SPELL_CAUSE_FEAR:
+ mass_enchantment(ENCH_FEAR, powc, MHITYOU);
+ break;
+
+ case SPELL_CREATE_NOISE: // unused, the player can shout to do this - bwr
+ if (!silenced(you.x_pos, you.y_pos))
+ {
+ mpr("You hear a voice call your name!");
+ noisy( 25, you.x_pos, you.y_pos );
+ }
+ break;
+
+ case SPELL_REMOVE_CURSE:
+ remove_curse(false);
+ break;
+
+ case SPELL_MAGIC_DART:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+
+ zapping(ZAP_MAGIC_DARTS, powc, beam);
+ break;
+
+ case SPELL_FIREBALL:
+ fireball(powc);
+ break;
+
+ case SPELL_DELAYED_FIREBALL:
+ // This spell has two main advantages over Fireball:
+ //
+ // (1) The release is instantaneous, so monsters will not
+ // get an action before the player... this allows the
+ // player to hit monsters with a double fireball (this
+ // is why we only allow one delayed fireball at a time,
+ // if you want to allow for more, then the release should
+ // take at least some amount of time).
+ //
+ // The casting of this spell still costs a turn. So
+ // casting Delayed Fireball and immediately releasing
+ // the fireball is only slightly different than casting
+ // a regular Fireball (monsters act in the middle instead
+ // of at the end). This is why we allow for the spell
+ // level discount so that Fireball is free with this spell
+ // (so that it only costs 7 levels instead of 13 to have
+ // both).
+ //
+ // (2) When the fireball is released, it is guaranteed to
+ // go off... the spell only fails at this point. This can
+ // be a large advantage for characters who have difficulty
+ // casting Fireball in their standard equipment. However,
+ // the power level for the actual fireball is determined at
+ // release, so if you do swap out your enhancers you'll
+ // get a less powerful ball when its released. -- bwr
+ //
+ if (!you.attribute[ ATTR_DELAYED_FIREBALL ])
+ {
+ // okay, this message is weak but functional -- bwr
+ mpr( "You feel magically charged." );
+ you.attribute[ ATTR_DELAYED_FIREBALL ] = 1;
+ }
+ else
+ {
+ canned_msg( MSG_NOTHING_HAPPENS );
+ }
+ break;
+
+ case SPELL_STRIKING:
+ if (spell_direction( spd, beam ) == -1)
+ return (false);
+
+ zapping( ZAP_STRIKING, powc, beam );
+ break;
+
+ case SPELL_CONJURE_FLAME:
+ conjure_flame(powc);
+ break;
+
+ case SPELL_DIG:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+
+ if (spd.isMe)
+ {
+ canned_msg(MSG_UNTHINKING_ACT);
+ return (false);
+ }
+ zapping(ZAP_DIGGING, powc, beam);
+ break;
+
+ case SPELL_BOLT_OF_FIRE:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_FIRE, powc, beam);
+ break;
+
+ case SPELL_BOLT_OF_COLD:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_COLD, powc, beam);
+ break;
+
+ case SPELL_LIGHTNING_BOLT:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_LIGHTNING, powc, beam);
+ break;
+
+ case SPELL_BOLT_OF_MAGMA:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_MAGMA, powc, beam);
+ break;
+
+ case SPELL_POLYMORPH_OTHER:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+
+ if (spd.isMe)
+ {
+ mpr("Sorry, it doesn't work like that.");
+ return (false);
+ }
+ zapping(ZAP_POLYMORPH_OTHER, powc, beam);
+ break;
+
+ case SPELL_SLOW:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_SLOWING, powc, beam);
+ break;
+
+ case SPELL_HASTE:
+ if (spell_direction(spd, beam, DIR_NONE, TARG_FRIEND) == -1)
+ return (false);
+ zapping(ZAP_HASTING, powc, beam);
+ break;
+
+ case SPELL_PARALYZE:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_PARALYSIS, powc, beam);
+ break;
+
+ case SPELL_CONFUSE:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_CONFUSION, powc, beam);
+ break;
+
+ case SPELL_CONFUSING_TOUCH:
+ cast_confusing_touch(powc);
+ break;
+
+ case SPELL_SURE_BLADE:
+ cast_sure_blade(powc);
+ break;
+
+ case SPELL_INVISIBILITY:
+ if (spell_direction(spd, beam, DIR_NONE, TARG_FRIEND) == -1)
+ return (false);
+ zapping(ZAP_INVISIBILITY, powc, beam);
+ break;
+
+ case SPELL_THROW_FLAME:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_FLAME, powc, beam);
+ break;
+
+ case SPELL_THROW_FROST:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_FROST, powc, beam);
+ break;
+
+ case SPELL_CONTROLLED_BLINK:
+ blink();
+ break;
+
+ case SPELL_FREEZING_CLOUD:
+ cast_big_c(powc, CLOUD_COLD);
+ break;
+
+ case SPELL_MEPHITIC_CLOUD:
+ stinking_cloud(powc);
+ break;
+
+ case SPELL_RING_OF_FLAMES:
+ cast_ring_of_flames(powc);
+ break;
+
+ case SPELL_RESTORE_STRENGTH:
+ restore_stat(STAT_STRENGTH, false);
+ break;
+
+ case SPELL_RESTORE_INTELLIGENCE:
+ restore_stat(STAT_INTELLIGENCE, false);
+ break;
+
+ case SPELL_RESTORE_DEXTERITY:
+ restore_stat(STAT_DEXTERITY, false);
+ break;
+
+ case SPELL_VENOM_BOLT:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_VENOM_BOLT, powc, beam);
+ break;
+
+ case SPELL_OLGREBS_TOXIC_RADIANCE:
+ cast_toxic_radiance();
+ break;
+
+ case SPELL_TELEPORT_OTHER:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+
+ if (spd.isMe)
+ {
+ mpr("Sorry, it doesn't work like that.");
+ return (false);
+ }
+ // teleport creature (I think)
+ zapping(ZAP_TELEPORTATION, powc, beam);
+ break;
+
+ case SPELL_LESSER_HEALING:
+ cast_healing(5);
+ break;
+
+ case SPELL_GREATER_HEALING:
+ cast_healing(25);
+ break;
+
+ case SPELL_CURE_POISON_I: //jmf: `healing' version? group w/ S_C_P_II?
+ cast_cure_poison(powc);
+ break;
+
+ case SPELL_PURIFICATION:
+ purification();
+ break;
+
+ case SPELL_DEATHS_DOOR:
+ cast_deaths_door(powc);
+ break;
+
+ case SPELL_SELECTIVE_AMNESIA:
+ cast_selective_amnesia(false);
+ break; // Sif Muna power calls with true
+
+ case SPELL_MASS_CONFUSION:
+ mass_enchantment(ENCH_CONFUSION, powc, MHITYOU);
+ break;
+
+ case SPELL_SMITING:
+ cast_smiting(powc);
+ break;
+
+ case SPELL_REPEL_UNDEAD:
+ turn_undead(50);
+ break;
+
+ case SPELL_HOLY_WORD:
+ holy_word(50);
+ break;
+
+ case SPELL_DETECT_CURSE:
+ detect_curse(false);
+ break;
+
+ case SPELL_SUMMON_SMALL_MAMMAL:
+ summon_small_mammals(powc); //jmf: hmm, that's definately *plural* ;-)
+ break;
+
+ case SPELL_ABJURATION_I: //jmf: why not group with SPELL_ABJURATION_II?
+ abjuration(powc);
+ break;
+
+ case SPELL_SUMMON_SCORPIONS:
+ summon_scorpions(powc);
+ break;
+
+ case SPELL_LEVITATION:
+ potion_effect( POT_LEVITATION, powc );
+ break;
+
+ case SPELL_BOLT_OF_DRAINING:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_NEGATIVE_ENERGY, powc, beam);
+ break;
+
+ case SPELL_LEHUDIBS_CRYSTAL_SPEAR:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_CRYSTAL_SPEAR, powc, beam);
+ break;
+
+ case SPELL_BOLT_OF_INACCURACY:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_BEAM_OF_ENERGY, powc, beam);
+ break;
+
+ case SPELL_POISONOUS_CLOUD:
+ cast_big_c(powc, CLOUD_POISON);
+ break;
+
+ case SPELL_POISON_ARROW:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+
+ zapping( ZAP_POISON_ARROW, powc, beam );
+ break;
+
+ case SPELL_FIRE_STORM:
+ cast_fire_storm(powc);
+ break;
+
+ case SPELL_DETECT_TRAPS:
+ strcpy(info, "You detect ");
+ strcat(info, (detect_traps(powc) > 0) ? "some traps!" : "nothing.");
+ mpr(info);
+ break;
+
+ case SPELL_BLINK:
+ random_blink(true);
+ break;
+
+ case SPELL_ISKENDERUNS_MYSTIC_BLAST:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+
+ zapping( ZAP_MYSTIC_BLAST, powc, beam );
+ break;
+
+ case SPELL_SWARM:
+ summon_swarm( powc, false, false );
+ break;
+
+ case SPELL_SUMMON_HORRIBLE_THINGS:
+ summon_things(powc);
+ break;
+
+ case SPELL_ENSLAVEMENT:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ if (spd.isMe)
+ {
+ canned_msg(MSG_UNTHINKING_ACT);
+ return (false);
+ }
+ zapping(ZAP_ENSLAVEMENT, powc, beam);
+ break;
+
+ case SPELL_MAGIC_MAPPING:
+ if (you.level_type == LEVEL_LABYRINTH || you.level_type == LEVEL_ABYSS)
+ mpr("You feel momentarily disoriented.");
+ else if (you.level_type == LEVEL_PANDEMONIUM)
+ mpr("Your Earth magic cannot map Pandemonium.");
+ else
+ {
+ mpr( "You feel aware of your surroundings." );
+ powc = stepdown_value( powc, 10, 10, 40, 45 );
+ magic_mapping( 5 + powc, 50 + random2avg( powc * 2, 2 ) );
+ }
+ break;
+
+ case SPELL_HEAL_OTHER:
+ if (spell_direction(spd, beam, DIR_NONE, TARG_FRIEND) == -1)
+ return (false);
+
+ if (spd.isMe)
+ {
+ mpr("Sorry, it doesn't work like that.");
+ return (false);
+ }
+ zapping(ZAP_HEALING, powc, beam);
+ break;
+
+ case SPELL_ANIMATE_DEAD:
+ mpr("You call on the dead to walk for you.");
+ animate_dead(powc + 1, BEH_FRIENDLY, you.pet_target, 1);
+ break;
+
+ case SPELL_PAIN:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ dec_hp(1, false);
+ zapping(ZAP_PAIN, powc, beam);
+ break;
+
+ case SPELL_EXTENSION:
+ extension(powc);
+ break;
+
+ case SPELL_CONTROL_UNDEAD:
+ mass_enchantment(ENCH_CHARM, powc, MHITYOU);
+ break;
+
+ case SPELL_ANIMATE_SKELETON:
+ mpr("You attempt to give life to the dead...");
+ animate_a_corpse(you.x_pos, you.y_pos, BEH_FRIENDLY, you.pet_target,
+ CORPSE_SKELETON);
+ break;
+
+ case SPELL_VAMPIRIC_DRAINING:
+ vampiric_drain(powc);
+ break;
+
+ case SPELL_SUMMON_WRAITHS:
+ summon_undead(powc);
+ break;
+
+ case SPELL_DETECT_ITEMS:
+ detect_items(powc);
+ break;
+
+ case SPELL_BORGNJORS_REVIVIFICATION:
+ cast_revivification(powc);
+ break;
+
+ case SPELL_BURN:
+ burn_freeze(powc, BEAM_FIRE);
+ break;
+
+ case SPELL_FREEZE:
+ burn_freeze(powc, BEAM_COLD);
+ break;
+
+ case SPELL_SUMMON_ELEMENTAL:
+ summon_elemental(powc, 0, 2);
+ break;
+
+ case SPELL_OZOCUBUS_REFRIGERATION:
+ cast_refrigeration(powc);
+ break;
+
+ case SPELL_STICKY_FLAME:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_STICKY_FLAME, powc, beam);
+ break;
+
+ case SPELL_SUMMON_ICE_BEAST:
+ summon_ice_beast_etc(powc, MONS_ICE_BEAST);
+ break;
+
+ case SPELL_OZOCUBUS_ARMOUR:
+ ice_armour(powc, false);
+ break;
+
+ case SPELL_CALL_IMP:
+ if (one_chance_in(3))
+ summon_ice_beast_etc(powc, MONS_WHITE_IMP);
+ else if (one_chance_in(7))
+ summon_ice_beast_etc(powc, MONS_SHADOW_IMP);
+ else
+ summon_ice_beast_etc(powc, MONS_IMP);
+ break;
+
+ case SPELL_REPEL_MISSILES:
+ missile_prot(powc);
+ break;
+
+ case SPELL_BERSERKER_RAGE:
+ cast_berserk();
+ break;
+
+ case SPELL_DISPEL_UNDEAD:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_DISPEL_UNDEAD, powc, beam);
+ break;
+
+ case SPELL_GUARDIAN:
+ summon_ice_beast_etc(powc, MONS_ANGEL);
+ break;
+
+ //jmf: FIXME: SPELL_PESTILENCE?
+
+ case SPELL_THUNDERBOLT:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_LIGHTNING, powc, beam);
+ break;
+
+ case SPELL_FLAME_OF_CLEANSING:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_CLEANSING_FLAME, powc, beam);
+ break;
+
+ //jmf: FIXME: SPELL_SHINING_LIGHT?
+
+ case SPELL_SUMMON_DAEVA:
+ summon_ice_beast_etc(powc, MONS_DAEVA);
+ break;
+
+ case SPELL_ABJURATION_II:
+ abjuration(powc);
+ break;
+
+ // Remember that most holy spells above don't yet use powc!
+
+ case SPELL_TWISTED_RESURRECTION:
+ cast_twisted(powc, BEH_FRIENDLY, you.pet_target);
+ break;
+
+ case SPELL_REGENERATION:
+ cast_regen(powc);
+ break;
+
+ case SPELL_BONE_SHARDS:
+ cast_bone_shards(powc);
+ break;
+
+ case SPELL_BANISHMENT:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_BANISHMENT, powc, beam);
+ break;
+
+ case SPELL_CIGOTUVIS_DEGENERATION:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+
+ if (spd.isMe)
+ {
+ canned_msg(MSG_UNTHINKING_ACT);
+ return (false);
+ }
+ zapping(ZAP_DEGENERATION, powc, beam);
+ break;
+
+ case SPELL_STING:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_STING, powc, beam);
+ break;
+
+ case SPELL_SUBLIMATION_OF_BLOOD:
+ sublimation(powc);
+ break;
+
+ case SPELL_TUKIMAS_DANCE:
+ dancing_weapon(powc, false);
+ break;
+
+ case SPELL_HELLFIRE:
+ // should only be available from:
+ // staff of Dispater & Sceptre of Asmodeus
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+
+ zapping(ZAP_HELLFIRE, powc, beam);
+ break;
+
+ case SPELL_SUMMON_DEMON:
+ mpr("You open a gate to Pandemonium!");
+ summon_ice_beast_etc(powc, summon_any_demon(DEMON_COMMON));
+ break;
+
+ case SPELL_DEMONIC_HORDE:
+ mpr("You open a gate to Pandemonium!");
+ dem_hor2 = 3 + random2(5);
+ for (dem_hor = 0; dem_hor < 4 + dem_hor2; dem_hor++)
+ {
+ summon_ice_beast_etc(powc, summon_any_demon(DEMON_LESSER));
+ }
+ break;
+
+ case SPELL_SUMMON_GREATER_DEMON:
+ mpr("You open a gate to Pandemonium!");
+
+ dem_hor = ((random2(powc) <= 5) ? BEH_HOSTILE : BEH_CHARMED);
+
+ if (dem_hor == BEH_CHARMED)
+ mpr("You don't feel so good about this...");
+
+ create_monster( summon_any_demon(DEMON_GREATER), ENCH_ABJ_V, dem_hor,
+ you.x_pos, you.y_pos, MHITYOU, 250 );
+
+ break;
+
+ case SPELL_CORPSE_ROT:
+ corpse_rot(0);
+ break;
+
+ case SPELL_TUKIMAS_VORPAL_BLADE:
+ if (!brand_weapon(SPWPN_VORPAL, powc))
+ canned_msg(MSG_SPELL_FIZZLES);
+ break;
+
+ case SPELL_FIRE_BRAND:
+ if (!brand_weapon(SPWPN_FLAMING, powc))
+ canned_msg(MSG_SPELL_FIZZLES);
+ break;
+
+ case SPELL_FREEZING_AURA:
+ if (!brand_weapon(SPWPN_FREEZING, powc))
+ canned_msg(MSG_SPELL_FIZZLES);
+ break;
+
+ case SPELL_LETHAL_INFUSION:
+ if (!brand_weapon(SPWPN_DRAINING, powc))
+ canned_msg(MSG_SPELL_FIZZLES);
+ break;
+
+ case SPELL_MAXWELLS_SILVER_HAMMER:
+ if (!brand_weapon(SPWPN_DUMMY_CRUSHING, powc))
+ canned_msg(MSG_SPELL_FIZZLES);
+ break;
+
+ case SPELL_POISON_WEAPON:
+ if (!brand_weapon(SPWPN_VENOM, powc))
+ canned_msg(MSG_SPELL_FIZZLES);
+ break;
+
+ case SPELL_CRUSH:
+ burn_freeze(powc, BEAM_MISSILE);
+ break;
+
+ case SPELL_BOLT_OF_IRON:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_IRON_BOLT, powc, beam);
+ break;
+
+ case SPELL_STONE_ARROW:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_STONE_ARROW, powc, beam);
+ break;
+
+ case SPELL_TOMB_OF_DOROKLOHE:
+ entomb();
+ break;
+
+ case SPELL_STONEMAIL:
+ stone_scales(powc);
+ break;
+
+ case SPELL_SHOCK:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_ELECTRICITY, powc, beam);
+ break;
+
+ case SPELL_SWIFTNESS:
+ cast_swiftness(powc);
+ break;
+
+ case SPELL_FLY:
+ cast_fly(powc);
+ break;
+
+ case SPELL_INSULATION:
+ cast_insulation(powc);
+ break;
+
+ case SPELL_ORB_OF_ELECTROCUTION:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_ORB_OF_ELECTRICITY, powc, beam);
+ break;
+
+ case SPELL_DETECT_CREATURES:
+ detect_creatures(powc);
+ break;
+
+ case SPELL_CURE_POISON_II: // poison magic version of cure poison
+ cast_cure_poison(powc);
+ break;
+
+ case SPELL_CONTROL_TELEPORT:
+ cast_teleport_control(powc);
+ break;
+
+ case SPELL_POISON_AMMUNITION:
+ cast_poison_ammo();
+ break;
+
+ case SPELL_RESIST_POISON:
+ cast_resist_poison(powc);
+ break;
+
+ case SPELL_PROJECTED_NOISE:
+ project_noise();
+ break;
+
+ case SPELL_ALTER_SELF:
+ if (!enough_hp( you.hp_max / 2, true ))
+ {
+ mpr( "Your body is in too poor a condition "
+ "for this spell to function." );
+
+ return (false);
+ }
+
+ mpr("Your body is suffused with transfigurative energy!");
+
+ set_hp( 1 + random2(you.hp), false );
+
+ if (!mutate(100, false))
+ mpr("Odd... you don't feel any different.");
+ break;
+
+ case SPELL_DEBUGGING_RAY:
+ if (spell_direction(spd, beam, DIR_NONE, TARG_ANY) == -1)
+ return (false);
+ zapping(ZAP_DEBUGGING_RAY, powc, beam);
+ break;
+
+ case SPELL_RECALL:
+ recall(0);
+ break;
+
+ case SPELL_PORTAL:
+ portal();
+ break;
+
+ case SPELL_AGONY:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+
+ if (spd.isMe)
+ {
+ canned_msg(MSG_UNTHINKING_ACT);
+ return (false);
+ }
+ zapping(ZAP_AGONY, powc, beam);
+ break;
+
+ case SPELL_SPIDER_FORM:
+ transform(powc, TRAN_SPIDER);
+ break;
+
+ case SPELL_DISRUPT:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+
+ zapping(ZAP_DISRUPTION, powc, beam);
+ break;
+
+ case SPELL_DISINTEGRATE:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+
+ if (spd.isMe)
+ {
+ canned_msg(MSG_UNTHINKING_ACT);
+ return (false);
+ }
+ zapping(ZAP_DISINTEGRATION, powc, beam);
+ break;
+
+ case SPELL_BLADE_HANDS:
+ transform(powc, TRAN_BLADE_HANDS);
+ break;
+
+ case SPELL_STATUE_FORM:
+ transform(powc, TRAN_STATUE);
+ break;
+
+ case SPELL_ICE_FORM:
+ transform(powc, TRAN_ICE_BEAST);
+ break;
+
+ case SPELL_DRAGON_FORM:
+ transform(powc, TRAN_DRAGON);
+ break;
+
+ case SPELL_NECROMUTATION:
+ transform(powc, TRAN_LICH);
+ break;
+
+ case SPELL_DEATH_CHANNEL:
+ cast_death_channel(powc);
+ break;
+
+ case SPELL_SYMBOL_OF_TORMENT:
+ if (you.is_undead || you.mutation[MUT_TORMENT_RESISTANCE])
+ {
+ mpr("To torment others, one must first know what torment means. ");
+ return (false);
+ }
+ torment(you.x_pos, you.y_pos);
+ break;
+
+ case SPELL_DEFLECT_MISSILES:
+ deflection(powc);
+ break;
+
+ case SPELL_ORB_OF_FRAGMENTATION:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_ORB_OF_FRAGMENTATION, powc, beam);
+ break;
+
+ case SPELL_ICE_BOLT:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_ICE_BOLT, powc, beam);
+ break;
+
+ case SPELL_ARC:
+ burn_freeze(powc, BEAM_ELECTRICITY);
+ break;
+
+ case SPELL_AIRSTRIKE:
+ airstrike(powc);
+ break;
+
+ case SPELL_ICE_STORM:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ zapping(ZAP_ICE_STORM, powc, beam);
+ break;
+
+ case SPELL_SHADOW_CREATURES:
+ mpr( "Wisps of shadow whirl around you..." );
+ create_monster( RANDOM_MONSTER, ENCH_ABJ_II, BEH_FRIENDLY,
+ you.x_pos, you.y_pos, you.pet_target, 250 );
+ break;
+
+ //jmf: new spells 19mar2000
+ case SPELL_FLAME_TONGUE:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+
+ if (spd.isMe)
+ {
+ canned_msg(MSG_UNTHINKING_ACT);
+ return (false);
+ }
+ zapping(ZAP_FLAME_TONGUE, powc, beam);
+
+ /*
+ // This is not the place for this sort of power adjustment,
+ // it just makes it harder to balance -- bwr
+ zapping(ZAP_FLAME_TONGUE, 2 + random2(4) + random2(4)
+ + random2(powc) / 25, beam);
+ */
+ break;
+
+ case SPELL_PASSWALL:
+ cast_passwall(powc);
+ break;
+
+ case SPELL_IGNITE_POISON:
+ cast_ignite_poison(powc);
+ break;
+
+ case SPELL_STICKS_TO_SNAKES:
+ cast_sticks_to_snakes(powc);
+ break;
+
+ case SPELL_SUMMON_LARGE_MAMMAL:
+ cast_summon_large_mammal(powc);
+ break;
+
+ case SPELL_SUMMON_DRAGON:
+ cast_summon_dragon(powc);
+ break;
+
+ case SPELL_TAME_BEASTS:
+ cast_tame_beasts(powc);
+ break;
+
+ case SPELL_SLEEP:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+
+ if (spd.isMe)
+ {
+ canned_msg(MSG_UNTHINKING_ACT);
+ return (false);
+ }
+
+ zapping(ZAP_SLEEP, powc, beam);
+ break;
+
+ case SPELL_MASS_SLEEP:
+ cast_mass_sleep(powc);
+ break;
+
+ case SPELL_DETECT_MAGIC:
+ mpr("FIXME: implement!");
+ break;
+
+ case SPELL_DETECT_SECRET_DOORS:
+ cast_detect_secret_doors(powc);
+ break;
+
+ case SPELL_SEE_INVISIBLE:
+ cast_see_invisible(powc);
+ break;
+
+ case SPELL_FORESCRY:
+ cast_forescry(powc);
+ break;
+
+ case SPELL_SUMMON_BUTTERFLIES:
+ cast_summon_butterflies(powc);
+ break;
+
+ case SPELL_WARP_BRAND:
+ if (!brand_weapon(SPWPN_DISTORTION, powc))
+ canned_msg(MSG_SPELL_FIZZLES);
+ break;
+
+ case SPELL_SILENCE:
+ cast_silence(powc);
+ break;
+
+ case SPELL_SHATTER:
+ cast_shatter(powc);
+ break;
+
+ case SPELL_DISPERSAL:
+ cast_dispersal(powc);
+ break;
+
+ case SPELL_DISCHARGE:
+ cast_discharge(powc);
+ break;
+
+ case SPELL_BEND:
+ cast_bend(powc);
+ break;
+
+ case SPELL_BACKLIGHT:
+ if (spell_direction(spd, beam) == -1)
+ return (false);
+ if (spd.isMe)
+ {
+ canned_msg(MSG_UNTHINKING_ACT);
+ return (false);
+ }
+ zapping(ZAP_BACKLIGHT, powc + 10, beam);
+ break;
+
+ case SPELL_INTOXICATE:
+ cast_intoxicate(powc);
+ break;
+
+ case SPELL_GLAMOUR:
+ cast_glamour(powc);
+ break;
+
+ case SPELL_EVAPORATE:
+ cast_evaporate(powc);
+ break;
+
+ case SPELL_FULSOME_DISTILLATION:
+ cast_fulsome_distillation(powc);
+ break;
+
+ case SPELL_FRAGMENTATION:
+ cast_fragmentation(powc);
+ break;
+
+ case SPELL_AIR_WALK:
+ transform(powc, TRAN_AIR);
+ break;
+
+ case SPELL_SANDBLAST:
+ cast_sandblast(powc);
+ break;
+
+ case SPELL_ROTTING:
+ cast_rotting(powc);
+ break;
+
+ case SPELL_SHUGGOTH_SEED:
+ cast_shuggoth_seed(powc);
+ break;
+
+ case SPELL_CONDENSATION_SHIELD:
+ cast_condensation_shield(powc);
+ break;
+
+ case SPELL_SEMI_CONTROLLED_BLINK:
+ cast_semi_controlled_blink(powc); //jmf: powc is ignored
+ break;
+
+ case SPELL_STONESKIN:
+ cast_stoneskin(powc);
+ break;
+
+ case SPELL_SIMULACRUM:
+ simulacrum(powc);
+ break;
+
+ case SPELL_CONJURE_BALL_LIGHTNING:
+ cast_conjure_ball_lightning(powc);
+ break;
+
+ case SPELL_TWIST:
+ cast_twist(powc);
+ break;
+
+ case SPELL_FAR_STRIKE:
+ cast_far_strike(powc);
+ break;
+
+ case SPELL_SWAP:
+ cast_swap(powc);
+ break;
+
+ case SPELL_APPORTATION:
+ cast_apportation(powc);
+ break;
+
+ default:
+ mpr("Invalid spell!");
+ break;
+ } // end switch
+
+ return (true);
+} // end you_spells()
+
+void exercise_spell( int spell, bool spc, bool success )
+{
+ // (!success) reduces skill increase for miscast spells
+ int ndx = 0;
+ int skill;
+ int workout = 0;
+
+ unsigned int disciplines = spell_type(spell);
+
+ //jmf: evil evil evil -- exclude HOLY bit
+ disciplines &= (~SPTYP_HOLY);
+
+ int skillcount = count_bits( disciplines );
+
+ if (!success)
+ skillcount += 4 + random2(10);
+
+ for (ndx = 0; ndx <= SPTYP_LAST_EXPONENT; ndx++)
+ {
+ if (!spell_typematch( spell, 1 << ndx ))
+ continue;
+
+ skill = spell_type2skill( 1 << ndx );
+ workout = (random2(1 + spell_difficulty(spell)) / skillcount);
+
+ if (!one_chance_in(5))
+ workout++; // most recently, this was an automatic add {dlb}
+
+ exercise( skill, workout );
+ }
+
+ /* ******************************************************************
+ Other recent formulae for the above:
+
+ * workout = random2(spell_difficulty(spell_ex)
+ * (10 + (spell_difficulty(spell_ex) * 2 )) / 10 / spellsy + 1);
+
+ * workout = spell_difficulty(spell_ex)
+ * (15 + spell_difficulty(spell_ex)) / 15 / spellsy;
+
+ spellcasting had also been generally exercised at the same time
+ ****************************************************************** */
+
+ if (spc)
+ {
+ exercise(SK_SPELLCASTING, one_chance_in(3) ? 1
+ : random2(1 + random2(spell_difficulty(spell))));
+ }
+
+ //+ (coinflip() ? 1 : 0) + (skillcount ? 1 : 0));
+
+/* ******************************************************************
+ 3.02 was:
+
+ if ( spc && spellsy )
+ exercise(SK_SPELLCASTING, random2(random2(spell_difficulty(spell_ex) + 1) / spellsy)); // + 1);
+ else if ( spc )
+ exercise(SK_SPELLCASTING, random2(random2(spell_difficulty(spell_ex)))); // + 1);
+****************************************************************** */
+
+} // end exercise_spell()
+
+/* This determines how likely it is that more powerful wild magic effects
+ * will occur. Set to 100 for the old probabilities (although the individual
+ * effects have been made much nastier since then).
+ */
+
+bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail,
+ int force_effect, const char *cause )
+{
+/* sp_type is the type of the spell
+ * mag_pow is overall power of the spell or effect (ie its level)
+ * mag_fail is the degree to which you failed
+ * force_effect forces a certain effect to occur. Currently unused.
+ */
+ struct bolt beam;
+ bool failMsg = true;
+
+ int loopj = 0;
+ int spec_effect = 0;
+ int hurted = 0;
+
+ if (sp_type == SPTYP_RANDOM)
+ sp_type = 1 << (random2(12));
+
+ spec_effect = (mag_pow * mag_fail * (10 + mag_pow) / 7
+ * WILD_MAGIC_NASTINESS) / 100;
+
+ if (force_effect == 100
+ && random2(40) > spec_effect && random2(40) > spec_effect)
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ return (false);
+ }
+
+ // setup beam
+ beam.isTracer = false;
+
+ spec_effect = spec_effect / 100;
+
+#if DEBUG_DIAGNOSTICS
+ const int old_fail = spec_effect;
+#endif
+
+ spec_effect = random2(spec_effect);
+
+ if (spec_effect > 3)
+ spec_effect = 3;
+ else if (spec_effect < 0)
+ spec_effect = 0;
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "Sptype: %d, failure1: %d, failure2: %d",
+ sp_type, old_fail, spec_effect );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ if (force_effect != 100)
+ spec_effect = force_effect;
+
+ switch (sp_type)
+ {
+ case SPTYP_CONJURATION:
+ switch (spec_effect)
+ {
+ case 0: // just a harmless message
+ switch (random2(10))
+ {
+ case 0:
+ snprintf( info, INFO_SIZE, "Sparks fly from your %s!",
+ your_hand(true) );
+ mpr(info);
+ break;
+
+ case 1:
+ mpr("The air around you crackles with energy!");
+ break;
+
+ case 2:
+ snprintf( info, INFO_SIZE, "Wisps of smoke drift from your %s.",
+ your_hand(true));
+ mpr(info);
+ break;
+ case 3:
+ mpr("You feel a strange surge of energy!");
+ break;
+ case 4:
+ mpr("You are momentarily dazzled by a flash of light!");
+ break;
+ case 5:
+ mpr("Strange energies run through your body.");
+ break;
+ case 6:
+ mpr("Your skin tingles.");
+ break;
+ case 7:
+ mpr("Your skin glows momentarily.");
+ break;
+ case 8:
+ canned_msg(MSG_NOTHING_HAPPENS);
+ break;
+ case 9:
+ // josh declares mummies cannot smell {dlb}
+ if (you.species != SP_MUMMY)
+ mpr("You smell something strange.");
+ else
+ mpr("Your bandages flutter.");
+ }
+ break;
+
+ case 1: // a bit less harmless stuff
+ switch (random2(2))
+ {
+ case 0:
+ snprintf( info, INFO_SIZE, "Smoke pours from your %s!",
+ your_hand(true));
+ mpr(info);
+
+ big_cloud( CLOUD_GREY_SMOKE, you.x_pos, you.y_pos, 20,
+ 7 + random2(7) );
+ break;
+ case 1:
+ mpr("A wave of violent energy washes through your body!");
+ ouch(6 + random2avg(7, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ break;
+ }
+ break;
+
+ case 2: // rather less harmless stuff
+ switch (random2(2))
+ {
+ case 0:
+ mpr("Energy rips through your body!");
+ ouch(9 + random2avg(17, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ break;
+ case 1:
+ mpr("You are caught in a violent explosion!");
+ beam.type = SYM_BURST;
+ beam.damage = dice_def( 3, 12 );
+ beam.flavour = BEAM_MISSILE; // unsure about this
+ // BEAM_EXPLOSION instead? {dlb}
+
+ beam.target_x = you.x_pos;
+ beam.target_y = you.y_pos;
+ strcpy(beam.beam_name, "explosion");
+ beam.colour = random_colour();
+ beam.beam_source = NON_MONSTER;
+ beam.thrower = (cause) ? KILL_MISC : KILL_YOU;
+ beam.aux_source = cause;
+ beam.ex_size = 1;
+
+ explosion(beam);
+ break;
+ }
+ break;
+
+ case 3: // considerably less harmless stuff
+ switch (random2(2))
+ {
+ case 0:
+ mpr("You are blasted with magical energy!");
+ ouch(12 + random2avg(29, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ break;
+ case 1:
+ mpr("There is a sudden explosion of magical energy!");
+ beam.type = SYM_BURST;
+ beam.damage = dice_def( 3, 20 );
+ beam.flavour = BEAM_MISSILE; // unsure about this
+ // BEAM_EXPLOSION instead? {dlb}
+ beam.target_x = you.x_pos;
+ beam.target_y = you.y_pos;
+ strcpy(beam.beam_name, "explosion");
+ beam.colour = random_colour();
+ beam.beam_source = NON_MONSTER;
+ beam.thrower = (cause) ? KILL_MISC : KILL_YOU;
+ beam.aux_source = cause;
+ beam.ex_size = coinflip()?1:2;
+
+ explosion(beam);
+ break;
+ }
+ break;
+ }
+ break; // end conjuration
+
+ case SPTYP_ENCHANTMENT:
+ switch (spec_effect)
+ {
+ case 0: // harmless messages only
+ switch (random2(10))
+ {
+ case 0:
+ snprintf( info, INFO_SIZE, "Your %s glow momentarily.",
+ your_hand(true) );
+ mpr(info);
+ break;
+ case 1:
+ mpr("The air around you crackles with energy!");
+ break;
+ case 2:
+ mpr("Multicolored lights dance before your eyes!");
+ break;
+ case 3:
+ mpr("You feel a strange surge of energy!");
+ break;
+ case 4:
+ mpr("Waves of light ripple over your body.");
+ break;
+ case 5:
+ mpr("Strange energies run through your body.");
+ break;
+ case 6:
+ mpr("Your skin tingles.");
+ break;
+ case 7:
+ mpr("Your skin glows momentarily.");
+ break;
+ case 8:
+ canned_msg(MSG_NOTHING_HAPPENS);
+ break;
+ case 9:
+ if (!silenced(you.x_pos, you.y_pos))
+ mpr("You hear something strange.");
+ else if (you.attribute[ATTR_TRANSFORMATION] != TRAN_AIR)
+ mpr("Your skull vibrates slightly.");
+ else
+ canned_msg(MSG_NOTHING_HAPPENS);
+ break;
+ }
+ break;
+
+ case 1: // slightly annoying
+ switch (random2(2))
+ {
+ case 0:
+ potion_effect(POT_LEVITATION, 20);
+ break;
+ case 1:
+ random_uselessness(2 + random2(7), 0);
+ break;
+ }
+ break;
+
+ case 2: // much more annoying
+ switch (random2(7))
+ {
+ case 0:
+ case 1:
+ case 2:
+ mpr("You sense a malignant aura.");
+ curse_an_item(0, 0);
+ break;
+ case 3:
+ case 4:
+ case 5:
+ potion_effect(POT_SLOWING, 10);
+ break;
+ case 6:
+ potion_effect(POT_BERSERK_RAGE, 10);
+ break;
+ }
+ break;
+
+ case 3: // potentially lethal
+ switch (random2(4))
+ {
+ case 0:
+ do
+ {
+ curse_an_item(0, 0);
+ loopj = random2(3);
+ }
+ while (loopj != 0);
+
+ mpr("You sense an overwhelmingly malignant aura!");
+ break;
+ case 1:
+ potion_effect(POT_PARALYSIS, 10);
+ break;
+ case 2:
+ potion_effect(POT_CONFUSION, 10);
+ break;
+ case 3:
+ mpr("You feel saturated with unharnessed energies!");
+ you.magic_contamination += random2avg(19,3);
+ break;
+ }
+ break;
+ }
+ break; // end enchantments
+
+ case SPTYP_TRANSLOCATION:
+ switch (spec_effect)
+ {
+ case 0: // harmless messages only
+ switch (random2(10))
+ {
+ case 0:
+ mpr("Space warps around you.");
+ break;
+ case 1:
+ mpr("The air around you crackles with energy!");
+ break;
+ case 2:
+ mpr("You feel a wrenching sensation.");
+ break;
+ case 3:
+ mpr("You feel a strange surge of energy!");
+ break;
+ case 4:
+ mpr("You spin around.");
+ break;
+ case 5:
+ mpr("Strange energies run through your body.");
+ break;
+ case 6:
+ mpr("Your skin tingles.");
+ break;
+ case 7:
+ mpr("The world appears momentarily distorted!");
+ break;
+ case 8:
+ canned_msg(MSG_NOTHING_HAPPENS);
+ break;
+ case 9:
+ mpr("You feel uncomfortable.");
+ break;
+ }
+ break;
+
+ case 1: // mostly harmless
+ switch (random2(6))
+ {
+ case 0:
+ case 1:
+ case 2:
+ mpr("You are caught in a localised field of spatial distortion.");
+ ouch(4 + random2avg(9, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ break;
+ case 3:
+ case 4:
+ mpr("Space bends around you!");
+ random_blink(false);
+ ouch(4 + random2avg(7, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ break;
+ case 5:
+ mpr("Space twists in upon itself!");
+ create_monster( MONS_SPATIAL_VORTEX, ENCH_ABJ_III, BEH_HOSTILE,
+ you.x_pos, you.y_pos, MHITYOU, 250 );
+ break;
+ }
+ break;
+
+ case 2: // less harmless
+ switch (random2(7))
+ {
+ case 0:
+ case 1:
+ case 2:
+ mpr("You are caught in a strong localised spatial distortion.");
+ ouch(9 + random2avg(23, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ break;
+ case 3:
+ case 4:
+ mpr("Space warps around you!");
+
+ if (one_chance_in(3))
+ you_teleport2( true );
+ else
+ random_blink( false );
+
+ ouch(5 + random2avg(9, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ potion_effect(POT_CONFUSION, 40);
+ break;
+ case 5:
+ mpr("Space twists in upon itself!");
+
+ for (loopj = 0; loopj < 2 + random2(3); loopj++)
+ {
+ create_monster( MONS_SPATIAL_VORTEX, ENCH_ABJ_III,
+ BEH_HOSTILE, you.x_pos, you.y_pos,
+ MHITYOU, 250 );
+ }
+ break;
+ case 6:
+ mpr("You are cast into the Abyss!");
+ more();
+ banished(DNGN_ENTER_ABYSS); // sends you to the abyss
+ break;
+ }
+ break;
+
+ case 3: // much less harmless
+
+ switch (random2(4))
+ {
+ case 0:
+ mpr("You are caught in an extremely strong localised spatial distortion!");
+ ouch(15 + random2avg(29, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ break;
+ case 1:
+ mpr("Space warps crazily around you!");
+ you_teleport2( true );
+
+ ouch(9 + random2avg(17, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ potion_effect(POT_CONFUSION, 60);
+ break;
+ case 2:
+ mpr("You are cast into the Abyss!");
+ more();
+ banished(DNGN_ENTER_ABYSS); // sends you to the abyss
+ break;
+ case 3:
+ mpr("You feel saturated with unharnessed energies!");
+ you.magic_contamination += random2avg(19,3);
+ break;
+ }
+ break;
+ }
+ break; // end translocations
+
+ case SPTYP_SUMMONING:
+ switch (spec_effect)
+ {
+ case 0: // harmless messages only
+ switch (random2(10))
+ {
+ case 0:
+ mpr("Shadowy shapes form in the air around you, then vanish.");
+ break;
+ case 1:
+ if (!silenced(you.x_pos, you.y_pos))
+ mpr("You hear strange voices.");
+ else
+ mpr("You feel momentarily dizzy.");
+ break;
+ case 2:
+ mpr("Your head hurts.");
+ break;
+ case 3:
+ mpr("You feel a strange surge of energy!");
+ break;
+ case 4:
+ mpr("Your brain hurts!");
+ break;
+ case 5:
+ mpr("Strange energies run through your body.");
+ break;
+ case 6:
+ mpr("The world appears momentarily distorted.");
+ break;
+ case 7:
+ mpr("Space warps around you.");
+ break;
+ case 8:
+ canned_msg(MSG_NOTHING_HAPPENS);
+ break;
+ case 9:
+ mpr("Distant voices call out to you!");
+ break;
+ }
+ break;
+
+ case 1: // a little bad
+ switch (random2(6))
+ {
+ case 0: // identical to translocation
+ case 1:
+ case 2:
+ mpr("You are caught in a localised spatial distortion.");
+ ouch(5 + random2avg(9, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ break;
+
+ case 3:
+ mpr("Space twists in upon itself!");
+ create_monster( MONS_SPATIAL_VORTEX, ENCH_ABJ_III, BEH_HOSTILE,
+ you.x_pos, you.y_pos, MHITYOU, 250 );
+ break;
+
+ case 4:
+ case 5:
+ if (create_monster( summon_any_demon(DEMON_LESSER), ENCH_ABJ_V,
+ BEH_HOSTILE, you.x_pos, you.y_pos,
+ MHITYOU, 250 ) != -1)
+ {
+ mpr("Something appears in a flash of light!");
+ }
+ break;
+ }
+
+ case 2: // more bad
+ switch (random2(6))
+ {
+ case 0:
+ mpr("Space twists in upon itself!");
+
+ for (loopj = 0; loopj < 2 + random2(3); loopj++)
+ {
+ create_monster( MONS_SPATIAL_VORTEX, ENCH_ABJ_III,
+ BEH_HOSTILE, you.x_pos, you.y_pos,
+ MHITYOU, 250 );
+ }
+ break;
+
+ case 1:
+ case 2:
+ if (create_monster( summon_any_demon(DEMON_COMMON), ENCH_ABJ_V,
+ BEH_HOSTILE, you.x_pos, you.y_pos,
+ MHITYOU, 250) != -1)
+ {
+ mpr("Something forms out of thin air!");
+ }
+ break;
+
+ case 3:
+ case 4:
+ case 5:
+ mpr("A chorus of chattering voices calls out to you!");
+ create_monster( summon_any_demon(DEMON_LESSER), ENCH_ABJ_V,
+ BEH_HOSTILE, you.x_pos, you.y_pos,
+ MHITYOU, 250 );
+
+ create_monster( summon_any_demon(DEMON_LESSER), ENCH_ABJ_V,
+ BEH_HOSTILE, you.x_pos, you.y_pos,
+ MHITYOU, 250 );
+
+ if (coinflip())
+ {
+ create_monster( summon_any_demon(DEMON_LESSER), ENCH_ABJ_V,
+ BEH_HOSTILE, you.x_pos, you.y_pos,
+ MHITYOU, 250 );
+ }
+
+ if (coinflip())
+ {
+ create_monster( summon_any_demon(DEMON_LESSER), ENCH_ABJ_V,
+ BEH_HOSTILE, you.x_pos, you.y_pos,
+ MHITYOU, 250 );
+ }
+ break;
+ }
+ break;
+
+ case 3: // more bad
+ switch (random2(4))
+ {
+ case 0:
+ if (create_monster( MONS_ABOMINATION_SMALL, 0, BEH_HOSTILE,
+ you.x_pos, you.y_pos, MHITYOU, 250 ) != -1)
+ {
+ mpr("Something forms out of thin air.");
+ }
+ break;
+
+ case 1:
+ if (create_monster( summon_any_demon(DEMON_GREATER), 0,
+ BEH_HOSTILE, you.x_pos, you.y_pos,
+ MHITYOU, 250 ) != -1)
+ {
+ mpr("You sense a hostile presence.");
+ }
+ break;
+
+ case 2:
+ mpr("Something turns its malign attention towards you...");
+
+ create_monster( summon_any_demon(DEMON_COMMON), ENCH_ABJ_III,
+ BEH_HOSTILE, you.x_pos, you.y_pos,
+ MHITYOU, 250 );
+
+ create_monster( summon_any_demon(DEMON_COMMON), ENCH_ABJ_III,
+ BEH_HOSTILE, you.x_pos, you.y_pos,
+ MHITYOU, 250);
+
+ if (coinflip())
+ {
+ create_monster(summon_any_demon(DEMON_COMMON), ENCH_ABJ_III,
+ BEH_HOSTILE, you.x_pos, you.y_pos,
+ MHITYOU, 250);
+ }
+ break;
+
+ case 3:
+ mpr("You are cast into the Abyss!");
+ banished(DNGN_ENTER_ABYSS);
+ break;
+ }
+ break;
+ } // end Summonings
+ break;
+
+ case SPTYP_DIVINATION:
+ switch (spec_effect)
+ {
+ case 0: // just a harmless message
+ switch (random2(10))
+ {
+ case 0:
+ mpr("Weird images run through your mind.");
+ break;
+ case 1:
+ if (!silenced(you.x_pos, you.y_pos))
+ mpr("You hear strange voices.");
+ else
+ mpr("Your nose twitches.");
+ break;
+ case 2:
+ mpr("Your head hurts.");
+ break;
+ case 3:
+ mpr("You feel a strange surge of energy!");
+ break;
+ case 4:
+ mpr("Your brain hurts!");
+ break;
+ case 5:
+ mpr("Strange energies run through your body.");
+ break;
+ case 6:
+ mpr("Everything looks hazy for a moment.");
+ break;
+ case 7:
+ mpr("You seem to have forgotten something, but you can't remember what it was!");
+ break;
+ case 8:
+ canned_msg(MSG_NOTHING_HAPPENS);
+ break;
+ case 9:
+ mpr("You feel uncomfortable.");
+ break;
+ }
+ break;
+
+ case 1: // more annoying things
+ switch (random2(2))
+ {
+ case 0:
+ mpr("You feel slightly disoriented.");
+ forget_map(10 + random2(10));
+ break;
+ case 1:
+ potion_effect(POT_CONFUSION, 10);
+ break;
+ }
+ break;
+
+ case 2: // even more annoying things
+ switch (random2(2))
+ {
+ case 0:
+ if (you.is_undead)
+ mpr("You suddenly recall your previous life!");
+ else if (lose_stat(STAT_INTELLIGENCE, 1 + random2(3)))
+ mpr("You have damaged your brain!");
+ else
+ mpr("You have a terrible headache.");
+ break;
+ case 1:
+ mpr("You feel lost.");
+ forget_map(40 + random2(40));
+ break;
+ }
+
+ potion_effect(POT_CONFUSION, 1); // common to all cases here {dlb}
+ break;
+
+ case 3: // nasty
+ switch (random2(3))
+ {
+ case 0:
+ mpr( forget_spell() ? "You have forgotten a spell!"
+ : "You get a splitting headache." );
+ break;
+ case 1:
+ mpr("You feel completely lost.");
+ forget_map(100);
+ break;
+ case 2:
+ if (you.is_undead)
+ mpr("You suddenly recall your previous life.");
+ else if (lose_stat(STAT_INTELLIGENCE, 3 + random2(3)))
+ mpr("You have damaged your brain!");
+ else
+ mpr("You have a terrible headache.");
+ break;
+ }
+
+ potion_effect(POT_CONFUSION, 1); // common to all cases here {dlb}
+ break;
+ }
+ break; // end divinations
+
+ case SPTYP_NECROMANCY:
+ if (you.religion == GOD_KIKUBAAQUDGHA
+ && (!player_under_penance() && you.piety >= 50
+ && random2(150) <= you.piety))
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ break;
+ }
+
+ switch (spec_effect)
+ {
+ case 0:
+ switch (random2(10))
+ {
+ case 0:
+ // mummies cannot smell {dlb}
+ if (you.species != SP_MUMMY)
+ mpr("You smell decay.");
+ break;
+ case 1:
+ if (!silenced(you.x_pos, you.y_pos))
+ mpr("You hear strange and distant voices.");
+ else
+ mpr("You feel homesick.");
+ break;
+ case 2:
+ mpr("Pain shoots through your body.");
+ break;
+ case 3:
+ mpr("Your bones ache.");
+ break;
+ case 4:
+ mpr("The world around you seems to dim momentarily.");
+ break;
+ case 5:
+ mpr("Strange energies run through your body.");
+ break;
+ case 6:
+ mpr("You shiver with cold.");
+ break;
+ case 7:
+ mpr("You sense a malignant aura.");
+ break;
+ case 8:
+ canned_msg(MSG_NOTHING_HAPPENS);
+ break;
+ case 9:
+ mpr("You feel very uncomfortable.");
+ break;
+ }
+ break;
+
+ case 1: // a bit nasty
+ switch (random2(3))
+ {
+ case 0:
+ if (you.is_undead)
+ {
+ mpr("You feel weird for a moment.");
+ break;
+ }
+ mpr("Pain shoots through your body!");
+ ouch(5 + random2avg(15, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ break;
+ case 1:
+ mpr("You feel horribly lethargic.");
+ potion_effect(POT_SLOWING, 15);
+ break;
+ case 2:
+ // josh declares mummies cannot smell {dlb}
+ if (you.species != SP_MUMMY)
+ {
+ mpr("You smell decay."); // identical to a harmless message
+ you.rotting++;
+ }
+ break;
+ }
+ break;
+
+ case 2: // much nastier
+ switch (random2(3))
+ {
+ case 0:
+ mpr("Flickering shadows surround you.");
+
+ create_monster( MONS_SHADOW, ENCH_ABJ_II, BEH_HOSTILE,
+ you.x_pos, you.y_pos, MHITYOU, 250 );
+
+ if (coinflip())
+ {
+ create_monster( MONS_SHADOW, ENCH_ABJ_II, BEH_HOSTILE,
+ you.x_pos, you.y_pos, MHITYOU, 250 );
+ }
+
+ if (coinflip())
+ {
+ create_monster( MONS_SHADOW, ENCH_ABJ_II, BEH_HOSTILE,
+ you.x_pos, you.y_pos, MHITYOU, 250 );
+ }
+ break;
+
+ case 1:
+ if (!player_prot_life() && one_chance_in(3))
+ {
+ drain_exp();
+ break;
+ } // otherwise it just flows through...
+
+ case 2:
+ if (you.is_undead)
+ {
+ mpr("You feel weird for a moment.");
+ break;
+ }
+ mpr("You convulse helplessly as pain tears through your body!");
+ ouch(15 + random2avg(23, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ break;
+ }
+ break;
+
+ case 3: // even nastier
+ switch (random2(6))
+ {
+ case 0:
+ if (you.is_undead)
+ {
+ mpr("Something just walked over your grave. No, really!");
+ break;
+ }
+ mpr("Your body is wracked with pain!");
+
+ dec_hp((you.hp / 2) - 1, false);
+ break;
+
+ case 1:
+ mpr("You are engulfed in negative energy!");
+
+ if (!player_prot_life())
+ {
+ drain_exp();
+ break;
+ } // otherwise it just flows through...
+
+ case 2:
+ lose_stat(STAT_RANDOM, 1 + random2avg(7, 2));
+ break;
+
+ case 3:
+ if (you.is_undead)
+ {
+ mpr("You feel terrible.");
+ break;
+ }
+
+ rot_player( random2avg(7, 2) + 1 );
+ break;
+
+ case 4:
+ if (create_monster( MONS_SOUL_EATER, ENCH_ABJ_IV, BEH_HOSTILE,
+ you.x_pos, you.y_pos, MHITYOU, 250) != -1)
+ {
+ mpr("Something reaches out for you...");
+ }
+ break;
+
+ case 5:
+ if (create_monster( MONS_REAPER, ENCH_ABJ_IV, BEH_HOSTILE,
+ you.x_pos, you.y_pos, MHITYOU, 250) != -1)
+ {
+ mpr("Death has come for you...");
+ }
+ break;
+ }
+ break;
+ }
+ break; // end necromancy
+
+ case SPTYP_TRANSMIGRATION:
+ switch (spec_effect)
+ {
+ case 0: // just a harmless message
+ switch (random2(10))
+ {
+ case 0:
+ snprintf( info, INFO_SIZE, "Your %s glow momentarily.",
+ your_hand(true));
+ mpr(info);
+ break;
+ case 1:
+ mpr("The air around you crackles with energy!");
+ break;
+ case 2:
+ mpr("Multicolored lights dance before your eyes!");
+ break;
+ case 3:
+ mpr("You feel a strange surge of energy!");
+ break;
+ case 4:
+ mpr("Waves of light ripple over your body.");
+ break;
+ case 5:
+ mpr("Strange energies run through your body.");
+ break;
+ case 6:
+ mpr("Your skin tingles.");
+ break;
+ case 7:
+ mpr("Your skin glows momentarily.");
+ break;
+ case 8:
+ canned_msg(MSG_NOTHING_HAPPENS);
+ break;
+ case 9:
+ // mummies cannot smell
+ if (you.species != SP_MUMMY)
+ mpr("You smell something strange.");
+ break;
+ }
+ break;
+
+ case 1: // slightly annoying
+ switch (random2(2))
+ {
+ case 0:
+ mpr("Your body is twisted painfully.");
+ ouch(1 + random2avg(11, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ break;
+ case 1:
+ random_uselessness(2 + random2(7), 0);
+ break;
+ }
+ break;
+
+ case 2: // much more annoying
+ switch (random2(4))
+ {
+ case 0:
+ mpr("Your body is twisted very painfully!");
+ ouch(3 + random2avg(23, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ break;
+ case 1:
+ mpr("You feel saturated with unharnessed energies!");
+ you.magic_contamination += random2avg(19,3);
+ break;
+ case 2:
+ potion_effect(POT_PARALYSIS, 10);
+ break;
+ case 3:
+ potion_effect(POT_CONFUSION, 10);
+ break;
+ }
+ break;
+
+ case 3: // even nastier
+
+ switch (random2(3))
+ {
+ case 0:
+ mpr("Your body is flooded with distortional energies!");
+ you.magic_contamination += random2avg(35, 3);
+
+ ouch(3 + random2avg(18, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ break;
+
+ case 1:
+ mpr("You feel very strange.");
+ delete_mutation(100);
+ ouch(5 + random2avg(23, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ break;
+
+ case 2:
+ mpr("Your body is distorted in a weirdly horrible way!");
+ failMsg = !give_bad_mutation();
+ if (coinflip())
+ give_bad_mutation(false, failMsg);
+
+ ouch(5 + random2avg(23, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ break;
+ }
+ break;
+ }
+ break; // end transmigrations
+
+ case SPTYP_FIRE:
+ switch (spec_effect)
+ {
+ case 0: // just a harmless message
+ switch (random2(10))
+ {
+ case 0:
+ snprintf( info, INFO_SIZE, "Sparks fly from your %s!",
+ your_hand(true));
+ mpr(info);
+ break;
+ case 1:
+ mpr("The air around you burns with energy!");
+ break;
+ case 2:
+ snprintf( info, INFO_SIZE, "Wisps of smoke drift from your %s.",
+ your_hand(true));
+ mpr(info);
+ break;
+ case 3:
+ mpr("You feel a strange surge of energy!");
+ break;
+ case 4:
+ // mummies cannot smell
+ if (you.species != SP_MUMMY)
+ mpr("You smell smoke.");
+ break;
+ case 5:
+ mpr("Heat runs through your body.");
+ break;
+ case 6:
+ mpr("You feel uncomfortably hot.");
+ break;
+ case 7:
+ mpr("Lukewarm flames ripple over your body.");
+ break;
+ case 8:
+ canned_msg(MSG_NOTHING_HAPPENS);
+ break;
+ case 9:
+ if (!silenced(you.x_pos, you.y_pos))
+ mpr("You hear a sizzling sound.");
+ else
+ mpr("You feel like you have heartburn.");
+ break;
+ }
+ break;
+
+ case 1: // a bit less harmless stuff
+ switch (random2(2))
+ {
+ case 0:
+ snprintf( info, INFO_SIZE, "Smoke pours from your %s!",
+ your_hand(true) );
+ mpr(info);
+
+ big_cloud( CLOUD_GREY_SMOKE + random2(3),
+ you.x_pos, you.y_pos, 20, 7 + random2(7) );
+ break;
+
+ case 1:
+ mpr("Flames sear your flesh.");
+ scrolls_burn(3, OBJ_SCROLLS);
+
+ if (player_res_fire() < 0)
+ {
+ ouch(2 + random2avg(13, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ }
+ break;
+ }
+ break;
+
+ case 2: // rather less harmless stuff
+ switch (random2(2))
+ {
+ case 0:
+ mpr("You are blasted with fire.");
+
+ ouch( check_your_resists( 5 + random2avg(29, 2), 2 ), 0,
+ KILLED_BY_WILD_MAGIC, cause );
+
+ scrolls_burn( 5, OBJ_SCROLLS );
+ break;
+
+ case 1:
+ mpr("You are caught a fiery explosion!");
+
+ beam.type = SYM_BURST;
+ beam.damage = dice_def( 3, 14 );
+ beam.flavour = BEAM_FIRE;
+ beam.target_x = you.x_pos;
+ beam.target_y = you.y_pos;
+ strcpy(beam.beam_name, "explosion");
+ beam.colour = RED;
+ beam.beam_source = NON_MONSTER;
+ beam.thrower = (cause) ? KILL_MISC : KILL_YOU;
+ beam.aux_source = cause;
+ beam.ex_size = 1;
+
+ explosion(beam);
+ break;
+ }
+ break;
+
+ case 3: // considerably less harmless stuff
+ switch (random2(3))
+ {
+ case 0:
+ mpr("You are blasted with searing flames!");
+
+ ouch( check_your_resists( 9 + random2avg(33, 2), 2 ), 0,
+ KILLED_BY_WILD_MAGIC, cause );
+
+ scrolls_burn( 10, OBJ_SCROLLS );
+ break;
+ case 1:
+ mpr("There is a sudden and violent explosion of flames!");
+
+ beam.type = SYM_BURST;
+ beam.damage = dice_def( 3, 20 );
+ beam.flavour = BEAM_FIRE;
+ beam.target_x = you.x_pos;
+ beam.target_y = you.y_pos;
+ strcpy( beam.beam_name, "fireball" );
+ beam.colour = RED;
+ beam.beam_source = NON_MONSTER;
+ beam.thrower = (cause) ? KILL_MISC : KILL_YOU;
+ beam.aux_source = cause;
+ beam.ex_size = coinflip()?1:2;
+
+ explosion(beam);
+ break;
+
+ case 2:
+ mpr("You are covered in liquid fire!");
+ you.duration[DUR_LIQUID_FLAMES] += random2avg(7, 3) + 1;
+ break;
+ }
+ break;
+ }
+ break; // end fire
+
+ case SPTYP_ICE:
+ switch (spec_effect)
+ {
+ case 0: // just a harmless message
+ switch (random2(10))
+ {
+ case 0:
+ mpr("You shiver with cold.");
+ break;
+ case 1:
+ mpr("A chill runs through your body.");
+ break;
+ case 2:
+ snprintf( info, INFO_SIZE, "Wisps of condensation drift from your %s.",
+ your_hand(true));
+ mpr(info);
+ break;
+ case 3:
+ mpr("You feel a strange surge of energy!");
+ break;
+ case 4:
+ snprintf( info, INFO_SIZE,"Your %s feel numb with cold.",
+ your_hand(true));
+ mpr(info);
+ break;
+ case 5:
+ mpr("A chill runs through your body.");
+ break;
+ case 6:
+ mpr("You feel uncomfortably cold.");
+ break;
+ case 7:
+ mpr("Frost covers your body.");
+ break;
+ case 8:
+ canned_msg(MSG_NOTHING_HAPPENS);
+ break;
+ case 9:
+ if (!silenced(you.x_pos, you.y_pos))
+ mpr("You hear a crackling sound.");
+ else
+ mpr("A snowflake lands on your nose.");
+ break;
+ }
+ break;
+
+ case 1: // a bit less harmless stuff
+ switch (random2(2))
+ {
+ case 0:
+ mpr("You feel extremely cold.");
+ break;
+ case 1:
+ mpr("You are covered in a thin layer of ice");
+ scrolls_burn(2, OBJ_POTIONS);
+
+ if (player_res_cold() < 0)
+ ouch(4 + random2avg(5, 2), 0, KILLED_BY_WILD_MAGIC, cause);
+ break;
+ }
+ break;
+
+ case 2: // rather less harmless stuff
+ switch (random2(2))
+ {
+ case 0:
+ mpr("Heat is drained from your body.");
+
+ ouch(check_your_resists(5 + random2(6) + random2(7), 3), 0,
+ KILLED_BY_WILD_MAGIC, cause);
+
+ scrolls_burn(4, OBJ_POTIONS);
+ break;
+
+ case 1:
+ mpr("You are caught in an explosion of ice and frost!");
+
+ beam.type = SYM_BURST;
+ beam.damage = dice_def( 3, 11 );
+ beam.flavour = BEAM_COLD;
+ beam.target_x = you.x_pos;
+ beam.target_y = you.y_pos;
+ strcpy(beam.beam_name, "explosion");
+ beam.colour = WHITE;
+ beam.beam_source = NON_MONSTER;
+ beam.thrower = (cause) ? KILL_MISC : KILL_YOU;
+ beam.aux_source = cause;
+ beam.ex_size = 1;
+
+ explosion(beam);
+ break;
+ }
+ break;
+
+ case 3: // less harmless stuff
+ switch (random2(2))
+ {
+ case 0:
+ mpr("You are blasted with ice!");
+
+ ouch(check_your_resists(9 + random2avg(23, 2), 3), 0,
+ KILLED_BY_WILD_MAGIC, cause);
+
+ scrolls_burn(9, OBJ_POTIONS);
+ break;
+ case 1:
+ snprintf( info, INFO_SIZE,"Freezing gasses pour from your %s!",
+ your_hand(true));
+ mpr(info);
+
+ big_cloud(CLOUD_COLD, you.x_pos, you.y_pos, 20,
+ 8 + random2(4));
+ break;
+ }
+ break;
+ }
+ break; // end ice
+
+ case SPTYP_EARTH:
+ switch (spec_effect)
+ {
+ case 0: // just a harmless message
+ case 1:
+ switch (random2(10))
+ {
+ case 0:
+ mpr("You feel earthy.");
+ break;
+ case 1:
+ mpr("You are showered with tiny particles of grit.");
+ break;
+ case 2:
+ snprintf( info, INFO_SIZE,"Sand pours from your %s.",
+ your_hand(true));
+ mpr(info);
+ break;
+ case 3:
+ mpr("You feel a surge of energy from the ground.");
+ break;
+ case 4:
+ if (!silenced(you.x_pos, you.y_pos))
+ mpr("You hear a distant rumble.");
+ else
+ mpr("You sympathise with the stones.");
+ break;
+ case 5:
+ mpr("You feel gritty.");
+ break;
+ case 6:
+ mpr("You feel momentarily lethargic.");
+ break;
+ case 7:
+ mpr("Motes of dust swirl before your eyes.");
+ break;
+ case 8:
+ canned_msg(MSG_NOTHING_HAPPENS);
+ break;
+ case 9:
+ strcpy(info, "Your ");
+ strcat(info, (you.species == SP_NAGA) ? "underbelly feels" :
+ (you.species == SP_CENTAUR) ? "hooves feel"
+ : "feet feel");
+ strcat(info, " warm.");
+ mpr(info);
+ break;
+ }
+ break;
+
+ case 2: // slightly less harmless stuff
+ switch (random2(1))
+ {
+ case 0:
+ switch (random2(3))
+ {
+ case 0:
+ mpr("You are hit by flying rocks!");
+ break;
+ case 1:
+ mpr("You are blasted with sand!");
+ break;
+ case 2:
+ mpr("Rocks fall onto you out of nowhere!");
+ break;
+ }
+
+ hurted = random2avg(13, 2) + 10;
+ hurted -= random2(1 + player_AC());
+
+ ouch(hurted, 0, KILLED_BY_WILD_MAGIC, cause);
+ break;
+ }
+ break;
+
+ case 3: // less harmless stuff
+ switch (random2(1))
+ {
+ case 0:
+ mpr("You are caught in an explosion of flying shrapnel!");
+
+ beam.type = SYM_BURST;
+ beam.damage = dice_def( 3, 15 );
+ beam.flavour = BEAM_FRAG;
+ beam.target_x = you.x_pos;
+ beam.target_y = you.y_pos;
+ strcpy(beam.beam_name, "explosion");
+ beam.colour = CYAN;
+
+ if (one_chance_in(5))
+ beam.colour = BROWN;
+ if (one_chance_in(5))
+ beam.colour = LIGHTCYAN;
+
+ beam.beam_source = NON_MONSTER;
+ beam.thrower = (cause) ? KILL_MISC : KILL_YOU;
+ beam.aux_source = cause;
+ beam.ex_size = 1;
+
+ explosion(beam);
+ break;
+ }
+ break;
+ }
+ break; // end Earth
+
+ case SPTYP_AIR:
+ switch (spec_effect)
+ {
+ case 0: // just a harmless message
+ switch (random2(10))
+ {
+ case 0:
+ mpr("Ouch! You gave yourself an electric shock.");
+ break;
+ case 1:
+ mpr("You feel momentarily weightless.");
+ break;
+ case 2:
+ snprintf( info, INFO_SIZE, "Wisps of vapour drift from your %s.",
+ your_hand(true));
+ mpr(info);
+ break;
+ case 3:
+ mpr("You feel a strange surge of energy!");
+ break;
+ case 4:
+ mpr("You feel electric!");
+ break;
+ case 5:
+ snprintf( info, INFO_SIZE, "Sparks of electricity dance between your %s.",
+ your_hand(true));
+ mpr(info);
+ break;
+ case 6:
+ mpr("You are blasted with air!");
+ break;
+ case 7:
+ // mummies cannot smell
+ if (!silenced(you.x_pos, you.y_pos))
+ mpr("You hear a whooshing sound.");
+ else if (you.species != SP_MUMMY)
+ mpr("You smell ozone.");
+ break;
+ case 8:
+ canned_msg(MSG_NOTHING_HAPPENS);
+ break;
+ case 9:
+ // mummies cannot smell
+ if (!silenced(you.x_pos, you.y_pos))
+ mpr("You hear a crackling sound.");
+ else if (you.species != SP_MUMMY)
+ mpr("You smell something musty.");
+ break;
+ }
+ break;
+
+ case 1: // a bit less harmless stuff
+ switch (random2(2))
+ {
+ case 0:
+ mpr("There is a short, sharp shower of sparks.");
+ break;
+ case 1:
+ snprintf( info, INFO_SIZE, "The wind %s around you!",
+ silenced(you.x_pos, you.y_pos) ? "whips" : "howls");
+ mpr(info);
+ break;
+ }
+ break;
+
+ case 2: // rather less harmless stuff
+ switch (random2(2))
+ {
+ case 0:
+ mpr("Electricity courses through your body.");
+ ouch(check_your_resists(4 + random2avg(9, 2), 5), 0,
+ KILLED_BY_WILD_MAGIC, cause);
+ break;
+ case 1:
+ snprintf( info, INFO_SIZE, "Noxious gasses pour from your %s!",
+ your_hand(true));
+ mpr(info);
+
+ big_cloud(CLOUD_STINK, you.x_pos, you.y_pos, 20,
+ 9 + random2(4));
+ break;
+ }
+ break;
+
+ case 3: // less harmless stuff
+ switch (random2(2))
+ {
+ case 0:
+ mpr("You are caught in an explosion of electrical discharges!");
+
+ beam.type = SYM_BURST;
+ beam.damage = dice_def( 3, 8 );
+ beam.flavour = BEAM_ELECTRICITY;
+ beam.target_x = you.x_pos;
+ beam.target_y = you.y_pos;
+ strcpy(beam.beam_name, "explosion");
+ beam.colour = LIGHTBLUE;
+ beam.beam_source = NON_MONSTER;
+ beam.thrower = (cause) ? KILL_MISC : KILL_YOU;
+ beam.aux_source = cause;
+ beam.ex_size = one_chance_in(4)?1:2;
+
+ explosion(beam);
+ break;
+ case 1:
+ snprintf( info, INFO_SIZE, "Venomous gasses pour from your %s!",
+ your_hand(true));
+ mpr(info);
+
+ big_cloud( CLOUD_POISON, you.x_pos, you.y_pos, 20,
+ 8 + random2(5) );
+ break;
+ }
+ break;
+ }
+ break; // end air
+
+ case SPTYP_POISON:
+ switch (spec_effect)
+ {
+ case 0: // just a harmless message
+ switch (random2(10))
+ {
+ case 0:
+ mpr("You feel mildly nauseous.");
+ break;
+ case 1:
+ mpr("You feel slightly ill.");
+ break;
+ case 2:
+ snprintf( info, INFO_SIZE, "Wisps of poison gas drift from your %s.",
+ your_hand(true) );
+ mpr(info);
+ break;
+ case 3:
+ mpr("You feel a strange surge of energy!");
+ break;
+ case 4:
+ mpr("You feel faint for a moment.");
+ break;
+ case 5:
+ mpr("You feel sick.");
+ break;
+ case 6:
+ mpr("You feel odd.");
+ break;
+ case 7:
+ mpr("You feel weak for a moment.");
+ break;
+ case 8:
+ canned_msg(MSG_NOTHING_HAPPENS);
+ break;
+ case 9:
+ if (!silenced(you.x_pos, you.y_pos))
+ mpr("You hear a slurping sound.");
+ else if (you.species != SP_MUMMY)
+ mpr("You taste almonds.");
+ break;
+ }
+ break;
+
+ case 1: // a bit less harmless stuff
+ switch (random2(2))
+ {
+ case 0:
+ if (player_res_poison())
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ return (false);
+ }
+
+ mpr("You feel sick.");
+ poison_player( 2 + random2(3) );
+ break;
+
+ case 1:
+ snprintf( info, INFO_SIZE, "Noxious gasses pour from your %s!",
+ your_hand(true) );
+ mpr(info);
+
+ place_cloud(CLOUD_STINK, you.x_pos, you.y_pos,
+ 2 + random2(4));
+ break;
+ }
+ break;
+
+ case 2: // rather less harmless stuff
+ switch (random2(3))
+ {
+ case 0:
+ if (player_res_poison())
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ return (false);
+ }
+
+ mpr("You feel very sick.");
+ poison_player( 3 + random2avg(9, 2) );
+ break;
+
+ case 1:
+ mpr("Noxious gasses pour from your hands!");
+ big_cloud(CLOUD_STINK, you.x_pos, you.y_pos, 20,
+ 8 + random2(5));
+ break;
+
+ case 2:
+ if (player_res_poison())
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ return (false);
+ }
+ lose_stat(STAT_RANDOM, 1);
+ break;
+ }
+ break;
+
+ case 3: // less harmless stuff
+ switch (random2(3))
+ {
+ case 0:
+ if (player_res_poison())
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ return (false);
+ }
+
+ mpr("You feel incredibly sick.");
+ poison_player( 10 + random2avg(19, 2) );
+ break;
+ case 1:
+ snprintf( info, INFO_SIZE, "Venomous gasses pour from your %s!",
+ your_hand(true));
+ mpr(info);
+
+ big_cloud(CLOUD_POISON, you.x_pos, you.y_pos, 20,
+ 7 + random2(7));
+ break;
+ case 2:
+ if (player_res_poison())
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ return (false);
+ }
+
+ lose_stat(STAT_RANDOM, 1 + random2avg(5, 2));
+ break;
+ }
+ break;
+ }
+ break; // end poison
+ }
+
+ return (true);
+} // end miscast_effect()
diff --git a/trunk/source/spl-cast.h b/trunk/source/spl-cast.h
new file mode 100644
index 0000000000..f517a5ff3f
--- /dev/null
+++ b/trunk/source/spl-cast.h
@@ -0,0 +1,49 @@
+/*
+ * File: spl-cast.cc
+ * Summary: Spell casting functions.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef SPL_CAST_H
+#define SPL_CAST_H
+
+char list_spells( void );
+int spell_fail( int spell );
+int calc_spell_power( int spell, bool apply_intel );
+int spell_enhancement( unsigned int typeflags );
+
+// last updaetd 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: it_use3 - spell
+ * *********************************************************************** */
+void exercise_spell( int spell_ex, bool spc, bool divide );
+
+
+// last updaetd 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+bool cast_a_spell( void );
+
+
+// last updaetd 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - debug - it_use3 - spell
+ * *********************************************************************** */
+bool your_spells( int spc2, int powc = 0, bool allow_fail = true );
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - decks - fight - it_use2 - it_use3 - item_use - items -
+ * misc - mstuff2 - religion - spell - spl-book - spells4
+ * *********************************************************************** */
+bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail,
+ int force_effect, const char *cause = NULL );
+
+
+#endif
diff --git a/trunk/source/spl-data.h b/trunk/source/spl-data.h
new file mode 100644
index 0000000000..aee5e09bc0
--- /dev/null
+++ b/trunk/source/spl-data.h
@@ -0,0 +1,1286 @@
+/*
+ In case anyone ever wants to add new spells, or just understand my reasons
+ for putting a particular spell into a particular type, read on:
+
+ Guidelines for typing spells
+
+ Conjuration
+ This type has a near monopoly on effective and relatively risk-free combat
+ spells. All other types of combat spells are either indirect (enchantments),
+ risky/detrimental/not versatile (necromancy) or just plain crappy (burn and
+ freeze), although smiting (holy) is not too bad.
+ Conjuration spells all involve the magical creation of matter and/or energy
+ (which are the same thing anyway, right?). They are distinguished from
+ summoning spells in that they do not involve the summoning of an entire
+ creature from another place.
+
+ Enchantment
+ These spells mostly cause some kind of durational effect, which lasts only
+ until the magic wears off. Enchantments are distinguished from trans-
+ migrations in that the latter cause a permanent alteration in something
+ which persists even after the magic has faded, while the effects of the
+ former last only so long as the magic does. Sometimes enchantments may take
+ advantage of the more powerful aspects of transmigration to induce some
+ kind of radical change (eg polymorph).
+ Some enchantments would also fall under the description of 'meta-magic'
+ spells, like Selective Amnesia and Remove Curse (and if I ever implement
+ Dispel Magic, it will be an enchantment).
+ It is possible that some divinations could be retyped as
+ divination/enchantment, as they appear to be primarily concerned with
+ detecting enchantments. Detect Curse and Identify are what I'm thinking
+ of here.
+
+ Fire and Ice
+ These are quite obvious. I'm trying to keep these two balanced with each
+ other, but it can be difficult. I have to weigh up some useful fire spells,
+ like Sticky Flame, Fireball, Ring of Flames and Firestorm, and the fact that
+ Fire wizards have an advantage when summoning fire elementals by either
+ spell or device, with the also quite useful Refrigeration, Ice Armour and
+ Freezing Cloud. Ice wizards don't have a corresponding advantage with
+ water elementals, because water and ice are two different things (ice is not
+ necessarily water ice, for example).
+ Generally, Fire spells tend towards chaos, disorder and entropy, while
+ Ice spells tend towards order and stasis. But these trends are rather
+ underdeveloped at the moment.
+ Note that just about the only reason one would ever choose an ice or fire
+ wizard over a conjurer would be the resistance gained at level 12.
+ Especially because having a fire specialisation basically removes any chance
+ of ever using ice spells effectively, and vice versa.
+
+ Transmigration
+ See enchantments.
+
+ Necromancy
+ This is the fun stuff. Necromancy is a mixed bag of many and various
+ different kinds of spells, with a few common themes:
+ -Differentiation of living, dead and undead. Some necromancy affects only
+ the living (pain, vampiric draining etc), some affects only the dead
+ (animate dead, twisted resurrection etc), and some affects only undead
+ (dispel and control undead).
+ -Actual or potential harm: eg risk in Death's Door, hp loss with Pain,
+ disease with summon greater undead, etc. Also loss of potential experience
+ gain with bolt of draining and degeneration.
+ -Material components are central to many of the spells.
+ -Some spells duplicate effects of other types, but do so in a different
+ (neither superior or inferior) way. Eg bone shards is a very powerful spell
+ for only 3 magic points, but requires preparation. Also, necromantic
+ healing spells are different and more idiosyncratic than holy healing.
+ Although regeneration is usually less useful than lesser healing and is
+ level 3 instead of 2, it can be cast before combat (when 1 turn spent
+ casting is less important), and is affected by extension.
+ -Generally unholy theme of spells (I mean, Twisted Resurrection?).
+
+ Holy
+ The Holy type is also fairly various, but is rather less interesting than
+ necromancy (after all, priests are better at fighting than necromancers).
+ Holy spells do things like driving off undead and healing. Note that I
+ consider item stickycursing to be more of an issue for enchantments rather
+ than holy magic, which is why remove curse is enchantment.
+
+ Summoning
+ These spells involve bringing a creature from somewhere else (possibly on
+ another plane of existence) to this world to do battle for the caster. Some
+ future summonings could potentially be combination conjuration/summoning
+ spells, eg the ball lightning spell I keep planning to implement.
+ Also, potential exists for some risky high-level spells, maybe demon
+ summoning?
+
+ Divination
+ These spells provide information to the caster. A diviner class would be
+ possible (and having detect curse and identify would be very handy), but
+ would be extremely difficult to play - there is no potential in this type
+ for combat spells.
+
+ Translocation
+ Translocation spells deal with teleportation etc, also interplanar travel
+ (eg Banishment, and the planned Gate spell).
+ It is possible that I may give summoners some special access to trans-
+ locations due to the obvious similarities.
+
+ Poison
+ These spells all involve poison. Most are also conjurations.
+ I don't plan to implement a 'Poisoner' class, as it would become unplayable
+ deep in the dungeon where most monsters are poison resistant.
+
+ Many spells use magic from two types. These spells are equally
+ available to either type; a conjurer is no worse at a fire/conjuration than
+ at a pure conjuration. I guess a spell could be of three types, but they
+ would have to be types with short names (limited space in the spell
+ windows).
+ - Note : this is no longer true, with the implementation of magic skills.
+ Your skill for a spell is effectively the average of all types used in it.
+ Poison has no skills, but still has a staff
+
+
+*/
+
+/*
+ * When adding enchantments, must add them to extension as well!
+ *
+ * spells to do:
+ * Contingency?
+ * Trigger contingency
+ * Preserve Corpses
+ * Permanency
+ * Ball Lightning
+ * Explosive rune?
+ * Fennel wands
+ * More summonings!
+ */
+
+#ifndef SPLDATA_H
+#define SPLDATA_H
+
+
+{
+ SPELL_IDENTIFY, "Identify",
+ SPTYP_DIVINATION,
+ 6
+},
+
+{
+ SPELL_TELEPORT_SELF, "Teleport Self",
+ SPTYP_TRANSLOCATION,
+ 5
+},
+
+{
+ SPELL_CAUSE_FEAR, "Cause Fear",
+ SPTYP_ENCHANTMENT,
+ 5
+},
+
+{
+ SPELL_CREATE_NOISE, "Create Noise",
+ SPTYP_ENCHANTMENT,
+ 1
+},
+
+{
+ SPELL_REMOVE_CURSE, "Remove Curse",
+ SPTYP_ENCHANTMENT,
+ 5
+},
+
+{
+ SPELL_MAGIC_DART, "Magic Dart",
+ SPTYP_CONJURATION,
+ 1
+},
+
+{
+ SPELL_FIREBALL, "Fireball",
+ SPTYP_CONJURATION | SPTYP_FIRE,
+ 6
+},
+
+{
+ SPELL_SWAP, "Swap",
+ SPTYP_TRANSLOCATION,
+ 3
+},
+
+{
+ SPELL_APPORTATION, "Apportation",
+ SPTYP_TRANSLOCATION,
+ 1
+},
+
+{
+ SPELL_TWIST, "Twist",
+ SPTYP_TRANSLOCATION,
+ 1
+},
+
+{
+ SPELL_CONJURE_FLAME, "Conjure Flame",
+ SPTYP_CONJURATION | SPTYP_FIRE,
+ 3
+},
+
+{
+ SPELL_DIG, "Dig",
+ SPTYP_TRANSMIGRATION | SPTYP_EARTH,
+ 4
+},
+
+{
+ SPELL_BOLT_OF_FIRE, "Bolt of Fire",
+ SPTYP_CONJURATION | SPTYP_FIRE,
+ 5
+},
+
+{
+ SPELL_BOLT_OF_COLD, "Bolt of Cold",
+ SPTYP_CONJURATION | SPTYP_ICE,
+ 5
+},
+
+{
+ SPELL_LIGHTNING_BOLT, "Lightning Bolt",
+ SPTYP_CONJURATION | SPTYP_AIR,
+ 6
+},
+
+{
+ SPELL_BOLT_OF_MAGMA, "Bolt of Magma",
+ SPTYP_CONJURATION | SPTYP_FIRE | SPTYP_EARTH,
+ 5
+},
+
+{
+ SPELL_POLYMORPH_OTHER, "Polymorph Other",
+ SPTYP_TRANSMIGRATION, // removed enchantment, wasn't needed -- bwr
+ 5
+},
+
+{
+ SPELL_SLOW, "Slow",
+ SPTYP_ENCHANTMENT,
+ 3
+},
+
+{
+ SPELL_HASTE, "Haste",
+ SPTYP_ENCHANTMENT,
+ 6 // lowered to 6 from 8, since its easily available from various items
+ // and Swiftness is level 2 (and gives a similar effect). Its also
+ // not that much better than Invisibility. -- bwr
+},
+
+{
+ SPELL_PARALYZE, "Paralyze",
+ SPTYP_ENCHANTMENT,
+ 4
+},
+
+{
+ SPELL_CONFUSE, "Confuse",
+ SPTYP_ENCHANTMENT,
+ 3
+},
+
+{
+ SPELL_INVISIBILITY, "Invisibility",
+ SPTYP_ENCHANTMENT,
+ 6
+},
+
+{
+ SPELL_THROW_FLAME, "Throw Flame",
+ SPTYP_CONJURATION | SPTYP_FIRE,
+ 2
+},
+
+{
+ SPELL_THROW_FROST, "Throw Frost",
+ SPTYP_CONJURATION | SPTYP_ICE,
+ 2
+},
+
+{
+ SPELL_CONTROLLED_BLINK, "Controlled Blink",
+ SPTYP_TRANSLOCATION,
+ 4
+},
+
+{
+ SPELL_FREEZING_CLOUD, "Freezing Cloud",
+ SPTYP_CONJURATION | SPTYP_ICE | SPTYP_AIR,
+ 7
+},
+
+{
+ SPELL_MEPHITIC_CLOUD, "Mephitic Cloud",
+ SPTYP_CONJURATION | SPTYP_POISON | SPTYP_AIR,
+ 3
+},
+
+{
+ SPELL_RING_OF_FLAMES, "Ring of Flames",
+ SPTYP_ENCHANTMENT | SPTYP_FIRE,
+ 8
+},
+
+{
+ SPELL_RESTORE_STRENGTH, "Restore Strength",
+ SPTYP_HOLY,
+ 2
+},
+
+{
+ SPELL_RESTORE_INTELLIGENCE, "Restore Intelligence",
+ SPTYP_HOLY,
+ 2
+},
+
+{
+ SPELL_RESTORE_DEXTERITY, "Restore Dexterity",
+ SPTYP_HOLY,
+ 2
+},
+
+{
+ SPELL_VENOM_BOLT, "Venom Bolt",
+ SPTYP_CONJURATION | SPTYP_POISON,
+ 5
+},
+
+{
+ SPELL_OLGREBS_TOXIC_RADIANCE, "Olgreb's Toxic Radiance",
+ SPTYP_POISON,
+ 4
+},
+
+{
+ SPELL_TELEPORT_OTHER, "Teleport Other",
+ SPTYP_TRANSLOCATION,
+ 4
+},
+
+{
+ SPELL_LESSER_HEALING, "Lesser Healing",
+ SPTYP_HOLY,
+ 2
+},
+
+{
+ SPELL_GREATER_HEALING, "Greater Healing",
+ SPTYP_HOLY,
+ 6
+},
+
+{
+ SPELL_CURE_POISON_I, "Cure Poison",
+ SPTYP_HOLY,
+ 3
+},
+
+{
+ SPELL_PURIFICATION, "Purification",
+ SPTYP_HOLY,
+ 5
+},
+
+{
+ SPELL_DEATHS_DOOR, "Death's Door",
+ SPTYP_ENCHANTMENT | SPTYP_NECROMANCY,
+ 8
+},
+
+{
+ SPELL_SELECTIVE_AMNESIA, "Selective Amnesia",
+ SPTYP_ENCHANTMENT,
+ 3
+},
+
+{
+ SPELL_MASS_CONFUSION, "Mass Confusion",
+ SPTYP_ENCHANTMENT,
+ 6
+},
+
+{
+ SPELL_SMITING, "Smiting",
+ SPTYP_HOLY,
+ 4
+},
+
+{
+ SPELL_REPEL_UNDEAD, "Repel Undead",
+ SPTYP_HOLY,
+ 3
+},
+
+{
+ SPELL_HOLY_WORD, "Holy Word",
+ SPTYP_HOLY,
+ 7
+},
+
+{
+ SPELL_DETECT_CURSE, "Detect Curse",
+ SPTYP_DIVINATION,
+ 3
+},
+
+{
+ SPELL_SUMMON_SMALL_MAMMAL, "Summon Small Mammals",
+ SPTYP_SUMMONING,
+ 1
+},
+
+{
+ SPELL_ABJURATION_I, "Abjuration",
+ SPTYP_SUMMONING,
+ 3
+},
+
+{
+ SPELL_SUMMON_SCORPIONS, "Summon Scorpions",
+ SPTYP_SUMMONING | SPTYP_POISON,
+ 4
+},
+
+{
+ SPELL_LEVITATION, "Levitation",
+ SPTYP_ENCHANTMENT | SPTYP_AIR,
+ 2
+},
+
+{
+ SPELL_BOLT_OF_DRAINING, "Bolt of Draining",
+ SPTYP_CONJURATION | SPTYP_NECROMANCY,
+ 6
+},
+
+{
+ SPELL_LEHUDIBS_CRYSTAL_SPEAR, "Lehudib's Crystal Spear",
+ SPTYP_CONJURATION | SPTYP_EARTH,
+ 8
+},
+
+{
+ SPELL_BOLT_OF_INACCURACY, "Bolt of Inaccuracy",
+ SPTYP_CONJURATION,
+ 2
+},
+
+{
+ SPELL_POISONOUS_CLOUD, "Poisonous Cloud",
+ SPTYP_CONJURATION | SPTYP_POISON | SPTYP_AIR,
+ 6
+}
+,
+
+{
+ SPELL_FIRE_STORM, "Fire Storm",
+ SPTYP_CONJURATION | SPTYP_FIRE,
+ 9
+},
+
+{
+ SPELL_DETECT_TRAPS, "Detect Traps",
+ SPTYP_DIVINATION,
+ 2
+},
+
+{
+ SPELL_BLINK, "Blink",
+ SPTYP_TRANSLOCATION,
+ 2
+},
+
+
+// The following name was found in the hack.exe file of an early version
+// of PCHACK - credit goes to its creator (whoever that may be):
+{
+ SPELL_ISKENDERUNS_MYSTIC_BLAST, "Iskenderun's Mystic Blast",
+ SPTYP_CONJURATION,
+ 4
+},
+
+{
+ SPELL_SWARM, "Summon Swarm",
+ SPTYP_SUMMONING,
+ 6
+},
+
+{
+ SPELL_SUMMON_HORRIBLE_THINGS, "Summon Horrible Things",
+ SPTYP_SUMMONING,
+ 8
+},
+
+{
+ SPELL_ENSLAVEMENT, "Enslavement",
+ SPTYP_ENCHANTMENT,
+ 4
+},
+
+{
+ SPELL_MAGIC_MAPPING, "Magic Mapping",
+ SPTYP_DIVINATION | SPTYP_EARTH,
+ 4
+},
+
+{
+ SPELL_HEAL_OTHER, "Heal Other",
+ SPTYP_HOLY,
+ 3
+},
+
+{
+ SPELL_ANIMATE_DEAD, "Animate Dead",
+ SPTYP_NECROMANCY,
+ 4
+},
+
+{
+ SPELL_PAIN, "Pain",
+ SPTYP_NECROMANCY,
+ 1
+},
+
+{
+ SPELL_EXTENSION, "Extension",
+ SPTYP_ENCHANTMENT,
+ 5
+},
+
+{
+ SPELL_CONTROL_UNDEAD, "Control Undead",
+ SPTYP_ENCHANTMENT | SPTYP_NECROMANCY,
+ 6
+},
+
+{
+ SPELL_ANIMATE_SKELETON, "Animate Skeleton",
+ SPTYP_NECROMANCY,
+ 1
+},
+
+{
+ SPELL_VAMPIRIC_DRAINING, "Vampiric Draining",
+ SPTYP_NECROMANCY,
+ 3
+},
+
+{
+ SPELL_SUMMON_WRAITHS, "Summon Wraiths",
+ SPTYP_NECROMANCY | SPTYP_SUMMONING,
+ 7
+},
+
+{
+ SPELL_DETECT_ITEMS, "Detect Items",
+ SPTYP_DIVINATION,
+ 2
+},
+
+{
+ SPELL_BORGNJORS_REVIVIFICATION, "Borgnjor's Revivification",
+ SPTYP_NECROMANCY,
+ 6
+},
+
+{
+ SPELL_BURN, "Burn", // used by wanderers
+ SPTYP_FIRE,
+ 1
+},
+
+{
+ SPELL_FREEZE, "Freeze",
+ SPTYP_ICE,
+ 1
+},
+
+{
+ SPELL_SUMMON_ELEMENTAL, "Summon Elemental",
+ SPTYP_SUMMONING,
+ 4
+},
+
+{
+ SPELL_OZOCUBUS_REFRIGERATION, "Ozocubu's Refrigeration",
+ SPTYP_ICE,
+ 5
+},
+
+{
+ SPELL_STICKY_FLAME, "Sticky Flame",
+ SPTYP_CONJURATION | SPTYP_FIRE,
+ 4
+},
+
+{
+ SPELL_SUMMON_ICE_BEAST, "Summon Ice Beast",
+ SPTYP_ICE | SPTYP_SUMMONING,
+ 5
+},
+
+{
+ SPELL_OZOCUBUS_ARMOUR, "Ozocubu's Armour",
+ SPTYP_ENCHANTMENT | SPTYP_ICE,
+ 3
+},
+
+{
+ SPELL_CALL_IMP, "Call Imp",
+ SPTYP_SUMMONING,
+ 3
+},
+
+{
+ SPELL_REPEL_MISSILES, "Repel Missiles",
+ SPTYP_ENCHANTMENT | SPTYP_AIR,
+ 2
+},
+
+{
+ SPELL_BERSERKER_RAGE, "Berserker Rage",
+ SPTYP_ENCHANTMENT,
+ 3
+},
+
+{
+ SPELL_DISPEL_UNDEAD, "Dispel Undead",
+ SPTYP_NECROMANCY,
+ 4
+},
+
+{
+ SPELL_GUARDIAN, "Guardian",
+ SPTYP_HOLY,
+ 7
+},
+
+{
+ SPELL_PESTILENCE, "Pestilence",
+ SPTYP_HOLY,
+ 4
+},
+
+{
+ SPELL_THUNDERBOLT, "Thunderbolt",
+ SPTYP_HOLY | SPTYP_AIR,
+ 6 // why is this the only holy spell with a secondary? {dlb}
+}
+,
+
+{
+ SPELL_FLAME_OF_CLEANSING, "Flame of Cleansing",
+ SPTYP_HOLY,
+ 8
+},
+
+{
+ SPELL_SHINING_LIGHT, "Shining Light",
+ SPTYP_HOLY,
+ 7
+},
+
+{
+ SPELL_SUMMON_DAEVA, "Summon Daeva",
+ SPTYP_HOLY,
+ 8
+},
+
+{
+ SPELL_ABJURATION_II, "Abjuration",
+ SPTYP_HOLY,
+ 4
+},
+
+{
+ SPELL_TWISTED_RESURRECTION, "Twisted Resurrection",
+ SPTYP_NECROMANCY,
+ 5
+},
+
+{
+ SPELL_REGENERATION, "Regeneration",
+ SPTYP_ENCHANTMENT | SPTYP_NECROMANCY,
+ 3
+},
+
+{
+ SPELL_BONE_SHARDS, "Bone Shards",
+ SPTYP_NECROMANCY,
+ 3
+},
+
+{
+ SPELL_BANISHMENT, "Banishment",
+ SPTYP_TRANSLOCATION,
+ 5
+},
+
+{
+ SPELL_CIGOTUVIS_DEGENERATION, "Cigotuvi's Degeneration",
+ SPTYP_TRANSMIGRATION | SPTYP_NECROMANCY,
+ 5
+},
+
+{
+ SPELL_STING, "Sting",
+ SPTYP_CONJURATION | SPTYP_POISON,
+ 1
+},
+
+{
+ SPELL_SUBLIMATION_OF_BLOOD, "Sublimation of Blood",
+ SPTYP_NECROMANCY,
+ 2
+},
+
+{
+ SPELL_TUKIMAS_DANCE, "Tukima's Dance",
+ SPTYP_ENCHANTMENT,
+ 3
+},
+
+{
+ SPELL_HELLFIRE, "Hellfire",
+ SPTYP_CONJURATION | SPTYP_FIRE,
+ 9
+},
+
+{
+ SPELL_SUMMON_DEMON, "Summon Demon",
+ SPTYP_SUMMONING,
+ 5
+},
+
+{
+ SPELL_DEMONIC_HORDE, "Demonic Horde",
+ SPTYP_SUMMONING,
+ 6
+},
+
+{
+ SPELL_SUMMON_GREATER_DEMON, "Summon Greater Demon",
+ SPTYP_SUMMONING,
+ 7
+},
+
+{
+ SPELL_CORPSE_ROT, "Corpse Rot",
+ SPTYP_NECROMANCY,
+ 2
+},
+
+{
+ SPELL_TUKIMAS_VORPAL_BLADE, "Tukima's Vorpal Blade",
+ SPTYP_ENCHANTMENT,
+ 2
+},
+
+{
+ SPELL_FIRE_BRAND, "Fire Brand",
+ SPTYP_ENCHANTMENT | SPTYP_FIRE,
+ 2
+},
+
+{
+ SPELL_FREEZING_AURA, "Freezing Aura",
+ SPTYP_ENCHANTMENT | SPTYP_ICE,
+ 2
+},
+
+{
+ SPELL_LETHAL_INFUSION, "Lethal Infusion",
+ SPTYP_ENCHANTMENT | SPTYP_NECROMANCY,
+ 2
+},
+
+{
+ SPELL_CRUSH, "Crush", // used by wanderers
+ SPTYP_EARTH,
+ 1
+},
+
+{
+ SPELL_BOLT_OF_IRON, "Bolt of Iron",
+ SPTYP_CONJURATION | SPTYP_EARTH,
+ 6
+},
+
+{
+ SPELL_STONE_ARROW, "Stone Arrow",
+ SPTYP_CONJURATION | SPTYP_EARTH,
+ 3
+},
+
+{
+ SPELL_TOMB_OF_DOROKLOHE, "Tomb of Doroklohe",
+ SPTYP_CONJURATION | SPTYP_EARTH, // conj makes more sense than tmig -- bwr
+ 7
+}
+,
+
+{
+ SPELL_STONEMAIL, "Stonemail",
+ SPTYP_ENCHANTMENT | SPTYP_EARTH,
+ 6
+},
+
+{
+ SPELL_SHOCK, "Shock",
+ SPTYP_CONJURATION | SPTYP_AIR,
+ 1
+},
+
+{
+ SPELL_SWIFTNESS, "Swiftness",
+ SPTYP_ENCHANTMENT | SPTYP_AIR,
+ 2
+},
+
+{
+ SPELL_FLY, "Fly",
+ SPTYP_ENCHANTMENT | SPTYP_AIR,
+ 4
+},
+
+{
+ SPELL_INSULATION, "Insulation",
+ SPTYP_ENCHANTMENT | SPTYP_AIR,
+ 4
+},
+
+{
+ SPELL_ORB_OF_ELECTROCUTION, "Orb of Electrocution",
+ SPTYP_CONJURATION | SPTYP_AIR,
+ 7
+},
+
+{
+ SPELL_DETECT_CREATURES, "Detect Creatures",
+ SPTYP_DIVINATION,
+ 2
+},
+
+{
+ SPELL_CURE_POISON_II, "Cure Poison",
+ SPTYP_POISON,
+ 2
+}
+,
+
+{
+ SPELL_CONTROL_TELEPORT, "Control Teleport",
+ SPTYP_ENCHANTMENT | SPTYP_TRANSLOCATION,
+ 6
+},
+
+{
+ SPELL_POISON_AMMUNITION, "Poison Ammunition",
+ SPTYP_ENCHANTMENT | SPTYP_POISON,
+ 4 // jmf: SPTYP_TRANSMIGRATION vs SPTYP_ENCHANTMENT?
+}
+,
+
+{
+ SPELL_POISON_WEAPON, "Poison Weapon",
+ SPTYP_ENCHANTMENT | SPTYP_POISON,
+ 4
+},
+
+{
+ SPELL_RESIST_POISON, "Resist Poison",
+ SPTYP_ENCHANTMENT | SPTYP_POISON,
+ 4
+},
+
+{
+ SPELL_PROJECTED_NOISE, "Projected Noise",
+ SPTYP_ENCHANTMENT,
+ 2
+},
+
+{
+ SPELL_ALTER_SELF, "Alter Self",
+ SPTYP_TRANSMIGRATION,
+ 7
+},
+
+{
+ SPELL_DEBUGGING_RAY, "Debugging Ray",
+ SPTYP_CONJURATION,
+ 7
+},
+
+{
+ SPELL_RECALL, "Recall",
+ SPTYP_SUMMONING | SPTYP_TRANSLOCATION,
+ 3
+},
+
+{
+ SPELL_PORTAL, "Portal",
+ SPTYP_TRANSLOCATION,
+ 8
+},
+
+{
+ SPELL_AGONY, "Agony",
+ SPTYP_NECROMANCY,
+ 5
+},
+
+{
+ SPELL_SPIDER_FORM, "Spider Form",
+ SPTYP_TRANSMIGRATION | SPTYP_POISON,
+ 3
+},
+
+{
+ SPELL_DISRUPT, "Disrupt",
+ SPTYP_TRANSMIGRATION,
+ 1
+},
+
+{
+ SPELL_DISINTEGRATE, "Disintegrate",
+ SPTYP_TRANSMIGRATION,
+ 6
+},
+
+{
+ SPELL_BLADE_HANDS, "Blade Hands",
+ SPTYP_TRANSMIGRATION,
+ 5 // only removes weapon, so I raised this from 4 -- bwr
+},
+
+{
+ SPELL_STATUE_FORM, "Statue Form",
+ SPTYP_TRANSMIGRATION | SPTYP_EARTH,
+ 6
+},
+
+{
+ SPELL_ICE_FORM, "Ice Form",
+ SPTYP_ICE | SPTYP_TRANSMIGRATION,
+ 4 // doesn't allow for equipment, so I lowered this from 5 -- bwr
+},
+
+{
+ SPELL_DRAGON_FORM, "Dragon Form",
+ SPTYP_FIRE | SPTYP_TRANSMIGRATION,
+ 8
+},
+
+{
+ SPELL_NECROMUTATION, "Necromutation",
+ SPTYP_TRANSMIGRATION | SPTYP_NECROMANCY,
+ 8
+},
+
+{
+ SPELL_DEATH_CHANNEL, "Death Channel",
+ SPTYP_NECROMANCY,
+ 9
+},
+
+{
+ SPELL_SYMBOL_OF_TORMENT, "Symbol of Torment",
+ SPTYP_NECROMANCY,
+ 6
+},
+
+{
+ SPELL_DEFLECT_MISSILES, "Deflect Missiles",
+ SPTYP_ENCHANTMENT | SPTYP_AIR,
+ 6
+},
+
+{
+ SPELL_ORB_OF_FRAGMENTATION, "Orb of Fragmentation",
+ SPTYP_CONJURATION | SPTYP_EARTH,
+ 7
+},
+
+{
+ SPELL_ICE_BOLT, "Ice Bolt",
+ SPTYP_CONJURATION | SPTYP_ICE,
+ 4
+},
+
+{
+ SPELL_ICE_STORM, "Ice Storm",
+ SPTYP_CONJURATION | SPTYP_ICE,
+ 9
+},
+
+{
+ SPELL_ARC, "Arc", // used by wanderers
+ SPTYP_AIR,
+ 1
+},
+
+{
+ SPELL_AIRSTRIKE, "Airstrike",
+ SPTYP_AIR,
+ 4
+},
+
+{
+ SPELL_SHADOW_CREATURES, "Shadow Creatures",
+ SPTYP_SUMMONING, // jmf: or SPTYP_SUMMONING | SPTYP_CONJURATION
+ 5
+}
+,
+
+{
+ SPELL_CONFUSING_TOUCH, "Confusing Touch",
+ SPTYP_ENCHANTMENT,
+ 1
+},
+
+{
+ SPELL_SURE_BLADE, "Sure Blade",
+ SPTYP_ENCHANTMENT,
+ 2
+},
+
+
+
+ //jmf: new spells
+
+
+{
+ SPELL_FLAME_TONGUE, "Flame Tongue",
+ SPTYP_CONJURATION | SPTYP_FIRE,
+ 1
+},
+
+{
+ SPELL_PASSWALL, "Passwall",
+ SPTYP_TRANSMIGRATION | SPTYP_EARTH,
+ 3
+},
+
+{
+ SPELL_IGNITE_POISON, "Ignite Poison",
+ SPTYP_FIRE | SPTYP_TRANSMIGRATION,
+ 7
+},
+
+{
+ SPELL_STICKS_TO_SNAKES, "Sticks to Snakes",
+ SPTYP_TRANSMIGRATION | SPTYP_SUMMONING,
+ 2
+},
+
+{
+ SPELL_SUMMON_LARGE_MAMMAL, "Call Canine Familiar",
+ SPTYP_SUMMONING,
+ 3
+},
+
+{
+ SPELL_SUMMON_DRAGON, "Summon Dragon",
+ SPTYP_FIRE | SPTYP_SUMMONING,
+ 9
+},
+
+{
+ SPELL_TAME_BEASTS, "Tame Beasts",
+ SPTYP_ENCHANTMENT,
+ 5
+},
+
+{
+ SPELL_SLEEP, "Ensorcelled Hibernation",
+ SPTYP_ENCHANTMENT | SPTYP_ICE,
+ 2
+},
+
+{
+ SPELL_MASS_SLEEP, "Metabolic Englaciation",
+ SPTYP_ENCHANTMENT | SPTYP_ICE,
+ 7
+},
+
+{
+ SPELL_DETECT_MAGIC, "Detect Magic",
+ SPTYP_DIVINATION,
+ 1
+},
+
+{
+ SPELL_DETECT_SECRET_DOORS, "Detect Secret Doors",
+ SPTYP_DIVINATION,
+ 1
+},
+
+{
+ SPELL_SEE_INVISIBLE, "See Invisible",
+ SPTYP_ENCHANTMENT | SPTYP_DIVINATION,
+ 4
+},
+
+{
+ SPELL_FORESCRY, "Forescry",
+ SPTYP_DIVINATION,
+ 5
+},
+
+{
+ SPELL_SUMMON_BUTTERFLIES, "Summon Butterflies",
+ SPTYP_SUMMONING,
+ 1
+},
+
+{
+ SPELL_WARP_BRAND, "Warp Weapon",
+ SPTYP_ENCHANTMENT | SPTYP_TRANSLOCATION,
+ 7 // this is high for a reason - Warp brands are very powerful.
+},
+
+{
+ SPELL_SILENCE, "Silence",
+ SPTYP_ENCHANTMENT | SPTYP_AIR,
+ 3
+},
+
+{
+ SPELL_SHATTER, "Shatter",
+ SPTYP_TRANSMIGRATION | SPTYP_EARTH,
+ 9
+},
+
+{
+ SPELL_DISPERSAL, "Dispersal",
+ SPTYP_TRANSLOCATION,
+ 7
+},
+
+{
+ SPELL_DISCHARGE, "Static Discharge",
+ SPTYP_CONJURATION | SPTYP_AIR,
+ 4
+},
+
+{
+ SPELL_BEND, "Bend",
+ SPTYP_TRANSLOCATION,
+ 1
+},
+
+{
+ SPELL_BACKLIGHT, "Corona",
+ SPTYP_ENCHANTMENT,
+ 1
+},
+
+{
+ SPELL_INTOXICATE, "Alistair's Intoxication",
+ SPTYP_TRANSMIGRATION | SPTYP_POISON,
+ 4
+},
+
+{
+ SPELL_GLAMOUR, "Glamour",
+ SPTYP_ENCHANTMENT,
+ 5
+},
+
+{
+ SPELL_EVAPORATE, "Evaporate",
+ SPTYP_FIRE | SPTYP_TRANSMIGRATION,
+ 2 // XXX: level 2 or 3, what should it be now? -- bwr
+},
+
+{
+ SPELL_ERINGYAS_SURPRISING_BOUQUET, "Eringya's Surprising Bouquet",
+ SPTYP_TRANSMIGRATION | SPTYP_EARTH,
+ 4
+},
+
+{
+ SPELL_FRAGMENTATION, "Lee's Rapid Deconstruction",
+ SPTYP_TRANSMIGRATION | SPTYP_EARTH,
+ 5
+},
+
+{
+ SPELL_AIR_WALK, "Air Walk",
+ SPTYP_TRANSMIGRATION | SPTYP_AIR,
+ 9
+},
+
+{
+ SPELL_SANDBLAST, "Sandblast",
+ SPTYP_TRANSMIGRATION | SPTYP_EARTH,
+ 1
+},
+
+{
+ SPELL_ROTTING, "Rotting",
+ SPTYP_TRANSMIGRATION | SPTYP_NECROMANCY,
+ 5
+},
+
+{
+ SPELL_SHUGGOTH_SEED, "Shuggoth Seed",
+ SPTYP_NECROMANCY | SPTYP_SUMMONING,
+ 7
+},
+
+{
+ SPELL_MAXWELLS_SILVER_HAMMER, "Maxwell's Silver Hammer",
+ SPTYP_ENCHANTMENT | SPTYP_EARTH,
+ 2
+},
+
+{
+ SPELL_CONDENSATION_SHIELD, "Condensation Shield",
+ SPTYP_ICE | SPTYP_TRANSMIGRATION,
+ 4
+},
+
+{
+ SPELL_SEMI_CONTROLLED_BLINK, "Semi-Controlled Blink",
+ SPTYP_TRANSLOCATION,
+ 3
+},
+
+{
+ SPELL_STONESKIN, "Stoneskin",
+ SPTYP_EARTH | SPTYP_TRANSMIGRATION, // was ench -- bwr
+ 2
+},
+
+{
+ SPELL_SIMULACRUM, "Simulacrum",
+ SPTYP_ICE | SPTYP_NECROMANCY,
+ 7
+},
+
+{
+ SPELL_CONJURE_BALL_LIGHTNING, "Conjure Ball Lightning",
+ SPTYP_AIR | SPTYP_CONJURATION,
+ 8
+},
+
+{
+ SPELL_FAR_STRIKE, "Far Strike",
+ SPTYP_TRANSLOCATION,
+ 3
+},
+
+{
+ SPELL_DELAYED_FIREBALL, "Delayed Fireball",
+ SPTYP_FIRE | SPTYP_CONJURATION,
+ 7
+},
+
+{
+ SPELL_FULSOME_DISTILLATION, "Fulsome Distillation",
+ SPTYP_TRANSMIGRATION | SPTYP_NECROMANCY,
+ 1
+},
+
+{
+ SPELL_POISON_ARROW, "Poison Arrow",
+ SPTYP_CONJURATION | SPTYP_POISON,
+ 6
+},
+
+{
+ SPELL_STRIKING, "Striking",
+ 0,
+ 1
+},
+
+{
+ SPELL_NO_SPELL, "nonexistent spell",
+ 0,
+ 0,
+},
+
+
+#endif
diff --git a/trunk/source/spl-util.cc b/trunk/source/spl-util.cc
new file mode 100644
index 0000000000..fa6e2d5885
--- /dev/null
+++ b/trunk/source/spl-util.cc
@@ -0,0 +1,786 @@
+/*
+ * File: spl-util.h *
+ * Summary: data handlers for player-avilable spell list *
+ * Written by: don brodale <dbrodale@bigfootinteractive.com> *
+ * *
+ * Changelog(most recent first): *
+ *
+ * <3> 04oct2001 bwr absorbed spells0.cc
+ * <2> 24jun2000 jmf changed to use new data structure
+ * <1> 12jun2000 dlb created after much thought
+ */
+
+#include "AppHdr.h"
+#include "spl-util.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <limits.h>
+
+#include "externs.h"
+
+#include "direct.h"
+#include "debug.h"
+#include "stuff.h"
+#include "itemname.h"
+#include "macro.h"
+#include "monstuff.h"
+#include "player.h"
+#include "spl-book.h"
+#include "view.h"
+
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+
+static struct playerspell spelldata[] = {
+#include "spl-data.h"
+};
+
+static int plyrspell_list[NUM_SPELLS];
+
+#define PLYRSPELLDATASIZE (sizeof(spelldata)/sizeof(struct playerspell))
+
+static struct playerspell *seekspell(int spellid);
+static bool cloud_helper( int (*func) (int, int, int, int), int x, int y,
+ int pow, int ctype );
+
+/*
+ * BEGIN PUBLIC FUNCTIONS
+ */
+
+// all this does is merely refresh the internal spell list {dlb}:
+void init_playerspells(void)
+{
+ unsigned int x = 0;
+
+ for (x = 0; x < NUM_SPELLS; x++)
+ plyrspell_list[x] = -1;
+
+ // can only use up to PLYRSPELLDATASIZE _MINUS ONE_, or the
+ // last entry tries to set plyrspell_list[SPELL_NO_SPELL]
+ // which corrupts the heap.
+ for (x = 0; x < PLYRSPELLDATASIZE - 1; x++)
+ plyrspell_list[spelldata[x].id] = x;
+
+ for (x = 0; x < NUM_SPELLS; x++)
+ {
+ if (plyrspell_list[x] == -1)
+ plyrspell_list[x] = plyrspell_list[SPELL_NO_SPELL];
+ }
+
+ return; // return value should not matter here {dlb}
+}; // end init_playerspells()
+
+int get_spell_slot_by_letter( char letter )
+{
+ ASSERT( isalpha( letter ) );
+
+ const int index = letter_to_index( letter );
+
+ if (you.spell_letter_table[ index ] == -1)
+ return (-1);
+
+ return (you.spell_letter_table[index]);
+}
+
+int get_spell_by_letter( char letter )
+{
+ ASSERT( isalpha( letter ) );
+
+ const int slot = get_spell_slot_by_letter( letter );
+
+ return ((slot == -1) ? SPELL_NO_SPELL : you.spells[slot]);
+}
+
+bool add_spell_to_memory( int spell )
+{
+ int i, j;
+
+ // first we find a slot in our head:
+ for (i = 0; i < 25; i++)
+ {
+ if (you.spells[i] == SPELL_NO_SPELL)
+ break;
+ }
+
+ you.spells[i] = spell;
+
+ // now we find an available label:
+ for (j = 0; j < 52; j++)
+ {
+ if (you.spell_letter_table[j] == -1)
+ break;
+ }
+
+ you.spell_letter_table[j] = i;
+
+ you.spell_no++;
+
+ return (true);
+}
+
+bool del_spell_from_memory_by_slot( int slot )
+{
+ int j;
+
+ you.spells[ slot ] = SPELL_NO_SPELL;
+
+ for (j = 0; j < 52; j++)
+ {
+ if (you.spell_letter_table[j] == slot)
+ you.spell_letter_table[j] = -1;
+
+ }
+
+ you.spell_no--;
+
+ return (true);
+}
+
+
+int spell_hunger(int which_spell)
+{
+ int level = seekspell(which_spell)->level;
+
+ switch (level)
+ {
+ case 1: return 50;
+ case 2: return 95;
+ case 3: return 160;
+ case 4: return 250;
+ case 5: return 350;
+ case 6: return 550;
+ case 7: return 700;
+ case 8: return 850;
+ case 9: return 1000;
+ case 10: return 1000;
+ case 11: return 1100;
+ case 12: return 1250;
+ case 13: return 1380;
+ case 14: return 1500;
+ case 15: return 1600;
+ default: return 1600 + (20 * level);
+ }
+} // end spell_hunger();
+
+// applied to spell misfires (more power = worse) and triggers
+// for Xom acting (more power = more likely to grab his attention) {dlb}
+int spell_mana(int which_spell)
+{
+ return (seekspell(which_spell)->level);
+}
+
+// applied in naughties (more difficult = higher level knowledge = worse)
+// and triggers for Sif acting (same reasoning as above, just good) {dlb}
+int spell_difficulty(int which_spell)
+{
+ return (seekspell(which_spell)->level);
+}
+
+int spell_levels_required( int which_spell )
+{
+ int levels = spell_difficulty( which_spell );
+
+ if (which_spell == SPELL_DELAYED_FIREBALL
+ && player_has_spell( SPELL_FIREBALL ))
+ {
+ levels -= spell_difficulty( SPELL_FIREBALL );
+ }
+ else if (which_spell == SPELL_FIREBALL
+ && player_has_spell( SPELL_DELAYED_FIREBALL ))
+ {
+ levels = 0;
+ }
+
+ return (levels);
+}
+
+bool spell_typematch(int which_spell, unsigned int which_discipline)
+{
+ return (seekspell(which_spell)->disciplines & which_discipline);
+}
+
+//jmf: next two for simple bit handling
+unsigned int spell_type(int spell)
+{
+ return (seekspell(spell)->disciplines);
+}
+
+int count_bits(unsigned int bits)
+{
+ unsigned int n;
+ int c = 0;
+
+ for (n = 1; n < INT_MAX; n <<= 1)
+ {
+ if (n & bits)
+ c++;
+ }
+
+ return (c);
+}
+
+// this will probably be used often, so rather than use malloc/free
+// (which may lead to memory fragmentation) I'll just use a static
+// array of characters -- if/when the String changeover takes place,
+// this will all shift, no doubt {dlb}
+/*
+ const char *spell_title( int which_spell )
+ {
+ static char this_title[41] = ""; // this is generous, to say the least {dlb}
+ strncpy(this_title, seekspell(which_spell)->title, 41);
+ // truncation better than overrun {dlb}
+ return ( this_title );
+ } // end spell_title()
+*/
+
+const char *spell_title(int spell) //jmf: ah the joys of driving ms. data
+{
+ return (seekspell(spell)->title);
+}
+
+
+// FUNCTION APPLICATORS: Idea from Juho Snellman <jsnell@lyseo.edu.ouka.fi>
+// on the Roguelike News pages, Development section.
+// <URL:http://www.skoardy.demon.co.uk/rlnews/>
+// Here are some function applicators: sort of like brain-dead,
+// home-grown iterators for the container "dungeon".
+
+// Apply a function-pointer to all visible squares
+// Returns summation of return values from passed in function.
+int apply_area_visible( int (*func) (int, int, int, int), int power )
+{
+ int x, y;
+ int rv = 0;
+
+ //jmf: FIXME: randomly start from other quadrants, like raise_dead?
+ for (x = you.x_pos - 8; x <= you.x_pos + 8; x++)
+ {
+ for (y = you.y_pos - 8; y <= you.y_pos + 8; y++)
+ {
+ if (see_grid(x, y))
+ rv += func(x, y, power, 0);
+ }
+ }
+
+ return (rv);
+} // end apply_area_visible()
+
+// Applies the effect to all nine squares around/including the target.
+// Returns summation of return values from passed in function.
+int apply_area_square( int (*func) (int, int, int, int), int cx, int cy,
+ int power )
+{
+ int x, y;
+ int rv = 0;
+
+ for (x = cx - 1; x <= cx + 1; x++)
+ {
+ for (y = cy - 1; y <= cy + 1; y++)
+ {
+ rv += func(x, y, power, 0);
+ }
+ }
+
+ return (rv);
+} // end apply_area_square()
+
+
+// Applies the effect to the eight squares beside the target.
+// Returns summation of return values from passed in function.
+int apply_area_around_square( int (*func) (int, int, int, int),
+ int targ_x, int targ_y, int power)
+{
+ int x, y;
+ int rv = 0;
+
+ for (x = targ_x - 1; x <= targ_x + 1; x++)
+ {
+ for (y = targ_y - 1; y <= targ_y + 1; y++)
+ {
+ if (x == targ_x && y == targ_y)
+ continue;
+ else
+ rv += func(x, y, power, 0);
+ }
+ }
+ return (rv);
+} // end apply_area_around_square()
+
+// Effect up to max_targs monsters around a point, chosen randomly
+// Return varies with the function called; return values will be added up.
+int apply_random_around_square( int (*func) (int, int, int, int),
+ int targ_x, int targ_y,
+ bool hole_in_middle, int power, int max_targs )
+{
+ int rv = 0;
+
+ if (max_targs <= 0)
+ return 0;
+
+ if (max_targs >= 9 && !hole_in_middle)
+ {
+ return (apply_area_square( func, targ_x, targ_y, power ));
+ }
+
+ if (max_targs >= 8 && hole_in_middle)
+ {
+ return (apply_area_around_square( func, targ_x, targ_y, power ));
+ }
+
+ FixedVector< coord_def, 8 > targs;
+ int count = 0;
+
+ for (int x = targ_x - 1; x <= targ_x + 1; x++)
+ {
+ for (int y = targ_y - 1; y <= targ_y + 1; y++)
+ {
+ if (hole_in_middle && (x == targ_x && y == targ_y))
+ continue;
+
+ if (mgrd[x][y] == NON_MONSTER
+ && !(x == you.x_pos && y == you.y_pos))
+ {
+ continue;
+ }
+
+ // Found target
+ count++;
+
+ // Slight differece here over the basic algorithm...
+ //
+ // For cases where the number of choices <= max_targs it's
+ // obvious (all available choices will be selected).
+ //
+ // For choices > max_targs, here's a brief proof:
+ //
+ // Let m = max_targs, k = choices - max_targs, k > 0.
+ //
+ // Proof, by induction (over k):
+ //
+ // 1) Show n = m + 1 (k = 1) gives uniform distribution,
+ // P(new one not chosen) = 1 / (m + 1).
+ // m 1 1
+ // P(specific previous one replaced) = --- * --- = ---
+ // m+1 m m+1
+ //
+ // So the probablity is uniform (ie. any element has
+ // a 1/(m+1) chance of being in the unchosen slot).
+ //
+ // 2) Assume the distribution is uniform at n = m+k.
+ // (ie. the probablity that any of the found elements
+ // was chosen = m / (m+k) (the slots are symetric,
+ // so it's the sum of the probabilities of being in
+ // any of them)).
+ //
+ // 3) Show n = m + k + 1 gives a uniform distribution.
+ // P(new one chosen) = m / (m + k + 1)
+ // P(any specific previous choice remaining chosen)
+ // = [1 - P(swaped into m+k+1 position)] * P(prev. chosen)
+ // m 1 m
+ // = [ 1 - ----- * --- ] * ---
+ // m+k+1 m m+k
+ //
+ // m+k m m
+ // = ----- * --- = -----
+ // m+k+1 m+k m+k+1
+ //
+ // Therefore, it's uniform for n = m + k + 1. QED
+ //
+ // The important thing to note in calculating the last
+ // probability is that the chosen elements have already
+ // passed tests which verify that they *don't* belong
+ // in slots m+1...m+k, so the only positions an already
+ // chosen element can end up in are it's original
+ // position (in one of the chosen slots), or in the
+ // new slot.
+ //
+ // The new item can, of course, be placed in any slot,
+ // swapping the value there into the new slot... we
+ // just don't care about the non-chosen slots enough
+ // to store them, so it might look like the item
+ // automatically takes the new slot when not chosen
+ // (although, by symetry all the non-chosen slots are
+ // the same... and similarly, by symetry, all chosen
+ // slots are the same).
+ //
+ // Yes, that's a long comment for a short piece of
+ // code, but I want people to have an understanding
+ // of why this works (or at least make them wary about
+ // changing it without proof and breaking this code). -- bwr
+
+ // Accept the first max_targs choices, then when
+ // new choices come up, replace one of the choices
+ // at random, max_targs/count of the time (the rest
+ // of the time it replaces an element in an unchosen
+ // slot -- but we don't care about them).
+ if (count <= max_targs)
+ {
+ targs[ count - 1 ].x = x;
+ targs[ count - 1 ].y = y;
+ }
+ else if (random2( count ) < max_targs)
+ {
+ const int pick = random2( max_targs );
+ targs[ pick ].x = x;
+ targs[ pick ].y = y;
+ }
+ }
+ }
+
+ const int targs_found = (count < max_targs) ? count : max_targs;
+
+ if (targs_found)
+ {
+ // Used to divide the power up among the targets here, but
+ // it's probably better to allow the full power through and
+ // balance the called function. -- bwr
+ for (int i = 0; i < targs_found; i++)
+ {
+ ASSERT( targs[i].x && targs[i].y );
+ rv += func( targs[i].x, targs[i].y, power, 0 );
+ }
+ }
+
+ return (rv);
+} // end apply_random_around_square()
+
+// apply func to one square of player's choice beside the player
+int apply_one_neighbouring_square(int (*func) (int, int, int, int), int power)
+{
+ struct dist bmove;
+
+ mpr("Which direction? [ESC to cancel]", MSGCH_PROMPT);
+ direction( bmove, DIR_DIR, TARG_ENEMY );
+
+ if (!bmove.isValid)
+ {
+ canned_msg(MSG_SPELL_FIZZLES);
+ return (0);
+ }
+
+ int rv = func(you.x_pos + bmove.dx, you.y_pos + bmove.dy, power, 1);
+
+ if (rv == 0)
+ canned_msg(MSG_NOTHING_HAPPENS);
+
+ return (rv);
+} // end apply_one_neighbouring_square()
+
+int apply_area_within_radius( int (*func) (int, int, int, int),
+ int x, int y, int pow, int radius, int ctype )
+{
+ int ix, iy;
+ int sq_radius = radius * radius;
+ int sx, sy, ex, ey; // start and end x, y - bounds checked
+ int rv = 0;
+
+ // begin x,y
+ sx = x - radius;
+ sy = y - radius;
+ if (sx < 0) sx = 0;
+ if (sy < 0) sy = 0;
+
+ // end x,y
+ ex = x + radius;
+ ey = y + radius;
+ if (ex > GXM) ex = GXM;
+ if (ey > GYM) ey = GYM;
+
+ for (ix = sx; ix < ex; ix++)
+ {
+ for (iy = sy; iy < ey; iy++)
+ {
+ if (distance(x, y, ix, iy) <= sq_radius)
+ rv += func(ix, iy, pow, ctype);
+ }
+ }
+
+ return (rv);
+} // end apply_area_within_radius()
+
+// apply_area_cloud:
+// Try to make a realistic cloud by expanding from a point, filling empty
+// floor tiles until we run out of material (passed in as number).
+// We really need some sort of a queue structure, since ideally I'd like
+// to do a (shallow) breadth-first-search of the dungeon floor.
+// This ought to work okay for small clouds.
+void apply_area_cloud( int (*func) (int, int, int, int), int x, int y,
+ int pow, int number, int ctype )
+{
+ int spread, clouds_left = number;
+ int good_squares = 0, neighbours[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ int dx = 1, dy = 1;
+ bool x_first;
+
+ if (clouds_left && cloud_helper(func, x, y, pow, ctype))
+ clouds_left--;
+
+ if (!clouds_left)
+ return;
+
+ if (coinflip())
+ dx *= -1;
+ if (coinflip())
+ dy *= -1;
+
+ x_first = coinflip();
+
+ if (x_first)
+ {
+ if (clouds_left && cloud_helper(func, x + dx, y, pow, ctype))
+ {
+ clouds_left--;
+ good_squares++;
+ neighbours[0]++;
+ }
+
+ if (clouds_left && cloud_helper(func, x - dx, y, pow, ctype))
+ {
+ clouds_left--;
+ good_squares++;
+ neighbours[1]++;
+ }
+
+ if (clouds_left && cloud_helper(func, x, y + dy, pow, ctype))
+ {
+ clouds_left--;
+ good_squares++;
+ neighbours[2]++;
+ }
+
+ if (clouds_left && cloud_helper(func, x, y - dy, pow, ctype))
+ {
+ clouds_left--;
+ good_squares++;
+ neighbours[3]++;
+ }
+ }
+ else
+ {
+ if (clouds_left && cloud_helper(func, x, y + dy, pow, ctype))
+ {
+ clouds_left--;
+ good_squares++;
+ neighbours[2]++;
+ }
+
+ if (clouds_left && cloud_helper(func, x, y - dy, pow, ctype))
+ {
+ clouds_left--;
+ good_squares++;
+ neighbours[3]++;
+ }
+
+ if (clouds_left && cloud_helper(func, x + dx, y, pow, ctype))
+ {
+ clouds_left--;
+ good_squares++;
+ neighbours[0]++;
+ }
+
+ if (clouds_left && cloud_helper(func, x - dx, y, pow, ctype))
+ {
+ clouds_left--;
+ good_squares++;
+ neighbours[1]++;
+ }
+ }
+
+ // now diagonals; we could randomize dx & dy again here
+ if (clouds_left && cloud_helper(func, x + dx, y + dy, pow, ctype))
+ {
+ clouds_left--;
+ good_squares++;
+ neighbours[4]++;
+ }
+
+ if (clouds_left && cloud_helper(func, x - dx, y + dy, pow, ctype))
+ {
+ clouds_left--;
+ good_squares++;
+ neighbours[5]++;
+ }
+
+ if (clouds_left && cloud_helper(func, x + dx, y - dy, pow, ctype))
+ {
+ clouds_left--;
+ good_squares++;
+ neighbours[6]++;
+ }
+
+ if (clouds_left && cloud_helper(func, x - dx, y - dy, pow, ctype))
+ {
+ clouds_left--;
+ good_squares++;
+ neighbours[7]++;
+ }
+
+ if (!(clouds_left && good_squares))
+ return;
+
+ for (int i = 0; i < 8 && clouds_left; i++)
+ {
+ if (neighbours[i] == 0)
+ continue;
+
+ spread = clouds_left / good_squares;
+ clouds_left -= spread;
+ good_squares--;
+
+ switch (i)
+ {
+ case 0:
+ apply_area_cloud(func, x + dx, y, pow, spread, ctype);
+ break;
+ case 1:
+ apply_area_cloud(func, x - dx, y, pow, spread, ctype);
+ break;
+ case 2:
+ apply_area_cloud(func, x, y + dy, pow, spread, ctype);
+ break;
+ case 3:
+ apply_area_cloud(func, x, y - dy, pow, spread, ctype);
+ break;
+ case 4:
+ apply_area_cloud(func, x + dx, y + dy, pow, spread, ctype);
+ break;
+ case 5:
+ apply_area_cloud(func, x - dx, y + dy, pow, spread, ctype);
+ break;
+ case 6:
+ apply_area_cloud(func, x + dx, y - dy, pow, spread, ctype);
+ break;
+ case 7:
+ apply_area_cloud(func, x - dx, y - dy, pow, spread, ctype);
+ break;
+ }
+ }
+} // end apply_area_cloud()
+
+char spell_direction( struct dist &spelld, struct bolt &pbolt,
+ int restrict, int mode )
+{
+ if (restrict == DIR_TARGET)
+ mpr( "Choose a target (+/- for next/prev monster)", MSGCH_PROMPT );
+ else
+ mpr( STD_DIRECTION_PROMPT, MSGCH_PROMPT );
+
+ message_current_target();
+
+ direction( spelld, restrict, mode );
+
+ if (!spelld.isValid)
+ {
+ // check for user cancel
+ canned_msg(MSG_SPELL_FIZZLES);
+ return -1;
+ }
+
+ pbolt.target_x = spelld.tx;
+ pbolt.target_y = spelld.ty;
+ pbolt.source_x = you.x_pos;
+ pbolt.source_y = you.y_pos;
+
+ return 1;
+} // end spell_direction()
+
+const char *spelltype_name(unsigned int which_spelltype)
+{
+ static char bug_string[80];
+
+ switch (which_spelltype)
+ {
+ case SPTYP_CONJURATION:
+ return ("Conjuration");
+ case SPTYP_ENCHANTMENT:
+ return ("Enchantment");
+ case SPTYP_FIRE:
+ return ("Fire");
+ case SPTYP_ICE:
+ return ("Ice");
+ case SPTYP_TRANSMIGRATION:
+ return ("Transmigration");
+ case SPTYP_NECROMANCY:
+ return ("Necromancy");
+ case SPTYP_HOLY:
+ return ("Holy");
+ case SPTYP_SUMMONING:
+ return ("Summoning");
+ case SPTYP_DIVINATION:
+ return ("Divination");
+ case SPTYP_TRANSLOCATION:
+ return ("Translocation");
+ case SPTYP_POISON:
+ return ("Poison");
+ case SPTYP_EARTH:
+ return ("Earth");
+ case SPTYP_AIR:
+ return ("Air");
+ default:
+ snprintf( bug_string, sizeof(bug_string),
+ "invalid(%d)", which_spelltype );
+
+ return (bug_string);
+ }
+} // end spelltype_name()
+
+int spell_type2skill(unsigned int spelltype)
+{
+ char buffer[80];
+
+ switch (spelltype)
+ {
+ case SPTYP_CONJURATION: return (SK_CONJURATIONS);
+ case SPTYP_ENCHANTMENT: return (SK_ENCHANTMENTS);
+ case SPTYP_FIRE: return (SK_FIRE_MAGIC);
+ case SPTYP_ICE: return (SK_ICE_MAGIC);
+ case SPTYP_TRANSMIGRATION: return (SK_TRANSMIGRATION);
+ case SPTYP_NECROMANCY: return (SK_NECROMANCY);
+ case SPTYP_SUMMONING: return (SK_SUMMONINGS);
+ case SPTYP_DIVINATION: return (SK_DIVINATIONS);
+ case SPTYP_TRANSLOCATION: return (SK_TRANSLOCATIONS);
+ case SPTYP_POISON: return (SK_POISON_MAGIC);
+ case SPTYP_EARTH: return (SK_EARTH_MAGIC);
+ case SPTYP_AIR: return (SK_AIR_MAGIC);
+
+ default:
+ case SPTYP_HOLY:
+ snprintf( buffer, sizeof(buffer),
+ "spell_type2skill: called with spelltype %d", spelltype );
+
+ mpr( buffer );
+ return (-1);
+ }
+} // end spell_type2skill()
+
+/*
+ **************************************************
+ * *
+ * END PUBLIC FUNCTIONS *
+ * *
+ **************************************************
+ */
+
+//jmf: simplified; moved init code to top function, init_playerspells()
+static struct playerspell *seekspell(int spell)
+{
+ return (&spelldata[plyrspell_list[spell]]);
+}
+
+static bool cloud_helper( int (*func) (int, int, int, int), int x, int y,
+ int pow, int ctype )
+{
+ if (grd[x][y] > DNGN_LAST_SOLID_TILE && env.cgrid[x][y] == EMPTY_CLOUD)
+ {
+ func(x, y, pow, ctype);
+ return true;
+ }
+
+ return false;
+}
diff --git a/trunk/source/spl-util.h b/trunk/source/spl-util.h
new file mode 100644
index 0000000000..848530dbbf
--- /dev/null
+++ b/trunk/source/spl-util.h
@@ -0,0 +1,87 @@
+/*
+ * File: spl-util.h
+ * Summary: data handlers for player spell list
+ * Written by: don brodale <dbrodale@bigfootinteractive.com>
+ *
+ * Changelog(most recent first):
+ *
+ * 24jun2000 jmf simplified structures
+ * <00> 12jun2000 dlb created after much thought
+ */
+
+
+#ifndef SPL_UTIL_H
+#define SPL_UTIL_H
+
+#include "enum.h" // just for NUM_SPELL_TYPES and TARG_ENEMY
+#include "direct.h" // just for DIR_NONE
+
+struct playerspell
+{
+ int id;
+ const char *title;
+ unsigned int disciplines; //jmf: a bitfield
+ unsigned int level;
+};
+
+
+//* * called from: acr
+void init_playerspells(void);
+
+int get_spell_slot_by_letter( char letter );
+int get_spell_by_letter( char letter );
+
+bool add_spell_to_memory( int spell );
+bool del_spell_from_memory_by_slot( int slot );
+
+// * called from: spell
+int spell_hunger(int which_spell);
+
+// * called from: it_use3 - spell - spells3
+int spell_mana(int which_spell);
+
+// * called from: chardump - it_use3 - player - spell - spl-book -
+// * spells0 - spells3
+int spell_difficulty(int which_spell);
+
+int spell_levels_required(int which_spell);
+
+// * called from: chardump - spell - spl-book - spells0
+bool spell_typematch(int which_spell, unsigned int which_discipline);
+unsigned int spell_type( int which_spell ); //jmf: simplification of above
+int count_bits( unsigned int bits );
+
+// * called from: chardump - command - debug - spl-book - spells0
+const char *spell_title(int which_spell);
+
+//int spell_restriction(int which_spell, int which_restriction);
+
+int apply_area_visible(int (*func) (int, int, int, int), int power);
+
+int apply_area_square(int (*func) (int, int, int, int),
+ int cx, int cy, int power);
+
+int apply_area_around_square( int (*func) (int, int, int, int),
+ int targ_x, int targ_y, int power );
+
+int apply_random_around_square( int (*func) (int, int, int, int),
+ int targ_x, int targ_y, bool hole_in_middle,
+ int power, int max_targs );
+
+int apply_one_neighbouring_square(int (*func) (int, int, int, int),
+ int power);
+
+int apply_area_within_radius(int (*func) (int, int, int, int),
+ int x, int y, int pow, int radius, int ctype);
+
+char spell_direction( struct dist &spelld, struct bolt &pbolt,
+ int restrict = DIR_NONE, int mode = TARG_ENEMY );
+
+void apply_area_cloud(int (*func) (int, int, int, int), int x, int y,
+ int pow, int number, int ctype);
+
+const char *spelltype_name(unsigned int which_spelltype);
+
+int spell_type2skill (unsigned int which_spelltype);
+
+#endif
diff --git a/trunk/source/stuff.cc b/trunk/source/stuff.cc
new file mode 100644
index 0000000000..4ad0e2a394
--- /dev/null
+++ b/trunk/source/stuff.cc
@@ -0,0 +1,661 @@
+/*
+ * File: stuff.cc
+ * Summary: Misc stuff.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <4> 11/14/99 cdl added random40(), made arg to random*() signed
+ * <3> 11/06/99 cdl added random22()
+ * <2> 9/25/99 cdl linuxlib -> liblinux
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "stuff.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+// may need this later for something else {dlb}:
+// required for table_lookup() {dlb}
+//#include <stdarg.h>
+// required for table_lookup() {dlb}
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#ifdef LINUX
+#include "liblinux.h"
+#endif
+
+#include "externs.h"
+
+#include "macro.h"
+#include "misc.h"
+#include "monstuff.h"
+#include "mon-util.h"
+#include "output.h"
+#include "skills2.h"
+#include "view.h"
+
+
+// required for stuff::coinflip() and cf_setseed()
+unsigned long cfseed;
+
+// unfortunately required for near_stairs(ugh!):
+extern unsigned char (*mapch) (unsigned char);
+
+// Crude, but functional.
+char *const make_time_string( time_t abs_time, char *const buff, int buff_size )
+{
+ const int days = abs_time / 86400;
+ const int hours = (abs_time % 86400) / 3600;
+ const int mins = (abs_time % 3600) / 60;
+ const int secs = abs_time % 60;
+
+ char day_buff[32];
+
+ if (days > 0)
+ {
+ snprintf( day_buff, sizeof(day_buff), "%d day%s, ",
+ days, (days > 1) ? "s" : "" );
+ }
+
+ snprintf( buff, buff_size, "%s%02d:%02d:%02d",
+ (days > 0) ? day_buff : "", hours, mins, secs );
+
+ return (buff);
+}
+
+void set_redraw_status( unsigned long flags )
+{
+ you.redraw_status_flags |= flags;
+}
+
+void tag_followers( void )
+{
+ int count_x, count_y;
+
+ for (count_x = you.x_pos - 1; count_x <= you.x_pos + 1; count_x++)
+ {
+ for (count_y = you.y_pos - 1; count_y <= you.y_pos + 1; count_y++)
+ {
+ if (count_x == you.x_pos && count_y == you.y_pos)
+ continue;
+
+ if (mgrd[count_x][count_y] == NON_MONSTER)
+ continue;
+
+ struct monsters *fmenv = &menv[mgrd[count_x][count_y]];
+
+ if ((fmenv->type == MONS_PANDEMONIUM_DEMON)
+ || (fmenv->type == MONS_PLANT)
+ || (fmenv->type == MONS_FUNGUS)
+ || (fmenv->type == MONS_OKLOB_PLANT)
+ || (fmenv->type == MONS_CURSE_SKULL)
+ || (fmenv->type == MONS_PLAYER_GHOST) // cdl
+ || (fmenv->type == MONS_CURSE_TOE)
+ || (fmenv->type == MONS_POTION_MIMIC)
+ || (fmenv->type == MONS_WEAPON_MIMIC)
+ || (fmenv->type == MONS_ARMOUR_MIMIC)
+ || (fmenv->type == MONS_SCROLL_MIMIC)
+ || (fmenv->type == MONS_GOLD_MIMIC)
+ || (fmenv->type == -1))
+ {
+ continue;
+ }
+
+ if (monster_habitat(fmenv->type) != DNGN_FLOOR)
+ continue;
+
+ if (fmenv->speed_increment < 50)
+ continue;
+
+ // only friendly monsters, or those actively seeking the
+ // player, will follow up/down stairs.
+ if (!(mons_friendly(fmenv) ||
+ (fmenv->behaviour == BEH_SEEK && fmenv->foe == MHITYOU)))
+ {
+ continue;
+ }
+
+ // monster is chasing player through stairs:
+ fmenv->flags |= MF_TAKING_STAIRS;
+
+#if DEBUG_DIAGNOSTICS
+ snprintf( info, INFO_SIZE, "%s is marked for following.",
+ ptr_monam( fmenv, DESC_CAP_THE ) );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+ }
+ }
+}
+
+void untag_followers( void )
+{
+ for (int m = 0; m < MAX_MONSTERS; m++)
+ {
+ struct monsters *mon = &menv[m];
+ mon->flags &= (~MF_TAKING_STAIRS);
+ }
+}
+
+unsigned char get_ch(void)
+{
+ unsigned char gotched = getch();
+
+ if (gotched == 0)
+ gotched = getch();
+
+ return gotched;
+} // end get_ch()
+
+int random2(int max)
+{
+#ifdef USE_NEW_RANDOM
+ //return (int) ((((float) max) * rand()) / RAND_MAX); - this is bad!
+ // Uses FP, so is horribly slow on computers without coprocessors.
+ // Taken from comp.lang.c FAQ. May have problems as max approaches
+ // RAND_MAX, but this is rather unlikely.
+ // We've used rand() rather than random() for the portability, I think.
+
+ if (max < 1 || max >= RAND_MAX)
+ return 0;
+ else
+ return (int) rand() / (RAND_MAX / max + 1);
+#else
+
+ if (max < 1)
+ return 0;
+
+ return rand() % max;
+#endif
+}
+
+// random2avg() returns same mean value as random2() but with a lower variance
+// never use with rolls < 2 as that would be silly - use random2() instead {dlb}
+int random2avg(int max, int rolls)
+{
+ int sum = 0;
+
+ sum += random2(max);
+
+ for (int i = 0; i < (rolls - 1); i++)
+ {
+ sum += random2(max + 1);
+ }
+
+ return (sum / rolls);
+}
+
+int roll_dice( int num, int size )
+{
+ int ret = 0;
+ int i;
+
+ // If num <= 0 or size <= 0, then we'll just return the default
+ // value of zero. This is good behaviour in that it will be
+ // appropriate for calculated values that might be passed in.
+ if (num > 0 && size > 0)
+ {
+ ret += num; // since random2() is zero based
+
+ for (i = 0; i < num; i++)
+ ret += random2( size );
+ }
+
+ return (ret);
+}
+
+int roll_dice( const struct dice_def &dice )
+{
+ return (roll_dice( dice.num, dice.size ));
+}
+
+// originally designed to randomize evasion -
+// values are slightly lowered near (max) and
+// approach an upper limit somewhere near (limit/2)
+int random2limit(int max, int limit)
+{
+ int i;
+ int sum = 0;
+
+ if (max < 1)
+ return 0;
+
+ for (i = 0; i < max; i++)
+ {
+ if (random2(limit) >= i)
+ sum++;
+ }
+
+ return sum;
+} // end random2limit()
+
+// answers the question: "Is a grid within character's line of sight?"
+bool see_grid(unsigned char grx, unsigned char gry)
+{
+ if (grx > you.x_pos - 9 && grx < you.x_pos + 9
+ && gry > you.y_pos - 9 && gry < you.y_pos + 9)
+ {
+ if (env.show[grx - you.x_pos + 9][gry - you.y_pos + 9] != 0)
+ return true;
+
+ // rare case: can player see self? (of course!)
+ if (grx == you.x_pos && gry == you.y_pos)
+ return true;
+ }
+
+ return false;
+} // end see_grid()
+
+void end(int end_arg)
+{
+#ifdef LINUX
+ lincurses_shutdown();
+#endif
+
+#ifdef MAC
+ deinit_mac();
+#endif
+
+#ifdef WIN32CONSOLE
+ deinit_libw32c();
+#endif
+
+ exit(end_arg);
+}
+
+void redraw_screen(void)
+{
+#ifdef PLAIN_TERM
+// this function is used for systems without gettext/puttext to redraw the
+// playing screen after a call to for example inventory.
+ draw_border();
+
+ you.redraw_hit_points = 1;
+ you.redraw_magic_points = 1;
+ you.redraw_strength = 1;
+ you.redraw_intelligence = 1;
+ you.redraw_dexterity = 1;
+ you.redraw_armour_class = 1;
+ you.redraw_evasion = 1;
+ you.redraw_gold = 1;
+ you.redraw_experience = 1;
+ you.wield_change = true;
+
+ set_redraw_status( REDRAW_LINE_1_MASK | REDRAW_LINE_2_MASK | REDRAW_LINE_3_MASK );
+
+ print_stats();
+
+ if (Options.delay_message_clear)
+ mesclr( true );
+
+ new_level();
+
+ viewwindow(1, false);
+#endif
+} // end redraw_screen()
+
+// STEPDOWN FUNCTION to replace conditional chains in spells2.cc 12jan2000 {dlb}
+// it is a bit more extensible and optimizes the logical structure, as well
+// usage: summon_swarm() summon_undead() summon_scorpions() summon_things()
+// ex(1): stepdown_value (foo, 2, 2, 6, 8) replaces the following block:
+//
+
+/*
+ if (foo > 2)
+ foo = (foo - 2) / 2 + 2;
+ if (foo > 4)
+ foo = (foo - 4) / 2 + 4;
+ if (foo > 6)
+ foo = (foo - 6) / 2 + 6;
+ if (foo > 8)
+ foo = 8;
+ */
+
+//
+// ex(2): bar = stepdown_value(bar, 2, 2, 6, -1) replaces the following block:
+//
+
+/*
+ if (bar > 2)
+ bar = (bar - 2) / 2 + 2;
+ if (bar > 4)
+ bar = (bar - 4) / 2 + 4;
+ if (bar > 6)
+ bar = (bar - 6) / 2 + 6;
+ */
+
+// I hope this permits easier/more experimentation with value stepdowns in
+// the code it really needs to be rewritten to accept arbitrary (unevenly
+// spaced) steppings
+int stepdown_value(int base_value, int stepping, int first_step,
+ int last_step, int ceiling_value)
+{
+ int return_value = base_value;
+
+ // values up to the first "step" returned unchanged:
+ if (return_value <= first_step)
+ return return_value;
+
+ for (int this_step = first_step; this_step <= last_step;
+ this_step += stepping)
+ {
+ if (return_value > this_step)
+ return_value = ((return_value - this_step) / 2) + this_step;
+ else
+ break; // exit loop iff value fully "stepped down"
+ }
+
+ // "no final ceiling" == -1
+ if (ceiling_value != -1 && return_value > ceiling_value)
+ return ceiling_value; // highest value to return is "ceiling"
+ else
+ return return_value; // otherwise, value returned "as is"
+
+} // end stepdown_value()
+
+
+// I got so tired of seeing: ".. && random2(foo) == 0 && .." in the code
+// that I broke down and wrote this little -- very little -- function.
+// anyway, I think improving the readability of the code offsets whatever
+// overhead the additional (intermediary) function call added to Crawl -
+// we'll just make it up by tightening code elsewhere, right guys?
+// [use with == and != only .. never directly with comparisons or math]
+// -- 14jan2000 {dlb}
+bool one_chance_in(int a_million)
+{
+ return (random2(a_million) == 0);
+} // end one_chance_in() - that's it? :P {dlb}
+
+// I got to thinking a bit more about how much people talk
+// about RNGs and RLs and also about the issue of performance
+// when it comes to Crawl's RNG ... turning to *Numerical
+// Recipies in C* (Chapter 7-4, page 298), I hit upon what
+// struck me as a fine solution.
+
+// You can read all the details about this function (pretty
+// much stolen shamelessly from NRinC) elsewhere, but having
+// tested it out myself I think it satisfies Crawl's incessant
+// need to decide things on a 50-50 flip of the coin. No call
+// to random2() required -- along with all that wonderful math
+// and type casting -- and only a single variable its pointer,
+// and some bitwise operations to randomly generate 1s and 0s!
+// No parameter passing, nothing. Too good to be true, but it
+// works as long as cfseed is not set to absolute zero when it
+// is initialized ... good for 2**n-1 random bits before the
+// pattern repeats (n = long's bitlength on your platform).
+// It also avoids problems with poor implementations of rand()
+// on some platforms in regards to low-order bits ... a big
+// problem if one is only looking for a 1 or a 0 with random2()!
+
+// Talk about a hard sell! Anyway, it returns bool, so please
+// use appropriately -- I set it to bool to prevent such
+// tomfoolery, as I think that pure RNG and quickly grabbing
+// either a value of 1 or 0 should be separated where possible
+// to lower overhead in Crawl ... at least until it assembles
+// itself into something a bit more orderly :P 16jan2000 {dlb}
+
+// NB(1): cfseed is defined atop stuff.cc
+// NB(2): IB(foo) and MASK are defined somewhere in defines.h
+// NB(3): the function assumes that cf_setseed() has been called
+// beforehand - the call is presently made in acr::initialise()
+// right after srandom() and srand() are called (note also
+// that cf_setseed() requires rand() - random2 returns int
+// but a long can't hurt there).
+bool coinflip(void)
+{
+ extern unsigned long cfseed; // defined atop stuff.cc
+ unsigned long *ptr_cfseed = &cfseed;
+
+ if (*ptr_cfseed & IB18)
+ {
+ *ptr_cfseed = ((*ptr_cfseed ^ MASK) << 1) | IB1;
+ return true;
+ }
+ else
+ {
+ *ptr_cfseed <<= 1;
+ return false;
+ }
+} // end coinflip()
+
+// cf_setseed should only be called but once in all of Crawl!!! {dlb}
+void cf_setseed(void)
+{
+ extern unsigned long cfseed; // defined atop stuff.cc
+ unsigned long *ptr_cfseed = &cfseed;
+
+ do
+ {
+ // using rand() here makes these predictable -- bwr
+ *ptr_cfseed = rand();
+ }
+ while (*ptr_cfseed == 0);
+}
+
+// simple little function to quickly modify all three stats
+// at once - does check for '0' modifiers to prevent needless
+// adding .. could use checking for sums less than zero, I guess.
+// used in conjunction with newgame::species_stat_init() and
+// newgame::job_stat_init() routines 24jan2000 {dlb}
+void modify_all_stats(int STmod, int IQmod, int DXmod)
+{
+ if (STmod)
+ {
+ you.strength += STmod;
+ you.max_strength += STmod;
+ you.redraw_strength = 1;
+ }
+
+ if (IQmod)
+ {
+ you.intel += IQmod;
+ you.max_intel += IQmod;
+ you.redraw_intelligence = 1;
+ }
+
+ if (DXmod)
+ {
+ you.dex += DXmod;
+ you.max_dex += DXmod;
+ you.redraw_dexterity = 1;
+ }
+
+ return;
+} // end modify_stat()
+
+void canned_msg(unsigned char which_message)
+{
+ switch (which_message)
+ {
+ case MSG_SOMETHING_APPEARS:
+ strcpy(info, "Something appears ");
+ strcat(info, (you.species == SP_NAGA || you.species == SP_CENTAUR)
+ ? "before you" : "at your feet");
+ strcat(info, "!");
+ mpr(info);
+ break;
+
+ case MSG_NOTHING_HAPPENS:
+ mpr("Nothing appears to happen.");
+ break;
+ case MSG_YOU_RESIST:
+ mpr("You resist.");
+ break;
+ case MSG_TOO_BERSERK:
+ mpr("You are too berserk!");
+ break;
+ case MSG_NOTHING_CARRIED:
+ mpr("You aren't carrying anything.");
+ break;
+ case MSG_CANNOT_DO_YET:
+ mpr("You can't do that yet.");
+ break;
+ case MSG_OK:
+ mpr("Okay, then.");
+ break;
+ case MSG_UNTHINKING_ACT:
+ mpr("Why would you want to do that?");
+ break;
+ case MSG_SPELL_FIZZLES:
+ mpr("The spell fizzles.");
+ break;
+ case MSG_HUH:
+ mpr("Huh?");
+ break;
+ case MSG_EMPTY_HANDED:
+ mpr("You are now empty-handed.");
+ break;
+ }
+
+ return;
+} // end canned_msg()
+
+// jmf: general helper (should be used all over in code)
+// -- idea borrowed from Nethack
+bool yesno( const char *str, bool safe, bool clear_after )
+{
+ unsigned char tmp;
+
+ for (;;)
+ {
+ mpr(str, MSGCH_PROMPT);
+
+ tmp = (unsigned char) getch();
+
+ if (Options.easy_confirm == CONFIRM_ALL_EASY
+ || (Options.easy_confirm == CONFIRM_SAFE_EASY && safe))
+ {
+ tmp = toupper( tmp );
+ }
+
+ if (clear_after)
+ mesclr();
+
+ if (tmp == 'N')
+ return false;
+ else if (tmp == 'Y')
+ return true;
+ else
+ mpr("[Y]es or [N]o only, please.");
+ }
+} // end yesno()
+
+// More accurate than distance() given the actual movement geonmetry -- bwr
+int grid_distance( int x, int y, int x2, int y2 )
+{
+ const int dx = abs( x - x2 );
+ const int dy = abs( y - y2 );
+
+ // returns distance in terms of moves:
+ return ((dx > dy) ? dx : dy);
+}
+
+int distance( int x, int y, int x2, int y2 )
+{
+ //jmf: now accurate, but remember to only compare vs. pre-squared distances.
+ // thus, next to == (distance(m1.x,m1.y, m2.x,m2.y) <= 2)
+ const int dx = x - x2;
+ const int dy = y - y2;
+
+ return ((dx * dx) + (dy * dy));
+} // end distance()
+
+bool adjacent( int x, int y, int x2, int y2 )
+{
+ return (abs(x - x2) <= 1 && abs(y - y2) <= 1);
+}
+
+bool silenced(char x, char y)
+{
+#ifdef USE_SILENCE_CODE
+
+ if (you.duration[DUR_SILENCE] > 0
+ && distance(x, y, you.x_pos, you.y_pos) <= 36) // (6 * 6)
+ {
+ return true;
+ }
+ else
+ {
+ //else // FIXME: implement, and let monsters cast, too
+ // for (int i = 0; i < MAX_SILENCES; i++)
+ // {
+ // if (distance(x, y, silencer[i].x, silencer[i].y) <= 36)
+ // return true;
+ // }
+ return false;
+ }
+
+#else
+ return false;
+#endif
+} // end silenced()
+
+bool player_can_hear(char x, char y)
+{
+#ifdef USE_SILENCE_CODE
+ return (!silenced(x, y) && !silenced(you.x_pos, you.y_pos));
+#else
+ return true;
+#endif
+} // end player_can_hear()
+
+unsigned char random_colour(void)
+{
+ return (1 + random2(15));
+} // end random_colour()
+
+char index_to_letter(int the_index)
+{
+ return (the_index + ((the_index < 26) ? 'a' : ('A' - 26)));
+} // end index_to_letter()
+
+int letter_to_index(int the_letter)
+{
+ if (the_letter >= 'a' && the_letter <= 'z')
+ // returns range [0-25] {dlb}
+ the_letter -= 'a';
+ else if (the_letter >= 'A' && the_letter <= 'Z')
+ // returns range [26-51] {dlb}
+ the_letter -= ('A' - 26);
+
+ return the_letter;
+} // end letter_to_index()
+
+// returns 0 if the point is not near stairs
+// returns 1 if the point is near unoccupied stairs
+// returns 2 if the point is near player-occupied stairs
+
+int near_stairs(int px, int py, int max_dist, unsigned char &stair_gfx)
+{
+ int i,j;
+
+ for(i=-max_dist; i<=max_dist; i++)
+ {
+ for(j=-max_dist; j<=max_dist; j++)
+ {
+ int x = px + i;
+ int y = py + j;
+
+ if (x<0 || x>=GXM || y<0 || y>=GYM)
+ continue;
+
+ // very simple check
+ if (grd[x][y] >= DNGN_STONE_STAIRS_DOWN_I
+ && grd[x][y] <= DNGN_RETURN_FROM_SWAMP
+ && grd[x][y] != DNGN_ENTER_SHOP) // silly
+ {
+ stair_gfx = mapch(grd[x][y]);
+ return ((x == you.x_pos && y == you.y_pos) ? 2 : 1);
+ }
+ }
+ }
+
+ return false;
+}
diff --git a/trunk/source/stuff.h b/trunk/source/stuff.h
new file mode 100644
index 0000000000..88fc11fb53
--- /dev/null
+++ b/trunk/source/stuff.h
@@ -0,0 +1,197 @@
+/*
+ * File: stuff.cc
+ * Summary: Misc stuff.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <3> 11/14/99 cdl added random40
+ * <2> 11/06/99 cdl added random22
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef STUFF_H
+#define STUFF_H
+
+#include "externs.h"
+
+char *const make_time_string(time_t abs_time, char *const buff, int buff_size);
+
+void set_redraw_status( unsigned long flags );
+
+void tag_followers( void );
+void untag_followers( void );
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void cf_setseed(void);
+
+
+/* ***********************************************************************
+ * called from: xxx
+ * *********************************************************************** */
+bool coinflip(void);
+
+
+/* ***********************************************************************
+ * called from: xxx
+ * *********************************************************************** */
+bool one_chance_in(int a_million);
+
+
+/* ***********************************************************************
+ * called from: xxx
+ * *********************************************************************** */
+int random2(int randmax);
+
+
+/* ***********************************************************************
+ * called from: xxx
+ * *********************************************************************** */
+int random2avg( int max, int rolls );
+
+int roll_dice( int num, int size );
+int roll_dice( const struct dice_def &dice );
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: beam - fight - misc
+ * *********************************************************************** */
+int random2limit(int max, int limit);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: bang - beam - monplace - monstuff - spells1 - spells2 -
+ * spells4 - view
+ * *********************************************************************** */
+bool see_grid(unsigned char grx, unsigned char gry);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: spells2
+ * *********************************************************************** */
+int stepdown_value(int base_value, int stepping, int first_step, int last_step, int ceiling_value);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - command - effects - food - item_use - items -
+ * newgame - ouch - shopping - spell - spl-book - spells1 -
+ * spells3
+ * *********************************************************************** */
+unsigned char get_ch(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: files - newgame - ouch
+ * *********************************************************************** */
+void end(int end_arg);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: newgame
+ * *********************************************************************** */
+void modify_all_stats(int STmod, int IQmod, int DXmod);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - acr - command - direct - invent - item_use -
+ * religion - shopping - spell - spl-book - spells3
+ * *********************************************************************** */
+void redraw_screen(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - acr - beam - command - decks - debug - effects -
+ * it_use3 - item_use - items - misc - ouch - religion -
+ * spell - spl-book - spells - spells1 - spells2 - spells3 -
+ * spells4
+ * *********************************************************************** */
+void canned_msg(unsigned char which_message);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - acr - command - it_use3 - item_use - items -
+ * misc - ouch - religion - spl-book - spells4
+ * *********************************************************************** */
+bool yesno( const char * str, bool safe = true, bool clear_after = true );
+
+
+// last updated 21may2000 {dlb}
+/* ***********************************************************************
+ * called from: fight - monstuff - spells4 - view
+ * *********************************************************************** */
+int grid_distance( int x, int y, int x2, int y2 );
+int distance( int x, int y, int x2, int y2);
+bool adjacent( int x, int y, int x2, int y2 );
+
+
+// last updated 21may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - acr - bang - beam - effects - fight - it_use2 -
+ * it_use3 - monstuff - mstuff2 - religion - spell - spells -
+ * spells3 - spells4 - stuff - view
+ * *********************************************************************** */
+bool silenced(char x, char y);
+
+
+// last updated XXmay2000 {dlb}
+/* ***********************************************************************
+ * called from: xxx
+ * *********************************************************************** */
+bool player_can_hear(char x, char y);
+
+
+// last updated 27may2000 {dlb}
+/* ***********************************************************************
+ * called from: dungeon - files - it_use2 - it_use3 - monstuff - mon-util -
+ * mstuff2 - newgame - spells - view
+ * *********************************************************************** */
+unsigned char random_colour(void);
+
+
+// last updated 08jun2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - chardump - command - files - invent - item_use -
+ * items - newgame - spl-book - spells0 - spells1
+ * *********************************************************************** */
+char index_to_letter (int the_index);
+
+
+// last updated 08jun2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - command - food - it_use3 - item_use - items -
+ * spell - spl-book - spells1 - spells3
+ * *********************************************************************** */
+int letter_to_index(int the_letter);
+
+
+// last updated 16mar2001 {dlb}
+/* ***********************************************************************
+ * called from: monplace
+ * *********************************************************************** */
+int near_stairs(int px, int py, int max_dist, unsigned char &stair_gfx);
+
+// last updated 16mar2001 {dlb}
+/* ***********************************************************************
+ * called from: fight
+ * *********************************************************************** */
+// just want to do this in a consistent fashion
+inline bool testbits(unsigned int flags, unsigned int test)
+{
+ return ((flags & test) == test);
+}
+
+#endif
+
diff --git a/trunk/source/tags.cc b/trunk/source/tags.cc
new file mode 100644
index 0000000000..f4babe75e5
--- /dev/null
+++ b/trunk/source/tags.cc
@@ -0,0 +1,1831 @@
+/*
+ * File: tags.cc
+ * Summary: Auxilary functions to make savefile versioning simpler.
+ * Written by: Gordon Lipford
+ *
+ * Change History (most recent first):
+ *
+ * <2> 16 Mar 2001 GDL Added TAG_LEVEL_ATTITUDE
+ * <1> 27 Jan 2001 GDL Created
+ */
+
+/* ------------------------- how tags work ----------------------------------
+
+1. Tag types are enumerated in enum.h, from TAG_VERSION (more a placeholder
+ than anything else, it is not actually saved as a tag) to TAG_XXX. NUM_TAGS
+ is equal to the actual number of defined tags.
+
+2. Tags are created with tag_construct(), which forwards the construction
+ request appropriately. tag_write() is then used to write the tag to an
+ output stream.
+
+3. Tags are parsed with tag_read(), which tries to read a tag header and then
+ forwards the request appropriately, returning the ID of the tag it found,
+ or zero if no tag was found.
+
+4. In order to know which tags are used by a particular file type, a client
+ calls tag_set_expected( fileType ), which sets up an array of chars.
+ Within the array, a value of 1 means the tag is expected; -1 means that
+ the tag is not expected. A client can then set values in this array to
+ anything other than 1 to indicate a successful tag_read() of that tag.
+
+5. A case should be provided in tag_missing() for any tag which might be
+ missing from a tagged save file. For example, if a developer adds
+ TAG_YOU_NEW_STUFF to the player save file, he would have to provide a
+ case in tag_missing() for this tag since it might not be there in
+ earlier savefiles. The tags defined with the original tag system (and
+ so not needing cases in tag_missing()) are as follows:
+
+ TAG_YOU = 1, // 'you' structure
+ TAG_YOU_ITEMS, // your items
+ TAG_YOU_DUNGEON, // dungeon specs (stairs, branches, features)
+ TAG_LEVEL, // various grids & clouds
+ TAG_LEVEL_ITEMS, // items/traps
+ TAG_LEVEL_MONSTERS, // monsters
+ TAG_GHOST, // ghost
+
+6. The marshalling and unmarshalling of data is done in network order and
+ is meant to keep savefiles cross-platform. They are non-ascii - always
+ FTP in binary mode. Note also that the marshalling sizes are 1,2, and 4
+ for byte, short, and long - assuming that 'int' would have been
+ insufficient on 16 bit systems (and that Crawl otherwise lacks
+ system-indepedent data types).
+
+*/
+
+#include <stdio.h>
+#include <string.h> // for memcpy
+
+#ifdef LINUX
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+
+#ifdef USE_EMX
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+
+#ifdef OS9
+#include <stat.h>
+#else
+#include <sys/stat.h>
+#endif
+
+#include "AppHdr.h"
+
+#include "abl-show.h"
+#include "enum.h"
+#include "externs.h"
+#include "files.h"
+#include "itemname.h"
+#include "monstuff.h"
+#include "mon-util.h"
+#include "randart.h"
+#include "skills.h"
+#include "skills2.h"
+#include "stuff.h"
+#include "tags.h"
+
+// THE BIG IMPORTANT TAG CONSTRUCTION/PARSE BUFFER
+static char *tagBuffer = NULL;
+
+// These three are defined in overmap.cc
+extern FixedArray < unsigned char, MAX_LEVELS, MAX_BRANCHES > altars_present;
+extern FixedVector < char, MAX_BRANCHES > stair_level;
+extern FixedArray < unsigned char, MAX_LEVELS, MAX_BRANCHES > feature;
+
+extern unsigned char your_sign; /* these two are defined in view.cc */
+extern unsigned char your_colour;
+
+// temp file pairs used for file level cleanup
+FixedArray < bool, MAX_LEVELS, MAX_BRANCHES > tmp_file_pairs;
+
+
+// static helpers
+static void tag_construct_you(struct tagHeader &th);
+static void tag_construct_you_items(struct tagHeader &th);
+static void tag_construct_you_dungeon(struct tagHeader &th);
+static void tag_read_you(struct tagHeader &th, char minorVersion);
+static void tag_read_you_items(struct tagHeader &th, char minorVersion);
+static void tag_read_you_dungeon(struct tagHeader &th);
+
+static void tag_construct_level(struct tagHeader &th);
+static void tag_construct_level_items(struct tagHeader &th);
+static void tag_construct_level_monsters(struct tagHeader &th);
+static void tag_construct_level_attitude(struct tagHeader &th);
+static void tag_read_level(struct tagHeader &th, char minorVersion);
+static void tag_read_level_items(struct tagHeader &th, char minorVersion);
+static void tag_read_level_monsters(struct tagHeader &th, char minorVersion);
+static void tag_read_level_attitude(struct tagHeader &th);
+static void tag_missing_level_attitude();
+
+static void tag_construct_ghost(struct tagHeader &th);
+static void tag_read_ghost(struct tagHeader &th, char minorVersion);
+
+// provide a wrapper for file writing, just in case.
+int write2(FILE * file, char *buffer, unsigned int count)
+{
+ return fwrite(buffer, 1, count, file);
+}
+
+// provide a wrapper for file reading, just in case.
+int read2(FILE * file, char *buffer, unsigned int count)
+{
+ return fread(buffer, 1, count, file);
+}
+
+void marshallByte(struct tagHeader &th, char data)
+{
+ tagBuffer[th.offset] = data;
+ th.offset += 1;
+}
+
+char unmarshallByte(struct tagHeader &th)
+{
+ char data = tagBuffer[th.offset];
+ th.offset += 1;
+ return data;
+}
+
+// marshall 2 byte short in network order
+void marshallShort(struct tagHeader &th, short data)
+{
+ char b2 = (char)(data & 0x00FF);
+ char b1 = (char)((data & 0xFF00) >> 8);
+
+ tagBuffer[th.offset] = b1;
+ tagBuffer[th.offset + 1] = b2;
+
+ th.offset += 2;
+}
+
+// unmarshall 2 byte short in network order
+short unmarshallShort(struct tagHeader &th)
+{
+ short b1 = tagBuffer[th.offset];
+ short b2 = tagBuffer[th.offset + 1];
+
+ short data = (b1 << 8) | (b2 & 0x00FF);
+
+ th.offset += 2;
+ return data;
+}
+
+// marshall 4 byte int in network order
+void marshallLong(struct tagHeader &th, long data)
+{
+ char b4 = (char) (data & 0x000000FF);
+ char b3 = (char)((data & 0x0000FF00) >> 8);
+ char b2 = (char)((data & 0x00FF0000) >> 16);
+ char b1 = (char)((data & 0xFF000000) >> 24);
+
+ tagBuffer[th.offset] = b1;
+ tagBuffer[th.offset + 1] = b2;
+ tagBuffer[th.offset + 2] = b3;
+ tagBuffer[th.offset + 3] = b4;
+
+ th.offset += 4;
+}
+
+// unmarshall 4 byte int in network order
+long unmarshallLong(struct tagHeader &th)
+{
+ long b1 = tagBuffer[th.offset];
+ long b2 = tagBuffer[th.offset + 1];
+ long b3 = tagBuffer[th.offset + 2];
+ long b4 = tagBuffer[th.offset + 3];
+
+ long data = (b1 << 24) | ((b2 & 0x000000FF) << 16);
+ data |= ((b3 & 0x000000FF) << 8) | (b4 & 0x000000FF);
+
+ th.offset += 4;
+ return data;
+}
+
+// single precision float -- marshall in network order.
+void marshallFloat(struct tagHeader &th, float data)
+{
+ long intBits = *((long *)(&data));
+ marshallLong(th, intBits);
+}
+
+// single precision float -- unmarshall in network order.
+float unmarshallFloat(struct tagHeader &th)
+{
+ long intBits = unmarshallLong(th);
+
+ return *((float *)(&intBits));
+}
+
+// string -- marshall length & string data
+void marshallString(struct tagHeader &th, char *data, int maxSize)
+{
+ // allow for very long strings.
+ short len = strlen(data);
+ if (maxSize > 0 && len > maxSize)
+ len = maxSize;
+ marshallShort(th, len);
+
+ // put in the actual string -- we'll null terminate on
+ // unmarshall.
+ memcpy(&tagBuffer[th.offset], data, len);
+
+ th.offset += len;
+}
+
+// string -- unmarshall length & string data
+void unmarshallString(struct tagHeader &th, char *data, int maxSize)
+{
+ // get length
+ short len = unmarshallShort(th);
+ int copylen = len;
+ if (len > maxSize && maxSize > 0)
+ copylen = maxSize;
+
+ // read the actual string and null terminate
+ memcpy(data, &tagBuffer[th.offset], copylen);
+ data[copylen] = '\0';
+
+ th.offset += len;
+}
+
+// boolean (to avoid system-dependant bool implementations)
+void marshallBoolean(struct tagHeader &th, bool data)
+{
+ char charRep = 0; // for false
+ if (data)
+ charRep = 1;
+
+ tagBuffer[th.offset] = charRep;
+ th.offset += 1;
+}
+
+// boolean (to avoid system-dependant bool implementations)
+bool unmarshallBoolean(struct tagHeader &th)
+{
+ bool data;
+
+ if (tagBuffer[th.offset] == 1)
+ data = true;
+ else
+ data = false;
+
+ th.offset += 1;
+ return data;
+}
+
+// Saving the date as a string so we're not reliant on a particular epoch.
+void make_date_string( time_t in_date, char buff[20] )
+{
+ if (in_date <= 0)
+ {
+ buff[0] = '\0';
+ return;
+ }
+
+
+ struct tm *date = localtime( &in_date );
+
+ snprintf( buff, 20,
+ "%4d%02d%02d%02d%02d%02d%s",
+ date->tm_year + 1900, date->tm_mon, date->tm_mday,
+ date->tm_hour, date->tm_min, date->tm_sec,
+ ((date->tm_isdst > 0) ? "D" : "S") );
+}
+
+static int get_val_from_string( const char *ptr, int len )
+{
+ int ret = 0;
+ int pow = 1;
+
+ for (const char *chr = ptr + len - 1; chr >= ptr; chr--)
+ {
+ ret += (*chr - '0') * pow;
+ pow *= 10;
+ }
+
+ return (ret);
+}
+
+time_t parse_date_string( char buff[20] )
+{
+ struct tm date;
+
+ date.tm_year = get_val_from_string( &buff[0], 4 ) - 1900;
+ date.tm_mon = get_val_from_string( &buff[4], 2 );
+ date.tm_mday = get_val_from_string( &buff[6], 2 );
+ date.tm_hour = get_val_from_string( &buff[8], 2 );
+ date.tm_min = get_val_from_string( &buff[10], 2 );
+ date.tm_sec = get_val_from_string( &buff[12], 2 );
+
+ date.tm_isdst = (buff[14] == 'D');
+
+ return (mktime( &date ));
+}
+
+// PUBLIC TAG FUNCTIONS
+void tag_init(long largest_tag)
+{
+ if (tagBuffer != NULL)
+ return;
+
+ tagBuffer = (char *)malloc(largest_tag);
+}
+
+void tag_construct(struct tagHeader &th, int tagID)
+{
+ th.offset = 0;
+ th.tagID = tagID;
+
+ switch(tagID)
+ {
+ case TAG_YOU:
+ tag_construct_you(th);
+ break;
+ case TAG_YOU_ITEMS:
+ tag_construct_you_items(th);
+ break;
+ case TAG_YOU_DUNGEON:
+ tag_construct_you_dungeon(th);
+ break;
+ case TAG_LEVEL:
+ tag_construct_level(th);
+ break;
+ case TAG_LEVEL_ITEMS:
+ tag_construct_level_items(th);
+ break;
+ case TAG_LEVEL_MONSTERS:
+ tag_construct_level_monsters(th);
+ break;
+ case TAG_LEVEL_ATTITUDE:
+ tag_construct_level_attitude(th);
+ break;
+ case TAG_GHOST:
+ tag_construct_ghost(th);
+ break;
+ default:
+ // I don't know how to make that!
+ break;
+ }
+}
+
+void tag_write(struct tagHeader &th, FILE *saveFile)
+{
+ const int tagHdrSize = 6;
+ int tagSize=0;
+
+ char swap[tagHdrSize];
+
+ // make sure there is some data to write!
+ if (th.offset == 0)
+ return;
+
+ // special case: TAG_VERSION. Skip tag header.
+ if (th.tagID != TAG_VERSION)
+ {
+ // swap out first few bytes
+ memcpy(swap, tagBuffer, tagHdrSize);
+
+ // save tag size
+ tagSize = th.offset;
+
+ // swap in the header
+ th.offset = 0;
+ marshallShort(th, th.tagID);
+ marshallLong(th, tagSize);
+
+ // write header
+ write2(saveFile, tagBuffer, th.offset);
+
+ // swap real data back in
+ memcpy(tagBuffer, swap, tagHdrSize);
+
+ // reset tag size
+ th.offset = tagSize;
+ }
+
+ // write tag data
+ write2(saveFile, tagBuffer, th.offset);
+ return;
+}
+
+// minorVersion is available for any sub-readers that need it
+// (like TAG_LEVEL_MONSTERS)
+int tag_read(FILE *fp, char minorVersion)
+{
+ const int tagHdrSize = 6;
+ struct tagHeader hdr, th;
+ th.offset = 0;
+
+ // read tag header
+ if (read2(fp, tagBuffer, tagHdrSize) != tagHdrSize)
+ return 0;
+
+ // unmarshall tag type and length (not including header)
+ hdr.tagID = unmarshallShort(th);
+ hdr.offset = unmarshallLong(th);
+
+ // sanity check
+ if (hdr.tagID <= 0 || hdr.offset <= 0)
+ return 0;
+
+ // now reset th and read actual data
+ th.offset = 0;
+ if (read2(fp, tagBuffer, hdr.offset) != hdr.offset)
+ return 0;
+
+ // ok, we have data now.
+ switch(hdr.tagID)
+ {
+ case TAG_YOU:
+ tag_read_you(th, minorVersion);
+ break;
+ case TAG_YOU_ITEMS:
+ tag_read_you_items(th, minorVersion);
+ break;
+ case TAG_YOU_DUNGEON:
+ tag_read_you_dungeon(th);
+ break;
+ case TAG_LEVEL:
+ tag_read_level(th, minorVersion);
+ break;
+ case TAG_LEVEL_ITEMS:
+ tag_read_level_items(th, minorVersion);
+ break;
+ case TAG_LEVEL_MONSTERS:
+ tag_read_level_monsters(th, minorVersion);
+ break;
+ case TAG_LEVEL_ATTITUDE:
+ tag_read_level_attitude(th);
+ break;
+ case TAG_GHOST:
+ tag_read_ghost(th, minorVersion);
+ break;
+ default:
+ // I don't know how to read that!
+ return 0;
+ }
+
+ return hdr.tagID;
+}
+
+
+// older savefiles might want to call this to get a tag
+// properly initialized if it wasn't part of the savefile.
+// For now, none are supported.
+
+// This function will be called AFTER all other tags for
+// the savefile are read, so everything that can be
+// initialized should have been by now.
+
+// minorVersion is available for any child functions that need
+// it (currently none)
+void tag_missing(int tag, char minorVersion)
+{
+ UNUSED( minorVersion );
+
+ switch(tag)
+ {
+ case TAG_LEVEL_ATTITUDE:
+ tag_missing_level_attitude();
+ break;
+ default:
+ perror("Tag %d is missing; file is likely corrupt.");
+ end(-1);
+ }
+}
+
+// utility
+void tag_set_expected(char tags[], int fileType)
+{
+ int i;
+
+ for(i=0; i<NUM_TAGS; i++)
+ {
+ tags[i] = -1;
+ switch(fileType)
+ {
+ case TAGTYPE_PLAYER:
+ if (i >= TAG_YOU && i <=TAG_YOU_DUNGEON)
+ tags[i] = 1;
+ break;
+ case TAGTYPE_LEVEL:
+ if (i >= TAG_LEVEL && i <= TAG_LEVEL_ATTITUDE)
+ tags[i] = 1;
+ break;
+ case TAGTYPE_GHOST:
+ if (i == TAG_GHOST)
+ tags[i] = 1;
+ default:
+ // I don't know what kind of file that is!
+ break;
+ }
+ }
+}
+
+// NEVER _MODIFY_ THE CONSTRUCT/READ FUNCTIONS, EVER. THAT IS THE WHOLE POINT
+// OF USING TAGS. Apologies for the screaming.
+
+// Note anyway that the formats are somewhat flexible; you could change map
+// size, the # of slots in player inventory, etc. Constants like GXM,
+// NUM_EQUIP, and NUM_DURATIONS are saved, so the appropriate amount will
+// be restored even if a later version increases these constants.
+
+// --------------------------- player tags (foo.sav) -------------------- //
+static void tag_construct_you(struct tagHeader &th)
+{
+ char buff[20]; // used for date string
+ int i,j;
+
+ marshallString(th, you.your_name, 30);
+
+ marshallByte(th,you.religion);
+ marshallByte(th,you.piety);
+ marshallByte(th,you.invis);
+ marshallByte(th,you.conf);
+ marshallByte(th,you.paralysis);
+ marshallByte(th,you.slow);
+ marshallByte(th,you.fire_shield);
+ marshallByte(th,you.rotting);
+ marshallByte(th,you.exhausted);
+ marshallByte(th,you.deaths_door);
+ marshallByte(th,your_sign);
+ marshallByte(th,your_colour);
+ marshallByte(th,you.pet_target);
+
+ marshallByte(th,you.max_level);
+ marshallByte(th,you.where_are_you);
+ marshallByte(th,you.char_direction);
+ marshallByte(th,you.your_level);
+ marshallByte(th,you.is_undead);
+ marshallByte(th,you.special_wield);
+ marshallByte(th,you.berserker);
+ marshallByte(th,you.berserk_penalty);
+ marshallByte(th,you.level_type);
+ marshallByte(th,you.synch_time);
+ marshallByte(th,you.disease);
+ marshallByte(th,you.species);
+
+ marshallShort(th, you.hp);
+
+ if (you.haste > 215)
+ you.haste = 215;
+
+ marshallByte(th,you.haste);
+
+ if (you.might > 215)
+ you.might = 215;
+
+ marshallByte(th,you.might);
+
+ if (you.levitation > 215)
+ you.levitation = 215;
+
+ marshallByte(th,you.levitation);
+
+ if (you.poison > 215)
+ you.poison = 215;
+
+ marshallByte(th,you.poison);
+
+ marshallShort(th, you.hunger);
+
+ // how many you.equip?
+ marshallByte(th, NUM_EQUIP);
+ for (i = 0; i < NUM_EQUIP; ++i)
+ marshallByte(th,you.equip[i]);
+
+ marshallByte(th,you.magic_points);
+ marshallByte(th,you.max_magic_points);
+ marshallByte(th,you.strength);
+ marshallByte(th,you.intel);
+ marshallByte(th,you.dex);
+ marshallByte(th,you.confusing_touch);
+ marshallByte(th,you.sure_blade);
+ marshallByte(th,you.hit_points_regeneration);
+ marshallByte(th,you.magic_points_regeneration);
+
+ marshallShort(th, you.hit_points_regeneration * 100);
+ marshallLong(th, you.experience);
+ marshallLong(th, you.gold);
+
+ marshallByte(th,you.char_class);
+ marshallByte(th,you.experience_level);
+ marshallLong(th, you.exp_available);
+
+ /* max values */
+ marshallByte(th,you.max_strength);
+ marshallByte(th,you.max_intel);
+ marshallByte(th,you.max_dex);
+
+ marshallShort(th, you.base_hp);
+ marshallShort(th, you.base_hp2);
+ marshallShort(th, you.base_magic_points);
+ marshallShort(th, you.base_magic_points2);
+
+ marshallShort(th, you.x_pos);
+ marshallShort(th, you.y_pos);
+
+ marshallString(th, you.class_name, 30);
+
+ marshallShort(th, you.burden);
+
+ // how many spells?
+ marshallByte(th, 25);
+ for (i = 0; i < 25; ++i)
+ marshallByte(th, you.spells[i]);
+
+ marshallByte(th, 52);
+ for (i = 0; i < 52; i++)
+ marshallByte( th, you.spell_letter_table[i] );
+
+ marshallByte(th, 52);
+ for (i = 0; i < 52; i++)
+ marshallShort( th, you.ability_letter_table[i] );
+
+ // how many skills?
+ marshallByte(th, 50);
+ for (j = 0; j < 50; ++j)
+ {
+ marshallByte(th,you.skills[j]); /* skills! */
+ marshallByte(th,you.practise_skill[j]); /* skills! */
+ marshallLong(th,you.skill_points[j]);
+ marshallByte(th,you.skill_order[j]); /* skills ordering */
+ }
+
+ // how many durations?
+ marshallByte(th, NUM_DURATIONS);
+ for (j = 0; j < NUM_DURATIONS; ++j)
+ marshallByte(th,you.duration[j]);
+
+ // how many attributes?
+ marshallByte(th, 30);
+ for (j = 0; j < 30; ++j)
+ marshallByte(th,you.attribute[j]);
+
+ // how many mutations/demon powers?
+ marshallShort(th, 100);
+ for (j = 0; j < 100; ++j)
+ {
+ marshallByte(th,you.mutation[j]);
+ marshallByte(th,you.demon_pow[j]);
+ }
+
+ // how many penances?
+ marshallByte(th, MAX_NUM_GODS);
+ for (i = 0; i < MAX_NUM_GODS; i++)
+ marshallByte(th, you.penance[i]);
+
+ // which gods have been worshipped by this character?
+ marshallByte(th, MAX_NUM_GODS);
+ for (i = 0; i < MAX_NUM_GODS; i++)
+ marshallByte(th, you.worshipped[i]);
+
+ marshallByte(th, you.gift_timeout);
+ marshallByte(th, you.normal_vision);
+ marshallByte(th, you.current_vision);
+ marshallByte(th, you.hell_exit);
+
+ // elapsed time
+ marshallFloat(th, (float)you.elapsed_time);
+
+ // wizard mode used
+ marshallByte(th, you.wizard);
+
+ // time of game start
+ make_date_string( you.birth_time, buff );
+ marshallString(th, buff, 20);
+
+ // real_time == -1 means game was started before this feature
+ if (you.real_time != -1)
+ {
+ const time_t now = time(NULL);
+ you.real_time += (now - you.start_time);
+
+ // Reset start_time now that real_time is being saved out...
+ // this may just be a level save.
+ you.start_time = now;
+ }
+
+ marshallLong( th, you.real_time );
+ marshallLong( th, you.num_turns );
+}
+
+static void tag_construct_you_items(struct tagHeader &th)
+{
+ int i,j;
+
+ // how many inventory slots?
+ marshallByte(th, ENDOFPACK);
+ for (i = 0; i < ENDOFPACK; ++i)
+ {
+ marshallByte(th,you.inv[i].base_type);
+ marshallByte(th,you.inv[i].sub_type);
+ marshallShort(th,you.inv[i].plus);
+ marshallLong(th,you.inv[i].special);
+ marshallByte(th,you.inv[i].colour);
+ marshallLong(th,you.inv[i].flags);
+ marshallShort(th,you.inv[i].quantity);
+ marshallShort(th,you.inv[i].plus2);
+ }
+
+ // item descrip for each type & subtype
+ // how many types?
+ marshallByte(th, 5);
+ // how many subtypes?
+ marshallByte(th, 50);
+ for (i = 0; i < 5; ++i)
+ {
+ for (j = 0; j < 50; ++j)
+ marshallByte(th, you.item_description[i][j]);
+ }
+
+ // identification status
+ // how many types?
+ marshallByte(th, 4);
+ // how many subtypes?
+ marshallByte(th, 50);
+
+ // this is really dumb. We copy the id[] array from itemname
+ // to the stack, for no good reason that I can see.
+ char identy[4][50];
+
+ save_id(identy);
+
+ for (i = 0; i < 4; ++i)
+ {
+ for (j = 0; j < 50; ++j)
+ marshallByte(th, identy[i][j]);
+ }
+
+ // how many unique items?
+ marshallByte(th, 50);
+ for (j = 0; j < 50; ++j)
+ {
+ marshallByte(th,you.unique_items[j]); /* unique items */
+ marshallByte(th,you.had_book[j]);
+ }
+
+ // how many unrandarts?
+ marshallShort(th, NO_UNRANDARTS);
+
+ for (j = 0; j < NO_UNRANDARTS; ++j)
+ marshallBoolean(th, does_unrandart_exist(j));
+}
+
+static void tag_construct_you_dungeon(struct tagHeader &th)
+{
+ int i,j;
+
+ // how many unique creatures?
+ marshallByte(th, 50);
+ for (j = 0; j < 50; ++j)
+ marshallByte(th,you.unique_creatures[j]); /* unique beasties */
+
+ // how many branches?
+ marshallByte(th, MAX_BRANCHES);
+ for (j = 0; j < 30; ++j)
+ {
+ marshallByte(th,you.branch_stairs[j]);
+ marshallByte(th,stair_level[j]);
+ }
+
+ // how many levels?
+ marshallShort(th, MAX_LEVELS);
+ for (i = 0; i < MAX_LEVELS; ++i)
+ {
+ for (j = 0; j < MAX_BRANCHES; ++j)
+ {
+ marshallByte(th,altars_present[i][j]);
+ marshallByte(th,feature[i][j]);
+ marshallBoolean(th,tmp_file_pairs[i][j]);
+ }
+ }
+}
+
+static void tag_read_you(struct tagHeader &th, char minorVersion)
+{
+ char buff[20]; // For birth date
+ int i,j;
+ char count_c;
+ short count_s;
+
+ unmarshallString(th, you.your_name, 30);
+
+ you.religion = unmarshallByte(th);
+ you.piety = unmarshallByte(th);
+ you.invis = unmarshallByte(th);
+ you.conf = unmarshallByte(th);
+ you.paralysis = unmarshallByte(th);
+ you.slow = unmarshallByte(th);
+ you.fire_shield = unmarshallByte(th);
+ you.rotting = unmarshallByte(th);
+ you.exhausted = unmarshallByte(th);
+ you.deaths_door = unmarshallByte(th);
+ your_sign = unmarshallByte(th);
+ your_colour = unmarshallByte(th);
+ you.pet_target = unmarshallByte(th);
+
+ you.max_level = unmarshallByte(th);
+ you.where_are_you = unmarshallByte(th);
+ you.char_direction = unmarshallByte(th);
+ you.your_level = unmarshallByte(th);
+ you.is_undead = unmarshallByte(th);
+ you.special_wield = unmarshallByte(th);
+ you.berserker = unmarshallByte(th);
+ you.berserk_penalty = unmarshallByte(th);
+ you.level_type = unmarshallByte(th);
+ you.synch_time = unmarshallByte(th);
+ you.disease = unmarshallByte(th);
+ you.species = unmarshallByte(th);
+ you.hp = unmarshallShort(th);
+ you.haste = unmarshallByte(th);
+ you.might = unmarshallByte(th);
+ you.levitation = unmarshallByte(th);
+ you.poison = unmarshallByte(th);
+ you.hunger = unmarshallShort(th);
+
+ // how many you.equip?
+ count_c = unmarshallByte(th);
+ for (i = 0; i < count_c; ++i)
+ you.equip[i] = unmarshallByte(th);
+
+ you.magic_points = unmarshallByte(th);
+ you.max_magic_points = unmarshallByte(th);
+ you.strength = unmarshallByte(th);
+ you.intel = unmarshallByte(th);
+ you.dex = unmarshallByte(th);
+ you.confusing_touch = unmarshallByte(th);
+ you.sure_blade = unmarshallByte(th);
+ you.hit_points_regeneration = unmarshallByte(th);
+ you.magic_points_regeneration = unmarshallByte(th);
+
+ you.hit_points_regeneration = unmarshallShort(th) / 100;
+ you.experience = unmarshallLong(th);
+ you.gold = unmarshallLong(th);
+
+ you.char_class = unmarshallByte(th);
+ you.experience_level = unmarshallByte(th);
+ you.exp_available = unmarshallLong(th);
+
+ /* max values */
+ you.max_strength = unmarshallByte(th);
+ you.max_intel = unmarshallByte(th);
+ you.max_dex = unmarshallByte(th);
+
+ you.base_hp = unmarshallShort(th);
+ you.base_hp2 = unmarshallShort(th);
+ you.base_magic_points = unmarshallShort(th);
+ you.base_magic_points2 = unmarshallShort(th);
+
+ you.x_pos = unmarshallShort(th);
+ you.y_pos = unmarshallShort(th);
+
+ unmarshallString(th, you.class_name, 30);
+
+ you.burden = unmarshallShort(th);
+
+ // how many spells?
+ you.spell_no = 0;
+ count_c = unmarshallByte(th);
+ for (i = 0; i < count_c; ++i)
+ {
+ you.spells[i] = unmarshallByte(th);
+ if (you.spells[i] != SPELL_NO_SPELL)
+ you.spell_no++;
+ }
+
+ if (minorVersion >= 2)
+ {
+ count_c = unmarshallByte(th);
+ for (i = 0; i < count_c; i++)
+ you.spell_letter_table[i] = unmarshallByte(th);
+
+ count_c = unmarshallByte(th);
+ for (i = 0; i < count_c; i++)
+ you.ability_letter_table[i] = unmarshallShort(th);
+ }
+ else
+ {
+ for (i = 0; i < 52; i++)
+ {
+ you.spell_letter_table[i] = -1;
+ you.ability_letter_table[i] = ABIL_NON_ABILITY;
+ }
+
+ for (i = 0; i < 25; i++)
+ {
+ if (you.spells[i] != SPELL_NO_SPELL)
+ you.spell_letter_table[i] = i;
+ }
+
+ if (you.religion != GOD_NO_GOD)
+ set_god_ability_slots();
+ }
+
+ // how many skills?
+ count_c = unmarshallByte(th);
+ for (j = 0; j < count_c; ++j)
+ {
+ you.skills[j] = unmarshallByte(th);
+ you.practise_skill[j] = unmarshallByte(th);
+ you.skill_points[j] = unmarshallLong(th);
+
+ if (minorVersion >= 2)
+ you.skill_order[j] = unmarshallByte(th);
+ }
+
+ // initialize ordering when we don't read it in:
+ if (minorVersion < 2)
+ init_skill_order();
+
+ // set up you.total_skill_points and you.skill_cost_level
+ calc_total_skill_points();
+
+ // how many durations?
+ count_c = unmarshallByte(th);
+ for (j = 0; j < count_c; ++j)
+ you.duration[j] = unmarshallByte(th);
+
+ // how many attributes?
+ count_c = unmarshallByte(th);
+ for (j = 0; j < count_c; ++j)
+ you.attribute[j] = unmarshallByte(th);
+
+ // how many mutations/demon powers?
+ count_s = unmarshallShort(th);
+ for (j = 0; j < count_s; ++j)
+ {
+ you.mutation[j] = unmarshallByte(th);
+ you.demon_pow[j] = unmarshallByte(th);
+ }
+
+ // how many penances?
+ count_c = unmarshallByte(th);
+ for (i = 0; i < count_c; i++)
+ you.penance[i] = unmarshallByte(th);
+
+ if (minorVersion >= 2)
+ {
+ count_c = unmarshallByte(th);
+ for (i = 0; i < count_c; i++)
+ you.worshipped[i] = unmarshallByte(th);
+ }
+ else
+ {
+ for (i = 0; i < count_c; i++)
+ you.worshipped[i] = false;
+
+ if (you.religion != GOD_NO_GOD)
+ you.worshipped[you.religion] = true;
+ }
+
+ you.gift_timeout = unmarshallByte(th);
+ you.normal_vision = unmarshallByte(th);
+ you.current_vision = unmarshallByte(th);
+ you.hell_exit = unmarshallByte(th);
+
+ // elapsed time
+ you.elapsed_time = (double)unmarshallFloat(th);
+
+ if (minorVersion >= 1)
+ {
+ // wizard mode
+ you.wizard = (bool) unmarshallByte(th);
+
+ // time of character creation
+ unmarshallString( th, buff, 20 );
+ you.birth_time = parse_date_string( buff );
+ }
+
+ if (minorVersion >= 2)
+ {
+ you.real_time = unmarshallLong(th);
+ you.num_turns = unmarshallLong(th);
+ }
+ else
+ {
+ you.real_time = -1;
+ you.num_turns = -1;
+ }
+}
+
+static void tag_convert_to_4_3_item( item_def &item )
+{
+ const unsigned char plus = item.plus;
+ const unsigned char plus2 = item.plus2;
+ const unsigned char ident = item.flags;
+ const unsigned char special = item.special;
+
+ if (item.quantity <= 0)
+ return;
+
+ // First, convert ident into flags:
+ item.flags = (ident == 3) ? ISFLAG_IDENT_MASK :
+ (ident > 0) ? ISFLAG_KNOW_CURSE
+ : 0;
+
+ switch (item.base_type)
+ {
+ case OBJ_ARMOUR:
+ if ((ident == 1 && special % 30 >= 25) || ident == 2)
+ item.flags |= ISFLAG_KNOW_TYPE;
+
+ // Convert special values
+ item.special %= 30;
+ if (item.special < 25)
+ {
+ if (item.sub_type == ARM_HELMET)
+ {
+ item.plus2 = plus2 % 30;
+ set_helmet_desc( item, (special / 30) << 8 );
+ }
+ else
+ {
+ switch (special / 30)
+ {
+ case DARM_EMBROIDERED_SHINY:
+ set_equip_desc( item, ISFLAG_EMBROIDERED_SHINY );
+ break;
+ case DARM_RUNED:
+ set_equip_desc( item, ISFLAG_RUNED );
+ break;
+ case DARM_GLOWING:
+ set_equip_desc( item, ISFLAG_GLOWING );
+ break;
+ case DARM_ELVEN:
+ set_equip_race( item, ISFLAG_ELVEN );
+ break;
+ case DARM_DWARVEN:
+ set_equip_race( item, ISFLAG_DWARVEN );
+ break;
+ case DARM_ORCISH:
+ set_equip_race( item, ISFLAG_ORCISH );
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else if (item.special == 25)
+ {
+ item.flags |= ISFLAG_UNRANDART;
+ item.special = 0;
+ }
+ else
+ {
+ item.flags |= ISFLAG_RANDART;
+
+ // calc old seed
+ item.special = item.base_type * special
+ + item.sub_type * (plus % 100)
+ + plus2 * 100;
+ }
+ break;
+
+ case OBJ_WEAPONS:
+ if ((ident == 1 && (special < 180 && special % 30 >= 25)) || ident == 2)
+ item.flags |= ISFLAG_KNOW_TYPE;
+
+ // Convert special values
+ if (special < 181) // don't mangle fixed artefacts
+ {
+ item.special %= 30;
+ if (item.special < 25)
+ {
+ switch (special / 30)
+ {
+ case DWPN_RUNED:
+ set_equip_desc( item, ISFLAG_RUNED );
+ break;
+ case DWPN_GLOWING:
+ set_equip_desc( item, ISFLAG_GLOWING );
+ break;
+ case DWPN_ORCISH:
+ set_equip_race( item, ISFLAG_ORCISH );
+ break;
+ case DWPN_ELVEN:
+ set_equip_race( item, ISFLAG_ELVEN );
+ break;
+ case DWPN_DWARVEN:
+ set_equip_race( item, ISFLAG_DWARVEN );
+ break;
+ default:
+ break;
+ }
+ }
+ else if (item.special == 25)
+ {
+ item.flags |= ISFLAG_UNRANDART;
+ item.special = 0;
+ }
+ else
+ {
+ item.flags |= ISFLAG_RANDART;
+
+ // calc old seed
+ item.special = item.base_type * special
+ + item.sub_type * (plus % 100)
+ + plus2 * 100;
+ }
+ }
+ break;
+
+ case OBJ_MISSILES:
+ // Needles were moved into the bonus eggplant spot. -- bwr
+ if (item.sub_type == 6)
+ item.sub_type = MI_NEEDLE;
+
+ if (ident == 2)
+ item.flags |= ISFLAG_KNOW_TYPE;
+
+ // Convert special values
+ item.special %= 30;
+ switch (special / 30)
+ {
+ case DAMMO_ORCISH:
+ set_equip_race( item, ISFLAG_ORCISH );
+ break;
+ case DAMMO_ELVEN:
+ set_equip_race( item, ISFLAG_ELVEN );
+ break;
+ case DAMMO_DWARVEN:
+ set_equip_race( item, ISFLAG_DWARVEN );
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case OBJ_WANDS:
+ if (ident == 2)
+ item.flags |= ISFLAG_KNOW_PLUSES;
+ break;
+
+ case OBJ_JEWELLERY:
+ if (ident == 1 && (special == 200 || special == 201))
+ item.flags |= ISFLAG_KNOW_TYPE;
+ else if (ident == 2)
+ item.flags |= (ISFLAG_KNOW_TYPE | ISFLAG_KNOW_PLUSES);
+
+ if (special == 201)
+ {
+ item.flags |= ISFLAG_UNRANDART;
+ item.special = 0;
+ }
+ else if (special == 200)
+ {
+ item.flags |= ISFLAG_RANDART;
+
+ // calc old seed
+ item.special = item.base_type * special
+ + item.sub_type * (plus % 100)
+ + plus2 * 100;
+ }
+ break;
+
+ default:
+ if (ident > 0)
+ item.flags |= ISFLAG_KNOW_TYPE;
+ break;
+ }
+
+
+ // Second, convert plus and plus2
+ if (item.base_type == OBJ_WEAPONS
+ || item.base_type == OBJ_MISSILES
+ || item.base_type == OBJ_ARMOUR
+ || item.base_type == OBJ_JEWELLERY)
+ {
+ item.plus = plus;
+
+ // item is cursed:
+ if (plus > 100)
+ {
+ item.plus -= 100;
+ item.flags |= ISFLAG_CURSED;
+ }
+
+ // Weapons use both as pluses.
+ // Non-artefact jewellery uses both as pluses.
+ // Artefact jewellery has literal values for both pluses.
+ // Armour and Missiles only use plus for their plus value.
+ // Armour has literal usage of plus2 for sub-subtypes.
+ if (item.base_type != OBJ_JEWELLERY)
+ {
+ item.plus -= 50;
+
+ if (item.base_type == OBJ_WEAPONS)
+ item.plus2 -= 50;
+ }
+ else if (special != 200)
+ {
+ // regular jewellery & unrandarts -- unused pluses were 0s
+ if (item.plus)
+ item.plus -= 50;
+
+ if (item.plus2)
+ item.plus2 -= 50;
+ }
+ else if (special == 200)
+ {
+ // Randart jewellery used pluses only as seeds, right now
+ // they're always zero (since random artefact rings avoid
+ // base types with pluses).
+ item.plus = 0;
+ item.plus2 = 0;
+ }
+ }
+}
+
+static void tag_read_you_items(struct tagHeader &th, char minorVersion)
+{
+ int i,j;
+ char count_c, count_c2;
+ short count_s;
+
+ // how many inventory slots?
+ count_c = unmarshallByte(th);
+ for (i = 0; i < count_c; ++i)
+ {
+ if (minorVersion < 1)
+ {
+ you.inv[i].base_type = (unsigned char) unmarshallByte(th);
+ you.inv[i].sub_type = (unsigned char) unmarshallByte(th);
+ you.inv[i].plus = (unsigned char) unmarshallByte(th);
+ you.inv[i].special = (unsigned char) unmarshallByte(th);
+ you.inv[i].colour = (unsigned char) unmarshallByte(th);
+ you.inv[i].flags = (unsigned char) unmarshallByte(th);
+ you.inv[i].quantity = unmarshallShort(th);
+ you.inv[i].plus2 = (unsigned char) unmarshallByte(th);
+
+ tag_convert_to_4_3_item( you.inv[i] );
+ }
+ else
+ {
+ you.inv[i].base_type = (unsigned char) unmarshallByte(th);
+ you.inv[i].sub_type = (unsigned char) unmarshallByte(th);
+ you.inv[i].plus = unmarshallShort(th);
+ you.inv[i].special = unmarshallLong(th);
+ you.inv[i].colour = (unsigned char) unmarshallByte(th);
+ you.inv[i].flags = (unsigned long) unmarshallLong(th);
+ you.inv[i].quantity = unmarshallShort(th);
+ you.inv[i].plus2 = unmarshallShort(th);
+ }
+
+ // these never need to be saved for items in the inventory -- bwr
+ you.inv[i].x = -1;
+ you.inv[i].y = -1;
+ you.inv[i].link = i;
+ }
+
+ // item descrip for each type & subtype
+ // how many types?
+ count_c = unmarshallByte(th);
+ // how many subtypes?
+ count_c2 = unmarshallByte(th);
+ for (i = 0; i < count_c; ++i)
+ {
+ for (j = 0; j < count_c2; ++j)
+ you.item_description[i][j] = unmarshallByte(th);
+ }
+
+ // identification status
+ // how many types?
+ count_c = unmarshallByte(th);
+ // how many subtypes?
+ count_c2 = unmarshallByte(th);
+
+ // argh.. this is awful.
+ for (i = 0; i < count_c; ++i)
+ {
+ for (j = 0; j < count_c2; ++j)
+ {
+ char ch;
+ ch = unmarshallByte(th);
+
+ switch (i)
+ {
+ case IDTYPE_WANDS:
+ set_ident_type(OBJ_WANDS, j, ch);
+ break;
+ case IDTYPE_SCROLLS:
+ set_ident_type(OBJ_SCROLLS, j, ch);
+ break;
+ case IDTYPE_JEWELLERY:
+ set_ident_type(OBJ_JEWELLERY, j, ch);
+ break;
+ case IDTYPE_POTIONS:
+ set_ident_type(OBJ_POTIONS, j, ch);
+ break;
+ }
+ }
+ }
+
+ // how many unique items?
+ count_c = unmarshallByte(th);
+ for (j = 0; j < count_c; ++j)
+ {
+ you.unique_items[j] = unmarshallByte(th);
+ you.had_book[j] = unmarshallByte(th);
+ }
+
+ // how many unrandarts?
+ count_s = unmarshallShort(th);
+ for (j = 0; j < count_s; ++j)
+ set_unrandart_exist(j, unmarshallBoolean(th));
+
+ // # of unrandarts could certainly change. If it does,
+ // the new ones won't exist yet - zero them out.
+ for (; j < NO_UNRANDARTS; j++)
+ set_unrandart_exist(j, 0);
+}
+
+static void tag_read_you_dungeon(struct tagHeader &th)
+{
+ int i,j;
+ char count_c;
+ short count_s;
+
+ // how many unique creatures?
+ count_c = unmarshallByte(th);
+ for (j = 0; j < count_c; ++j)
+ you.unique_creatures[j] = unmarshallByte(th);
+
+ // how many branches?
+ count_c = unmarshallByte(th);
+ for (j = 0; j < count_c; ++j)
+ {
+ you.branch_stairs[j] = unmarshallByte(th);
+ stair_level[j] = unmarshallByte(th);
+ }
+
+ // how many levels?
+ count_s = unmarshallShort(th);
+ for (i = 0; i < count_s; ++i)
+ {
+ for (j = 0; j < count_c; ++j)
+ {
+ altars_present[i][j] = unmarshallByte(th);
+ feature[i][j] = unmarshallByte(th);
+ tmp_file_pairs[i][j] = unmarshallBoolean(th);
+ }
+ }
+}
+
+// ------------------------------- level tags ---------------------------- //
+
+static void tag_construct_level(struct tagHeader &th)
+{
+ int i;
+ int count_x, count_y;
+
+ marshallFloat(th, (float)you.elapsed_time);
+
+ // map grids
+ // how many X?
+ marshallShort(th, GXM);
+ // how many Y?
+ marshallShort(th, GYM);
+ for (count_x = 0; count_x < GXM; count_x++)
+ {
+ for (count_y = 0; count_y < GYM; count_y++)
+ {
+ marshallByte(th, grd[count_x][count_y]);
+ marshallByte(th, env.map[count_x][count_y]);
+ marshallByte(th, env.cgrid[count_x][count_y]);
+ }
+ }
+
+ marshallShort(th, env.cloud_no);
+
+ // how many clouds?
+ marshallShort(th, MAX_CLOUDS);
+ for (i = 0; i < MAX_CLOUDS; i++)
+ {
+ marshallByte(th, env.cloud[i].x);
+ marshallByte(th, env.cloud[i].y);
+ marshallByte(th, env.cloud[i].type);
+ marshallShort(th, env.cloud[i].decay);
+ }
+
+ // how many shops?
+ marshallByte(th, 5);
+ for (i = 0; i < 5; i++)
+ {
+ marshallByte(th, env.shop[i].keeper_name[0]);
+ marshallByte(th, env.shop[i].keeper_name[1]);
+ marshallByte(th, env.shop[i].keeper_name[2]);
+ marshallByte(th, env.shop[i].x);
+ marshallByte(th, env.shop[i].y);
+ marshallByte(th, env.shop[i].greed);
+ marshallByte(th, env.shop[i].type);
+ marshallByte(th, env.shop[i].level);
+ }
+}
+
+static void tag_construct_level_items(struct tagHeader &th)
+{
+ int i;
+
+ // how many traps?
+ marshallShort(th, MAX_TRAPS);
+ for (i = 0; i < MAX_TRAPS; ++i)
+ {
+ marshallByte(th, env.trap[i].type);
+ marshallByte(th, env.trap[i].x);
+ marshallByte(th, env.trap[i].y);
+ }
+
+ // how many items?
+ marshallShort(th, MAX_ITEMS);
+ for (i = 0; i < MAX_ITEMS; ++i)
+ {
+ marshallByte(th, mitm[i].base_type);
+ marshallByte(th, mitm[i].sub_type);
+ marshallShort(th, mitm[i].plus);
+ marshallShort(th, mitm[i].plus2);
+ marshallLong(th, mitm[i].special);
+ marshallShort(th, mitm[i].quantity);
+
+ marshallByte(th, mitm[i].colour);
+ marshallShort(th, mitm[i].x);
+ marshallShort(th, mitm[i].y);
+ marshallLong(th, mitm[i].flags);
+
+ marshallShort(th, mitm[i].link); // unused
+ marshallShort(th, igrd[mitm[i].x][mitm[i].y]); // unused
+ }
+}
+
+static void tag_construct_level_monsters(struct tagHeader &th)
+{
+ int i,j;
+
+ // how many mons_alloc?
+ marshallByte(th, 20);
+ for (i = 0; i < 20; ++i)
+ marshallShort(th, env.mons_alloc[i]);
+
+ // how many monsters?
+ marshallShort(th, MAX_MONSTERS);
+ // how many monster enchantments?
+ marshallByte(th, NUM_MON_ENCHANTS);
+ // how many monster inventory slots?
+ marshallByte(th, NUM_MONSTER_SLOTS);
+
+ for (i = 0; i < MAX_MONSTERS; i++)
+ {
+ marshallByte(th, menv[i].armour_class);
+ marshallByte(th, menv[i].evasion);
+ marshallByte(th, menv[i].hit_dice);
+ marshallByte(th, menv[i].speed);
+ marshallByte(th, menv[i].speed_increment);
+ marshallByte(th, menv[i].behaviour);
+ marshallByte(th, menv[i].x);
+ marshallByte(th, menv[i].y);
+ marshallByte(th, menv[i].target_x);
+ marshallByte(th, menv[i].target_y);
+ marshallByte(th, menv[i].flags);
+
+ for (j = 0; j < NUM_MON_ENCHANTS; j++)
+ marshallByte(th, menv[i].enchantment[j]);
+
+ marshallShort(th, menv[i].type);
+ marshallShort(th, menv[i].hit_points);
+ marshallShort(th, menv[i].max_hit_points);
+ marshallShort(th, menv[i].number);
+
+ for (j = 0; j < NUM_MONSTER_SLOTS; j++)
+ marshallShort(th, menv[i].inv[j]);
+ }
+}
+
+void tag_construct_level_attitude(struct tagHeader &th)
+{
+ int i;
+
+ // how many monsters?
+ marshallShort(th, MAX_MONSTERS);
+
+ for (i = 0; i < MAX_MONSTERS; i++)
+ {
+ marshallByte(th, menv[i].attitude);
+ marshallShort(th, menv[i].foe);
+ }
+}
+
+
+static void tag_read_level( struct tagHeader &th, char minorVersion )
+{
+ int i,j;
+ int gx, gy;
+
+ env.elapsed_time = (double)unmarshallFloat(th);
+
+ // map grids
+ // how many X?
+ gx = unmarshallShort(th);
+ // how many Y?
+ gy = unmarshallShort(th);
+ for (i = 0; i < gx; i++)
+ {
+ for (j = 0; j < gy; j++)
+ {
+ grd[i][j] = unmarshallByte(th);
+ env.map[i][j] = unmarshallByte(th);
+ if (env.map[i][j] == 201) // what is this??
+ env.map[i][j] = 239;
+
+ mgrd[i][j] = NON_MONSTER;
+ env.cgrid[i][j] = unmarshallByte(th);
+
+ if (minorVersion < 3)
+ {
+ // increased number of clouds to 100 in 4.3
+ if (env.cgrid[i][j] > 30)
+ env.cgrid[i][j] = 101;
+ }
+ }
+ }
+
+ env.cloud_no = unmarshallShort(th);
+
+ // how many clouds?
+ gx = unmarshallShort(th);
+ for (i = 0; i < gx; i++)
+ {
+ env.cloud[i].x = unmarshallByte(th);
+ env.cloud[i].y = unmarshallByte(th);
+ env.cloud[i].type = unmarshallByte(th);
+ env.cloud[i].decay = unmarshallShort(th);
+ }
+
+ // how many shops?
+ gx = unmarshallByte(th);
+ for (i = 0; i < gx; i++)
+ {
+ env.shop[i].keeper_name[0] = unmarshallByte(th);
+ env.shop[i].keeper_name[1] = unmarshallByte(th);
+ env.shop[i].keeper_name[2] = unmarshallByte(th);
+ env.shop[i].x = unmarshallByte(th);
+ env.shop[i].y = unmarshallByte(th);
+ env.shop[i].greed = unmarshallByte(th);
+ env.shop[i].type = unmarshallByte(th);
+ env.shop[i].level = unmarshallByte(th);
+ }
+}
+
+static void tag_read_level_items(struct tagHeader &th, char minorVersion)
+{
+ int i;
+ int count;
+
+ // how many traps?
+ count = unmarshallShort(th);
+ for (i = 0; i < count; ++i)
+ {
+ env.trap[i].type = unmarshallByte(th);
+ env.trap[i].x = unmarshallByte(th);
+ env.trap[i].y = unmarshallByte(th);
+ }
+
+ // how many items?
+ count = unmarshallShort(th);
+ for (i = 0; i < count; ++i)
+ {
+ if (minorVersion < 3)
+ {
+ mitm[i].base_type = (unsigned char) unmarshallByte(th);
+ mitm[i].sub_type = (unsigned char) unmarshallByte(th);
+ mitm[i].plus = (unsigned char) unmarshallByte(th);
+ mitm[i].plus2 = (unsigned char) unmarshallByte(th);
+ mitm[i].special = (unsigned char) unmarshallByte(th);
+ mitm[i].quantity = unmarshallLong(th);
+ mitm[i].colour = (unsigned char) unmarshallByte(th);
+ mitm[i].x = (unsigned char) unmarshallByte(th);
+ mitm[i].y = (unsigned char) unmarshallByte(th);
+ mitm[i].flags = (unsigned char) unmarshallByte(th);
+
+ tag_convert_to_4_3_item( mitm[i] );
+ }
+ else
+ {
+ mitm[i].base_type = (unsigned char) unmarshallByte(th);
+ mitm[i].sub_type = (unsigned char) unmarshallByte(th);
+ mitm[i].plus = unmarshallShort(th);
+ mitm[i].plus2 = unmarshallShort(th);
+ mitm[i].special = unmarshallLong(th);
+ mitm[i].quantity = unmarshallShort(th);
+ mitm[i].colour = (unsigned char) unmarshallByte(th);
+ mitm[i].x = unmarshallShort(th);
+ mitm[i].y = unmarshallShort(th);
+ mitm[i].flags = (unsigned long) unmarshallLong(th);
+ }
+
+ // pre 4.2 files had monster items stacked at (2,2) -- moved to (0,0)
+ if (minorVersion < 2 && mitm[i].x == 2 && mitm[i].y == 2)
+ {
+ mitm[i].x = 0;
+ mitm[i].y = 0;
+ }
+
+ unmarshallShort(th); // mitm[].link -- unused
+ unmarshallShort(th); // igrd[mitm[i].x][mitm[i].y] -- unused
+ }
+}
+
+static void tag_read_level_monsters(struct tagHeader &th, char minorVersion)
+{
+ int i,j;
+ int count, ecount, icount;
+
+ // how many mons_alloc?
+ count = unmarshallByte(th);
+ for (i = 0; i < count; ++i)
+ env.mons_alloc[i] = unmarshallShort(th);
+
+ // how many monsters?
+ count = unmarshallShort(th);
+ // how many monster enchantments?
+ ecount = unmarshallByte(th);
+ // how many monster inventory slots?
+ icount = unmarshallByte(th);
+
+ for (i = 0; i < count; i++)
+ {
+ menv[i].armour_class = unmarshallByte(th);
+ menv[i].evasion = unmarshallByte(th);
+ menv[i].hit_dice = unmarshallByte(th);
+ menv[i].speed = unmarshallByte(th);
+ menv[i].speed_increment = unmarshallByte(th);
+ menv[i].behaviour = unmarshallByte(th);
+ menv[i].x = unmarshallByte(th);
+ menv[i].y = unmarshallByte(th);
+ menv[i].target_x = unmarshallByte(th);
+ menv[i].target_y = unmarshallByte(th);
+ menv[i].flags = unmarshallByte(th);
+
+ // VERSION NOTICE: for pre 4.2 files, flags was either 0
+ // or 1. Now, we can transfer ENCH_CREATED_FRIENDLY over
+ // from the enchantments array to flags.
+ // Also need to take care of ENCH_FRIEND_ABJ_xx flags
+
+ for (j = 0; j < ecount; j++)
+ menv[i].enchantment[j] = unmarshallByte(th);
+
+ if (minorVersion < 2)
+ {
+ menv[i].flags = 0;
+ for(j=0; j<NUM_MON_ENCHANTS; j++)
+ {
+ if (j>=ecount)
+ menv[i].enchantment[j] = ENCH_NONE;
+ else
+ {
+ if (menv[i].enchantment[j] == 71) // old ENCH_CREATED_FRIENDLY
+ {
+ menv[i].enchantment[j] = ENCH_NONE;
+ menv[i].flags |= MF_CREATED_FRIENDLY;
+ }
+ if (menv[i].enchantment[j] >= 65 // old ENCH_FRIEND_ABJ_I
+ && menv[i].enchantment[j] <= 70) // old ENCH_FRIEND_ABJ_VI
+ {
+ menv[i].enchantment[j] -= (65 - ENCH_ABJ_I);
+ menv[i].flags |= MF_CREATED_FRIENDLY;
+ }
+ }
+ }
+ } // end minorversion < 2
+
+ menv[i].type = unmarshallShort(th);
+ menv[i].hit_points = unmarshallShort(th);
+ menv[i].max_hit_points = unmarshallShort(th);
+ menv[i].number = unmarshallShort(th);
+
+ for (j = 0; j < icount; j++)
+ menv[i].inv[j] = unmarshallShort(th);
+
+ // place monster
+ if (menv[i].type != -1)
+ mgrd[menv[i].x][menv[i].y] = i;
+ }
+}
+
+void tag_read_level_attitude(struct tagHeader &th)
+{
+ int i, count;
+
+ // how many monsters?
+ count = unmarshallShort(th);
+
+ for (i = 0; i < count; i++)
+ {
+ menv[i].attitude = unmarshallByte(th);
+ menv[i].foe = unmarshallShort(th);
+ }
+}
+
+void tag_missing_level_attitude()
+{
+ // we don't really have to do a lot here.
+ // just set foe to MHITNOT; they'll pick up
+ // a foe first time through handle_monster() if
+ // there's one around.
+
+ // as for attitude, a couple simple checks
+ // can be used to determine friendly/neutral/
+ // hostile.
+ int i;
+ bool isFriendly;
+ unsigned int new_beh = BEH_WANDER;
+
+ for(i=0; i<MAX_MONSTERS; i++)
+ {
+ // only do actual monsters
+ if (menv[i].type < 0)
+ continue;
+
+ isFriendly = testbits(menv[i].flags, MF_CREATED_FRIENDLY);
+
+ menv[i].foe = MHITNOT;
+
+ switch(menv[i].behaviour)
+ {
+ case 0: // old BEH_SLEEP
+ new_beh = BEH_SLEEP; // don't wake sleepers
+ break;
+ case 3: // old BEH_FLEE
+ case 10: // old BEH_FLEE_FRIEND
+ new_beh = BEH_FLEE;
+ break;
+ case 1: // old BEH_CHASING_I
+ case 6: // old BEH_FIGHT
+ new_beh = BEH_SEEK;
+ break;
+ case 7: // old BEH_ENSLAVED
+ if (!mons_has_ench(&menv[i], ENCH_CHARM))
+ isFriendly = true;
+ break;
+ default:
+ break;
+ }
+
+ menv[i].attitude = (isFriendly)?ATT_FRIENDLY : ATT_HOSTILE;
+ menv[i].behaviour = new_beh;
+ menv[i].foe_memory = 0;
+ }
+}
+
+
+// ------------------------------- ghost tags ---------------------------- //
+
+static void tag_construct_ghost(struct tagHeader &th)
+{
+ int i;
+
+ marshallString(th, ghost.name, 20);
+
+ // how many ghost values?
+ marshallByte(th, 20);
+
+ for (i = 0; i < 20; i++)
+ marshallShort( th, ghost.values[i] );
+}
+
+static void tag_read_ghost(struct tagHeader &th, char minorVersion)
+{
+ int i, count_c;
+
+ snprintf( info, INFO_SIZE, "minor version = %d", minorVersion );
+
+ unmarshallString(th, ghost.name, 20);
+
+ // how many ghost values?
+ count_c = unmarshallByte(th);
+
+ for (i = 0; i < count_c; i++)
+ {
+ // for version 4.4 we moved from unsigned char to shorts -- bwr
+ if (minorVersion < 4)
+ ghost.values[i] = unmarshallByte(th);
+ else
+ ghost.values[i] = unmarshallShort(th);
+ }
+
+ if (minorVersion < 4)
+ {
+ // Getting rid 9of hopefulling the last) of this silliness -- bwr
+ if (ghost.values[ GVAL_RES_FIRE ] >= 97)
+ ghost.values[ GVAL_RES_FIRE ] -= 100;
+
+ if (ghost.values[ GVAL_RES_COLD ] >= 97)
+ ghost.values[ GVAL_RES_COLD ] -= 100;
+ }
+}
+
+// ----------------------------------------------------------------------- //
diff --git a/trunk/source/tags.h b/trunk/source/tags.h
new file mode 100644
index 0000000000..9b7a0e85e9
--- /dev/null
+++ b/trunk/source/tags.h
@@ -0,0 +1,97 @@
+/*
+ * File: tags.h
+ * Summary: Auxilary functions to make savefile versioning simpler.
+ * Written by: Gordon Lipford
+ *
+ * Change History (most recent first):
+ *
+ * <1> 27 Jan 2001 GDL Created
+ */
+
+#ifndef TAGS_H
+#define TAGS_H
+
+#include <stdio.h>
+#include "externs.h"
+
+// last updated 22jan2001 {gdl}
+/* ***********************************************************************
+ * called from: files tags
+ * *********************************************************************** */
+int write2(FILE * file, char *buffer, unsigned int count);
+
+
+// last updated 22jan2001 {gdl}
+/* ***********************************************************************
+ * called from: files tags
+ * *********************************************************************** */
+int read2(FILE * file, char *buffer, unsigned int count);
+
+
+// last updated 22jan2001 {gdl}
+/* ***********************************************************************
+ * called from: files tags
+ * *********************************************************************** */
+void marshallByte(struct tagHeader &th, char data);
+void marshallShort(struct tagHeader &th, short data);
+void marshallLong(struct tagHeader &th, long data);
+void marshallFloat(struct tagHeader &th, float data);
+void marshallBoolean(struct tagHeader &th, bool data);
+void marshallString(struct tagHeader &th, char *data, int maxSize = 0);
+
+// last updated 22jan2001 {gdl}
+/* ***********************************************************************
+ * called from: tags files
+ * *********************************************************************** */
+char unmarshallByte(struct tagHeader &th);
+short unmarshallShort(struct tagHeader &th);
+long unmarshallLong(struct tagHeader &th);
+float unmarshallFloat(struct tagHeader &th);
+bool unmarshallBoolean(struct tagHeader &th);
+void unmarshallString(struct tagHeader &th, char *data, int maxSize);
+
+void make_date_string( time_t in_date, char buff[20] );
+time_t parse_date_string( char[20] );
+
+// last updated 22jan2001 {gdl}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void tag_init(long largest_tag = 50000);
+
+
+// last updated 22jan2001 {gdl}
+/* ***********************************************************************
+ * called from: files
+ * *********************************************************************** */
+void tag_construct(struct tagHeader &th, int i);
+
+
+// last updated 22jan2001 {gdl}
+/* ***********************************************************************
+ * called from: files
+ * *********************************************************************** */
+void tag_write(struct tagHeader &th, FILE *saveFile);
+
+
+// last updated 22jan2001 {gdl}
+/* ***********************************************************************
+ * called from: files
+ * *********************************************************************** */
+void tag_set_expected(char tags[], int fileType);
+
+
+// last updated 22jan2001 {gdl}
+/* ***********************************************************************
+ * called from: files
+ * *********************************************************************** */
+void tag_missing(int tag, char minorVersion);
+
+
+// last updated 22jan2001 {gdl}
+/* ***********************************************************************
+ * called from: files
+ * *********************************************************************** */
+int tag_read(FILE *fp, char minorVersion);
+
+#endif // TAGS_H
diff --git a/trunk/source/transfor.cc b/trunk/source/transfor.cc
new file mode 100644
index 0000000000..9ee38d548d
--- /dev/null
+++ b/trunk/source/transfor.cc
@@ -0,0 +1,551 @@
+/*
+ * File: transfor.cc
+ * Summary: Misc function related to player transformations.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <2> 5/26/99 JDJ transform() and untransform() set you.wield_change so
+ * the weapon line updates.
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "transfor.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "externs.h"
+
+#include "it_use2.h"
+#include "itemname.h"
+#include "items.h"
+#include "misc.h"
+#include "player.h"
+#include "skills2.h"
+#include "stuff.h"
+
+extern unsigned char your_sign; // defined in view.cc
+extern unsigned char your_colour; // defined in view.cc
+void drop_everything(void);
+void extra_hp(int amount_extra);
+
+bool remove_equipment(FixedVector < char, 8 > &remove_stuff)
+{
+ char str_pass[ ITEMNAME_SIZE ];
+
+ // if we're removing body armour, the cloak will come off as well -- bwr
+ if (remove_stuff[EQ_BODY_ARMOUR] == 1 && you.equip[EQ_BODY_ARMOUR] != -1)
+ remove_stuff[EQ_CLOAK] = 1;
+
+ // if we're removing gloves, the weapon will come off as well -- bwr
+ if (remove_stuff[EQ_GLOVES] == 1 && you.equip[EQ_GLOVES] != -1)
+ remove_stuff[EQ_WEAPON] = 1;
+
+ if (remove_stuff[EQ_WEAPON] == 1 && you.equip[EQ_WEAPON] != -1)
+ {
+ unwield_item(you.equip[EQ_WEAPON]);
+ you.equip[EQ_WEAPON] = -1;
+ mpr("You are empty-handed.");
+ you.wield_change = true;
+ }
+
+ for (int i = EQ_CLOAK; i < EQ_LEFT_RING; i++)
+ {
+ if (remove_stuff[i] == 0 || you.equip[i] == -1)
+ continue;
+
+ in_name( you.equip[i], DESC_CAP_YOUR, str_pass );
+
+ snprintf( info, INFO_SIZE, "%s falls away.", str_pass );
+ mpr(info);
+
+ unwear_armour( you.equip[i] );
+ you.equip[i] = -1;
+ }
+
+ return true;
+} // end remove_equipment()
+
+// Returns true if any piece of equipment that has to be removed is cursed.
+// Useful for keeping low level transformations from being too useful.
+static bool check_for_cursed_equipment( FixedVector < char, 8 > &remove_stuff )
+{
+ for (int i = EQ_WEAPON; i < EQ_LEFT_RING; i++)
+ {
+ if (remove_stuff[i] == 0 || you.equip[i] == -1)
+ continue;
+
+ if (item_cursed( you.inv[ you.equip[i] ] ))
+ {
+ mpr( "Your cursed equipment won't allow you to complete the "
+ "transformation." );
+
+ return (true);
+ }
+ }
+
+ return (false);
+} // end check_for_cursed_equipment()
+
+bool transform(int pow, char which_trans)
+{
+ if (you.species == SP_MERFOLK && player_is_swimming()
+ && which_trans != TRAN_DRAGON)
+ {
+ // This might by overkill, but it's okay because obviously
+ // whatever magical ability that let's them walk on land is
+ // removed when they're in water (in this case, their natural
+ // form is completely over-riding any other... goes well with
+ // the forced transform when entering water)... but merfolk can
+ // transform into dragons, because dragons fly. -- bwr
+ mpr("You cannot transform out of your normal form while in water.");
+ return (false);
+ }
+
+ // This must occur before the untransform() and the is_undead check.
+ if (you.attribute[ATTR_TRANSFORMATION] == which_trans)
+ {
+ if (you.duration[DUR_TRANSFORMATION] < 100)
+ {
+ mpr( "You extend your transformation's duration." );
+ you.duration[DUR_TRANSFORMATION] += random2(pow);
+
+ if (you.duration[DUR_TRANSFORMATION] > 100)
+ you.duration[DUR_TRANSFORMATION] = 100;
+
+ return (true);
+ }
+ else
+ {
+ mpr( "You cannot extend your transformation any further!" );
+ return (false);
+ }
+ }
+
+ if (you.attribute[ATTR_TRANSFORMATION] != TRAN_NONE)
+ untransform();
+
+ if (you.is_undead)
+ {
+ mpr("Your unliving flesh cannot be transformed in this way.");
+ return (false);
+ }
+
+ //jmf: silently discard this enchantment
+ you.duration[DUR_STONESKIN] = 0;
+
+ FixedVector < char, 8 > rem_stuff;
+
+ for (int i = EQ_WEAPON; i < EQ_RIGHT_RING; i++)
+ rem_stuff[i] = 1;
+
+ you.redraw_evasion = 1;
+ you.redraw_armour_class = 1;
+ you.wield_change = true;
+
+ /* Remember, it can still fail in the switch below... */
+ switch (which_trans)
+ {
+ case TRAN_SPIDER: // also AC +3, ev +3, fast_run
+ if (check_for_cursed_equipment( rem_stuff ))
+ return (false);
+
+ mpr("You turn into a venomous arachnid creature.");
+ remove_equipment( rem_stuff );
+
+ you.attribute[ATTR_TRANSFORMATION] = TRAN_SPIDER;
+ you.duration[DUR_TRANSFORMATION] = 10 + random2(pow) + random2(pow);
+
+ if (you.duration[DUR_TRANSFORMATION] > 60)
+ you.duration[DUR_TRANSFORMATION] = 60;
+
+ modify_stat( STAT_DEXTERITY, 5, true );
+
+ your_sign = 's';
+ your_colour = BROWN;
+ return (true);
+
+ case TRAN_ICE_BEAST: // also AC +3, cold +3, fire -1, pois +1
+ mpr( "You turn into a creature of crystalline ice." );
+
+ rem_stuff[ EQ_CLOAK ] = 0;
+
+ remove_equipment( rem_stuff );
+
+ you.attribute[ATTR_TRANSFORMATION] = TRAN_ICE_BEAST;
+ you.duration[DUR_TRANSFORMATION] = 30 + random2(pow) + random2(pow);
+
+ if (you.duration[ DUR_TRANSFORMATION ] > 100)
+ you.duration[ DUR_TRANSFORMATION ] = 100;
+
+ extra_hp(12); // must occur after attribute set
+
+ if (you.duration[DUR_ICY_ARMOUR])
+ mpr( "Your new body merges with your icy armour." );
+
+ your_sign = 'I';
+ your_colour = WHITE;
+ return (true);
+
+ case TRAN_BLADE_HANDS:
+ rem_stuff[EQ_CLOAK] = 0;
+ rem_stuff[EQ_HELMET] = 0;
+ rem_stuff[EQ_BOOTS] = 0;
+ rem_stuff[EQ_BODY_ARMOUR] = 0;
+
+ if (check_for_cursed_equipment( rem_stuff ))
+ return (false);
+
+ mpr("Your hands turn into razor-sharp scythe blades.");
+ remove_equipment( rem_stuff );
+
+ you.attribute[ATTR_TRANSFORMATION] = TRAN_BLADE_HANDS;
+ you.duration[DUR_TRANSFORMATION] = 10 + random2(pow);
+
+ if (you.duration[ DUR_TRANSFORMATION ] > 100)
+ you.duration[ DUR_TRANSFORMATION ] = 100;
+ return (true);
+
+ case TRAN_STATUE: // also AC +20, ev -5, elec +1, pois +1, neg +1, slow
+ if (you.species == SP_GNOME && coinflip())
+ mpr( "Look, a garden gnome. How cute!" );
+ else if (player_genus(GENPC_DWARVEN) && one_chance_in(10))
+ mpr( "You inwardly fear your resemblance to a lawn ornament." );
+ else
+ mpr( "You turn into a living statue of rough stone." );
+
+ rem_stuff[ EQ_WEAPON ] = 0; /* can still hold a weapon */
+ rem_stuff[ EQ_CLOAK ] = 0;
+ rem_stuff[ EQ_HELMET ] = 0;
+ rem_stuff[ EQ_BOOTS ] = 0;
+ // too stiff to make use of shields, gloves, or armour -- bwr
+
+ remove_equipment( rem_stuff );
+
+ you.attribute[ATTR_TRANSFORMATION] = TRAN_STATUE;
+ you.duration[DUR_TRANSFORMATION] = 20 + random2(pow) + random2(pow);
+
+ if (you.duration[ DUR_TRANSFORMATION ] > 100)
+ you.duration[ DUR_TRANSFORMATION ] = 100;
+
+ modify_stat( STAT_DEXTERITY, -2, true );
+ modify_stat( STAT_STRENGTH, 2, true );
+ extra_hp(15); // must occur after attribute set
+
+ if (you.duration[DUR_STONEMAIL] || you.duration[DUR_STONESKIN])
+ mpr( "Your new body merges with your stone armour." );
+
+ your_sign = '8';
+ your_colour = LIGHTGREY;
+ return (true);
+
+ case TRAN_DRAGON: // also AC +10, ev -3, cold -1, fire +2, pois +1, flight
+ if (you.species == SP_MERFOLK && player_is_swimming())
+ mpr("You fly out of the water as you turn into a fearsome dragon!");
+ else
+ mpr("You turn into a fearsome dragon!");
+
+ remove_equipment(rem_stuff);
+
+ you.attribute[ATTR_TRANSFORMATION] = TRAN_DRAGON;
+ you.duration[DUR_TRANSFORMATION] = 20 + random2(pow) + random2(pow);
+
+ if (you.duration[ DUR_TRANSFORMATION ] > 100)
+ you.duration[ DUR_TRANSFORMATION ] = 100;
+
+ modify_stat( STAT_STRENGTH, 10, true );
+ extra_hp(16); // must occur after attribute set
+
+ your_sign = 'D';
+ your_colour = GREEN;
+ return (true);
+
+ case TRAN_LICH:
+ // also AC +3, cold +1, neg +3, pois +1, is_undead, res magic +50,
+ // spec_death +1, and drain attack (if empty-handed)
+ if (you.deaths_door)
+ {
+ mpr( "The transformation conflicts with an enchantment "
+ "already in effect." );
+
+ return (false);
+ }
+
+ mpr("Your body is suffused with negative energy!");
+
+ // undead cannot regenerate -- bwr
+ if (you.duration[DUR_REGENERATION])
+ {
+ mpr( "You stop regenerating.", MSGCH_DURATION );
+ you.duration[DUR_REGENERATION] = 0;
+ }
+
+ // silently removed since undead automatically resist poison -- bwr
+ you.duration[DUR_RESIST_POISON] = 0;
+
+ /* no remove_equip */
+ you.attribute[ATTR_TRANSFORMATION] = TRAN_LICH;
+ you.duration[DUR_TRANSFORMATION] = 20 + random2(pow) + random2(pow);
+
+ if (you.duration[ DUR_TRANSFORMATION ] > 100)
+ you.duration[ DUR_TRANSFORMATION ] = 100;
+
+ modify_stat( STAT_STRENGTH, 3, true );
+ your_sign = 'L';
+ your_colour = LIGHTGREY;
+ you.is_undead = US_UNDEAD;
+ you.hunger_state = HS_SATIATED; // no hunger effects while transformed
+ set_redraw_status( REDRAW_HUNGER );
+ return (true);
+
+ case TRAN_AIR:
+ // also AC 20, ev +20, regen/2, no hunger, fire -2, cold -2, air +2,
+ // pois +1, spec_earth -1
+ mpr( "You feel diffuse..." );
+
+ remove_equipment(rem_stuff);
+
+ drop_everything();
+
+ you.attribute[ATTR_TRANSFORMATION] = TRAN_AIR;
+ you.duration[DUR_TRANSFORMATION] = 35 + random2(pow) + random2(pow);
+
+ if (you.duration[ DUR_TRANSFORMATION ] > 150)
+ you.duration[ DUR_TRANSFORMATION ] = 150;
+
+ modify_stat( STAT_DEXTERITY, 8, true );
+ your_sign = '#';
+ your_colour = DARKGREY;
+ return (true);
+
+ case TRAN_SERPENT_OF_HELL:
+ // also AC +10, ev -5, fire +2, pois +1, life +2, slow
+ mpr( "You transform into a huge demonic serpent!" );
+
+ remove_equipment(rem_stuff);
+
+ you.attribute[ATTR_TRANSFORMATION] = TRAN_SERPENT_OF_HELL;
+ you.duration[DUR_TRANSFORMATION] = 20 + random2(pow) + random2(pow);
+
+ if (you.duration[ DUR_TRANSFORMATION ] > 120)
+ you.duration[ DUR_TRANSFORMATION ] = 120;
+
+ modify_stat( STAT_STRENGTH, 13, true );
+ extra_hp(17); // must occur after attribute set
+
+ your_sign = 'S';
+ your_colour = RED;
+ return (true);
+ }
+
+ return (false);
+} // end transform()
+
+void untransform(void)
+{
+ FixedVector < char, 8 > rem_stuff;
+
+ for (int i = EQ_WEAPON; i < EQ_RIGHT_RING; i++)
+ rem_stuff[i] = 0;
+
+ you.redraw_evasion = 1;
+ you.redraw_armour_class = 1;
+ you.wield_change = true;
+
+ your_sign = '@';
+ your_colour = LIGHTGREY;
+
+ // must be unset first or else infinite loops might result -- bwr
+ const int old_form = you.attribute[ ATTR_TRANSFORMATION ];
+ you.attribute[ ATTR_TRANSFORMATION ] = TRAN_NONE;
+ you.duration[ DUR_TRANSFORMATION ] = 0;
+
+ switch (old_form)
+ {
+ case TRAN_SPIDER:
+ mpr("Your transformation has ended.", MSGCH_DURATION);
+ modify_stat( STAT_DEXTERITY, -5, true );
+ break;
+
+ case TRAN_BLADE_HANDS:
+ mpr( "Your hands revert to their normal proportions.", MSGCH_DURATION );
+ you.wield_change = true;
+ break;
+
+ case TRAN_STATUE:
+ mpr( "You revert to your normal fleshy form.", MSGCH_DURATION );
+ modify_stat( STAT_DEXTERITY, 2, true );
+ modify_stat( STAT_STRENGTH, -2, true );
+
+ // Note: if the core goes down, the combined effect soon disappears,
+ // but the reverse isn't true. -- bwr
+ if (you.duration[DUR_STONEMAIL])
+ you.duration[DUR_STONEMAIL] = 1;
+
+ if (you.duration[DUR_STONESKIN])
+ you.duration[DUR_STONESKIN] = 1;
+ break;
+
+ case TRAN_ICE_BEAST:
+ mpr( "You warm up again.", MSGCH_DURATION );
+
+ // Note: if the core goes down, the combined effect soon disappears,
+ // but the reverse isn't true. -- bwr
+ if (you.duration[DUR_ICY_ARMOUR])
+ you.duration[DUR_ICY_ARMOUR] = 1;
+ break;
+
+ case TRAN_DRAGON:
+ mpr( "Your transformation has ended.", MSGCH_DURATION );
+ modify_stat(STAT_STRENGTH, -10, true);
+
+ if (!player_is_levitating()
+ && (grd[you.x_pos][you.y_pos] == DNGN_LAVA
+ || grd[you.x_pos][you.y_pos] == DNGN_DEEP_WATER
+ || grd[you.x_pos][you.y_pos] == DNGN_SHALLOW_WATER))
+ {
+ if (you.species == SP_MERFOLK
+ && grd[you.x_pos][you.y_pos] != DNGN_LAVA)
+ {
+ mpr("You dive into the water and return to your normal form.");
+ merfolk_start_swimming();
+ }
+
+ if (grd[you.x_pos][you.y_pos] != DNGN_SHALLOW_WATER)
+ fall_into_a_pool( true, grd[you.x_pos][you.y_pos] );
+ }
+ break;
+
+ case TRAN_LICH:
+ mpr( "You feel yourself come back to life.", MSGCH_DURATION );
+ modify_stat(STAT_STRENGTH, -3, true);
+ you.is_undead = US_ALIVE;
+ break;
+
+ case TRAN_AIR:
+ mpr( "Your body solidifies.", MSGCH_DURATION );
+ modify_stat(STAT_DEXTERITY, -8, true);
+ break;
+
+ case TRAN_SERPENT_OF_HELL:
+ mpr( "Your transformation has ended.", MSGCH_DURATION );
+ modify_stat(STAT_STRENGTH, -13, true);
+ break;
+ }
+
+ // If nagas wear boots while transformed, they fall off again afterwards:
+ // I don't believe this is currently possible, and if it is we
+ // probably need something better to cover all possibilities. -bwr
+ if ((you.species == SP_NAGA || you.species == SP_CENTAUR)
+ && you.equip[ EQ_BOOTS ] != -1
+ && you.inv[ you.equip[EQ_BOOTS] ].plus2 != TBOOT_NAGA_BARDING)
+ {
+ rem_stuff[EQ_BOOTS] = 1;
+ remove_equipment(rem_stuff);
+ }
+
+ calc_hp();
+} // end untransform()
+
+// XXX: This whole system is a mess as it still relies on special
+// cases to handle a large number of things (see wear_armour()) -- bwr
+bool can_equip( char use_which )
+{
+
+ // if more cases are added to this if must also change in
+ // item_use for naga barding
+ if (!player_is_shapechanged())
+ /* or a transformation which doesn't change overall shape */
+ {
+ if (use_which == EQ_BOOTS)
+ {
+ switch (you.species)
+ {
+ case SP_NAGA:
+ case SP_CENTAUR:
+ case SP_KENKU:
+ return (false);
+ default:
+ break;
+ }
+ }
+ else if (use_which == EQ_HELMET)
+ {
+ switch (you.species)
+ {
+ case SP_MINOTAUR:
+ case SP_KENKU:
+ return (false);
+ default:
+ break;
+ }
+ }
+ }
+
+ if (use_which == EQ_HELMET && you.mutation[MUT_HORNS])
+ return (false);
+
+ if (use_which == EQ_BOOTS && you.mutation[MUT_HOOVES])
+ return (false);
+
+ if (use_which == EQ_GLOVES && you.mutation[MUT_CLAWS] >= 3)
+ return (false);
+
+ switch (you.attribute[ATTR_TRANSFORMATION])
+ {
+ case TRAN_NONE:
+ case TRAN_LICH:
+ return (true);
+
+ case TRAN_BLADE_HANDS:
+ return (use_which != EQ_WEAPON
+ && use_which != EQ_GLOVES
+ && use_which != EQ_SHIELD);
+
+ case TRAN_STATUE:
+ return (use_which == EQ_WEAPON
+ || use_which == EQ_CLOAK
+ || use_which == EQ_HELMET);
+
+ case TRAN_ICE_BEAST:
+ return (use_which == EQ_CLOAK);
+
+ default:
+ return (false);
+ }
+
+ return (true);
+} // end can_equip()
+
+void extra_hp(int amount_extra) // must also set in calc_hp
+{
+ calc_hp();
+
+ you.hp *= amount_extra;
+ you.hp /= 10;
+
+ deflate_hp(you.hp_max, false);
+} // end extra_hp()
+
+void drop_everything(void)
+{
+ int i = 0;
+
+ if (inv_count() < 1)
+ return;
+
+ mpr( "You find yourself unable to carry your possessions!" );
+
+ for (i = 0; i < ENDOFPACK; i++)
+ {
+ if (is_valid_item( you.inv[i] ))
+ {
+ copy_item_to_grid( you.inv[i], you.x_pos, you.y_pos );
+ you.inv[i].quantity = 0;
+ }
+ }
+
+ return;
+} // end drop_everything()
diff --git a/trunk/source/transfor.h b/trunk/source/transfor.h
new file mode 100644
index 0000000000..5efa5a87b2
--- /dev/null
+++ b/trunk/source/transfor.h
@@ -0,0 +1,46 @@
+/*
+ * File: transfor.cc
+ * Summary: Misc function related to player transformations.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef TRANSFOR_H
+#define TRANSFOR_H
+
+#include "FixVec.h"
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - transfor
+ * *********************************************************************** */
+void untransform(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: item_use
+ * *********************************************************************** */
+bool can_equip(char use_which);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - spell
+ * *********************************************************************** */
+bool transform(int pow, char which_trans);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: mutation - transfor
+ * *********************************************************************** */
+bool remove_equipment( FixedVector<char, 8>& remove_stuff );
+
+
+#endif
diff --git a/trunk/source/unrand.h b/trunk/source/unrand.h
new file mode 100644
index 0000000000..595da409c0
--- /dev/null
+++ b/trunk/source/unrand.h
@@ -0,0 +1,1138 @@
+/*
+ * File: unrand.cc
+ * Summary: Definitions for unrandom artifacts.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ * <3> 7 Aug 2001 MV Added many new items
+ * <2> 5/09/99 JDJ Cekugob no longer has fire and cold
+ * resistances.
+ * <1> -/--/-- LRH Created
+ */
+#ifndef UNRAND_H
+#define UNRAND_H
+
+#include "defines.h"
+
+/*
+ List of "unrandom" artefacts. Not the same as "fixed" artefacts, which are
+ completely hardcoded (eg Singing Sword, Wrath of Trog).
+ note: the order of the list doesn't matter
+ Because the list numbering starts at 1, the last entry is the highest value
+ which can be given to NO_UNRANDARTS (eg if the list consists of randarts no
+ 1, 2 or 3, NO_UNRANDARTS must be set to 3 or lower, but probably not to 0).
+ Setting it higher could cause nasty problems.
+
+ Okay, so the steps to adding a new unrandart go as follows:
+ 1) - Fill in a new entry below, using the following guidelines:
+ true name: The name which is displayed when the item is id'd
+ un-id'd name: obvious
+ class: weapon, armour etc
+ type: long sword, plate mail etc. Jewellery unrandarts have the powers of
+ their base types in addition to anything else.
+ plus: For weapons, plus to-hit. For armour, plus. For jewellery, irrelevant.
+ But add 100 to make the item stickycursed. Note that the values for
+ wpns and armr are +50.
+ plus2: For wpns, plus to-dam. Curses are irrelevant here. Mostly unused
+ for armr and totally for rings. Armour: if boots, plus2 == 1 means
+ naga barding; 2 means centaur barding. If headgear, 1 means helmet,
+ 2 means helm, 3 means cap, 4 means wizard's hat.
+ colour: Obvious. Don't use BLACK, use DARKGREY instead.
+
+ * Note * any exact combination of class, type, plus & plus2 must be unique,
+ so (for example) you can't have two +5, +5 long swords in the list. Curses
+ don't count as distinguishing factors.
+
+ brand: Weapons only. Have a look in enum.h for a list, and look in fight.cc
+ and describe.cc for the effects.
+ Range of possible values: see enum.h
+
+ +/- to AC, ev, str, int, dex - These are pretty obvious. Be careful - a player
+ with a negative str, int or dex dies instantly, so avoid high penalties
+ to these stats.
+ Range: any, but be careful.
+
+ res fire, res cold: Resists. Can be above 1; multiple sources of fire or cold
+ resist *are* cumulative. Can also be -1 (but probably not -2 or below)
+ for susceptibility.
+ Range: -1 to about 5, after which you'll become almost immune.
+ res elec: Resist electricity. Unlike fire and cold, resist electricity
+ reduces electrical damage to 0. This makes multiple resists irrelevant.
+ Also is no susceptibility, so don't use -1.
+ Range: 0 or 1.
+ res poison: same as res electricity.
+ Range: 0 or 1.
+ life prot: Stops energy draining and negative energy attacks. Not cumulative,
+ and no susceptibility here either.
+ Range: 0 or 1.
+
+ res magic: This is cumulative, but no susceptibility. To be meaningful,
+ should be set to about 20 - 60.
+ Range: 0 to MAXINT probably, but about 100 is a realistic ceiling.
+
+ see invis: Lets you see invisible things, but not submerged water beasts.
+ Range: 0 or 1.
+ turn invis: Gives you the ability to turn invisible using the 'a' menu.
+ levitate, blink, go berserk, sense surroundings: like turn invis.
+ Ranges for all these: 0 or 1.
+
+ make noise: Irritate nearby creatures and disrupts rest. Weapons only.
+ Range: 1 - 4, for different types of noises (see special_wielded() in
+ it_use3.cc); 0 for none.
+ no spells: Prevents any spellcasting (but not scrolls or wands etc)
+ Range: 0 or 1.
+ teleport: Every now and then randomly teleports you. *Really* annoying.
+ Weapons only.
+ Range: 0 to about 15 (higher means more teleporting).
+ no teleport: Prevents the player from teleporting, except rarely when they're
+ forced to (eg banished to the Abyss).
+ Range: 0 or 1.
+
+ force berserk: Every time you attack, you go berserk. Weapons only.
+ Range: 0 or 1.
+ speed metabolism: Makes you consume food faster. No effect on mummies.
+ Range: 0 to about 4. 4 would be horrible; 1 is annoying but tolerable.
+ mutate: makes you mutate, sometimes after a long delay. No effect on some
+ races (espec undead).
+ Range: 0 to about 4.
+ +/- to-hit/to-dam: Obvious. Affects both melee and missile. Should be left
+ at 0 for weapons, which get +s normally.
+
+ cursed: 0 or 1. Sets the item's initial curse status. Cursed items
+ will tend to recurse themselves when rewielded. Maybe this should be
+ made to be a value that determines how often it will recurse? -- bwr
+
+ stealth: -100 to 80. Adds to stealth value.
+
+ Some currently unused properties follow, then:
+
+ First string: is appended to the unrandart's 'V' description when id'd.
+
+ Second string: replaces the thing at the start of a 'V' description.
+ If empty, uses the description of the unrandart's base type. Note: the
+ base type of a piece of unrandart jewellery is relevant to its function, so
+ don't obscure it unnecessarily.
+
+ Then another unused string.
+
+ 2) - Add one to the #define NO_UNRANDARTS line in randart.h
+
+ 3) - Maybe increase the probability of an unrandart of the appropriate
+ type being created; look in dungeon.cc for this (search for "unrand").
+ Forget this step if you don't understand it; it's of very little importance.
+
+ Done! Now recompile and wait years for it to turn up.
+
+ Note: changing NO_UNRANDARTS probably makes savefiles incompatible.
+
+ */
+
+/* This is a dummy, but still counts for NO_UNRANDARTS */
+/* 1 */
+{
+ "Dum", "",
+/* class, type, plus (to-hit), plus2 (depends on class), colour */
+ 250, 250, 250, 250, 0,
+/* Properties, all approx thirty of them: */
+ {
+/* brand, +/- to AC, +/- to ev, +/- to str, +/- to int, +/- to dex */
+ 0, 0, 0, 0, 0, 0,
+/* res fire, res cold, res elec, res poison, life protection, res magic */
+ 0, 0, 0, 0, 0, 0,
+/* see invis, turn invis, levitate, blink, teleport at will, go berserk */
+ 0, 0, 0, 0, 0, 0,
+/* sense surroundings, make noise, no spells, teleport, no teleprt */
+ 0, 0, 0, 0, 0,
+/* force berserk, speed metabolism, mutate, +/- to hit, +/- to dam (not weapons) */
+ 0, 0, 0, 0, 0,
+/* cursed, stealth */
+ 0, 0
+ }
+ ,
+/* Special description appended to the 'V' description */
+ "",
+/* Base description of item */
+ "",
+/* Unused string */
+ ""
+}
+,
+
+
+/* 2 */
+{
+ "long sword \"Bloodbane\"", "blackened long sword",
+ OBJ_WEAPONS, WPN_LONG_SWORD, +7, +8, DARKGREY,
+ {
+ SPWPN_VORPAL, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, // berserk
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, // force berserk
+ 0, -20 // stealth
+ }
+ ,
+ "",
+ "",
+ ""
+}
+,
+
+/* 3 */
+{
+ "ring of Shadows", "black ring",
+ OBJ_JEWELLERY, RING_INVISIBILITY, 0, 0, DARKGREY,
+ {
+ 0, 0, 4, 0, 0, 0, // EV
+ 0, 0, 0, 0, 1, 0, // life prot
+ 1, 0, 0, 0, 0, 0, // see invis
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, -3, 0, // to hit
+ 0, 10 // stealth
+ }
+ ,
+ "",
+ "",
+ ""
+}
+,
+
+/* 4 */
+{
+ "long sword of Flaming Death", "smoking long sword",
+ OBJ_WEAPONS, WPN_LONG_SWORD, +6, +2, RED,
+ {
+ SPWPN_FLAMING, 0, 0, 0, 0, 0,
+ 2, -1, 0, 1, 0, 20, // res fire, cold, poison, magic
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "",
+ "",
+ ""
+}
+,
+
+/* 5 */
+{
+ "shield of Ignorance", "dull large shield",
+ OBJ_ARMOUR, ARM_LARGE_SHIELD, +5, 0, BROWN,
+ {
+ 0, 2, 2, 0, -6, 0, // AC, EV, int
+ 0, 0, 0, 0, 1, 0, // life prot
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0 // cursed
+ }
+ ,
+ "",
+ "",
+ ""
+}
+,
+
+
+/* 6 */
+{
+ "Holy Armour of Zin", "glowing golden plate mail",
+ OBJ_ARMOUR, ARM_PLATE_MAIL, +6, 0, YELLOW,
+ {
+ 0, 0, 0, 3, 0, 0, // str
+ 0, 0, 0, 0, 2, 50, // life prot, magic
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "",
+ "A suit of mail and large plates of golden metal.",
+ ""
+}
+,
+
+/* 7 */
+{
+ "robe of Augmentation", "silk robe",
+ OBJ_ARMOUR, ARM_ROBE, +4, 0, LIGHTRED,
+ {
+ 0, 0, 0, 2, 2, 2, // str, int, dex
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "",
+ "A robe made of the finest silk.",
+ ""
+}
+,
+
+/* 8 */
+{
+ "mace of Brilliance", "brightly glowing mace",
+ OBJ_WEAPONS, WPN_MACE, +5, +5, WHITE,
+ {
+ SPWPN_HOLY_WRATH, 3, 0, 0, 0, 0, // AC
+ 0, 0, 0, 0, 1, 0, // life prot
+ 1, 0, 0, 0, 0, 0, // see invis
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, -20 // stealth
+ }
+ ,
+ "",
+ "",
+ ""
+}
+,
+
+/* 9 */
+{
+ "cloak of the Thief", "tattered cloak",
+ OBJ_ARMOUR, ARM_CLOAK, +1, 0, DARKGREY,
+ {
+ 0, 0, 2, 0, 0, 2, // EV, dex
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0, 0, // see invis, turn invis, levitate
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, -3, // to dam
+ 0, 60 // stealth
+ }
+ ,
+ "It allows its wearer to excel in the arts of thievery.",
+ "",
+ ""
+}
+,
+
+
+
+
+/* 10 */
+{
+ "buckler \"Bullseye\"", "round buckler",
+ OBJ_ARMOUR, ARM_BUCKLER, +10, 0, RED,
+ {
+ 0, 0, -3, 0, 0, 0, // EV
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "",
+ "",
+ ""
+}
+,
+
+/* 11 */
+{
+ "crown of Dyrovepreva", "jewelled bronze crown",
+ OBJ_ARMOUR, ARM_HELMET, +3, THELM_SPECIAL, BROWN,
+ {
+ 0, 0, 0, 0, 2, 0, // int
+ 0, 0, 1, 0, 0, 0, // res elec
+ 1, 0, 0, 0, 0, 0, // see invis
+ 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, // speeds metabolism
+ 0, 0
+ }
+ ,
+ "",
+ "A large crown of dull bronze, set with a dazzling array of gemstones.",
+ ""
+}
+,
+
+
+/* 12 */
+{
+ "demon blade \"Leech\"", "runed demon blade",
+ OBJ_WEAPONS, WPN_DEMON_BLADE, +13, +4, MAGENTA,
+ {
+ SPWPN_VAMPIRICISM, -1, -1, -1, -1, -1, // AC, EV, str, int, dex
+ 0, 0, 0, 0, 1, 0, // life prot
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0 // cursed
+ }
+ ,
+ "",
+ "",
+ ""
+}
+,
+
+/* 13 */
+{
+ "amulet of Cekugob", "crystal amulet",
+ OBJ_JEWELLERY, AMU_WARDING, +0, 0, LIGHTGREY,
+ {
+ 0, 1, 1, 0, 0, 0, // AC, EV
+ 0, 0, 1, 1, 1, 0, // res elec, poison, life prot
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, // prevent teleport
+ 0, 2, 0, 0, 0, // speed metabolism
+ 0, 0
+ }
+ ,
+ "",
+ "",
+ ""
+}
+,
+
+
+/* 14 */
+{
+ "robe of Misfortune", "fabulously ornate robe",
+ OBJ_ARMOUR, ARM_ROBE, -5, 0, MAGENTA,
+ {
+ 0, 0, -4, -2, -2, -2, // EV, str, int, dex
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0, // prevent spellcasting, cause teleport
+ 0, 0, 5, 0, 0, // radiation
+ 1, -80 // cursed, stealth
+ }
+ ,
+ "",
+ "A splendid flowing robe of fur and silk.",
+ ""
+}
+
+#ifdef USE_NEW_UNRANDS
+,
+/* 15 */
+{
+ "dagger of Chilly Death", "sapphire dagger",
+ OBJ_WEAPONS, WPN_DAGGER, +2, +6, LIGHTBLUE,
+ {
+ SPWPN_FREEZING, 0, 0, 0, 0, 0,
+ -1, 2, 0, 1, 0, 20, // res fire, cold, poison, magic
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "",
+ "A dagger made of one huge piece of sapphire.",
+ ""
+}
+,
+/* 16 */
+{
+ "amulet of the Four Winds", "jade amulet",
+ OBJ_JEWELLERY, AMU_CLARITY, +0, 0, LIGHTGREEN,
+ {
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 60, // life prot, magic resistance
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "",
+ "",
+ ""
+}
+,
+
+/* 17 */
+{
+ "dagger \"Morg\"", "rusty dagger",
+ OBJ_WEAPONS, WPN_DAGGER, -1, +4, LIGHTRED,
+ {
+ SPWPN_PAIN, 0, 0, 0, 5, 0, // int
+ 0, 0, 0, 0, 0, 30, // res magic
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "Many years ago it was property of powerful mage called "
+ "Boris. He got lost in the Dungeon while seeking the Orb. ",
+ "An ugly rusty dagger. ",
+ ""
+}
+,
+
+/* 18 */
+{
+ "scythe \"Finisher\"", "blackened scythe",
+ OBJ_WEAPONS, WPN_SCYTHE, +3, +5, DARKGRAY,
+ {
+ SPWPN_SPEED, 0, 0, 3, 0, 0, // str
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0 // cursed
+ }
+ ,
+ "",
+ "A long and sharp scythe, specially modified for combat purposes.",
+ ""
+}
+,
+
+/* 19 */
+{
+ "sling \"Punk\"", "blue sling",
+ OBJ_WEAPONS, WPN_SLING, +3, +4, LIGHTBLUE,
+ {
+ SPWPN_FROST, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0, // res cold
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "",
+ "A sling made of weird blue leather.",
+ ""
+}
+,
+/* 20 */
+{
+ "bow of Krishna \"Sharnga\"", "golden bow",
+ OBJ_WEAPONS, WPN_BOW, +8, +8, YELLOW,
+ {
+ SPWPN_SPEED, 0, 0, 0, 0, 3, // dex
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, // see invis
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "It once belonged to one foreign god. It works best with some kind "
+ "of special arrows which are not generally available.",
+ "A wonderful golden bow. ",
+ ""
+}
+,
+/* 21 */
+{
+ "cloak of Flash", "vibrating cloak",
+ OBJ_ARMOUR, ARM_CLOAK, +2, 0, RED,
+ {
+ 0, 0, 4, 0, 0, 0, // EV
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 1, 0, // levitate, teleport
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "",
+ "A vibrating cloak.",
+ ""
+}
+,
+/* 22 */
+{
+ "giant club \"Skullcrusher\"", "brutal giant club",
+ OBJ_WEAPONS, WPN_GIANT_CLUB, +0, +5, BROWN,
+ {
+ SPWPN_VORPAL, 0, 0, 5, 0, 0, // str
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "",
+ "",
+ ""
+}
+,
+/* 23 */
+{
+ "boots of the Assassin", "soft boots",
+ OBJ_ARMOUR, ARM_BOOTS, +2, 0, BROWN,
+ {
+ 0, 0, 0, 0, 0, 3, // dex
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0, // turn invis
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 80 // stealth
+ }
+ ,
+ "These boots were specially designed by the Assassin's Guild.",
+ "Some soft boots.",
+ ""
+}
+,
+/* 24 */
+{
+ "glaive of the Guard", "polished glaive",
+ OBJ_WEAPONS, WPN_GLAIVE, +5, +8, LIGHTCYAN,
+ {
+ SPWPN_PROTECTION, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 1, // see invis, go berserk
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "This weapon once belonged to Gar Dogh, the guard of king's treasures. "
+ "According to legend he was lost somewhere in the Dungeon.",
+ "",
+ ""
+}
+,
+/* 25 */
+{
+ "sword of Jihad", "crystal sword",
+ OBJ_WEAPONS, WPN_LONG_SWORD, +4, +4, WHITE,
+ {
+ SPWPN_HOLY_WRATH, 0, 3, 0, 0, 0, // EV
+ 0, 0, 0, 0, 1, 20, // life prot, res magic
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, // force berserk
+ 0, -50 // stealth (TSO hates backstab)
+ }
+ ,
+ "This sword was The Shining One's gift to one of his paladins." ,
+ "A long sword made of one huge piece of crystal.",
+ ""
+}
+,
+/* 26 */
+{
+ "Lear's chain mail", "golden chain mail",
+ OBJ_ARMOUR, ARM_CHAIN_MAIL, -1, 0, YELLOW,
+ {
+ 0, 0, 0, 0, 0, -3, // dex
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, // prevent spellcasting
+ 0, 0, 0, 0, 0,
+ 1, 0 // cursed
+ }
+ ,
+ "",
+ "A chain mail made of pure gold.",
+ ""
+}
+,
+/* 27 */
+{
+ "skin of Zhor", "smelly skin",
+ OBJ_ARMOUR, ARM_ANIMAL_SKIN, +4, 0, BROWN,
+ {
+ 0, 0, 0, 0, 0, 0,
+ 0, 2, 0, 0, 0, 0, // res cold
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "",
+ "A skin of some strange animal.",
+ ""
+}
+,
+/* 28 */
+{
+ "crossbow \"Fiery Devil\"", "flaming crossbow",
+ OBJ_WEAPONS, WPN_CROSSBOW, +4, +0, LIGHTRED,
+ {
+ SPWPN_FLAME, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, // res fire
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "",
+ "A flaming crossbow.",
+ ""
+}
+,
+/* 29 */
+{
+ "salamander hide armour", "red leather armour",
+ OBJ_ARMOUR, ARM_LEATHER_ARMOUR, +3, 0, RED,
+ {
+ 0, 0, 0, 0, 0, 0,
+ 2, 0, 0, 0, 0, 0, // res fire
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "",
+ "A leather armour made of salamander's skin.",
+ ""
+}
+,
+/* 30 */
+{
+ "gauntlets of War", "thick gauntlets",
+ OBJ_ARMOUR, ARM_GLOVES, +3, 0, BROWN,
+ {
+ 0, 0, 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, 3, // to hit, to dam
+ 0, 0
+ }
+ ,
+ "",
+ "",
+ ""
+}
+,
+/* 31 */
+{
+ "sword of Doom Knight", "adamantine great sword",
+ OBJ_WEAPONS, WPN_GREAT_SWORD, +4, +4, BLUE,
+ {
+ SPWPN_PAIN, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 50, // res magic
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, // prevent spellcasting
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "",
+ "An adamantine great sword.",
+ ""
+}
+,
+/* 32 */
+{
+ "shield of Resistance", "bronze shield",
+ OBJ_ARMOUR, ARM_SHIELD, +3, 0, LIGHTRED,
+ {
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 0, 0, 0, 40, // res fire, cold, magic
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "",
+ "A bronze shield.",
+ ""
+}
+,
+/* 33 */
+{
+ "robe of Folly", "dull robe",
+ OBJ_ARMOUR, ARM_ROBE, -1, 0, LIGHTGRAY,
+ {
+ 0, 0, 0, 0, -5, 0, // int
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, // prevent spellcasting
+ 0, 0, 0, 0, 0,
+ 1, 0 // cursed
+ }
+ ,
+ "",
+ "A dull gray robe.",
+ ""
+}
+,
+/* 34 */
+{
+ "necklace of Bloodlust", "blood-stained necklace",
+ OBJ_JEWELLERY, AMU_RAGE, +0, 0, RED,
+ {
+ 0, 0, 0, 2, -2, 0, // str, int
+ 0, 0, 0, 0, 0, 30, // res magic
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 3, // force berserk, to dam
+ 1, -20 // cursed, stealth
+ }
+ ,
+ "",
+ "",
+ ""
+}
+,
+/* 35 */
+{
+ "\"Eos\"", "encrusted morningstar",
+ OBJ_WEAPONS, WPN_MORNINGSTAR, +5, +5, LIGHTCYAN,
+ {
+ SPWPN_ELECTROCUTION, 0, 0, 0, 0, 0, // morning -> bring light/sparks?
+ 0, 0, 1, 0, 0, 0, // res elec
+ 1, 0, 0, 0, 0, 0, // see invis
+ 0, 0, 0, 0, 1, // prevent teleportation
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "",
+ "",
+ ""
+}
+,
+/* 36 */
+{
+ "ring of Shaolin", "jade ring",
+ OBJ_JEWELLERY, RING_EVASION, +8, 0, LIGHTGREEN,
+ {
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "",
+ "",
+ ""
+}
+,
+/* 37 */
+{
+ "ring of Robustness", "steel ring",
+ OBJ_JEWELLERY, RING_PROTECTION, +8, 0, LIGHTGRAY,
+ {
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "",
+ "",
+ ""
+}
+,
+/* 38 */
+{
+ "Edison's patent armour", "weird-looking armour",
+ OBJ_ARMOUR, ARM_PLATE_MAIL, +10, 0, LIGHTGREEN,
+ {
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 1, // prevent spellcasting, prevent teleport
+ 0, 0, 0, 0, 0,
+ 1, 0 // cursed
+ }
+ ,
+ "",
+ "A weird-looking armour.",
+ ""
+}
+,
+/* 39 */
+{
+ "spear of Voo-Doo", "ebony spear",
+ OBJ_WEAPONS, WPN_SPEAR, +2, +10, DARKGRAY,
+ {
+ SPWPN_VAMPIRICISM, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0, // res poison, prot life
+ 0, 0, 0, 0, 0, 0,
+ 0, 3, 0, 0, 0, // noise
+ 0, 0, 0, 0, 0,
+ 0, -30 // stealth
+ }
+ ,
+ "It's really dark and malign artifact and no wise man would even touch it.",
+ "",
+ ""
+}
+,
+/* 40 */
+{
+ "trident of the Octopus king", "mangy trident",
+ OBJ_WEAPONS, WPN_TRIDENT, +10, +4, CYAN,
+ {
+ SPWPN_VENOM, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 50, // res poison, res magic
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "This trident was stolen many years ago from the Octopus's garden "
+ "by one really unimportant and already dead man. But beware of "
+ "Octopus's king's wrath!",
+ "",
+ ""
+}
+,
+/* 41 */
+{
+ "mask of the Dragon", "blue mask",
+ OBJ_ARMOUR, ARM_HELMET, +0, THELM_SPECIAL, BLUE,
+ {
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 40, // res magic
+ 1, 0, 0, 0, 0, 0, // see invis
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 2, 2, // to hit, to dam
+ 0, 0
+ }
+ ,
+ "",
+ "A blue mask.",
+ ""
+}
+,
+/* 42 */
+{
+ "mithril axe \"Arga\"", "mithril axe",
+ OBJ_WEAPONS, WPN_WAR_AXE, +10, +6, WHITE,
+ {
+ SPWPN_SPEED, 0, 0, 2, 0, 0, // str
+ 0, 0, 0, 0, 0, 30, // resist magic
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "",
+ "A beautiful mithril axe, probably lost by some dwarven hero.",
+ ""
+}
+,
+/* 43 */
+{
+ "Elemental Staff", "black staff",
+ OBJ_WEAPONS, WPN_QUARTERSTAFF, +3, +1, DARKGRAY,
+ {
+ SPWPN_PROTECTION, 0, 0, 0, 0, 0,
+ 1, 1, 0, 0, 0, 60, // res fire, cold, magic
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, // noise
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "This powerful staff used to belong to leader of"
+ " the Guild of Five Elements.",
+ "A black glyphic staff.",
+ ""
+}
+,
+/* 44 */
+{
+ "hand crossbow \"Sniper\"", "black crossbow",
+ OBJ_WEAPONS, WPN_HAND_CROSSBOW, +10, +0, DARKGRAY,
+ {
+ SPWPN_VENOM, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, // see invis
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "",
+ "A hand crossbow made of some black material.",
+ ""
+}
+,
+/* 45 */
+{
+ "bow \"Erchidel\"", "metal bow",
+ OBJ_WEAPONS, WPN_BOW, +5, +3, CYAN,
+ {
+ SPWPN_PROTECTION, 0, 0, 3, 0, 0, // str
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "",
+ "A metal bow.",
+ ""
+}
+,
+/* 46 */
+{
+ "robe of Night", "black robe",
+ OBJ_ARMOUR, ARM_ROBE, +4, 0, DARKGRAY,
+ {
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 30, // res magic
+ 1, 1, 0, 0, 0, 0, // see invis, turn invis
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 50 // stealth
+ }
+ ,
+ "According to legend this robe was gift of Ratri the Goddess of the Night "
+ "to one her follower.",
+ "A long black robe made of strange flossy material.",
+ ""
+}
+,
+/* 47 */
+{
+ "plutonium sword", "glowing long sword",
+ OBJ_WEAPONS, WPN_LONG_SWORD, +5, +10, LIGHTGREEN,
+ {
+ 0, 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, // radiation
+ 1, -20 // cursed, stealth
+ }
+ ,
+ "",
+ "A long sword made of weird glowing metal.",
+ ""
+}
+,
+/* 48 */
+{
+ "mace \"Undeadhunter\"", "steel mace",
+ OBJ_WEAPONS, WPN_MACE, +4, +6, LIGHTGRAY,
+ {
+ SPWPN_DISRUPTION, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0, // life prot
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "",
+ "",
+ ""
+}
+,
+/* 49 */
+{
+ "armour of the Dragon King", "shiny dragon armour",
+ OBJ_ARMOUR, ARM_GOLD_DRAGON_ARMOUR, +5, 0, YELLOW,
+ {
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 50, // res magic (base gives fire, cold, poison)
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "",
+ "",
+ ""
+}
+,
+/* 50 */
+{
+ "hat of the Alchemist", "dirty hat",
+ OBJ_ARMOUR, ARM_HELMET, +2, THELM_SPECIAL, MAGENTA,
+ {
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0, 30, // res fire, cold, elec, magic
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "",
+ "A dirty hat.",
+ ""
+}
+,
+/* 51 */
+{
+ "Fencer's gloves", "silk gloves",
+ OBJ_ARMOUR, ARM_GLOVES, +2, 0, WHITE,
+ {
+ 0, 0, 3, 0, 0, 3, // EV, dex
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 5, 0, // to hit
+ 0, 0
+ }
+ ,
+ "",
+ "A gloves made of white silk.",
+ ""
+}
+,
+/* 52 */
+{
+ "ring of the Mage", "sapphire ring",
+ OBJ_JEWELLERY, RING_WIZARDRY, +0, 0, LIGHTBLUE,
+ {
+ 0, 0, 0, 0, 3, 0, // int
+ 0, 0, 0, 0, 0, 50, // res magic
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0
+ }
+ ,
+ "",
+ "",
+ ""
+}
+#endif // USE_NEW_UNRANDS
+,
+/* This is a dummy */
+/* 1 */
+{
+ "Dum", "",
+/* class, type, plus (to-hit), plus2 (depends on class), colour */
+ 250, 250, 250, 250, 0,
+/* Properties, all approx thirty of them: */
+ {
+/* brand, +/- to AC, +/- to ev, +/- to str, +/- to int, +/- to dex */
+ 0, 0, 0, 0, 0, 0,
+/* res fire, res cold, res elec, res poison, life protection, res magic */
+ 0, 0, 0, 0, 0, 0,
+/* see invis, turn invis, levitate, blink, teleport at will, go berserk */
+ 0, 0, 0, 0, 0, 0,
+/* sense surroundings, make noise, no spells, teleport, no teleprt */
+ 0, 0, 0, 0, 0,
+/* force berserk, speed metabolism, mutate, +/- to hit, +/- to dam (not weapons) */
+ 0, 0, 0, 0, 0,
+/* some as yet unused properties */
+ 0, 0
+ }
+ ,
+/* 3 strings for describing the item in the 'V' display. */
+ "",
+ "",
+ ""
+}
+#endif
diff --git a/trunk/source/version.h b/trunk/source/version.h
new file mode 100644
index 0000000000..fce3d06539
--- /dev/null
+++ b/trunk/source/version.h
@@ -0,0 +1,51 @@
+/*
+ * File: version.h
+ * Summary: Contains version information
+ * Written by: ??
+ *
+ * Change History (most recent first):
+ *
+ * <2> 10/12/99 BCR Added BUILD_DATE #define
+ * <1> -/--/-- --- Created
+ */
+
+/* Crawl versioning:
+ * Crawl uses three numbers to determine the version:
+ * Version, which changes when the dev team makes enormous overhauls
+ * to the game (which may cause savefiles from previous versions to
+ * temporarily stop working, for example)
+ * Release, which changes when siginficant new features have been
+ * added to the game.
+ * Mod, which changes with every publicly released version that
+ * contains nothing more than bug fixes, cosmetic changes,
+ * internal cleanup, etc.
+ *
+ * Further, any source or binary uploaded anywhere that is _not_ of
+ * release quality should be labelled as such:
+ * alpha for potentially unstable dev versions, or
+ * beta for feature-complete and mostly balanced versions
+ *
+ * several alphas or betas in a row should be labelled incrementally;
+ * alpha1 -> alpha2 -> alpha3 -> beta1 -> beta2 -> ...
+ */
+
+
+#ifndef VERSION_H
+#define VERSION_H
+
+
+// last updated 07august2001 {mv}
+/* ***********************************************************************
+ * called from: chardump - command - newgame
+ * *********************************************************************** */
+#define VERSION "4.0.0 beta 26"
+
+
+// last updated 20feb2001 {GDL}
+/* ***********************************************************************
+ * called from: command
+ * *********************************************************************** */
+#define BUILD_DATE __DATE__
+
+
+#endif
diff --git a/trunk/source/view.cc b/trunk/source/view.cc
new file mode 100644
index 0000000000..0e2fccd58e
--- /dev/null
+++ b/trunk/source/view.cc
@@ -0,0 +1,3524 @@
+/*
+ * File: view.cc
+ * Summary: Misc function used to render the dungeon.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <10> 29 Jul 00 JDJ show_map iterates horizontally to 79 instead of 80.
+ * item no longer indexes past the end of environ::grid.
+ * <9> 19 Jun 00 GDL Complete rewrite of LOS code
+ * <8> 11/23/99 LRH Added colour-coded play-screen map & clean_map
+ * init options
+ * <7> 9/29/99 BCR Removed first argument from draw_border
+ * <6> 9/11/99 LRH Added calls to overmap functions
+ * <5> 6/22/99 BWR Fixed and improved the stealth
+ * <4> 5/20/99 BWR show_map colours all portals,
+ * exits from subdungeons now
+ * look like up stairs.
+ * <3> 5/09/99 JDJ show_map draws shops in yellow.
+ * <2> 5/09/99 JDJ show_map accepts '\r' along with '.'.
+ * <1> -/--/-- LRH Created
+ */
+
+#include "AppHdr.h"
+#include "view.h"
+
+#include <string.h>
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#include "externs.h"
+
+#include "debug.h"
+#include "insult.h"
+#include "macro.h"
+#include "monstuff.h"
+#include "mon-util.h"
+#include "overmap.h"
+#include "player.h"
+#include "skills2.h"
+#include "stuff.h"
+#include "spells4.h"
+
+
+unsigned char your_sign; // accessed as extern in transfor.cc and acr.cc
+unsigned char your_colour; // accessed as extern in transfor.cc and acr.cc
+
+FixedArray < unsigned int, 20, 19 > show_backup;
+
+unsigned char show_green;
+extern int stealth; // defined in acr.cc
+extern FixedVector<char, 10> Visible_Statue; // defined in acr.cc
+
+// char colour_code_map(unsigned char map_value);
+char colour_code_map( int x, int y );
+
+unsigned char (*mapch) (unsigned char);
+unsigned char (*mapch2) (unsigned char);
+unsigned char mapchar(unsigned char ldfk);
+unsigned char mapchar2(unsigned char ldfk);
+unsigned char mapchar3(unsigned char ldfk);
+unsigned char mapchar4(unsigned char ldfk);
+void cloud_grid(void);
+void monster_grid(bool do_updates);
+
+//---------------------------------------------------------------
+//
+// get_number_of_lines
+//
+// Made this a function instead of a #define. This should help
+// considering the fact that the curses version is a macro
+// (curses tends to be implemented with a large number of
+// preprocessor macros, which can wreak havoc with things
+// like the C++ string class, so we want to isolate that
+// away to keep portability up).
+//
+// Other OSes might want to hook into reading system environment
+// variables or player set options to determine the screen size
+// (see the Options and SysEnv structures, as well as initfile.cc).
+//
+// This might be better to move to the lib*.cc files, but we
+// don't really have a standard API defined for them, or the
+// all important libdos.cc. It would be a good idea to eventually
+// head that way. -- bwr
+//
+//---------------------------------------------------------------
+int get_number_of_lines(void)
+{
+#ifdef LINUX
+ return (get_number_of_lines_from_curses());
+#elif MAC
+ return (MAC_NUMBER_OF_LINES);
+#else
+ return (25);
+#endif
+}
+
+
+//---------------------------------------------------------------
+//
+// get_ibm_symbol
+//
+// Returns the DOS character code and color for everything drawn
+// with the IBM graphics option.
+//
+//---------------------------------------------------------------
+static void get_ibm_symbol(unsigned int object, unsigned short *ch,
+ unsigned short *color)
+{
+ ASSERT(color != NULL);
+ ASSERT(ch != NULL);
+
+ switch (object)
+ {
+ case DNGN_UNSEEN:
+ *ch = 0;
+ break;
+
+ case DNGN_ROCK_WALL:
+ case DNGN_PERMAROCK_WALL:
+ *color = env.rock_colour;
+ *ch = 177;
+ break; // remember earth elementals
+
+ // stone in the realm of Zot is coloured the same as rock
+ case DNGN_STONE_WALL:
+ *color = (player_in_branch( BRANCH_HALL_OF_ZOT ) ? env.rock_colour
+ : LIGHTGREY);
+ *ch = 177;
+ break;
+
+ case DNGN_CLOSED_DOOR:
+ *ch = 254;
+ break;
+
+ case DNGN_METAL_WALL:
+ *ch = 177;
+ *color = CYAN;
+ break;
+
+ case DNGN_SECRET_DOOR:
+ *ch = 177;
+ *color = env.rock_colour;
+ break;
+
+ case DNGN_GREEN_CRYSTAL_WALL:
+ *ch = 177;
+ *color = GREEN;
+ break;
+
+ case DNGN_ORCISH_IDOL:
+ *ch = '8';
+ *color = DARKGREY;
+ break;
+
+ case DNGN_WAX_WALL:
+ *ch = 177;
+ *color = YELLOW;
+ break; // wax wall
+ /* Anything added here must also be added to the PLAIN_TERMINAL
+ viewwindow2 below */
+
+ case DNGN_SILVER_STATUE:
+ *ch = '8';
+ *color = WHITE;
+ Visible_Statue[ STATUE_SILVER ] = 1;
+ break;
+
+ case DNGN_GRANITE_STATUE:
+ *ch = '8';
+ *color = LIGHTGREY;
+ break;
+
+ case DNGN_ORANGE_CRYSTAL_STATUE:
+ *ch = '8';
+ *color = LIGHTRED;
+ Visible_Statue[ STATUE_ORANGE_CRYSTAL ] = 1;
+ break;
+
+ case DNGN_LAVA:
+ *ch = 247;
+ *color = RED;
+ break;
+
+ case DNGN_DEEP_WATER:
+ *ch = 247; // this wavy thing also used for water elemental
+ *color = BLUE;
+ break;
+
+ case DNGN_SHALLOW_WATER:
+ *ch = 247; // this wavy thing also used for water elemental
+ *color = CYAN;
+ break;
+
+ case DNGN_FLOOR:
+ *color = env.floor_colour;
+ *ch = 249;
+ break;
+
+ case DNGN_ENTER_HELL:
+ *ch = 239;
+ *color = RED;
+ seen_other_thing(object);
+ break;
+
+ case DNGN_OPEN_DOOR:
+ *ch = 39;
+ break;
+
+ case DNGN_BRANCH_STAIRS:
+ *ch = 240;
+ *color = BROWN;
+ break;
+
+ case DNGN_TRAP_MECHANICAL:
+ *color = LIGHTCYAN;
+ *ch = 94;
+ break;
+
+ case DNGN_TRAP_MAGICAL:
+ *color = MAGENTA;
+ *ch = 94;
+ break;
+
+ case DNGN_TRAP_III:
+ *color = LIGHTGREY;
+ *ch = 94;
+ break;
+
+ case DNGN_UNDISCOVERED_TRAP:
+ *ch = 249;
+ *color = env.floor_colour;
+ break;
+
+ case DNGN_ENTER_SHOP:
+ *ch = 239;
+ *color = YELLOW;
+
+ seen_other_thing(object);
+ break;
+ // if I change anything above here, must also change magic mapping!
+
+ case DNGN_ENTER_LABYRINTH:
+ *ch = 239;
+ *color = LIGHTGREY;
+ seen_other_thing(object);
+ break;
+
+ // not sure why we have "odd" here, but "ladders" are special in
+ // that they all lead to the first staircase of the next level
+ // (and returning from there will take you somewhere different)
+ // ... that's why they're brown... it's a warning -- bwr
+ case DNGN_ROCK_STAIRS_DOWN:
+ *color = BROWN; // ladder // odd {dlb}
+ case DNGN_STONE_STAIRS_DOWN_I:
+ case DNGN_STONE_STAIRS_DOWN_II:
+ case DNGN_STONE_STAIRS_DOWN_III:
+ *ch = '>';
+ break;
+
+ case DNGN_ROCK_STAIRS_UP:
+ *color = BROWN; // ladder // odd {dlb}
+ case DNGN_STONE_STAIRS_UP_I:
+ case DNGN_STONE_STAIRS_UP_II:
+ case DNGN_STONE_STAIRS_UP_III:
+ *ch = '<';
+ break;
+
+ case DNGN_ENTER_DIS:
+ *color = CYAN;
+ *ch = 239;
+ break;
+
+ case DNGN_ENTER_GEHENNA:
+ *color = RED;
+ *ch = 239;
+ break;
+
+ case DNGN_ENTER_COCYTUS:
+ *color = LIGHTCYAN;
+ *ch = 239;
+ break;
+
+ case DNGN_ENTER_TARTARUS:
+ *color = DARKGREY;
+ *ch = 239;
+ break;
+
+ case DNGN_ENTER_ABYSS:
+ *color = random2(16);
+ *ch = 239;
+ seen_other_thing(object);
+ break;
+
+ case DNGN_EXIT_ABYSS:
+ *color = random2(16);
+ *ch = 239;
+ break;
+
+ case DNGN_STONE_ARCH:
+ *color = LIGHTGREY;
+ *ch = 239;
+ break;
+
+ case DNGN_ENTER_PANDEMONIUM:
+ *color = LIGHTBLUE;
+ *ch = 239;
+ seen_other_thing(object);
+ break;
+
+ case DNGN_EXIT_PANDEMONIUM:
+ *color = LIGHTBLUE;
+ *ch = 239;
+ break;
+
+ case DNGN_TRANSIT_PANDEMONIUM:
+ *color = LIGHTGREEN;
+ *ch = 239;
+ break;
+
+ case DNGN_ENTER_ORCISH_MINES:
+ case DNGN_ENTER_HIVE:
+ case DNGN_ENTER_LAIR:
+ case DNGN_ENTER_SLIME_PITS:
+ case DNGN_ENTER_VAULTS:
+ case DNGN_ENTER_CRYPT:
+ case DNGN_ENTER_HALL_OF_BLADES:
+ case DNGN_ENTER_TEMPLE:
+ case DNGN_ENTER_SNAKE_PIT:
+ case DNGN_ENTER_ELVEN_HALLS:
+ case DNGN_ENTER_TOMB:
+ case DNGN_ENTER_SWAMP:
+ case 123:
+ case 124:
+ case 125:
+ case 126:
+ *color = YELLOW;
+ *ch = '>';
+ seen_staircase(object);
+ break;
+
+ case DNGN_ENTER_ZOT:
+ *color = MAGENTA;
+ *ch = 239;
+ seen_staircase(object);
+ break;
+
+ case DNGN_RETURN_FROM_ORCISH_MINES:
+ case DNGN_RETURN_FROM_HIVE:
+ case DNGN_RETURN_FROM_LAIR:
+ case DNGN_RETURN_FROM_SLIME_PITS:
+ case DNGN_RETURN_FROM_VAULTS:
+ case DNGN_RETURN_FROM_CRYPT:
+ case DNGN_RETURN_FROM_HALL_OF_BLADES:
+ case DNGN_RETURN_FROM_TEMPLE:
+ case DNGN_RETURN_FROM_SNAKE_PIT:
+ case DNGN_RETURN_FROM_ELVEN_HALLS:
+ case DNGN_RETURN_FROM_TOMB:
+ case DNGN_RETURN_FROM_SWAMP:
+ case 143:
+ case 144:
+ case 145:
+ case 146:
+ *color = YELLOW;
+ *ch = '<';
+ break;
+
+ case DNGN_RETURN_FROM_ZOT:
+ *color = MAGENTA;
+ *ch = 239;
+ break;
+
+ case DNGN_ALTAR_ZIN:
+ *color = WHITE;
+ *ch = 220;
+ seen_altar(GOD_ZIN);
+ break;
+
+ case DNGN_ALTAR_SHINING_ONE:
+ *color = YELLOW;
+ *ch = 220;
+ seen_altar(GOD_SHINING_ONE);
+ break;
+
+ case DNGN_ALTAR_KIKUBAAQUDGHA:
+ *color = DARKGREY;
+ *ch = 220;
+ seen_altar(GOD_KIKUBAAQUDGHA);
+ break;
+
+ case DNGN_ALTAR_YREDELEMNUL:
+ *color = ((one_chance_in(3)) ? RED : DARKGREY);
+ *ch = 220;
+ seen_altar(GOD_YREDELEMNUL);
+ break;
+
+ case DNGN_ALTAR_XOM:
+ *color = random_colour();
+ *ch = 220;
+ seen_altar(GOD_XOM);
+ break;
+
+ case DNGN_ALTAR_VEHUMET:
+ *color = LIGHTBLUE;
+ if (one_chance_in(3))
+ *color = LIGHTMAGENTA;
+ if (one_chance_in(3))
+ *color = LIGHTRED;
+ *ch = 220;
+ seen_altar(GOD_VEHUMET);
+ break;
+
+ case DNGN_ALTAR_OKAWARU:
+ *color = CYAN;
+ *ch = 220;
+ seen_altar(GOD_OKAWARU);
+ break;
+
+ case DNGN_ALTAR_MAKHLEB:
+ *color = RED;
+ if (one_chance_in(3))
+ *color = LIGHTRED;
+ if (one_chance_in(3))
+ *color = YELLOW;
+ *ch = 220;
+ seen_altar(GOD_MAKHLEB);
+ break;
+
+ case DNGN_ALTAR_SIF_MUNA:
+ *color = BLUE;
+ *ch = 220;
+ seen_altar(GOD_SIF_MUNA);
+ break;
+
+ case DNGN_ALTAR_TROG:
+ *color = RED;
+ *ch = 220;
+ seen_altar(GOD_TROG);
+ break;
+
+ case DNGN_ALTAR_NEMELEX_XOBEH:
+ *color = LIGHTMAGENTA;
+ *ch = 220;
+ seen_altar(GOD_NEMELEX_XOBEH);
+ break;
+
+ case DNGN_ALTAR_ELYVILON:
+ *color = LIGHTGREY;
+ *ch = 220;
+ seen_altar(GOD_ELYVILON);
+ break;
+
+ case DNGN_BLUE_FOUNTAIN:
+ *color = BLUE;
+ *ch = 159;
+ break;
+
+ case DNGN_SPARKLING_FOUNTAIN:
+ *color = LIGHTBLUE;
+ *ch = 159;
+ break;
+
+ case DNGN_DRY_FOUNTAIN_I:
+ case DNGN_DRY_FOUNTAIN_II:
+ case DNGN_PERMADRY_FOUNTAIN:
+ *color = LIGHTGREY;
+ *ch = 159;
+ break;
+
+ case 256:
+ *ch = '0';
+ break;
+
+ case 257:
+ *color = CYAN;
+ *ch = '~';
+ break; /* Invis creature walking through water */
+
+ case 258:
+ *ch = ')';
+ break; // weapon )
+
+ case 259:
+ *ch = '[';
+ break; // armour [
+
+ case 260:
+ *ch = '/';
+ break; // wands, etc.
+
+ case 261:
+ *ch = '%';
+ break; // food
+
+ case 262:
+ *ch = '+';
+ break; // books +
+
+ case 263:
+ *ch = '?';
+ break; // scroll ?
+
+ case 264:
+ *ch = '=';
+ break; // ring = etc
+
+ case 265:
+ *ch = '!';
+ break; // potions !
+
+ case 266:
+ *ch = '(';
+ break; // stones
+
+ case 267:
+ *ch = '+';
+ break; // book +
+
+ case 268:
+ *ch = '%';
+ break; // corpses part 1
+
+ case 269:
+ *ch = '\\';
+ break; // magical staves
+
+ case 270:
+ *ch = '}';
+ break; // gems
+
+ case 271:
+ *ch = '%';
+ break; // don't know ?
+
+ case 272:
+ *ch = '$';
+ break; // $ gold
+
+ case 273:
+ *ch = '"';
+ break; // amulet
+
+ default:
+ *ch = ((object >= 297) ? mons_char(object - 297) : object);
+ break;
+ }
+} // end get_ibm_symbol()
+
+
+//---------------------------------------------------------------
+//
+// viewwindow2
+//
+// Draws the main window using the extended IBM character set.
+//
+// This function should not interfer with the game condition,
+// unless do_updates is set (ie. stealth checks for visible
+// monsters).
+//
+//---------------------------------------------------------------
+void viewwindow2(char draw_it, bool do_updates)
+{
+ const long BUFFER_SIZE = 1550;
+#ifdef DOS_TERM
+ // DOS functions like gettext() and puttext() can only
+ // work with arrays of characters, not shorts.
+ FixedVector < unsigned char, BUFFER_SIZE > buffy; //[800]; //392];
+#else
+ FixedVector < unsigned short, BUFFER_SIZE > buffy; //[800]; //392];
+#endif
+
+ unsigned short ch, color;
+
+ losight(env.show, grd, you.x_pos, you.y_pos);
+
+ int count_x, count_y;
+
+ for (count_x = 0; count_x < 18; count_x++)
+ {
+ for (count_y = 0; count_y < 18; count_y++)
+ {
+ env.show_col[count_x][count_y] = LIGHTGREY;
+ show_backup[count_x][count_y] = 0;
+ }
+ }
+
+ item();
+ cloud_grid();
+ monster_grid(do_updates);
+ int bufcount = 0;
+
+ if (draw_it == 1)
+ {
+ _setcursortype(_NOCURSOR);
+ for (count_y = you.y_pos - 8; count_y < you.y_pos + 9; count_y++)
+ {
+ bufcount += 16;
+
+ for (count_x = you.x_pos - 8; count_x < you.x_pos + 9; count_x++)
+ {
+ // may be overriden by the code below
+ color = env.show_col[ count_x - you.x_pos + 9 ]
+ [ count_y - you.y_pos + 9 ];
+
+ unsigned int object = env.show[ count_x - you.x_pos + 9 ]
+ [ count_y - you.y_pos + 9 ];
+
+ get_ibm_symbol(object, &ch, &color);
+
+ if (count_x == you.x_pos && count_y == you.y_pos)
+ {
+ ch = your_sign;
+
+ if (player_is_swimming())
+ {
+ color = (grd[you.x_pos][you.y_pos] == DNGN_DEEP_WATER)
+ ? BLUE : CYAN;
+ }
+ else
+ {
+ color = your_colour;
+ }
+ }
+
+ ASSERT(bufcount + 1 < BUFFER_SIZE);
+ buffy[bufcount] = ch;
+ buffy[bufcount + 1] = color;
+
+ bufcount += 2;
+ }
+
+ bufcount += 16;
+ }
+
+ if (you.level_type != LEVEL_LABYRINTH && you.level_type != LEVEL_ABYSS)
+ {
+ bufcount = 0;
+
+ for (count_y = 0; count_y < 17; count_y++)
+ {
+ bufcount += 16;
+
+ for (count_x = 0; count_x < 17; count_x++)
+ {
+ ASSERT(bufcount < BUFFER_SIZE);
+
+ if (buffy[bufcount] != 0)
+ {
+ env.map[ count_x + you.x_pos - 9 ]
+ [ count_y + you.y_pos - 9 ] = buffy[bufcount];
+ }
+
+ if (Options.clean_map == 1
+ && show_backup[count_x + 1][count_y + 1] != 0)
+ {
+ get_ibm_symbol(show_backup[count_x + 1][count_y + 1],
+ &ch, &color);
+ env.map[ count_x + you.x_pos - 9 ]
+ [ count_y + you.y_pos - 9 ] = ch;
+ }
+ bufcount += 2;
+ }
+ bufcount += 16;
+ }
+ }
+
+ bufcount = 0;
+ for (count_y = 0; count_y < 17; count_y++)
+ {
+ for (count_x = 0; count_x < 33; count_x++)
+ {
+ if (count_x + you.x_pos - 17 < 3
+ || count_y + you.y_pos - 9 < 3
+ || count_x + you.x_pos - 14 > 77
+ || count_y + you.y_pos - 9 > 67)
+ {
+ ASSERT(bufcount < BUFFER_SIZE);
+ buffy[bufcount] = 0;
+ bufcount++;
+ buffy[bufcount] = 0;
+ bufcount++;
+ continue;
+ }
+
+ if (count_x >= 8 && count_x <= 24 && count_y >= 0
+ && count_y <= 16 && buffy[bufcount] != 0)
+ {
+ bufcount += 2;
+ continue;
+ }
+
+ ASSERT(bufcount + 1 < BUFFER_SIZE);
+
+ buffy[bufcount] = env.map[ count_x + you.x_pos - 17 ]
+ [ count_y + you.y_pos - 9 ];
+
+ buffy[bufcount + 1] = DARKGREY;
+ if (Options.colour_map)
+ {
+ if (env.map[ count_x + you.x_pos - 16 ]
+ [ count_y + you.y_pos - 8 ] != 0)
+ {
+ buffy[bufcount + 1]
+ = colour_code_map( count_x + you.x_pos - 17,
+ count_y + you.y_pos - 9 );
+ }
+ }
+ bufcount += 2;
+ }
+ }
+
+ if (you.berserker)
+ {
+ for (count_x = 1; count_x < 1400; count_x += 2)
+ {
+ if (buffy[count_x] != DARKGREY)
+ buffy[count_x] = RED;
+ }
+ }
+
+ if (show_green != BLACK)
+ {
+ for (count_x = 1; count_x < 1400; count_x += 2)
+ {
+ if (buffy[count_x] != DARKGREY)
+ buffy[count_x] = show_green;
+ }
+
+ show_green = BLACK;
+
+ if (you.special_wield == SPWLD_SHADOW)
+ show_green = DARKGREY;
+ }
+
+#ifdef DOS_TERM
+ puttext(2, 1, 34, 17, buffy.buffer());
+#endif
+
+#ifdef PLAIN_TERM
+ gotoxy(2, 1);
+ bufcount = 0;
+
+ // following lines are purely optional.
+ // if used, players will 'jump' move.
+ // Resting will be a LOT faster too.
+ if (you.running == 0)
+ {
+ for (count_x = 0; count_x < 1120; count_x += 2)
+ { // 1056
+ ch = buffy[count_x];
+ color = buffy[count_x + 1];
+// ASSERT(color < 16);
+ ASSERT(ch < 255);
+
+ textcolor(color);
+ putch(ch);
+
+ if (count_x % 66 == 64 && count_x > 0)
+ gotoxy(2, wherey() + 1);
+ }
+ // remember to comment out the line below if you comment out jump move.
+ }
+ _setcursortype(_NORMALCURSOR);
+#endif
+ }
+} // end viewwindow2()
+
+char colour_code_map( int x, int y )
+{
+ // XXX: Yes, the map array and the grid array are off by one. -- bwr
+ const int map_value = env.map[x][y];
+ const int grid_value = grd[x + 1][y + 1];
+
+ // XXX: Yeah, this is ugly, but until we have stored layers in the
+ // map we can't tell if we've seen a square, detected it, or just
+ // detected the item or monster on top... giving colour here will
+ // result in detect creature/item detecting features like stairs. -- bwr
+ if (map_value != mapch2( grid_value ))
+ return (DARKGREY);
+
+ switch (grid_value)
+ {
+ case DNGN_TRAP_MECHANICAL:
+ return (LIGHTCYAN);
+
+ case DNGN_TRAP_MAGICAL:
+ case DNGN_TRAP_III:
+ return (MAGENTA);
+
+ case DNGN_ENTER_SHOP:
+ return (YELLOW);
+
+ case DNGN_ENTER_DIS:
+ return (CYAN);
+
+ case DNGN_ENTER_HELL:
+ case DNGN_ENTER_GEHENNA:
+ return (RED);
+
+ case DNGN_ENTER_COCYTUS:
+ return (LIGHTCYAN);
+
+ case DNGN_ENTER_ABYSS:
+ return random2(16); // so it can be black - is this right? {dlb}
+
+ case DNGN_ENTER_LABYRINTH:
+ case DNGN_STONE_ARCH:
+ return (LIGHTGREY);
+
+ case DNGN_ENTER_PANDEMONIUM:
+ return (LIGHTBLUE);
+
+ case DNGN_EXIT_PANDEMONIUM:
+ // Exit pandemonium gates won't show up on the map as light blue
+ // unless the character has the "gate to pandemonium" demonspawn
+ // mutation. This is so that the player can't quickly use a
+ // crystal ball to find their way out. -- bwr
+ return (you.mutation[MUT_PANDEMONIUM] ? LIGHTBLUE : LIGHTGREEN);
+
+ case DNGN_TRANSIT_PANDEMONIUM:
+ return (LIGHTGREEN);
+
+ case DNGN_ENTER_ZOT:
+ case DNGN_RETURN_FROM_ZOT:
+ return (MAGENTA);
+
+ case DNGN_STONE_STAIRS_DOWN_I:
+ case DNGN_STONE_STAIRS_DOWN_II:
+ case DNGN_STONE_STAIRS_DOWN_III:
+ case DNGN_ROCK_STAIRS_DOWN:
+ return (RED);
+
+ case DNGN_STONE_STAIRS_UP_I:
+ case DNGN_STONE_STAIRS_UP_II:
+ case DNGN_STONE_STAIRS_UP_III:
+ case DNGN_ROCK_STAIRS_UP:
+ return (BLUE);
+
+ case DNGN_ENTER_ORCISH_MINES:
+ case DNGN_ENTER_HIVE:
+ case DNGN_ENTER_LAIR:
+ case DNGN_ENTER_SLIME_PITS:
+ case DNGN_ENTER_VAULTS:
+ case DNGN_ENTER_CRYPT:
+ case DNGN_ENTER_HALL_OF_BLADES:
+ case DNGN_ENTER_TEMPLE:
+ case DNGN_ENTER_SNAKE_PIT:
+ case DNGN_ENTER_ELVEN_HALLS:
+ case DNGN_ENTER_TOMB:
+ case DNGN_ENTER_SWAMP:
+ case 123:
+ case 124:
+ case 125:
+ case 126:
+ return (LIGHTRED);
+
+ case DNGN_RETURN_FROM_ORCISH_MINES:
+ case DNGN_RETURN_FROM_HIVE:
+ case DNGN_RETURN_FROM_LAIR:
+ case DNGN_RETURN_FROM_SLIME_PITS:
+ case DNGN_RETURN_FROM_VAULTS:
+ case DNGN_RETURN_FROM_CRYPT:
+ case DNGN_RETURN_FROM_HALL_OF_BLADES:
+ case DNGN_RETURN_FROM_TEMPLE:
+ case DNGN_RETURN_FROM_SNAKE_PIT:
+ case DNGN_RETURN_FROM_ELVEN_HALLS:
+ case DNGN_RETURN_FROM_TOMB:
+ case DNGN_RETURN_FROM_SWAMP:
+ case 143:
+ case 144:
+ case 145:
+ case 146:
+ return (LIGHTBLUE);
+
+ default:
+ break;
+ }
+
+ return (DARKGREY);
+}
+
+
+void monster_grid(bool do_updates)
+{
+ struct monsters *monster = 0; // NULL {dlb}
+
+ for (int s = 0; s < MAX_MONSTERS; s++)
+ {
+ monster = &menv[s];
+
+ if (monster->type != -1 && mons_near(monster))
+ {
+ if (do_updates
+ && (monster->behaviour == BEH_SLEEP
+ || monster->behaviour == BEH_WANDER)
+ && check_awaken(s))
+ {
+ behaviour_event( monster, ME_ALERT, MHITYOU );
+
+ if (you.turn_is_over == 1
+ && mons_shouts(monster->type) > 0
+ && random2(30) >= you.skills[SK_STEALTH])
+ {
+ int noise_level = 8;
+
+ if (!mons_friendly(monster)
+ && (!silenced(you.x_pos, you.y_pos)
+ && !silenced(monster->x, monster->y)))
+ {
+ if (mons_is_demon( monster->type ) && coinflip())
+ {
+ if (monster->type == MONS_IMP
+ || monster->type == MONS_WHITE_IMP
+ || monster->type == MONS_SHADOW_IMP)
+ {
+ imp_taunt( monster );
+ }
+ else
+ {
+ demon_taunt( monster );
+ }
+ }
+ else
+ {
+ int the_shout = mons_shouts(monster->type);
+
+ strcpy(info, "You hear ");
+ switch (the_shout)
+ {
+ case S_SILENT:
+ default:
+ strcat(info, "buggy behaviour!");
+ break;
+ case S_SHOUT:
+ strcat(info, "a shout!");
+ break;
+ case S_BARK:
+ strcat(info, "a bark!");
+ break;
+ case S_SHOUT2:
+ strcat(info, "two shouts!");
+ noise_level = 12;
+ break;
+ case S_ROAR:
+ strcat(info, "a roar!");
+ noise_level = 12;
+ break;
+ case S_SCREAM:
+ strcat(info, "a hideous shriek!");
+ break;
+ case S_BELLOW:
+ strcat(info, "a bellow!");
+ break;
+ case S_SCREECH:
+ strcat(info, "a screech!");
+ break;
+ case S_BUZZ:
+ strcat(info, "an angry buzzing noise.");
+ break;
+ case S_MOAN:
+ strcat(info, "a chilling moan.");
+ break;
+ case S_WHINE:
+ strcat(info,
+ "an irritating high-pitched whine.");
+ break;
+ case S_CROAK:
+ if (coinflip())
+ strcat(info, "a loud, deep croak!");
+ else
+ strcat(info, "a croak.");
+ break;
+ case S_GROWL:
+ strcat(info, "an angry growl!");
+ break;
+ case S_HISS:
+ strcat(info, "an angry hiss!");
+ noise_level = 4; // not very loud -- bwr
+ break;
+ }
+
+ mpr(info);
+ }
+ }
+
+ noisy( noise_level, monster->x, monster->y );
+ }
+ }
+
+ if (!player_monster_visible( monster ))
+ {
+ // ripple effect?
+ if (grd[monster->x][monster->y] == DNGN_SHALLOW_WATER
+ && !mons_flies(monster))
+ {
+ show_backup[ monster->x - you.x_pos + 9 ]
+ [ monster->y - you.y_pos + 9]
+ = env.show[ monster->x - you.x_pos + 9 ]
+ [ monster->y - you.y_pos + 9 ];
+ env.show[monster->x - you.x_pos + 9]
+ [monster->y - you.y_pos + 9] = 257;
+ }
+ continue;
+ }
+ else if (!mons_friendly( monster )
+ && !mons_is_mimic( monster->type )
+ && !mons_flag( monster->type, M_NO_EXP_GAIN )
+ && you.running > 0)
+ {
+ // Friendly monsters, mimics, or harmless monsters
+ // don't disturb the player's running/resting.
+ //
+ // Doing it this way causes players in run mode 2
+ // to move one square, and in mode 1 to stop. This
+ // means that the character will run one square if
+ // a monster is in sight... we automatically jump
+ // to zero if we're resting. -- bwr
+ if (you.run_x == 0 && you.run_y == 0)
+ you.running = 0;
+ else
+ you.running--;
+ }
+
+ // mimics are always left on map
+ if (!mons_is_mimic( monster->type ))
+ {
+ show_backup[monster->x - you.x_pos + 9]
+ [monster->y - you.y_pos + 9]
+ = env.show[monster->x - you.x_pos + 9]
+ [monster->y - you.y_pos + 9];
+ }
+
+ env.show[monster->x - you.x_pos + 9]
+ [monster->y - you.y_pos + 9] = monster->type + 297;
+
+ env.show_col[monster->x - you.x_pos + 9]
+ [monster->y - you.y_pos + 9]
+ = ((mcolour[monster->type] == BLACK)
+ ? monster->number : mcolour[monster->type]);
+#ifdef USE_COLOUR_OPTS
+ if (mons_friendly(monster))
+ {
+ env.show_col[monster->x - you.x_pos + 9]
+ [monster->y - you.y_pos + 9]
+ |= COLFLAG_FRIENDLY_MONSTER;
+ }
+#endif
+ } // end "if (monster->type != -1 && mons_ner)"
+ } // end "for s"
+} // end monster_grid()
+
+
+bool check_awaken(int mons_aw)
+{
+ int mons_perc = 0;
+ struct monsters *monster = &menv[mons_aw];
+ const int mon_holy = mons_holiness( monster->type );
+
+ // berserkers aren't really concerned about stealth
+ if (you.berserker)
+ return (true);
+
+ // Repel undead is a holy aura, to which evil creatures are sensitive.
+ // Note that even though demons aren't affected by repel undead, they
+ // do sense this type of divine aura. -- bwr
+ if (you.duration[DUR_REPEL_UNDEAD]
+ && (mon_holy == MH_UNDEAD || mon_holy == MH_DEMONIC))
+ {
+ return (true);
+ }
+
+ // I assume that creatures who can see invisible are very perceptive
+ mons_perc = 10 + (mons_intel(monster->type) * 4) + monster->hit_dice
+ + mons_see_invis(monster) * 5;
+
+ // critters that are wandering still have MHITYOU as their foe are
+ // still actively on guard for the player, even if they can't see
+ // him. Give them a large bonus (handle_behaviour() will nuke 'foe'
+ // after a while, removing this bonus.
+ if (monster->behaviour == BEH_WANDER && monster->foe == MHITYOU)
+ mons_perc += 15;
+
+ if (!mons_player_visible(monster))
+ mons_perc -= 75;
+
+ if (monster->behaviour == BEH_SLEEP)
+ {
+ if (mon_holy == MH_NATURAL)
+ {
+ // monster is "hibernating"... reduce chance of waking
+ if (mons_has_ench( monster, ENCH_SLEEP_WARY ))
+ mons_perc -= 10;
+ }
+ else // unnatural creature
+ {
+ // Unnatural monsters don't actually "sleep", they just
+ // haven't noticed an intruder yet... we'll assume that
+ // they're diligently on guard.
+ mons_perc += 10;
+ }
+ }
+
+ // glowing with magical contamination isn't very stealthy
+ if (you.magic_contamination > 10)
+ mons_perc += you.magic_contamination - 10;
+
+ if (mons_perc < 0)
+ mons_perc = 0;
+
+ return (random2(stealth) <= mons_perc);
+} // end check_awaken()
+
+
+void item()
+{
+ char count_x, count_y;
+
+ for (count_y = (you.y_pos - 8); (count_y < you.y_pos + 9); count_y++)
+ {
+ for (count_x = (you.x_pos - 8); (count_x < you.x_pos + 9); count_x++)
+ {
+ if (count_x >= 0 && count_x < GXM && count_y >= 0 && count_y < GYM)
+ {
+ if (igrd[count_x][count_y] != NON_ITEM)
+ {
+ if (env.show[count_x - you.x_pos + 9]
+ [count_y - you.y_pos + 9] != 0)
+ {
+ if (grd[count_x][count_y] == DNGN_SHALLOW_WATER)
+ {
+ env.show_col[count_x - you.x_pos + 9]
+ [count_y - you.y_pos + 9] = CYAN;
+ }
+ else
+ {
+ env.show_col[count_x - you.x_pos + 9]
+ [count_y - you.y_pos + 9]
+ = mitm[igrd[count_x][count_y]].colour;
+ }
+
+ switch (mitm[igrd[count_x][count_y]].base_type)
+ {
+ case OBJ_ORBS:
+ env.show[count_x - you.x_pos + 9]
+ [count_y - you.y_pos + 9] = 256;
+ break;
+ // need + 6 because show is 0 - 12, not -6 - +6
+ case OBJ_WEAPONS:
+ case OBJ_MISSILES:
+ env.show[count_x - you.x_pos + 9]
+ [count_y - you.y_pos + 9] = 258;
+ break;
+ case OBJ_ARMOUR:
+ env.show[count_x - you.x_pos + 9]
+ [count_y - you.y_pos + 9] = 259;
+ break;
+ case OBJ_WANDS:
+ env.show[count_x - you.x_pos + 9]
+ [count_y - you.y_pos + 9] = 260;
+ break;
+ case OBJ_FOOD:
+ env.show[count_x - you.x_pos + 9]
+ [count_y - you.y_pos + 9] = 261;
+ break;
+ case OBJ_UNKNOWN_I:
+ env.show[count_x - you.x_pos + 9]
+ [count_y - you.y_pos + 9] = 262;
+ break;
+ case OBJ_SCROLLS:
+ env.show[count_x - you.x_pos + 9]
+ [count_y - you.y_pos + 9] = 263;
+ break;
+
+ case OBJ_JEWELLERY:
+ if (mitm[igrd[count_x][count_y]].sub_type >= AMU_RAGE)
+ {
+ env.show[count_x - you.x_pos + 9]
+ [count_y - you.y_pos + 9] = 273;
+ }
+ else
+ {
+ env.show[count_x - you.x_pos + 9]
+ [count_y - you.y_pos + 9] = 264;
+ }
+ break;
+
+ case OBJ_POTIONS:
+ env.show[count_x - you.x_pos + 9]
+ [count_y - you.y_pos + 9] = 265;
+ break;
+ case OBJ_UNKNOWN_II:
+ env.show[count_x - you.x_pos + 9]
+ [count_y - you.y_pos + 9] = 266;
+ break;
+ case OBJ_BOOKS:
+ env.show[count_x - you.x_pos + 9]
+ [count_y - you.y_pos + 9] = 267;
+ break;
+ case OBJ_STAVES:
+ env.show[count_x - you.x_pos + 9]
+ [count_y - you.y_pos + 9] = 269;
+ break;
+ case OBJ_MISCELLANY:
+ env.show[count_x - you.x_pos + 9]
+ [count_y - you.y_pos + 9] = 270;
+ break;
+ case OBJ_CORPSES:
+ env.show[count_x - you.x_pos + 9]
+ [count_y - you.y_pos + 9] = 271;
+ break;
+
+ case OBJ_GOLD:
+ env.show[count_x - you.x_pos + 9]
+ [count_y - you.y_pos + 9] = 272;
+
+ env.show_col[count_x - you.x_pos + 9]
+ [count_y - you.y_pos + 9] = YELLOW;
+ break;
+
+ default:
+ env.show[count_x - you.x_pos + 9]
+ [count_y - you.y_pos + 9] = '8';
+ break;
+ }
+ }
+ }
+ }
+ } // end of "for count_y, count_x"
+ }
+} // end item()
+
+
+void cloud_grid(void)
+{
+ int mnc = 0;
+
+ // btw, this is also the 'default' color {dlb}
+ unsigned char which_color = LIGHTGREY;
+
+ for (int s = 0; s < MAX_CLOUDS; s++)
+ {
+ // can anyone explain this??? {dlb}
+ // its an optimization to avoid looking past the last cloud -bwr
+ if (mnc > env.cloud_no)
+ break;
+
+ if (env.cloud[s].type != CLOUD_NONE)
+ {
+ mnc++;
+
+ if (see_grid(env.cloud[s].x, env.cloud[s].y))
+ {
+ show_backup[env.cloud[s].x - you.x_pos + 9]
+ [env.cloud[s].y - you.y_pos + 9]
+ = env.show[env.cloud[s].x - you.x_pos + 9]
+ [env.cloud[s].y - you.y_pos + 9];
+
+ env.show[env.cloud[s].x - you.x_pos + 9]
+ [env.cloud[s].y - you.y_pos + 9] = '#';
+
+ switch (env.cloud[s].type)
+ {
+ case CLOUD_FIRE:
+ case CLOUD_FIRE_MON:
+ if (env.cloud[s].decay <= 20)
+ which_color = RED;
+ else if (env.cloud[s].decay <= 40)
+ which_color = LIGHTRED;
+ else if (one_chance_in(4))
+ which_color = RED;
+ else if (one_chance_in(4))
+ which_color = LIGHTRED;
+ else
+ which_color = YELLOW;
+ break;
+
+ case CLOUD_STINK:
+ case CLOUD_STINK_MON:
+ which_color = GREEN;
+ break;
+
+ case CLOUD_COLD:
+ case CLOUD_COLD_MON:
+ if (env.cloud[s].decay <= 20)
+ which_color = BLUE;
+ else if (env.cloud[s].decay <= 40)
+ which_color = LIGHTBLUE;
+ else if (one_chance_in(4))
+ which_color = BLUE;
+ else if (one_chance_in(4))
+ which_color = LIGHTBLUE;
+ else
+ which_color = WHITE;
+ break;
+
+ case CLOUD_POISON:
+ case CLOUD_POISON_MON:
+ which_color = (one_chance_in(3) ? LIGHTGREEN : GREEN);
+ break;
+
+ case CLOUD_BLUE_SMOKE:
+ case CLOUD_BLUE_SMOKE_MON:
+ which_color = LIGHTBLUE;
+ break;
+
+ case CLOUD_PURP_SMOKE:
+ case CLOUD_PURP_SMOKE_MON:
+ which_color = MAGENTA;
+ break;
+
+ case CLOUD_MIASMA:
+ case CLOUD_MIASMA_MON:
+ case CLOUD_BLACK_SMOKE:
+ case CLOUD_BLACK_SMOKE_MON:
+ which_color = DARKGREY;
+ break;
+
+ default:
+ which_color = LIGHTGREY;
+ break;
+ }
+
+ env.show_col[env.cloud[s].x - you.x_pos + 9]
+ [env.cloud[s].y - you.y_pos + 9] = which_color;
+ }
+ } // end 'if != CLOUD_NONE'
+ } // end 'for s' loop
+} // end cloud_grid()
+
+
+void noisy( int loudness, int nois_x, int nois_y )
+{
+ int p;
+ struct monsters *monster = 0; // NULL {dlb}
+
+ if (silenced( nois_x, nois_y ))
+ return;
+
+ int dist = loudness * loudness;
+
+ for (p = 0; p < MAX_MONSTERS; p++)
+ {
+ monster = &menv[p];
+
+ if (monster->type < 0)
+ continue;
+
+ if (distance(monster->x, monster->y, nois_x, nois_y) <= dist
+ && !silenced(monster->x, monster->y))
+ {
+ // If the noise came from the character, any nearby monster
+ // will be jumping on top of them.
+ if (nois_x == you.x_pos && nois_y == you.y_pos)
+ behaviour_event( monster, ME_ALERT, MHITYOU );
+ else
+ behaviour_event( monster, ME_DISTURB, MHITNOT, nois_x, nois_y );
+ }
+ }
+} // end noisy()
+
+/* ========================================================================
+ * brand new LOS code
+ * ========================================================================
+ * The new LOS works via a new (I think) shadow casting algorithm,
+ * plus an esthetic tweak for more pleasing corner illumination. More
+ * detail can be had by contacting its author, Gordon Lipford. */
+
+#define MAX_LIGHT_RADIUS 20
+#define CIRC_MAX 32000
+#define BIG_SHADOW 32000
+
+// the following two constants represent the 'middle' of the sh array.
+// since the current shown area is 19x19, centering the view at (9,9)
+// means it will be exactly centered.
+// This is done to accomodate possible future changes in viewable screen
+// area - simply change sh_xo and sh_yo to the new view center.
+
+const int sh_xo = 9; // X and Y origins for the sh array
+const int sh_yo = 9;
+
+// the Cell class, used in the shadow-casting LOS algorithm
+class Cell
+{
+
+public:
+ int up_count;
+ int up_max;
+ int low_count;
+ int low_max;
+ bool lit;
+ bool lit_delay;
+ bool visible; // for blockers only
+ void init();
+ bool reachedLower();
+ bool reachedUpper();
+
+ Cell()
+ {
+ init();
+ };
+};
+
+void Cell::init()
+{
+ up_count = 0;
+ up_max = 0;
+ low_count = 0;
+ low_max = 0;
+ lit = true;
+ visible = true;
+ lit_delay = false;
+}
+
+bool Cell::reachedLower()
+{
+ // integer math: a 'step' has a value of 10
+ // see if we're within a half step of the max. VERY important
+ // to use 'half step' or else things look really stupid.
+ if (low_max != 0 && low_count + 5 >= low_max && low_count - 5 < low_max)
+ return true;
+
+ return false;
+}
+
+bool Cell::reachedUpper()
+{
+ // see if we're within a half step of the max. VERY important
+ // to use 'half step' or else things look really stupid.
+ if (up_max != 0 && up_count + 5 >= up_max && up_count - 5 < up_max)
+ return true;
+
+ return false;
+}
+
+// the cell array
+static FixedVector < Cell, MAX_LIGHT_RADIUS + 1 > cells;
+
+// the 'circle' array. For any given row, we won't check higher than
+// this given cell.
+static FixedVector < int, MAX_LIGHT_RADIUS + 1 > circle;
+
+// current light radius
+static int LR = 0;
+
+// View constant
+const int view = 2; // 1=widest LOS .. 5=narrowest
+
+// initialize LOS code for a given light radius
+extern void setLOSRadius(int newLR)
+{
+ int i, j;
+
+ // sanity check - also allows multiple calls w/out performance loss
+ if (LR == newLR)
+ return;
+
+ LR = newLR;
+ // cells should already be initted. calculate the circle array.
+
+ // note that rows 0 and 1 will always go to infinity.
+ circle[0] = circle[1] = CIRC_MAX;
+
+ // for the rest, simply calculate max height based on light rad.
+ for (i = 2; i <= LR; i++)
+ {
+ // check top
+ if (2 * i * i <= LR * LR)
+ {
+ circle[i] = CIRC_MAX;
+ continue;
+ }
+
+ for (j = i - 1; j >= 0; j--)
+ {
+ // check that Distance (I^2 + J^2) is no more than (R+0.5)^2
+ // this rounding allows for *much* better looking circles.
+ if (i * i + j * j <= LR * LR + LR)
+ {
+ circle[i] = j;
+ break;
+ }
+ }
+ }
+}
+
+static int calcUpper(int bX, int bY)
+{
+ // got a blocker at row bX, cell bY. do all values
+ // and scale by a factor of 10 for the integer math.
+ int upper;
+
+ upper = (10 * (10 * bX - view)) / (10 * bY + view);
+ if (upper < 10) // upper bound for blocker on diagonal
+ upper = 10;
+
+ return upper;
+}
+
+static int calcLower(int bX, int bY)
+{
+ // got a blocker at row bX, cell bY. do all values
+ // and scale by a factor of 10 for the integer math.
+
+ if (bY == 0)
+ return BIG_SHADOW;
+
+ return (10 * (10 * bX + view)) / (10 * bY - view);
+}
+
+// for easy x,y octant translation
+static int xxcomp[8] = { 1, 0, 0, -1, -1, 0, 0, 1 };
+static int xycomp[8] = { 0, 1, -1, 0, 0, -1, 1, 0 };
+static int yxcomp[8] = { 0, 1, 1, 0, 0, -1, -1, 0 };
+static int yycomp[8] = { 1, 0, 0, 1, -1, 0, 0, -1 };
+
+static void los_octant(int o, FixedArray < unsigned int, 19, 19 > &sh,
+ FixedArray < unsigned char, 80, 70 > &gr, int x_p,
+ int y_p)
+{
+ int row, cell, top, south;
+ int tx, ty; // translated x, y deltas for this octant
+ unsigned char gv; // grid value
+ bool row_dark, all_dark;
+ bool blocker, vis_corner;
+ int up_inc, low_inc;
+
+ // leave [0,0] alone, because the old LOS code seems to.
+
+ // init cell[0]. this is the only one that needs clearing.
+ cells[0].init();
+ all_dark = false;
+ vis_corner = false;
+
+ // loop through each row
+ for (row = 1; row <= LR; row++)
+ {
+ row_dark = true;
+
+ // loop through each cell, up to the max allowed by circle[]
+ top = circle[row];
+ if (top > row)
+ top = row;
+
+ for (cell = 0; cell <= top; cell++)
+ {
+ // translate X,Y co'ord + bounds check
+ tx = row * xxcomp[o] + cell * xycomp[o];
+ ty = row * yxcomp[o] + cell * yycomp[o];
+
+ if (x_p + tx < 0 || x_p + tx > 79 || y_p + ty < 0 || y_p + ty > 69)
+ continue;
+
+ // check for all_dark - we've finished the octant but
+ // have yet to fill in '0' for the rest of the sight grid
+ if (all_dark == true)
+ {
+ sh[sh_xo + tx][sh_yo + ty] = 0;
+ continue;
+ }
+
+ // get grid value.. see if it blocks LOS
+ gv = gr[x_p + tx][y_p + ty];
+ blocker = (gv < MINSEE);
+
+ // init some other variables
+ up_inc = 10;
+ low_inc = 10;
+ south = cell - 1;
+
+ // STEP 1 - inherit values from immediate West, if possible
+ if (cell < row)
+ {
+ // check for delayed lighting
+ if (cells[cell].lit_delay)
+ {
+ if (!blocker)
+ { // blockers don't light up with lit_delay.
+ if (cells[south].lit)
+ {
+ if (cells[south].low_max != 0)
+ {
+ cells[cell].lit = false;
+ // steal lower values
+ cells[cell].low_max = cells[south].low_max;
+ cells[cell].low_count = cells[south].low_count;
+ cells[south].low_count = 0;
+ cells[south].low_max = 0;
+ low_inc = 0; // avoid double-inc.
+ }
+ else
+ cells[cell].lit = true;
+ }
+ }
+ cells[cell].lit_delay = false;
+ }
+ }
+ else
+ {
+ // initialize new cell.
+ cells[cell].init();
+ }
+
+ // STEP 2 - check for blocker
+ // a dark blocker in shadow's edge will be visible
+ if (blocker)
+ {
+ if (cells[cell].lit || (cell != 0 && cells[south].lit)
+ || vis_corner)
+ {
+ // hack: make 'corners' visible
+ vis_corner = cells[cell].lit;
+
+ cells[cell].lit = false;
+ cells[cell].visible = true;
+
+ int upper = calcUpper(row, cell);
+ int lower = calcLower(row, cell);
+
+ if (upper < cells[cell].up_max || cells[cell].up_max == 0)
+ {
+ // new upper shadow
+ cells[cell].up_max = upper;
+ cells[cell].up_count = 0;
+ up_inc = 0;
+ }
+
+ if (lower > cells[cell].low_max || cells[cell].low_max == 0)
+ {
+ // new lower shadow
+ cells[cell].low_max = lower;
+ cells[cell].low_count = -10;
+ low_inc = 0;
+ if (lower <= 30) // somewhat arbitrary
+ cells[cell].lit_delay = true;
+ // set dark_delay if lower > 20?? how to decide?
+ }
+ }
+ else
+ {
+ cells[cell].visible = false;
+ }
+ }
+ else
+ {
+ cells[cell].visible = false; // special flags for blockers
+ }
+
+ // STEP 3 - add increments to upper, lower counts
+ cells[cell].up_count += up_inc;
+ cells[cell].low_count += low_inc;
+
+ // STEP 4 - check south for dark
+ if (south >= 0)
+ if (cells[south].reachedUpper() == true)
+ {
+ if (cells[cell].reachedUpper() == false)
+ {
+ cells[cell].up_max = cells[south].up_max;
+ cells[cell].up_count = cells[south].up_count;
+ cells[cell].up_count -= cells[south].up_max;
+ }
+ cells[cell].lit = false;
+ cells[cell].visible = false;
+ }
+
+ // STEP 5 - nuke lower if south lower
+ if (south >= 0)
+ {
+ if (cells[south].reachedLower())
+ {
+ cells[cell].low_max = cells[south].low_max;
+ cells[cell].low_count = cells[south].low_count;
+ cells[cell].low_count -= cells[south].low_max;
+ cells[south].low_count = cells[south].low_max = 0;
+ }
+
+ if (cells[south].low_max != 0
+ || (cells[south].lit == false
+ && cells[south].low_max == 0))
+ {
+ cells[cell].low_count = cells[cell].low_max + 10;
+ }
+ }
+
+ // STEP 6 - light up if we've reached lower bound
+ if (cells[cell].reachedLower() == true)
+ cells[cell].lit = true;
+
+ // now place appropriate value in sh
+ if (cells[cell].lit == true
+ || (blocker == true && cells[cell].visible == true))
+ {
+ sh[sh_xo + tx][sh_yo + ty] = gv;
+ }
+ else
+ sh[sh_xo + tx][sh_yo + ty] = 0;
+
+ if (cells[cell].lit == true)
+ row_dark = false;
+ } // end for - cells
+
+ vis_corner = false; // don't carry over to next row. :)
+ if (row_dark == true)
+ all_dark = true;
+ } // end for - rows
+}
+
+void losight(FixedArray < unsigned int, 19, 19 > &sh,
+ FixedArray < unsigned char, 80, 70 > &gr, int x_p, int y_p)
+{
+ int o;
+
+ for (o = 0; o < 8; o++)
+ los_octant(o, sh, gr, x_p, y_p);
+}
+
+
+void draw_border(void)
+{
+ textcolor( BORDER_COLOR );
+ clrscr();
+ redraw_skill( you.your_name, player_title() );
+
+ gotoxy(40, 2);
+ cprintf( "%s %s", species_name( you.species, you.experience_level ),
+ (you.wizard ? "*WIZARD*" : "" ) );
+
+ gotoxy(40, 3); cprintf("HP:");
+ gotoxy(40, 4); cprintf("Magic:");
+ gotoxy(40, 5); cprintf("AC:");
+ gotoxy(40, 6); cprintf("EV:");
+ gotoxy(40, 7); cprintf("Str:");
+ gotoxy(40, 8); cprintf("Int:");
+ gotoxy(40, 9); cprintf("Dex:");
+ gotoxy(40, 10); cprintf("Gold:");
+ gotoxy(40, 11); cprintf("Experience:");
+ gotoxy(40, 12); cprintf("Level");
+} // end draw_border()
+
+// show_map() now centers the known map along x or y. This prevents
+// the player from getting "artificial" location clues by using the
+// map to see how close to the end they are. They'll need to explore
+// to get that. This function is still a mess, though. -- bwr
+void show_map( FixedVector<int, 2> &spec_place )
+{
+ int i, j;
+
+ int bufcount2 = 0;
+
+ char move_x = 0;
+ char move_y = 0;
+ char getty = 0;
+
+#ifdef DOS_TERM
+ char buffer[4800];
+#endif
+
+ // buffer2[GYM * GXM * 2] segfaults my box {dlb}
+ char buffer2[GYM * GXM * 2];
+
+ char min_x = 80, max_x = 0, min_y = 0, max_y = 0;
+ bool found_y = false;
+
+ const int num_lines = get_number_of_lines();
+ const int half_screen = num_lines / 2 - 1;
+
+ for (j = 0; j < GYM; j++)
+ {
+ for (i = 0; i < GXM; i++)
+ {
+ if (env.map[i][j])
+ {
+ if (!found_y)
+ {
+ found_y = true;
+ min_y = j;
+ }
+
+ max_y = j;
+
+ if (i < min_x)
+ min_x = i;
+
+ if (i > max_x)
+ max_x = i;
+ }
+ }
+ }
+
+ const int map_lines = max_y - min_y + 1;
+
+ const int start_x = min_x + (max_x - min_x + 1) / 2 - 40; // no x scrolling
+ int start_y; // y does scroll
+
+ int screen_y = you.y_pos;
+
+ // if close to top of known map, put min_y on top
+ // else if close to bottom of known map, put max_y on bottom.
+ //
+ // The num_lines comparisons are done to keep things neat, by
+ // keeping things at the top of the screen. By shifting an
+ // additional one in the num_lines > map_lines case, we can
+ // keep the top line clear... which makes things look a whole
+ // lot better for small maps.
+ if (num_lines > map_lines)
+ screen_y = min_y + half_screen - 1;
+ else if (num_lines == map_lines || screen_y - half_screen < min_y)
+ screen_y = min_y + half_screen;
+ else if (screen_y + half_screen > max_y)
+ screen_y = max_y - half_screen;
+
+ int curs_x = you.x_pos - start_x;
+ int curs_y = you.y_pos - screen_y + half_screen;
+
+#ifdef DOS_TERM
+ gettext(1, 1, 80, 25, buffer);
+ window(1, 1, 80, 25);
+#endif
+
+ clrscr();
+ textcolor(DARKGREY);
+
+ put_screen:
+ bufcount2 = 0;
+
+ _setcursortype(_NOCURSOR);
+
+#ifdef PLAIN_TERM
+ gotoxy(1, 1);
+#endif
+
+ start_y = screen_y - half_screen;
+
+ for (j = 0; j < num_lines; j++)
+ {
+ for (i = 0; i < 80; i++)
+ {
+ if (start_y + j >= 65 || start_y + j <= 3
+ || start_x + i < 0 || start_x + i >= GXM - 1)
+ {
+ buffer2[bufcount2 + 1] = DARKGREY;
+ buffer2[bufcount2] = 0;
+ bufcount2 += 2;
+
+#ifdef PLAIN_TERM
+ goto print_it;
+#endif
+
+#ifdef DOS_TERM
+ continue;
+#endif
+
+ }
+
+ buffer2[bufcount2 + 1] = colour_code_map(start_x + i, start_y + j);
+
+ if (start_x + i + 1 == you.x_pos && start_y + j + 1 == you.y_pos)
+ buffer2[bufcount2 + 1] = WHITE;
+
+ buffer2[bufcount2] = env.map[start_x + i][start_y + j];
+ bufcount2 += 2;
+
+#ifdef PLAIN_TERM
+
+ print_it:
+ // avoid line wrap
+ if (i == 79)
+ continue;
+
+ // newline
+ if (i == 0 && j > 0)
+ gotoxy( 1, j + 1 );
+
+ textcolor( buffer2[bufcount2 - 1] );
+ putch( buffer2[bufcount2 - 2] );
+#endif
+ }
+ }
+
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer2);
+#endif
+
+ _setcursortype(_NORMALCURSOR);
+ gotoxy(curs_x, curs_y);
+
+ gettything:
+ getty = getch();
+
+ if (spec_place[0] == 0 && getty != 0 && getty != '+' && getty != '-'
+ && getty != 'h' && getty != 'j' && getty != 'k' && getty != 'l'
+ && getty != 'y' && getty != 'u' && getty != 'b' && getty != 'n'
+#ifdef LINUX
+ && getty != 'H' && getty != 'J' && getty != 'K' && getty != 'L'
+ && getty != 'Y' && getty != 'U' && getty != 'B' && getty != 'N'
+#endif
+ && (getty < '0' || getty > '9'))
+ {
+ goto putty;
+ }
+
+ if (spec_place[0] == 1 && getty != 0 && getty != '+' && getty != '-'
+ && getty != 'h' && getty != 'j' && getty != 'k' && getty != 'l'
+ && getty != 'y' && getty != 'u' && getty != 'b' && getty != 'n'
+#ifdef LINUX
+ && getty != 'H' && getty != 'J' && getty != 'K' && getty != 'L'
+ && getty != 'Y' && getty != 'U' && getty != 'B' && getty != 'N'
+#endif
+ && getty != '.' && getty != 'S' && (getty < '0' || getty > '9'))
+ {
+ goto gettything;
+ }
+
+ if (getty == 0)
+ getty = getch();
+
+ switch (getty)
+ {
+ case 'b':
+ case '1':
+ move_x = -1;
+ move_y = 1;
+ break;
+
+ case 'j':
+ case '2':
+ move_y = 1;
+ move_x = 0;
+ break;
+
+ case 'u':
+ case '9':
+ move_x = 1;
+ move_y = -1;
+ break;
+
+ case 'k':
+ case '8':
+ move_y = -1;
+ move_x = 0;
+ break;
+
+ case 'y':
+ case '7':
+ move_y = -1;
+ move_x = -1;
+ break;
+
+ case 'h':
+ case '4':
+ move_x = -1;
+ move_y = 0;
+ break;
+
+ case 'n':
+ case '3':
+ move_y = 1;
+ move_x = 1;
+ break;
+
+ case 'l':
+ case '6':
+ move_x = 1;
+ move_y = 0;
+ break;
+
+#ifndef LINUX
+ // This is old DOS keypad support
+ case 'H':
+ move_y = -1;
+ move_x = 0;
+ break;
+ case 'P':
+ move_y = 1;
+ move_x = 0;
+ break;
+ case 'K':
+ move_x = -1;
+ move_y = 0;
+ break;
+ case 'M':
+ move_x = 1;
+ move_y = 0;
+ break;
+ case 'O':
+ move_x = -1;
+ move_y = 1;
+ break;
+ case 'I':
+ move_x = 1;
+ move_y = -1;
+ break;
+ case 'G':
+ move_y = -1;
+ move_x = -1;
+ break;
+ case 'Q':
+ move_y = 1;
+ move_x = 1;
+ break;
+
+#else
+
+ case 'B':
+ move_x = -10;
+ move_y = 10;
+ break;
+
+ case 'J':
+ move_y = 10;
+ move_x = 0;
+ break;
+
+ case 'U':
+ move_x = 10;
+ move_y = -10;
+ break;
+
+ case 'K':
+ move_y = -10;
+ move_x = 0;
+ break;
+
+ case 'Y':
+ move_y = -10;
+ move_x = -10;
+ break;
+
+ case 'H':
+ move_x = -10;
+ move_y = 0;
+ break;
+
+ case 'N':
+ move_y = 10;
+ move_x = 10;
+ break;
+
+ case 'L':
+ move_x = 10;
+ move_y = 0;
+ break;
+
+#endif
+
+ case '+':
+ move_y = 20;
+ move_x = 0;
+ break;
+ case '-':
+ move_y = -20;
+ move_x = 0;
+ break;
+ case '.':
+ case '\r':
+ case 'S':
+ spec_place[0] = start_x + curs_x;
+ spec_place[1] = start_y + curs_y;
+ goto putty;
+
+ default:
+ move_x = 0;
+ move_y = 0;
+ break;
+ }
+
+ if (curs_x + move_x < 1 || curs_x + move_x > 80)
+ move_x = 0;
+
+ curs_x += move_x;
+
+ if (num_lines < map_lines)
+ {
+ // Scrolling only happens when we don't have a large enough
+ // display to show the known map.
+ if (getty == '-' || getty == '+')
+ {
+ if (getty == '-')
+ screen_y -= 20;
+
+ if (screen_y <= min_y + half_screen)
+ screen_y = min_y + half_screen;
+
+ if (getty == '+')
+ screen_y += 20;
+
+ if (screen_y >= max_y - half_screen)
+ screen_y = max_y - half_screen;
+
+ goto put_screen;
+ }
+
+ if (curs_y + move_y < 1)
+ {
+ // screen_y += (curs_y + move_y) - 1;
+ screen_y += move_y;
+
+ if (screen_y < min_y + half_screen)
+ screen_y = min_y + half_screen;
+
+ move_y = 0;
+ }
+
+ if (curs_y + move_y > num_lines - 1)
+ {
+ // screen_y += (curs_y + move_y) - num_lines + 1;
+ screen_y += move_y;
+
+ if (screen_y > max_y - half_screen)
+ screen_y = max_y - half_screen;
+
+ move_y = 0;
+ }
+ }
+
+ if (curs_y + move_y < 1 || curs_y + move_y > num_lines)
+ move_y = 0;
+
+ curs_y += move_y;
+ goto put_screen;
+
+ putty:
+
+#ifdef DOS_TERM
+ puttext(1, 1, 80, 25, buffer);
+#endif
+
+ return;
+} // end show_map()
+
+
+void magic_mapping(int map_radius, int proportion)
+{
+ int i, j, k, l, empty_count;
+
+ if (map_radius > 50)
+ map_radius = 50;
+
+ for (i = you.x_pos - map_radius; i < you.x_pos + map_radius; i++)
+ {
+ for (j = you.y_pos - map_radius; j < you.y_pos + map_radius; j++)
+ {
+ if (random2(100) > proportion)
+ continue; // note that proportion can be over 100
+
+ if (i < 5 || j < 5 || i > (GXM - 5) || j > (GYM - 5))
+ continue;
+
+ if (env.map[i][j] == mapch2(grd[i + 1][j + 1]))
+ continue;
+
+ empty_count = 8;
+
+ if (grd[i][j] < DNGN_LAVA && grd[i][j] != DNGN_CLOSED_DOOR)
+ {
+ for (k = 0; k < 3; k++)
+ {
+ for (l = 0; l < 3; l++)
+ {
+ if (k == 1 && l == 1)
+ continue;
+
+ if (grd[i + k][j + l] <= 60
+ && grd[i + k][j + l] != DNGN_CLOSED_DOOR)
+ {
+ empty_count--;
+ }
+ }
+ }
+ }
+
+ if (empty_count > 0)
+ env.map[i][j] = mapch(grd[i + 1][j + 1]);
+ }
+ }
+} // end magic_mapping()
+
+
+/* mapchars 3 & 4 are for non-ibm char sets */
+unsigned char mapchar(unsigned char ldfk)
+{
+ unsigned char showed = 0;
+
+ switch (ldfk)
+ {
+ case DNGN_UNSEEN:
+ showed = 0;
+ break;
+
+ case DNGN_SECRET_DOOR:
+ case DNGN_ROCK_WALL:
+ case DNGN_PERMAROCK_WALL:
+ case DNGN_STONE_WALL:
+ case DNGN_METAL_WALL:
+ case DNGN_GREEN_CRYSTAL_WALL:
+ case DNGN_WAX_WALL:
+ showed = 176;
+ break;
+
+ case DNGN_CLOSED_DOOR:
+ showed = 206;
+ break;
+
+ case 20: // orcish idol
+ case 24: // ???
+ case 25: // ???
+ case DNGN_SILVER_STATUE:
+ case DNGN_GRANITE_STATUE:
+ case DNGN_ORANGE_CRYSTAL_STATUE:
+ showed = '8';
+ break;
+
+ case DNGN_LAVA_X:
+ case DNGN_WATER_X:
+ case DNGN_LAVA:
+ case DNGN_DEEP_WATER:
+ case DNGN_SHALLOW_WATER:
+ showed = 247;
+ break;
+
+ case DNGN_FLOOR:
+ case DNGN_UNDISCOVERED_TRAP:
+ showed = 250;
+ break;
+
+ //case 68: showed = '>'; break; // < (60)
+
+ case DNGN_OPEN_DOOR:
+ showed = 39;
+ break;
+
+ //case 72: showed = '<'; break;
+
+ case DNGN_TRAP_MECHANICAL:
+ case DNGN_TRAP_MAGICAL:
+ case DNGN_TRAP_III:
+ showed = '^';
+ break;
+
+ case DNGN_STONE_STAIRS_DOWN_I:
+ case DNGN_STONE_STAIRS_DOWN_II:
+ case DNGN_STONE_STAIRS_DOWN_III:
+ case DNGN_ROCK_STAIRS_DOWN:
+ case DNGN_ENTER_ORCISH_MINES:
+ case DNGN_ENTER_HIVE:
+ case DNGN_ENTER_LAIR:
+ case DNGN_ENTER_SLIME_PITS:
+ case DNGN_ENTER_VAULTS:
+ case DNGN_ENTER_CRYPT:
+ case DNGN_ENTER_HALL_OF_BLADES:
+ case DNGN_ENTER_TEMPLE:
+ case DNGN_ENTER_SNAKE_PIT:
+ case DNGN_ENTER_ELVEN_HALLS:
+ case DNGN_ENTER_TOMB:
+ case DNGN_ENTER_SWAMP:
+ case 123:
+ case 124:
+ case 125:
+ case 126:
+ showed = '>';
+ break;
+
+ case DNGN_STONE_STAIRS_UP_I:
+ case DNGN_STONE_STAIRS_UP_II:
+ case DNGN_STONE_STAIRS_UP_III:
+ case DNGN_ROCK_STAIRS_UP:
+ case DNGN_RETURN_FROM_ORCISH_MINES:
+ case DNGN_RETURN_FROM_HIVE:
+ case DNGN_RETURN_FROM_LAIR:
+ case DNGN_RETURN_FROM_SLIME_PITS:
+ case DNGN_RETURN_FROM_VAULTS:
+ case DNGN_RETURN_FROM_CRYPT:
+ case DNGN_RETURN_FROM_HALL_OF_BLADES:
+ case DNGN_RETURN_FROM_TEMPLE:
+ case DNGN_RETURN_FROM_SNAKE_PIT:
+ case DNGN_RETURN_FROM_ELVEN_HALLS:
+ case DNGN_RETURN_FROM_TOMB:
+ case DNGN_RETURN_FROM_SWAMP:
+ case 143:
+ case 144:
+ case 145:
+ case 146:
+ showed = '<';
+ break;
+
+ case DNGN_ENTER_HELL:
+ case DNGN_ENTER_LABYRINTH:
+ case DNGN_ENTER_SHOP:
+ case DNGN_ENTER_DIS:
+ case DNGN_ENTER_GEHENNA:
+ case DNGN_ENTER_COCYTUS:
+ case DNGN_ENTER_TARTARUS:
+ case DNGN_ENTER_ABYSS:
+ case DNGN_EXIT_ABYSS:
+ case DNGN_STONE_ARCH:
+ case DNGN_ENTER_PANDEMONIUM:
+ case DNGN_EXIT_PANDEMONIUM:
+ case DNGN_TRANSIT_PANDEMONIUM:
+ case DNGN_ENTER_ZOT:
+ case DNGN_RETURN_FROM_ZOT:
+ showed = 239;
+ break;
+
+ case DNGN_ALTAR_ZIN:
+ case DNGN_ALTAR_SHINING_ONE:
+ case DNGN_ALTAR_KIKUBAAQUDGHA:
+ case DNGN_ALTAR_YREDELEMNUL:
+ case DNGN_ALTAR_XOM:
+ case DNGN_ALTAR_VEHUMET:
+ case DNGN_ALTAR_OKAWARU:
+ case DNGN_ALTAR_MAKHLEB:
+ case DNGN_ALTAR_SIF_MUNA:
+ case DNGN_ALTAR_TROG:
+ case DNGN_ALTAR_NEMELEX_XOBEH:
+ case DNGN_ALTAR_ELYVILON:
+ showed = 220;
+ break;
+
+ case DNGN_BLUE_FOUNTAIN:
+ case DNGN_DRY_FOUNTAIN_I:
+ case DNGN_SPARKLING_FOUNTAIN:
+ case DNGN_DRY_FOUNTAIN_II:
+ case DNGN_DRY_FOUNTAIN_III:
+ case DNGN_DRY_FOUNTAIN_IV:
+ case DNGN_DRY_FOUNTAIN_V:
+ case DNGN_DRY_FOUNTAIN_VI:
+ case DNGN_DRY_FOUNTAIN_VII:
+ case DNGN_DRY_FOUNTAIN_VIII:
+ case DNGN_PERMADRY_FOUNTAIN:
+ showed = 159;
+ break;
+
+ default:
+ showed = 0;
+ break;
+ }
+
+ return showed;
+}
+
+
+unsigned char mapchar2(unsigned char ldfk)
+{
+ unsigned char showed = 0;
+
+ switch (ldfk)
+ {
+ case DNGN_UNSEEN:
+ showed = 0;
+ break;
+
+ case DNGN_SECRET_DOOR:
+ case DNGN_ROCK_WALL:
+ case DNGN_PERMAROCK_WALL:
+ case DNGN_STONE_WALL:
+ case DNGN_METAL_WALL:
+ case DNGN_GREEN_CRYSTAL_WALL:
+ case DNGN_WAX_WALL:
+ showed = 177;
+ break;
+
+ case DNGN_CLOSED_DOOR:
+ showed = 254;
+ break;
+
+ //case DNGN_LAVA_X: showed = 247; break; // deprecated? {dlb}
+ //case DNGN_WATER_X: showed = 247; break; // deprecated? {dlb}
+
+ case 20: // orcish idol
+ case 24: // ???
+ case 25: // ???
+ case DNGN_SILVER_STATUE:
+ case DNGN_GRANITE_STATUE:
+ case DNGN_ORANGE_CRYSTAL_STATUE:
+ showed = '8';
+ break;
+
+ case DNGN_LAVA:
+ case DNGN_DEEP_WATER:
+ case DNGN_SHALLOW_WATER:
+ showed = 247;
+ break;
+
+ case DNGN_FLOOR:
+ case DNGN_UNDISCOVERED_TRAP:
+ showed = 249;
+ break;
+
+ case 68:
+ showed = '>';
+ break; // <
+
+ case DNGN_OPEN_DOOR:
+ showed = 39;
+ break;
+
+ case 72:
+ showed = '<';
+ break; // <
+
+ case DNGN_TRAP_MECHANICAL:
+ case DNGN_TRAP_MAGICAL:
+ case DNGN_TRAP_III:
+ showed = '^';
+ break;
+
+ case DNGN_STONE_STAIRS_DOWN_I:
+ case DNGN_STONE_STAIRS_DOWN_II:
+ case DNGN_STONE_STAIRS_DOWN_III:
+ case DNGN_ROCK_STAIRS_DOWN:
+ case DNGN_ENTER_ORCISH_MINES:
+ case DNGN_ENTER_HIVE:
+ case DNGN_ENTER_LAIR:
+ case DNGN_ENTER_SLIME_PITS:
+ case DNGN_ENTER_VAULTS:
+ case DNGN_ENTER_CRYPT:
+ case DNGN_ENTER_HALL_OF_BLADES:
+ case DNGN_ENTER_TEMPLE:
+ case DNGN_ENTER_SNAKE_PIT:
+ case DNGN_ENTER_ELVEN_HALLS:
+ case DNGN_ENTER_TOMB:
+ case DNGN_ENTER_SWAMP:
+ case 123:
+ case 124:
+ case 125:
+ case 126:
+ showed = '>';
+ break;
+
+ case DNGN_STONE_STAIRS_UP_I:
+ case DNGN_STONE_STAIRS_UP_II:
+ case DNGN_STONE_STAIRS_UP_III:
+ case DNGN_ROCK_STAIRS_UP:
+ case DNGN_RETURN_FROM_ORCISH_MINES:
+ case DNGN_RETURN_FROM_HIVE:
+ case DNGN_RETURN_FROM_LAIR:
+ case DNGN_RETURN_FROM_SLIME_PITS:
+ case DNGN_RETURN_FROM_VAULTS:
+ case DNGN_RETURN_FROM_CRYPT:
+ case DNGN_RETURN_FROM_HALL_OF_BLADES:
+ case DNGN_RETURN_FROM_TEMPLE:
+ case DNGN_RETURN_FROM_SNAKE_PIT:
+ case DNGN_RETURN_FROM_ELVEN_HALLS:
+ case DNGN_RETURN_FROM_TOMB:
+ case DNGN_RETURN_FROM_SWAMP:
+ case 143:
+ case 144:
+ case 145:
+ case 146:
+ showed = '<';
+ break;
+
+ case DNGN_ENTER_HELL:
+ case DNGN_ENTER_LABYRINTH:
+ case DNGN_ENTER_SHOP:
+ case DNGN_ENTER_DIS:
+ case DNGN_ENTER_GEHENNA:
+ case DNGN_ENTER_COCYTUS:
+ case DNGN_ENTER_TARTARUS:
+ case DNGN_ENTER_ABYSS:
+ case DNGN_EXIT_ABYSS:
+ case DNGN_STONE_ARCH:
+ case DNGN_ENTER_PANDEMONIUM:
+ case DNGN_EXIT_PANDEMONIUM:
+ case DNGN_TRANSIT_PANDEMONIUM:
+ case DNGN_ENTER_ZOT:
+ case DNGN_RETURN_FROM_ZOT:
+ showed = 239;
+ break;
+
+ case DNGN_ALTAR_ZIN:
+ case DNGN_ALTAR_SHINING_ONE:
+ case DNGN_ALTAR_KIKUBAAQUDGHA:
+ case DNGN_ALTAR_YREDELEMNUL:
+ case DNGN_ALTAR_XOM:
+ case DNGN_ALTAR_VEHUMET:
+ case DNGN_ALTAR_OKAWARU:
+ case DNGN_ALTAR_MAKHLEB:
+ case DNGN_ALTAR_SIF_MUNA:
+ case DNGN_ALTAR_TROG:
+ case DNGN_ALTAR_NEMELEX_XOBEH:
+ case DNGN_ALTAR_ELYVILON:
+ showed = 220;
+ break;
+
+ case DNGN_BLUE_FOUNTAIN:
+ case DNGN_DRY_FOUNTAIN_I:
+ case DNGN_SPARKLING_FOUNTAIN:
+ case DNGN_DRY_FOUNTAIN_II:
+ case DNGN_DRY_FOUNTAIN_III:
+ case DNGN_DRY_FOUNTAIN_IV:
+ case DNGN_DRY_FOUNTAIN_V:
+ case DNGN_DRY_FOUNTAIN_VI:
+ case DNGN_DRY_FOUNTAIN_VII:
+ case DNGN_DRY_FOUNTAIN_VIII:
+ case DNGN_PERMADRY_FOUNTAIN:
+ showed = 159;
+ break;
+ default:
+ showed = 0;
+ break;
+ }
+
+ return showed;
+}
+
+
+// realize that this is simply a repackaged version of
+// stuff::see_grid() -- make certain they correlate {dlb}:
+bool mons_near(struct monsters *monster, unsigned int foe)
+{
+ // early out -- no foe!
+ if (foe == MHITNOT)
+ return (false);
+
+ if (foe == MHITYOU)
+ {
+ if (monster->x > you.x_pos - 9 && monster->x < you.x_pos + 9
+ && monster->y > you.y_pos - 9 && monster->y < you.y_pos + 9)
+ {
+ if (env.show[monster->x - you.x_pos + 9][monster->y - you.y_pos + 9])
+ return (true);
+ }
+ return (false);
+ }
+
+ // must be a monster
+ struct monsters *myFoe = &menv[foe];
+ if (myFoe->type >= 0)
+ {
+ if (monster->x > myFoe->x - 9 && monster->x < myFoe->x + 9
+ && monster->y > myFoe->y - 9 && monster->y < myFoe->y + 9)
+ {
+ return (true);
+ }
+ }
+
+ return (false);
+} // end mons_near()
+
+
+//---------------------------------------------------------------
+//
+// get_non_ibm_symbol
+//
+// Returns the character code and color for everything drawn
+// without the IBM graphics option.
+//
+//---------------------------------------------------------------
+static void get_non_ibm_symbol(unsigned int object, unsigned short *ch,
+ unsigned short *color)
+{
+ ASSERT(color != NULL);
+ ASSERT(ch != NULL);
+
+ switch (object)
+ {
+
+ case DNGN_UNSEEN:
+ *ch = 0;
+ break;
+
+ case DNGN_ROCK_WALL:
+ case DNGN_PERMAROCK_WALL:
+ *color = env.rock_colour;
+ *ch = '#';
+ break;
+
+ case DNGN_STONE_WALL:
+ if (player_in_branch( BRANCH_HALL_OF_ZOT ))
+ *color = env.rock_colour;
+ else
+ *color = LIGHTGREY;
+ *ch = '#';
+ break;
+
+ case DNGN_CLOSED_DOOR:
+ *ch = '+';
+ break;
+
+ case DNGN_METAL_WALL:
+ *ch = '#';
+ *color = CYAN;
+ break;
+
+ case DNGN_SECRET_DOOR:
+ *ch = '#';
+ *color = env.rock_colour;
+ break;
+
+ case DNGN_GREEN_CRYSTAL_WALL:
+ *ch = '#';
+ *color = GREEN;
+ break;
+
+ case DNGN_ORCISH_IDOL:
+ *ch = '8';
+ *color = DARKGREY;
+ break;
+
+ case DNGN_WAX_WALL:
+ *ch = '#';
+ *color = YELLOW;
+ break;
+
+ case DNGN_SILVER_STATUE:
+ *ch = '8';
+ *color = WHITE;
+ Visible_Statue[ STATUE_SILVER ] = 1;
+ break;
+
+ case DNGN_GRANITE_STATUE:
+ *ch = '8';
+ *color = LIGHTGREY;
+ break;
+
+ case DNGN_ORANGE_CRYSTAL_STATUE:
+ *ch = '8';
+ *color = LIGHTRED;
+ Visible_Statue[ STATUE_ORANGE_CRYSTAL ] = 1;
+ break;
+
+ case DNGN_LAVA:
+ *ch = '{';
+ *color = RED;
+ break;
+
+ case DNGN_DEEP_WATER:
+ *ch = '{';
+ // this wavy thing also used for water elemental
+ // note that some monsters which use IBM graphics aren't set
+ // for this function - too tricky for now.
+ *color = BLUE;
+ break;
+
+ case DNGN_SHALLOW_WATER:
+ *color = CYAN;
+ *ch = '{';
+ break;
+
+ case DNGN_FLOOR:
+ *color = env.floor_colour;
+ *ch = '.';
+ break;
+
+ case DNGN_ENTER_HELL:
+ *color = RED;
+ *ch = '\\';
+ seen_other_thing(DNGN_ENTER_HELL);
+ break;
+
+ case DNGN_OPEN_DOOR:
+ *ch = '\'';
+ break;
+
+ case DNGN_BRANCH_STAIRS:
+ *color = BROWN;
+ *ch = '>';
+ break;
+
+ case DNGN_TRAP_MECHANICAL:
+ *color = 11;
+ *ch = '^';
+ break;
+
+ case DNGN_TRAP_MAGICAL:
+ *color = MAGENTA;
+ *ch = '^';
+ break;
+
+ case DNGN_TRAP_III:
+ *color = LIGHTGREY;
+ *ch = '^';
+ break;
+
+ case DNGN_UNDISCOVERED_TRAP:
+ *color = env.floor_colour;
+ *ch = '.';
+ break;
+
+ case DNGN_ENTER_SHOP:
+ *color = YELLOW;
+ *ch = '\\';
+ seen_other_thing(DNGN_ENTER_SHOP);
+ break;
+// if I change anything above here, must also change magic mapping!
+
+ case DNGN_ENTER_LABYRINTH:
+ *color = LIGHTGREY;
+ *ch = '\\';
+ seen_other_thing(DNGN_ENTER_LABYRINTH);
+ break;
+
+ case DNGN_ROCK_STAIRS_DOWN:
+ *color = BROWN; // ladder
+ case DNGN_STONE_STAIRS_DOWN_I:
+ case DNGN_STONE_STAIRS_DOWN_II:
+ case DNGN_STONE_STAIRS_DOWN_III:
+ *ch = '>';
+ break;
+
+ case DNGN_ROCK_STAIRS_UP:
+ *color = BROWN; // ladder
+ case DNGN_STONE_STAIRS_UP_I:
+ case DNGN_STONE_STAIRS_UP_II:
+ case DNGN_STONE_STAIRS_UP_III:
+ *ch = '<';
+ break;
+
+ case DNGN_ENTER_DIS:
+ *color = CYAN;
+ *ch = '\\';
+ break;
+
+ case DNGN_ENTER_GEHENNA:
+ *color = RED;
+ *ch = '\\';
+ break;
+
+ case DNGN_ENTER_COCYTUS:
+ *color = LIGHTCYAN;
+ *ch = '\\';
+ break;
+
+ case DNGN_ENTER_TARTARUS:
+ *color = DARKGREY;
+ *ch = '\\';
+ break;
+
+ case DNGN_ENTER_ABYSS:
+ *color = random2(16);
+ *ch = '\\';
+ seen_other_thing(DNGN_ENTER_ABYSS);
+ break;
+
+ case DNGN_EXIT_ABYSS:
+ *color = random2(16);
+ *ch = '\\';
+ break;
+
+ case DNGN_STONE_ARCH:
+ *color = LIGHTGREY;
+ *ch = '\\';
+ break;
+
+ case DNGN_ENTER_PANDEMONIUM:
+ *color = LIGHTBLUE;
+ *ch = '\\';
+ seen_other_thing(DNGN_ENTER_PANDEMONIUM);
+ break;
+
+ case DNGN_EXIT_PANDEMONIUM:
+ *color = LIGHTBLUE;
+ *ch = '\\';
+ break;
+
+ case DNGN_TRANSIT_PANDEMONIUM:
+ *color = LIGHTGREEN;
+ *ch = '\\';
+ break; // gate to other part of pandemonium
+
+ case DNGN_ENTER_ORCISH_MINES:
+ case DNGN_ENTER_HIVE:
+ case DNGN_ENTER_LAIR:
+ case DNGN_ENTER_SLIME_PITS:
+ case DNGN_ENTER_VAULTS:
+ case DNGN_ENTER_CRYPT:
+ case DNGN_ENTER_HALL_OF_BLADES:
+ case DNGN_ENTER_TEMPLE:
+ case DNGN_ENTER_SNAKE_PIT:
+ case DNGN_ENTER_ELVEN_HALLS:
+ case DNGN_ENTER_TOMB:
+ case DNGN_ENTER_SWAMP:
+ case 123:
+ case 124:
+ case 125:
+ case 126:
+ *color = YELLOW;
+ *ch = '>';
+ seen_staircase(object);
+ break;
+
+ case DNGN_ENTER_ZOT:
+ *color = MAGENTA;
+ *ch = '\\';
+ seen_staircase(object);
+ break;
+
+ case DNGN_RETURN_FROM_ORCISH_MINES:
+ case DNGN_RETURN_FROM_HIVE:
+ case DNGN_RETURN_FROM_LAIR:
+ case DNGN_RETURN_FROM_SLIME_PITS:
+ case DNGN_RETURN_FROM_VAULTS:
+ case DNGN_RETURN_FROM_CRYPT:
+ case DNGN_RETURN_FROM_HALL_OF_BLADES:
+ case DNGN_RETURN_FROM_TEMPLE:
+ case DNGN_RETURN_FROM_SNAKE_PIT:
+ case DNGN_RETURN_FROM_ELVEN_HALLS:
+ case DNGN_RETURN_FROM_TOMB:
+ case DNGN_RETURN_FROM_SWAMP:
+ case 143:
+ case 144:
+ case 145:
+ case 146:
+ *color = YELLOW;
+ *ch = '<';
+ break;
+
+ case DNGN_RETURN_FROM_ZOT:
+ *color = MAGENTA;
+ *ch = '\\';
+ break;
+
+ case DNGN_ALTAR_ZIN:
+ *color = WHITE;
+ *ch = '_';
+ seen_altar(GOD_ZIN);
+ break;
+
+ case DNGN_ALTAR_SHINING_ONE:
+ *color = YELLOW;
+ *ch = '_';
+ seen_altar(GOD_SHINING_ONE);
+ break;
+
+ case DNGN_ALTAR_KIKUBAAQUDGHA:
+ *color = DARKGREY;
+ *ch = '_';
+ seen_altar(GOD_KIKUBAAQUDGHA);
+ break;
+
+ case DNGN_ALTAR_YREDELEMNUL:
+ *color = DARKGREY;
+ if (one_chance_in(3))
+ *color = RED;
+ *ch = '_';
+ seen_altar(GOD_YREDELEMNUL);
+ break;
+
+ case DNGN_ALTAR_XOM:
+ *color = random_colour();
+ *ch = '_';
+ seen_altar(GOD_XOM);
+ break;
+
+ case DNGN_ALTAR_VEHUMET:
+ *color = LIGHTBLUE;
+ if (one_chance_in(3))
+ *color = LIGHTMAGENTA;
+ if (one_chance_in(3))
+ *color = LIGHTRED;
+ *ch = '_';
+ seen_altar(GOD_VEHUMET);
+ break;
+
+ case DNGN_ALTAR_OKAWARU:
+ *color = CYAN;
+ *ch = '_';
+ seen_altar(GOD_OKAWARU);
+ break;
+
+ case DNGN_ALTAR_MAKHLEB:
+ *color = RED;
+ if (one_chance_in(3))
+ *color = LIGHTRED;
+ if (one_chance_in(3))
+ *color = YELLOW;
+ *ch = '_';
+ seen_altar(GOD_MAKHLEB);
+ break;
+
+ case DNGN_ALTAR_SIF_MUNA:
+ *color = BLUE;
+ *ch = '_';
+ seen_altar(GOD_SIF_MUNA);
+ break;
+
+ case DNGN_ALTAR_TROG:
+ *color = RED;
+ *ch = '_';
+ seen_altar(GOD_TROG);
+ break;
+
+ case DNGN_ALTAR_NEMELEX_XOBEH:
+ *color = LIGHTMAGENTA;
+ *ch = '_';
+ seen_altar(GOD_NEMELEX_XOBEH);
+ break;
+
+ case DNGN_ALTAR_ELYVILON:
+ *color = LIGHTGREY;
+ *ch = '_';
+ seen_altar(GOD_ELYVILON);
+ break;
+
+ case DNGN_BLUE_FOUNTAIN:
+ *color = BLUE;
+ *ch = '}';
+ break;
+
+ case DNGN_SPARKLING_FOUNTAIN:
+ *color = LIGHTBLUE;
+ *ch = '}';
+ break;
+
+ case DNGN_DRY_FOUNTAIN_I:
+ case DNGN_DRY_FOUNTAIN_II:
+ case DNGN_PERMADRY_FOUNTAIN:
+ *color = LIGHTGREY;
+ *ch = '}';
+ break;
+
+ case 256:
+ *ch = '0';
+ break;
+
+ case 257:
+ *color = CYAN;
+ *ch = '~';
+ break; /* Invis creature walking through water */
+
+ case 258:
+ *ch = ')';
+ break; // weapon )
+
+ case 259:
+ *ch = '[';
+ break; // armour [
+
+ case 260:
+ *ch = '/';
+ break; // wands, etc.
+
+ case 261:
+ *ch = '%';
+ break; // food
+
+ case 262:
+ *ch = '+';
+ break; // books +
+
+ case 263:
+ *ch = '?';
+ break; // scroll ?
+
+ case 264:
+ *ch = '=';
+ break; // ring = etc
+
+ case 265:
+ *ch = '!';
+ break; // potions !
+
+ case 266:
+ *ch = '(';
+ break; // stones
+
+ case 267:
+ *ch = ':';
+ break; // book +
+
+ case 268:
+ *ch = '%';
+ break; // corpses part 1
+
+ case 269:
+ *ch = '|';
+ break; // magical staves
+
+ case 270:
+ *ch = '}';
+ break; // gems
+
+ case 271:
+ *ch = '%';
+ break; // don't know ?
+
+ case 272:
+ *ch = '$';
+ break; // $ gold
+
+ case 273:
+ *ch = '"';
+ break; // amulet
+
+ default:
+ int mnr = object;
+ *ch = ((mnr >= 297) ? mons_char(mnr - 297) : object); // yeah
+ break;
+ }
+}
+
+
+/*
+ This is the viewwindow function for computers without IBM graphic displays.
+ It is activated by a command line argument, which sets a function pointer.
+ */
+void viewwindow3(char draw_it, bool do_updates)
+{
+ int bufcount = 0;
+ FixedVector < unsigned short, 1500 > buffy; //[800]; //392];
+
+ unsigned short ch, color;
+
+ int count_x, count_y;
+
+ losight(env.show, grd, you.x_pos, you.y_pos);
+
+ for (count_x = 0; count_x < 18; count_x++)
+ {
+ for (count_y = 0; count_y < 18; count_y++)
+ {
+ env.show_col[count_x][count_y] = LIGHTGREY;
+ show_backup[count_x][count_y] = 0;
+ }
+ }
+
+ item();
+ cloud_grid();
+ monster_grid(do_updates);
+ bufcount = 0;
+
+ if (draw_it == 1)
+ {
+ _setcursortype(_NOCURSOR);
+ for (count_y = (you.y_pos - 8); (count_y < you.y_pos + 9); count_y++)
+ {
+ bufcount += 16;
+
+ for (count_x = (you.x_pos - 8); (count_x < you.x_pos + 9); count_x++)
+ {
+ color = env.show_col[count_x - you.x_pos + 9]
+ [count_y - you.y_pos + 9];
+
+ if (count_x == you.x_pos && count_y == you.y_pos)
+ {
+ ch = your_sign;
+
+ if (player_is_swimming())
+ {
+ color = (grd[you.x_pos][you.y_pos] == DNGN_DEEP_WATER)
+ ? BLUE : CYAN;
+ }
+ else
+ {
+ color = your_colour;
+ }
+ }
+ else
+ {
+ unsigned int object = env.show[count_x - you.x_pos + 9]
+ [count_y - you.y_pos + 9];
+
+ get_non_ibm_symbol(object, &ch, &color);
+ }
+
+ buffy[bufcount] = ch; //showed;
+ buffy[bufcount + 1] = color;
+ bufcount += 2;
+ }
+
+ bufcount += 16;
+ }
+
+ bufcount = 0;
+
+ if (you.level_type != LEVEL_LABYRINTH
+ && you.level_type != LEVEL_ABYSS)
+ {
+ for (count_y = 0; count_y < 17; count_y++)
+ {
+ bufcount += 16;
+ for (count_x = 0; count_x < 17; count_x++)
+ {
+ if (buffy[bufcount] != 0
+ && (count_x + you.x_pos - 9) >= 0
+ && (count_y + you.y_pos - 9) >= 0)
+ {
+ env.map[count_x + you.x_pos - 9]
+ [count_y + you.y_pos - 9] = buffy[bufcount];
+ }
+
+ if (Options.clean_map == 1
+ && show_backup[count_x + 1][count_y + 1] != 0
+ && (count_x + you.x_pos - 9) >= 0
+ && (count_y + you.y_pos - 9) >= 0)
+ {
+ get_non_ibm_symbol( show_backup[count_x + 1]
+ [count_y + 1],
+ &ch, &color );
+ env.map[count_x + you.x_pos - 9]
+ [count_y + you.y_pos - 9] = ch;
+ }
+ bufcount += 2;
+ }
+ bufcount += 16;
+ }
+ }
+
+ bufcount = 0;
+
+ for (count_y = 0; count_y < 17; count_y++)
+ {
+ for (count_x = 0; count_x < 33; count_x++)
+ {
+ if (count_x + you.x_pos - 17 < 3
+ || count_y + you.y_pos - 9 < 3
+ || count_x + you.x_pos - 14 > (GXM - 3)
+ || count_y + you.y_pos - 9 > (GYM - 3))
+ {
+ buffy[bufcount] = 0;
+ bufcount++;
+ buffy[bufcount] = 0;
+ bufcount++;
+ continue;
+ }
+
+ if (count_x >= 8 && count_x <= 24 && count_y >= 0
+ && count_y <= 16 && buffy[bufcount] != 0)
+ {
+ bufcount += 2;
+ continue;
+ }
+
+ buffy[bufcount] = env.map[count_x + you.x_pos - 17]
+ [count_y + you.y_pos - 9];
+
+ buffy[bufcount + 1] = DARKGREY;
+
+ if (Options.colour_map)
+ {
+ if (env.map[count_x + you.x_pos - 16]
+ [count_y + you.y_pos - 8] != 0)
+ {
+ buffy[bufcount + 1]
+ = colour_code_map( count_x + you.x_pos - 17,
+ count_y + you.y_pos - 9 );
+ }
+ }
+
+ bufcount += 2;
+ }
+ }
+
+ if (you.berserker)
+ {
+ for (count_x = 1; count_x < 1400; count_x += 2)
+ {
+ if (buffy[count_x] != DARKGREY)
+ buffy[count_x] = RED;
+ }
+ }
+
+ if (show_green != BLACK)
+ {
+ for (count_x = 1; count_x < 1400; count_x += 2)
+ {
+ if (buffy[count_x] != DARKGREY)
+ buffy[count_x] = show_green;
+ }
+
+ show_green = ((you.special_wield == SPWLD_SHADOW) ? DARKGREY
+ : BLACK);
+ }
+
+#ifdef DOS_TERM
+ puttext(2, 1, 34, 17, buffy.buffer());
+#endif
+
+#ifdef PLAIN_TERM
+ gotoxy(2, 1);
+ bufcount = 0;
+
+ if (you.running == 0) // this line is purely optional
+ {
+ for (count_x = 0; count_x < 1120; count_x += 2) // 1056
+ {
+ textcolor(buffy[count_x + 1]);
+ putch(buffy[count_x]);
+
+ if (count_x % 66 == 64 && count_x > 0)
+#ifdef DOS_TERM
+ cprintf(EOL " ");
+#endif
+
+#ifdef PLAIN_TERM
+ gotoxy(2, wherey() + 1);
+#endif
+ }
+ }
+#endif
+ _setcursortype(_NORMALCURSOR);
+ } // end of (if brek...)
+} // end viewwindow3()
+
+
+unsigned char mapchar3(unsigned char ldfk)
+{
+ unsigned char showed = 0;
+
+ switch (ldfk)
+ {
+ case DNGN_UNSEEN:
+ showed = 0;
+ break;
+
+ case DNGN_SECRET_DOOR:
+ case DNGN_ROCK_WALL:
+ case DNGN_PERMAROCK_WALL:
+ case DNGN_STONE_WALL:
+ case DNGN_METAL_WALL:
+ case DNGN_GREEN_CRYSTAL_WALL:
+ case DNGN_WAX_WALL:
+ showed = '*';
+ break;
+
+ case DNGN_CLOSED_DOOR:
+ showed = '+';
+ break;
+
+ case 20: // orcish idol
+ case 24: // ???
+ case 25: // ???
+ case DNGN_SILVER_STATUE:
+ case DNGN_GRANITE_STATUE:
+ case DNGN_ORANGE_CRYSTAL_STATUE:
+ showed = '8';
+ break;
+
+ case DNGN_LAVA_X:
+ case DNGN_WATER_X:
+ case DNGN_LAVA:
+ case DNGN_DEEP_WATER:
+ case DNGN_SHALLOW_WATER:
+ showed = '{';
+ break;
+
+ case DNGN_FLOOR:
+ case DNGN_UNDISCOVERED_TRAP:
+ showed = ',';
+ break;
+
+ //case 68: showed = '>'; break; // < (60)
+
+ case DNGN_OPEN_DOOR:
+ showed = 39;
+ break; // open door
+
+ //case 72: showed = '<'; break;
+
+ case DNGN_TRAP_MECHANICAL:
+ case DNGN_TRAP_MAGICAL:
+ case DNGN_TRAP_III:
+ showed = '^';
+ break;
+
+ case DNGN_STONE_STAIRS_DOWN_I:
+ case DNGN_STONE_STAIRS_DOWN_II:
+ case DNGN_STONE_STAIRS_DOWN_III:
+ case DNGN_ROCK_STAIRS_DOWN:
+ case DNGN_ENTER_ORCISH_MINES:
+ case DNGN_ENTER_HIVE:
+ case DNGN_ENTER_LAIR:
+ case DNGN_ENTER_SLIME_PITS:
+ case DNGN_ENTER_VAULTS:
+ case DNGN_ENTER_CRYPT:
+ case DNGN_ENTER_HALL_OF_BLADES:
+ case DNGN_ENTER_TEMPLE:
+ case DNGN_ENTER_SNAKE_PIT:
+ case DNGN_ENTER_ELVEN_HALLS:
+ case DNGN_ENTER_TOMB:
+ case DNGN_ENTER_SWAMP:
+ case 123:
+ case 124:
+ case 125:
+ case 126:
+ showed = '>';
+ break;
+
+ case DNGN_STONE_STAIRS_UP_I:
+ case DNGN_STONE_STAIRS_UP_II:
+ case DNGN_STONE_STAIRS_UP_III:
+ case DNGN_ROCK_STAIRS_UP:
+ case DNGN_RETURN_FROM_ORCISH_MINES:
+ case DNGN_RETURN_FROM_HIVE:
+ case DNGN_RETURN_FROM_LAIR:
+ case DNGN_RETURN_FROM_SLIME_PITS:
+ case DNGN_RETURN_FROM_VAULTS:
+ case DNGN_RETURN_FROM_CRYPT:
+ case DNGN_RETURN_FROM_HALL_OF_BLADES:
+ case DNGN_RETURN_FROM_TEMPLE:
+ case DNGN_RETURN_FROM_SNAKE_PIT:
+ case DNGN_RETURN_FROM_ELVEN_HALLS:
+ case DNGN_RETURN_FROM_TOMB:
+ case DNGN_RETURN_FROM_SWAMP:
+ case 143:
+ case 144:
+ case 145:
+ case 146:
+ showed = '<';
+ break;
+
+ case DNGN_ENTER_HELL:
+ case DNGN_ENTER_LABYRINTH:
+ case DNGN_ENTER_SHOP:
+ case DNGN_ENTER_DIS:
+ case DNGN_ENTER_GEHENNA:
+ case DNGN_ENTER_COCYTUS:
+ case DNGN_ENTER_TARTARUS:
+ case DNGN_ENTER_ABYSS:
+ case DNGN_EXIT_ABYSS:
+ case DNGN_STONE_ARCH:
+ case DNGN_ENTER_PANDEMONIUM:
+ case DNGN_EXIT_PANDEMONIUM:
+ case DNGN_TRANSIT_PANDEMONIUM:
+ case DNGN_ENTER_ZOT:
+ case DNGN_RETURN_FROM_ZOT:
+ showed = '\\';
+ break;
+
+ case DNGN_ALTAR_ZIN:
+ case DNGN_ALTAR_SHINING_ONE:
+ case DNGN_ALTAR_KIKUBAAQUDGHA:
+ case DNGN_ALTAR_YREDELEMNUL:
+ case DNGN_ALTAR_XOM:
+ case DNGN_ALTAR_VEHUMET:
+ case DNGN_ALTAR_OKAWARU:
+ case DNGN_ALTAR_MAKHLEB:
+ case DNGN_ALTAR_SIF_MUNA:
+ case DNGN_ALTAR_TROG:
+ case DNGN_ALTAR_NEMELEX_XOBEH:
+ case DNGN_ALTAR_ELYVILON:
+ showed = '_';
+ break;
+
+ case DNGN_BLUE_FOUNTAIN:
+ case DNGN_DRY_FOUNTAIN_I:
+ case DNGN_SPARKLING_FOUNTAIN:
+ case DNGN_DRY_FOUNTAIN_II:
+ case DNGN_DRY_FOUNTAIN_III:
+ case DNGN_DRY_FOUNTAIN_IV:
+ case DNGN_DRY_FOUNTAIN_V:
+ case DNGN_DRY_FOUNTAIN_VI:
+ case DNGN_DRY_FOUNTAIN_VII:
+ case DNGN_DRY_FOUNTAIN_VIII:
+ case DNGN_PERMADRY_FOUNTAIN:
+ showed = '}';
+ break;
+
+ default:
+ showed = 0;
+ break;
+ }
+
+ return showed;
+}
+
+
+unsigned char mapchar4(unsigned char ldfk)
+{
+ unsigned char showed = 0;
+
+ switch (ldfk)
+ {
+ case DNGN_UNSEEN:
+ showed = 0;
+ break;
+
+ case DNGN_CLOSED_DOOR:
+ showed = '+';
+ break;
+
+ case DNGN_SECRET_DOOR:
+ case DNGN_ROCK_WALL:
+ case DNGN_PERMAROCK_WALL:
+ case DNGN_STONE_WALL:
+ case DNGN_METAL_WALL:
+ case DNGN_GREEN_CRYSTAL_WALL:
+ case DNGN_WAX_WALL:
+ showed = '#';
+ break;
+
+ case 20: // orcish idol
+ case 24: // ???
+ case 25: // ???
+ case DNGN_SILVER_STATUE:
+ case DNGN_GRANITE_STATUE:
+ case DNGN_ORANGE_CRYSTAL_STATUE:
+ showed = '8';
+ break;
+
+ case DNGN_LAVA_X:
+ case DNGN_WATER_X:
+ case DNGN_LAVA:
+ case DNGN_DEEP_WATER:
+ case DNGN_SHALLOW_WATER:
+ showed = '{';
+ break;
+
+ case DNGN_FLOOR:
+ case DNGN_UNDISCOVERED_TRAP:
+ showed = '.';
+ break;
+
+ case 68:
+ showed = '>'; // <
+ break;
+
+ case DNGN_OPEN_DOOR:
+ showed = 39;
+ break;
+
+ case 72:
+ showed = '<';
+ break;
+
+ case DNGN_TRAP_MECHANICAL:
+ case DNGN_TRAP_MAGICAL:
+ case DNGN_TRAP_III:
+ showed = '^';
+ break;
+
+ case DNGN_STONE_STAIRS_DOWN_I:
+ case DNGN_STONE_STAIRS_DOWN_II:
+ case DNGN_STONE_STAIRS_DOWN_III:
+ case DNGN_ROCK_STAIRS_DOWN:
+ case DNGN_ENTER_ORCISH_MINES:
+ case DNGN_ENTER_HIVE:
+ case DNGN_ENTER_LAIR:
+ case DNGN_ENTER_SLIME_PITS:
+ case DNGN_ENTER_VAULTS:
+ case DNGN_ENTER_CRYPT:
+ case DNGN_ENTER_HALL_OF_BLADES:
+ case DNGN_ENTER_TEMPLE:
+ case DNGN_ENTER_SNAKE_PIT:
+ case DNGN_ENTER_ELVEN_HALLS:
+ case DNGN_ENTER_TOMB:
+ case DNGN_ENTER_SWAMP:
+ case 123:
+ case 124:
+ case 125:
+ case 126:
+ showed = '>';
+ break;
+
+ case DNGN_STONE_STAIRS_UP_I:
+ case DNGN_STONE_STAIRS_UP_II:
+ case DNGN_STONE_STAIRS_UP_III:
+ case DNGN_ROCK_STAIRS_UP:
+ case DNGN_RETURN_FROM_ORCISH_MINES:
+ case DNGN_RETURN_FROM_HIVE:
+ case DNGN_RETURN_FROM_LAIR:
+ case DNGN_RETURN_FROM_SLIME_PITS:
+ case DNGN_RETURN_FROM_VAULTS:
+ case DNGN_RETURN_FROM_CRYPT:
+ case DNGN_RETURN_FROM_HALL_OF_BLADES:
+ case DNGN_RETURN_FROM_TEMPLE:
+ case DNGN_RETURN_FROM_SNAKE_PIT:
+ case DNGN_RETURN_FROM_ELVEN_HALLS:
+ case DNGN_RETURN_FROM_TOMB:
+ case DNGN_RETURN_FROM_SWAMP:
+ case 143:
+ case 144:
+ case 145:
+ case 146:
+ showed = '<';
+ break;
+
+ case DNGN_ENTER_HELL:
+ case DNGN_ENTER_LABYRINTH:
+ case DNGN_ENTER_SHOP:
+ case DNGN_ENTER_DIS:
+ case DNGN_ENTER_GEHENNA:
+ case DNGN_ENTER_COCYTUS:
+ case DNGN_ENTER_TARTARUS:
+ case DNGN_ENTER_ABYSS:
+ case DNGN_EXIT_ABYSS:
+ case DNGN_STONE_ARCH:
+ case DNGN_ENTER_PANDEMONIUM:
+ case DNGN_EXIT_PANDEMONIUM:
+ case DNGN_TRANSIT_PANDEMONIUM:
+ case DNGN_ENTER_ZOT:
+ case DNGN_RETURN_FROM_ZOT:
+ showed = '\\';
+ break;
+
+ case DNGN_ALTAR_ZIN:
+ case DNGN_ALTAR_SHINING_ONE:
+ case DNGN_ALTAR_KIKUBAAQUDGHA:
+ case DNGN_ALTAR_YREDELEMNUL:
+ case DNGN_ALTAR_XOM:
+ case DNGN_ALTAR_VEHUMET:
+ case DNGN_ALTAR_OKAWARU:
+ case DNGN_ALTAR_MAKHLEB:
+ case DNGN_ALTAR_SIF_MUNA:
+ case DNGN_ALTAR_TROG:
+ case DNGN_ALTAR_NEMELEX_XOBEH:
+ case DNGN_ALTAR_ELYVILON:
+ showed = '_';
+ break;
+
+ case DNGN_BLUE_FOUNTAIN:
+ case DNGN_DRY_FOUNTAIN_I:
+ case DNGN_SPARKLING_FOUNTAIN:
+ case DNGN_DRY_FOUNTAIN_II:
+ case DNGN_DRY_FOUNTAIN_III:
+ case DNGN_DRY_FOUNTAIN_IV:
+ case DNGN_DRY_FOUNTAIN_V:
+ case DNGN_DRY_FOUNTAIN_VI:
+ case DNGN_DRY_FOUNTAIN_VII:
+ case DNGN_DRY_FOUNTAIN_VIII:
+ case DNGN_PERMADRY_FOUNTAIN:
+ showed = '}';
+ break;
+
+ default:
+ showed = 0;
+ break;
+ }
+
+ return showed;
+}
diff --git a/trunk/source/view.h b/trunk/source/view.h
new file mode 100644
index 0000000000..75c5714ddd
--- /dev/null
+++ b/trunk/source/view.h
@@ -0,0 +1,100 @@
+/*
+ * File: view.cc
+ * Summary: Misc function used to render the dungeon.
+ * Written by: Linley Henzell
+ *
+ * Change History (most recent first):
+ *
+ * <2> 9/29/99 BCR Added the BORDER_COLOR define
+ * <1> -/--/-- LRH Created
+ */
+
+
+#ifndef VIEW_H
+#define VIEW_H
+
+
+#include "externs.h"
+
+
+#define BORDER_COLOR BROWN
+
+int get_number_of_lines(void);
+
+// last updated 29may2000 {dlb}
+/* ***********************************************************************
+ * called from: bang - beam - direct - effects - fight - monstuff -
+ * mstuff2 - spells1 - spells2
+ * *********************************************************************** */
+bool mons_near(struct monsters *monster, unsigned int foe = MHITYOU);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - player - stuff
+ * *********************************************************************** */
+void draw_border(void);
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - view
+ * *********************************************************************** */
+void item(void);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: direct - monstufff - view
+ * *********************************************************************** */
+void losight(FixedArray<unsigned int, 19, 19>& sh, FixedArray<unsigned char, 80, 70>& gr, int x_p, int y_p);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: ability - acr - it_use3 - item_use - spell
+ * *********************************************************************** */
+void magic_mapping(int map_radius, int proportion);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - effects - it_use2 - it_use3 - item_use - spell -
+ * spells - spells3 - spells4
+ * *********************************************************************** */
+void noisy( int loudness, int nois_x, int nois_y );
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr - spells3
+ * *********************************************************************** */
+void show_map( FixedVector<int, 2>& spec_place );
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void viewwindow2(char draw_it, bool do_updates);
+
+
+// last updated 12may2000 {dlb}
+/* ***********************************************************************
+ * called from: acr
+ * *********************************************************************** */
+void viewwindow3(char draw_it, bool do_updates); // non-IBM graphics
+
+// last updated 19jun2000 (gdl)
+/* ***********************************************************************
+ * called from: acr view
+ * *********************************************************************** */
+void setLOSRadius(int newLR);
+
+// last updated 02apr2001 (gdl)
+/* ***********************************************************************
+ * called from: view monstuff
+ * *********************************************************************** */
+bool check_awaken(int mons_aw);
+
+
+#endif
diff --git a/trunk/source/winhdr.h b/trunk/source/winhdr.h
new file mode 100644
index 0000000000..a8d99fb1e3
--- /dev/null
+++ b/trunk/source/winhdr.h
@@ -0,0 +1,70 @@
+/*
+ * File: WinHdr.h
+ * Summary: OS specific stuff for inclusion into AppHdr.h.
+ * Written by: Jesse Jones
+ *
+ * Copyright © 1999 Jesse Jones.
+ *
+ * Change History (most recent first):
+ *
+ * <1> 5/30/99 JDJ Created.
+ */
+
+
+#ifndef WINHDR_H
+#define WINHDR_H
+
+
+// ===================================================================================
+// Windows Includes
+// ===================================================================================
+#define WIN32_LEAN_AND_MEAN // exclude some of the less common APIs
+#define NOSERVICE
+#define NOMCX
+#define NOIME
+
+#define STRICT 1 // enable as much type checking as the lame Windows API will allow
+#define NOMINMAX // don't let Windows define (lower case!) min and max macros (conflicts with STL)
+
+#include <windows.h>
+#include <wtypes.h>
+#include <commdlg.h>
+#include <tchar.h>
+
+
+// ===================================================================================
+// MSVC Warnings (I'm not sure if these will fly with Crawl)
+// ===================================================================================
+#if _MSC_VER
+#ifndef ENABLE_EXTRA_WARNINGS
+#define ENABLE_EXTRA_WARNINGS 1 // if non-zero selected level 4 warnings are enabled
+#endif
+
+#if ENABLE_EXTRA_WARNINGS
+#pragma warning(error : 4057) // The pointer expressions used with the given operator had different base types.
+// #pragma warning(error : 4100) // The given formal parameter was never referenced in the body of the function for which it was declared.
+#pragma warning(error : 4130) // The operator was used with the address of a string literal.
+#pragma warning(error : 4131) // The specified function declaration is not in prototype form.
+#pragma warning(error : 4132) // The constant was not initialized.
+#pragma warning(error : 4152) // A pointer to a function was converted to a pointer to data, or visa versa.
+#pragma warning(error : 4208) // nonstandard extension used : delete [exp] - exp evaluated but ignored
+#pragma warning(error : 4211) // nonstandard extension used : redefined extern to static
+#pragma warning(error : 4212) // nonstandard extension used : function declaration used ellipsis
+#pragma warning(error : 4222) // nonstandard extension used : 'identifier' : 'static' should not be used on member functions defined at file scope
+#pragma warning(error : 4223) // nonstandard extension used : non-lvalue array converted to pointer
+#pragma warning(error : 4355) // 'this' : used in base member initializer list
+#pragma warning(error : 4663) // C++ language change: to explicitly specialize class template 'identifier' use the following syntax:
+#pragma warning(error : 4665) // C++ language change: assuming 'declaration' is an explicit specialization of a function template
+#pragma warning(error : 4701) // local variable 'name' may be used without having been initialized
+#pragma warning(error : 4705) // statement has no effect
+#pragma warning(error : 4706) // assignment within conditional expression
+#endif
+
+#pragma warning(disable : 4800) // casting integer to bool
+#pragma warning(disable : 4786) // identifier was truncated to '255' characters in the browser
+
+#endif
+
+
+
+#endif
diff --git a/trunk/source/wpn-misc.cc b/trunk/source/wpn-misc.cc
new file mode 100644
index 0000000000..c6d38f98e6
--- /dev/null
+++ b/trunk/source/wpn-misc.cc
@@ -0,0 +1,268 @@
+/*
+ *********************************************************************
+ * File: wpn-misc.cc *
+ * Summary: temporary home for weapon f(x) until struct'ed *
+ * Written by: don brodale <dbrodale@bigfootinteractive.com> *
+ * *
+ * Changelog(most recent first): *
+ * *
+ * <00> 12jun2000 dlb created after little thought *
+ *********************************************************************
+ */
+
+#include "AppHdr.h"
+#include "wpn-misc.h"
+
+#include "externs.h"
+
+// all of this will be replaced by a struct and data handlers {dlb}:
+
+/*
+ **************************************************
+ * *
+ * BEGIN PUBLIC FUNCTIONS *
+ * *
+ **************************************************
+*/
+
+char damage_type(unsigned char wclass, unsigned char wtype)
+{
+ char type_damage = DVORP_CRUSHING; // this is the default, btw {dlb}
+
+ if (wclass == OBJ_WEAPONS)
+ {
+ switch (wtype)
+ {
+ case WPN_DAGGER:
+ case WPN_DEMON_BLADE:
+ case WPN_DOUBLE_SWORD:
+ case WPN_GREAT_SWORD:
+ case WPN_KATANA:
+ case WPN_KNIFE:
+ case WPN_LONG_SWORD:
+ case WPN_QUICK_BLADE:
+ case WPN_SABRE:
+ case WPN_FALCHION:
+ case WPN_SCIMITAR:
+ case WPN_SCYTHE:
+ case WPN_SHORT_SWORD:
+ case WPN_TRIPLE_SWORD:
+ type_damage = DVORP_SLICING;
+ break;
+
+ case WPN_DEMON_TRIDENT:
+ case WPN_EVENINGSTAR:
+ case WPN_GIANT_SPIKED_CLUB:
+ case WPN_MORNINGSTAR:
+ case WPN_SPEAR:
+ case WPN_SPIKED_FLAIL:
+ case WPN_TRIDENT:
+ type_damage = DVORP_PIERCING;
+ break;
+
+ case WPN_WAR_AXE:
+ case WPN_BATTLEAXE:
+ case WPN_BROAD_AXE:
+ case WPN_EXECUTIONERS_AXE:
+ case WPN_GLAIVE:
+ case WPN_HALBERD:
+ case WPN_HAND_AXE:
+ type_damage = DVORP_CHOPPING;
+ break;
+ }
+ }
+
+ return (type_damage);
+} // end damage_type()
+
+bool can_cut_meat(unsigned char wclass, unsigned char wtype)
+{
+ int type = damage_type( wclass, wtype );
+
+ if (type == DVORP_CHOPPING || type == DVORP_SLICING)
+ return (true);
+
+ return (false);
+}
+
+int hands_reqd_for_weapon(unsigned char wclass, unsigned char wtype)
+{
+ int reqd_hands = HANDS_ONE_HANDED;
+
+ switch (wclass)
+ {
+ case OBJ_WEAPONS:
+ switch (wtype)
+ {
+ case WPN_HALBERD:
+ case WPN_SCYTHE:
+ case WPN_GLAIVE:
+ case WPN_QUARTERSTAFF:
+ case WPN_BATTLEAXE:
+ case WPN_EXECUTIONERS_AXE:
+ case WPN_GREAT_SWORD:
+ case WPN_TRIPLE_SWORD:
+ case WPN_GREAT_MACE:
+ case WPN_GREAT_FLAIL:
+ case WPN_GIANT_CLUB:
+ case WPN_GIANT_SPIKED_CLUB:
+ reqd_hands = HANDS_TWO_HANDED;
+ break;
+
+ case WPN_SPEAR:
+ case WPN_TRIDENT:
+ case WPN_DEMON_TRIDENT:
+ case WPN_WAR_AXE:
+ case WPN_BROAD_AXE:
+ case WPN_KATANA:
+ case WPN_DOUBLE_SWORD:
+ reqd_hands = HANDS_ONE_OR_TWO_HANDED;
+ break;
+ }
+ break;
+
+ case OBJ_STAVES:
+ reqd_hands = HANDS_TWO_HANDED;
+ break;
+ }
+
+ return (reqd_hands);
+} // end hands_reqd_for_weapon()
+
+bool is_demonic(unsigned char weapon_subtype)
+{
+ switch (weapon_subtype)
+ {
+ case WPN_DEMON_BLADE:
+ case WPN_DEMON_WHIP:
+ case WPN_DEMON_TRIDENT:
+ return true;
+
+ default:
+ return false;
+ }
+} // end is_demonic()
+
+bool launches_things( unsigned char weapon_subtype )
+{
+ switch (weapon_subtype)
+ {
+ case WPN_SLING:
+ case WPN_BOW:
+ case WPN_CROSSBOW:
+ case WPN_HAND_CROSSBOW:
+ case WPN_BLOWGUN:
+ return (true);
+
+ default:
+ return (false);
+ }
+} // end launches_things()
+
+unsigned char launched_by(unsigned char weapon_subtype)
+{
+ switch (weapon_subtype)
+ {
+ case WPN_BLOWGUN:
+ return MI_NEEDLE;
+ case WPN_SLING:
+ return MI_STONE;
+ case WPN_BOW:
+ return MI_ARROW;
+ case WPN_CROSSBOW:
+ return MI_BOLT;
+ case WPN_HAND_CROSSBOW:
+ return MI_DART;
+ default:
+ return MI_EGGPLANT; // lame debugging code :P {dlb}
+ }
+} // end launched_by()
+
+// this function returns the skill that the weapon would use in melee
+char weapon_skill(unsigned char wclass, unsigned char wtype)
+{
+ char skill2use = SK_FIGHTING;
+
+ if (wclass == OBJ_STAVES
+ && (wtype < STAFF_SMITING || wtype >= STAFF_AIR))
+ {
+ skill2use = SK_STAVES;
+ }
+ else if (wclass != OBJ_WEAPONS)
+ skill2use = SK_FIGHTING;
+ else
+ {
+ switch (wtype)
+ {
+ case WPN_CLUB:
+ case WPN_MACE:
+ case WPN_HAMMER:
+ case WPN_ANCUS:
+ case WPN_WHIP:
+ case WPN_FLAIL:
+ case WPN_MORNINGSTAR:
+ case WPN_GIANT_CLUB:
+ case WPN_GIANT_SPIKED_CLUB:
+ case WPN_EVENINGSTAR:
+ case WPN_DEMON_WHIP:
+ case WPN_SPIKED_FLAIL:
+ case WPN_GREAT_FLAIL:
+ case WPN_GREAT_MACE:
+ case WPN_BOW:
+ case WPN_BLOWGUN:
+ case WPN_CROSSBOW:
+ case WPN_HAND_CROSSBOW:
+ skill2use = SK_MACES_FLAILS;
+ break;
+
+ case WPN_KNIFE:
+ case WPN_DAGGER:
+ case WPN_SHORT_SWORD:
+ case WPN_QUICK_BLADE:
+ case WPN_SABRE:
+ skill2use = SK_SHORT_BLADES;
+ break;
+
+ case WPN_FALCHION:
+ case WPN_LONG_SWORD:
+ case WPN_SCIMITAR:
+ case WPN_KATANA:
+ case WPN_DOUBLE_SWORD:
+ case WPN_DEMON_BLADE:
+ case WPN_GREAT_SWORD:
+ case WPN_TRIPLE_SWORD:
+ skill2use = SK_LONG_SWORDS;
+ break;
+
+ case WPN_HAND_AXE:
+ case WPN_WAR_AXE:
+ case WPN_BROAD_AXE:
+ case WPN_BATTLEAXE:
+ case WPN_EXECUTIONERS_AXE:
+ skill2use = SK_AXES;
+ break;
+
+ case WPN_SPEAR:
+ case WPN_HALBERD:
+ case WPN_GLAIVE:
+ case WPN_SCYTHE:
+ case WPN_TRIDENT:
+ case WPN_DEMON_TRIDENT:
+ skill2use = SK_POLEARMS;
+ break;
+
+ case WPN_QUARTERSTAFF:
+ skill2use = SK_STAVES;
+ break;
+ }
+ }
+
+ return (skill2use);
+} // end weapon_skill()
+/*
+ **************************************************
+ * *
+ * END PUBLIC FUNCTIONS *
+ * *
+ **************************************************
+*/
diff --git a/trunk/source/wpn-misc.h b/trunk/source/wpn-misc.h
new file mode 100644
index 0000000000..e1d45c8d4a
--- /dev/null
+++ b/trunk/source/wpn-misc.h
@@ -0,0 +1,67 @@
+/*
+ *********************************************************************
+ * File: wpn-misc.h *
+ * Summary: temporary home for weapon f(x) until struct'ed *
+ * Written by: don brodale <dbrodale@bigfootinteractive.com> *
+ * *
+ * Changelog(most recent first): *
+ * *
+ * <00> 12jun2000 dlb created after little thought *
+ *********************************************************************
+*/
+
+
+#ifndef WPNMISC_H
+#define WPNMISC_H
+
+#include "externs.h"
+
+
+/* ***********************************************************************
+ * called from: food.h
+ * *********************************************************************** */
+bool can_cut_meat(unsigned char wclass, unsigned char wtype);
+
+/* ***********************************************************************
+ * called from: acr - fight - food - item_use - itemname - spells2
+ * *********************************************************************** */
+char damage_type(unsigned char wclass, unsigned char wtype);
+
+
+// last updated: 10jun2000 {dlb}
+/* ***********************************************************************
+ * called from: describe - fight - item_use
+ * *********************************************************************** */
+int hands_reqd_for_weapon(unsigned char wclass, unsigned char wtype);
+
+
+// last updated: 10jun2000 {dlb}
+/* ***********************************************************************
+ * called from: dungeon - fight - item_use - randart
+ * *********************************************************************** */
+bool is_demonic(unsigned char weapon_subtype);
+
+
+// last updated: 10jun2000 {dlb}
+/* ***********************************************************************
+ * called from: dungeon - item_use - mstuff2
+ * *********************************************************************** */
+unsigned char launched_by(unsigned char weapon_subtype);
+
+
+// last updated: 10jun2000 {dlb}
+/* ***********************************************************************
+ * called from: describe - dungeon - fight - item_use - mstuff2 - randart -
+ * spells2 - spells3
+ * *********************************************************************** */
+bool launches_things( unsigned char weapon_subtype );
+
+
+// last updated: 10jun2000 {dlb}
+/* ***********************************************************************
+ * called from: describe - fight - files - it_use3 - newgame - spells1
+ * *********************************************************************** */
+char weapon_skill(unsigned char wclass, unsigned char wtype);
+
+
+#endif