summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorennewalker <ennewalker@c06c8d41-db1a-0410-9941-cceddc491573>2007-11-22 16:20:45 +0000
committerennewalker <ennewalker@c06c8d41-db1a-0410-9941-cceddc491573>2007-11-22 16:20:45 +0000
commit99bbf3affa945e02892a4d7c93e8cf2fd26057a2 (patch)
tree0bbbe0fd08732fc6c52f6a83093a45cbcb93e620
parentd5c27d429f8037a2cbdb7ea848d3d1e8cb9fefb0 (diff)
downloadcrawl-ref-99bbf3affa945e02892a4d7c93e8cf2fd26057a2.tar.gz
crawl-ref-99bbf3affa945e02892a4d7c93e8cf2fd26057a2.zip
r6764@kamatari (orig r2130): dshaligram | 2007-09-17 15:30:46 -0400
Trunk is now 0.4. r6766@kamatari (orig r2132): dshaligram | 2007-09-17 16:21:17 -0400 Merged newgame fixes and compile fixes for dgamelaunch patches to trunk. r6769@kamatari (orig r2135): j-p-e-g | 2007-09-18 09:37:01 -0400 Hopefully repeat my previous changes for trunk: documentation and index/offset fix. r6770@kamatari (orig r2136): j-p-e-g | 2007-09-18 11:54:14 -0400 Applying modified (by me) mutation patches of dolorous', mostly clean-up and output changes. * More consistent output for Centaurs and chars with hoof mutation (patch 1794849). * Remove "deterioration" (ghouls type) from % screen. d. is right in that this was misleading. (1795995) * Change "no piety" message for Yredelemnul. Okay, this is not mutation-related and of no consequence to boot (Yred doesn't accept offerings), but why not? (1796199) * Mutation output now lists unremovable mutations first (innate and demonspawn). It's all fairly small stuff, but is it small enough to branch? I think yes, but asking doesn't hurt, right? r6771@kamatari (orig r2137): zelgadis | 2007-09-18 21:19:56 -0400 Added new commands "re-do previous command" (bound to `) and "repeat next command" (bound to 0). Though this is just an interface change, it changes code in the core input processing function (input() in acr.cc), and also messes around with the input buffer, so it could probably do with more testing before merging it into the 0.3 branch. r6773@kamatari (orig r2139): zelgadis | 2007-09-18 22:01:24 -0400 "newly seen" vs "already seen" context was missing for see-monster activity interrupt data. r6775@kamatari (orig r2141): zelgadis | 2007-09-18 23:10:09 -0400 Removed detailed_hunger option, the hunger states near starving, very hungry and very full are now always displayed. r6777@kamatari (orig r2143): zelgadis | 2007-09-19 00:18:53 -0400 If wizard mode is on when going through a portal to a bazaar, Crawl will ask the user for the name of a bazaar map to load (minus the "bazaar_" at the front of the name); escape or enter can be pressed to get a random map. Adds new wizard command 'P', to create portal-vault-portals to arbitrary destinations (though any desitnation but "bazaar" will currently cause an assertion when the portal is entered). Adds new map marker class map_wiz_props_marker, which can be used by wizard commands to create a map marker with abritrary properties. r6779@kamatari (orig r2145): zelgadis | 2007-09-19 02:42:50 -0400 Introduces three new wall types, translucent versions of the normal rock wall, stone wall and permanent rock wall. These are for use in vaults, and are never randomly generated. Magically translucent versions of the normal wall types are used, rather than glass, so we don't have to figure out how glass would react to things like digging and Shatter, but can re-use the code for the normal wall types. I've tried to fix all the places where the old code assumes that any square which is visible to the player has no walls between it and the player, but I've probably missed lots; this will require a lot of play testing before its ready for non-developers. viewwindow() now has two calls to losight(), the second one determining what squares would be visible if all translucent walls were made transparent, so that there's a quick way to see if there's any translucent walls between the player and a square. This second call to losight() doesn't cause any noticeable slowdown for me, but it might on an older system. Other than viewwindow() making a second call to losight(), there shouldn't be any changes to game-play or game-logic if there aren't any translucent walls around. The wizard blinking command (&b) has been changed so that it ignores all normal restrictions except for needing to see the target square and not landing on monsters; if the player lands on a wall square it's changed to floor. Wizard blinking also doesn't increase magical contamination. r6780@kamatari (orig r2146): zelgadis | 2007-09-19 04:55:18 -0400 This change moves the logic for when a level or branch prohibits teleport control from the C++ code into the vault .des files. This is done with the additions of two things: * Changeable, persistent per-level and per-branch flags which affect game play. * Dungeon events for the killing of monsters, picking up of objects and changing of features. The current level and branch flags are for teleport control prevention, making a level unmappable (like the Abyss or a Labyrinth), and preventing magic mapping from working (like the Abyss or a Labyrinth). Some related changes: * The new .des header KMASK allows for dungeon grid masks like no_monster_gen to be applied to specific symbols rather than the entire vault. * If the wizard mapping command (&{) is used in a place which is unmappable, it will ask if you wish to force the area to be mappable (so you can see what an entire Labyrinth or Abyss level looks like without having to hack the source). * A new wizard-mode level-map command, 'T', will teleport the player to wherever the cursor is pointing. r6781@kamatari (orig r2147): j-p-e-g | 2007-09-19 13:58:35 -0400 Highlighting species in aptitudes list, and added the "." command to help screen. I've added some "\n" to make it look nice (on Windows) but it's looking differently on Linux. *shrugs* r6783@kamatari (orig r2149): j-p-e-g | 2007-09-19 18:54:50 -0400 Fixing a number of bugs on throwing nets, so it's all in all a net improvement. ;) I'm reusing item.plus2 as a marker for trapping monsters or not. AFAIK, missiles don't need those, and it makes stacking so much easier. Gladiators start with Throwing skill 1, except for Kobolds (don't get a net) who get an additional level at Dodging. r6784@kamatari (orig r2150): zelgadis | 2007-09-19 18:56:46 -0400 Input buffer needs to be flushed if the first iteration of command repetition is canceled. Repetitions of searching and go-nowhere weren't being interrupted. Wasn't generating activity interrupts for AI_FULL_MP and AI_FULL_HP. r6786@kamatari (orig r2152): haranp | 2007-09-19 19:28:26 -0400 Fix for memory corruption when reading savefiles. r6787@kamatari (orig r2153): zelgadis | 2007-09-19 20:02:32 -0400 Fixed =/== typo. r6788@kamatari (orig r2154): zelgadis | 2007-09-20 00:18:24 -0400 Mutations 'green marks' was being miscounted as mutation #64, rather than the correct #65, leading to there being the wrong number of entries in the mutation tables. r6789@kamatari (orig r2155): zelgadis | 2007-09-20 00:26:28 -0400 A number of "gain mutation" debug command improvements: * The name given is now a simple name (fast, clever, etc) matching the enumeration name, rather than the description of when you first get the mutation. * The name can be "any" to get a random mutation, or "xom" to get a random Xom mutation. * If the player has the resist mutation mutation, the command asks if you want to get rid of it. * You can force a mutation to happen, so that it will happen in spite of mutation resistance mutation, mutation resistance amulet, already being covered in too many scales, and so on. Other wizard command improvements: * The dismiss all (genocide) command can now take a regex of the monsters to dismiss, rather than dismissing all of them. * The heal and super-heal wizard commands now never make you engorged. r6791@kamatari (orig r2157): zelgadis | 2007-09-20 01:47:52 -0400 Was clearing the list of remembered get_input_line() lines at the wrong time. r6792@kamatari (orig r2158): zelgadis | 2007-09-20 02:27:28 -0400 Inscribing an item with "=p" will, for Nemelexites, prevent just that item from being sacrificed; "!p" still prevents an entire stack of items from being sacrificed, and the prompt message for "!p" is now clearer on that. Also, explictly marked stashes are never sacrificed by Nemelxites. r6794@kamatari (orig r2160): zelgadis | 2007-09-20 03:46:53 -0400 more() should be skipped during any type of key replay, not just command repetition. r6795@kamatari (orig r2161): haranp | 2007-09-20 06:11:58 -0400 Delays now give their startup messages when they start, rather than when they are pushed onto the queue. Fixes 1797499. r6798@kamatari (orig r2164): j-p-e-g | 2007-09-20 07:51:22 -0400 Previous commit applied to trunk: * cleanup of weird_colour() * hooves mutation one level only * fixes for vampire food level checks * Xom gifts interrupt travel r6799@kamatari (orig r2165): j-p-e-g | 2007-09-20 12:58:33 -0400 Cleanup of manual (patches 1798238, 1798239) and of claw mutation as well as the breathe poison one (patches 1795977, 1797293). All patches by dolorous. r6801@kamatari (orig r2167): zelgadis | 2007-09-20 20:27:59 -0400 No longer id ego weapons of monsters simply because the monster is already wielding them. However, if a monster wields or unwields a weapon and it gives a message like "The dagger is surrounded by flames!", that still id's the ego. Also, wand zaps by visible monster now update the wand's zap count. r6807@kamatari (orig r2169): zelgadis | 2007-09-20 22:24:18 -0400 Oops, my "dismiss monsters by regex" change didn't take into account that the "debug atuoexplore" debug command uses the dismiss-monsters command. r6839@kamatari (orig r2170): zelgadis | 2007-09-21 01:11:51 -0400 Can now search the description database by name (keyword) with '?/'. Not adding to 0.3-branch yet in case it needs some tweaks. r6840@kamatari (orig r2171): zelgadis | 2007-09-21 05:18:24 -0400 Oops, '\' is the glyph for staves on Windows. r6841@kamatari (orig r2172): j-p-e-g | 2007-09-21 05:21:44 -0400 Add past tense to visited branches output, and a few corrections. r6843@kamatari (orig r2174): j-p-e-g | 2007-09-21 11:16:15 -0400 Fixed note taking (NOTE_HP_CHANGE) for invisible monsters (bug 1786776) and in general (wasn't working). Also tweaked tutorial message on burning spellbooks (Bug 1799350). r6846@kamatari (orig r2177): zelgadis | 2007-09-21 22:48:12 -0400 If there are multiple matches to the "?/" describe command, then they will be displayed in a menu, which the user can select from. Menu entries for monsters will be given the same color as the monster, with the monster's symbol added to the end of the string. Entering a single character as input to the "?/" describe command lists all monsters with that display symbol. Monsters sharing the same display symbol can now have the same string appended or prepended to their description (implemented to make the "?/" command have to deal with less special cases). Currently only used by nagas with __N_suffix. Has the side-effect advantage that the naga subspicies description and the "attractive/repulsive" description goes before the big block of quoted text, rather than after it. r6847@kamatari (orig r2178): zelgadis | 2007-09-21 23:12:44 -0400 Oops, forgot about database case insensitivity again. r6848@kamatari (orig r2179): zelgadis | 2007-09-22 05:21:32 -0400 Added additional optional parameter to item_def::name(), ignore_flags, which will cause the name to be constructed as if those item flags had been unset. Give an auxiliary cause of death for a stat going below 1. (Death by stat loss is already pretty rare, and death by stat loss with confusion as to what caused the stat loss must be *really* rare, but still, if you were confused about what caused the stat loss that lead to death, that'd be pretty frustrating) ouch() is now called from within modify_stat() and lose_stat() right after the stat is lowered, rather than when the stat is updated on the screen. This incidentally fixes the minor annoyance of saying "no" to stat loss death in wizard mode, only to be asked if you want to die every time the screen is updated until you fix having a non-positive stat. r6849@kamatari (orig r2180): dshaligram | 2007-09-22 10:25:42 -0400 Implemented SQLite fronts for dbm_firstkey and dbm_nextkey to fix trunk build on Windows. r6850@kamatari (orig r2181): dshaligram | 2007-09-22 10:31:36 -0400 Fix MinGW complaining about possible uninitialised variables. r6851@kamatari (orig r2182): dshaligram | 2007-09-22 11:34:04 -0400 Removed overly spammy visual messages (specifically, monsters lashing their tails). Fixed butcher weapon-swap crash (David). r6853@kamatari (orig r2184): zelgadis | 2007-09-23 03:15:24 -0400 Nemelex gift deck changes: * Changed pure deck distribution formula. All consumable items go towards decks of wonder, books and jewellery go towards decks of dungeon, and corpses are now valued proportionally to their weight, rather than every corpse being of equal value. * The chance of getting rare and legendary decks increases with piety. * The card countdown (which must be 0 to get a new gift deck) sometimes decreases when drawing a card, with the chance increasing with the number of piety points gained from drawing the card. All of this is very tentative and subject to change upon the results of play testing. Also, some more optional debugging messages have been added, which can be activated in a more fine grained manner than DEBUG_DIAGNOSTICS (DEBUG_CARDS, DEBUG_GIFTS, etc). r6854@kamatari (orig r2185): zelgadis | 2007-09-24 01:04:58 -0400 ?/ now asks if you want to describe a monster, spell, or feature, and filters out matches if they aren't of the desired type. If there's more than one match, after selecting a match to look at, exiting from the description will return you to the menu, rather than to the dungeon. If you've asked for monsters, you can toggle sorting of the menu between alphabetical and by aproximated monster toughness (this probably still needs some work, since it seems to say that ordinary worms are tougher than brain worms). Only the monster symbol is coloured when showing a menu of monsters to describe. r6855@kamatari (orig r2186): zelgadis | 2007-09-24 06:19:40 -0400 Added some missing cases to various mons_foo_level() functions. Added mon-pick related function mons_global_level(), which returns a reasonable level value for monsters independant of the place of the monster, primarily useful for comparing the levels of two monsters which might never show up in the same place (in which case mons_level() is useless). r6856@kamatari (orig r2187): j-p-e-g | 2007-09-24 10:11:22 -0400 A few simple fixes. * Add zero level invocations to Trog and Ely's religion screens * Demonspawn get 0-2 additional damage for demonic weapons (similar to MD + dwarven weapons) * Darts and Throwing don't crosstrain anymore * Don't offer "inscribe items" text during tutorial. * Cleanup and minor fixes of tutorial r6858@kamatari (orig r2189): nlanza | 2007-09-24 12:55:50 -0400 Clean up a printf format string to placate the extra-special pickiness of gcc 4 in newer OS X. r6859@kamatari (orig r2190): nlanza | 2007-09-24 12:57:57 -0400 Add state.cc to the Xcode build and massage the compile settings to deal with the fact that yacc on 10.5 emits code that the compiler's default settings don't like -- signed/unsigned comparisons, specifically. r6862@kamatari (orig r2193): dshaligram | 2007-09-24 15:15:51 -0400 Beogh butcher fix for trunk. r6863@kamatari (orig r2194): dshaligram | 2007-09-24 15:25:34 -0400 Refix ?/ error message format to handle 64-bit and 32-bit size_t without compiler warning noises. r6864@kamatari (orig r2195): dshaligram | 2007-09-24 16:08:10 -0400 Added DGL_STARTUP_PREFS_BY_NAME to store new character options by username for dgamelaunch. Dropped ice statue hitpoints to compensate for their immunity to disintegration. r6866@kamatari (orig r2197): dshaligram | 2007-09-24 16:14:30 -0400 Fixed combat messages for out of sight draining attacks (jarpiain). r6868@kamatari (orig r2199): zelgadis | 2007-09-25 04:00:46 -0400 Make formatted_string::parse_string() split up the string into chunks of 999 characters or less so that formatted_string::cprintf()'s character buffer doesn't overflow. r6869@kamatari (orig r2200): zelgadis | 2007-09-25 04:25:40 -0400 Slight improvement to repeating mutation command. r6871@kamatari (orig r2202): zelgadis | 2007-09-25 07:07:01 -0400 Prevent Crawl from going into an infinite loop during newgame setup if an incompatible class/race combination is specified in the init file. r6873@kamatari (orig r2204): dshaligram | 2007-09-25 14:12:02 -0400 * Fixed Vault:8 level being generated with no rune (cbus). * Dropped odds of statue vault. * Take note of messages received in dgamelaunch chat. * crawl -vscores, etc. should not attempt to create save/morgue directories (Marc). * Changed wording of "Foo wielding bar comes into view" to "Foo comes into view. It is wielding bar.". * Suppress curse status display of monster items. * TSO worshippers are no longer warned when stabbing monsters if TSO doesn't object to stabbing those monsters. * Wand zap status is now {zapped: N} instead of {zapped N times} to reduce verbosity. r6875@kamatari (orig r2206): haranp | 2007-09-25 19:28:04 -0400 Restore original correct text to MR artifacts. r6876@kamatari (orig r2207): dshaligram | 2007-09-26 07:27:16 -0400 Removed hard tabs. Corrected sling bullet description. Targeting forward wrap-around was broken, fixed. Dropped damage bonus for kenku clawed-kick. Don't show {tried} for equipped items. Removed Elyvilon's protection from high-damage hits even when not praying. r6880@kamatari (orig r2211): dshaligram | 2007-09-26 07:54:26 -0400 Minivault balancer fix for trunk. r6881@kamatari (orig r2212): dshaligram | 2007-09-26 08:25:04 -0400 Fixed missile preservation numbers for sling bullets and javelins. r6882@kamatari (orig r2213): dshaligram | 2007-09-26 08:36:31 -0400 All vaults are now "uniq" (one-use-per-game) by default. Vaults that want to be reused must be tagged "allow_dup". r6884@kamatari (orig r2215): dshaligram | 2007-09-26 09:50:10 -0400 Dropped bolt of inaccuracy accuracy. It's probably still be too accurate, given the nerf to monster EV vs beams. Bumped inaccuracy to level 3. r6886@kamatari (orig r2217): dshaligram | 2007-09-26 15:43:53 -0400 Adjusted piety costs for Beogh smiting and Okawaru Haste (cbus/syllogism). Reduced monster spawn ramp-up in Vestibule. r6888@kamatari (orig r2219): dshaligram | 2007-09-26 16:33:14 -0400 Fixed Beogh being angered by killing a non-orc friendly with a beam (cbus). r6890@kamatari (orig r2221): j-p-e-g | 2007-09-26 17:45:01 -0400 Fix wording for translucent rock walls (1798932). Change freshness calculation for chunk sorting: all chunks now sorted oldest to freshest, listing rotten last for non-Saprovores. Small comment fixes. r6892@kamatari (orig r2223): zelgadis | 2007-09-26 20:26:01 -0400 Allow Pandemonium lesser demon vaults and labyrinth entrances to be duplicated within a game. r6894@kamatari (orig r2225): dshaligram | 2007-09-27 02:51:32 -0400 Added allow_dup to all bazaar and lab maps. r6896@kamatari (orig r2227): dshaligram | 2007-09-27 06:59:19 -0400 Bumped piety cost for brothers-in-arms and greater healing. Added COLOUR: directive to maps to allow custom colouring of features by glyph, and tweaked the strawberry fields variants to use it. r6897@kamatari (orig r2228): dshaligram | 2007-09-27 07:10:13 -0400 Updated level-design.txt for COLOUR. Fixed map_lines::clear() not cleaning colour overlay. r6898@kamatari (orig r2229): dshaligram | 2007-09-27 07:12:22 -0400 Updated canned level-compiler. r6900@kamatari (orig r2231): dshaligram | 2007-09-27 08:33:29 -0400 remember_name was broken, fixed. Colour overlays were not being rotated/mirrored, fixed. r6902@kamatari (orig r2233): dshaligram | 2007-09-28 03:58:50 -0400 Fixed issues with substring matches of item names (spears being generated for pears) in maps (David). The change also means that item names have to be specified in full in map definitions. r6903@kamatari (orig r2234): zelgadis | 2007-09-28 04:18:33 -0400 Beogh won't smite the player if his idol was destroyed by a monster. r6904@kamatari (orig r2235): zelgadis | 2007-09-28 04:27:29 -0400 crawl_state now keeps track of whether or not the current code is being executed because of a god's actions, and if so which god (with "actions" not including god-supplied invocations). Currently only used to prevent Xom from being amused/stimulated by his own actions. r6905@kamatari (orig r2236): j-p-e-g | 2007-09-28 07:59:18 -0400 Adding allow_dup tags to several vaults. (David) r6908@kamatari (orig r2239): j-p-e-g | 2007-09-28 09:01:04 -0400 Whoops, I'd forgotten to change something in a minivault. r6910@kamatari (orig r2241): dshaligram | 2007-09-28 09:58:05 -0400 Added a sanity check for followers to prevent frozen monsters (cbus). Still need to figure out why monsters are getting marked as followers when they shouldn't. r6912@kamatari (orig r2243): dshaligram | 2007-09-28 10:15:06 -0400 Reintroduced Slime:6 royal-jelly-death marker. [1804113] Corrected spell order in Practical Magic. r6914@kamatari (orig r2245): dshaligram | 2007-09-28 14:43:36 -0400 Better messages for explore finding multiple non-stacking items (say "two leather armours" instead of "leather armour and leather armour"). r6916@kamatari (orig r2247): dshaligram | 2007-09-28 15:42:10 -0400 [1800818] Fixed broken follower tagging for bazaars. r6918@kamatari (orig r2249): j-p-e-g | 2007-09-28 18:40:28 -0400 Updating description for "freshness" sorting option. r6920@kamatari (orig r2251): dshaligram | 2007-09-28 18:58:41 -0400 Fixed possible crash when placing monster bands. Also reworked the mapgen stats to give more detailed information. r6922@kamatari (orig r2253): j-p-e-g | 2007-09-29 08:40:55 -0400 Berserking monsters are now noisy with a noise level that befits their shout_type. r6924@kamatari (orig r2255): j-p-e-g | 2007-09-29 09:33:37 -0400 Changing the piety gain messages to be threefold for no piety, little piety (1) and lots of piety (> 1). Currently, piety is raised by at most 1 at a point so the last one is currently unused. Eventually, we'll want to include that one, though. (Although I've got trouble imagining a piety gain greater than, say, 2 or 3.) r6937@kamatari (orig r2256): zelgadis | 2007-09-30 01:56:13 -0400 This commit breaks save file compatability. Lots of new things that amuse/stimulate Xom, and a few things which don't amuse him as much anymore. Among the new things is a corpse turning into a skeleton while butchering it; if this is too harsh to do just for Xom's amusement (previously turning into a skeleton while butchering was an ignored case and still produced chunks of flesh) it can be changed back. Also, if a Xom worshiper draws the Blank card, Xom makes it act like a Xom card, since a plain old Blank card is boring. Keep track of which branch the Orb is in, if the player isn't carrying it. Keep track of how/why the player ended up in a particular level type (Abyss, Pan, etc). Changed most "a distortion effect" cause strings for distortion caused tranlsocation miscast effects to something more specific. Added new wizard commands 'C' to curse or uncruse an item, and 'Ctrl-A' to re-generate the Abyss. r6938@kamatari (orig r2257): zelgadis | 2007-09-30 02:50:01 -0400 A few improvements to banished() and entry cause tracking. r6939@kamatari (orig r2258): j-p-e-g | 2007-09-30 09:11:01 -0400 Add redraw_hp to the "Elixir" card. Hide Xom piety on status screen. r6941@kamatari (orig r2260): j-p-e-g | 2007-09-30 09:18:19 -0400 Monster centaurs now sometimes (rarely) wear barding. The chances are lower even than for naga as I believe that centaurs occur more frequently than naga. As I've been completely disregarding the Snake Pit I could be entirely wrong. r6943@kamatari (orig r2262): j-p-e-g | 2007-09-30 11:45:57 -0400 Trog's bookburning invocation only costs a turn and food if it's actually successful. r6944@kamatari (orig r2263): j-p-e-g | 2007-09-30 11:53:09 -0400 Introducing shortcut for searching the current level as requested in FR 1801705. Also adding feedback when auto-travel fails to kick in. And trying to get out of a net no longer stops travel, only being caught in one does (FR 1800821). r6947@kamatari (orig r2266): dshaligram | 2007-09-30 13:18:31 -0400 Fixed regex escapes for "." stash search. r6956@kamatari (orig r2268): dshaligram | 2007-09-30 14:37:21 -0400 [1804879] Fixed bad time-elapsed events being generated for new levels, also fixes labyrinths/bazaars not being generated correctly. r6959@kamatari (orig r2271): zelgadis | 2007-09-30 20:09:26 -0400 The Shuffle card now kills the player if any stats are lowered below 1. r6960@kamatari (orig r2272): zelgadis | 2007-10-01 00:05:20 -0400 Fix wizard mode cheating-death from losing experience or levels when level 1, so you won't end up as a level 0 character with 0 HP. r6961@kamatari (orig r2273): zelgadis | 2007-10-01 00:29:44 -0400 Better interface for creating runes and decks. r6962@kamatari (orig r2274): zelgadis | 2007-10-01 02:01:58 -0400 Tweak command can now accept hexadecimal values. r6963@kamatari (orig r2275): dshaligram | 2007-10-01 02:09:00 -0400 Fixed broken 64-bit compile. r6964@kamatari (orig r2276): zelgadis | 2007-10-01 02:50:07 -0400 Some paranoia checks for buggy decks when evoking or stacking them. If the deck has no cards left yet still exists, the deck is destroyed and Nemelexites are awarded a brownie point for using up a deck. If a stacked deck has holes in it, the holes are removed. If a stacked deck has buggy cards in it, they are discarded. If a deck had problems with it, the user is asked if s/he is sure about using the (now fixed) deck, and no turns are used if the answer is "no". r6965@kamatari (orig r2277): zelgadis | 2007-10-01 03:27:21 -0400 Oops, had some code placed after a "return" statement; why didn't the compiler catch that? r6966@kamatari (orig r2278): j-p-e-g | 2007-10-01 03:51:02 -0400 Overhaul trapping net escape functions. With the help of several factors (such as size, wielded weapon or stats) the game decides whether you should try to destroy the net to come free, or try to slip out of it. The same calculation also influences how long this will take. r6968@kamatari (orig r2280): dshaligram | 2007-10-01 04:50:12 -0400 Restore vampiric healing for killing blows (jarpiain). r6970@kamatari (orig r2282): dshaligram | 2007-10-01 06:29:29 -0400 [1804917] Berserkers no longer get Polearms skill for their throwing spears, since the spears use only Throwing. r6971@kamatari (orig r2283): dshaligram | 2007-10-01 06:44:11 -0400 Fixed vampiric healing on death using raw damage instead of actual damage, which produced super-healing for stabbing (jarpiain). r6973@kamatari (orig r2285): zelgadis | 2007-10-01 08:06:58 -0400 The player now dies if the Focus card causes any stat to go below 1. r6974@kamatari (orig r2286): zelgadis | 2007-10-01 08:31:37 -0400 Oops, check_buggy_deck() was itself buggy; fixed. Also, fixed the deck stacking interface so that all available cards are always visible, rather than sometimes being split across a '-more-' prompt. r6975@kamatari (orig r2287): dshaligram | 2007-10-01 14:27:31 -0400 Wanderers could start with items equipped in the wrong slots, fixed. r6976@kamatari (orig r2288): dshaligram | 2007-10-01 15:18:06 -0400 Fixed bad species name (eg: deep elves with the bows title) in dump because of reuse of static buffers (Iaido). r6978@kamatari (orig r2290): dshaligram | 2007-10-01 17:14:06 -0400 Restored 0.2's character combinations, fixed crash when killing a monster using Pain. r6991@kamatari (orig r2293): zelgadis | 2007-10-02 02:52:08 -0400 Added floor_special and floor_reserved to dngn_feature_names[], to make the array match up with the enums. Don't describe the weapon with which an unseen monster is attacking. Added methods can_see() and visible_to() to the actor, player and monster classes, which take care of calling mons_player_visible(), player_monster_visible(), mons_monster_visible() and mons_near(). Re-arranged the first 12 dungeon_feature_type enumerations so that similar features are contiguous (i.e., closed door and secret door are next to each other), and added DNGN_MAXOPAQUE (one less than DNGN_MINSEE), DNGN_MINWALL and DNGN_MAXWALL. r6992@kamatari (orig r2294): zelgadis | 2007-10-02 03:25:05 -0400 Xom is stimulated/amused if a harmful beam ricochets and hits the originator of the beam. r6993@kamatari (orig r2295): dshaligram | 2007-10-02 06:57:45 -0400 Fixed segfault in explore discovery reporting (syllogism). r6995@kamatari (orig r2297): dshaligram | 2007-10-02 07:15:12 -0400 Fixed elven fighters getting Armour skill instead of Dodging. Fixed deep elf bow aptitude (Anym). r6997@kamatari (orig r2299): dshaligram | 2007-10-02 07:38:37 -0400 Replaced inc_god_acting/dec_god_acting pairing with god_acting objects. r6998@kamatari (orig r2300): zelgadis | 2007-10-02 18:40:40 -0400 Made Xom be smarter about being amused at losing/missing runes, and made Xom also be amused at runes being destroyed. Related changes: * Keep track of which items have ever been held by the player with ISFLAG_BEEN_IN_INV. * item_was_destroyed() is called when an item is destroyed (as in dropped in lava, not destroy_item() being called), and item_was_lost() is called if the item was lost (i.e., being left behind in the Abyss). * Keeps track of the number of runes that the character has collected, and how many have been left in the Halls of Zot. r6999@kamatari (orig r2301): zelgadis | 2007-10-02 21:39:08 -0400 Added svn properties svn:keywords and svn:eol-style to files which were missing them. r7000@kamatari (orig r2302): zelgadis | 2007-10-03 00:09:08 -0400 Runes and the Orb now have elemental (flickering/shifting) colours. r7001@kamatari (orig r2303): zelgadis | 2007-10-03 00:19:40 -0400 Don't assert-fail due to a buggy rune being in the player's inventory when constructing a score-file entry, since checks for buggy runes are done elsewhere in the game. r7002@kamatari (orig r2304): dshaligram | 2007-10-03 02:40:26 -0400 Updated colour names in initfile.cc for the new elemental colours. r7003@kamatari (orig r2305): dshaligram | 2007-10-03 02:43:35 -0400 Make element_cols static. r7006@kamatari (orig r2308): dshaligram | 2007-10-03 03:30:57 -0400 Corrected INSTALL. r7008@kamatari (orig r2310): j-p-e-g | 2007-10-03 15:20:02 -0400 Outsourcing weapon noises to speak.txt, and adding more messages. r7009@kamatari (orig r2311): dshaligram | 2007-10-03 16:21:40 -0400 Cleaned up newgame item creation code, fixed MuFi starting with bad items as shields (cbus), and corrected Rupert's description. r7010@kamatari (orig r2312): dshaligram | 2007-10-03 16:25:34 -0400 Fixed equipment slot assignment check. r7012@kamatari (orig r2314): zelgadis | 2007-10-04 01:05:42 -0400 Moved all of the bazaar specific logic/code to dat/bazaar (or turned the code into Lua utility functions which can be reused by things other than bazaars). Related changes: * Portal vault entrances now work if they have destinations ("dst" property) besides "bazaar" (though it still causes an assert if no matchng maps for the destination can be found). * The floor and rock colour for a level are generated once and then stored in the save file, rather than being constantly regenerated (which means that bazaar floor colours are now truly random, rather than being tied to the depth of the bazaar entrance). * The floor and rock colour for a portal vault (or for any level containing any vault) can be set with ROCKCOL and FLOORCOL (which currently only accepts a single colour, unlike COLOUR); there are also Lua functions for querying and setting the colours. * Each portal vault level_type_name can have an associated Lua callback which is called when level generation is complete; it can be used for things like stair fixup. I also moved the Halls of Zot rock/floor colour special casing to the dat/zot.des file, since it was easy once ROCKCOL and FLOORCOL had been implemented. r7013@kamatari (orig r2315): zelgadis | 2007-10-04 01:07:33 -0400 ROCKCOL and FLOORCOL changes for the prebuilt parser/lexer. r7014@kamatari (orig r2316): zelgadis | 2007-10-04 02:01:30 -0400 Quiet a compile warning. r7015@kamatari (orig r2317): zelgadis | 2007-10-04 02:36:16 -0400 Wizard commands should never use up a turn. r7016@kamatari (orig r2318): dshaligram | 2007-10-04 03:01:16 -0400 Makhleb accepts undead and demon kills once again, matching b26 behaviour (Iaido). r7017@kamatari (orig r2319): dshaligram | 2007-10-04 03:20:11 -0400 [1804502] Fixed undead pretending to resist dispel undead. r7019@kamatari (orig r2321): zelgadis | 2007-10-04 04:53:33 -0400 Lots more keywords, plus hiliting for numbers, ranges, weights and slashes. r7020@kamatari (orig r2322): dshaligram | 2007-10-04 06:28:54 -0400 Unicode support tweak: always set locale to what's specified in UNICODE_LOCALE, defaulting to en_US.UTF-8. r7022@kamatari (orig r2324): j-p-e-g | 2007-10-04 08:52:55 -0400 Another cleanup of dungeon features. Adding general markers for first branch/last branch and first altar/last altar that should hopefully make adding new ones easier. r7023@kamatari (orig r2325): j-p-e-g | 2007-10-04 08:58:23 -0400 Add documentation for weapon noises and update comments. Also update information about Throwing crosstraining. r7028@kamatari (orig r2328): zelgadis | 2007-10-05 02:10:49 -0400 Shaft traps (trap doors) [1792195] and level annotation [1769009] added, with the shaft traps changed as per comments on SF; shafts aren't randomly generated yet, so this doesn't change gameplay. Changed DNGN_TRAP_III to DNGN_TRAP_NATURAL, of which trap type the shaft traps are the only current member. r7029@kamatari (orig r2329): zelgadis | 2007-10-05 03:05:22 -0400 Oops, was calling dgn_set_floor_colours() in wrong place, leading to some levels getting the wrong colours. Also, make dgn_set_colours_from_monsters() be paranoid about improprely set up env.mons_alloc[]. r7030@kamatari (orig r2330): zelgadis | 2007-10-05 03:31:05 -0400 init_pandemonium() needs to re-do dgn_set_colours_from_monsters(), since it is called after level generation is complete. r7031@kamatari (orig r2331): zelgadis | 2007-10-05 04:27:09 -0400 Randomly generate shaft traps. r7032@kamatari (orig r2332): dshaligram | 2007-10-05 04:42:04 -0400 Corrected grammar on a couple of Singing Sword messages, fixed crash when placing vaults with &L (bobbens). r7033@kamatari (orig r2333): dshaligram | 2007-10-05 04:53:32 -0400 Removed unnecessary conditional that may cause issues building Lua. r7034@kamatari (orig r2334): dshaligram | 2007-10-05 05:10:34 -0400 Fixed segfault when using &Z (bobbens). r7035@kamatari (orig r2335): dshaligram | 2007-10-05 06:58:57 -0400 Refix &Z crash-fix, which didn't actually fix the crash. :P r7037@kamatari (orig r2337): zelgadis | 2007-10-05 18:20:15 -0400 Remove trap-door-like logic from shaft traps, since shafts are just supposed to be holes hidden by debris. r7038@kamatari (orig r2338): nlanza | 2007-10-05 23:32:13 -0400 Add xom.h to the project file so everything's listed. r7039@kamatari (orig r2339): nlanza | 2007-10-05 23:33:03 -0400 Uninitialized variable fixes. r7040@kamatari (orig r2340): dshaligram | 2007-10-06 07:47:47 -0400 Fixed off-by-one error when complaining about oversized maps (bobbens). r7041@kamatari (orig r2341): dshaligram | 2007-10-06 09:04:13 -0400 First steps toward removing the need for 6-deep rock-wall padding around dungeon maps. This is likely to be buggy for a while. r7042@kamatari (orig r2342): dshaligram | 2007-10-06 14:42:21 -0400 Added new maps by bobbens, moved Crypt and Tomb maps to crypt.des. r7044@kamatari (orig r2344): dshaligram | 2007-10-06 16:35:15 -0400 Discarding unused .des files. r7046@kamatari (orig r2346): dshaligram | 2007-10-06 17:30:10 -0400 Assume KFEAT: ? = floor if we've seen a KITEM: or KMONS: for the same glyph. r7047@kamatari (orig r2347): dshaligram | 2007-10-06 17:32:35 -0400 Updated Vault:8 map for new Kfoo behaviour. r7048@kamatari (orig r2348): dshaligram | 2007-10-06 17:41:33 -0400 Fixed bad hp/mp gain calculation when gaining multiple experience levels with one kill (jarpiain). r7050@kamatari (orig r2350): dshaligram | 2007-10-07 06:37:49 -0400 Adjust monster generation difficulty to be closer to 0.2 averages, but with more variance. Early monster difficulty should be less brutal now. r7052@kamatari (orig r2352): dshaligram | 2007-10-07 07:32:10 -0400 Increased max monsters to 350, breaks saves, may be buggy. Incremented save major version. r7053@kamatari (orig r2353): dshaligram | 2007-10-07 07:53:26 -0400 Allow overriding monster colours in map specs using col:<newcolour>. r7054@kamatari (orig r2354): dshaligram | 2007-10-07 07:58:59 -0400 Fixed bad comparison with string literal (bobbens). r7055@kamatari (orig r2355): dshaligram | 2007-10-07 09:32:22 -0400 Clear dropped+thrown flags on corpse when converting it to chunks (V-Napkin). Also announce rod identification when it self-ids [1808821]. r7057@kamatari (orig r2357): dshaligram | 2007-10-07 09:41:42 -0400 [1808631] PCs in statue-form should not be able to scramble out of deep water. r7058@kamatari (orig r2358): dshaligram | 2007-10-07 09:45:05 -0400 [1808624] Dropping part of a stack of wielded items should not unwield the whole stack. r7059@kamatari (orig r2359): dshaligram | 2007-10-07 09:51:03 -0400 [1808560] Staff of power unwield was not removing max mp bonus, fixed. r7060@kamatari (orig r2360): dshaligram | 2007-10-07 09:55:48 -0400 [1808372] Clip menu item labels at terminal width. r7061@kamatari (orig r2361): dshaligram | 2007-10-07 10:07:44 -0400 Fixed bad magic points calculation when levelling up with a worn item of magical power (V-Napkin). r7062@kamatari (orig r2362): dshaligram | 2007-10-07 10:12:54 -0400 [1808952] Smiting monsters did not wake them up, fixed. r7064@kamatari (orig r2364): dshaligram | 2007-10-07 10:43:42 -0400 [1808964] Holy Word wakes and annoys affected monsters. r7065@kamatari (orig r2365): dshaligram | 2007-10-07 10:55:57 -0400 [1808968] Using the weapons of the demon lords in combat angers TSO and Zin. r7067@kamatari (orig r2367): dshaligram | 2007-10-07 12:16:53 -0400 Unicode makefile tweak for trunk. r7069@kamatari (orig r2368): zelgadis | 2007-10-07 21:15:23 -0400 Ran into a bug where searching backwards through inventory for a free slot which won't leave gaps (in find_free_slot()) would fail if the inventory was empty; fixed bug by making find_free_slot() retry with forwards search if backwards search failed. I can't reproduce the bug, but the fix doesn't seem to cause any problems when there isn't a bug. r7070@kamatari (orig r2369): zelgadis | 2007-10-08 00:25:58 -0400 Make mpr_comma_separated_list() end the message with a period. r7071@kamatari (orig r2370): zelgadis | 2007-10-08 01:55:47 -0400 Added class CrawlHashTable, a savable/loadable string-keyed associative array with heterogeneous values, capable of holding booleans, bytes, shorts, longs, floats, string, coordinates (coord_def), items (item_def) and nested hash tables. A table can be made to be homogeneous by giving it a value type, which causes dynamic type checking to be performed. The same type checking can be performed for individual member values of a heterogeneous table by setting a flag on that value. A flag can also be set on an individual member value to prevent its value from being changed. CrawlHashTable is currently only used for the props field of the item_def struct (though it could easily be added elsewhere), and is only being used by decks. The deck structure has been changed so that deck.plus is the original number of cards in the deck, deck.plus2 is either the number of cards used or the number of cards left, and deck.special hold the deck's rarity. The cards themselves are selected at deck creation time and stored in the nested hash table deck.props["cards"]. The Nemelex "Peek Deck" ability has been changed to identify the deck, draw three cards from it, show them to the user, and shuffle them back into the deck (with special cases for decks containing only one or two cards). A fourth Nemelex ability, "Mark Deck", has been added, which picks four cards from the deck, marks them, and then shuffles them back into the deck, creating a deck with a mixture of marked and unmarked cards. r7072@kamatari (orig r2371): dshaligram | 2007-10-08 07:10:52 -0400 Fixed map colours being inherited by unrelated maps during compilation. Pause after reporting an error for dgamelaunch so that the dgl menu does not hide the error message. r7074@kamatari (orig r2373): dshaligram | 2007-10-08 07:58:07 -0400 Make Escape cancel out of menu and prompt for the ability and spellcasting menus (Marc). r7077@kamatari (orig r2375): dshaligram | 2007-10-08 08:28:20 -0400 Fixed ENCH_SLEEPY persisting for too long with ensorcelled hibernation. r7078@kamatari (orig r2376): dshaligram | 2007-10-08 08:34:40 -0400 Removed unnecessary ench_sleepy duration. r7079@kamatari (orig r2377): dshaligram | 2007-10-08 10:01:16 -0400 Ghosts can use ensorcelled hibernation. Breaks saves, needs some work on PC sleep and wake-up correctness. r7080@kamatari (orig r2378): dshaligram | 2007-10-08 10:06:54 -0400 s/cannot_move/cannot_act/ for clarity. r7081@kamatari (orig r2379): dshaligram | 2007-10-08 13:22:04 -0400 Fixed crash when summoned creature is killed by trap (Iaido) - monsters should not trigger traps on creation, only when moving onto a square. Upped ammo preservation chances for javelins (Chilliwack). r7083@kamatari (orig r2381): dshaligram | 2007-10-08 13:47:17 -0400 Re-enable ghosts in Labyrinths. r7084@kamatari (orig r2382): dshaligram | 2007-10-08 14:18:10 -0400 Adjust piety costs for various god powers. r7086@kamatari (orig r2384): j-p-e-g | 2007-10-08 15:26:19 -0400 Applying dolorous' latest patch (1806451), mostly correcting typos in the comments and changing Xom stimulation from 256 to 255 (as the function apparently cannot handle that). r7087@kamatari (orig r2385): j-p-e-g | 2007-10-08 15:28:58 -0400 Minor changes to net, one shoving debug information into DEBUG_DIAGNOSTICS compile, another changing net descriptions. r7089@kamatari (orig r2387): dshaligram | 2007-10-08 16:08:53 -0400 Orc knights and warlords can yell battle-cries to make lesser orcs fight better. r7090@kamatari (orig r2388): dshaligram | 2007-10-08 16:22:04 -0400 Orc battle cries respect silence and also boost physical ranged attacks. r7091@kamatari (orig r2389): zelgadis | 2007-10-09 07:39:22 -0400 Added an actual vector version of CrawlHashTable, and removed the code for making a hash table imitate a vector. Since there's now more than just one type of savable/restorable container, hash.cc and hash.h have been renamed to store.cc and store.h ("store" for storage). Destroying/unlinking/deleting an item now clears out the item's props field. r7092@kamatari (orig r2390): dshaligram | 2007-10-09 07:56:58 -0400 Moved orc battle cries to sound channel, increased duration to reduce message spam. r7096@kamatari (orig r2394): j-p-e-g | 2007-10-09 10:59:08 -0400 Allow bargains in bazaars, ranging from 60% to 95%. The value of created items is also increased by a fair bit. I also changed species MR as in the last post of FR 1787813: all Elves get 4, Ogre Mage 5, and Demigods also 4. Someone (Darshan?) will probably want to twiddle with the numbers, at least for the bazaars, so for now, I'll put off committing this into 0.3. r7097@kamatari (orig r2395): j-p-e-g | 2007-10-09 11:04:14 -0400 Make mechanical traps in Orcish Mines and Elven Halls of appropriate racial type. I'd prefer it if there was a chance involved but IMHO a given trap should shoot the same (racial) type of ammo, so this is now always the case in these two branches, for all of needle, arrow, bolt, spear and axe traps. r7098@kamatari (orig r2396): dshaligram | 2007-10-09 12:05:08 -0400 Returning weapon beam path updates for trunk. r7100@kamatari (orig r2398): dshaligram | 2007-10-09 12:40:48 -0400 Branded weapons and armour are now always visibly special. r7102@kamatari (orig r2400): dshaligram | 2007-10-09 14:15:07 -0400 Fixed temple_secret_doors: playing hide-and-seek with the Temple is not good. r7104@kamatari (orig r2402): j-p-e-g | 2007-10-09 17:46:52 -0400 Updating level-design.txt (done by David), mostly spacing changes but also a few content differences, e.g. removing information on tricky.des and adding information on some new features (I think, it's hard to tell what was already in the older version with all this indenting going on). r7106@kamatari (orig r2403): zelgadis | 2007-10-09 23:43:21 -0400 Remember and describe randart properties which have been learned via wearing the randart. Breaks savefile compatibility for saved games containing any randarts. r7107@kamatari (orig r2404): dshaligram | 2007-10-10 02:02:22 -0400 Fix los radius check in can_see(). r7109@kamatari (orig r2406): dshaligram | 2007-10-10 13:39:13 -0400 [1810484] Fixed Lua userdata leak - shouldn't use luaL_checkudata from __gc metamethod. r7110@kamatari (orig r2407): dshaligram | 2007-10-10 13:52:21 -0400 [1809884] Fixed detected_item_colour being clobbered with black. r7111@kamatari (orig r2408): dshaligram | 2007-10-10 13:55:22 -0400 Removed hardcoding in travel colour check. r7113@kamatari (orig r2410): dshaligram | 2007-10-10 14:16:16 -0400 [1809278][1809633] Fixed spotty level badness. r7114@kamatari (orig r2411): dshaligram | 2007-10-10 14:23:53 -0400 Fixed DEPTH for david_defended_altar. r7115@kamatari (orig r2412): dshaligram | 2007-10-10 14:54:31 -0400 New vaults, courtesy bobbens. r7117@kamatari (orig r2414): dshaligram | 2007-10-10 15:14:11 -0400 Fixed all abilities being listed as using piety (jarpiain). r7120@kamatari (orig r2417): zelgadis | 2007-10-10 20:03:04 -0400 Re-roll randarts which have no properties, plus randart jewellery where the properties are redundant or conflicting with respect to the base jewellery type. Also, add known randart properties boolean vector to unrandarts. r7122@kamatari (orig r2419): zelgadis | 2007-10-10 23:23:34 -0400 For unidentified randart jewellery, remember and display obvious-from-wearing effects caused by the base type item as if they were randart properties. Related changes: * Equpping or unequipping a ring of magical power or staff of power will give a message about mana capacity increasing/decreasing. * The randart property RAP_MAGICAL_POWER has been added. randart_wpn_property() doesn't yet give this to any randarts, but the rest of the code for it is in place. r7123@kamatari (orig r2420): zelgadis | 2007-10-11 01:04:23 -0400 Oops, was using UNIQ_LOST_IN_ABYSS wrongly. r7124@kamatari (orig r2421): dshaligram | 2007-10-11 02:23:48 -0400 [1807611] Inventory menus show weight of stack, not one item in stack. r7126@kamatari (orig r2423): dshaligram | 2007-10-11 07:51:53 -0400 [1804499] Fixed acquirement occasionally mauling unrandarts and producing bad items. r7128@kamatari (orig r2425): dshaligram | 2007-10-11 10:33:01 -0400 [1809728] Fixed bug where you could get multiple levels of a single-level mutation (such as torment resistance). r7130@kamatari (orig r2427): dshaligram | 2007-10-11 10:41:10 -0400 [1811182] Fixed help screen hotkeys. r7132@kamatari (orig r2429): dshaligram | 2007-10-11 11:15:23 -0400 [1808191] Fixed truncated imp messages. r7134@kamatari (orig r2431): dshaligram | 2007-10-11 12:43:34 -0400 Fixed minimum distance of lab entrance from exit. r7135@kamatari (orig r2432): dshaligram | 2007-10-11 12:50:19 -0400 Lock before opening .dsc files. r7137@kamatari (orig r2434): dshaligram | 2007-10-11 13:00:28 -0400 Unflasked efreets are now permanent and more likely to be friendly. r7138@kamatari (orig r2435): dshaligram | 2007-10-11 13:12:58 -0400 Upped Beogh weapon damage bonus. r7139@kamatari (orig r2436): dshaligram | 2007-10-11 13:29:03 -0400 Adjusted enchantment durations for paralysis and confusion. r7140@kamatari (orig r2437): dshaligram | 2007-10-11 14:09:32 -0400 Fixed Lugonu's Corruption, remaining cases of truncated monster shouts. r7142@kamatari (orig r2439): dshaligram | 2007-10-11 14:18:15 -0400 Dropped cost of smiting for TSO. r7143@kamatari (orig r2440): dshaligram | 2007-10-11 14:32:53 -0400 Weakened monster lightning damage, dropped AC protection from lightning damage by half. r7145@kamatari (orig r2442): haranp | 2007-10-11 15:51:55 -0400 Fix for 1805138: wands of draining no longer leak information when the bolt misses. r7146@kamatari (orig r2443): haranp | 2007-10-11 16:10:42 -0400 Fix for 1807899: stash-examining a shop will trigger ID noting. r7147@kamatari (orig r2444): haranp | 2007-10-11 16:16:40 -0400 Dwarves and orcs now get +1 to-dam when throwing racial gear. (Yup, this includes armour.) [1804894] r7148@kamatari (orig r2445): dshaligram | 2007-10-12 02:29:56 -0400 [1811733] Brand plants on stairs. r7149@kamatari (orig r2446): dshaligram | 2007-10-12 04:41:38 -0400 Added -O2 -Wuninitialized to Unix makefile. r7151@kamatari (orig r2448): dshaligram | 2007-10-12 15:38:28 -0400 Updated CREDITS. r7152@kamatari (orig r2449): j-p-e-g | 2007-10-12 17:45:59 -0400 A few tiny changes courtesy of dolorous. 1811785: mummy food/drink checks changed to US_UNDEAD check 1811735: vampires don't get holy weapons from acquirement 1811249: remove redundant poison resistance check for Ghouls 1810890: very minor comment fix r7153@kamatari (orig r2450): zelgadis | 2007-10-13 01:17:12 -0400 This change breaks savefile compatibility. Removed speed_inc field from monsterentry struct and added field energy_usage, which lets a monster take different amounts of time for different types of actions, defaulting to 10 points of energy for everything but picking up an object, which defaults to 100% of the monster's speed (the same as before this change). This is currently only used to make curse toes move at half the speed with which they attack (which was previously hard-coded), but is could be used for a lot of interesting things. A related change is that the manner in which apply_enchantment() deals with a monster moving at a different rate than the player has changed for monsters with non-zero-speed. As an example, giant bats have a speed of 30, which means that apply_enchantments() gets called three times per player move if the player is at normal speed; apply_enchantment() has to compensate for this so that a poisoned bat doesn't suffer three times the damage as a monster with speed 10. Monsters being able to do things in energy increments of other than 10 complicated this, and the easiest way to deal with the complication was to keep track of how much energy a monster had recently expended with the new monsters class member ench_countdown, and use that to call apply_enchantments() once for every normal-speed player move (zero-speed monsters are still dealt with in the same manner as before). Because of this, the "spd" variable in apply_enchantment() and decay_enchantment() is normalized to 10 for all non-zero-speed monsters. This doesn't work for ENCH_HELD, since a fast monster should be able to escape from a net more quickly than a slow monster. I've tried to compensate for this, but I'm not sure if I've done it right. r7154@kamatari (orig r2451): zelgadis | 2007-10-13 01:58:53 -0400 Fix giving an interruption message when a monster ignored with the runrest_ignore_monster option gets too close. Also give a more informative interruption message when an air elemental quits being "submerged" in the air, and give a new message when it first "submerges" itself into the air. r7155@kamatari (orig r2452): zelgadis | 2007-10-13 02:07:38 -0400 Oops, overlooked that ench_countdown needs to be rescaled when a monster gains or loses the slow or haste enchantments. r7156@kamatari (orig r2453): j-p-e-g | 2007-10-13 09:50:13 -0400 Implementing merfolk monsters. There are two types, merfolk fighters, and mermaids. The latter are more interesting. ;) Whenever a mermaid sings there's a chance you get beheld, meaning you cannot move away from the mermaid, that is cannot increase the distance between you and her. (Because of the distance pecularities this means at dist 1 you can only be NSW or E of the mermaid but not the diagonal directions.) If you manage to be beheld by several mermaids at the same time, your movements have to respect the distance to all of them. I've added a vector beheld_by that keeps track of beholding monsters and makes checking distance and updating beholding status easier. Merfolk are immune to the mermaid song. r7157@kamatari (orig r2454): j-p-e-g | 2007-10-13 09:57:46 -0400 Adding a description for merfolk fighters and mermaids. r7158@kamatari (orig r2455): haranp | 2007-10-13 19:28:11 -0400 Fixed "shiny" and "embroidered" items not showing as white in abbreviated display. Fix bad merfolk energy. r7159@kamatari (orig r2456): zelgadis | 2007-10-14 00:09:48 -0400 handle_monster_move() still wasn't dealing quite right with invoking apply_enchantments(), since a monster could have apply_enchantments() not called for a normal-speed player turn, and then get called twice in a row during the next turn. This fix also makes zero-speed monsters like plants have apply_enchantments() be handled the same way as other monsters, so enchantments are now allways processed in time increments of 10 energy units (cloud processing for zero speed monsters is still handled separately, though). r7160@kamatari (orig r2457): zelgadis | 2007-10-14 01:20:15 -0400 Give a message and interrupt activity if a visible door is opened or eaten by an unseen monster (either invisible or out of line of sight). r7161@kamatari (orig r2458): zelgadis | 2007-10-14 03:52:00 -0400 The clear() methods should clear the default_flags and type members, as well as clearing out the contained values. r7162@kamatari (orig r2459): zelgadis | 2007-10-14 04:29:33 -0400 Added to classes actor, monsters and player the method can_pass_through(), which returns true for a grid that the monster or player can pass trhough. Also added new monster type "rock worm" to demonstrate a monster which can pass through solid walls. r7163@kamatari (orig r2460): zelgadis | 2007-10-14 06:53:00 -0400 Wrong feature name order for statues. r7164@kamatari (orig r2461): haranp | 2007-10-14 19:46:16 -0400 Tomb rebalancing. r7166@kamatari (orig r2462): nlanza | 2007-10-14 21:04:56 -0400 Squash unused-variable warnings by only declaring variables that exist solely for ASSERT when we're defining DEBUG. r7167@kamatari (orig r2463): nlanza | 2007-10-14 21:06:18 -0400 Add store.{cc,h} to the Xcode build and clean up debugging support a bit. r7168@kamatari (orig r2464): zelgadis | 2007-10-15 00:03:33 -0400 Removed amnesia/forgetfullness trap, mutation and scroll. The mutation has been replaced with an involuntary shouting mutation, and the trap with an alarm trap. The scroll hasn't been replaced with anything, and the frequency of scrolls of random uselessness has thus doubled; someone needs to re-do the scroll frequencies. Also added a "drifting" mutation, which causes the player to sometimes drift in a random direction after moving. r7169@kamatari (orig r2465): zelgadis | 2007-10-15 02:36:07 -0400 Some fixes for mermaid beholding: * A mermaid stops beholding if it polymorphs into something else. * If new walls are created, then Crawl stops the beholdment of any mermaid that gets hidden by the new walls. * Do paranoid sanity checking on beholders before each command with check_beholders() and try to restore sanity if any bugs are found (and give a diagnostics message if DEBUG is set). r7170@kamatari (orig r2466): zelgadis | 2007-10-15 04:45:04 -0400 If a submerged monster moves onto a grid in which it can't be submerged, force it to unsuberge (i.e., a mermaid moving directly from water onto floor without first unsubmerign). If a submerged monster shouts, force it to unsubmerge first. If a visible submerged monster unsubmerges within view of the player, say that it "bursts forth from the water" if it can travel over land, and that it "surfaces" otherwise, rather than saying that it "comes into view". If an invisble sumberged monster unsubmerges within view of a player who can't see invisible, and it can move over land, say "something invisble bursts forth from the water". r7171@kamatari (orig r2467): zelgadis | 2007-10-15 06:32:44 -0400 Fix problem of friendly monsters not using any energy when there's nothing around to fight and they're right next to the player. r7172@kamatari (orig r2468): dshaligram | 2007-10-15 07:28:19 -0400 Fixed bad grammar in highscore entry for characters killed by hellfire. r7173@kamatari (orig r2469): dshaligram | 2007-10-15 07:41:50 -0400 Fixed bad treatment of ghosts and pandemonium lords that get the delayed fireball spell. Also allow pan lords to get orc slaying or disruption brands if the player merits it. r7174@kamatari (orig r2470): dshaligram | 2007-10-15 07:54:13 -0400 Fixed yaktaurs picking up two crossbows and switching crossbows before each shot. r7175@kamatari (orig r2471): dshaligram | 2007-10-15 08:10:59 -0400 Cleanup: move_item_to_grid returns a bool to indicate that drop was successful. r7176@kamatari (orig r2472): dshaligram | 2007-10-15 08:27:57 -0400 [1813214] Trog should not gift the Wrath of Trog. r7177@kamatari (orig r2473): dshaligram | 2007-10-15 08:45:17 -0400 Shift-run doesn't distinguish between wall types to make it more useful in labyrinths. r7178@kamatari (orig r2474): dshaligram | 2007-10-15 09:00:44 -0400 Yaks gore. r7179@kamatari (orig r2475): dshaligram | 2007-10-15 12:32:08 -0400 Fixed Demonspawn getting multiple levels of single-level mutations (cbus). r7180@kamatari (orig r2476): dshaligram | 2007-10-15 12:47:48 -0400 Fixed level that was breaking trunk. r7181@kamatari (orig r2477): dshaligram | 2007-10-15 13:05:01 -0400 Dropped chances of unbranded enchanted items being glowing/runed. r7185@kamatari (orig r2479): haranp | 2007-10-15 19:25:45 -0400 Added basic HTML output functionality to formatted_string. Not used anywhere yet. r7186@kamatari (orig r2480): haranp | 2007-10-15 19:52:18 -0400 Self-banishment is not considered unholy. Banishment at the air is still unholy. [1767848] r7187@kamatari (orig r2481): zelgadis | 2007-10-16 03:08:28 -0400 Added new field seen_context to the monsters class, which can be set to cause a non-standard context to be passed to interrupt_activity( AI_SEE_MONSTER ) if it is called before the current turn is over. If a submerged monster surfaces in order to shout, it has to wait one turn before being able to submerge again. Added back in a scroll named "forgetfullness", but rather than giving amnesia about the map it gives amnesia about non-equipped inventory items. I tried to make the effects annoying rather than serious. r7188@kamatari (orig r2482): zelgadis | 2007-10-16 03:32:17 -0400 Fix for bug 1813676: handle_monster_move() should have been returning immediately if applying the monster's enchantments caused the monster structure to be reset, thus rendering the monster invalid. r7189@kamatari (orig r2483): haranp | 2007-10-16 04:18:17 -0400 Summoned monsters now have the (increasingly misnamed) CREATED_FRIENDLY flag, so they don't give XP, even if initially hostile, to prevent scumming. [1784802] r7190@kamatari (orig r2484): haranp | 2007-10-16 05:09:10 -0400 s/Location/Place/ (David) r7191@kamatari (orig r2485): haranp | 2007-10-16 05:32:26 -0400 Forgetfulness removed; it's now a scroll of fog with a 1-in-10 chance of producing miasma instead. r7192@kamatari (orig r2486): haranp | 2007-10-16 05:39:09 -0400 Minor note formatting improvements (David.) r7193@kamatari (orig r2487): haranp | 2007-10-16 05:44:06 -0400 Wands shouldn't be generated without charges. r7194@kamatari (orig r2488): zelgadis | 2007-10-18 13:32:38 -0400 Lua accessors for you.x_pos, you.y_pos and you.pos r7195@kamatari (orig r2489): zelgadis | 2007-10-18 13:42:50 -0400 Added fog machine Lua map markers. Needs a C interface to make it usable in level generation. Clouds now have a "spread rate" field, which by default uses the same per-cloud-type rate as before (normal spread rate for steam, grey smoke and black smoke, no spreading for other cloud types). Might want to make the spread rate decrease as the cloud spreads (currently it remains unchanged). Added new dungeon event type "entered level", to complement "entering level". r7196@kamatari (orig r2490): haranp | 2007-10-19 12:30:10 -0400 1815768: some NOTE_USER_NOTEs should be NOTE_MESSAGE instead (actually they should be yet another note type, but NOTE_MESSAGE works for now.) r7197@kamatari (orig r2491): haranp | 2007-10-19 13:20:43 -0400 Hurting holies was being counted as KILL_ANGEL instead of ATTACK_HOLY (bobbens) r7199@kamatari (orig r2493): haranp | 2007-10-19 18:30:42 -0400 Menus are now tagged. Menu colours now only apply to a menu with a matching tag, unless the menu colour tag is empty or "any". Menu colours are specified as tag:colour:pattern, where the "tag:" part is optional (default is empty tag, i.e., all menus.) The following menu tags exist: ability, description, equip, help, inventory, notes, resists, spell, stash. Default .crawlrc should probably be changed (and the docs, too...) r7200@kamatari (orig r2494): zelgadis | 2007-10-20 00:18:07 -0400 Oops, couldn't set a non-default 0% cloud spread rate. r7201@kamatari (orig r2495): haranp | 2007-10-20 04:23:44 -0400 Menu tagging corrections + docs + initfile (David) r7202@kamatari (orig r2496): dshaligram | 2007-10-20 14:05:53 -0400 Moved position information Lua functions to luadgn.cc. r7203@kamatari (orig r2497): dshaligram | 2007-10-20 14:11:16 -0400 Blademasters and master archers shouldn't pick up weapons. r7205@kamatari (orig r2499): dshaligram | 2007-10-21 04:36:44 -0400 Rock stair travel fix for trunk. r7206@kamatari (orig r2500): dshaligram | 2007-10-21 05:47:19 -0400 Note when Xom banishes player. r7207@kamatari (orig r2501): dshaligram | 2007-10-21 08:01:09 -0400 [1816969] Use AT_NO_ATK in mon-data.h for unused monster attacks (bobbens). r7208@kamatari (orig r2502): dshaligram | 2007-10-21 08:20:11 -0400 Added missing double-quote (bobbens). r7209@kamatari (orig r2503): dshaligram | 2007-10-21 08:31:11 -0400 [1813910] Typo fixes in mutation messages (dolorous). r7210@kamatari (orig r2504): dshaligram | 2007-10-21 09:05:22 -0400 [1800206] Ghoul food cleanup (dolorous). r7211@kamatari (orig r2505): j-p-e-g | 2007-10-21 09:49:11 -0400 Add information to demon weapons that Demonspawn fight better with them. (Hmmm, while I wrote Demonspawns going by proper grammar rules my gut feeling says it should be simply "Demonspawn" without that "s". Help?) Also catering to FR 1816411: disallow elven M&F as well as dwarven Pole-arms. r7213@kamatari (orig r2506): dshaligram | 2007-10-21 11:29:17 -0400 [1795751] Mutation cleanup, courtesy dolorous. r7214@kamatari (orig r2507): dshaligram | 2007-10-21 11:36:04 -0400 Fixed permanent transforms (syllogism). r7217@kamatari (orig r2510): dshaligram | 2007-10-21 13:43:14 -0400 Fixed Lua dependency for trunk. r7218@kamatari (orig r2511): dshaligram | 2007-10-21 15:14:03 -0400 Accept "none" as a brand without carping about it to stderr. r7220@kamatari (orig r2513): j-p-e-g | 2007-10-21 18:19:23 -0400 Demigods no longer have a fast metabolism and gain random stats more often. I thought there was a FR about this somewhere but maybe it was "only" suggested in the discussion group. Anyway, I've been told this has been sanctioned from "high up", so here it is. ;) Oh, and fix that Demonspawn plural. r7222@kamatari (orig r2515): j-p-e-g | 2007-10-22 07:00:16 -0400 Applying two patches by dolorous: 1817546: refix Beogh butchering crash 1817459: fix a couple of typos r7223@kamatari (orig r2516): dshaligram | 2007-10-22 12:13:40 -0400 Fixed monsters wearing shields and other inappropriate armour as body armour. r7224@kamatari (orig r2517): j-p-e-g | 2007-10-22 17:30:59 -0400 Changing screaming mutation to influence both frequency and volume of shouting -> yelling -> screaming. Reduced frequency of level 2 and 3 to make up for greater range. When paralysed, you are unable to scream. Also cleaning up mutation listings. r7225@kamatari (orig r2518): haranp | 2007-10-23 07:25:01 -0400 Fixed bad message with RAP_MAGICAL_POWER. Type safety; this required moving randart_prop_type to enum.h. r7228@kamatari (orig r2521): dshaligram | 2007-10-23 12:53:11 -0400 [1815754] Mutagenic randarts are less mutagenic. r7229@kamatari (orig r2522): haranp | 2007-10-23 12:58:30 -0400 Blade card now gives feedback when failing to brand. Blade card can now give different brands, not just SPWPN_VORPAL. Type safety on brand_weapon(). r7230@kamatari (orig r2523): haranp | 2007-10-23 13:50:10 -0400 You can now Triple Draw from decks you aren't wielding. r7231@kamatari (orig r2524): haranp | 2007-10-23 17:14:20 -0400 Some code cleanup. r7232@kamatari (orig r2525): haranp | 2007-10-23 17:23:06 -0400 Receiving a pure deck from Nemelex now decays the appropriate sacrifice weight by 20%. r7233@kamatari (orig r2526): j-p-e-g | 2007-10-23 18:19:01 -0400 Adding Vampire aptitudes to tables.txt (Bug 1816344). Also changed Ranged Combat to Throwing, while I was at it. Fixing 1817775: portaled projectile treats returning weapons like any other projectile (no duplicates any more, but also no returning). I think this makes sense, seeing how the spell teleports it somewhere so how should it know the path back. Fixing 1817995: starting items not stacking correctly. Question: Why is the flag BEEN_IN_INV even set for starting inventory? Applying two patches by dolorous: 1818736: comment fix for MUT_SAPROVOROUS 1818667: remove redundant MUT_HOOVES check r7234@kamatari (orig r2527): haranp | 2007-10-23 18:24:01 -0400 Added Lugonu greeting message (Jovann) r7236@kamatari (orig r2529): dshaligram | 2007-10-24 04:08:04 -0400 Fixed bad play time format in character dump, removed turns_by_place and kills_by_place from the default dump_order. r7238@kamatari (orig r2531): haranp | 2007-10-24 04:58:17 -0400 Lugonu invocations are now invocations and have fail rates. r7239@kamatari (orig r2532): dshaligram | 2007-10-24 05:29:20 -0400 Orc battle cry fixes (shouldn't affect berserk/confused/paralysed monsters). Affected orcs are woken up if they happen to be asleep (<3). Ensorcelled hibernation should not work on berserk creatures. r7240@kamatari (orig r2533): dshaligram | 2007-10-24 05:39:19 -0400 [1818732] Merfolk hunters start with a knife. r7241@kamatari (orig r2534): dshaligram | 2007-10-24 06:08:24 -0400 [1818767] Idle time clamped at 5 minutes. r7242@kamatari (orig r2535): dshaligram | 2007-10-24 08:42:08 -0400 [1818799] Reduce message spam from Olgreb's toxic radiance. r7243@kamatari (orig r2536): dshaligram | 2007-10-24 09:19:24 -0400 [1757174] Disallow mapping in labyrinths. r7244@kamatari (orig r2537): j-p-e-g | 2007-10-24 10:05:13 -0400 Add a "forget level map" command, Ctrl-F, to level map. This command used to be for waypoints along with Ctrl-W but as that never made it into the level map help I don't think it matters. (FR 1745112) r7245@kamatari (orig r2538): j-p-e-g | 2007-10-24 10:54:49 -0400 Add "forget level" command to manual, and change wording of the deformed body mutation for Centaurs and Nagas (FR 1814790). r7247@kamatari (orig r2540): dshaligram | 2007-10-24 12:21:32 -0400 [1779076] Greedy explore will ignore items (after prompting) if autopickup fails twice on the same spot, such as when inventory is full. If pickup_dropped = true (not likely if greedy explore is in use), greedy explore uses the old strategy of not budging until the item is picked up. r7248@kamatari (orig r2541): dshaligram | 2007-10-25 01:22:59 -0400 Fixed bugs in greedy-explore's item ignore prompts. r7249@kamatari (orig r2542): dshaligram | 2007-10-25 03:13:13 -0400 [1813368] Makhleb/Vehumet passive power gain now active without needing to pray. Vehumet's spell boost and warding must still be prayed for. r7250@kamatari (orig r2543): dshaligram | 2007-10-25 05:11:50 -0400 Spell changes: strengthened stone arrow and the storms, weakened bolts of fire and cold, and crystal spear. (Re)allow partial spell names when using &Z in wizmode. r7251@kamatari (orig r2544): haranp | 2007-10-25 05:24:32 -0400 Added Pain (== agony) and Torment (== Symbol of Torment) to the Deck of Destruction. Boosted cost of Stack Deck. r7252@kamatari (orig r2545): dshaligram | 2007-10-25 05:49:39 -0400 [1810433] Ogre hunters start with large rocks. Monster ogres can also throw large rocks but are never generated with rocks. r7253@kamatari (orig r2546): haranp | 2007-10-25 06:07:25 -0400 Drawing from Destruction with no monsters nearby does not gain piety. r7254@kamatari (orig r2547): haranp | 2007-10-25 06:09:32 -0400 Doc fixes (Erik) r7255@kamatari (orig r2548): haranp | 2007-10-25 06:16:06 -0400 More doc fixes (Erik) r7256@kamatari (orig r2549): dshaligram | 2007-10-25 06:16:22 -0400 [1819634] Fixed filenames missing in Lua file-not-found error messages. r7257@kamatari (orig r2550): dshaligram | 2007-10-25 06:18:29 -0400 [1817064] Fixed shift-running stopping for secret doors. r7258@kamatari (orig r2551): dshaligram | 2007-10-25 06:28:15 -0400 [1817804] Fixed bogus "You're already here" messages from interlevel travel. r7259@kamatari (orig r2552): dshaligram | 2007-10-25 06:35:36 -0400 [1816483] Sling bullets should not be poisoned. r7260@kamatari (orig r2553): dshaligram | 2007-10-25 06:42:58 -0400 [1817009] Changed secret-doored temple entrance. r7261@kamatari (orig r2554): haranp | 2007-10-25 06:44:29 -0400 No unnecessary double messaging when drawing the Wraith. r7262@kamatari (orig r2555): haranp | 2007-10-25 06:51:30 -0400 more doc fixes (Erik) r7263@kamatari (orig r2556): haranp | 2007-10-25 07:06:37 -0400 More doc fixes. r7264@kamatari (orig r2557): j-p-e-g | 2007-10-25 07:40:09 -0400 FR 1818615: modify prayer prompt to stop praying for 'y', renew prayer for 'r' and cancel prompt for anything else. r7266@kamatari (orig r2559): dshaligram | 2007-10-25 08:19:25 -0400 dgn_place_map takes a coord_def to specify the centre of the map for minivaults and floating vaults. This placement can be activated using an asterisk (mapname*) when entering the name of the map in the &L command. r7267@kamatari (orig r2560): j-p-e-g | 2007-10-25 08:45:42 -0400 Applying two patches by dolorous: 1819730: remove redundancy for creating random undead servant (Yred) 1819013: typo fix Also modified spell description for Portaled Projectile. r7268@kamatari (orig r2561): dshaligram | 2007-10-25 08:53:10 -0400 [1818982] Kenku talons as mutation (dolorous). r7270@kamatari (orig r2563): dshaligram | 2007-10-25 09:02:05 -0400 [1786778] Fixed dolinks.sh and domake.sh (dolorous). r7273@kamatari (orig r2566): haranp | 2007-10-25 09:24:37 -0400 Added Trowel portal generation. Somewhat buggy. r7274@kamatari (orig r2567): dshaligram | 2007-10-25 09:43:39 -0400 Added a flag to disable generation of exits from a vault. Need to clean up vault placement to make it easier to parameterise it. r7275@kamatari (orig r2568): dshaligram | 2007-10-25 09:45:08 -0400 Only non-trolls get hunger from troll leather armour (syllogism). r7276@kamatari (orig r2569): haranp | 2007-10-25 10:49:06 -0400 Type safety and code cleanup. r7277@kamatari (orig r2570): dshaligram | 2007-10-25 10:59:57 -0400 [1804809] Fixed buggy handling of colour overlays. r7278@kamatari (orig r2571): haranp | 2007-10-25 11:05:11 -0400 Minor code cleanup. r7279@kamatari (orig r2572): dshaligram | 2007-10-25 12:02:13 -0400 Use a safer macro for clua ret (doy). r7280@kamatari (orig r2573): dshaligram | 2007-10-25 12:16:36 -0400 Fixed bug that consistently placed characters too near the exit in labyrinths. r7281@kamatari (orig r2574): dshaligram | 2007-10-25 12:48:10 -0400 Fixed labyrinth sizes for trunk. r7282@kamatari (orig r2575): dshaligram | 2007-10-25 13:11:44 -0400 Fixed wizmode segfault on &^ with no god. r7283@kamatari (orig r2576): dshaligram | 2007-10-25 13:25:35 -0400 Refixed labyrinth entry point. r7285@kamatari (orig r2578): dshaligram | 2007-10-25 14:43:19 -0400 Fixed bug that would allow Lua dofile on arbitrary files using absolute paths. r7287@kamatari (orig r2580): dshaligram | 2007-10-25 22:42:56 -0400 Dropped to-hit on javelins. r7288@kamatari (orig r2581): dshaligram | 2007-10-25 23:33:48 -0400 Suppress unnecessary "Floor." lines when looking around and targeting. r7289@kamatari (orig r2582): dshaligram | 2007-10-25 23:53:22 -0400 [1820172] Typo fixes (dolorous). r7290@kamatari (orig r2583): dshaligram | 2007-10-26 01:09:10 -0400 Beogh orcs will follow the PC downstairs even if they're not directly adjacent to the player, but are adjacent to other friendly orcs that are (in)directly adjacent to the player. r7291@kamatari (orig r2584): dshaligram | 2007-10-26 04:33:37 -0400 Monsters can gain experience and level-up. Breaks saves. r7292@kamatari (orig r2585): dshaligram | 2007-10-26 04:38:36 -0400 Monsters lose experience when drained. r7293@kamatari (orig r2586): dshaligram | 2007-10-26 07:11:03 -0400 Orcs may surrender to Beogh worshippers when beaten up. Adjusted experience gain for monsters, duration of orc battle cries and removed use of invocations to determine the success of spontaneous orc conversion. Fixed monsters getting bad experience values. r7294@kamatari (orig r2587): dshaligram | 2007-10-26 07:15:09 -0400 Fixed item_check not being called correctly (syllogism). r7295@kamatari (orig r2588): j-p-e-g | 2007-10-26 07:32:57 -0400 Fix bug 1814617: teleport/banish not clearing being trapped in net r7296@kamatari (orig r2589): dshaligram | 2007-10-26 07:50:08 -0400 Fixed non-friendly monsters not gaining experience (oops). r7298@kamatari (orig r2591): j-p-e-g | 2007-10-26 07:56:45 -0400 Fix remaining net bug. r7300@kamatari (orig r2593): dshaligram | 2007-10-26 08:56:40 -0400 No experience for summoned hostile elementals and scorpions (syllogism). r7301@kamatari (orig r2594): dshaligram | 2007-10-26 09:05:22 -0400 Backed-out redundant no-xp-for-summons change, already fixed differently by Haran. r7307@kamatari (orig r2600): dshaligram | 2007-10-26 12:26:19 -0400 Trowel card now picks vaults tagged "trowel_portal". r7308@kamatari (orig r2601): dshaligram | 2007-10-26 12:32:37 -0400 Added cset_unicode to options texts (V-Napkin), fixed staff of energy not working for transformations (syllogism). r7311@kamatari (orig r2604): j-p-e-g | 2007-10-26 13:27:02 -0400 Alternative message for "kneeling" at altars. r7313@kamatari (orig r2606): j-p-e-g | 2007-10-26 18:38:21 -0400 Adding two new mutations for the heck of it: * MUT_PAWS: "You have soft paws in place of feet." Similar to HOOVES and TALONS - incidentally, I resorted a few mutations for better grouping - but increases stealth. * MUT_EXTRA_EYES: grow up to three extra eyes that increase depth perception and thus accuracy. I'm still looking for a drawback to this mutation (other than looking weird). Also, could be related to ACUTE/BLURRY VISION somehow. Breaks saves, or at least mutations. r7314@kamatari (orig r2607): dshaligram | 2007-10-27 01:51:13 -0400 Increased experience needed for monsters to level up, bumped orc sorcerers up one HD, and factored in XL in Beogh orc spontaneous conversion. r7315@kamatari (orig r2608): dshaligram | 2007-10-27 02:13:39 -0400 Nets should not be branded. r7316@kamatari (orig r2609): dshaligram | 2007-10-27 02:42:43 -0400 Added a space in the note taken when messages are received in dgl. Dropped hobgoblin max hp. r7317@kamatari (orig r2610): dshaligram | 2007-10-27 02:50:04 -0400 Fixed mutation array size mismatch assert. r7318@kamatari (orig r2611): dshaligram | 2007-10-27 02:54:08 -0400 [1821096] Olgreb's toxic radiance should not affect submerged monsters (dolorous). r7319@kamatari (orig r2612): dshaligram | 2007-10-27 03:15:37 -0400 [1820931] Fixed wizmode &o deck bug (doy). r7320@kamatari (orig r2613): dshaligram | 2007-10-27 03:44:37 -0400 [1821098] Fixed bat transform not conferring flight. Fixed player_is_levitating and renamed it to player_is_airborne to describe the function better. r7323@kamatari (orig r2616): dshaligram | 2007-10-27 04:42:26 -0400 Fixed monsters::is_levitating not checking randarts that provide levitation. r7324@kamatari (orig r2617): dshaligram | 2007-10-27 05:47:42 -0400 Fixed macros not working for targeting (Chilliwack). r7325@kamatari (orig r2618): dshaligram | 2007-10-27 06:10:27 -0400 Fixed !R inscription not confirming remove when only one item is worn (jarpiain). r7327@kamatari (orig r2620): dshaligram | 2007-10-27 06:31:49 -0400 Vestibule monster generation drops off quickly and approaches zero. r7328@kamatari (orig r2621): dshaligram | 2007-10-27 06:51:39 -0400 Dropped cost of Okawaru Haste. r7329@kamatari (orig r2622): dshaligram | 2007-10-27 07:27:10 -0400 Increased gift timeout for Okawaru armour gifts, made it easier to sustain piety while working off a gift timeout. r7330@kamatari (orig r2623): dshaligram | 2007-10-27 07:34:28 -0400 Okawaru and Trog gifts should not be negatively enchanted, where reasonable. r7331@kamatari (orig r2624): dshaligram | 2007-10-27 07:52:27 -0400 Weakened control demon demonspawn power (syllogism). r7332@kamatari (orig r2625): dshaligram | 2007-10-27 08:45:04 -0400 Made Xom more random, reduced chance of bad effects at low amusement levels. r7336@kamatari (orig r2628): dshaligram | 2007-10-27 10:46:37 -0400 Removed unnecessary #if UNIX lines, changed textcolor to textattr for view redraw. r7342@kamatari (orig r2629): dshaligram | 2007-10-27 11:59:10 -0400 Minor view code cleanup; this ought to fix the DOS redraw issues as well. r7344@kamatari (orig r2631): nlanza | 2007-10-27 13:33:21 -0400 Add mgrow.{cc,h} to the Xcode project. r7346@kamatari (orig r2632): dshaligram | 2007-10-28 04:07:04 -0400 Toned down Xom's use of demons. r7349@kamatari (orig r2635): dshaligram | 2007-10-28 06:37:06 -0400 Monsters should not gain experience for offing their friends. r7351@kamatari (orig r2637): dshaligram | 2007-10-28 07:12:14 -0400 Moved dangerous minivaults deeper (bobbens). r7353@kamatari (orig r2639): j-p-e-g | 2007-10-28 10:31:57 -0400 Changed vaults (dploog). r7354@kamatari (orig r2640): j-p-e-g | 2007-10-28 11:15:21 -0400 Another mutation commit. Sorry, I couldn't resist. I'm replacing the (stupid, I agree) "extra eyes" mutation with the more Crawlific "shaggy fur" mutation. It currently doesn't count towards the scales counter, but that could be changed. Also, maybe it could replace one of the scales with a similar AC bonus. Oh, and trolls start out with this at level 1 because I think it fits them. Adding the percentage bonus (rarity 1) and penalty (rarity 9) for mana. Maybe the bonus (+10%, +20%, +30%) should be abolished entirely as David suggested; for now I've left it as a mutation pair. As a third change I'm including the experimental sleepiness mutation that makes you randomly fall asleep. Being hit, loud noises and starving will make you wake up. Again, may break mutations of existing save files. --------------------------------- To answer David's question on balancing (or rather, make everything more complicated, I'm afraid) I've counted mutations in 0.3 and as of this commit, to compare them. Rarity influences the chance a mutation, once randomly chosen, will be considered acceptable, with a chance of rarity/10. Each round of trying to find an acceptable mutation there's a 1/1000 chance of just giving up. In brackets I will list the average probability of a good/bad mutation being chosen in a given round. (The difference to 100 is the chance of having to reroll.) in 0.3: 46 good mutations of average rarity 3.2 (23.72%) 12 bad mutations of average rarity 8 (15.47%) 4 in-between mutations of average rarity 7 (4.51%) (56.3% chance of rerolling) new: 48 good mutations of average rarity 3.1 (21.72%) 14 bad mutations of average rarity 7.6 (15.71%) 6 in-between mutations of average rarity 5 (4.41%) (58.16% chance of rerolling) By in-between mutations I mean ones with advantages and drawbacks, namely weak_flexible, strong_stiff, horns, hooves, talons and paws. (The last four are probably seen as mostly negative by a lot of players due to losing an equipment slot.) Because of the lower rarity of the new mutations (including drifting) the overall chance of _not_ receiving a mutation has slightly increased (1/1000 chance per reroll necessary). r7356@kamatari (orig r2642): j-p-e-g | 2007-10-28 12:18:11 -0400 Repairing levels for trunk. Whoops... r7358@kamatari (orig r2644): dshaligram | 2007-10-28 14:46:28 -0400 Transform fixes for trunk. r7360@kamatari (orig r2646): dshaligram | 2007-10-28 15:29:42 -0400 Removed "dig_this" minivault. r7362@kamatari (orig r2648): dshaligram | 2007-10-29 02:27:10 -0400 Fixed javelin base hit, dropped weight slightly. r7363@kamatari (orig r2649): dshaligram | 2007-10-29 02:39:09 -0400 Give ogres one extra rock to throw, increased preservation rates for javelins and large rocks, dropped weight of large rocks. r7365@kamatari (orig r2651): dshaligram | 2007-10-29 02:52:14 -0400 [1817715] Fixed autopickup trying to pick up nets you're caught in. r7367@kamatari (orig r2653): dshaligram | 2007-10-29 03:57:57 -0400 Tweaked -mapstat to show random maps available by depth. Added a floating dummy vault to correct probabilities of vaults in non-dungeon branches. r7370@kamatari (orig r2656): dshaligram | 2007-10-29 05:50:59 -0400 Fixed monster thrown weapon preservation rate. r7374@kamatari (orig r2660): j-p-e-g | 2007-10-29 08:30:20 -0400 Beogh conversion fixes for trunk. r7375@kamatari (orig r2661): j-p-e-g | 2007-10-29 08:54:55 -0400 float.des changes. r7377@kamatari (orig r2663): dshaligram | 2007-10-29 09:20:03 -0400 Removed obsolete "levels" option. des files to load should be specified in loadmaps.lua and nowhere else. r7378@kamatari (orig r2664): dshaligram | 2007-10-29 10:01:08 -0400 Sort maps by weight in mapgen.log output (random map listing). r7379@kamatari (orig r2665): dshaligram | 2007-10-29 10:28:20 -0400 Vault fixes + applied bobbens' levdes.vim water-colour patch. r7380@kamatari (orig r2666): dshaligram | 2007-10-29 10:51:06 -0400 Added a note on generating mapgen stats. r7382@kamatari (orig r2668): dshaligram | 2007-10-29 14:08:09 -0400 s/antennas/antennae/. r7384@kamatari (orig r2670): haranp | 2007-10-29 16:13:56 -0400 Better messages for Genie effects. r7386@kamatari (orig r2672): dshaligram | 2007-10-30 00:16:54 -0400 [1814784] Enable NaEE. r7387@kamatari (orig r2673): dshaligram | 2007-10-30 00:37:28 -0400 [1822251] Fixed bug in the handling of poisoned needles. r7388@kamatari (orig r2674): dshaligram | 2007-10-30 00:51:24 -0400 [1800190] Reavers get to choose starting spellbook. Moved poison level check to poison_monster. r7390@kamatari (orig r2676): dshaligram | 2007-10-30 01:16:17 -0400 Fixed extra keypress needed to navigate out of spellbook descriptions when examining books in shops (Erik). r7392@kamatari (orig r2678): dshaligram | 2007-10-30 01:35:40 -0400 Place altar to Lugonu randomly, not necessarily in LOS. r7395@kamatari (orig r2681): haranp | 2007-10-30 07:17:52 -0400 Stack Deck interface improvements. Incidentally, describe.cc needs to be fixed to describe marked/stacked decks properly. r7397@kamatari (orig r2683): dshaligram | 2007-10-30 09:09:37 -0400 Updated CREDITS and INSTALL, fixed Tomb:2 (David), fixed Xom's mutation-as-reward strategy. r7398@kamatari (orig r2684): dshaligram | 2007-10-30 09:19:29 -0400 Fixed Xom being amused by repeatedly zapping tried wands (like digging), tweaked messages for demon summons. r7399@kamatari (orig r2685): dshaligram | 2007-10-30 09:34:53 -0400 Wings mutation is single-level. r7402@kamatari (orig r2688): dshaligram | 2007-10-30 12:02:16 -0400 [1822636] Fixed bad handling of banishment by distortion weapon animated by Tukima's Dance. r7404@kamatari (orig r2690): dshaligram | 2007-10-30 14:08:49 -0400 Fixed mkdir call for djgpp. r7406@kamatari (orig r2692): haranp | 2007-10-30 18:29:10 -0400 'v' now describes decks properly. There is a small information leak: if you know (from Peek Deck) that the deck contains a card X somewhere, and then you draw card X which happens not to be the seen card X in the internal structure, you can still see from the 'v' output that there is another X card hiding in there. r7407@kamatari (orig r2693): haranp | 2007-10-30 18:36:39 -0400 Noted D:1} trick to search for items on dlevel 1 only [1823009] r7408@kamatari (orig r2694): haranp | 2007-10-30 18:48:14 -0400 Unarmed title is based on base, not modified, stats [1821727] r7409@kamatari (orig r2695): haranp | 2007-10-30 19:01:30 -0400 Slightly better message when zapping identifies a wand [1817031] r7411@kamatari (orig r2697): dshaligram | 2007-10-30 22:13:19 -0400 [1823057] Fixed explore's mimic handling. r7415@kamatari (orig r2701): dshaligram | 2007-10-31 04:01:02 -0400 s/favorite/favourite/ r7416@kamatari (orig r2702): haranp | 2007-10-31 07:31:12 -0400 dec_penance() now happens after the godly wrath, not before. Fixes 1819735. r7417@kamatari (orig r2703): haranp | 2007-10-31 08:11:04 -0400 Update stashes when butchery is done. Fixes 1820396. r7418@kamatari (orig r2704): haranp | 2007-10-31 08:18:22 -0400 ID is no longer possible on portaled projectiles. Fixes 1817777. r7419@kamatari (orig r2705): haranp | 2007-10-31 08:49:37 -0400 1822982: slightly better spell power string. r7420@kamatari (orig r2706): haranp | 2007-10-31 09:31:38 -0400 Portal no longer works once you have the Orb. r7421@kamatari (orig r2707): haranp | 2007-10-31 09:44:57 -0400 s/portaled/portal r7422@kamatari (orig r2708): haranp | 2007-10-31 10:19:08 -0400 Nagas no longer get racial weapons [1811726]. r7423@kamatari (orig r2709): haranp | 2007-10-31 10:24:18 -0400 Changed description for weapons of distortion [1808856] r7427@kamatari (orig r2712): j-p-e-g | 2007-11-01 07:17:45 -0400 Corrections to tables.txt r7428@kamatari (orig r2713): j-p-e-g | 2007-11-01 07:41:11 -0400 Committing patch 1823611, 1822279, 1821680 and 1821019 by dolorous: typo fixes, mutation message fixes for black scales and boney plates, and fixed removal of elven M&F and dwarven Polearms. r7430@kamatari (orig r2715): dshaligram | 2007-11-01 07:59:18 -0400 Added you.good_god() and you.evil_god() to check if the player is worshipping a good/evil god. Passing a god name is optional, and will check if that god is good/evil (you.good_god("Elyvilon") == true). r7431@kamatari (orig r2716): dshaligram | 2007-11-01 08:11:05 -0400 Allow yesno to use an override keymap applied after getchm(), make Escape cancel out of the explore stop prompt (bobbens). r7432@kamatari (orig r2717): dshaligram | 2007-11-01 09:22:39 -0400 Added a brief howto for portal vaults (bobbens), removed unnecessary desc field from lm_pdesc.lua, breaks saves. r7433@kamatari (orig r2718): haranp | 2007-11-01 18:52:52 -0400 Some prayer cases which shouldn't have taken time were taking time. [1824174] r7434@kamatari (orig r2719): haranp | 2007-11-01 19:03:32 -0400 Changed order of spells in Book of Control. [1823455] r7435@kamatari (orig r2720): haranp | 2007-11-01 19:05:37 -0400 Fixed the other instance of Control Teleport (in Spatial Translocations.) r7436@kamatari (orig r2721): dshaligram | 2007-11-02 02:27:40 -0400 Applied bobbens' patch: you.skills("foo") gets skill level of foo from Lua. r7437@kamatari (orig r2722): dshaligram | 2007-11-02 02:52:42 -0400 Fixed LFLAGS not working right when conditionalised (bobbens). r7438@kamatari (orig r2723): dshaligram | 2007-11-02 04:56:48 -0400 Fixed level-map not showing column 79 if the term is 80 columns (bobbens). r7439@kamatari (orig r2724): dshaligram | 2007-11-02 07:40:34 -0400 Allow using floor="other_feature" when initialising a one-way stair, so that the stair is replaced with other_feature instead of regular floor (bobbens). r7440@kamatari (orig r2725): dshaligram | 2007-11-02 09:36:20 -0400 Fixed broken MHITNOT/MHITYOU, changed handling of DUR_SLOW to be like DUR_HASTE, reduced paralysis duration for crystal balls of fixation. MHITNOT fix breaks saves. r7441@kamatari (orig r2726): dshaligram | 2007-11-02 10:22:15 -0400 Unbreak trunk build (oops). r7442@kamatari (orig r2727): dshaligram | 2007-11-02 11:05:33 -0400 Experimental support for monster shields, needs more work for rationalising shield class for monsters with player and beam to-hit. r7443@kamatari (orig r2728): haranp | 2007-11-03 06:48:49 -0400 Minor code cleanups. r7445@kamatari (orig r2730): haranp | 2007-11-03 08:29:53 -0400 Added HURRY option to makefile.unix. Slightly changed how randart weapon/armour mimics work. r7447@kamatari (orig r2732): haranp | 2007-11-03 09:06:10 -0400 Fixed bug with show_beam on when self-targeting without ever moving the direction cursor. [1812562] r7452@kamatari (orig r2737): dshaligram | 2007-11-03 12:05:59 -0400 Removed remaining traces of travel_colour (David). r7454@kamatari (orig r2739): dshaligram | 2007-11-03 12:16:43 -0400 Restrict aerie to main-dungeon-only. r7456@kamatari (orig r2741): dshaligram | 2007-11-03 12:37:50 -0400 Updated release build (DOS+Windows) script for 0.3. r7462@kamatari (orig r2745): haranp | 2007-11-03 15:42:38 -0400 Refix for direction(): prev_target should work now. r7465@kamatari (orig r2748): dshaligram | 2007-11-04 09:16:55 -0500 Killing-blow damage was not being saved to logfile, fixed. r7466@kamatari (orig r2749): j-p-e-g | 2007-11-04 10:53:36 -0500 Nets that hold you cannot be destroyed by Ely's Destroy Weapon ability. (Fix 1825520). Monsters will be held in nets longer. Doesn't influence time needed to destroy it, so ogres and such will still get out quickly. Needs more testing, I guess. Intelligent friendlies will try to avoid traps you (the player) know about, and the chance for triggering known blade and net traps is much lower. Also, friendly casters are much less likely to spam you with "spells" if there are no enemies around. r7469@kamatari (orig r2752): j-p-e-g | 2007-11-04 14:15:23 -0500 Make autoexplore stop when orcs convert to Beogh. r7470@kamatari (orig r2753): j-p-e-g | 2007-11-04 15:19:28 -0500 Renaming Portal Vaults to Bazaars. [FR 1824984] Fix 1825526: not stepping into deep water costing a turn Fix 1825352: ?torment only being unholy if it wasn't known r7472@kamatari (orig r2755): haranp | 2007-11-04 16:11:19 -0500 Pluralise "knife" correctly (to "knives") [1825553] r7473@kamatari (orig r2756): j-p-e-g | 2007-11-04 17:14:50 -0500 FR 1821775: While held in a net, you can fire blowguns, though there's a penalty similar to the one when wearing a buckler and accuracy is lowered. I'm not sure about the numbers - they'll have to be tweaked a bit, I guess. Also fix possibility to drift out of net. r7474@kamatari (orig r2757): ennewalker | 2007-11-04 17:43:49 -0500 Fixing typo in manual. (Thanks, AlexMax.) r7478@kamatari (orig r2758): dshaligram | 2007-11-05 01:33:43 -0500 Updated CREDITS. r7479@kamatari (orig r2759): haranp | 2007-11-05 03:31:39 -0500 Vault fixes (David) r7481@kamatari (orig r2761): haranp | 2007-11-05 03:47:20 -0500 Removed CHANCE line (oops) r7484@kamatari (orig r2764): j-p-e-g | 2007-11-05 04:05:35 -0500 latest net fixes (Nemelex prayer, swapping with friendlies) for trunk r7485@kamatari (orig r2765): haranp | 2007-11-05 05:28:43 -0500 Incorporate patches 1825023 (typos) and 1824868 (bug in fully_contains().) r7487@kamatari (orig r2767): haranp | 2007-11-05 05:50:57 -0500 Fixed 1825223: unknown curses don't leak information in prices. r7489@kamatari (orig r2769): j-p-e-g | 2007-11-05 09:19:39 -0500 Net fix (reduced trapping turns) also for trunk. r7491@kamatari (orig r2771): j-p-e-g | 2007-11-05 11:07:44 -0500 Correct tables.txt and add wizard mode to version information. r7493@kamatari (orig r2773): j-p-e-g | 2007-11-05 11:53:54 -0500 claw mutation fix for net damage, courtesy of dolorous r7495@kamatari (orig r2775): j-p-e-g | 2007-11-06 06:51:01 -0500 Corrections to manual (patch by maiermirk) and fix to freeing self from net. r7496@kamatari (orig r2776): haranp | 2007-11-06 12:35:30 -0500 Geryon can now fly. r7497@kamatari (orig r2777): haranp | 2007-11-06 18:46:55 -0500 Massive rewrite of makeitem.cc. Might be buggy. Fixed some old bugs, e.g. double reroll of =oCT. items() now respects force_type more often. As a side effect, acquirement is less likely to give randart jewellery or armour. r7498@kamatari (orig r2778): haranp | 2007-11-07 05:32:26 -0500 Fix for 1827415: handle_time()-induced banishments (e.g. Hell miscasts) were being applied one turn too late. r7500@kamatari (orig r2780): haranp | 2007-11-07 09:19:45 -0500 s/liquid/barnacled/ r7503@kamatari (orig r2783): j-p-e-g | 2007-11-07 09:37:54 -0500 latest net improvement (make switching damage -> escape rarer) for trunk r7504@kamatari (orig r2784): haranp | 2007-11-07 13:20:00 -0500 Reorganized Metamorphosis, batform now impossible. r7506@kamatari (orig r2786): haranp | 2007-11-07 13:26:31 -0500 Merged r2729 (morgue dir creation) from 0.3. r7507@kamatari (orig r2787): haranp | 2007-11-07 13:50:27 -0500 Slightly compressed 'v' descriptions. Should fix 1826265. r7509@kamatari (orig r2789): haranp | 2007-11-07 14:00:38 -0500 Blocked some useless spells for Vampires and Ghouls. [1827689] r7511@kamatari (orig r2791): haranp | 2007-11-07 14:10:55 -0500 Runes no longer need ID [1826900] r7514@kamatari (orig r2794): haranp | 2007-11-07 14:50:44 -0500 Merged r2793 (better ability descriptions for Nemelex) r7515@kamatari (orig r2795): haranp | 2007-11-07 15:06:07 -0500 pray() prompt respects macros (V-Napkin) r7517@kamatari (orig r2797): haranp | 2007-11-07 15:13:08 -0500 Refix pray() fix. r7519@kamatari (orig r2799): haranp | 2007-11-07 15:25:52 -0500 Monochromatized spell power bars. r7521@kamatari (orig r2801): haranp | 2007-11-07 16:05:52 -0500 Cancelling 'E'voking a reaching weapon shouldn't cost anything. r7522@kamatari (orig r2802): ennewalker | 2007-11-07 22:46:17 -0500 Randarts with no mods get one of (ac, ev, str, int, dex.) [1826417] r7525@kamatari (orig r2804): haranp | 2007-11-08 05:42:41 -0500 Enslaved fleeing monsters now flee towards you, not away from you. Hopefully fixes 1828086. r7527@kamatari (orig r2806): haranp | 2007-11-08 05:59:12 -0500 Integrated patch 1828014 (spell order). Also unbroke trunk build. Oops. r7529@kamatari (orig r2808): haranp | 2007-11-08 06:04:21 -0500 Typo fixes (dolorous, 1827992) r7530@kamatari (orig r2809): haranp | 2007-11-08 10:37:55 -0500 1822496: saprovore mutation shouldn't be given except at birth. r7531@kamatari (orig r2810): haranp | 2007-11-08 11:04:50 -0500 Some cleanup of evoke_wielded(), more to come. r7532@kamatari (orig r2811): j-p-e-g | 2007-11-08 11:10:47 -0500 Fix to intelligent friendlies avoiding traps. It actually works now. :) r7533@kamatari (orig r2812): haranp | 2007-11-08 11:13:34 -0500 Fix critical bug (in trunk only) with Shift-diring directional spells and show_beam set. (It would always go down.) r7534@kamatari (orig r2813): haranp | 2007-11-08 11:32:01 -0500 Fix 1824176: firing will now only ask for confirmation when you actually fire. r7536@kamatari (orig r2815): haranp | 2007-11-08 11:55:18 -0500 Fix for 1826891: x-examination reveals secret doors masquerading as non-rock walls. They will now masquerade (to 'x') as walls of whatever type is nearby. r7538@kamatari (orig r2817): haranp | 2007-11-08 12:29:39 -0500 Better secret door hiding (Darshan) r7540@kamatari (orig r2819): haranp | 2007-11-08 12:51:18 -0500 Handle tabs properly in Windows. r7542@kamatari (orig r2821): haranp | 2007-11-08 13:02:01 -0500 Fixed 1828326 (eol style on text files) r7543@kamatari (orig r2822): haranp | 2007-11-08 13:17:54 -0500 Added map dumping (to NAME.map) to the '#' key. The map dump doesn't include the hero (i.e., no '@' symbol.) r7544@kamatari (orig r2823): haranp | 2007-11-08 13:30:21 -0500 Better map dumping (Darshan) r7545@kamatari (orig r2824): haranp | 2007-11-08 13:31:51 -0500 Gah, yet another minor bugfix to dump_map (third time's the charm) r7555@kamatari (orig r2829): haranp | 2007-11-09 08:17:07 -0500 Draconian fighter fix for trunk. r7556@kamatari (orig r2830): haranp | 2007-11-09 08:27:57 -0500 Patch 1828418: fixed all weapons being generated badly (dolorous) r7557@kamatari (orig r2831): j-p-e-g | 2007-11-09 11:01:49 -0500 Another step on the way to smarter monsters, again on the topic of trap handling. Changes: * intelligent monsters native to a branch (elves in Elven Halls etc.) will try not to step on traps * highly intelligent monsters have a chance to avoid traps as well * intelligent monsters use an estimate of the expected damage of a trap (simple randomized amount) to decide whether to cross it I've left the half hpmax check in as well because... um, for historical reasons? r7558@kamatari (orig r2832): dshaligram | 2007-11-09 11:20:05 -0500 [1828918] Fixed shadow creatures producing permanent summons. r7559@kamatari (orig r2833): dshaligram | 2007-11-09 12:42:56 -0500 [1829067] Fixed mephitic cloud not setting enchantment owner correctly on affected monsters. r7562@kamatari (orig r2835): zelgadis | 2007-11-09 20:33:31 -0500 A cloud's spread rate now undergoes exponential decay as the cloud spreads. r7566@kamatari (orig r2838): haranp | 2007-11-10 19:29:28 -0500 Allow potions to be generated randomly (oops...) r7567@kamatari (orig r2839): j-p-e-g | 2007-11-11 11:29:05 -0500 Implementing FR 1829063: warning when putting on/removing items with a stat property that will be fatal. r7568@kamatari (orig r2840): haranp | 2007-11-11 15:40:56 -0500 Don't trim menu_colours [1829940]. Removed a lot of dead code and fixed some minor bugs in wanderer generation. r7569@kamatari (orig r2841): haranp | 2007-11-11 17:16:19 -0500 Removed brand from blowgun of the Assassin [1829597] r7570@kamatari (orig r2842): haranp | 2007-11-11 17:44:16 -0500 Added a message for Forescry renewal (if Condensation Shield gets it, Forescry should too) [1829000] Removed a whole lot of dead code; the place for dead code is in the svn repository, not the compilation unit. r7576@kamatari (orig r2843): zelgadis | 2007-11-12 01:09:15 -0500 Lua map markers can now be generated in C code from map_lua_marker::parse_marker() by prefixing the Lua string with "lua_mapless:" rather than "lua:". Fog machines can be created and placed from within C code via place_fog_machine(). r7577@kamatari (orig r2844): haranp | 2007-11-13 04:31:47 -0500 Corpses don't need identification [1830717] r7578@kamatari (orig r2845): haranp | 2007-11-13 05:27:08 -0500 Fog now makes poison and steam (5% chance of each) instead of the old 10% chance for miasma (Erik.) r7579@kamatari (orig r2846): zelgadis | 2007-11-13 07:33:41 -0500 The number of traps randomly generated on a level, and which types of traps are randomly selected, can now easily be controlled on a branch by branch basis (and for Pan and the Abyss), similar to how monster level and rarity is controlled (via function pointers in the Branch data structure). The same can be done for fog machines (though this feature isn't being used as of yet). r7580@kamatari (orig r2847): haranp | 2007-11-13 07:37:07 -0500 'q' (or Escape) when prompted for food on the floor now cancels out of eating completely, rather than moving to inventory. r7581@kamatari (orig r2848): haranp | 2007-11-13 07:57:26 -0500 Better Returning description [1830132] r7582@kamatari (orig r2849): j-p-e-g | 2007-11-13 10:57:55 -0500 * Add Cannibalism to list of forbidded actions for good gods. * Add simple warning message (god "did not appreciate that!") when using unID'd items that would otherwise be penalized. * Change protection from harm to be independent of prayer. r7583@kamatari (orig r2850): haranp | 2007-11-13 12:49:42 -0500 Bunch of changes: Removed unnecessary static_casts<> from branch.cc, improved messages a bit. Removed incorrect caps from entomb(). Changed ornate/legendary bonuses from percentages to flat power bonuses (+150 and +300 respectively.) Ensured at least one Nemelex gift by the time you get the first power. Changed probability of Nemelex liking a gift, made it dependent on piety. Fix warning in cloud.cc. r7584@kamatari (orig r2851): haranp | 2007-11-13 13:55:53 -0500 Made Tome of Destruction more consistent for those with high Evoc. Made manuals visibly different from spellbooks. Also, you can't cancel reading a manual; so you risk wasting it if you read all unIDed books. r7585@kamatari (orig r2852): haranp | 2007-11-13 14:26:05 -0500 Dissection no longer requires confirmation if there is only one corpse on the square. r7586@kamatari (orig r2853): j-p-e-g | 2007-11-14 17:17:44 -0500 s/Ogre Mage/Ogre-Mage and beholding should not allow swapping with friendlies (Bug 1739619). r7588@kamatari (orig r2855): dshaligram | 2007-11-15 06:11:04 -0500 Fixed stash-tracker seeing through walls (it was using stale LOS after blink/teleport), fixed shadow creatures crash in labyrinths, and fixed use of displayed stair glyph for handling selection of monsters placed on stairs (display glyphs can be changed by the user). r7590@kamatari (orig r2857): haranp | 2007-11-15 17:06:31 -0500 Added an option, always_confirm_butcher. r7591@kamatari (orig r2858): zelgadis | 2007-11-16 03:18:15 -0500 M_AMPHIBIOUS now means both "land creature can swim through deep water" *and* "deep water creature can walk on land". Most of the supporting features neccessary for the "earth worm" FR [1766532] have been implemented, except for "fleeing towards walls". However, no work has yet been done to update the monster AI to work well when a monster is fighting an earth worm. r7592@kamatari (orig r2859): haranp | 2007-11-16 03:52:19 -0500 Removed: safe_autopickup, safe_zero_exp, lowercase_invocations, always_greet, terse_hand, increasing_skill_progress, use_notes, confirm_self_target. (default_autoprayer still exists.) r7593@kamatari (orig r2860): haranp | 2007-11-16 04:29:27 -0500 Added Crusade card: conversion/abjuration effect. r7594@kamatari (orig r2861): dshaligram | 2007-11-17 09:05:30 -0500 Updated CREDITS. r7596@kamatari (orig r2863): dshaligram | 2007-11-17 13:28:35 -0500 Fixed buggy Xom mutation handling. r7598@kamatari (orig r2865): dshaligram | 2007-11-17 13:56:43 -0500 Fixed bad shadow creatures summons when climbing with the Orb (bobbens). r7600@kamatari (orig r2867): dshaligram | 2007-11-18 05:08:39 -0500 [1833936] Fixed ASSERT in monster blink checks. r7601@kamatari (orig r2868): dshaligram | 2007-11-18 05:33:01 -0500 [1833959] Fixed broken digging beams. r7602@kamatari (orig r2869): dshaligram | 2007-11-18 05:36:11 -0500 Kill hard tabs. r7603@kamatari (orig r2870): j-p-e-g | 2007-11-18 19:44:33 -0500 Fix a net bug that was responsible for never (!) entrapping monsters. Whoops... Also autoID a weapon of returning the player actually sees returning. (Bug 1830129) r7605@kamatari (orig r2872): j-p-e-g | 2007-11-19 09:08:58 -0500 A number of tutorial improvements, including reintroducing info on spellbooks. Also: Fix 1832819. (Horn mutation not making helmet slot show as "restricted") Fix 1831983. (Autobutcher now ignores weapons inscribed with !w) r7607@kamatari (orig r2874): j-p-e-g | 2007-11-19 19:14:41 -0500 Clean-up of options in init.txt and crawl_options.txt courtesy of maiermirk (1829976, 1831190). This includes a lot of spacing changes, updates of some examples and moving around some options into more sensible groupings. Highlights: * add returning weapons to fire_order list and allow fire_order to use += on new lines (This should solve the second part of 1829475.) * heap_brand now defaults to "reverse" * detected_item_colour defaults to green Also s/artifact/artefact. r7609@kamatari (orig r2876): ennewalker | 2007-11-19 22:28:50 -0500 Extraneous up stairs on dungeon level 1 are confusing to new users. Removing the generation of extra up stairs there. r7610@kamatari (orig r2877): dolorous | 2007-11-19 22:35:47 -0500 Add various patches of mine: [1824221] don't give Yred-worshipping demonspawn the "raise dead" mutation [1829258] remove wrongly hardcoded exp-draining resistance for undead [1829691] typo fixes [1830030] clean up random god servant handling [1829890] fix divine retribution messages, generalize berserker summoning r7611@kamatari (orig r2878): dolorous | 2007-11-19 23:27:38 -0500 check for ghouls' eating ghouls in is_player_same_species() r7612@kamatari (orig r2879): dolorous | 2007-11-20 00:16:17 -0500 since Yred's "Animate Corpse" ability can overlap with the "raise dead" demonspawn mutation to an extent, don't allow Yred-worshipping demonspawn to get it regardless of piety r7614@kamatari (orig r2881): dolorous | 2007-11-20 01:27:45 -0500 for consistency, tweak Vehumet's starting message to mention his name r7615@kamatari (orig r2882): dshaligram | 2007-11-20 07:19:31 -0500 Fall back to ASCII if Unicode locale is unavailable (Guus). Also queue up startup error messages and display them before the newgame screen instead of emitting them to stderr. r7616@kamatari (orig r2883): dshaligram | 2007-11-20 07:28:36 -0500 Fix gcc optimising away overflow check (Guus). r7617@kamatari (orig r2884): j-p-e-g | 2007-11-20 07:36:35 -0500 A few changes to shafts: * shafts cannot be created above level 3 in the main dungeon * intelligent fleeing monsters will jump into shafts -> this will reveal the shaft to the player * rename "shaft trap" to "shaft" * ask for confirmation before stepping into a shaft Also finally fix colour from post-death inventory bleeding into the highscore and prompt. (This has always bugged me.) r7618@kamatari (orig r2885): dshaligram | 2007-11-20 08:36:42 -0500 Allow UNICODE_LOCALE=. in makefile.unix to specify a setlocale(LC_ALL,"") call instead of forcing a specific locale (adapted from Guus' Debian patch). Also fixed some makefile.unix checks to strip variables that are prone to trailing spaces. r7619@kamatari (orig r2886): dolorous | 2007-11-20 12:27:27 -0500 expand the special case for kobold fighters (leather armor, darts, etc.) to include halfling and gnome fighters too, as they have similar aptitudes; plus, they're worse with Armour skill than kobolds, so getting the fighter default of scale mail is disadvantageous r7620@kamatari (orig r2887): ennewalker | 2007-11-21 00:11:31 -0500 Fixing [1832064] stair bug. Added a cleanup function to ensure that there is at most one stone stair of each type on the level. r7621@kamatari (orig r2888): j-p-e-g | 2007-11-21 08:29:21 -0500 Finally include Ely piety gain from Destroy Weapon depending on both current piety and item value. (Only in 0.3 up to now. Whoops.) And make "evil" weapons (demonic, vampiric, pain, draining) always give piety when destroyed. (FR1832851) r7622@kamatari (orig r2889): dolorous | 2007-11-21 09:19:35 -0500 [1829667]: use c_getch() to get input for all the new-game menus, since they only get CK_* values (which c_getch(), but not getch(), returns under Unix) and single-byte characters (which c_getch() and getch() can handle as well as get_ch()); this is untested under Windows, but it should work, since the tutorial code uses the same technique r7623@kamatari (orig r2890): dolorous | 2007-11-21 20:40:14 -0500 make player::has_claws() return an int indicating the level of claws available; this removes the need for some special cases dealing with trolls' and ghouls' built-in claws r7624@kamatari (orig r2891): dolorous | 2007-11-21 21:36:43 -0500 make player::has_claws() and player::has_usable_claws() take a bool indicating whether claws from transformations should be taken into account; this removes the need for more special cases dealing with trolls' and ghouls' built-in claws r7625@kamatari (orig r2892): dolorous | 2007-11-21 23:05:26 -0500 Add minor cleanups of divine protection from harm: * move the list of gods that do it into the function god_protects_from_harm(), instead of hardcoding the list in two places * update the description of it, both in the code and the surrounding comments, since it no longer depends on prayer, and since it can now happen with piety less than 30 r7627@kamatari (orig r2893): j-p-e-g | 2007-11-22 07:07:18 -0500 Don't put players under penance for harming friendlies (or holy monsters) by reading an unID'd ?immolation (1834837). You will still lose piety for such an action, though. r7628@kamatari (orig r2894): ennewalker | 2007-11-22 09:50:10 -0500 Fixing assertion in monsters::pickup_armour when forcibly giving monsters unsupported equipment. r7629@kamatari (orig r2895): ennewalker | 2007-11-22 11:08:27 -0500 Fixing assertion from SUMMON_DRAKES trying to fire an invalid bolt. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/branches/stone_soup-0.3@2897 c06c8d41-db1a-0410-9941-cceddc491573
-rw-r--r--crawl-ref/CREDITS39
-rw-r--r--crawl-ref/INSTALL16
-rw-r--r--crawl-ref/docs/crawl_manual.txt16
-rw-r--r--crawl-ref/docs/crawl_options.txt1432
-rw-r--r--crawl-ref/docs/level-design.txt1041
-rw-r--r--crawl-ref/docs/tables.txt3
-rw-r--r--crawl-ref/init.txt123
-rw-r--r--crawl-ref/source/AppHdr.h7
-rw-r--r--crawl-ref/source/Crawl.xcodeproj/project.pbxproj50
-rw-r--r--crawl-ref/source/FixAry.h2
-rw-r--r--crawl-ref/source/abl-show.cc61
-rw-r--r--crawl-ref/source/abyss.cc161
-rw-r--r--crawl-ref/source/acr.cc1211
-rw-r--r--crawl-ref/source/beam.cc268
-rw-r--r--crawl-ref/source/beam.h5
-rw-r--r--crawl-ref/source/branch.cc204
-rw-r--r--crawl-ref/source/branch.h31
-rw-r--r--crawl-ref/source/chardump.cc4
-rw-r--r--crawl-ref/source/cio.cc17
-rw-r--r--crawl-ref/source/cio.h2
-rw-r--r--crawl-ref/source/cloud.cc240
-rw-r--r--crawl-ref/source/cloud.h42
-rw-r--r--crawl-ref/source/clua.cc51
-rw-r--r--crawl-ref/source/clua.h2
-rw-r--r--crawl-ref/source/command.cc504
-rw-r--r--crawl-ref/source/command.h3
-rw-r--r--crawl-ref/source/dat/bazaar.des76
-rw-r--r--crawl-ref/source/dat/clua/lm_1way.lua2
-rw-r--r--crawl-ref/source/dat/clua/lm_flags.lua347
-rw-r--r--crawl-ref/source/dat/clua/lm_fog.lua184
-rw-r--r--crawl-ref/source/dat/clua/lm_pdesc.lua6
-rw-r--r--crawl-ref/source/dat/clua/luamark.lua2
-rw-r--r--crawl-ref/source/dat/descript/features.txt14
-rw-r--r--crawl-ref/source/dat/descript/monsters.txt91
-rw-r--r--crawl-ref/source/dat/descript/spells.txt2
-rw-r--r--crawl-ref/source/dat/glass.des153
-rw-r--r--crawl-ref/source/dat/lab.des24
-rw-r--r--crawl-ref/source/dat/large.des5
-rw-r--r--crawl-ref/source/dat/levdes.vim26
-rw-r--r--crawl-ref/source/dat/speak.txt6
-rw-r--r--crawl-ref/source/database.cc81
-rw-r--r--crawl-ref/source/database.h17
-rw-r--r--crawl-ref/source/debug.cc555
-rw-r--r--crawl-ref/source/debug.h2
-rw-r--r--crawl-ref/source/decks.cc1180
-rw-r--r--crawl-ref/source/decks.h98
-rw-r--r--crawl-ref/source/defines.h17
-rw-r--r--crawl-ref/source/delay.cc185
-rw-r--r--crawl-ref/source/describe.cc406
-rw-r--r--crawl-ref/source/describe.h2
-rw-r--r--crawl-ref/source/dgnevent.cc13
-rw-r--r--crawl-ref/source/dgnevent.h28
-rw-r--r--crawl-ref/source/direct.cc211
-rw-r--r--crawl-ref/source/dungeon.cc645
-rw-r--r--crawl-ref/source/dungeon.h9
-rw-r--r--crawl-ref/source/effects.cc341
-rw-r--r--crawl-ref/source/effects.h18
-rw-r--r--crawl-ref/source/enum.h249
-rw-r--r--crawl-ref/source/externs.h113
-rw-r--r--crawl-ref/source/fight.cc247
-rw-r--r--crawl-ref/source/fight.h3
-rw-r--r--crawl-ref/source/files.cc59
-rw-r--r--crawl-ref/source/food.cc378
-rw-r--r--crawl-ref/source/food.h2
-rw-r--r--crawl-ref/source/format.cc42
-rw-r--r--crawl-ref/source/format.h3
-rw-r--r--crawl-ref/source/ghost.cc3
-rw-r--r--crawl-ref/source/hiscores.cc50
-rw-r--r--crawl-ref/source/initfile.cc121
-rw-r--r--crawl-ref/source/invent.cc9
-rw-r--r--crawl-ref/source/invent.h5
-rw-r--r--crawl-ref/source/it_use2.cc108
-rw-r--r--crawl-ref/source/it_use2.h2
-rw-r--r--crawl-ref/source/it_use3.cc437
-rw-r--r--crawl-ref/source/it_use3.h8
-rw-r--r--crawl-ref/source/item_use.cc450
-rw-r--r--crawl-ref/source/item_use.h12
-rw-r--r--crawl-ref/source/itemname.cc86
-rw-r--r--crawl-ref/source/itemname.h1
-rw-r--r--crawl-ref/source/itemprop.cc74
-rw-r--r--crawl-ref/source/itemprop.h14
-rw-r--r--crawl-ref/source/items.cc317
-rw-r--r--crawl-ref/source/items.h9
-rw-r--r--crawl-ref/source/lev-pand.cc5
-rw-r--r--crawl-ref/source/libdos.cc2
-rw-r--r--crawl-ref/source/libunix.cc15
-rw-r--r--crawl-ref/source/libutil.cc3
-rw-r--r--crawl-ref/source/libutil.h7
-rw-r--r--crawl-ref/source/libw32c.cc1
-rw-r--r--crawl-ref/source/lua/eat.lua6
-rw-r--r--crawl-ref/source/lua/safechnk.lua8
-rw-r--r--crawl-ref/source/luadgn.cc663
-rw-r--r--crawl-ref/source/luadgn.h2
-rw-r--r--crawl-ref/source/macro.cc193
-rw-r--r--crawl-ref/source/macro.h36
-rw-r--r--crawl-ref/source/makefile.obj4
-rw-r--r--crawl-ref/source/makefile.unix42
-rw-r--r--crawl-ref/source/makeitem.cc3588
-rw-r--r--crawl-ref/source/makeitem.h2
-rw-r--r--crawl-ref/source/mapdef.cc105
-rw-r--r--crawl-ref/source/mapdef.h50
-rw-r--r--crawl-ref/source/mapmark.cc57
-rw-r--r--crawl-ref/source/mapmark.h3
-rw-r--r--crawl-ref/source/menu.cc20
-rw-r--r--crawl-ref/source/menu.h10
-rw-r--r--crawl-ref/source/message.cc19
-rw-r--r--crawl-ref/source/misc.cc315
-rw-r--r--crawl-ref/source/misc.h13
-rwxr-xr-xcrawl-ref/source/misc/build_dcss_release.rb41
-rw-r--r--crawl-ref/source/mon-data.h3234
-rw-r--r--crawl-ref/source/mon-pick.cc157
-rw-r--r--crawl-ref/source/mon-pick.h1
-rw-r--r--crawl-ref/source/mon-util.cc498
-rw-r--r--crawl-ref/source/mon-util.h34
-rw-r--r--crawl-ref/source/monplace.cc65
-rw-r--r--crawl-ref/source/monplace.h3
-rw-r--r--crawl-ref/source/monstuff.cc854
-rw-r--r--crawl-ref/source/mstuff2.cc95
-rw-r--r--crawl-ref/source/mtransit.cc2
-rw-r--r--crawl-ref/source/mtransit.h2
-rw-r--r--crawl-ref/source/mutation.cc506
-rw-r--r--crawl-ref/source/mutation.h7
-rw-r--r--crawl-ref/source/newgame.cc420
-rw-r--r--crawl-ref/source/notes.h2
-rw-r--r--crawl-ref/source/ouch.cc73
-rw-r--r--crawl-ref/source/output.cc165
-rw-r--r--crawl-ref/source/overmap.cc150
-rw-r--r--crawl-ref/source/overmap.h12
-rw-r--r--crawl-ref/source/place.cc7
-rw-r--r--crawl-ref/source/place.h2
-rw-r--r--crawl-ref/source/player.cc770
-rw-r--r--crawl-ref/source/player.h23
-rw-r--r--crawl-ref/source/prebuilt/levcomp.lex.cc3234
-rw-r--r--crawl-ref/source/prebuilt/levcomp.tab.cc1760
-rw-r--r--crawl-ref/source/prebuilt/levcomp.tab.h143
-rw-r--r--crawl-ref/source/randart.cc233
-rw-r--r--crawl-ref/source/randart.h66
-rw-r--r--crawl-ref/source/religion.cc655
-rw-r--r--crawl-ref/source/religion.h17
-rw-r--r--crawl-ref/source/shopping.cc10
-rw-r--r--crawl-ref/source/skills2.cc10
-rw-r--r--crawl-ref/source/spells1.cc86
-rw-r--r--crawl-ref/source/spells1.h5
-rw-r--r--crawl-ref/source/spells2.cc103
-rw-r--r--crawl-ref/source/spells2.h5
-rw-r--r--crawl-ref/source/spells3.cc299
-rw-r--r--crawl-ref/source/spells4.cc439
-rw-r--r--crawl-ref/source/spells4.h6
-rw-r--r--crawl-ref/source/spl-book.cc9
-rw-r--r--crawl-ref/source/spl-cast.cc53
-rw-r--r--crawl-ref/source/spl-data.h16
-rw-r--r--crawl-ref/source/spl-util.cc90
-rw-r--r--crawl-ref/source/spl-util.h8
-rw-r--r--crawl-ref/source/sqldbm.cc64
-rw-r--r--crawl-ref/source/sqldbm.h9
-rw-r--r--crawl-ref/source/stash.cc7
-rw-r--r--crawl-ref/source/state.cc367
-rw-r--r--crawl-ref/source/state.h100
-rw-r--r--crawl-ref/source/store.cc1624
-rw-r--r--crawl-ref/source/store.h402
-rw-r--r--crawl-ref/source/stuff.cc57
-rw-r--r--crawl-ref/source/stuff.h5
-rw-r--r--crawl-ref/source/tags.cc121
-rw-r--r--crawl-ref/source/tags.h2
-rw-r--r--crawl-ref/source/terrain.cc23
-rw-r--r--crawl-ref/source/terrain.h5
-rw-r--r--crawl-ref/source/transfor.cc72
-rw-r--r--crawl-ref/source/traps.cc310
-rw-r--r--crawl-ref/source/traps.h21
-rw-r--r--crawl-ref/source/travel.cc7
-rw-r--r--crawl-ref/source/tutorial.cc7
-rw-r--r--crawl-ref/source/unrand.h2
-rw-r--r--crawl-ref/source/util/levcomp.lpp5
-rw-r--r--crawl-ref/source/util/levcomp.ypp55
-rw-r--r--crawl-ref/source/version.h6
-rw-r--r--crawl-ref/source/view.cc246
-rw-r--r--crawl-ref/source/view.h25
-rw-r--r--crawl-ref/source/xom.cc250
-rw-r--r--crawl-ref/source/xom.h43
179 files changed, 24620 insertions, 11837 deletions
diff --git a/crawl-ref/CREDITS b/crawl-ref/CREDITS
index 6976aff2c6..4f1317bf9f 100644
--- a/crawl-ref/CREDITS
+++ b/crawl-ref/CREDITS
@@ -1,6 +1,6 @@
The Dungeon Crawl Stone Soup team (Peter Berger, Matthew Cline, Nat Lanza,
-Haran Pilpel, David Ploog, Johanna Ploog, Darshan Shaligram) would like to
-thank:
+Haran Pilpel, David Ploog, Johanna Ploog, David Lawrence Ramsey,
+Darshan Shaligram, Enne Walker) would like to thank:
* Linley Henzell, the author of Dungeon Crawl, for writing this great game.
@@ -14,21 +14,20 @@ thank:
We'd also like to thank members of the Dungeon Crawl community who have
contributed to Dungeon Crawl Stone Soup:
-Warwick Allison Ilyak Lemuel Pitkin
-Juha Arpiainen Mitsuhiro Itakura David Lawrence Ramsey
-Roy Axenov Eino Keskitalo Remsleep
-Alexander Beisig Jarmo Kielosto David Rose
-Erik Inge Bolsø Kornel Kisielewicz Sebastian Salman
-Peter Borgmann Ryan Kusnery Brett Scarborough
-Rachel Elizabeth Dillon Jukka Kuusisto Roman Sêk
-Dylan O'Donnell Jordan Lewis Sigurd
-Jesse Luehrs Icy Lich Edgar Simo
-Mike Drinen Arien Malec Solf
-Kieron Dunbar Shawn M Moore Johan Strandell
-Elethiomel Eva Myers Marc H. Thoben
-Christopher Evenstar Onia Ninara Matt Titus
-Ben Goetter Erkki Nurmi Enne Walker
-Ciaran Hamilton nyra Steven Wheeler
-Chris Hamons Yuuma Oohara Jeremey Wilson
-R. Dan Henry Pedro Zooko
-Benoit Hudson Erik Piper
+Warwick Allison Benoit Hudson Pedro
+Juha Arpiainen Ilyak Erik Piper
+Roy Axenov Mitsuhiro Itakura Lemuel Pitkin
+Alexander Beisig Eino Keskitalo Remsleep
+Erik Inge Bolsø Jarmo Kielosto David Rose
+Peter Borgmann Kornel Kisielewicz Sebastian Salman
+Rachel Elizabeth Dillon Ryan Kusnery Brett Scarborough
+Dylan O'Donnell Jukka Kuusisto Roman Sêk
+Jesse Luehrs Jordan Lewis Sigurd
+Mike Drinen Icy Lich Edgar Simo
+Kieron Dunbar Arien Malec Solf
+Elethiomel Shawn M Moore Johan Strandell
+Christopher Evenstar Eva Myers Marc H. Thoben
+Ben Goetter Onia Ninara Matt Titus
+Ciaran Hamilton Erkki Nurmi Steven Wheeler
+Chris Hamons nyra Jeremey Wilson
+R. Dan Henry Yuuma Oohara Zooko
diff --git a/crawl-ref/INSTALL b/crawl-ref/INSTALL
index 871eadf95d..f33a79a896 100644
--- a/crawl-ref/INSTALL
+++ b/crawl-ref/INSTALL
@@ -50,15 +50,8 @@ Stone Soup 0.3 includes Lua 5.1.2 in its source tree. Crawl uses Lua
for dungeon generation. In addition, Crawl has a (rudimentary) Lua
interface for users to run scripts which can do things such as
conditionalise parts of the .crawlrc/init.txt. Such user Lua scripts
-are enabled by default on DOS and Windows, but can be turned off by
-editing your makefile and removing -DCLUA_BINDINGS from the compiler
-flags.
-
-User scripts are not enabled by default on Unix since the stock
-makefile installs Crawl setgid, and the Lua scripting interface has
-not been audited for setgid security. See the full section on Lua for
-more details. For non-privileged installs, you can enable Lua user
-scripts as described in the build instructions.
+are enabled by default, but can be turned off by removing
+-DCLUA_BINDINGS from your makefile.
Unicode support needs libncursesw and its header files; these are
usually available in your operating system's package-management
@@ -368,7 +361,4 @@ not UTF-8, you can force it to UTF-8 on most systems by doing "export
LC_ALL=en_US.UTF-8" or the equivalent, depending on your language
locale and what shell you're using.
-If you're playing Crawl on a remote machine, the remote Crawl should be
-built with Unicode support, it needs to have a UTF-8 locale installed,
-*and* your local terminal (where you're running telnet/ssh) needs to be
-able to decode UTF-8.
+able to decode UTF-8. \ No newline at end of file
diff --git a/crawl-ref/docs/crawl_manual.txt b/crawl-ref/docs/crawl_manual.txt
index 343f88fb29..0a761423c1 100644
--- a/crawl-ref/docs/crawl_manual.txt
+++ b/crawl-ref/docs/crawl_manual.txt
@@ -186,7 +186,7 @@ Strength: Affects the amount of damage you do in combat, as well as
Intelligence: Affects how well you can cast spells as well as how much
------------- nutrition spellcasting takes. Your ability to use some
- magical items is also influence by your intelligence.
+ magical items is also influenced by your intelligence.
Dexterity: Affects your accuracy in combat, your ability to dodge
---------- attacks aimed at you, your general effectiveness with
@@ -2160,6 +2160,11 @@ Other game-playing commands:
Ctrl-A Toggle autopickup. Note that encounters with
invisible monsters always turns autopickup off.
You need to switch it on with Ctrl-A afterwards.
+ Ctrl-V Toggle autoprayer. Note that encounters with
+ invisible monsters always turns autopickup off.
+ You need to switch it on with Ctrl-V afterwards.
+ ` Re-do previous command
+ 0 Repeat next command a given number of times
Non-game playing commands:
? The help menu.
@@ -2170,8 +2175,11 @@ Non-game playing commands:
# Dump character to file (name.txt).
: Add note to dump file (see option take_notes).
?: Read the notes in-game.
+ ?/ Describe a monster, spell or feature. You can
+ enter a partial name or a regex instead of the
+ full name.
~ Add or save macros and key mappings.
- = Reassign inventory/spell/abilities letters.
+ = Reassign inventory/spell/abilities letters.
Stashes:
Ctrl-F Find. This searches in stashes and shops, you
@@ -2181,6 +2189,9 @@ Stashes:
a seach for 'Trog' etc. works. If all items are
stashed (the default), then a string like 'D:13'
will list all known items on that level.
+ 'D:1}' will search for items on level 1 only,
+ as opposed to 'D:1', which will also list items
+ on D:10 through D:19.
Once the list of all found places is displayed,
you can cause auto-travel to go there (press the
associated letter) or you can examine the items
@@ -2217,6 +2228,7 @@ level_map_title option to get rid of that.
/ Cycles backward through stashes.
Ctrl-C Clear level and main maps (from temporarily
seen monsters, clouds etc.).
+ Ctrl-F Forget level map.
Waypoints can be set on the level map. You can travel to waypoints
using Ctrl-G. Check the option show_waypoints. The commands are
diff --git a/crawl-ref/docs/crawl_options.txt b/crawl-ref/docs/crawl_options.txt
index 7ff415d19c..a69309f5ad 100644
--- a/crawl-ref/docs/crawl_options.txt
+++ b/crawl-ref/docs/crawl_options.txt
@@ -1,8 +1,8 @@
-This document explains all of the options in the latest version of Dungeon
-Crawl Stone Soup. These options are set in the init.txt file located in the
-Crawl directory (the directory containing crawl.exe on Windows and DOS). On
-Unix systems, you need to set options in the ~/.crawlrc file (a file named
-.crawlrc in your home directory).
+This document explains all of the options in the latest version of
+Dungeon Crawl Stone Soup. These options are set in the init.txt file
+located in the Crawl directory (the directory containing crawl.exe on
+Windows and DOS). On Unix systems, you need to set options in the
+~/.crawlrc file (a file named .crawlrc in your home directory).
The contents of this text are:
@@ -14,24 +14,23 @@ The contents of this text are:
crawl_dir, morgue_dir, save_dir, sound
3- Lua files.
lua_file,
- base.lua, stash.lua, wield.lua, kills.lua, runrest.lua,
- gearset.lua, eat.lua, pickup.lua, trapwalk.lua
+ base.lua, stash.lua, wield.lua, kills.lua,
+ runrest.lua, gearset.lua, eat.lua, pickup.lua,
+ trapwalk.lua
4- Interface.
4-a Dropping and Picking up.
autopickup, autopickup_exceptions, default_autopickup,
- safe_autopickup, autopickup_no_burden, safe_zero_exp,
- pickup_thrown, pickup_dropped, assign_item_slot,
- drop_mode, pickup_mode, drop_filter
+ autopickup_no_burden, pickup_thrown, pickup_dropped,
+ assign_item_slot, drop_mode, pickup_mode, drop_filter
4-b Targeting.
target_zero_exp, target_oos, target_los_first,
- confirm_self_target, default_target,
- target_unshifted_dirs
+ default_target, target_unshifted_dirs
4-c Passive Sightings (Detection and Remembrance).
detected_monster_colour, detected_item_colour,
remembered_monster_colour, colour_map, clean_map
4-d Branding (Item and Monster Highlighting).
- heap_brand, friend_brand, stab_brand, may_stab_brand,
- stair_item_brand, trap_item_brand
+ friend_brand, stab_brand, may_stab_brand,
+ heap_brand, stair_item_brand, trap_item_brand
4-e Level Map Functions.
level_map_cursor_step, level_map_title, item_colour
4-f Viewport Display Options.
@@ -41,33 +40,32 @@ The contents of this text are:
scroll_margin
4-g Travel and Exploration.
travel_delay, travel_avoid_terrain,
- travel_stop_message, explore_greedy, explore_stop,
- runrest_ignore_message, runrest_ignore_poison,
- runrest_ignore_monster,
- trapwalk_safe_hp, tc_reachable,
- tc_dangerous, tc_excluded, tc_exclude_circle
+ explore_greedy, explore_stop, tc_reachable,
+ tc_dangerous, tc_excluded, tc_exclude_circle,
+ travel_stop_message, runrest_ignore_message,
+ runrest_ignore_poison, runrest_ignore_monster,
+ trapwalk_safe_hp
4-h Stashes.
stash_tracking, stash_filter
4-i Command Enhancements.
- auto_list, lowercase_invocations, easy_open, easy_butcher,
- easy_unequip, easy_confirm, easy_quit_item_prompts,
- easy_exit_menu, default_autoprayer, sort_menus
+ auto_list, easy_open, easy_unequip, easy_confirm,
+ easy_butcher, always_confirm_butcher,
+ easy_quit_item_prompts, easy_exit_menu,
+ default_autoprayer, sort_menus
4-j Message and Display Improvements.
- hp_warning, mp_warning, hp_colour, mp_colour, always_greet,
- terse_hand, delay_message_clear, menu_colour,
- menu_colour_prefix_id, menu_colour_prefix_class
- message_colour, increasing_skill_progress,
+ hp_warning, mp_warning, hp_colour, mp_colour,
+ delay_message_clear, message_colour,
show_inventory_weights, show_turns, show_beam,
- item_stack_summary_minimum
+ item_stack_summary_minimum, menu_colour,
+ menu_colour_prefix_id, menu_colour_prefix_class
4-k Missiles.
fire_items_start, fire_order
4-l Message Channels.
plain, prompt, god, pray, duration, danger, food, warning,
recovery, talk, talk_visual, intrinsic_gain, mutation,
- monster_spell, monster_enchant, monster_damage, rotten_meat,
- equipment, floor, multiturn, examine, examine_filter,
- diagnostics, tutorial
-
+ monster_spell, monster_enchant, monster_damage,
+ rotten_meat, equipment, floor, multiturn, examine,
+ examine_filter, diagnostics, tutorial
4-m Inscriptions.
autoinscribe
4-n Macro related Options.
@@ -77,14 +75,15 @@ The contents of this text are:
kill_map, dump_kill_places, dump_item_origins,
dump_item_origin_price, dump_message_count, dump_order
5-b Notes.
- use_notes, note_items, ood_interesting, note_hp_percent,
- note_skill_levels, note_skill_max, note_monsters,
- note_messages, note_all_spells
+ note_items, note_monsters, ood_interesting,
+ note_hp_percent, note_skill_levels,
+ note_all_skill_levels, note_skill_max, note_all_spells,
+ note_messages
6- Miscellaneous.
6-a All OS.
- macro_meta_entry, mouse_input, wiz_mode, colours,
- char_set, cset_ascii, cset_ibm, cset_dec, cset_unicode,
- feature, mon_glyph, classic_item_colours
+ macro_meta_entry, mouse_input, wiz_mode, use_ascii,
+ classic_item_colours, colours, char_set, cset_ascii,
+ cset_ibm, cset_dec, cset_unicode, feature, mon_glyph
6-b DOS and Windows.
dos_use_background_intensity
6-c Unix
@@ -131,46 +130,49 @@ For long option names, you can define option aliases by doing:
For instance, you can use:
ae := autopickup_exceptions
and thereafter use "ae" instead of "autopickup_exceptions":
- ae = >decay, >degeneration
+ ae = >uselessness, >inaccuracy
+
+If you get stuck or some things just won't seem to work properly,
+please ask for help on the newsgroup rec.games.roguelike.misc. Please
+flag queries with '-crawl-', as other roguelikes are also discussed
+there.
-If you get stuck or some things just won't seem to work properly, please ask
-for help on the newsgroup rec.games.roguelike.misc. Please flag queries with
-'-crawl-', as other roguelikes are also discussed there.
1- Starting Screen.
====================
-The following options are a convenience to help you quickly start your game of
-Crawl.
+The following options are a convenience to help you quickly start your
+game of Crawl.
name = Delilah
If set, that's the name all your Crawl characters will get.
-remember_name = false
- Crawl remembers the options (class, race etc.) you used to create your
- last character. You may recycle them in the starting screen for a new
- character. If this option is set to true, Crawl will also remember the
- last name you used.
+remember_name = true
+ Crawl remembers the options (class, race etc.) you used to
+ create your last character. You may recycle them in the
+ starting screen for a new character. If this option is set to
+ true, Crawl will also remember the last name you used.
- If you use this option and want to enter a name _after_ choosing your
- race and class, you must enter . at the initial name prompt - hitting
- Enter at the name prompt will simply reuse your old name if
- remember_name is set.
+ If you use this option and want to enter a name _after_
+ choosing your race and class, you must enter . at the initial
+ name prompt - hitting Enter at the name prompt will simply
+ reuse your old name if remember_name is set.
weapon = (random | short sword | hand axe | spear | mace | trident)
- Specifying the weapon option allows you to bypass the weapon selection
- screen. Note that tridents are restricted to only merfolk and
- gladiators, but you'll get the standard query in illegal cases.
+ Specifying the weapon option allows you to bypass the weapon
+ selection screen. Note that tridents are restricted to only
+ merfolk and gladiators, but you'll get the standard query in
+ illegal cases.
book = (flame | fire | ice | cold | summ | summoning | random)
- Several spellcasting classes can choose their starting spellbook.
- Note flame=fire and ice=cold and summ=summoning.
+ Several spellcasting classes can choose their starting
+ spellbook. Note flame=fire and ice=cold and summ=summoning.
chaos_knight = (Xom | Makhleb | random)
death_knight = (necromancy | Yredelemnul | random)
-priest = (Zin | Yredelemnul | Beogh | random)
+priest = (Zin | Yredelemnul | Beogh | random)
The above three make in advance the additional choices for
Chaos Knights, Death Knights, and Priests (Beogh for HO only).
@@ -182,33 +184,33 @@ class = (Fighter |...| Wanderer | random)
random_pick = false
The random_pick option will randomly generate a character.
- The above options (weapons and class options) will override where
- appropriate.
+ The above options (weapons and class options) will override
+ where appropriate.
2- File System.
================
crawl_dir = <path>
- Directory for reading macro.txt and init.txt, and dumping characters.
+ Directory for reading macro.txt.
It should end with the path delimiter.
morgue_dir = morgue
- Directory where morgue dumps (morgue*.txt and morgue*.lst) files are
- written.
+ Directory where morgue dumps files (morgue*.txt and
+ morgue*.lst) as well as character dumps files are written.
save_dir = saves
- Directory where saves and bones are stored. This option may be ignored
- depending on the settings used to compile Crawl, but should be
- honoured for the official Crawl binaries.
+ Directory where saves and bones are stored. This option may be
+ ignored depending on the settings used to compile Crawl, but
+ should be honoured for the official Crawl binaries.
sound = <regex>:<path to sound file>
- Plays the sound file if a message contains regex. The regex should
- not include commas or colons. For example
- sound = LOW HITPOINT WARNING:sound\sounds2\danger3.wav
+ Plays the sound file if a message contains regex. The regex
+ should not include commas or colons. For example
+ sound = LOW HITPOINT WARNING:sound\sounds2\danger3.wav
Getting appropriate sound files may be difficult. Check other
- roguelikes or old computer RPGs. Alternatively, ask for help in
- the newsgroup rec.games.roguelike.misc.
+ roguelikes or old computer RPGs. Alternatively, ask for help
+ in the newsgroup rec.games.roguelike.misc.
3- Lua files.
@@ -225,22 +227,27 @@ Lua files are included using the lua_file option (one file per line):
lua_file = <path/name.lua>
The available stock Lua scripts are
- stash.lua -- annotates the stash file for better searching (Ctrl-F)
- Searching for 'Long blades' will also turn up all weapons
- with the long blade skill. Similarly, you can use 'altar',
- 'portal' etc. Also, you can look for spellbooks ('book'),
- artifacts ('artifact'), and ego items ('ego').
+ stash.lua -- annotates the stash file for better searching
+ (Ctrl-F). Searching for 'Long blades' will also turn
+ up all weapons with the long blade skill. Similarly,
+ you can use 'altar','portal' etc. Also, you can look
+ for spellbooks ('book'), artefacts ('artefact'), and
+ ego items ('ego').
wield.lua -- shows more intelligent options when using 'w?'
kills.lua -- improves the Vanquished Creatures list in dump files;
- currently gives three lists (Vanquished, Friendly, Others)
- runrest.lua -- allows overriding certain stop conditions when running
- New options: runrest_ignore_poison, runrest_ignore_message,
- runrest_ignore_monster
- gearset.lua -- provides commands for switching of complete sets via macro
+ currently gives three lists (Vanquished, Friendly,
+ Others)
+ runrest.lua -- allows overriding certain stop conditions when
+ running
+ New options: runrest_ignore_poison,
+ runrest_ignore_message, runrest_ignore_monster
+ gearset.lua -- provides commands for switching of complete sets via
+ macro
New macroable functions: rememberkit, swapkit
eat.lua -- prompts to eat chunks in inventory.
pickup.lua -- smarter autopickup.
- trapwalk.lua -- allows travel to cross certain traps if you have enough HP.
+ trapwalk.lua -- allows travel to cross certain traps if you have
+ enough HP.
Also see section 7 on inline Lua fragments.
@@ -264,151 +271,145 @@ autopickup = $?!+"/%
+ or : Books
\ or | Staves
0 Orbs
- } Misc items
+ } Misc. items
X Corpses
$ Gold
Note that _whether_ items are picked up automatically or not, is
- controlled by the in-game toggle Ctrl-A. Also note that picking up
- takes a turn, but only one turn (regardless of the number of items).
- If you teleport or blink onto a square with interesting items, these
- will not be picked up.
+ controlled by the in-game toggle Ctrl-A. Also note that picking
+ up takes a turn, but only one turn (regardless of the number of
+ items). If you teleport or blink onto a square with interesting
+ items, these will not be picked up.
autopickup_exceptions = <pickup-regex, >don't-pickup-regex, ...
- A set of regexes that force matching items to be picked up (if prefixed
- with <), or never picked up (if prefixed with >). Excludes (>) take
- precedence over includes (<), so if the same item is matched by both
- an exclude and an include, it will not be subject to autopickup.
+ A set of regexes that force matching items to be picked up (if
+ prefixed with <), or never picked up (if prefixed with >).
+ Excludes (>) take precedence over includes (<), so if the same
+ item is matched by both an exclude and an include, it will not
+ be subject to autopickup.
An example:
- autopickup_exceptions = <curare-tipped needle
- Forces autopickup to grab all curare-tipped needles, even if missiles
- are not set in the "autopickup" option.
+ autopickup_exceptions = <curare-tipped needle
+ Forces autopickup to grab all curare-tipped needles, even if
+ missiles are not set in the "autopickup" option.
- Whitespace between <> and the match expression is significant, so this
- is a mistake:
- autopickup_exceptions = < ebony casket
+ Whitespace between <> and the match expression is significant,
+ so the following won't work:
+ autopickup_exceptions = < ebony casket
autopickup_exceptions replace the older ban_pickup. Using
- autopickup_exceptions = >decay, >degeneration
+ autopickup_exceptions = >uselessness, >inaccuracy
is the same as using
- ban_pickup = decay, degeneration
+ ban_pickup = uselessness, inaccuracy
- If the regexes are not prefixed with < or >, > is implied, so the
- option setting above can also be written as
- autopickup_exceptions = decay, degeneration
+ If the regexes are not prefixed with < or >, > is implied, so
+ the option setting above can also be written as
+ autopickup_exceptions = uselessness, inaccuracy
You can use multiple autopickup_exceptions lines. Some examples:
- autopickup_exceptions = degeneration, decay, potions? of confusion,
- autopickup_exceptions = potions? of slowing, potions? of paralysis
- autopickup_exceptions = potions? of strong poison,potions? of poison
- autopickup_exceptions = inaccuracy
- autopickup_exceptions = scrolls? of paper, immolation, curse armour,
- autopickup_exceptions = curse weapon, forgetfulness, uselessness,
- autopickup_exceptions = noise, torment
+ autopickup_exceptions = inaccuracy, scrolls? of paper,
+ autopickup_exceptions = immolation, curse (armour|weapon),
+ autopickup_exceptions = uselessness, noise, torment
-default_autopickup = true
- When set to false, the game starts with autopickup turned off. You can
- still toggle autopickup in-game with Ctrl-A.
+ Note that if pickup.lua has been sourced, you won't need to set
+ autopickup exceptions for potions except maybe for very special
+ cases.
-safe_autopickup = true
- When set, autopickup will not operate if there are visible unfriendly
- monsters (or statues.) If safe_zero_exp is set (the default), zero-XP
- monsters are considered friendly.
+default_autopickup = true
+ When set to false, the game starts with autopickup turned off.
+ You can still toggle autopickup in-game with Ctrl-A.
autopickup_no_burden = false
When set, autopickup will not pick up items which would increase
- your burden status (from unencumbered to burdened, or from encumbered
- to overloaded.)
-
-safe_zero_exp = true
- If set, presence of only zero experience monsters (like plants) will
- cause autopickups, even if safe_autopickup=true is set. This option
- also settles whether autoprayer considers such monsters risky.
+ your burden status (from unencumbered to burdened, or from
+ encumbered to overloaded.)
pickup_thrown = true
- pickup_thrown=true causes autopickup to pick up thrown/fired missiles,
- which can make life much easier for hunter types. If you use this, be
- aware that autopickup uses a turn - use Ctrl-A to turn it off while
- you're fighting, or use safe_autopickup=true.
+ pickup_thrown = true causes autopickup to pick up thrown/fired
+ missiles, which can make life much easier for hunter types. Be
+ aware that autopickup uses a turn, though it won't trigger if
+ there are hostile monsters in sight.
pickup_dropped = false
- pickup_dropped lets autopickup affect objects you've dropped. Set to
- false to block autopickup for dropped objects. This can be convenient.
+ pickup_dropped lets autopickup affect objects you've dropped.
+ Set to false to block autopickup for dropped objects. This can
+ be convenient.
assign_item_slot = (forward | backward)
- When picking up items, the inventory slot into which the item goes is
- normally the first free slot from a-zA-Z (this is the default "forward"
- behaviour). Setting assign_item_slot to "backward" changes the slot
- assignment to the first letter after the last slot.
+ When picking up items, the inventory slot into which the item
+ goes is normally the first free slot from a-zA-Z (this is the
+ default "forward" behaviour). Setting assign_item_slot to
+ "backward" changes the slot assignment to the first letter after
+ the last slot.
For instance, if you have items on 'a' and 'c', then with
- assign_item_slot = forward, the next item will go into 'b',
- assign_item_slot = backward, the next item will go to 'd' instead.
- With "backward", items dropped/fired and picked up later are more
- likely to get their old slot back.
+ assign_item_slot = forward, the next item will go into 'b',
+ assign_item_slot = backward, the next item will go to 'd'
+ instead.
+ With "backward", items dropped/fired and picked up later are
+ more likely to get their old slot back.
drop_mode = (multi | single)
- Single is the classic behaviour; when you select an inventory letter,
- that item will be dropped immediately. Multidrop allows you to select
- multiple items to be dropped. (You can also switch to multidrop from
- the classic drop menu using the '@' key).
+ Single is the classic behaviour; when you select an inventory
+ letter, that item will be dropped immediately. Multidrop allows
+ you to select multiple items to be dropped. (You can also switch
+ to multidrop from the classic drop menu using the '@' key).
- Multidrop is the default and can be very convenient, but be aware that
- every item dropped takes one turn. (This is different from picking up.)
- When selecting multidrops, the top right corner shows the estimated
- number of turns.
+ Multidrop is the default and can be very convenient, but be
+ aware that every item dropped takes one turn. (This is different
+ from picking up.)
+ When selecting multidrops, the top right corner shows the
+ estimated number of turns.
- The order in which items get dropped is from top to bottom in the
- inventory listing, but equipped items will be dropped last, and may be
- dropped out of order.
+ The order in which items get dropped is from top to bottom in
+ the inventory listing, but equipped items will be dropped last,
+ and may be dropped out of order.
pickup_mode = (multi | single | auto:X)
- Single is the classical behaviour (and default): when picking up items,
- you are prompted for them one by one. Multi makes a menu appear, where
- you can choose which items to pick up. Note that no matter how many
- items you choose, picking up will always take one turn.
- If pickup_mode is auto:X, where X is some number (for example, auto:5),
- then pickup will give a menu if there are at least X items on your
- square, and will prompt one by one otherwise.
+ Single is the classical behaviour (and default): when picking up
+ items, you are prompted for them one by one. Multi makes a menu
+ appear, where you can choose which items to pick up. Note that
+ no matter how many items you choose, picking up will always take
+ one turn.
+ If pickup_mode is auto:X, where X is some number (for example,
+ auto:5), then pickup will give a menu if there are at least X
+ items on your square, and will prompt one by one otherwise.
drop_filter = <regex>
- When selecting items using the global (de)select keys (',' or '-') in a
- multidrop menu, you can choose to select only items that match a
- search regex using this option.
+ When selecting items using the global (de)select keys (',' or
+ '-') in a multidrop menu, you can choose to select only items
+ that match a search regex using this option.
- For instance, to quickly select carrion and rotting chunks of meat, you
- could use:
- drop_filter = skeleton, rotting, corpse
- Other choices can come in handy as well, e.g. if you want to sacrifice
- regularly all weapons except axes, use:
- drop_filter = axe, broadaxe
+ For instance, to quickly select carrion and rotting chunks of
+ meat, you could use:
+ drop_filter = skeleton, rotting, corpse
+ Other choices can come in handy as well, e.g. if you want to
+ regularly sacrifice all weapons except axes, use:
+ drop_filter = axe, broadaxe
- When a drop_filter is set, using the select/deselect keys will set/
- clear selection of items that match the filter expression(s).
+ When a drop_filter is set, using the select/deselect keys will
+ set/clear selection of items that match the filter
+ expression(s).
4-b Targeting.
-------------------
target_zero_exp = false
- Set to false to disable targeting zero exp monsters (i.e. plants)
- in hostile targeting mode. This is usually convenient to do.
+ Set to false to disable targeting zero exp monsters (i.e.
+ plants) in hostile targeting mode. This is usually convenient to
+ do.
target_oos = true
- When cycling through items with 'x' look-around, setting target_oos to
- true allows you to jump the cursor to dungeon features (<> for stairs,
- Tab for shops, ^ for traps) and stashes (with the '*' and '/' keys)
- that are outside line-of-sight but in the main view. This is most
- sensibly used in connection with stash_tracking=all (see 4-g). Also
- see also target_los_first below.
+ When cycling through items with 'x' look-around, setting
+ target_oos to true allows you to jump the cursor to dungeon
+ features (<> for stairs, Tab for shops, ^ for traps) and stashes
+ (with the '*' and '/' keys) that are outside line-of-sight but
+ in the main view. This is most sensibly used in connection with
+ stash_tracking = all (see 4-g).
+ Also see target_los_first below.
target_los_first = true
- When cycling through items/features with the 'x' look-around command,
- setting target_los_first to true will force the cursor to squares in
- line-of-sight before going to squares outside LOS.
-
-confirm_self_target = true
- Setting this to true will make Crawl ask for confirmation whenever
- selecting the character as the target of a non-friendly-targeted spell
- (i.e., something other than haste, healing or invisibility.)
+ When cycling through items/features with the 'x' look-around
+ command, setting target_los_first to true will force the cursor
+ to squares in line-of-sight before going to squares outside LOS.
default_target = true
If set to true (the default), targeting will start on either
@@ -416,8 +417,8 @@ default_target = true
monster (if not) rather than on the character. If no monsters
are in view, targeting will start on the character regardless.
- If default_target = false, the targeting cursor will always start
- aimed at the character.
+ If default_target = false, the targeting cursor will always
+ start aimed at the character.
default_target is mutually exclusive with
target_unshifted_dirs. Using default_target will automatically
@@ -434,7 +435,6 @@ target_unshifted_dirs = false
If you use target_unshifted_dirs, default_target will be
automatically disabled.
-
4-c Passive Sightings (via detection and remembrance).
-----------------------------------------------------------
@@ -448,11 +448,11 @@ colour_map = true
Colours out of sight map features on the playing screen.
clean_map = false
- Cleans up out of sight monsters and clouds on the map. This is like
- pressing Ctrl-C (clearing both main screen and level map) all the time.
+ Cleans up out of sight monsters and clouds on the map. This is
+ like pressing Ctrl-C (clearing both main screen and level map)
+ all the time.
Setting this to true can be disconcerting for summoners.
-
4-d Branding (Item and monster highlighting).
-------------------------------------------------
@@ -460,41 +460,50 @@ Branding refers to displaying particular monsters (e.g. summons) or
items in a special way; special as in reversing fore- and background.
There are several branding choices (these will not work everywhere; it
depends on OS and terminal):
- standout -- often the same as reverse, might be underline or dim
- bold -- used by colour curses for brightening foreground colours
- blink -- used by colour curses for brightening background colours
+ standout -- often the same as reverse, might be underline or
+ dim
+ bold -- used by colour curses for brightening foreground
+ colours
+ blink -- used by colour curses for brightening background
+ colours
reverse -- this will probably work
dim -- probably no effect
underline -- this will probably work
- highlight:colour -- set background colour of branded monsters to "colour"
+ highlight:colour -- set background colour of branded monsters to
+ "colour"
The last can be abbreviated to hi:colour.
-See part Technical (6-) for dos_use_background_intensity under Windows and DOS.
+See part Technical (6-) for dos_use_background_intensity under Windows
+and DOS.
-By default, no brands are active apart from stair_item_brand.
-
-heap_brand = reverse
- Brand heaps of items (more than one item or stack).
+By default, only two of the item brands are active (and set to reverse):
+ heap_brand, stair_item_brand
+They can be deactivated by setting them to "none".
friend_brand = none
- Brand friends in some way. This is very helpful for summoners. E.g.
- friend_brand = hi:green
- shows friends with a green background. If the friend is itself green,
- it'll show up as black on green.
+ Brand friends in some way. This is very helpful for summoners.
+ E.g.
+ friend_brand = hi:green
+ shows friends with a green background. If the friend is itself
+ green, it'll show up as black on green.
stab_brand = none
Some deities object to you stabbing monsters. Certain classes
- specialise in stabbing monsters. Still other characters are happy if
- they spot a monster before the monster spots them. In all these cases,
- it helps to identify monsters that are unaware of the character (and
- hence susceptible to being stabbed) without using the 'x' command. All
- the normal 'brand' options apply. For example
- stab_brand = hi:blue
+ specialise in stabbing monsters. Still other characters are
+ happy if they spot a monster before the monster spots them. In
+ all these cases, it helps to identify monsters that are unaware
+ of the character (and hence susceptible to being stabbed) without
+ using the 'x' command. All the normal 'brand' options apply. For
+ example
+ stab_brand = hi:blue
may_stab_brand = none
Stabbing may be possible even if the monster is not asleep (if
it's confused or distracted, for instance). This option brands
monsters that you *might* be able to stab.
+heap_brand = reverse
+ Brand heaps of items (more than one item or stack).
+
stair_item_brand = reverse
Brands stairs that would otherwise be hidden by items. If you
use this brand, the items on the square are hidden by the stair
@@ -513,12 +522,12 @@ level_map_cursor_step = 7
Shift-direction or * direction.
level_map_title = true
- Whether to show the level name at the top of the level map screen.
+ Whether to show the level name at the top of the level map
+ screen.
item_colour = true
Colours items on level-map.
-
4-f Viewport Display Options
--------------------------------
@@ -590,229 +599,252 @@ scroll_margin = 2
An aliased option that sets both scroll_margin_x and
scroll_margin_y.
-
4-g Travel and Exploration.
-------------------------------
travel_delay = 20
How long travel waits after each move (milliseconds). Depends on
- platform. Setting to -1 will jump to end of travel - you will not see
- the individual moves.
+ platform. Setting to -1 will jump to end of travel - you will
+ not see the individual moves.
travel_avoid_terrain = (shallow water | deep water)
- Prevent travel from routing through shallow water. By default, this
- option is commented out. For merfolk and/or characters with permanent
- levitation,
- travel_avoid_terrain = shallow water, deep water
+ Prevent travel from routing through shallow water. By default,
+ this option is commented out. For merfolk and/or characters with
+ permanent levitation,
+ travel_avoid_terrain = shallow water, deep water
will prevent travel or explore from going through any water.
+explore_greedy = false
+ Greedy explore travels to items that are eligible for autopickup
+ in addition to exploring the level, but is otherwise identical
+ to regular explore. Greedy explore is only available with
+ stash_tracking = all (for any other value of stash_tracking,
+ normal explore behaviour is used). Greedy explore is also best
+ with pickup_dropped = false. Explore greed is disabled if you're
+ temporarily unable to pick up items (from uncontrolled
+ levitation, for instance).
+
+explore_stop = items,stairs,shops,altars,gates
+ Explore will stop for one of these conditions. Whatever you set
+ this option to, anything that stops travel will also stop
+ explore. Multiple explore_stop lines are *not* cumulative! The
+ last explore_stop line will override all previous explore_stop
+ lines.
+
+tc_reachable = blue
+tc_dangerous = cyan
+tc_disconnected = darkgrey
+tc_excluded = lightmagenta
+tc_exclude_circle = red
+ The above five settle the colouring of the level map ('X').
+ They are
+ reachable: all squares safely reachable (without leaving the
+ level)
+ dangerous: squares which are only connected to you via traps,
+ etc.
+ disconnected: squares which cannot be reached without leaving
+ the level
+ excluded: the colour for the centre of travel exclusions
+ (Ctrl-X)
+ excluded_circle: the colour for travel exclusions apart from
+ centre
+
travel_stop_message = <list of regexes>
- Travel will always stop upon hitpoint loss, confusion, stat drain,
- getting encumbered, catching sight of a non-friendly monster, and
- teleporting. In addition, a message containing one of the expressions
- in travel_stop_message will stop travel. For example,
+ Travel will always stop upon hitpoint loss, confusion, stat
+ drain, getting encumbered, catching sight of a non-friendly
+ monster, and teleporting. In addition, a message containing one
+ of the expressions in travel_stop_message will stop travel. For
+ example,
travel_stop_message = Something appears
- stops travel if Xom grants us a gift suddenly. To limit a substring
- match to a message channel, prefix the substring with the channel name
- and a colon (see section 4-k below on Message Channels). For instance,
- if you want travel to stop when you're hit by divine retribution, you
- could use:
+ stops travel if Xom grants us a gift suddenly. To limit a
+ substring match to a message channel, prefix the substring with
+ the channel name and a colon (see section 4-k below on Message
+ Channels). For instance, if you want travel to stop when you're
+ hit by divine retribution, you could use:
travel_stop_message = god:wrath finds you
- If you'd like to stop travel for any message sent to a particular
- channel, use a travel_stop_message line with that message channel name
- and a colon alone. For example, if you're playing a ghoul:
+ If you'd like to stop travel for any message sent to a
+ particular channel, use a travel_stop_message line with that
+ message channel name and a colon alone. For example, if you're
+ playing a ghoul:
travel_stop_message = rotten_meat:
Stop travel for any god messages (including prayer)
travel_stop_message = god:
Multiple travel_stop_message lines can be used.
-explore_greedy = false
- Greedy explore travels to items that are eligible for autopickup in
- addition to exploring the level, but is otherwise identical to
- regular explore. Greedy explore is only available with
- stash_tracking = all (for any other value of stash_tracking, normal
- explore behaviour is used). Greedy explore is also best with
- pickup_dropped = false. Explore greed is disabled if you're
- temporarily unable to pick up items (from uncontrolled levitation,
- for instance).
-
-explore_stop = items,stairs,shops,altars,gates
- Explore will stop for one of these conditions. Whatever you set this
- option to, anything that stops travel will also stop explore. Multiple
- explore_stop lines are *not* cumulative! The last explore_stop line
- will override all previous explore_stop lines.
-
runrest_ignore_message = <string>
- This only works if runrest.lua has been sourced already in init.txt.
- Any message containing the string will *not* stop your run. E.g.
- runrest_ignore_message = offer a prayer,prayer is over
- runrest_ignore_message = pleased with you,exalted
+ This only works if runrest.lua has already been sourced in
+ init.txt. Any message containing the string will *not* stop your
+ run. E.g.
+ runrest_ignore_message = offer a prayer,prayer is over
+ runrest_ignore_message = pleased with you,exalted
(useful in conjunction with autoprayer.)
+ Note that monster talk and dungeon noises already do not
+ interrupt running or resting, by default.
+
runrest_ignore_poison = <poison damage>:<minimum hp>
- This only works if runrest.lua has been sourced already in init.txt.
- Poison damage of x will be ignored if you have at least y hp if you've
- defined a runrest_ignore_poison = x:y option. Running here means
- shift-running and resting only. Only one runrest_ignore_poison line is
- considered. Note that for this work, you should also tell Crawl to
- ignore the "You feel sick" messages. For example,
- runrest_ignore_message = You feel.*sick
- runrest_ignore_poison = 4:100
+ This only works if runrest.lua has already been sourced in
+ init.txt. Poison damage of x will be ignored if you have at
+ least y hp if you've defined a runrest_ignore_poison = x:y
+ option. Running here means shift-running and resting only. Only
+ one runrest_ignore_poison line is considered. Note that for
+ this work, you should also tell Crawl to ignore the
+ "You feel sick" messages. For example,
+ runrest_ignore_message = You feel.*sick
+ runrest_ignore_poison = 4:100
runrest_ignore_monster = <string>:<distance>
- This only works if runrest.lua has been sourced already in init.txt.
+ This only works if runrest.lua has already been sourced in
+ init.txt.
Any monster containing the string will only interrupt your
activity if the distance between you and the monster is
less than the specified number. E.g. with
runrest_ignore_monster = fish:3
all of big fish, jellyfish, giant goldfish and lavafish will be
- considered safe for travel, explore and resting as long as the distance
- is at least 3.
+ considered safe for travel, explore and resting as long as the
+ distance is at least 3.
trapwalk_safe_hp = <trap_name>:<minimum_hp>, ...
- This only works if trapwalk.lua has been sourced already in init.txt.
- Any square containing one of the listed trap types will be considered
- safe for travel if your hp is greater than or equal to the number
- connected to the trap in question.
-
- All the existing trap types can be used, but in practice only the
- mechanical traps (dart, bolt, arrow, needle, spear, axe, blade) make
- sense. Note that travel tries to avoid traps if this is easily
- possible. Defaults to none. For example,
+ This only works if trapwalk.lua has already been sourced in
+ init.txt. Any square containing one of the listed trap types
+ will be considered safe for travel if your hp is greater than or
+ equal to the number connected to the trap in question.
+
+ All the existing trap types can be used, but in practice only
+ the mechanical traps (dart, bolt, arrow, needle, spear, axe,
+ blade) make sense. Note that travel tries to avoid traps if this
+ is easily possible. Defaults to none. For example,
trapwalk_safe_hp = dart:15, needle:25, spear:50
-tc_reachable = blue
-tc_dangerous = cyan
-tc_disconnected = darkgrey
-tc_excluded = lightmagenta
-tc_exclude_circle = red
- The above five settle the colouring of the level map ('X'). They are
- reachable: all squares safely reachable (without leaving the level)
- dangerous: squares which are only connected to you via traps, etc.
- disconnected: squares which cannot be reached without leaving the level
- excluded: the colour for the centre of travel exclusions (Ctrl-X)
- excluded_circle: the colour for travel exclusions apart from centre
-
-
4-h Stashes.
----------------
stash_tracking = (all | explicit | dropped)
- A stash is a heap of items tracked by Crawl. You can search in your
- stashes with Ctrl-F. This options rules how stashes are generated.
- When stash_tracking is set to 'all' (the default), the game marks any
- square where it sees any object as a stash. That gives you a
- comprehensive list of everything your character sees in the dungeon,
- but may slow the game down and use too much memory on older computers.
-
- With 'explicit', you have to explicitly tell the game what squares you
- want it to keep track of. You do that by stepping onto the square
- containing your stash of goodies and hitting Ctrl+S. The game will now
- keep track of what's on the square, when you add and remove stuff from
- your stash. You can also inscribe an item with "=s" to automatically
- mark a square as a stash whenever that item is dropped. If you
- remove everything from that square, the game will stop tracking
- the square altogether. You can also erase a stash square with
- Ctrl-E. Explicitly marked stashes will never be sacrificed by a
+ A stash is a heap of items tracked by Crawl. You can search in
+ your stashes with Ctrl-F. This options rules how stashes are
+ generated. When stash_tracking is set to 'all' (the default),
+ the game marks any square where it sees any object as a stash.
+ That gives you a comprehensive list of everything your character
+ sees in the dungeon, but may slow the game down and use too much
+ memory on older computers.
+
+ With 'explicit', you have to explicitly tell the game what
+ squares you want it to keep track of. You do that by stepping
+ onto the square containing your stash of goodies and hitting
+ Ctrl+S. The game will now keep track of what's on the square,
+ when you add and remove stuff from your stash. You can also
+ inscribe an item with "=s" to automatically mark a square as a
+ stash whenever that item is dropped. If you remove everything
+ from that square, the game will stop tracking the square
+ altogether. You can also erase a stash square with Ctrl-E.
+ Explicitly marked stashes will never be sacrificed by a
Nemelex Xobeh worshipper.
- When stash_tracking is set to 'dropped', any square where you drop
- something becomes a stash, and the game keeps track of all such
- squares. You can still use Ctrl-S and Ctrl-E as above.
+ When stash_tracking is set to 'dropped', any square where you
+ drop something becomes a stash, and the game keeps track of all
+ such squares. You can still use Ctrl-S and Ctrl-E as above.
stash_filter = <list of numbers>
- This option allows filtering certain classes of items when searching
- stashes. For example,
- stash_filter = 14, 4:21
- filters corpses (14) as well as food of the subtype chunks (4:21).
+ This option allows filtering certain classes of items when
+ searching stashes.
+ For example:
+ stash_filter = 14, 4:21
+ filters corpses (14) as well as food of the subtype chunks (4:21).
annotate_item_class = false
- This only works if stash.lua has been sourced already in init.txt.
- If set to true, automatically annotates items with their object class
- (e.g. weapon or wand) for stash searching.
+ This only works if stash.lua has already been sourced in
+ init.txt. Automatically annotates items with their object class,
+ e.g. weapon or wand, for stash searching.
4-i Command Enhancements.
-----------------------------
auto_list = true
When set (the default), the appropriate inventory items are
- automatically listed for commands like eat and read. This is like
- immediately hitting '?', and can be confusing to beginners because they
- won't get to see the prompts. This option does not apply to spell
- casting... Conjurers would probably find that really annoying.
-
-lowercase_invocations = true
- Set this option to true if you prefer to have invocations on 'a'-'e'
- instead of the older 'A'-'E'. Note that you can change the letters of
- invocations (and other abilites) with the '=' command.
+ automatically listed for commands like eat and read. This is
+ like immediately hitting '?', and can be confusing to beginners
+ because they won't get to see the prompts. This option does not
+ apply to spell casting... Conjurers would probably find that
+ really annoying.
easy_open = true
- Open doors by moving on to them. Highly convenient. Note that travel
- and exploration will automatically open doors depending on this option.
-
-easy_butcher = true
- If true, auto-switch to an appropriate uncursed weapon for butchery.
- For such tools any special messages are ignored. If false, you have to
- wield the tool manually.
+ Open doors by moving on to them. Highly convenient. Note that
+ travel and exploration will automatically open doors depending
+ on this option.
easy_unequip = true
Allows auto removal of armour and jewellery when dropping it.
easy_confirm = (none | safe | all)
Make confirmation questions easier to answer:
- none = force capitals on Y/N questions
- safe = force only on questions that will end game (default)
- all = never force capitals
- WARNING TO KEYPAD USERS: The number 7 is mapped to the letter 'y',
- which can result in accidentally answering yes to questions; it is
- suggested that you use a value of 'none' or 'safe'
+ none = force capitals on Y/N questions
+ safe = force only on questions that will end game (default)
+ all = never force capitals
+ WARNING TO KEYPAD USERS: The number 7 is mapped to the letter
+ 'y', which can result in accidentally answering yes to
+ questions; it is suggested that you use a value of 'none' or
+ 'safe'
+
+easy_butcher = true
+ If true, auto-switch to an appropriate uncursed weapon for
+ butchery. For such tools any special messages are ignored. If
+ false, you have to wield the tool manually.
+
+always_confirm_butcher = false
+ If true, always request confirmation before butchering. If
+ false, butchering will proceed automatically if there is exactly
+ one corpse on the square. If there are multiple corpses on a
+ square, you will always be prompted, regardless of this option.
easy_quit_item_prompts = true
- Setting this option to true allows the quitting of item listing with
- Space (as well as Escape, which always works). These lists are
- essentially all of those that are requesting an inventory item and
- accept '?' and '*'. The identify list will never easy quit.
+ Setting this option to true allows the quitting of item listing
+ with Space (as well as Escape, which always works). These lists
+ are essentially all of those that are requesting an inventory
+ item and accept '?' and '*'. The identify list will never easy
+ quit.
easy_exit_menu = true
- In multidrop (and pickup) menus, paging past the end will drop out of
- the menu if easy_exit_menu is true.
+ In multidrop (and pickup) menus, paging past the end will drop
+ out of the menu if easy_exit_menu is true.
default_autoprayer = false
- When set to true, the game will start with automatic prayers. This
- option can be toggled in-game with Ctrl-V.
+ When set to true, the game will start with automatic prayers.
+ This option can be toggled in-game with Ctrl-V.
- Automatic prayers take a turn like manual prayers and happen only if
+ Automatic prayers take a turn like manual prayers and happen
+ only if
- there is no hostile monster in sight
- some further conditions (like not standing at an altar)
- Note that even when you're praying, you can renew prayer anytime.
- Also note the option safe_zero_exp (see 4-a) decides whether zero
- experience monsters (like plants) are considered hostile.
- If you use autoprayer, you might want to set runrest_ignore_message
- to ignore the prayer messages (see the documentation for
- runrest_ignore_message).
+ Note that even when you're praying, you can renew prayer
+ anytime. Also note the option safe_zero_exp (see 4-a) decides
+ whether zero experience monsters (like plants) are considered
+ hostile.
+ If you use autoprayer, you might want to set
+ runrest_ignore_message to ignore the prayer messages (see the
+ documentation for runrest_ignore_message).
sort_menus = [menu:](true | false | auto:X)[:sort_order]
Controls if and how items are sorted in inventory and pickup
menus.
- When sort_menus = false (the default), items are not sorted,
- and will be ordered by inventory letter (or in the order
- they're stacked for items on the floor).
+ When sort_menus = false (the default), items are not sorted, and
+ will be ordered by inventory letter (or in the order they're
+ stacked for items on the floor).
- When sort_menus = true, items are sorted by base name,
- qualified name, curse status and quantity.
+ When sort_menus = true, items are sorted by base name, qualified
+ name, curse status and quantity.
If sort_menus = auto:X, items are sorted if there are at least
X items in the same category. For instance:
- sort_menus = auto:5
- will sort item classes that have at least 5 items. For
- instance, having 4 kinds of potions would not sort them, but
- having 5 would.
+ sort_menus = auto:5
+ will sort item classes that have at least 5 items. For instance,
+ having 4 kinds of potions would not sort them, but having 5
+ would.
You can explicitly specify sort criteria in the sort_menus
option as:
- sort_menus = true : basename, qualname, curse, qty
+ sort_menus = true : basename, qualname, curse, qty
Two items will be compared based on the first sort criteria
where they differ. So with the sort_menus line given above,
@@ -825,21 +857,21 @@ sort_menus = [menu:](true | false | auto:X)[:sort_order]
* basename:
This is the name of the item type. The basename for all of
- "a +0 robe", "an embroidered robe" and "the cursed +2 robe
- of Ponies" is just "robe". The basename for both of
- "a brass ring" and "a ring of fire resistance" are "ring".
+ "a +0 robe", "an embroidered robe" and "the cursed +2 robe of
+ Ponies" is just "robe". The basename for both of "a brass
+ ring" and "a ring of fire resistance" are "ring".
* qualname:
- The name of the item without articles (a/an/the),
- quantities, enchantments, or curse-status. The qualified
- names for the robes described above are "robe", "embroidered
- robe" and "robe of Ponies", respectively. The qualified
- names for the rings describe above are "brass ring" and
- "ring of fire resistance", respectively.
+ The name of the item without articles (a/an/the), quantities,
+ enchantments, or curse-status. The qualified names for the
+ robes described above are "robe", "embroidered robe" and "robe
+ of Ponies", respectively. The qualified names for the rings
+ described above are "brass ring" and "ring of fire
+ resistance", respectively.
* fullname:
- This is the name of the item as displayed in menus
- (including quantities, curse-status, etc.)
+ This is the name of the item as displayed in menus (including
+ (quantities, curse-status, etc.)
* curse:
Curse-status of the item (if known). Uncursed items show up
@@ -867,23 +899,23 @@ sort_menus = [menu:](true | false | auto:X)[:sort_order]
* freshness:
The freshness of chunks of meat; irrelevant for everything
- else. It makes the oldest chunks of meat show up first,
- with rotting chunks listed last for non-Saprovores.
+ else. It makes the oldest chunks of meat show up first, with
+ rotting chunks listed last for non-Saprovores.
If this sort criteria is placed before (or in the absence of)
- basename and qualname, then non-chunk food items will be
+ basename and qualname, then non-chunk food items will be
sorted between the non-rotting and rotting chunks.
- The default sort criteria are: "equipped, basename, qualname,
- curse, qty".
+ The default sort criteria are:
+ "equipped, basename, qualname, curse, qty".
- You can ask for a descending order sort by prefixing one or
- more sort criteria with > as:
- sort_menus = true : basename, >qty
+ You can ask for a descending order sort by prefixing one or more
+ sort criteria with > as:
+ sort_menus = true : basename, >qty
You can also request sorting only for specific menus:
- sort_menus = pickup: true
+ sort_menus = pickup: true
or
- sort_menus = inv: true
+ sort_menus = inv: true
(Menu types must be specified as name:, with no space between
name and colon.)
@@ -897,78 +929,111 @@ sort_menus = [menu:](true | false | auto:X)[:sort_order]
any: All menus; this is the default when unspecified.
For example,
- sort_menus = true : equipped, basename, qualname, curse, qty
- will produce the same inventory and drop menus as by default, with
- the exception that all worn/wielded items come first. This can be
- convenient if you use the '.' command to select subsequent items.
+ sort_menus = true : equipped, basename, qualname, curse, qty
+ will produce the same inventory and drop menus as by default,
+ with the exception that all worn/wielded items come first. This
+ can be convenient if you use the '.' command to select
+ subsequent items.
4-j Messages and Display Enhancements.
------------------------------------------
hp_warning = 10
- hp_warning gives "* * * LOW HITPOINT WARNING * * *" on the danger
- channel when the player takes damage and their hitpoints are less than
- this percentage of their maximum (use 0 to turn off these messages).
+ hp_warning gives "* * * LOW HITPOINT WARNING * * *" on the
+ danger channel when the player takes damage and their hitpoints
+ are less than this percentage of their maximum (use 0 to turn
+ off these messages).
mp_warning = 0
mp_warning gives "* * * LOW MAGIC WARNING * * *" on the danger
- channel when the player's magic points drop below this percentage of
- their maximum (use 0 to turn off these messages).
+ channel when the player's magic points drop below this
+ percentage of their maximum (use 0 to turn off these messages).
hp_colour = lightgrey, 50:yellow, 25:red
- hp_colour colours your HP appropriately in the display. In the default
- setting, your HP will appear in red if at less then 25%, yellow if at
- less than 50%, and lightgrey otherwise.
+ hp_colour colours your HP appropriately in the display. In the
+ default setting, your HP will appear in red if at less then 25%,
+ yellow if at less than 50%, and lightgrey otherwise.
mp_colour = lightgrey, 50:yellow, 25:red
mp_colour does to MP what hp_colour does to HP.
-terse_hand = true
- Set this to false to have the "in hand" description on the main screen
- the same as the inventory. The default setting of true will give the
- newer more terse description that should fit the limited space better.
-
delay_message_clear = false
- Setting this option to true will delay the clearing of messages until
- the message space is full (default is false which results in clearing
- between player actions).
+ Setting this option to true will delay the clearing of messages
+ until the message space is full (default is false which results
+ in clearing between player actions).
+
+show_inventory_weights = false
+ When this is set to true, inventory listings will mention the
+ weight of each item.
-always_greet = true
- always_greet will give the race/class and god messages everytime the
- game is started.
+show_turns = false
+ This option controls whether the turn counter (of turns elapsed)
+ is displayed in the main view.
-menu_colour = <colour>:<regex>
- This prints a line (of the inventory, a menu, or the discoveries
- screen) containing regex in the stated colour. There can be several
- statements in a list, or also several menu_colour lines. When using
- several menu_colour lines, the colour of the _first_ matching regex
- is applied. For a list of colours, check the colour option in 6-a.
+show_beam = false
+ When performing actions such as throwing or zapping, you can
+ toggle whether to show the beam path or not. This option
+ controls the initial status of this toggle. When set to true,
+ the path will be shown.
+
+item_stack_summary_minimum = 5
+ If you step over a stack with this number or more of items in
+ it, the first description line will contain a summary of all the
+ items in the stack (up to 50 items), in a format which looks
+ like this:
+ Items here: !! """ % ( )))))) [[[
+ Known artefacts will be coloured in yellow; glowing or runed
+ items will be in white, unless you already know that they are
+ not ego items.
+
+menu_colour = <match>:<colour>:<regex>
+ This prints a line (of the inventory, a menu, or the discoveries
+ screen) containing regex in the stated colour. There can be
+ several statements in a list, and also several menu_colour
+ lines. When using several menu_colour lines, the colour of the
+ _first_ matching regex is applied. For a list of colours, check
+ the colour option in 6-a.
+
+ The match specifies which listings are affected by the
+ colouring. If you specify 'any', or completely skip the <match>:
+ part, then all listings are used. Possible values for match are:
+ ability (the A screen)
+ description (the \ screen)
+ equip (the [, (, ), " screens)
+ help (the manual)
+ inventory
+ notes (the ?: screen)
+ resists (the % screen)
+ spell (the Z and I screens)
+ stash (the results from Ctrl-F)
To colour worn stuff and highlight cursed items, take
- menu_colour = lightred: cursed.*(worn|neck|hand|weapon)
- menu_colour = green:(worn|neck|hand|weapon)
- menu_colour = red: cursed
+ menu_colour = inventory:lightred: cursed.*(worn|neck|hand|weapon)
+ menu_colour = inventory:green:(worn|neck|hand|weapon)
+ menu_colour = inventory:red: cursed
To colour identified artefacts, try
- menu_colour = white:( [-+] the)
+ menu_colour = inventory:white:( [-+] the)
- If you frequently die because you forget to use emergency items, try
- menu_colour = cyan:(potions? of heal wounds|teleportation)
- menu_colour = lightcyan:(blinking|wand of (fire|cold|draining))
+ If you frequently die because you forget to use emergency items,
+ try
+ menu_colour = inventory:cyan:(potions? of heal wounds|blinking)
+ menu_colour = inventory:lightcyan:wand of (fire|cold|draining)
To quickly check what potions were trashed by a mummy curse, use
- menu_colour = lightred:potions? of (degeneration|decay)
+ menu_colour = inventory:lightred:potions? of (degeneration|decay)
If you like to see rotten chunks and corpses at a glance, use
- menu_colour = red: rotting
+ menu_colour = inventory:red: rotting
- menu_colour can also be applied to colour the in-game notes (to be
- read with '?:'). The following line will show level ups in white:
- menu_colour = white:Reached XP level
+ menu_colour can also be applied to colour the in-game notes (to
+ be read with '?:'). The following line will show level ups in
+ white:
+ menu_colour = notes:white:Reached XP level
menu_colour_prefix_id = false
- Setting this option to true will prefix the string against
- which menu_colour regexes are matched (not the string
+ Setting this option to true will prefix the string against which
+ menu_colour regexes are matched (not the string
displayed) with the item's identification state: "unidentified"
for unidentified, "known" for wands for which you know the type
but don't know the number of charges, and for rings with plusses
@@ -976,17 +1041,17 @@ menu_colour_prefix_id = false
"identified" for other identified items.
Note that the prefix is put before the the *entire* string which
- is displayed, so if you're wielding a uncursed dagger which has
+ is displayed, so if you're wielding an uncursed dagger which has
the 'a' slot, the string the regexes will match against is
"identified a - an uncursed dagger (weapon)".
menu_colour_prefix_class = false
Setting this option to true will prefix the string against which
menu_colour regexes are matched (not the string displayed) with
- the item's object type: armour, weapon, wand, etc. If both
- this option and menu_colour_prefix_id are set to true, then
- the identification string comes before the object type string
- (i.e., "identified weapon", "known wand", etc).
+ the item's object type: armour, weapon, wand, etc. If both this
+ option and menu_colour_prefix_id are set to true, then the
+ identification string comes before the object type string (i.e.,
+ "identified weapon", "known wand", etc).
Note that the prefix is put before the the *entire* string which
is displayed, so if you're wielding a uncursed dagger which has
@@ -994,44 +1059,14 @@ menu_colour_prefix_class = false
"weapon a - an uncursed dagger (weapon)".
message_colour = <colour>:[<channel>:]<regex>
- message_colour allows you to override colours for individual messages.
- For instance, if you find the low hp warning to be insufficiently
- attention grabbing, you could do something like
- message_colour = yellow:LOW HITPOINT WARNING
+ message_colour allows you to override colours for individual
+ messages. For instance, if you find the low hp warning to be
+ insufficiently attention grabbing, you could do something like
+ message_colour = yellow:LOW HITPOINT WARNING
You can also narrow the message match to a specific channel:
- message_colour = lightred:god:xom
+ message_colour = lightred:god:xom
If you don't want to see a message at all, you can mute it:
- message_colour = mute:You start resting
-
-increasing_skill_progress = true
- This affects the appearance of the skills screen ('m'). With the
- default true, the progress for getting new levels is shown with
- increasing percentiles, so that immediately after level up it will
- read (0%). With false, you get the old behaviour which counts backwards
- from 10.
-
-show_inventory_weights = false
- When this is set to true, inventory listings will mention the
- weight of each item.
-
-show_turns = false
- This option controls whether the turn counter (of turns elapsed) is
- displayed in the main view.
-
-show_beam = false
- When performing actions such as throwing or zapping, you can toggle
- whether to show the beam path or not. This option controls the
- initial status of this toggle. When set to true, the path will be
- shown.
-
-item_stack_summary_minimum = 5
- If you step over a stack with this number or more of items in it,
- the first description line will contain a summary of all the
- items in the stack (up to 50 items), in a format which looks
- like this:
- Items here: !! """ % ( )))))) [[[
- Known artefacts will be coloured in yellow; glowing or runed
- items will be in white.
+ message_colour = mute:You start resting
4-k Missiles.
-----------------
@@ -1041,19 +1076,21 @@ fire_items_start = c
fire_order = launcher, return,
fire_order += javelin / dart / stone / rock / spear / net / handaxe
- Controls the order of items autoselected for firing. Items should
- be separated by commas and items that appear first get higher priority.
- You can use multiple fire_order lines - all lines but the first must
- use fire_order +=
-
- Items in any position may be slash-separated to indicate that these
- are of equal priority. If this is the case, the first item in your
- inventory that fits one of these will be picked for firing.
+ Controls the order of items autoselected for firing. Items
+ should be separated by commas and items that appear first get
+ higher priority. You can use multiple fire_order lines - all
+ lines but the first must use fire_order +=
+
+ Items in any position may be slash-separated to indicate that
+ these are of equal priority. If this is the case, the first item
+ in your inventory that fits one of these will be picked for
+ firing.
- 'launcher' refers to firing the appropriate missile for the wielded
- weapon (ie crossbow, bow, sling, blowgun). You'll almost certainly
- want it first, as it'll be ignored when you're not wielding a ranged
- weapon. 'return' refers to (identified) weapons of returning.
+ 'launcher' refers to firing the appropriate missile for the
+ wielded weapon (ie crossbow, bow, sling, blowgun). You'll almost
+ certainly want it first, as it'll be ignored when you're not
+ wielding a ranged weapon. 'return' refers to (identified)
+ weapons of returning.
(See also pickup_thrown in 4-a.)
@@ -1061,10 +1098,10 @@ fire_order += javelin / dart / stone / rock / spear / net / handaxe
-------------------------
Crawl communicates to the players with its message window. Every message
-belongs to one of the so-called channels. The behaviour of each channel can be
-changed with the option
+belongs to one of the so-called channels. The behaviour of each channel
+can be changed with the option
- channel.CHANNEL_NAME = (COLOUR | mute | default | on | off | plain)
+ channel.CHANNEL_NAME = (COLOUR | mute | default | on | off | plain)
CHANNEL_NAME can currently be one of these:
plain = regular text (and things "uncoloured")
@@ -1077,16 +1114,18 @@ CHANNEL_NAME can currently be one of these:
warning = various other warnings
recovery = recovery from disease/stat loss/poison conditions
talk = monsters talking
- talk_visual = monster performing some action which the player sees
+ talk_visual = monster performing some action that the player sees
intrinsic_gain = level/stat/species power gains
mutation = gain/lose mutations
- monster_spell = messages about monsters gesturing and casting spells
- monster_enchant = messages pertaining to monster enchantments (up or down)
+ monster_spell = messages about monsters gesturing or casting spells
+ monster_enchant = messages pertaining to monster enchantments
monster_damage = messages telling how damaged a monster is
rotten_meat = messages about chunks/corpses becoming rotten
equipment = messages inidcating worn/wielded equipment
- floor = messages when looking at or walking over a floor item
- multiturn = indicates long actions (wearing armour, dissecting etc.)
+ floor = messages when looking at or walking over a floor
+ item
+ multiturn = indicates long actions (wearing armour, dissecting
+ etc.)
examine = messages from examine your surroundings
examine_filter = boring messages from examining your surroundings
diagnostics = debugging messages
@@ -1098,23 +1137,26 @@ The channel options are
alternate = turn channel on to it's alternate "colourful" scheme
on = same as default
plain = make channel the same colour as the "plain" channel
- (won't do anything silly like "mute" if plain == mute, though)
+ (won't do anything silly like "mute" if plain == mute,
+ though)
off = same as plain
- COLOUR can be any of the colours described in section 6-a (colours option).
+COLOUR can be any of the colours described in section 6-a (colours
+option).
-The only multi-colour channels currently are monster_damage and god. All other
-channels are defaulted to on, except for multiturn, which defaults to mute.
+The only multi-colour channels currently are monster_damage and god. All
+other channels are defaulted to on, except for multiturn, which defaults
+to mute.
Note that the template init.txt sets
- channel.multiturn = on
-in order to help new players. You may want to comment out this option, if
-the messages are too verbose.
+ channel.multiturn = on
+in order to help new players. You may want to comment out this option,
+if the messages are too verbose.
4-m Inscriptions.
---------------------
-In Crawl, items can be manually inscribed with the '{' command. This adds a
-note in curly braces to the item inscription. Several inscriptions are
-functional, namely all containing one of the following
+In Crawl, items can be manually inscribed with the '{' command. This
+adds a note in curly braces to the item inscription. Several
+inscriptions are functional, namely all containing one of the following
@w9 -- now typing 'w9' will wield this item
@*9 -- now any action command followed by '9' will use this item
!w -- before wielding this item, Crawl will ask for confirmation
@@ -1125,27 +1167,29 @@ functional, namely all containing one of the following
skipped, and none of the items sacrificed.
=p -- Nemelex Xobeh worshippers will be prompted before
sacrificing this particular item; if the answer is "no",
- then Crawl will go on to sacrifice further items in the stack.
+ then Crawl will go on to sacrifice further items in the
+ stack.
=g -- item will be picked up automatically if autopickup is on
=k -- item will be ignored in all listings on the ground
- (it can still be picked up if it's the only item on the ground)
+ (it can still be picked up if it's the only item on the
+ ground)
=s -- If stash tracking is explicit, then dropping this item will
cause a stash to automatically be marked.
-(in the example 'w' could be any sensible command and '9' could be any digit).
-An item may contain more than one shortcut.
-autoinscribe = <regex>:<inscription>
- Any item whose description contains the regex will be automatically
- inscribed (if autopickup is toggled on). For example, marking all
- royal jellies and honeycombs eases the Hive (if food is not in the
- autopickup option):
- autoinscribe = royal jell:=g
- autoinscribe = honeycomb:=g
+In the example, 'w' could be any sensible command and '9' could be any
+digit. An item may contain more than one shortcut.
- Another use of autoinscription is making sure that you don't lose
- charges of important wands accidentally, as in
- autoinscribe = wand of healing:!z
+autoinscribe = <regex>:<inscription>
+ Any item whose description contains the regex will be
+ automatically inscribed (if autopickup is toggled on). For
+ example, marking all royal jellies and honeycombs eases the Hive
+ (if food is not in the autopickup option):
+ autoinscribe = royal jell:=g
+ autoinscribe = honeycomb:=g
+ Another use of autoinscription is making sure that you don't
+ lose charges of important wands accidentally, as in
+ autoinscribe = wand of healing:!z
4-n Macro related Options.
------------------------------
@@ -1153,12 +1197,13 @@ autoinscribe = <regex>:<inscription>
flush.failure = true
flush.command = false
flush.message = false
- These are useful when using macros. Setting one of these sub-options
- to true will cause the entire input buffer to be dumped and thus
- effectively stop the macro. The sub-options currently are
- failure -- when spells/abilities get miscast
- command -- whenever the game is about to get the next command
- message -- whenever the game outputs a non-mute message
+ These are useful when using macros. Setting one of these
+ sub-options to true will cause the entire input buffer to be
+ dumped and thus effectively stop the macro. The sub-options
+ currently are
+ failure -- when spells/abilities get miscast
+ command -- whenever the game is about to get the next command
+ message -- whenever the game outputs a non-mute message
5- Character Dump.
@@ -1168,55 +1213,60 @@ flush.message = false
------------------------
The character dump or morgue files end with a list of all monsters that
-perished while the character was active. By default, dead monsters are grouped
-in three parts:
+perished while the character was active. By default, dead monsters are
+grouped in three parts:
Vanquished Creatures -- monsters killed by the character
Collateral Kills -- kills of friendly monsters
Others -- all other casualties (e.g. traps, hostile
monsters)
kill_map = friend:you, other:you
- will merge friendly and other kills into the main vanquished creatures
- list. Note that the merging is only for display (the game still
- maintains three separate lists internally) and that kill places (see
- below) may be in the wrong order for merged entries. The default is an
- empty list.
+ will merge friendly and other kills into the main vanquished
+ creatures list. Note that the merging is only for display (the
+ game still maintains three separate lists internally) and that
+ kill places (see below) may be in the wrong order for merged
+ entries. The default is an empty list.
dump_kill_places = (none | all | single)
In the Vanquished Creatures list, this option controls how the
- locations of each kill are displayed. Use 'none' to suppress place
- display altogether, 'all' to display all known (up to 5) kill places,
- anything else to the default of showing kill places only for single
- kills
-
-dump_item_origins = artifacts, rods
- The game remembers where you find items. If you want this item origin
- memory listed in your dumps, use this option to select which items get
- annotated. Available selectors are:
- artifacts, ego_arm, ego_weap, jewellery, runes,
+ locations of each kill are displayed. Use 'none' to suppress
+ place display altogether, 'all' to display all known (up to 5)
+ kill places, anything else to the default of showing kill places
+ only for single kills
+
+dump_item_origins = artefacts, rods
+ The game remembers where you find items. If you want this item
+ origin memory listed in your dumps, use this option to select
+ which items get annotated. Available selectors are:
+ artefacts, ego_arm, ego_weap, jewellery, runes,
rods, staves, books, all, none.
If you use multiple dump_item_origins lines, the last line takes
effect; all preceding lines are ignored.
- If you don't want any items to be annotated, set dump_item_origins to
- none, and set dump_item_origin_price to -1.
+ If you don't want any items to be annotated, set
+ dump_item_origins to none, and set dump_item_origin_price to -1.
dump_item_origin_price = -1
- Item origins are dumped if the price of the item is greater than or
- equal to this amount. Set this to -1 to prevent selection by price.
+ Item origins are dumped if the price of the item is greater than
+ or equal to this amount. Set this to -1 to prevent selection by
+ price.
dump_message_count = 7
- The number of last messages to be displayed in character dump files.
+ The number of last messages to be displayed in character dump
+ files.
dump_order = header,hiscore,stats,misc,notes,inventory,
dump_order += skills,spells,overview,mutations,messages,screenshot
dump_order += kills
Controls the order of sections in the dump. You can use multiple
- dump_order lines - all lines but the first must use dump_order +=
+ dump_order lines - all lines but the first must use
+ dump_order +=
- Two optional dump sections are turns_by_place and kills_by_place,
- which add detailed statistics to where turns were spent and monsters
- were killed. You can add them to your dump as:
+ Two optional dump sections are turns_by_place and
+ kills_by_place, which add detailed statistics to where turns
+ were spent and monsters were killed. You can add them to your
+ dump as:
+ dump_order += turns_by_place, kills_by_place
dump_order += turns_by_place, kills_by_place
@@ -1224,11 +1274,9 @@ dump_order += kills
5-b Notes.
--------------
-Crawl can automatically log certain events during play. You can read these in
-the dump or morgue files. Below are options for tweaking this behaviour.
-
-use_notes = true
- Set to true to get note-taking. The following events are logged:
+Crawl can automatically log certain events during play. You can read
+these in the dump or morgue files. Below are options for tweaking this behaviour.
+The following events are logged:
- Gaining or losing a level
- Entering a dungeon level for the first time
- Memorizing a spell of higher level than any learned before
@@ -1243,83 +1291,88 @@ use_notes = true
- Gaining or losing mutations
- Reaching significant levels in a skill (see below)
- Dying
- You can use the command ':' for manually adding notes.
+You can use the command ':' for manually adding notes.
user_note_prefix = <string>
Prefixes manually added notes with the given string, to make
them easier to find.
note_items = <regexes>
- When an item is identified, it will be noted if it is an artifact
- (fixed, unrand, or random) or if its short description matches a regex.
- E.g.
- note_items = rod,book,rune,acquirement
+ When an item is identified, it will be noted if it is an
+ artefact
+ (fixed, unrand, or random) or if its short description matches a
+ regex. E.g.
+ note_items = rod,book,rune,acquirement
+note_monsters = <regex list>
+ Monsters whose name matches an item in this comma-separated list
+ are considered interesting. You can have multiple note_monsters
+ lines. E.g.
+ note_monsters = Klown,orb of fire
+
ood_interesting = 8
- Monsters which are out of depth (OOD for short) for their current
- level, e.g. a dragon on level 2, will be noted if they are out of depth
- by at least ood_interesting levels. To disable OOD monster noting, set
- ood_interesting to 500; the default is 8.
+ Monsters which are out of depth (OOD for short) for their
+ current level, e.g. a dragon on level 2, will be noted if they
+ are out of depth by at least ood_interesting levels. To disable
+ OOD monster noting, set ood_interesting to 500.
Unique monsters are always noted, regardless of this setting.
OOD monsters are only noted in the main dungeon.
note_hp_percent = 5
- If your HP falls below a certain note_hp_percentage of your max HP, a
- note will be taken. There is some code to avoid repetitions of notes
- based on the same incident.
+ If your HP falls below a certain note_hp_percentage of your max
+ hit points, a note will be taken. There is some code to avoid
+ repetitions of notes based on the same incident.
note_skill_levels = 1,5,13,27
- This sets which skill levels are noteworthy. You can have multiple
- note_skill_levels lines. The default is nothing (no notes.)
+ This sets which skill levels are noteworthy. You can have
+ multiple note_skill_levels lines. The default is nothing (no
+ notes.)
note_all_skill_levels = false
- This is a shortcut for note_skill_levels = 1,2,..,27. If you set this
- to true, all skill levels are noteworthy.
+ This is a shortcut for note_skill_levels = 1,2,..,27. If you set
+ this to true, all skill levels are considered noteworthy.
note_skill_max = false
- Setting this option will cause a note whenever a new maximum in skill
- levels is reached. If note_skill_max is true and note_skill_levels is
- nonempty, notes will be taken whenever either of the criteria are met.
-
-note_monsters = <regex list>
- Monsters whose name matches an item in this comma-separated list are
- considered interesting. You can have multiple note_monsters lines. E.g.
- note_monsters = Klown,orb of fire
+ Setting this option will cause a note whenever a new maximum in
+ skill levels is reached. If note_skill_max is true and
+ note_skill_levels is nonempty, notes will be taken whenever
+ either of the criteria are met.
+note_all_spells = true
+ Will add a note for each spell memorised.
+
note_messages = <regex list>
Messages which match an item in this comma-separated list are
- considered interesting. You can have multiple note_messages lines. E.g.
- note_messages = Something interferes
- note_messages = protects you from harm
+ considered interesting. You can have multiple note_messages
+ lines. E.g.
+ note_messages = Something interferes
+ note_messages = protects you from harm
If you want all banishments to the Abyss noted, use
- note_messages = [bB]anish.*Abyss
+ note_messages = [bB]anish.*Abyss
If you want a note when your draconian scales turn <colour>, use
- note_messages = Your scales start
+ note_messages = Your scales start
-note_all_spells = true
- Will add a note for each spell memorised.
6- Miscellaneous.
-==============
+==================
6-a All OS.
---------------
macro_meta_entry = true
- macro_meta_entry lets you specify non-printable keycodes like \{3} when
- creating a macro. For instance, if you want to keymap 0 to Escape, you'd
- use a target keycode of \{27}.
+ macro_meta_entry lets you specify non-printable keycodes like
+ \{3} when creating a macro. For instance, if you want to keymap
+ 0 to Escape, you'd use a target keycode of \{27}.
mouse_input = false
- When enabled, the mouse_input option allows the game to use
+ When enabled, the mouse_input option allows the game to use
mouse input events on certain platforms (Windows and Unix).
Note that the extent of mouse support varies greatly across
- platforms and is strongly influenced by your terminal
- settings.
+ platforms and is strongly influenced by your terminal settings.
- On Unixes, you're only likely to get mouse support working
- with ncurses in xterms (specifically your $TERM probably needs
- to contain "xterm" for ncurses to activate its mouse events;
+ On Unixes, you're only likely to get mouse support working with
+ ncurses in xterms (specifically your $TERM probably needs to
+ contain "xterm" for ncurses to activate its mouse events;
if you're running Crawl in GNU screen in an xterm, the mouse
will probably not work).
@@ -1330,14 +1383,37 @@ mouse_input = false
right-clicking the titlebar of your command-prompt, selecting
Properties and disabling QuickEdit in the Options tab.
+wiz_mode = (no | never | yes)
+ Wizard mode options (available only in WIZARD compiles):
+ yes -- start games in wizard mode (game will not be scored)
+ no -- still allows player to enter wizard mode after start
+ of game
+ never -- never allow a wizard command to be used
+
+char_set = (ascii | ibm | dec | unicode)
+ Chooses different character sets for the game play screen. DOS
+ and Windows users will want to use the IBM character set, Unix
+ users will prefer DEC or plain ASCII.
+
+ On Unix, Crawl may be built with Unicode support, in which case
+ you can use char_set = unicode to use unicode characters in the
+ map display.
+
+classic_item_colours = false
+ Crawl uses 4.0 b26/0.1.x-like item colours if
+ classic_item_colours is set to true. The default (false) is to
+ use the new 0.2 item colours.
+ This option will not affect the colour of existing items, only
+ items generated after the option is set.
+
colour.OLDCOLOUR = NEWCOLOUR
- Useful for terminals where some colours are hard to read (and cannot
- be adjusted), as well as for creating a custom scheme, especially when
- used with the background option on a terminal with a non-black
- background.
- Format is colour.OLDCOLOUR = NEWCOLOUR, later rules take preference and
- the NEWCOLOUR is always literal (ie. it won't re-evaluate to a
- different colour).
+ Useful for terminals where some colours are hard to read (and
+ cannot be adjusted), as well as for creating a custom scheme,
+ especially when used with the background option on a terminal
+ with a non-black background.
+ Format is colour.OLDCOLOUR = NEWCOLOUR, later rules take
+ preference and the NEWCOLOUR is always literal (ie. it won't
+ re-evaluate to a different colour).
The colours are:
black, blue, green, cyan, red, magenta, brown, lightgrey,
darkgrey, lightblue, lightgreen, lightcyan, lightred,
@@ -1347,169 +1423,149 @@ colour.OLDCOLOUR = NEWCOLOUR
colour.lightcyan = cyan
colour.yellow = brown
-wiz_mode = (no | never | yes)
- Wizard mode options (available only in WIZARD compiles):
- yes -- start games in wizard mode (game will not be scored)
- no -- still allows player to enter wizard mode after start of game
- never -- never allow a wizard command to be used
-
-char_set = (ascii | ibm | dec | unicode)
- Chooses different character sets for the game play screen. DOS and
- Windows users will want to use the IBM character set, Unix users will
- prefer DEC or plain ASCII.
-
- On Unix, Crawl may be built with Unicode support, in which case you
- can use char_set = unicode to use unicode characters in the map
- display.
-
cset_ascii, cset_ibm, cset_dec, cset_unicode, cset_any
- Can be used to change individual characters in a specific character
- set (the character set used for display is determined by the char_set
- option). The syntax is the same for all of these; cset_any changes
- characters in all character sets.
+ Can be used to change individual characters in a specific
+ character set (the character set used for display is determined
+ by the char_set option). The syntax is the same for all of
+ these; cset_any changes characters in all character sets.
cset_XXX = <dungeon_character_name : symbol>
a list of these is allowed, as well.
The possible entries for dungeon_character_name are:
- wall, wall_magic, floor, floor_magic, door_open, door_closed, trap,
- stairs_down, stairs_up, altar, arch, fountain, wavy, statue,
- invis_exposed, item_detected, item_orb, item_weapon, item_armour,
- item_wand, item_food, item_scroll, item_ring, item_potion,
- item_missile, item_book, item_stave, item_miscellany, item_corpse,
- item_gold, item_amulet, cloud
+ wall, wall_magic, floor, floor_magic, door_open, door_closed,
+ trap, stairs_down, stairs_up, altar, arch, fountain, wavy,
+ statue, invis_exposed, item_detected, item_orb, item_weapon,
+ item_armour, item_wand, item_food, item_scroll, item_ring,
+ item_potion, item_missile, item_book, item_stave,
+ item_miscellany, item_corpse, item_gold, item_amulet, cloud
Most of these are self-explanatory. "arch" is used for shops and
portals. "floor_magic" and "wall_magic" are used to display
- magic-mapped squares on the level map. "invis_exposed" is the character
- for water creatures submerged in shallow water, or invisible creatures
- wading in shallow water.
+ magic-mapped squares on the level map. "invis_exposed" is the
+ character for water creatures submerged in shallow water, or
+ invisible creatures wading in shallow water.
- Symbols can be specified using a letter, or by a number (decimal code),
- or a hexadecimal number (prefixed with x):
+ Symbols can be specified using a letter, or by a number (decimal
+ code), or a hexadecimal number (prefixed with x):
For an example on IBM displays,
- cset_ibm = wall:219, arch:0, wavy:x7E
- shows walls as solid blocks, shops and portals as '0', and water as
- '~'.
+ cset_ibm = wall:219, arch:0, wavy:x7E
+ shows walls as solid blocks, shops and portals as '0', and water
+ as '~'.
feature = <regex> { <symbol>, <magicmap symbol>, <view colour>,
<levelmap_magic_colour>, <levelmap_seen_colour>,
<emphasised_colour>, <levelmap_emphasised_colour> }
- where <regex> is a regular expression describing a dungeon feature.
- This regex should match the description when using the 'x' command.
- In case the regex matches several descriptions, all such features are
- affected.
+ where <regex> is a regular expression describing a dungeon
+ feature. This regex should match the description when using the
+ 'x' command. In case the regex matches several descriptions, all
+ such features are affected.
- The list in {...} specifies the appearance of the dungeon feature(s),
- and should be self-explanatory. <symbol> can be used to override the
- above cset options, or also to distinguish among subtypes of a
- character.
+ The list in {...} specifies the appearance of the dungeon
+ feature(s), and should be self-explanatory. <symbol> can be used
+ to override the above cset options, or also to distinguish among
+ subtypes of a character.
- 'magic' always refers to magic mapping. So the <magicmap symbol> entry
- determines what symbol will be used for features only detected via
- magic mapping.
+ 'magic' always refers to magic mapping. So the <magicmap symbol>
+ entry determines what symbol will be used for features only
+ detected via magic mapping.
'emphasised_colour' refers to the colour used to highlight
- unvisited stone stairs; for non-stair features, setting
- emphasis colours does nothing useful.
+ unvisited stone stairs; for non-stair features, setting emphasis
+ colours does nothing useful.
- Leading parameters in the {...} list can be omitted by leaving them
- blank and using placeholder commas. Trailing parameters can be omitted
- without placeholder commas.
+ Leading parameters in the {...} list can be omitted by leaving
+ them blank and using placeholder commas. Trailing parameters can
+ be omitted without placeholder commas.
- Multiple feature option lines can be used, as can multiple feature
- descriptions strung together on the same line separated by semicolons.
+ Multiple feature option lines can be used, as can multiple
+ feature descriptions strung together on the same line separated
+ by semicolons.
Examples:
* Colour rock walls red:
- feature = rock wall { , , red }
+ feature = rock wall { , , red }
* Use # for metal walls in all character sets:
- feature = metal wall {#}
+ feature = metal wall {#}
Symbols can be specified as with cset:
- feature = metal wall {#}
- feature = metal wall {35}
- feature = metal wall {x23}
+ feature = metal wall {#}
+ feature = metal wall {35}
+ feature = metal wall {x23}
all do the same thing.
mon_glyph = <monster name or symbol> : <colour> <glyph>
The mon_glyph option allows you to customise the symbol and
colour used to display a monster.
- You can customise symbols based on monster names or their existing
- symbols. For instance, if you want to put elves on E and efreeti
- on e, you can do this:
+ You can customise symbols based on monster names or their
+ existing symbols. For instance, if you want to put elves on E
+ and efreeti on e, you can do this:
- mon_glyph = e : E
- mon_glyph = E : e
+ mon_glyph = e : E
+ mon_glyph = E : e
- If you want to change the symbol for a monster that uses a
- space as a symbol, specify an underscore on the left:
+ If you want to change the symbol for a monster that uses a space
+ as a symbol, specify an underscore on the left:
- mon_glyph = _ : #
+ mon_glyph = _ : #
(That changes shades to use #.)
- You can specify a different symbol, or a colour, or both, in
- any order. Here are more examples:
+ You can specify a different symbol, or a colour, or both, in any
+ order. Here are more examples:
- mon_glyph = deep elf annihilator : E lightmagenta
- mon_glyph = Xtahua : lightmagenta D
- mon_glyph = large zombie : darkgrey
- mon_glyph = small simulacrum : x
+ mon_glyph = deep elf annihilator : E lightmagenta
+ mon_glyph = Xtahua : lightmagenta D
+ mon_glyph = large zombie : darkgrey
+ mon_glyph = small simulacrum : x
(The left hand side of the : is case-sensitive.)
- You can specify symbols using their code points using the
- syntax as shown in the "feature" option. If you're using
+ You can specify symbols using their code points using the syntax
+ as shown in the "feature" option. If you're using
char_set=unicode, you can use unicode code points:
- mon_glyph = draconian scorcher : x6e9
+ mon_glyph = draconian scorcher : x6e9
A single _ is treated as a space; if you want a real underscore,
put a \ in front of it like this:
- mon_glyph = player ghost : \_
-
-classic_item_colours = false
- Crawl uses 4.0 b26/0.1.x-like item colours if classic_item_colours is
- set to true. The default (false) is to use the new 0.2 item colours.
- This option will not affect the colour of existing items, only items
- generated after the option is set.
+ mon_glyph = player ghost : \_
6-b DOS and Windows.
------------------------
dos_use_background_intensity = false
On DOS and Windows, if you're using a console that can do
- high-intensity background colours, set this option to true for superior
- friend-branding. If your console doesn't like this option, some
- friendly monsters will appear as blinking characters (and setting this
- option to false may be advisable to preserve your sanity in such
- cases).
+ high-intensity background colours, set this option to true for
+ superior friend-branding. If your console doesn't like this
+ option, some friendly monsters will appear as blinking
+ characters (and setting this option to false may be advisable to
+ preserve your sanity in such cases).
6-c Unix
------------
-background = <colour>
- Sets the default background colour by name (defaults to BLACK). This
- may be useful if you're using a terminal with a background colour other
- than black (such as an xterm), but this option is still experimental
- and the results may not be very good.
+background = black
+ Sets the default background colour by name (defaults to BLACK).
+ This may be useful if you're using a terminal with a background
+ colour other than black (such as an xterm), but this option is
+ still experimental and the results may not be very good.
use_fake_cursor = false
If true, Crawl draws the cursor explicitly on the level-map and
- targeting screens instead of relying on the term to draw the cursor.
- Use this if your term cannot show a cursor over darkgrey/black
- squares.
+ targeting screens instead of relying on the term to draw the
+ cursor. Use this if your term cannot show a cursor over
+ darkgrey/black squares.
-7- Inline Lua
-------------------
+7- Inline Lua
+==============
-Lua code can be used directly in your init.txt/.crawlrc. You can use
-Lua to selectively include parts of your init.txt (based on character
-type, for instance) using this syntax:
+Lua code can be used directly in your init.txt/.crawlrc. You can use Lua
+to selectively include parts of your init.txt (based on character type,
+for instance) using this syntax:
< Lua code >
or
@@ -1536,10 +1592,10 @@ autopickup = $?+"/
autopickup = $?+"/!%
: end
- or
+ or
: if you.race() == "Hill Orc" then
priest = Beogh
: else
priest = Yredelemnul
-:end
+: end
diff --git a/crawl-ref/docs/level-design.txt b/crawl-ref/docs/level-design.txt
index 4914025362..5571bec243 100644
--- a/crawl-ref/docs/level-design.txt
+++ b/crawl-ref/docs/level-design.txt
@@ -11,20 +11,22 @@ Contents: A. Introduction
H. Lua reference
I. Feature names
J. Map statistics
+ K. Portal vaults
A. Introduction
-----------------
-All fixed level information resides in various .des files to be found in
+All fixed level information resides in various .des files to be found in
the dat directory. If you are interested in adding some vaults, say, start
with the existing ones and modify them. Currently, the following .des files
are in use:
bazaar.des - entrances to bazaar portal vaults, and bazaars proper
+ crypt.des - Crypt:5, Tomb:1, Tomb:2, Tomb:3
elf.des - Elf:7
- entry.des - entry vaults (each game - but not tutorial games - uses one of
+ entry.des - entry vaults (each game - but not tutorial games - uses one of
these premade maps for the vicinity of the entrance)
- float.des - floating vaults
+ float.des - floating vaults
hells.des - hell entrances, Geryon's vestibule, Coc:7, Tar:7, Dis:7, Geh:7
hive.des - hive entrances, Hive:4
lab.des - labyrinths exits and flavour vaults
@@ -35,13 +37,13 @@ are in use:
pan.des - vaults of the Pan demon lords, Pan minivaults
portal.des - portal vaults entrances
temple.des - Ecumenical Temples, and Temple entrances
- vaults.des - entrances for the Vaults, Vaults:8, Blades, Tomb:?
+ vaults.des - entrances for the Vaults, and Vaults:8
zot.des - Zot:5
Kinds of Vaults
---------------
-The different kinds of vaults used by Crawl are described briefly below. In
+The different kinds of vaults used by Crawl are described briefly below. In
most cases, when the dungeon builder places a vault on a level, the rest of the
level (assuming the vault is not a full-map vault) is generated as
rooms+corridors. The only exceptions to this are branch entry vaults and
@@ -131,12 +133,12 @@ sections.
"SHUFFLE: de" may replace all 'd' with 'e' in the map.
"SUBST: 1=12." may replace each '1' with either '1' or '2' or '.'.
"MONS: butterfly, plant" turns all '1' into butterflies, and '2' into plants.
-"ITEM: stone" turns all 'd' into stones
+"ITEM: stone" turns all 'd' into stones.
"ITEM: w:10 any book / w:90 nothing" turns all 'e' into a book
(with 10% chance) or creates no object (with 90% chance).
-
+
The symbols on the map:
- x - rock wall
+ x - rock wall
w - water (could be deep or shallow)
W - shallow water
. - plain floor
@@ -146,8 +148,8 @@ The symbols on the map:
2 - second monster from the list (plant)
d - first item from the list (here stones)
e - second item from the list (here occassionally a book)
-
-
+
+
D. Map symbols
----------------
@@ -156,6 +158,9 @@ Terrain
x - rock wall (DNGN_ROCK_WALL)
X - permanent rock wall - always undiggable (DNGN_PERMAROCK_WALL)
c - stone wall - only affected by Shatter (DNGN_STONE_WALL)
+ m - clear rock wall (DNGN_CLEAR_ROCK_WALL)
+ n - clear stone wall - only affected by Shatter (DNGN_CLEAR_STONE_WALL)
+ o - clear permanent rock wall - always undiggable (DNGN_CLEAR_PERMAROCK_WALL)
v - metal wall - grounds electricity (DNGN_METAL_WALL)
b - crystal wall - reflects cold and fire (DNGN_GREEN_CRYSTAL_WALL)
a - wax wall - can melt (DNGN_WAX_WALL)
@@ -168,8 +173,8 @@ Terrain
w - deep water - can be randomly turned into shallow water by the
level-builder; you can prevent this conversion with the no_pool_fixup TAG.
Also, water may automatically receive water creatures! For entry
- vaults, avoid this with the no_monster_gen TAG.
- l - lava - again, use the no_monster_gen TAG for entry vaults!
+ vaults, avoid this with the no_monster_gen TAG or KMASK.
+ l - lava - again, use the no_monster_gen TAG or KMASK for entry vaults!
Features
--------
@@ -177,29 +182,29 @@ Features
not use any @, the dungeon builder will connect at least one floorspace on
the edge of your map to the rest of the level; if there is no floorspace
on the edge of your map, it will be isolated.
- }{ - Stone stairs - You must be able to reach these from each other. The
- { upstair is also the stair on which the player will enter the
+ }{ - Stone stairs - You must be able to reach these from each other. The
+ { upstair is also the stair on which the player will enter the
dungeon for entry vaults.
)( - Stone stairs, set 2.
][ - Stone stairs, set 3.
- >< - extra rock stairs - you can leave the level by these but will rarely be
- placed on them from another level
+ >< - escape hatches - you can leave the level by these but will usually
+ not land on stairs/hatches
I - orcish idol (does nothing)
^ - random trap.
~ - random trap suitable for the branch and depth the map is being used.
- A - Vestibule gateway (opened by Horn).
+ A - Vestibule gateway (opened by Horn).
B - Altar. These are assigned specific types (eg of Zin etc) in dungeon.cc,
in order.
C - Random Altar.
- F - Usually a Granite Statue, but may be Orange or Silver or Ice (1 in 100)
- G - Granite statue (does nothing) - you can see through but not walk through
- H - orange crystal statue (attacks mind)
- S - Silver statue (summons demons). Avoid using (rare).
+ F - Usually a Granite Statue, but may be Orange or Silver or Ice (1 in 100)
+ G - Granite statue (does nothing) - you can see through but not walk through.
+ Also, sight-based effects like smiting work past granite statues, as does
+ apportation.
T - Water fountain
U - Magic fountain
@@ -208,7 +213,7 @@ Features
Note: Due to the level maker having seen incremental improvements over
the years, there are some inconsistencies. For examples, dangerous
statues (orange, silver ice) are now genuine monsters. In particular,
-the 'H' and 'S' glyphs could be dispensed with (but many older vaults
+the 'H' and 'S' glyphs should be dispensed with (but many older vaults
use them, of course) - especially as there's no glyph for ice statues.
Also, the most of the other feature glyphs can be replaced with KFEAT:
@@ -216,7 +221,7 @@ lines. The same goes for some item glyphs ('R', 'Z') which
could be replaced by KITEM: lines.
Items
------
+-----
$ - gold
% - normal item
* - higher level item (good)
@@ -233,7 +238,7 @@ Monsters
9 - +5 depth monster
8 - (+2) * 2 depth monster (aargh!). Can get golden dragons and titans
this way.
- 1-7 - monster array monster. See section below on MONS: arrays for more
+ 1-7 - monster array monster. See section below on MONS: arrays for more
information
@@ -243,400 +248,472 @@ D. Header information
(All declarations apart from NAME: are translated to Lua function
calls behind the scenes. See the Lua reference for more information.)
-NAME: a_string
- Each map must have a unique name. Underscores and digits are ok.
-
-ORIENT: (float |encompass | north | northwest | ... | southeast)
-
- Some kind of ORIENT: line is mandatory for vaults; skipping
- ORIENT: makes your map a minivault. As a rule of thumb, if
- you're writing a small random map, skip the ORIENT: line and
- make it a minivault. For special levels and (branch) entry
- vaults, you do need an ORIENT: line.
-
- * "float": The dungeon builder puts your vault wherever it wants to.
- * "some_direction": The vault lies along that side of the map:
- xxxxxxxxxx xxxxxxxxxxxxx
- xORIENT:Nx xORIENT:NW|..
- x.VAULT..x x.VAULT...|..
- x--------x x---------|..
- xrest....x xrest........
- x...of...x x.....of.....
- x...levelx x.......level
- ...which brings us to padding. With any some_direction orientation,
- you need 6 layers of x-padding along any level-edge that the vault
- borders. For instance, if your map is ORIENT: north, you must have a
- 6 deep border of rock wall (or any other kind of wall) along the
- northern, eastern, and western edges of the map.
- * "encompass": the vault completely occupies the entire level.
- Padding is needed on all 4 sides.
-
- ORIENT: float vaults need no padding and give a lot of
- flexibility to the dungeon generator; float should generally
- be preferred to other ORIENT: settings for new vaults.
-
-
-DEPTH: For random vaults, branch entry vaults, and minivaults, this
- specifies the range of levels where the vault may be placed
- in the dungeon. E.g.
-
- DEPTH: 7-20
-
- DEPTH: does not force a map to be placed in a particular place; it
- applies only when the dungeon builder is looking for a random vault
- or minivault, so you can control at what depths your vault gets
- placed.
-
- A simple DEPTH: declaration that does not specify a branch
- applies to all branches. A map declared with depth 7-20 could
- be used in the Lair, for instance. (Lair:1 will be treated as
- a depth of 12 if the Lair entrance is on D:11.)
-
- You can constrain a map by branch:
-
- DEPTH: Lair:7-9
-
- (Anywhere between levels 7-9 of the Lair, inclusive.)
-
- You can apply multiple constraints in one DEPTH line,
- comma-separated:
-
- DEPTH: 7-20, !12-14
-
- (Anywhere in the dungeon between depths 7-20, but not on levels
- 12-14.)
-
- DEPTH: 7-20, !Orc
-
- (Anywhere in the dungeon between depths 7-20, but never in the Orcish
- Mines.)
-
- DEPTH: Lair:*
-
- (Anywhere in the Lair. Can also be expressed as "DEPTH: Lair".)
-
- Maps that do not specify a DEPTH: attribute will inherit their depth
- constraints from the closest preceding default-depth: line. If there
- is no preceding default-depth directive in the .des file, the map will
- have no DEPTH: constraint. Note that maps without a DEPTH: constraint
- cannot be selected as random vaults or minivaults.
-
-CHANCE: (number with 10 being default)
- For entry vaults and any other vaults randomly picked from among
- a set, this type of line affects the likelihood of the given vault
- being picked in a given game. The default CHANCE: is 10. The
- likelihood of a vault getting picked is:
- [vault's CHANCE: / sum of all CHANCE:s of vaults of that type]
-
-PLACE: Used to specify certain special levels. Existing special levels are:
- Temple, Hell, Dis:7, Geh:7, Coc:7, Tar:7, Hive:4, Vault:8, Snake:5,
- Elf:7, Slime:6, Blade, Zot:5, Tomb:1, Tomb:2, Tomb:3, Swamp:5.
-
- PLACE can also be used to specify arbitrary places, like D:3, which
- will force the map (or one of the maps with PLACE: D:3) to be picked
- when D:3 is generated.
-
- PLACE cannot be used to specify places in the Abyss, Pandemonium,
- or Labyrinths.
-
- PLACE can be used with random vaults and minivaults for testing them.
-
-TAGS: allow_dup, generate_awake, mini_float, no_item_gen, no_monster_gen,
- no_pool_fixup, orc_entry, uniq_BAR
-
- Tags go an a TAGS: line and are space-separated. Valid tags are:
- * "allow_dup": Vaults are normally used only once per game. If you
- have a vault that can be used more than once, use
- allow_dup to tell the dungeon builder that the vault
- can be reused.
- * "dummy": this tag indicates that the vault is a stub; if the dungeon
- builder picks a dummy vault, it pretends no vault was
- selected. Dummies are used to reduce the probability
- of other vaults at the same depth / place.
- * "entry": this tag MUST be there for a vault to be pickable as
- an entry vault.
- * "generate_awake": Monsters placed (using MONS, KMONS) in this
- vault will be generated awake.
- * "no_item_gen": Prevents random item generation in the vault.
- Items explicitly placed by the vault are not affected.
- * "mini_float": applicable only to minivaults, requests that
- the dungeon builder pick random exits from the minivault and
- connect it to the rest of the level, similar to the exit
- behaviour for floating vaults.
- * "no_monster_gen": Prevents random monster generation at the time
- of the vault's creation. Highly advised for entry vaults with
- a player-hostile geography, MUST-HAVE for those with water/lava.
- * "no_pool_fixup": prevents water squares next to land from being
- randomly converted from deep water (the default) to shallow.
- * "branch_entry" eg. "orc_entry", "lair_entry" etc.
- If chosen, these maps will contain the stairs for that
- branch. Use "O" to place the stairs. If a branch has very
- few entries, a dummy entry is advisable to make sure the
- player doesn't get bored of the same few entries recycled
- ad nauseam.
- * "mnoleg" or the name of some other pandemonium lord. This makes
- the map eligible for said pan lord's lair.
- * "uniq_BAR": (uniq_ with any suffix) specifies that only one vault
- with this tag can be used in a game.
-
-FLAGS: no_rotate, no_hmirror, no_vmirror
- Flags go on a FLAGS: line and are space-separated. Valid flags are:
- * "no_rotate": Normally, the dungeon builder can, at its whim,
- rotate your vault. This flag tells it, "hey, don't do that to my
- vault!"
- * "no_hmirror": Like no_rotate, but for horizontal mirroring.
- * "no_vmirror": Like no_rotate, but for vertical mirroring.
-
-ITEM: (list of items, separated by comma)
- These are used to help place specified items at specific places
- within a vault. They create an array with up to 8 positions. What's
- in the first position in the array will be used when the dungeon
- builder sees a "d" in the vault definition, the second will be used
- for "e"s, etc. Positions are comma-separated; several ITEM: lines
- are possible as well. The following defines letters 'd' - 'g':
- ITEM: stone, ring mail, meat ration, ring of hunger
-
- Positions can contain multiple possibilities, one of which the
- builder will choose randomly. Separate such multiple possibilities
- using a slash. Note that "nothing" (without the quotes) is a valid
- possibility. The random choice is done for each individual occurence
- of the letter. You can also give possibilities a "weight," which
- affects their chance of being picked. The default weight is 10. You
- can abbreviate "weight:30" by "w:30". The chance to pick a
- possibility is
- [possibility's weight: / sum of all weight:s in that array position]
-
- For example, the following line makes letter 'd' into a bread ration
- with 50% chance, or apple or orange with 25% chance each:
-
- ITEM: bread ration / w:5 apple / w:5 orange
-
- Modifiers:
- * "q:N" sets the item quantity to N (if N > 0). Does nothing
- if the item is not stackable.
- * "good_item" makes the builder try to make the item a good one.
- * "any" by itself gives random choice; you can combine "any" with
- "good_item."
- * "any book", "any misc" etc. gives a random item of that class.
- Valid item class names are: gold, weapon, missile, armour,
- wand, food, scroll, jewelry, potion, book, staff, orb,
- misc, carrion. All of these are usable in map definitions,
- apart from "orb" and "carrion".
-
- Limitations: You can't specify curse status nor item race,
- nor can you give specific egos, nor can give fixedarts. You
- also can't lay down corpses, skeletons, or chunks.
-
-MONS: (list of monsters)
- These are used to help place specific monsters at specific places
- in a vault. They create an array with up to 7 positions. What's in
- the first position in the array will be used when the dungeon
- builder sees a "1" in the vault definition, the second for "2,"
- etc. Note that if, for example, you place a 3 on the map, but your
- MONS: line has no third position, the 3 will be filled with
- RANDOM_MONSTER.
- You can use weights as for ITEM: lines.
-
- Individual monsters may be prefixed with the "generate_awake"
- (without the quotes). Use this sparingly:
- MONS: generate_awake giant beetle
-
- Monsters can also be given colours that override their default
- colour. Use this *very* sparingly:
- MONS: col:darkgrey fungus
-
- Note that 8, 9, 0 also place monsters (see the table).
-
-
-COLOUR: . = green / blue:5 / red / none
- COLOUR: allows you to attach explicit colours to any feature.
- Explicit colours will override the default colour for that
- feature. The example shown above colours all . (floor) in the
- map green, blue, red, or unchanged (use the default colour).
-
- You can use : to specify that all glyphs get the same colour:
- COLOUR: x : red / blue
- will colour all rock walls in the map red, or all rock
- walls blue.
-
- COLOUR: should be used very sparingly, and only for features
- where it won't cause confusion (i.e.: never re-colour features
- like lava!)
-
-SHUFFLE: def, 12/3?
- This allows you to randomly permute glyphs on the map. There are
- two ways:
-
- SHUFFLE: 123w (i.e. list of glyphs, NOT slash-separated)
- could, for example, swap all occurences of "1" with "2", as well as
- swapping all "3" with "w" (or any other of the 24 possibilities).
-
- SHUFFLE: 12/3w (i.e. list of slash-separated blocks of same size)
- will either do nothing or swap all "1" with "3" and then also swap
- "2" with "w" everywhere.
-
- Several SHUFFLE: lines can be used, and mixed with SUBST:, and the
- shuffles and substitutions will be applied in order. You can also
- put multiple SHUFFLEs on one line, comma-separated. Shuffles cannot
- use , or /. All spaces are stripped before shuffling.
-
-SUBST: ?=xc, !:bv, 1=2 1:100
- The SUBST: directive allows you to specify a placeholder symbol
- that is replaced with a random glyph from a set. For instance:
-
- SUBST: ? = TUV
- replaces occurrences of ? with one of TUV. Since whitespaces are
- irrelevant, this is the same as
- SUBST: ? = T U V
-
- SUBST: ? = T:20 U V
- makes T twice as likely to be used as U or V (the default weight
- is 10). Note that there has to be at least one space before and
- after T:20 and that whitespace in T:20 is not permitted.
-
- SUBST: ? : TUV
- replaces occurrences of ? with one of TUV, and guarantees that all
- occurrences of ? will get the same replacement symbol.
-
- The placeholder and replacement symbols can be any non-space,
- printable character, including : and =, apart from commas. For
- example, the following is valid:
- SUBST: = = +=:123def"
-
- SUBST: lines can safely replace symbols with themselves, as in:
- SUBST: w = wW
-
- Multiple SUBST: lines can be used, and mixed with SHUFFLE:, and
- will be applied in order. Multiple substitutions can be performed
- on one line, using commas.
-
-NSUBST: ? = 3:w / *:l
-
- NSUBST is similar to SUBST, replacing placeholders with
- replacement values. Unlike SUBST, however, it allows you to
- replace different instances of the same placeholder with
- completely different substitutions. For instance:
-
- ? = 3:w / *:l
-
- replaces three occurrences (randomly selected) of ? with w
- and all others with l.
-
- You can use complex SUBST specifications:
-
- ? = 3= w .:15 A / *: =+CF
-
- This is equivalent to SUBST: ? = w .:15 A for three ? and
- SUBST: ? : =+CF for all the others.
-
- You use any number of NSUBST specifiers:
-
- ? = wW / l / A / 1234
-
- Each specifier is preceded by the number of symbols to apply
- it to, followed by : or = (: to use one substitution for all
- occurrences, = to randomly pick for each occurrence). If you
- omit the initial N: or N=, then 1= is assumed, except for the
- last spec where *= is assumed.
-
-KFEAT: Z = C / needle trap / antique armour shop / altar_zin
- The KFEAT: directive allows you to specify a placeholder symbol
- that is replaced with another symbol, named feature, trap, or
- shop. For example, the line above will replace occurrences of Z
- with C (random altar), a needle trap, an antique armour shop, or
- an altar of Zin. Different instances of Z may receive different
- replacements. To force a single replacement for all Z, use:
-
- KFEAT: Z : C / needle trap / antique armour shop
-
- You'll notice that 'Z' is the symbol of the Orb of Zot. Kxxx
- directives allow you to assign arbitrary definitions to any symbol.
+NAME: a_string
+ Each map must have a unique name. Underscores and digits are ok.
+
+ORIENT: (float |encompass | north | northwest | ... | southeast)
+
+ Some kind of ORIENT: line is mandatory for vaults; skipping
+ ORIENT: makes your map a minivault. As a rule of thumb, if
+ you're writing a small random map, skip the ORIENT: line and
+ make it a minivault. For special levels and (branch) entry
+ vaults, you do need an ORIENT: line.
+
+ * "float": The dungeon builder puts your vault wherever it wants to.
+ * "some_direction": The vault lies along that side of the map:
+ xxxxxxxxxx xxxxxxxxxxxxx
+ xORIENT:Nx xORIENT:NW|..
+ x.VAULT..x x.VAULT...|..
+ x--------x x---------|..
+ xrest....x xrest........
+ x...of...x x.....of.....
+ x...levelx x.......level
+ ...which brings us to padding. With any some_direction orientation,
+ you need 6 layers of x-padding along any level-edge that the vault
+ borders. For instance, if your map is ORIENT: north, you must have a
+ 6 deep border of rock wall (or any other kind of wall) along the
+ northern, eastern, and western edges of the map.
+ * "encompass": the vault completely occupies the entire level.
+ Padding is needed on all 4 sides.
+
+ ORIENT: float vaults need no padding and give a lot of
+ flexibility to the dungeon generator; float should generally
+ be preferred to other ORIENT: settings for new vaults.
+
+
+DEPTH: For random vaults, branch entry vaults, and minivaults, this
+ specifies the range of levels where the vault may be placed
+ in the dungeon. E.g.
+
+ DEPTH: 7-20
+
+ DEPTH: does not force a map to be placed in a particular place; it
+ applies only when the dungeon builder is looking for a random vault
+ or minivault, so you can control at what depths your vault gets
+ placed.
+
+ A simple DEPTH: declaration that does not specify a branch
+ applies to all branches. A map declared with depth 7-20 could
+ be used in the Lair, for instance. (Lair:1 will be treated as
+ a depth of 12 if the Lair entrance is on D:11.)
+
+ You can constrain a map by branch:
+
+ DEPTH: Lair:7-9
+
+ (Anywhere between levels 7-9 of the Lair, inclusive.)
+
+ You can apply multiple constraints in one DEPTH line,
+ comma-separated:
+
+ DEPTH: 7-20, !12-14
+
+ (Anywhere in the dungeon between depths 7-20, but not on levels
+ 12-14.)
+
+ DEPTH: 7-20, !Orc
+
+ (Anywhere in the dungeon between depths 7-20, but never in the Orcish
+ Mines.)
+
+ DEPTH: Lair:*
+
+ (Anywhere in the Lair. Can also be expressed as "DEPTH: Lair".)
+
+ Maps that do not specify a DEPTH: attribute will inherit their depth
+ constraints from the closest preceding default-depth: line. If there
+ is no preceding default-depth directive in the .des file, the map will
+ have no DEPTH: constraint. Note that maps without a DEPTH: constraint
+ cannot be selected as random vaults or minivaults.
+
+CHANCE: (number with 10 being default)
+ For entry vaults and any other vaults randomly picked from among
+ a set, this type of line affects the likelihood of the given vault
+ being picked in a given game. The default CHANCE: is 10. The
+ likelihood of a vault getting picked is:
+ [vault's CHANCE: / sum of all CHANCE:s of vaults of that type]
+
+PLACE: Used to specify certain special levels. Existing special levels are:
+ Temple, Hell, Dis:7, Geh:7, Coc:7, Tar:7, Hive:4, Vault:8, Snake:5,
+ Elf:7, Slime:6, Blade, Zot:5, Tomb:1, Tomb:2, Tomb:3, Swamp:5.
+
+ PLACE can also be used to specify arbitrary places, like D:3, which
+ will force the map (or one of the maps with PLACE: D:3) to be picked
+ when D:3 is generated.
+
+ PLACE cannot be used to specify places in the Abyss, Pandemonium,
+ or Labyrinths.
+
+ PLACE can be used with random vaults and minivaults for testing them.
+
+TAGS: allow_dup, generate_awake, mini_float, no_item_gen, no_monster_gen,
+ no_pool_fixup, orc_entry, uniq_BAR
+
+ Tags go an a TAGS: line and are space-separated. Valid tags are:
+ * "allow_dup": Vaults are normally used only once per game. If you
+ have a vault that can be used more than once, use allow_dup to tell
+ the dungeon builder that the vault can be reused.
+ * "dummy": this tag indicates that the vault is a stub; if the dungeon
+ builder picks a dummy vault, it pretends no vault was selected.
+ Dummies are used to reduce the probability of other vaults at the
+ same depth / place.
+ * "entry": this tag MUST be there for a vault to be pickable as an
+ entry vault.
+ * "generate_awake": Monsters placed (using MONS, KMONS) in this vault
+ will be generated awake.
+ * "no_item_gen": Prevents random item generation in the vault.
+ Items explicitly placed by the vault are not affected.
+ * "mini_float": applicable only to minivaults, requests that
+ the dungeon builder pick random exits from the minivault and
+ connect it to the rest of the level, similar to the exit behaviour
+ for floating vaults.
+ * "no_monster_gen": Prevents random monster generation at the time of
+ the vault's creation. Highly advised for entry vaults with a
+ player-hostile geography, MUST-HAVE for those with water/lava.
+ Can be applied only to particular symbols with KMASK.
+ * "no_pool_fixup": prevents water squares next to land from being
+ randomly converted from deep water (the default) to shallow.
+ * "branch_entry" eg. "orc_entry", "lair_entry" etc.
+ If chosen, these maps will contain the stairs for that
+ branch. Use "O" to place the stairs. If a branch has very
+ few entries, a dummy entry is advisable to make sure the
+ player doesn't get bored of the same few entries recycled
+ ad nauseam.
+ * "mnoleg" or the name of some other pandemonium lord. This makes
+ the map eligible for said pan lord's lair.
+ * "uniq_BAR": (uniq_ with any suffix) specifies that only one of
+ the vaults with this tag can be used in a game.
+
+FLAGS: no_rotate, no_hmirror, no_vmirror
+ Flags go on a FLAGS: line and are space-separated. Valid flags are:
+ * "no_rotate": Normally, the dungeon builder can, at its whim,
+ rotate your vault. This flag tells it, "hey, don't do that to my
+ vault!"
+ * "no_hmirror": Like no_rotate, but for horizontal mirroring.
+ * "no_vmirror": Like no_rotate, but for vertical mirroring.
+
+LFLAGS: Persistent, changeable per-level flags which affect game
+ behavior (FLAGS just controls how the vault is placed); should
+ only be used for vaults with ORIENT encompass or with PLACE.
+ This causes a level's flags to be set when the level is first
+ created. These flags can later be altered using Lua markers;
+ see the slime pit vault in lair.des, and the vaults in hell.des
+ and elf.des for examples.
+
+ Valid flags are: no_tele_control, which prevents the player
+ from using teleport control; not_mappable, which prevents
+ the player from remembering where they've been (like in
+ the Abyss), and no_magic_map, which prevents magic mapping
+ from working.
+
+BFLAGS: Persistent, changeable per-*branch* flags which affect game
+ behavior; should only be used for vaults which go on the fist
+ level of a particular branch. These flags can later be altered
+ using Lua markers; see the Tomb vaults in vaults.lua for an
+ example.
+
+ Valid flags are: no_tele_control, which prevents the player
+ from using teleport control; not_mappable, which prevents
+ the player from remembering where they've been (like in
+ the Abyss), and no_magic_map, which prevents magic mapping
+ from working.
+
+FLOORCOL: blue
+ FLOORCOL: allows you to set the floor colour for the level
+ the vault appears in. Should only be used for bazaars and
+ other portal vaults.
+
+ROCKCOL: yellow
+ ROCKCOL: allows you to set the colour of rock walls for the
+ level the vault appears in. Should only be used for bazaars and
+ other portal vaults.
+
+ITEM: (list of items, separated by comma)
+ These are used to help place specified items at specific places
+ within a vault. They create an array with up to 8 positions. What's
+ in the first position in the array will be used when the dungeon
+ builder sees a "d" in the vault definition, the second will be used
+ for "e"s, etc. Positions are comma-separated; several ITEM: lines
+ are possible as well. The following defines letters 'd' - 'g':
+ ITEM: stone, ring mail, meat ration, ring of hunger
+
+ Positions can contain multiple possibilities, one of which the
+ builder will choose randomly. Separate such multiple possibilities
+ using a slash. Note that "nothing" (without the quotes) is a valid
+ possibility. The random choice is done for each individual occurence
+ of the letter. You can also give possibilities a "weight," which
+ affects their chance of being picked. The default weight is 10. You
+ can abbreviate "weight:30" by "w:30". The chance to pick a
+ possibility is
+ [possibility's weight: / sum of all weight:s in that array position]
+
+ For example, the following line makes letter 'd' into a bread ration
+ with 50% chance, or apple or orange with 25% chance each:
+
+ ITEM: bread ration / w:5 apple / w:5 orange
+
+ Modifiers:
+ * "q:N" sets the item quantity to N (if N > 0). Does nothing
+ if the item is not stackable.
+ * "good_item" makes the builder try to make the item a good one.
+ * "any" by itself gives random choice; you can combine "any" with
+ "good_item."
+ * "any book", "any misc" etc. gives a random item of that class.
+ Valid item class names are: gold, weapon, missile, armour,
+ wand, food, scroll, jewelry, potion, book, staff, orb,
+ misc, carrion. All of these are usable in map definitions,
+ apart from "orb" and "carrion".
+
+ Limitations: You can't specify curse status nor item race,
+ nor can you give specific egos, nor can give fixedarts. You
+ also can't lay down corpses, skeletons, or chunks.
+
+MONS: (list of monsters)
+ These are used to help place specific monsters at specific places
+ in a vault. They create an array with up to 7 positions. What's in
+ the first position in the array will be used when the dungeon
+ builder sees a "1" in the vault definition, the second for "2,"
+ etc. Note that if, for example, you place a 3 on the map, but your
+ MONS: line has no third position, the 3 will be filled with
+ RANDOM_MONSTER.
+ You can use weights as for ITEM: lines.
+
+ Individual monsters may be prefixed with the "generate_awake"
+ (without the quotes). Use this sparingly:
+ MONS: generate_awake giant beetle
+
+ Monsters can also be given colours that override their default
+ colour. Use this *very* sparingly:
+ MONS: col:darkgrey fungus
+
+ Note that 8, 9, 0 also place monsters (see the table).
+
+
+COLOUR: . = green / blue:5 / red / none
+ COLOUR: allows you to attach explicit colours to any feature.
+ Explicit colours will override the default colour for that
+ feature. The example shown above colours all . (floor) in the
+ map green, blue, red, or unchanged (use the default colour).
+
+ You can use : to specify that all glyphs get the same colour:
+ COLOUR: x : red / blue
+ will colour all rock walls in the map red, or all rock
+ walls blue.
+
+ COLOUR: should be used very sparingly, and only for features
+ where it won't cause confusion (i.e.: never re-colour features
+ like lava!)
+
+SHUFFLE: def, 12/3?
+ This allows you to randomly permute glyphs on the map. There are
+ two ways:
+
+ SHUFFLE: 123w (i.e. list of glyphs, NOT slash-separated)
+ could, for example, swap all occurences of "1" with "2", as well as
+ swapping all "3" with "w" (or any other of the 24 possibilities).
+
+ SHUFFLE: 12/3w (i.e. list of slash-separated blocks of same size)
+ will either do nothing or swap all "1" with "3" and then also swap
+ "2" with "w" everywhere.
+
+ Several SHUFFLE: lines can be used, and mixed with SUBST:, and the
+ shuffles and substitutions will be applied in order. You can also
+ put multiple SHUFFLEs on one line, comma-separated. Shuffles cannot
+ use , or /. All spaces are stripped before shuffling.
+
+SUBST: ?=xc, !:bv, 1=2 1:100
+ The SUBST: directive allows you to specify a placeholder symbol
+ that is replaced with a random glyph from a set. For instance:
+
+ SUBST: ? = TUV
+ replaces occurrences of ? with one of TUV. Since whitespaces are
+ irrelevant, this is the same as
+ SUBST: ? = T U V
+
+ SUBST: ? = T:20 U V
+ makes T twice as likely to be used as U or V (the default weight
+ is 10). Note that there has to be at least one space before and
+ after T:20 and that whitespace in T:20 is not permitted.
+
+ SUBST: ? : TUV
+ replaces occurrences of ? with one of TUV, and guarantees that all
+ occurrences of ? will get the same replacement symbol.
+
+ The placeholder and replacement symbols can be any non-space,
+ printable character, including : and =, apart from commas. For
+ example, the following is valid:
+ SUBST: = = +=:123def"
+
+ SUBST: lines can safely replace symbols with themselves, as in:
+ SUBST: w = wW
+
+ Multiple SUBST: lines can be used, and mixed with SHUFFLE:, and
+ will be applied in order. Multiple substitutions can be performed
+ on one line, using commas.
+
+NSUBST: ? = 3:w / *:l
+
+ NSUBST is similar to SUBST, replacing placeholders with
+ replacement values. Unlike SUBST, however, it allows you to
+ replace different instances of the same placeholder with
+ completely different substitutions. For instance:
+
+ ? = 3:w / *:l
+
+ replaces three occurrences (randomly selected) of ? with w
+ and all others with l.
+
+ You can use complex SUBST specifications:
+
+ ? = 3= w .:15 A / *: =+CF
+
+ This is equivalent to SUBST: ? = w .:15 A for three ? and
+ SUBST: ? : =+CF for all the others.
+
+ You use any number of NSUBST specifiers:
+
+ ? = wW / l / A / 1234
+
+ Each specifier is preceded by the number of symbols to apply
+ it to, followed by : or = (: to use one substitution for all
+ occurrences, = to randomly pick for each occurrence). If you
+ omit the initial N: or N=, then 1= is assumed, except for the
+ last spec where *= is assumed.
+
+KFEAT: Z = C / needle trap / antique armour shop / altar_zin
+ The KFEAT: directive allows you to specify a placeholder symbol
+ that is replaced with another symbol, named feature, trap, or
+ shop. For example, the line above will replace occurrences of Z
+ with C (random altar), a needle trap, an antique armour shop, or
+ an altar of Zin. Different instances of Z may receive different
+ replacements. To force a single replacement for all Z, use:
+
+ KFEAT: Z : C / needle trap / antique armour shop
+
+ You'll notice that 'Z' is the symbol of the Orb of Zot. Kxxx
+ directives allow you to assign arbitrary definitions to any symbol.
+
+ KFEAT features are specified as a feature name (see section I
+ for a full list of feature names). As another example, you can
+ place a portal to the Abyss as:
+
+ KFEAT: A = enter_abyss
- KFEAT features are specified as a feature name (see section I
- for a full list of feature names). As another example, you can
- place a portal to the Abyss as:
+ If you want no feature as an option in a KFEAT line, use '.' or
+ 'floor'. If you do not want to specify the type of shop, use
+ 'any shop' or 'random shop'.
- KFEAT: A = enter_abyss
+ The placeholder used by KFEAT can be shared by KITEM and KMONS;
+ see below. If the placeholder is shared, all defined Kxxxx
+ operations for the placeholder are performed. Also, all Kxxx
+ lines accept weights as for MONS or ITEM.
- If you want no feature as an option in a KFEAT line, use 'floor'.
- If you do not want to specify the type of shop, use 'any shop' or
- 'random shop'.
+KMONS: ? = orc priest / w:3 deep elf priest
- The placeholder used by KFEAT can be shared by KITEM and KMONS;
- see below. If the placeholder is shared, all defined Kxxxx
- operations for the placeholder are performed. Also, all Kxxx
- lines accept weights as for MONS or ITEM.
+ KMONS: allows you to specify a placeholder symbol that indicates
+ the position of a monster (or monsters).
+ Using KMONS: allows you to exceed the 7 slot limit for monsters.
+ It is also useful if you want to place a monster on a non-floor
+ square (used in association with a KFEAT:). For example,
+ KFEAT: Z = W
+ KMONS: Z = rat
+ places a rat on a shallow water square for all occurrences of Z.
-KMONS: ? = orc priest / w:3 deep elf priest
+ KMONS: also allows you to specify alternative monsters if the
+ primary monster you want to place is unavailable (because it
+ is a unique that was already generated). For instance, if you want
+ to generate one of Terence, Michael or Erica or a generic human
+ (whoever is available, in that order, you can use):
+ KMONS: n = Terence, Michael, Erica, human
+ Or if you want to pick randomly:
+ KMONS: n = Terence / Michael / Erica, human
- KMONS: allows you to specify a placeholder symbol that indicates
- the position of a monster (or monsters).
- Using KMONS: allows you to exceed the 7 slot limit for monsters.
- It is also useful if you want to place a monster on a non-floor
- square (used in association with a KFEAT:). For example,
- KFEAT: Z = W
- KMONS: Z = rat
- places a rat on a shallow water square for all occurrences of Z.
+KMASK: Z = no_monster_gen
- KMONS: also allows you to specify alternative monsters if the
- primary monster you want to place is unavailable (because it
- is a unique that was already generated). For instance, if you want
- to generate one of Terence, Michael or Erica or a generic human
- (whoever is available, in that order, you can use):
- KMONS: n = Terence, Michael, Erica, human
- Or if you want to pick randomly:
- KMONS: n = Terence / Michael / Erica, human
+ KMASK allows you set or unset various masks for particular
+ symbols, rather than for the entire vault like if you did it
+ with TAGS. Valid masks are
-KITEM: ? = potion of healing / potion of restore abilities
- KITEM: places the specified item at all occurrences of the
- placeholder. It can be combined with KFEAT: and KMONS: lines for
- the same placeholder.
+ * "no_item_gen": Prevents random item on that symbol. Items
+ explicitly placed on that symbol aren't affected.
+ * "no_monster_gen": Prevents random monster generation on that
+ symbol. MUST-HAVE for those with water/lava symbols in
+ entry vaults.
+ * "no_pool_fixup": prevents a water square next to land from being
+ randomly converted from deep water (the default) to shallow.
+ * "no_secret_doors": prevents a door from randomly being turned
+ into a secret door.
- You can use "gold" or "$" to place gold:
- KITEM: ? = nothing / gold
- KITEM: ? = nothing / $
+ For example
- You can use q: to specify quantities:
- KITEM: ? = q:100 gold
+ KMASK: W = no_monster_gen
- KITEM: allows you to place multiple items on the same square:
- KITEM: ? = bread ration, potion of water, potion of porridge
+ will prevent monsters from randomly being generated on shallow
+ water squares. Note that if shuffling and substitutions cause
+ W to end up as water 10% of the time and floor 90% of the time,
+ then those floor squares will still have no_monster_gen set, but
+ that's still a higher degree of control than you get with TAGS.
-MARKER: A = feat:<feature_name> or timer:
+ If TAGS has been used to set a mask for the entire vault, you
+ can use KMASK to remove that mask from particular symbols.
+ For instance:
- A marker ties a square on the map to a game-trigger of some
- sort (which depends on the marker and what feature it is on).
-
- The portals to the Hells in the Vestibule of Hell are each
- annotated with feature markers like this:
+ TAGS: no_monster_gen
+ KMASK: W = !no_monster_gen
- MARKER: D=feat:enter_dis, G=feat:enter_gehenna
+ would make it so that monsters are only randomly generated
+ on shallow water squares.
- When the horn is sounded, the stone arch at D becomes the
- portal to Dis, the arch at G becomes the portal to Gehenna,
- etc. This behaviour applies only to the Vestibule of Hell.
+KITEM: ? = potion of healing / potion of restore abilities
+ KITEM: places the specified item at all occurrences of the
+ placeholder. It can be combined with KFEAT: and KMONS: lines for
+ the same placeholder.
- Timer feature markers set a timer on a particular square;
- when time runs out, the feature at that square is changed
- (usually to floor). For instance:
+ You can use "gold" or "$" to place gold:
+ KITEM: ? = nothing / gold
+ KITEM: ? = nothing / $
- MARKER: A = timer: 500-1000
+ You can use q: to specify quantities:
+ KITEM: ? = q:100 gold
- Sets a timer that's between 500-1000 turns, inclusive, at the
- end of which whatever feature is on A gets converted to floor.
+ KITEM: allows you to place multiple items on the same square:
+ KITEM: ? = bread ration, potion of water, potion of porridge
- You can specify the final feature with a feat: qualifier:
+MARKER: A = feat:<feature_name> or timer:
- MARKER: A = timer: 500 feat:deep_water
+ A marker ties a square on the map to a game-trigger of some
+ sort (which depends on the marker and what feature it is on).
- This sets a timer for exactly 500 turns, and changes the
- feature to deep water at the end of it.
+ The portals to the Hells in the Vestibule of Hell are each
+ annotated with feature markers like this:
+
+ MARKER: D=feat:enter_dis, G=feat:enter_gehenna
+
+ When the horn is sounded, the stone arch at D becomes the
+ portal to Dis, the arch at G becomes the portal to Gehenna,
+ etc. This behaviour applies only to the Vestibule of Hell.
+
+ Timer feature markers set a timer on a particular square;
+ when time runs out, the feature at that square is changed
+ (usually to floor). For instance:
+
+ MARKER: A = timer: 500-1000
+
+ Sets a timer that's between 500-1000 turns, inclusive, at the
+ end of which whatever feature is on A gets converted to floor.
+
+ You can specify the final feature with a feat: qualifier:
+
+ MARKER: A = timer: 500 feat:deep_water
+
+ This sets a timer for exactly 500 turns, and changes the
+ feature to deep water at the end of it.
+
+ Feature names used in markers must be names matching the
+ names in the source code. There's a full list of feature
+ names in section I (Feature names) at the end of this
+ document.
- Feature names used in markers must be names matching the
- names in the source code. There's a full list of feature
- names in section I (Feature names) at the end of this
- document.
-
E. Conditionalising levels
-----------------------------
@@ -830,9 +907,9 @@ NOTE: You cannot use the colon-prefixed syntax for validation Lua. If
you have a big block of code, use the multiline syntax:
validate {{
- -- This level is always cool.
- crawl.mpr("This level is guaranteed perfect!")
- return true
+ -- This level is always cool.
+ crawl.mpr("This level is guaranteed perfect!")
+ return true
}}
@@ -841,18 +918,18 @@ G. Hints for level makers
* Technical stuff:
- If your map is not a minivault or a floating vault, make sure the
+ If your map is not a minivault or a floating vault, make sure the
side(s) forming the border have a rock wall padding at least 6 deep. For
- instance, if your map is ORIENT: north, you must have a 6 deep border of
- rock wall (or any other kind of wall) along the northern, eastern, and
- western edges of the map. If you're doing a fullscreen map (encompass),
+ instance, if your map is ORIENT: north, you must have a 6 deep border of
+ rock wall (or any other kind of wall) along the northern, eastern, and
+ western edges of the map. If you're doing a fullscreen map (encompass),
you must pad all around the map with 6 layers of wall.
- You do not have to place all of the stairs unless the level is full
+ 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
+ <). 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 (use at least > or < to make it possible for players
to get away).
@@ -860,7 +937,7 @@ G. Hints for level makers
one space of floor for accessibility. Alternatively, you can request
that the dungeon builder pick appropriate exits as it does for
floating vaults by using the "mini_float" tag.
-
+
The entry point '@' must be present for all vaults (except
full-screen vaults where it must not, and floating vaults and
minivaults where it is optional). All @ will be connected to floor
@@ -876,12 +953,12 @@ G. Hints for level makers
The level-builder will also implicitly treat doors and secret doors
on the edge of a map as explicit exits (the same as using @) and
connect them to the rest of the level.
-
+
Not using @ and allowing the level-builder to pick exits is
acceptable in floating vaults, but when you use no @'s with this
feature in mind, please add comments stating this - else somebody
may just add @'s later on. :)
-
+
Non-rectangular maps will be padded (to the right) with rock walls
(or with floor spaces for minivaults) for the smallest rectangle
containing them. Unfortunately.
@@ -890,7 +967,7 @@ G. Hints for level makers
atmosphere for the starting room, not to get a grip on the whole of D:1.
Minivaults should be rather small, as well, in order to increase the
chances they may actually be chosen during level generation.
-
+
* Randomise!
The level making syntax is now very supportive for making a single map
appear in many versions. Use the SHUFFLE: and SUBST: directives and look
@@ -899,18 +976,18 @@ G. Hints for level makers
always at the same place, it's a no-brainer for those who know. The same
goes for traps. This is much less so if there are several places for the
chamber (or trap) and there's even a chance it doesn't exist.
-
+
You can also use CHANCE to create modified versions of the same map. In
- order to do this, make several maps and endow each with a chance such
+ order to do this, make several maps and endow each with a chance such
that the sum of chances add up to 10.
- Randomisation does not just apply to layout: you could also have
+ Randomisation does not just apply to layout: you could also have
different monster population sets (for example make a branch end skewed
- for either melee or ranged opponents), or perhaps couple difficulty to
+ for either melee or ranged opponents), or perhaps couple difficulty to
loot.
* Not too much loot.
- For example, entry vaults should in general have very little loot - in
+ For example, entry vaults should in general have very little loot - in
particular no good_xxx or '*' items lest they might give incentive for
start-scumming. For random vaults, there needn't be loot at all and, in
any case, there shouldn't be too much of it. Compare with the branch ends
@@ -919,16 +996,16 @@ G. Hints for level makers
* Have a theme.
It is often worthwhile (to me at least) to have a theme in mind before
making the actual level. For entry vaults, something simple like
- 'fortress' or 'forest' may be enough. For later (or larger) maps, try
- to think of distinguishing features your map may have. Being cool can
+ 'fortress' or 'forest' may be enough. For later (or larger) maps, try
+ to think of distinguishing features your map may have. Being cool can
be good enough, but possessing some gameplay value (for example by being
- easier for particular skills/capabilities like ranged attacks or
+ easier for particular skills/capabilities like ranged attacks or
necromancy or Traps & Doors) is even better.
-
+
* Testing your maps.
This is easy for entry vaults. Temporarily introducing a CHANCE: 5000
will make your entry appear almost always. For other vaults, you can
- for the moment declare them as entry vaults with a huge CHANCE: as
+ for the moment declare them as entry vaults with a huge CHANCE: as
above (and preferably in wizard mode). For more intricate things like
new branch ends, you have to resort to wizard mode and use the &~ command
to go directly to the place where the map is used, say Snake:5. You may want
@@ -937,33 +1014,38 @@ G. Hints for level makers
which makes it very likely that the minivault will appear in the chosen
level.
- If the .des file syntax is incorrect, Crawl will tell you on which line of
+ Larger vaults can be conjured up in wizard mode using the &L command.
+ You don't need to specify the full name of the vault, a substring which
+ uniquely determines the vault is enough. You can playtest portal vaults
+ using the &P wizard command. Branch ends can be conveniently tested with
+ the &~ command.
+
+ If the .des file syntax is incorrect, Crawl will tell you on which line of
which des file it found the syntax error, making for easier debugging.
* Be fair!
Crawl is hard but try to balance your monsters. While it is true that Orc:1
can show an orcish knight, this is very rare. Hence it's probably a bad idea
- to use orcish knights for an entry to the Orcish Mines.
+ to use orcish knights for an entry to the Orcish Mines.
Phrased more generally, do not use OOD (out-of-depth) monsters unless you
- really know what you want.
-
- Be especially fair when creating entry vaults. If your entry is too
- hard, it might get degraded to tricky.des (or just removed). Keep in
- mind that your vault will be played very very often, so even small
- chances of something stupid happening (like creation of a really nasty
- monster) will kick in often enough.
-
+ really know what you want.
+
+ Be especially fair when creating entry vaults. If your entry is too hard,
+ it might get just trashed. Keep in mind that your vault will be played
+ very very often, so even small chances of something stupid happening
+ (like creation of a really nasty monster) will kick in often enough.
+
* Minivaults vs random vaults.
Minivaults are handled very differently from regular vaults and special
- levels. They're placed *after* normal map generation, whereas normal
- vaults are placed before generating the rest of the level. There's no
+ levels. They're placed *after* normal map generation, whereas normal
+ vaults are placed before generating the rest of the level. There's no
way to guarantee generation of a minivault on a particular level, although
using a PLACE: attribute makes the dungeon builder try very hard to place
the minivault on the specified level. Regular vaults can always be forced to
appear using a PLACE: attribute.
- Technically, you make a minivault like a normal floating vault but
+ Technically, you make a minivault like a normal floating vault but
without an ORIENT: line. Note that minivaults used to be exclusively of
size 12x12 but this restriction is gone. Still, the smaller the better.
@@ -1030,34 +1112,34 @@ Syntax for using Lua in .des files
* Colon-prefixed lines are individual Lua lines, extending to the end
of the line. E.g.
- : crawl.mpr("Hello")
+ : crawl.mpr("Hello")
Colon-prefixed lines are always in the main Lua chunk, unless they occur
before any map definitions, in which case they go to the global prelude.
* Lua blocks for the main (body) Lua
- lua {{ <code> }}
+ lua {{ <code> }}
or
- lua {{
- <code>
- }}
+ lua {{
+ <code>
+ }}
NOTE: Colon-prefixed lines, or lua {{ }} blocks defined before any
map's NAME: directive will add the Lua code to the global prelude.
* Lua blocks for the prelude:
- prelude {{ <code> }}
+ prelude {{ <code> }}
or
- prelude {{
- <code>
- }}
+ prelude {{
+ <code>
+ }}
* Lua blocks for the validate chunk:
- validate {{ <code> }}
+ validate {{ <code> }}
or
- validate {{
- <code>
- }}
+ validate {{
+ <code>
+ }}
Debugging Lua
@@ -1080,7 +1162,7 @@ It's very important that your finished level never croaks during
level-generation. A Lua error at this stage is considered a validation
failure.
-
+
Lua API reference
-----------------
a. The Map.
@@ -1095,11 +1177,11 @@ Lua functions dealing with the map are mostly grouped under the "dgn"
module. For convenience, .des file Lua chunks are run in an environment
such that function calls written as:
-fn(x, y, ...)
+ fn(x, y, ...)
are translated to
-dgn.fn(map, x, y, ...)
+ dgn.fn(map, x, y, ...)
where "map" is the reference to the map that the currently executing
Lua chunk belongs to. This is only for Lua chunks that belong to a
@@ -1112,7 +1194,11 @@ default_depth, name, depth, place, tags, tags_remove, chance, weight,
orient, shuffle, shuffle_remove, subst, subst_remove, map, mons, item,
kfeat, kitem, kmons, grid, points_connected, gly_point, gly_points,
original_map, glyphs_connected, orig_glyphs_connected, orig_gly_point,
-orig_gly_points.
+orig_gly_points, load_des_file, feature_number, feature_name,
+dgn_event_type, register_listener, remove_listener, remove_marker,
+num_matching_markers, feature_desc, feature_desc_at, item_from_index,
+mons_from_index, change_level_flags, change_branch_flags
+
Lua API - global game state
@@ -1195,3 +1281,56 @@ Will generate 10 dungeons. If you merely want statistics on the
probabilities of the levels, use:
crawl -mapstat 1
+
+
+K. Portal Vaults
+------------------
+
+Portal vaults are vaults accessed by portals in the dungeon (bazaars
+are a special case of portal vaults). You can create custom portal
+vaults as follows:
+
+Define a vault to hold the portal itself:
+
+# Bare-bones portal vault entry
+NAME: portal_generic_entry
+TAGS: allow_dup
+ORIENT: float
+MARKER: O = lua:one_way_stair { desc = "A portal to places unknown", \
+ dst = "generic_portal" }
+KFEAT: O = enter_portal_vault
+MAP
+O
+ENDMAP
+
+Portal entries must contain a portal vault entry (enter_portal_vault).
+This feature must always have a marker that provides the portal with a
+description ("A portal to places unknown") and a destination
+("generic_portal").
+
+This will produce a portal, but attempting to use it will trigger an
+ASSERT since there's no map for the destination. So we create a
+destination map like so:
+
+NAME: portal_generic_generic
+# Tag must match dst value of portal in entry.
+TAGS: generic_portal allow_dup
+ORIENT: encompass
+MONS: ancient lich
+KFEAT: > = exit_portal_vault
+MAP
+xxxxxxxxxxx
+x111111111x
+x1A111111>x
+x111111111x
+xxxxxxxxxxx
+ENDMAP
+
+Note that the entry point into the map will be a stone arch. You must
+provide an exit to the dungeon explicitly (KFEAT: > =
+exit_portal_vault) or the player will not be able to leave.
+
+Stairs will not work right in portal vaults, do not use them.
+
+You can use multiple maps with the destination tag (generic_portal),
+and the dungeon builder will pick one at random.
diff --git a/crawl-ref/docs/tables.txt b/crawl-ref/docs/tables.txt
index 4e77a5f888..38f187a3c6 100644
--- a/crawl-ref/docs/tables.txt
+++ b/crawl-ref/docs/tables.txt
@@ -67,6 +67,7 @@ Demonspawn 110 110 110 110 110 110 80 110 140
Ghoul 110 110 80 100 110 120 110 130 120
Kenku 90 90 100 80 100 100 160 100 130
Merfolk 160 60 90 70 100 120 100 100 120
+Vampire 140 110 50 100 140 110 140 140 150
---------------------------------------------------------------------
Arm Ddg Sth Stb Shd T&D Inv Evo Exp
@@ -105,6 +106,7 @@ Demonspawn 100 110 110 110 110 110 110 110 110 110 110 110 110
Ghoul 80 110 110 110 110 110 110 80 130 130 130 130 130
Kenku 100 75 75 75 75 75 75 80 90 100 80 80 90
Merfolk 80 70 90 140 150 50 130 90 100 150 140 140 100
+Vampire 110 100 110 110 140 110 140 90 140 140 140 140 140
---------------------------------------------------------------------
Fgt SBl LBl Axs M&F Pla Stv U C Thr Slg Bws Crb Drt
@@ -143,5 +145,6 @@ Demonspawn 100 100 110 100 90 110 110 110 100 110 110 110 100
Ghoul 120 130 130 120 100 120 120 120 150 90 150 90 100
Kenku 100 60 160 70 80 150 150 180 90 120 90 120 100
Merfolk 100 140 90 100 150 140 60 80 160 80 150 150 80
+Vampire 130 160 140 100 100 140 120 140 140 140 140 140 140
---------------------------------------------------------------------
Spc Coj Enc Sum Nec Trl Trm Div Fir Ice Air Ear Poi
diff --git a/crawl-ref/init.txt b/crawl-ref/init.txt
index d3058c3b07..7e3bcfc01f 100644
--- a/crawl-ref/init.txt
+++ b/crawl-ref/init.txt
@@ -14,15 +14,15 @@
# cases (the character's name and specifying files or directories when
# on a system that has case-sensitive filenames).
#
-# White space is stripped from the beginning and end of the line, as well
-# as immediately before and after the '='. If the option allows multiple
-# comma/semicolon-separated terms (such as autopickup_exceptions), all
-# whitespace around the separator is also trimmed. All other whitespace
-# is left intact.
+# White space is stripped from the beginning and end of the line, as
+# well as immediately before and after the '='. If the option allows
+# multiple comma/semicolon-separated terms (such as
+# autopickup_exceptions), all whitespace around the separator is also
+# trimmed. All other whitespace is left intact.
#
# For descriptions concerning an option consult the file
# crawl_options.txt
-# in your crawl/doc directory. Also note that the ordering of the options
+# in your docs directory. Also note that the ordering of the options
# is taken from that file; this is for presentational reasons only.
#
# Note that all boolean options (i.e. values of 'true' or 'false') have
@@ -38,16 +38,16 @@
# weapon = (random | short sword | hand axe | spear | mace | trident)
# chaos_knight = (Xom | Makhleb | random)
# death_knight = (necromancy | Yredelemnul | random)
-# priest = (Zin | Yredelemnul | Beogh | random)
-# race = (Human |...| Merfolk | random)
-# class = (Fighter |...| Wanderer | random)
+# priest = (Zin | Yredelemnul | Beogh | random)
+# race = (Human |...| Merfolk | random)
+# class = (Fighter |...| Wanderer | random)
# random_pick = true
##### 2- File System ###############################################
#
-# crawl_dir= <path>
+# crawl_dir = <path>
# morgue_dir = morgue
-# save_dir = saves
+# save_dir = saves
# sound = <regex>:<path to sound file>
##### 3- Lua Files #################################################
@@ -66,16 +66,14 @@ lua_file = lua/pickup.lua
##### 4-a Picking up and Dropping ###############
#
# autopickup = $?!+"/%
+# autopickup_exceptions = scrolls? of random uselessness
+# autopickup_exceptions = <deck of cards
+#
# default_autopickup = false
-# safe_autopickup = false
# autopickup_no_burden = true
-# safe_zero_exp = false
# pickup_thrown = false
# pickup_dropped = true
-# assign_item_slot = backward
-#
-# autopickup_exceptions = scrolls? of random uselessness
-# autopickup_exceptions = <deck of cards
+# assign_item_slot = (forward | backward)
#
# drop_mode = (multi | single)
# pickup_mode = (single | multi | auto:5)
@@ -86,7 +84,6 @@ lua_file = lua/pickup.lua
# target_zero_exp = true
# target_oos = false
# target_los_first = false
-# confirm_self_target = false
# default_target = false
# target_unshifted_dirs = true
@@ -99,12 +96,13 @@ lua_file = lua/pickup.lua
##### 4-d Branding ##############################
#
-friend_brand = hi:green
-stab_brand = hi:blue
-# may_stab_brand = hi:yellow
+friend_brand = hi:green
+stab_brand = hi:blue
+# may_stab_brand = hi:yellow
+# heap_brand = reverse
# heap_brand = reverse
# stair_item_brand = reverse
-# trap_item_brand = none
+# trap_item_brand = none
##### 4-e Level Map Functions ###################
#
@@ -115,10 +113,14 @@ stab_brand = hi:blue
##### 4-f Viewport Options ###################
# view_max_width = 33
# view_max_height = 17
+# view_lock_x = false
+# view_lock_y = false
# view_lock = false
# center_on_scroll = true
# symmetric_scroll = false
-# scroll_margin = 4
+# scroll_margin_x = 2
+# scroll_margin_y = 2
+# scroll_margin = 2
##### 4-g Travel and Exploration #################
#
@@ -126,7 +128,7 @@ stab_brand = hi:blue
# travel_avoid_terrain = shallow water
#
# explore_greedy = true
-# explore_stop = items,stairs,shops,altars,gates
+# explore_stop = items,stairs,shops,altars,gates
# tc_reachable = blue
# tc_dangerous = cyan
@@ -136,8 +138,8 @@ stab_brand = hi:blue
# The following options are not default. Uncommenting activates them.
#
-# stop_travel = Something appears
-# stop_travel = god:wrath finds you
+# travel_stop_message = Something appears
+# travel_stop_message = god:wrath finds you
# runrest_ignore_message = prayer ends
# runrest_ignore_message = You feel.*sick
# runrest_ignore_poison = 4:100
@@ -152,58 +154,57 @@ stab_brand = hi:blue
##### 4-i Command Enhancements ##################
#
-# auto_list = false
-# lowercase_invocations = false
-# easy_open = false
-# easy_butcher = false
+# auto_list = false
+# easy_open = false
# easy_unequip = false
# easy_confirm = (none | safe | all)
+# easy_butcher = false
+# always_confirm_butcher = true
# easy_quit_item_prompts = false
-# easy_exit_menu = true
+# easy_exit_menu = false
# default_autoprayer = true
# sort_menus = pickup: true : basename, qualname, curse, qty
##### 4-j Messages and Display Enhancements #####
#
# hp_warning = 10
-# mp_warning = 10
+# mp_warning = 0
# hp_colour = lightgrey, 50:yellow, 25:red
# mp_colour = lightgrey, 50:yellow, 25:red
-# terse_hand = false
-# delay_message_clear = true
-# always_greet = false
-# increasing_skill_progress = false
+# delay_message_clear = true
# show_inventory_weights = true
# show_turns = true
-# show_beam = true
-# item_stack_summary_minimum = 500
-# menu_colour_prefix_id = true
-# menu_colour_prefix_class = true
+# show_beam = true
+# item_stack_summary_minimum = 5
# Colouring for the inventory
-menu_colour = lightred: cursed.*(worn|neck|hand|weapon)\)
-menu_colour = green:(worn|neck|hand|weapon)\)
-menu_colour = red: cursed
-menu_colour = red: rotting
+menu_colour = inventory:lightred: cursed.*(worn|neck|hand|weapon)\)
+menu_colour = inventory:green:(worn|neck|hand|weapon)\)
+menu_colour = inventory:red: cursed
+menu_colour = inventory:red: rotting
# Identified artefacts
-menu_colour = white:( [-+] the)
+menu_colour = inventory:white:( [-+] the)
# These lines will colour ego items; they require that
# menu_colour_prefix_id and menu_colour_prefix_class be set to true
-# menu_colour = green:(^identified armour .* pair of .* of )
-# menu_colour = lightgrey:(^identified armour .* pair of )
-# menu_colour = green:(^identified (weapon|armour) .* of )
+# menu_colour_prefix_id = true
+# menu_colour_prefix_class = true
+
+# menu_colour = inventory:green:(^identified armour .* pair of .* of )
+# menu_colour = inventory:lightgrey:(^identified armour .* pair of )
+# menu_colour = inventory:green:(^identified (weapon|armour) .* of )
# Colouring for the notes
-menu_colour = white:Reached XP level
+menu_colour = notes:white:Reached XP level
# Message colours
message_colour = lightcyan:LOW MAGIC WARNING
-# These lines will suppress extra feedback messages from travel/shift-running.
+# These lines will suppress extra feedback messages from
+# travel/shift-running.
# message_colour = mute:warning:comes into view
# message_colour = mute:You start (searching|resting)
@@ -240,13 +241,12 @@ message_colour = lightcyan:LOW MAGIC WARNING
# dump_item_origins = all,artifacts,ego_arm,ego_weap,jewellery,runes
# dump_item_origin_price = -1
# dump_message_count = 7
-# dump_order = header,hiscore,stats,misc,notes,inventory,turns_by_place,
-# dump_order += skills,spells,overview,mutations,messages,screenshot
-# dump_order += kills_by_place,kills
+# dump_order = header,hiscore,stats,misc,notes,inventory,
+# dump_order += turns_by_place,skills,spells,overview,mutations,
+# dump_order += messages,screenshot,kills_by_place,kills
##### 5-b Notes #################################
#
-# use_notes = false
# user_note_prefix=@@@
# note_items = rod,book,rune
# note_monsters = orb of fire
@@ -260,25 +260,24 @@ message_colour = lightcyan:LOW MAGIC WARNING
# The following takes a note whenever the Abyss is left:
# note_messages = You pass through the gate
-##### 6- Miscellaneous #################################################
+##### 6- Miscellaneous #############################################
#
##### 6-a All OS ################################
#
# macro_meta_entry = false
# mouse_input = true
+# wiz_mode = no
+# char_set = ascii
+#
+# classic_item_colours = true
#
# colour.lightgray = black
# colour.lightcyan = cyan
# colour.yellow = brown
#
-# char_set = ascii
-# wiz_mode = no
-#
-# classic_item_colours = true
-#
# See crawl_options.txt for the options
-# char_set, cset_ascii, cset_ibm, cset_dec, cset_unicode,
-# cset_any, feature, mon_glyph
+# cset_ascii, cset_ibm, cset_dec, cset_unicode, cset_any,
+# feature, mon_glyph
##### 6-b DOS and Windows #######################
diff --git a/crawl-ref/source/AppHdr.h b/crawl-ref/source/AppHdr.h
index 5c5253ce9c..2f0d01ab0a 100644
--- a/crawl-ref/source/AppHdr.h
+++ b/crawl-ref/source/AppHdr.h
@@ -364,11 +364,6 @@
// 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) turns off missile trails, might be slow on some computers
// #define MISSILE_TRAILS_OFF
@@ -456,6 +451,6 @@
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/crawl-ref/source/Crawl.xcodeproj/project.pbxproj b/crawl-ref/source/Crawl.xcodeproj/project.pbxproj
index de9f6d5a80..212996623c 100644
--- a/crawl-ref/source/Crawl.xcodeproj/project.pbxproj
+++ b/crawl-ref/source/Crawl.xcodeproj/project.pbxproj
@@ -201,6 +201,8 @@
7B352EA10B00183400CABB32 /* mapdef.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 7B352E9E0B00183400CABB32 /* mapdef.h */; };
7B3B075B0BD13AAB00F2980E /* libreadline.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B3B07560BD13A8100F2980E /* libreadline.dylib */; };
7B3B07600BD13AF000F2980E /* libncurses.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B3B075F0BD13AF000F2980E /* libncurses.dylib */; };
+ 7B4896620CD3A5D2004A5F43 /* mgrow.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7B4896600CD3A5D2004A5F43 /* mgrow.cc */; };
+ 7B54B51B0CA8217900612805 /* state.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7B54B51A0CA8217900612805 /* state.cc */; };
7B61642D0C9CA8E80054B3D9 /* mpr.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 7B6164240C9CA8E80054B3D9 /* mpr.h */; };
7B61642E0C9CA8E80054B3D9 /* place.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7B6164250C9CA8E80054B3D9 /* place.cc */; };
7B61642F0C9CA8E80054B3D9 /* place.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 7B6164260C9CA8E80054B3D9 /* place.h */; };
@@ -220,6 +222,7 @@
7BBC4A080B0F783C00F27D45 /* levcomp.ypp in Sources */ = {isa = PBXBuildFile; fileRef = 7B352ED20B001B9E00CABB32 /* levcomp.ypp */; };
7BC222E70ABBB286003A7D9A /* itemprop.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BC222E50ABBB286003A7D9A /* itemprop.cc */; };
7BC222E80ABBB286003A7D9A /* itemprop.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 7BC222E60ABBB286003A7D9A /* itemprop.h */; };
+ 7BD222200CC2D51300B475D8 /* store.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BD2221F0CC2D51300B475D8 /* store.cc */; };
7BD75A350AC214A200B74F6E /* notes.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BD75A330AC214A200B74F6E /* notes.cc */; };
7BD75A360AC214A200B74F6E /* notes.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 7BD75A340AC214A200B74F6E /* notes.h */; };
7BDEBB290BB4CB0B008DF39F /* mtransit.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BDEBB280BB4CB0B008DF39F /* mtransit.cc */; };
@@ -548,6 +551,9 @@
7B352F200B00232500CABB32 /* vaults.des */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = vaults.des; path = dat/vaults.des; sourceTree = "<group>"; };
7B3B07560BD13A8100F2980E /* libreadline.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libreadline.dylib; path = /usr/lib/libreadline.dylib; sourceTree = "<absolute>"; };
7B3B075F0BD13AF000F2980E /* libncurses.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libncurses.dylib; path = /usr/lib/libncurses.dylib; sourceTree = "<absolute>"; };
+ 7B4896600CD3A5D2004A5F43 /* mgrow.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mgrow.cc; sourceTree = SOURCE_ROOT; };
+ 7B4896610CD3A5D2004A5F43 /* mgrow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mgrow.h; sourceTree = SOURCE_ROOT; };
+ 7B54B51A0CA8217900612805 /* state.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = state.cc; sourceTree = SOURCE_ROOT; };
7B6164240C9CA8E80054B3D9 /* mpr.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = mpr.h; sourceTree = SOURCE_ROOT; };
7B6164250C9CA8E80054B3D9 /* place.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = place.cc; sourceTree = SOURCE_ROOT; };
7B6164260C9CA8E80054B3D9 /* place.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = place.h; sourceTree = SOURCE_ROOT; };
@@ -563,8 +569,11 @@
7B9740060BE3AC8000AAE35B /* makeitem.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = makeitem.h; sourceTree = "<group>"; };
7BA3DBB90B3D90A700B5B3D7 /* branch.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = branch.cc; sourceTree = "<group>"; };
7BA3DBBA0B3D90A700B5B3D7 /* branch.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = branch.h; sourceTree = "<group>"; };
+ 7BB0A2280CB735C00034A741 /* xom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xom.h; sourceTree = SOURCE_ROOT; };
7BC222E50ABBB286003A7D9A /* itemprop.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = itemprop.cc; sourceTree = "<group>"; };
7BC222E60ABBB286003A7D9A /* itemprop.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = itemprop.h; sourceTree = "<group>"; };
+ 7BD2221E0CC2D51300B475D8 /* store.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = store.h; sourceTree = SOURCE_ROOT; };
+ 7BD2221F0CC2D51300B475D8 /* store.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = store.cc; sourceTree = SOURCE_ROOT; };
7BD75A330AC214A200B74F6E /* notes.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = notes.cc; sourceTree = "<group>"; };
7BD75A340AC214A200B74F6E /* notes.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = notes.h; sourceTree = "<group>"; };
7BDEBB280BB4CB0B008DF39F /* mtransit.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = mtransit.cc; sourceTree = "<group>"; };
@@ -713,17 +722,6 @@
7B352EF00B001F5B00CABB32 /* Crawl */ = {
isa = PBXGroup;
children = (
- 4C3001B60CD491EE008262DD /* mgrow.cc */,
- 4C3001B70CD491EE008262DD /* mgrow.h */,
- 7B6164240C9CA8E80054B3D9 /* mpr.h */,
- 7B6164250C9CA8E80054B3D9 /* place.cc */,
- 7B6164260C9CA8E80054B3D9 /* place.h */,
- 7B6164270C9CA8E80054B3D9 /* ray.h */,
- 7B6164280C9CA8E80054B3D9 /* state.h */,
- 7B6164290C9CA8E80054B3D9 /* terrain.cc */,
- 7B61642A0C9CA8E80054B3D9 /* terrain.h */,
- 7B61642B0C9CA8E80054B3D9 /* traps.cc */,
- 7B61642C0C9CA8E80054B3D9 /* traps.h */,
7B237E0D0A8EC9D000580F30 /* abl-show.cc */,
7B237E290A8EC9D000580F30 /* abl-show.h */,
7B237E280A8EC9D000580F30 /* abyss.cc */,
@@ -812,6 +810,8 @@
7B237E360A8EC9D000580F30 /* menu.h */,
7B237E350A8EC9D000580F30 /* message.cc */,
7B237DFD0A8EC9D000580F30 /* message.h */,
+ 7B4896600CD3A5D2004A5F43 /* mgrow.cc */,
+ 7B4896610CD3A5D2004A5F43 /* mgrow.h */,
7B237DFC0A8EC9D000580F30 /* misc.cc */,
7B237DE90A8EC9D000580F30 /* misc.h */,
7B237DE80A8EC9D000580F30 /* mon-pick.cc */,
@@ -824,6 +824,7 @@
7B237E420A8EC9D000580F30 /* monspeak.h */,
7B237E410A8EC9D000580F30 /* monstuff.cc */,
7B237E400A8EC9D000580F30 /* monstuff.h */,
+ 7B6164240C9CA8E80054B3D9 /* mpr.h */,
7B237E3F0A8EC9D000580F30 /* mstuff2.cc */,
7B237E6B0A8EC9D000580F30 /* mstuff2.h */,
7B237E6A0A8EC9D000580F30 /* mt19937ar.cc */,
@@ -842,10 +843,13 @@
7B237DEF0A8EC9D000580F30 /* output.h */,
7B237DEE0A8EC9D000580F30 /* overmap.cc */,
7B237DED0A8EC9D000580F30 /* overmap.h */,
+ 7B6164250C9CA8E80054B3D9 /* place.cc */,
+ 7B6164260C9CA8E80054B3D9 /* place.h */,
7B237E0B0A8EC9D000580F30 /* player.cc */,
7B237E0A0A8EC9D000580F30 /* player.h */,
7B237E090A8EC9D000580F30 /* randart.cc */,
7B237E080A8EC9D000580F30 /* randart.h */,
+ 7B6164270C9CA8E80054B3D9 /* ray.h */,
7B237E3B0A8EC9D000580F30 /* religion.cc */,
7B237E3A0A8EC9D000580F30 /* religion.h */,
7B237E390A8EC9D000580F30 /* shopping.cc */,
@@ -870,12 +874,20 @@
7B237E060A8EC9D000580F30 /* spl-util.h */,
7B237E200A8EC9D000580F30 /* stash.cc */,
7B237E1F0A8EC9D000580F30 /* stash.h */,
+ 7B54B51A0CA8217900612805 /* state.cc */,
+ 7B6164280C9CA8E80054B3D9 /* state.h */,
+ 7BD2221E0CC2D51300B475D8 /* store.h */,
+ 7BD2221F0CC2D51300B475D8 /* store.cc */,
7B237E1E0A8EC9D000580F30 /* stuff.cc */,
7B237E1D0A8EC9D000580F30 /* stuff.h */,
7B237E240A8EC9D000580F30 /* tags.cc */,
7B237E230A8EC9D000580F30 /* tags.h */,
+ 7B6164290C9CA8E80054B3D9 /* terrain.cc */,
+ 7B61642A0C9CA8E80054B3D9 /* terrain.h */,
7B237E220A8EC9D000580F30 /* transfor.cc */,
7B237E210A8EC9D000580F30 /* transfor.h */,
+ 7B61642B0C9CA8E80054B3D9 /* traps.cc */,
+ 7B61642C0C9CA8E80054B3D9 /* traps.h */,
7B237DF50A8EC9D000580F30 /* travel.cc */,
7B237DF40A8EC9D000580F30 /* travel.h */,
7BDEBB2F0BB4CB5C008DF39F /* tutorial.cc */,
@@ -883,6 +895,7 @@
7B237E140A8EC9D000580F30 /* view.cc */,
7B237E130A8EC9D000580F30 /* view.h */,
4CEF15890C128CA5002C7D7A /* xom.cc */,
+ 7BB0A2280CB735C00034A741 /* xom.h */,
);
name = Crawl;
sourceTree = "<group>";
@@ -1148,7 +1161,9 @@
7B61642E0C9CA8E80054B3D9 /* place.cc in Sources */,
7B6164320C9CA8E80054B3D9 /* terrain.cc in Sources */,
7B6164340C9CA8E80054B3D9 /* traps.cc in Sources */,
- 4C3001B80CD491EE008262DD /* mgrow.cc in Sources */,
+ 7B54B51B0CA8217900612805 /* state.cc in Sources */,
+ 7BD222200CC2D51300B475D8 /* store.cc in Sources */,
+ 7B4896620CD3A5D2004A5F43 /* mgrow.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1167,13 +1182,17 @@
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = NO;
+ GCC_DEBUGGING_SYMBOLS = full;
GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
GCC_OPTIMIZATION_LEVEL = 1;
GCC_PREPROCESSOR_DEFINITIONS = (
OSX,
CLUA_BINDINGS,
DB_NDBM,
);
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_SIGN_COMPARE = NO;
GCC_WARN_UNUSED_FUNCTION = NO;
GCC_WARN_UNUSED_LABEL = NO;
PRODUCT_NAME = crawl;
@@ -1268,7 +1287,8 @@
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = NO;
- GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
GCC_OPTIMIZATION_LEVEL = 1;
GCC_PREPROCESSOR_DEFINITIONS = (
OSX,
@@ -1279,11 +1299,13 @@
DEBUG_ITEM_SCAN,
FULLDEBUG,
);
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_SIGN_COMPARE = NO;
GCC_WARN_UNUSED_FUNCTION = NO;
GCC_WARN_UNUSED_LABEL = NO;
PRODUCT_NAME = crawl;
YACC_GENERATED_FILE_STEM = InputFileStem;
- ZERO_LINK = YES;
+ ZERO_LINK = NO;
};
name = Debug;
};
diff --git a/crawl-ref/source/FixAry.h b/crawl-ref/source/FixAry.h
index 5fe2bc350a..4e3ab70514 100644
--- a/crawl-ref/source/FixAry.h
+++ b/crawl-ref/source/FixAry.h
@@ -118,7 +118,7 @@ template <typename Z>
void Matrix<Z>::init(const Z &initial)
{
for (int i = 0; i < size; ++i)
- data[i] = initial;
+ data[i] = initial;
}
#endif // FIXARY_H
diff --git a/crawl-ref/source/abl-show.cc b/crawl-ref/source/abl-show.cc
index d9f27b19dc..3892ceb210 100644
--- a/crawl-ref/source/abl-show.cc
+++ b/crawl-ref/source/abl-show.cc
@@ -63,6 +63,7 @@
#include "spells2.h"
#include "spells3.h"
#include "spells4.h"
+#include "state.h"
#include "stuff.h"
#include "transfor.h"
#include "tutorial.h"
@@ -145,7 +146,7 @@ ability_type god_abilities[MAX_NUM_GODS][MAX_GOD_ABILITIES] =
ABIL_TROG_BROTHERS_IN_ARMS, ABIL_NON_ABILITY },
// Nemelex
{ ABIL_NEMELEX_PEEK_DECK, ABIL_NEMELEX_DRAW_CARD,
- ABIL_NEMELEX_TRIPLE_DRAW, ABIL_NON_ABILITY,
+ ABIL_NEMELEX_TRIPLE_DRAW, ABIL_NEMELEX_MARK_DECK,
ABIL_NEMELEX_STACK_DECK },
// Elyvilon
{ ABIL_ELYVILON_LESSER_HEALING, ABIL_ELYVILON_PURIFICATION,
@@ -277,7 +278,7 @@ static const ability_def Ability_List[] =
{ ABIL_TROG_BERSERK, "Berserk", 0, 0, 200, 0, ABFLAG_NONE },
{ ABIL_TROG_REGENERATION, "Trog's Hand", 0, 0, 50, 1, ABFLAG_NONE },
{ ABIL_TROG_BROTHERS_IN_ARMS, "Brothers in Arms",
- 0, 0, 100, generic_cost::fixed(4), ABFLAG_NONE },
+ 0, 0, 100, generic_cost::range(5, 6), ABFLAG_NONE },
// Elyvilon
{ ABIL_ELYVILON_DESTROY_WEAPONS, "Destroy Weapons", 0, 0, 0, 0, ABFLAG_NONE },
@@ -304,6 +305,7 @@ static const ability_def Ability_List[] =
{ ABIL_NEMELEX_PEEK_DECK, "Deck Peek", 3, 0, 0, 1, ABFLAG_INSTANT },
{ ABIL_NEMELEX_DRAW_CARD, "Draw Card", 2, 0, 0, 0, ABFLAG_NONE },
{ ABIL_NEMELEX_TRIPLE_DRAW, "Triple Draw", 2, 0, 100, 2, ABFLAG_NONE },
+ { ABIL_NEMELEX_MARK_DECK, "Mark Deck", 4, 0, 125, 5, ABFLAG_NONE },
{ ABIL_NEMELEX_STACK_DECK, "Stack Deck", 5, 0, 250, 10, ABFLAG_NONE },
// Beogh
@@ -381,7 +383,7 @@ const std::string make_cost_description( ability_type ability )
ret << " HP";
}
- if (abil.food_cost && you.species != SP_MUMMY)
+ if (abil.food_cost && you.is_undead != US_UNDEAD)
{
if (!ret.str().empty())
ret << ", ";
@@ -740,9 +742,10 @@ static talent get_talent(ability_type ability, bool check_confused)
failure = 80 - (you.piety / 25) - (4 * you.skills[SK_EVOCATIONS]);
break;
- case ABIL_NEMELEX_PEEK_DECK:
+ case ABIL_NEMELEX_MARK_DECK:
invoc = true;
- failure = 40 - (you.piety / 20) - (5 * you.skills[SK_EVOCATIONS]);
+ failure = 70 - (you.piety * 2 / 45)
+ - (9 * you.skills[SK_EVOCATIONS] / 2);
break;
case ABIL_NEMELEX_TRIPLE_DRAW:
@@ -750,6 +753,11 @@ static talent get_talent(ability_type ability, bool check_confused)
failure = 60 - (you.piety / 20) - (5 * you.skills[SK_EVOCATIONS]);
break;
+ case ABIL_NEMELEX_PEEK_DECK:
+ invoc = true;
+ failure = 40 - (you.piety / 20) - (5 * you.skills[SK_EVOCATIONS]);
+ break;
+
case ABIL_NEMELEX_DRAW_CARD:
invoc = true;
perfect = true; // Tactically important to allow perfection
@@ -824,6 +832,7 @@ bool activate_ability()
if ( talents.empty() )
{
mpr("Sorry, you're not good enough to have a special ability.");
+ crawl_state.zero_turns_taken();
return false;
}
if ( you.duration[DUR_CONF] )
@@ -832,6 +841,7 @@ bool activate_ability()
if ( talents.empty() )
{
mpr("You're too confused!");
+ crawl_state.zero_turns_taken();
return false;
}
}
@@ -875,6 +885,7 @@ bool activate_ability()
if ( selected < 0 )
{
mpr("You can't do that.");
+ crawl_state.zero_turns_taken();
return (false);
}
}
@@ -904,6 +915,7 @@ static bool activate_talent(const talent& tal)
if (hungerCheck && you.hunger_state <= HS_STARVING)
{
mpr("You're too hungry.");
+ crawl_state.zero_turns_taken();
return (false);
}
@@ -911,10 +923,16 @@ static bool activate_talent(const talent& tal)
// check that we can afford to pay the costs
if (!enough_mp( abil.mp_cost, false ))
+ {
+ crawl_state.zero_turns_taken();
return (false);
+ }
if (!enough_hp( abil.hp_cost, false ))
+ {
+ crawl_state.zero_turns_taken();
return (false);
+ }
// no turning back now... {dlb}
if (random2avg(100, 3) < tal.fail)
@@ -1238,7 +1256,7 @@ static bool do_ability(const ability_def& abil)
return (false);
}
- banished(DNGN_ENTER_PANDEMONIUM);
+ banished(DNGN_ENTER_PANDEMONIUM, "self");
break;
case ABIL_CHANNELING:
@@ -1555,7 +1573,9 @@ static bool do_ability(const ability_def& abil)
case ABIL_TROG_BROTHERS_IN_ARMS:
// Trog abilities don't use or train invocations.
- summon_berserker();
+ summon_berserker(you.piety +
+ random2(you.piety/4) - random2(you.piety/4),
+ true);
break;
case ABIL_SIF_MUNA_FORGET_SPELL:
@@ -1687,6 +1707,12 @@ static bool do_ability(const ability_def& abil)
exercise(SK_EVOCATIONS, 2 + random2(2));
break;
+ case ABIL_NEMELEX_MARK_DECK:
+ if ( !deck_mark() )
+ return false;
+ exercise(SK_EVOCATIONS, 4 + random2(4));
+ break;
+
case ABIL_NEMELEX_STACK_DECK:
if ( !deck_stack() )
return false;
@@ -1782,11 +1808,7 @@ static void pay_ability_costs(const ability_def& abil)
you.turn_is_over = !(abil.flags & ABFLAG_INSTANT);
const int food_cost = abil.food_cost + random2avg(abil.food_cost, 2);
- int piety_cost = abil.piety_cost.cost();
-
- if (abil.ability == ABIL_TROG_BROTHERS_IN_ARMS)
- // increase cost depending on current piety
- piety_cost += (you.piety-100)/20;
+ const int piety_cost = abil.piety_cost.cost();
#if DEBUG_DIAGNOSTICS
mprf(MSGCH_DIAGNOSTICS, "Cost: mp=%d; hp=%d; food=%d; piety=%d",
@@ -1816,7 +1838,7 @@ static void pay_ability_costs(const ability_def& abil)
int choose_ability_menu(const std::vector<talent>& talents)
{
- Menu abil_menu(MF_SINGLESELECT | MF_ANYPRINTABLE);
+ Menu abil_menu(MF_SINGLESELECT | MF_ANYPRINTABLE, "ability");
abil_menu.set_highlighter(NULL);
abil_menu.set_title(
new MenuEntry(" Ability "
@@ -2198,8 +2220,7 @@ void set_god_ability_slots( void )
{
if ( god_abilities[you.religion][i] != ABIL_NON_ABILITY )
{
- set_god_ability_helper(god_abilities[you.religion][i],
- (Options.lowercase_invocations ? 'a' : 'A') + num);
+ set_god_ability_helper(god_abilities[you.religion][i], 'a' + num);
++num;
}
}
@@ -2218,10 +2239,8 @@ static int find_ability_slot( ability_type which_ability )
// no requested slot, find new one and make it preferred.
- // skip over a-e if player prefers them for invocations
- const int startpoint = (Options.lowercase_invocations ? 5 : 0);
-
- for (int slot = startpoint; slot < 52; slot++)
+ // skip over a-e (invocations)
+ for (int slot = 5; slot < 52; slot++)
{
if (you.ability_letter_table[slot] == ABIL_NON_ABILITY)
{
@@ -2230,8 +2249,8 @@ static int find_ability_slot( ability_type which_ability )
}
}
- // if we skipped over a-e to reserve them, try them now
- for (int slot = startpoint - 1; slot >= 0; slot--)
+ // if we can't find anything else, try a-e
+ for (int slot = 4; slot >= 0; slot--)
{
if (you.ability_letter_table[slot] == ABIL_NON_ABILITY)
{
diff --git a/crawl-ref/source/abyss.cc b/crawl-ref/source/abyss.cc
index 06fa718286..a3ca3b9a77 100644
--- a/crawl-ref/source/abyss.cc
+++ b/crawl-ref/source/abyss.cc
@@ -33,6 +33,7 @@
#include "terrain.h"
#include "traps.h"
#include "view.h"
+#include "xom.h"
static bool place_feature_near( const coord_def &centre,
int radius,
@@ -69,6 +70,10 @@ void generate_abyss(void)
int i, j; // loop variables
int temp_rand; // probability determination {dlb}
+#if DEBUG_ABYSS
+ mpr("generate_abyss().", MSGCH_DIAGNOSTICS);
+#endif
+
for (i = 5; i < (GXM - 5); i++)
{
for (j = 5; j < (GYM - 5); j++)
@@ -91,6 +96,10 @@ void generate_abyss(void)
static void generate_area(int gx1, int gy1, int gx2, int gy2)
{
+#if DEBUG_ABYSS
+ mpr("generate_area().", MSGCH_DIAGNOSTICS);
+#endif
+
int items_placed = 0;
const int thickness = random2(70) + 30;
int thing_created;
@@ -156,6 +165,9 @@ static void generate_area(int gx1, int gy1, int gx2, int gy2)
{
thing_created = items(1, OBJ_MISCELLANY,
MISC_RUNE_OF_ZOT, true, 51, 51);
+#if DEBUG_ABYSS
+ mpr("Placing an Abyssal rune.", MSGCH_DIAGNOSTICS);
+#endif
}
else
{
@@ -172,6 +184,9 @@ static void generate_area(int gx1, int gy1, int gx2, int gy2)
}
}
+ int exits_wanted = 0;
+ int altars_wanted = 0;
+
for (int i = gx1; i <= gx2; i++)
{
for (int j = gy1; j <= gy2; j++)
@@ -180,9 +195,23 @@ static void generate_area(int gx1, int gy1, int gx2, int gy2)
grd[i][j] = replaced[random2(5)];
if (one_chance_in(7500)) // place an exit
+ exits_wanted++;
+
+ // Don't place exit under items
+ if (exits_wanted > 0 && igrd[i][j] == NON_ITEM)
+ {
grd[i][j] = DNGN_EXIT_ABYSS;
+ exits_wanted--;
+#if DEBUG_ABYSS
+ mpr("Placing Abyss exit.", MSGCH_DIAGNOSTICS);
+#endif
+ }
if (one_chance_in(10000)) // place an altar
+ altars_wanted++;
+
+ // Don't place altars under items.
+ if (altars_wanted > 0 && igrd[i][j] == NON_ITEM)
{
do
{
@@ -197,11 +226,109 @@ static void generate_area(int gx1, int gy1, int gx2, int gy2)
// Lugonu has a flat 50% chance of corrupting the altar
if ( coinflip() )
grd[i][j] = DNGN_ALTAR_LUGONU;
+
+ altars_wanted--;
+#if DEBUG_ABYSS
+ mpr("Placing altar.", MSGCH_DIAGNOSTICS);
+#endif
}
}
}
}
+static int abyss_exit_nearness()
+{
+ int nearness = INFINITE_DISTANCE;
+
+ for (int x = you.x_pos - LOS_RADIUS; x < you.x_pos + LOS_RADIUS; x++)
+ for (int y = you.y_pos - LOS_RADIUS; y < you.y_pos + LOS_RADIUS; y++)
+ {
+ if (!in_bounds(x, y))
+ continue;
+
+ // HACK: Why doesn't is_terrain_known() work here?
+ if (grd[x][y] == DNGN_EXIT_ABYSS
+ && get_screen_glyph(x, y) != ' ')
+ {
+ nearness = MIN(nearness,
+ grid_distance(you.x_pos, you.y_pos,
+ x, y));
+ }
+ }
+
+ return (nearness);
+}
+
+static int abyss_rune_nearness()
+{
+ int nearness = INFINITE_DISTANCE;
+
+ for (int x = you.x_pos - LOS_RADIUS; x < you.x_pos + LOS_RADIUS; x++)
+ for (int y = you.y_pos - LOS_RADIUS; y < you.y_pos + LOS_RADIUS; y++)
+ {
+ if (!in_bounds(x, y))
+ continue;
+
+ // HACK: Why doesn't is_terrain_known() work here?
+ if (get_screen_glyph(x, y) != ' ')
+ {
+ int i = igrd[x][y];
+
+ while (i != NON_ITEM)
+ {
+ item_def& item(mitm[i]);
+ if (is_rune(item) && item.plus == RUNE_ABYSSAL)
+ nearness = MIN(nearness,
+ grid_distance(you.x_pos, you.y_pos,
+ x, y));
+ i = item.link;
+ }
+ }
+ }
+
+ return (nearness);
+}
+
+static int exit_was_near;
+static int rune_was_near;
+
+static void xom_check_nearness_setup()
+{
+ exit_was_near = abyss_exit_nearness();
+ rune_was_near = abyss_rune_nearness();
+}
+
+// If the player was almost to the exit when it disppeared, Xom is
+// extremely amused. He's also extremely amused if the player winds
+// up right next to an exit when there wasn't one there before. The
+// same applies to Abyssal runes.
+static void xom_check_nearness()
+{
+ // Update known terrain
+ viewwindow(true, false);
+
+ int exit_is_near = abyss_exit_nearness();
+ int rune_is_near = abyss_rune_nearness();
+
+ if ((exit_was_near < INFINITE_DISTANCE
+ && exit_is_near == INFINITE_DISTANCE)
+ || (rune_was_near < INFINITE_DISTANCE
+ && rune_is_near == INFINITE_DISTANCE
+ && you.attribute[ATTR_ABYSSAL_RUNES] == 0))
+ {
+ xom_is_stimulated(255, "Xom snickers loudly.", true);
+ }
+
+ if ((rune_was_near == INFINITE_DISTANCE
+ && rune_is_near < INFINITE_DISTANCE
+ && you.attribute[ATTR_ABYSSAL_RUNES] == 0)
+ || (exit_was_near == INFINITE_DISTANCE &&
+ exit_is_near < INFINITE_DISTANCE))
+ {
+ xom_is_stimulated(255);
+ }
+}
+
static void abyss_lose_monster(monsters &mons)
{
if (mons.needs_transit())
@@ -213,6 +340,12 @@ static void abyss_lose_monster(monsters &mons)
void area_shift(void)
/*******************/
{
+#if DEBUG_ABYSS
+ mpr("area_shift().", MSGCH_DIAGNOSTICS);
+#endif
+
+ xom_check_nearness_setup();
+
for (unsigned int i = 0; i < MAX_MONSTERS; i++)
{
monsters &m = menv[i];
@@ -237,7 +370,7 @@ void area_shift(void)
grd[i][j] = DNGN_UNSEEN;
// nuke items
- destroy_item_stack( i, j );
+ lose_item_stack( i, j );
if (mgrd[i][j] != NON_MONSTER)
abyss_lose_monster( menv[ mgrd[i][j] ] );
@@ -296,6 +429,8 @@ void area_shift(void)
generate_area(5, 5, (GXM - 5), (GYM - 5));
+ xom_check_nearness();
+
for (unsigned int mcount = 0; mcount < 15; mcount++)
{
mons_place( RANDOM_MONSTER, BEH_HOSTILE, MHITNOT, false, 1, 1,
@@ -319,6 +454,8 @@ void save_abyss_uniques()
void abyss_teleport( bool new_area )
/**********************************/
{
+ xom_check_nearness_setup();
+
int x, y, i, j, k;
if (!new_area)
@@ -340,11 +477,19 @@ void abyss_teleport( bool new_area )
if (i < 100)
{
+#if DEBUG_ABYSS
+ mpr("Non-new area Abyss teleport.", MSGCH_DIAGNOSTICS);
+#endif
you.moveto(x, y);
+ xom_check_nearness();
return;
}
}
+#if DEBUG_ABYSS
+ mpr("New area Abyss teleport.", MSGCH_DIAGNOSTICS);
+#endif
+
// teleport to a new area of the abyss:
init_pandemonium(); // get new monsters
@@ -361,17 +506,7 @@ void abyss_teleport( bool new_area )
{
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 );
- }
-
+ item_was_lost( mitm[k] );
destroy_item( k );
}
}
@@ -396,6 +531,8 @@ void abyss_teleport( bool new_area )
generate_area( 10, 10, (GXM - 10), (GYM - 10) );
+ xom_check_nearness();
+
grd[you.x_pos][you.y_pos] = DNGN_FLOOR;
if ( one_chance_in(5) )
place_feature_near( you.pos(), LOS_RADIUS,
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc
index a32a1f67e4..ee535c1371 100644
--- a/crawl-ref/source/acr.cc
+++ b/crawl-ref/source/acr.cc
@@ -136,6 +136,7 @@
#include "tutorial.h"
#include "view.h"
#include "stash.h"
+#include "xom.h"
crawl_environment env;
player you;
@@ -148,6 +149,8 @@ char info[ INFO_SIZE ]; // messaging queue extern'd everywhere {dlb}
int stealth; // externed in view.cc
+static key_recorder repeat_again_rec;
+
// Clockwise, around the compass from north (same order as enum RUN_DIR)
const struct coord_def Compass[8] =
{
@@ -170,6 +173,15 @@ static void world_reacts();
static command_type get_next_cmd();
static keycode_type get_next_keycode();
static command_type keycode_to_command( keycode_type key );
+static void setup_cmd_repeat();
+static void do_prev_cmd_again();
+static void update_replay_state();
+
+static void show_commandline_options_help();
+static void wanderer_startup_message();
+static void god_greeting_message( bool game_start );
+static void take_starting_note();
+static void startup_tutorial();
#ifdef DGL_SIMPLE_MESSAGING
static void read_messages();
@@ -187,27 +199,8 @@ int main( int argc, char *argv[] )
// 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(" -morgue <dir> directory to save character dumps");
- puts(" -macro <dir> directory to save/find macro.txt");
- 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");
- puts(" -scorefile <filename> scorefile to report on");
- exit(1);
+ show_commandline_options_help();
+ return 1;
}
// Init monsters up front - needed to handle the mon_glyph option right.
@@ -222,7 +215,7 @@ int main( int argc, char *argv[] )
if (Options.sc_entries != 0 || !SysEnv.scorefile.empty())
{
hiscores_print_all( Options.sc_entries, Options.sc_format );
- exit(0);
+ return 0;
}
else
{
@@ -235,130 +228,35 @@ int main( int argc, char *argv[] )
// override some options for tutorial
init_tutorial_options();
- if (game_start || Options.always_greet)
- {
- msg::stream << "Welcome, " << you.your_name << " the "
- << species_name( you.species,you.experience_level )
- << " " << you.class_name << "."
- << std::endl;
- // Activate markers only after the welcome message, so the
- // player can see any resulting messages.
- env.markers.activate_all();
+ msg::stream << "Welcome, " << you.your_name << " the "
+ << species_name( you.species,you.experience_level )
+ << " " << you.class_name << "."
+ << std::endl;
- // 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 ];
+ // Activate markers only after the welcome message, so the
+ // player can see any resulting messages.
+ env.markers.activate_all();
- 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.");
- }
- }
+ if (game_start && you.char_class == JOB_WANDERER)
+ wanderer_startup_message();
- // 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;
- case GOD_LUGONU:
- simple_god_message( " says: Spread carnage and corruption!");
- break;
- case GOD_BEOGH:
- simple_god_message(
- " says: Drown the unbelievers in a sea of blood!");
- break;
- default:
- break;
- }
+ god_greeting_message( game_start );
- // warn player about their weapon, if unsuitable
- wield_warning(false);
- }
+ // warn player about their weapon, if unsuitable
+ wield_warning(false);
if ( game_start )
- {
+ {
if (Options.tutorial_left)
- {
- // don't allow triggering at game start
- Options.tut_just_triggered = true;
- // print stats and everything
- prep_input();
- msg::streams(MSGCH_TUTORIAL)
- << "Press any key to start the tutorial intro, "
- "or Escape to skip it."
- << std::endl;
- const int ch = c_getch();
-
- if (ch != ESCAPE)
- tut_starting_screen();
- }
-
- std::ostringstream notestr;
- notestr << you.your_name << ", the "
- << species_name(you.species,you.experience_level) << " "
- << you.class_name
- << ", began the quest for the Orb.";
- take_note(Note(NOTE_USER_NOTE, 0, 0, notestr.str().c_str()));
-
- notestr.str("");
- notestr.clear();
-
- notestr << "HP: " << you.hp << "/" << you.hp_max
- << " MP: " << you.magic_points << "/" << you.max_magic_points;
- take_note(Note(NOTE_XP_LEVEL_CHANGE, you.experience_level, 0,
- notestr.str().c_str()));
+ startup_tutorial();
+ take_starting_note();
}
while (true)
- {
input();
- }
// Should never reach this stage, right?
-
#ifdef UNIX
unixcurses_shutdown();
#endif
@@ -366,6 +264,130 @@ int main( int argc, char *argv[] )
return 0;
} // end main()
+static void show_commandline_options_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(" -morgue <dir> directory to save character dumps");
+ puts(" -macro <dir> directory to save/find macro.txt");
+ 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");
+ puts(" -scorefile <filename> scorefile to report on");
+}
+
+static void wanderer_startup_message()
+{
+ 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.");
+ }
+}
+
+static void god_greeting_message( bool game_start )
+{
+ 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:
+ simple_god_message(" says: 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;
+ case GOD_LUGONU:
+ simple_god_message( " says: Spread carnage and corruption!");
+ break;
+ case GOD_BEOGH:
+ simple_god_message(
+ " says: Drown the unbelievers in a sea of blood!");
+ break;
+ case GOD_NO_GOD:
+ case NUM_GODS:
+ case GOD_RANDOM:
+ break;
+ }
+}
+
+static void take_starting_note()
+{
+ std::ostringstream notestr;
+ notestr << you.your_name << ", the "
+ << species_name(you.species,you.experience_level) << " "
+ << you.class_name
+ << ", began the quest for the Orb.";
+ take_note(Note(NOTE_MESSAGE, 0, 0, notestr.str().c_str()));
+
+ notestr.str("");
+ notestr.clear();
+
+ notestr << "HP: " << you.hp << "/" << you.hp_max
+ << " MP: " << you.magic_points << "/" << you.max_magic_points;
+ take_note(Note(NOTE_XP_LEVEL_CHANGE, you.experience_level, 0,
+ notestr.str().c_str()));
+}
+
+static void startup_tutorial()
+{
+ // don't allow triggering at game start
+ Options.tut_just_triggered = true;
+ // print stats and everything
+ prep_input();
+ msg::streams(MSGCH_TUTORIAL)
+ << "Press any key to start the tutorial intro, or Escape to skip it."
+ << std::endl;
+ const int ch = c_getch();
+
+ if (ch != ESCAPE)
+ tut_starting_screen();
+}
+
#ifdef WIZARD
static void handle_wizard_command( void )
{
@@ -390,16 +412,53 @@ static void handle_wizard_command( void )
you.wizard = true;
redraw_screen();
+
+ if (crawl_state.cmd_repeat_start)
+ {
+ crawl_state.cancel_cmd_repeat("Can't repeat entering wizard "
+ "mode.");
+ return;
+ }
}
mpr( "Enter Wizard Command (? - help): ", MSGCH_PROMPT );
wiz_command = getch();
+ if (crawl_state.cmd_repeat_start)
+ {
+ // Easiest to list which wizard commands *can* be repeated.
+ switch (wiz_command)
+ {
+ case 'x':
+ case '$':
+ case 'a':
+ case 'c':
+ case 'h':
+ case 'H':
+ case 'm':
+ case 'M':
+ case 'X':
+ case '!':
+ case '[':
+ case ']':
+ case '^':
+ case '%':
+ case 'o':
+ case 'z':
+ case 'Z':
+ break;
+
+ default:
+ crawl_state.cant_cmd_repeat("You cannot repeat that "
+ "wizard command.");
+ return;
+ }
+ }
+
switch (wiz_command)
{
case '?':
- list_commands(true); // tell it to list wizard commands
- redraw_screen();
+ list_commands(true, 0, true); // tell it to list wizard commands
break;
case CONTROL('G'):
@@ -549,13 +608,41 @@ static void handle_wizard_command( void )
break;
+ case 'C':
+ {
+ // this command isn't very exciting... feel free to replace
+ i = prompt_invent_item( "(Un)curse which item?", MT_INVLIST, -1 );
+ if (i == PROMPT_ABORT)
+ {
+ canned_msg( MSG_OK );
+ break;
+ }
+
+ item_def& item(you.inv[i]);
+
+ if (item_cursed(item))
+ do_uncurse_item(item);
+ else
+ do_curse_item(item);
+
+ break;
+ }
+
case 'B':
if (you.level_type != LEVEL_ABYSS)
- banished( DNGN_ENTER_ABYSS );
+ banished( DNGN_ENTER_ABYSS, "wizard command" );
else
down_stairs(you.your_level, DNGN_EXIT_ABYSS);
break;
+ case CONTROL('A'):
+ if (you.level_type == LEVEL_ABYSS)
+ abyss_teleport(true);
+ else
+ mpr("You can only abyss_teleport() inside the Abyss.");
+
+ break;
+
case 'g':
debug_add_skills();
break;
@@ -574,21 +661,29 @@ static void handle_wizard_command( void )
you.duration[DUR_POISONING] = 0;
you.disease = 0;
set_hp( abs(you.hp_max), false );
- set_hunger( 5000 + abs(you.hunger), true );
+ set_hunger( 10999, true );
break;
case 'H':
you.rotting = 0;
you.duration[DUR_POISONING] = 0;
+ if (you.duration[DUR_BEHELD])
+ {
+ you.duration[DUR_BEHELD] = 0;
+ you.beheld_by.clear();
+ }
+ you.duration[DUR_CONF] = 0;
you.disease = 0;
inc_hp( 10, true );
set_hp( you.hp_max, false );
- set_hunger( 12000, true );
+ set_hunger( 10999, true );
you.redraw_hit_points = 1;
break;
case 'b':
- blink(1000, true); // wizards can always blink
+ // wizards can always blink, with no restrictions or
+ // magical contamination.
+ blink(1000, true, true);
break;
case '~':
@@ -664,23 +759,34 @@ static void handle_wizard_command( void )
case 'P':
{
- mpr( "Destination for portal? ", MSGCH_PROMPT );
- get_input_line( specs, sizeof( specs ) );
+ mpr( "Destination for portal (defaults to 'bazaar')? ", MSGCH_PROMPT );
+ if (cancelable_get_line( specs, sizeof( specs ) ))
+ {
+ canned_msg( MSG_OK );
+ break;
+ }
std::string dst = specs;
dst = trim_string(dst);
+ dst = replace_all(dst, " ", "_");
if (dst == "")
- canned_msg( MSG_OK );
- else
+ dst = "bazaar";
+
+ if (find_map_by_name(dst) == -1 &&
+ random_map_for_tag(dst, false) == -1)
{
- grd[you.x_pos][you.y_pos] = DNGN_ENTER_PORTAL_VAULT;
- map_wiz_props_marker
- *marker = new map_wiz_props_marker(you.pos());
- marker->set_property("dst", dst);
- marker->set_property("desc", "wizard portal, dest = " + dst);
- env.markers.add(marker);
+ mprf("No map named '%s' or tagged '%s'.",
+ dst.c_str(), dst.c_str());
+ break;
}
+
+ grd[you.x_pos][you.y_pos] = DNGN_ENTER_PORTAL_VAULT;
+ map_wiz_props_marker
+ *marker = new map_wiz_props_marker(you.pos());
+ marker->set_property("dst", dst);
+ marker->set_property("desc", "wizard portal, dest = " + dst);
+ env.markers.add(marker);
break;
}
@@ -809,7 +915,7 @@ static void handle_wizard_command( void )
// Use mpr_comma_separated_list() because the list
// might be *LONG*.
- mpr_comma_separated_list(prefix, matches, ", ", " and ",
+ mpr_comma_separated_list(prefix, matches, " and ", ", ",
MSGCH_DIAGNOSTICS);
return;
}
@@ -849,6 +955,19 @@ static void handle_wizard_command( void )
break;
case '{':
+ if (testbits(env.level_flags, LFLAG_NOT_MAPPABLE)
+ || testbits(get_branch_flags(), BFLAG_NOT_MAPPABLE))
+ {
+ if (!yesno("Force level to be mappable? "))
+ {
+ canned_msg( MSG_OK );
+ return;
+ }
+
+ unset_level_flags(LFLAG_NOT_MAPPABLE | LFLAG_NO_MAGIC_MAP);
+ unset_branch_flags(BFLAG_NOT_MAPPABLE | BFLAG_NO_MAGIC_MAP);
+ }
+
magic_mapping(1000, 100, true, true);
break;
@@ -913,6 +1032,7 @@ static void handle_wizard_command( void )
formatted_mpr(formatted_string::parse_string("Not a <magenta>Wizard</magenta> Command."));
break;
}
+ you.turn_is_over = false;
}
#endif
@@ -988,16 +1108,161 @@ static void recharge_rods()
}
}
+static bool cmd_is_repeatable(command_type cmd, bool is_again = false)
+{
+ switch(cmd)
+ {
+ // Informational commands
+ case CMD_LOOK_AROUND:
+ case CMD_INSPECT_FLOOR:
+ case CMD_EXAMINE_OBJECT:
+ case CMD_LIST_WEAPONS:
+ case CMD_LIST_ARMOUR:
+ case CMD_LIST_JEWELLERY:
+ case CMD_LIST_EQUIPMENT:
+ case CMD_CHARACTER_DUMP:
+ case CMD_DISPLAY_COMMANDS:
+ case CMD_DISPLAY_INVENTORY:
+ case CMD_DISPLAY_KNOWN_OBJECTS:
+ case CMD_DISPLAY_MUTATIONS:
+ case CMD_DISPLAY_SKILLS:
+ case CMD_DISPLAY_OVERMAP:
+ case CMD_DISPLAY_RELIGION:
+ case CMD_DISPLAY_CHARACTER_STATUS:
+ case CMD_DISPLAY_SPELLS:
+ case CMD_EXPERIENCE_CHECK:
+ case CMD_GET_VERSION:
+ case CMD_RESISTS_SCREEN:
+ case CMD_READ_MESSAGES:
+ case CMD_SEARCH_STASHES:
+ mpr("You can't repeat informational commands.");
+ return false;
+
+ // Multi-turn commands
+ case CMD_PICKUP:
+ case CMD_DROP:
+ case CMD_BUTCHER:
+ case CMD_GO_UPSTAIRS:
+ case CMD_GO_DOWNSTAIRS:
+ case CMD_WIELD_WEAPON:
+ case CMD_WEAPON_SWAP:
+ case CMD_WEAR_JEWELLERY:
+ case CMD_REMOVE_JEWELLERY:
+ case CMD_MEMORISE_SPELL:
+ case CMD_EXPLORE:
+ case CMD_INTERLEVEL_TRAVEL:
+ mpr("You can't repeat multi-turn commands.");
+ return false;
+
+ // Miscellaneous non-repeatable commands.
+ case CMD_TOGGLE_AUTOPICKUP:
+ case CMD_ADJUST_INVENTORY:
+ case CMD_REPLAY_MESSAGES:
+ case CMD_REDRAW_SCREEN:
+ case CMD_MACRO_ADD:
+ case CMD_SAVE_GAME:
+ case CMD_SAVE_GAME_NOW:
+ case CMD_SUSPEND_GAME:
+ case CMD_QUIT:
+ case CMD_DESTROY_ITEM:
+ case CMD_MARK_STASH:
+ case CMD_FORGET_STASH:
+ case CMD_FIX_WAYPOINT:
+ case CMD_CLEAR_MAP:
+ case CMD_INSCRIBE_ITEM:
+ case CMD_TOGGLE_AUTOPRAYER:
+ case CMD_MAKE_NOTE:
+ mpr("You can't repeat that command.");
+ return false;
+
+ case CMD_DISPLAY_MAP:
+ mpr("You can't repeat map commands.");
+ return false;
+
+ case CMD_MOUSE_MOVE:
+ case CMD_MOUSE_CLICK:
+ mpr("You can't repeat mouse clicks or movements.");
+ return false;
+
+ case CMD_REPEAT_CMD:
+ mpr("You can't repeat the repeat command!");
+ return false;
+
+ case CMD_RUN_LEFT:
+ case CMD_RUN_DOWN:
+ case CMD_RUN_UP:
+ case CMD_RUN_RIGHT:
+ case CMD_RUN_UP_LEFT:
+ case CMD_RUN_DOWN_LEFT:
+ case CMD_RUN_UP_RIGHT:
+ case CMD_RUN_DOWN_RIGHT:
+ mpr("Why would you want to repeat a run command?");
+ return false;
+
+ case CMD_PREV_CMD_AGAIN:
+ ASSERT(!is_again);
+ if (crawl_state.prev_cmd == CMD_NO_CMD)
+ {
+ mpr("No previous command to repeat.");
+ return false;
+ }
+
+ return cmd_is_repeatable(crawl_state.prev_cmd, true);
+
+ case CMD_MOVE_NOWHERE:
+ case CMD_REST:
+ case CMD_SEARCH:
+ return i_feel_safe(true);
+
+ case CMD_MOVE_LEFT:
+ case CMD_MOVE_DOWN:
+ case CMD_MOVE_UP:
+ case CMD_MOVE_RIGHT:
+ case CMD_MOVE_UP_LEFT:
+ case CMD_MOVE_DOWN_LEFT:
+ case CMD_MOVE_UP_RIGHT:
+ case CMD_MOVE_DOWN_RIGHT:
+ if (!i_feel_safe())
+ return yesno("Really repeat movement command while monsters "
+ "are nearby?");
+
+ return true;
+
+ case CMD_NO_CMD:
+ mpr("Unknown command, not repeating.");
+ return false;
+
+ default:
+ return true;
+ }
+
+ return false;
+}
+
/* used to determine whether to apply the berserk penalty at end
of round */
bool apply_berserk_penalty = false;
+static void drift_player(int move_x, int move_y);
/*
- This function handles the player's input. It's called from main(), from
- inside an endless loop.
+ * This function handles the player's input. It's called from main(),
+ * from inside an endless loop.
*/
static void input()
{
+ crawl_state.clear_god_acting();
+ check_beholders();
+
+ if (crawl_state.is_replaying_keys() && crawl_state.is_repeating_cmd()
+ && kbhit())
+ {
+ // User pressed a key, so stop repeating commands and discard
+ // the keypress
+ crawl_state.cancel_cmd_repeat();
+ getchm();
+ return;
+ }
+
you.turn_is_over = false;
prep_input();
@@ -1041,8 +1306,18 @@ static void input()
learned_something_new(TUT_RETREAT_CASTER);
}
- if ( you.duration[DUR_PARALYSIS] )
+ if ( you.cannot_act() )
{
+ crawl_state.cancel_cmd_repeat("Cannot move, cancelling command "
+ "repetition.");
+
+ // may sleep walk
+ if (!you.paralysed() && you.mutation[MUT_DRIFTING]
+ && (random2(100) <= you.mutation[MUT_DRIFTING] * 5) )
+ {
+ drift_player(0, 0);
+ }
+
world_reacts();
return;
}
@@ -1075,7 +1350,12 @@ static void input()
crawl_state.check_term_size();
if (crawl_state.terminal_resized)
handle_terminal_resize();
-
+
+ repeat_again_rec.paused = (crawl_state.is_replaying_keys()
+ && !crawl_state.cmd_repeat_start);
+
+ crawl_state.input_line_curr = 0;
+
{
// Enable the cursor to read input. The cursor stays on while
// the command is being processed, so subsidiary prompts
@@ -1089,6 +1369,13 @@ static void input()
crawl_state.waiting_for_command = false;
+ if (cmd != CMD_PREV_CMD_AGAIN && cmd != CMD_REPEAT_CMD
+ && !crawl_state.is_replaying_keys())
+ {
+ crawl_state.prev_cmd = cmd;
+ crawl_state.input_line_strs.clear();
+ }
+
if (cmd != CMD_MOUSE_MOVE)
c_input_reset(false);
@@ -1098,8 +1385,17 @@ static void input()
if (!you.turn_is_over && cmd != CMD_NEXT_CMD)
process_command( cmd );
+ repeat_again_rec.paused = true;
+
if (cmd != CMD_MOUSE_MOVE)
c_input_reset(false, true);
+
+ // If the command was CMD_REPEAT_CMD, then the key for the
+ // command to repeat has been placed into the macro buffer,
+ // so return now to let input() be called again while
+ // the keys to repeat are recorded.
+ if (cmd == CMD_REPEAT_CMD)
+ return;
}
if (need_to_autoinscribe())
@@ -1115,6 +1411,8 @@ static void input()
else
viewwindow(true, false);
+ update_replay_state();
+
if (you.num_turns != -1)
{
PlaceInfo& curr_PlaceInfo = you.get_place_info();
@@ -1176,6 +1474,8 @@ static void input()
curr_PlaceInfo += delta;
curr_PlaceInfo.assert_validity();
}
+
+ crawl_state.clear_god_acting();
}
static bool toggle_flag( bool* flag, const char* flagname )
@@ -1185,11 +1485,26 @@ static bool toggle_flag( bool* flag, const char* flagname )
return *flag;
}
+static bool stairs_check_beheld()
+{
+ if (you.duration[DUR_BEHELD] && !you.duration[DUR_CONF])
+ {
+ mprf("You cannot move away from %s!",
+ menv[you.beheld_by[0]].name(DESC_NOCAP_THE, true).c_str());
+ return true;
+ }
+
+ return false;
+}
+
static void go_downstairs();
static void go_upstairs()
{
const dungeon_feature_type ygrd = grd(you.pos());
+ if (stairs_check_beheld())
+ return;
+
// Allow both < and > to work for Abyss exits.
if (ygrd == DNGN_EXIT_ABYSS)
{
@@ -1228,7 +1543,21 @@ static void go_upstairs()
static void go_downstairs()
{
- if (grid_stair_direction(grd(you.pos())) != CMD_GO_DOWNSTAIRS)
+ bool shaft = (trap_type_at_xy(you.x_pos, you.y_pos) == TRAP_SHAFT
+ && grd[you.x_pos][you.y_pos] != DNGN_UNDISCOVERED_TRAP);
+
+
+ if (stairs_check_beheld())
+ return;
+
+ if (shaft && you.flight_mode() == FL_LEVITATE)
+ {
+ mpr("You can't fall through a shaft while levitating.");
+ return;
+ }
+
+ if (grid_stair_direction(grd(you.pos())) != CMD_GO_DOWNSTAIRS
+ && !shaft)
{
if (grd(you.pos()) == DNGN_STONE_ARCH)
mpr("There is nothing on the other side of the stone arch.");
@@ -1242,10 +1571,18 @@ static void go_downstairs()
mpr("You're held in a net!");
return;
}
- tag_followers(); // only those beside us right now can follow
- start_delay( DELAY_DESCENDING_STAIRS,
- 1 + (you.burden_state > BS_UNENCUMBERED),
- you.your_level );
+
+ if (shaft)
+ {
+ start_delay( DELAY_DESCENDING_STAIRS, 0, you.your_level );
+ }
+ else
+ {
+ tag_followers(); // only those beside us right now can follow
+ start_delay( DELAY_DESCENDING_STAIRS,
+ 1 + (you.burden_state > BS_UNENCUMBERED),
+ you.your_level );
+ }
}
static void experience_check()
@@ -1292,8 +1629,6 @@ static void experience_check()
void process_command( command_type cmd )
{
-
- FixedVector < int, 2 > plox;
apply_berserk_penalty = true;
switch (cmd)
@@ -1361,6 +1696,51 @@ void process_command( command_type cmd )
Options.show_more_prompt = true;
break;
+ case CMD_REPEAT_KEYS:
+ ASSERT(crawl_state.is_repeating_cmd());
+
+ if (crawl_state.prev_repetition_turn == you.num_turns
+ && !(crawl_state.repeat_cmd == CMD_WIZARD
+ || (crawl_state.repeat_cmd == CMD_PREV_CMD_AGAIN
+ && crawl_state.prev_cmd == CMD_WIZARD)))
+ {
+ // This is a catch-all that shouldn't really happen.
+ // If the command always takes zero turns, then it
+ // should be prevented in cmd_is_repeatable(). If
+ // a command sometimes takes zero turns (because it
+ // can't be done, for instance), then
+ // crawl_state.zero_turns_taken() should be called when
+ // it does take zero turns, to cancel command repetition
+ // before we reach here.
+#ifdef WIZARD
+ crawl_state.cant_cmd_repeat("Can't repeat a command which "
+ "takes no turns (unless it's a "
+ "wizard command), cancelling ");
+#else
+ crawl_state.cant_cmd_repeat("Can't repeat a command which "
+ "takes no turns, cancelling "
+ "repetitions.");
+#endif
+ crawl_state.cancel_cmd_repeat();
+ return;
+ }
+
+ crawl_state.cmd_repeat_count++;
+ if (crawl_state.cmd_repeat_count >= crawl_state.cmd_repeat_goal)
+ {
+ crawl_state.cancel_cmd_repeat();
+ return;
+ }
+
+ ASSERT(crawl_state.repeat_cmd_keys.size() > 0);
+ repeat_again_rec.paused = true;
+ macro_buf_add(crawl_state.repeat_cmd_keys);
+ macro_buf_add(KEY_REPEAT_KEYS);
+
+ crawl_state.prev_repetition_turn = you.num_turns;
+
+ break;
+
case CMD_TOGGLE_AUTOPICKUP:
toggle_flag( &Options.autopickup_on, "Autopickup");
break;
@@ -1474,8 +1854,19 @@ void process_command( command_type cmd )
}
else if (you.attribute[ATTR_HELD])
{
- mpr("You cannot shoot anything while held in a net!");
- break;
+ const item_def *weapon = you.weapon();
+ if (!weapon || !is_range_weapon(*weapon))
+ {
+ mpr("You cannot throw anything while held in a net!");
+ break;
+ }
+ else if (weapon->sub_type != WPN_BLOWGUN)
+ {
+ mprf("You cannot shoot with your %s while held in a net!",
+ weapon->name(DESC_BASENAME).c_str());
+ break;
+ }
+ // else shooting is possible
}
if (Options.tutorial_left)
Options.tut_throw_counter++;
@@ -1645,6 +2036,10 @@ void process_command( command_type cmd )
mesclr();
break;
+ case CMD_ANNOTATE_LEVEL:
+ annotate_level();
+ break;
+
case CMD_EXPLORE:
// Start exploring
start_explore(Options.explore_greedy);
@@ -1660,11 +2055,13 @@ void process_command( command_type cmd )
break;
}
#endif
- plox[0] = 0;
- show_map(plox, true);
- redraw_screen();
- if (plox[0] > 0)
- start_travel(plox[0], plox[1]);
+ {
+ coord_def pos;
+ show_map(pos, true);
+ redraw_screen();
+ if (pos.x > 0)
+ start_travel(pos.x, pos.y);
+ }
break;
case CMD_DISPLAY_KNOWN_OBJECTS:
@@ -1700,10 +2097,12 @@ void process_command( command_type cmd )
case CMD_DISPLAY_COMMANDS:
if (Options.tutorial_left)
+ {
list_tutorial_help();
+ redraw_screen();
+ }
else
- list_commands(false);
- redraw_screen();
+ list_commands(false, 0, true);
break;
case CMD_EXPERIENCE_CHECK:
@@ -1814,6 +2213,14 @@ void process_command( command_type cmd )
version();
break;
+ case CMD_REPEAT_CMD:
+ setup_cmd_repeat();
+ break;
+
+ case CMD_PREV_CMD_AGAIN:
+ do_prev_cmd_again();
+ break;
+
case CMD_NO_CMD:
default:
if (Options.tutorial_left)
@@ -1884,6 +2291,9 @@ static void decrement_durations()
if (decrement_a_duration(DUR_BUILDING_RAGE))
go_berserk(false);
+ if (decrement_a_duration(DUR_SLEEP))
+ you.awake();
+
// 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
@@ -2110,11 +2520,17 @@ static void decrement_durations()
decrement_a_duration( DUR_SURE_BLADE,
"The bond with your blade fades away." );
+ if ( decrement_a_duration( DUR_BEHELD, "You break out of your daze.",
+ -1, 0, NULL, MSGCH_RECOVERY ))
+ {
+ you.beheld_by.clear();
+ }
+
dec_slow_player();
dec_haste_player();
if (decrement_a_duration(DUR_MIGHT, "You feel a little less mighty now."))
- modify_stat(STAT_STRENGTH, -5, true);
+ modify_stat(STAT_STRENGTH, -5, true, "might running out");
if (decrement_a_duration(DUR_BERSERKER, "You are no longer berserk."))
{
@@ -2327,10 +2743,12 @@ static void check_banished()
static void world_reacts()
{
+ crawl_state.clear_god_acting();
+
if (you.num_turns != -1)
{
you.num_turns++;
- if (env.turns_on_level + 1 > env.turns_on_level)
+ if (env.turns_on_level < INT_MAX)
env.turns_on_level++;
update_turn_count();
}
@@ -2338,10 +2756,12 @@ static void world_reacts()
run_environment_effects();
- if ( !you.duration[DUR_PARALYSIS] && !you.mutation[MUT_BLURRY_VISION] &&
+ if ( !you.cannot_act() && !you.mutation[MUT_BLURRY_VISION] &&
(you.mutation[MUT_ACUTE_VISION] >= 2 ||
random2(50) < you.skills[SK_TRAPS_DOORS]) )
+ {
search_around(false); // check nonadjacent squares too
+ }
stealth = check_stealth();
@@ -2447,7 +2867,7 @@ static void world_reacts()
// food death check:
if (you.is_undead != US_UNDEAD && you.hunger <= 500)
{
- if (!you.duration[DUR_PARALYSIS] && one_chance_in(40))
+ if (!you.cannot_act() && one_chance_in(40))
{
mpr("You lose consciousness!", MSGCH_FOOD);
you.duration[DUR_PARALYSIS] += 5 + random2(8);
@@ -2465,7 +2885,7 @@ static void world_reacts()
viewwindow(true, false);
- if (you.duration[DUR_PARALYSIS] > 0 && any_messages())
+ if (you.cannot_act() && any_messages())
more();
spawn_random_monsters();
@@ -2485,8 +2905,6 @@ static void show_message_line(std::string line)
std::string sender = line.substr(0, sender_pos);
line = line.substr(sender_pos + 1);
trim_string(line);
- // XXX: Eventually fix mpr so it can do a different colour for
- // the sender.
formatted_string fs;
fs.textcolor(WHITE);
fs.cprintf("%s: ", sender.c_str());
@@ -2657,6 +3075,7 @@ command_type keycode_to_command( keycode_type key )
{
case KEY_MACRO_DISABLE_MORE: return CMD_DISABLE_MORE;
case KEY_MACRO_ENABLE_MORE: return CMD_ENABLE_MORE;
+ case KEY_REPEAT_KEYS: return CMD_REPEAT_KEYS;
case 'b': return CMD_MOVE_DOWN_LEFT;
case 'h': return CMD_MOVE_LEFT;
case 'j': return CMD_MOVE_DOWN;
@@ -2737,8 +3156,9 @@ command_type keycode_to_command( keycode_type key )
case '(': return CMD_LIST_WEAPONS;
case '\\': return CMD_DISPLAY_KNOWN_OBJECTS;
case '\'': return CMD_WEAPON_SWAP;
+ case '`': return CMD_PREV_CMD_AGAIN;
- case '0': return CMD_NO_CMD;
+ case '0': return CMD_REPEAT_CMD;
case '5': return CMD_REST;
case CONTROL('B'): return CMD_OPEN_DOOR_DOWN_LEFT;
@@ -2756,7 +3176,7 @@ command_type keycode_to_command( keycode_type key )
case CONTROL('E'): return CMD_FORGET_STASH;
case CONTROL('F'): return CMD_SEARCH_STASHES;
case CONTROL('G'): return CMD_INTERLEVEL_TRAVEL;
- case CONTROL('I'): return CMD_NO_CMD;
+ case CONTROL('I'): return CMD_ANNOTATE_LEVEL;
case CONTROL('M'): return CMD_NO_CMD;
case CONTROL('O'): return CMD_EXPLORE;
case CONTROL('P'): return CMD_REPLAY_MESSAGES;
@@ -2823,7 +3243,6 @@ static void open_door(int move_x, int move_y, bool check_confused)
if (mon != NON_MONSTER && player_can_hit_monster(&menv[mon]))
{
-
if (mons_is_caught(&menv[mon]))
{
@@ -2848,7 +3267,8 @@ static void open_door(int move_x, int move_y, bool check_confused)
return;
}
- if (grd[dx][dy] >= DNGN_TRAP_MECHANICAL && grd[dx][dy] <= DNGN_TRAP_III)
+ if (grd[dx][dy] >= DNGN_TRAP_MECHANICAL
+ && grd[dx][dy] <= DNGN_TRAP_NATURAL)
{
if (env.cgrid[dx][dy] != EMPTY_CLOUD)
{
@@ -2997,7 +3417,6 @@ static void close_door(int door_x, int door_y)
}
} // end open_door()
-
// initialise whole lot of stuff...
// returns true if a new character
static bool initialise(void)
@@ -3145,6 +3564,8 @@ static bool initialise(void)
activate_notes(true);
+ add_key_recorder(&repeat_again_rec);
+
return (newc);
}
@@ -3203,8 +3624,49 @@ static void do_berserk_no_combat_penalty(void)
} // end do_berserk_no_combat_penalty()
-// Called when the player moves by walking/running. Also calls
-// attack function and trap function etc when necessary.
+void drift_player(int move_x, int move_y)
+{
+ int drift_dir = -1;
+ int okay_dirs = 0;
+
+ // don't drift if held in a net
+ if (you.attribute[ATTR_HELD])
+ return;
+
+ for (int i = 0; i < 8; i++)
+ {
+ const coord_def drift_delta = Compass[i];
+ const coord_def new_pos = you.pos() + drift_delta;
+ const unsigned short targ_monst = mgrd(new_pos);
+
+ if (you.can_pass_through(new_pos)
+ && !is_grid_dangerous(grd(new_pos))
+ && (targ_monst == NON_MONSTER ||
+ mons_is_submerged(&menv[targ_monst])))
+ {
+ if (one_chance_in(++okay_dirs))
+ drift_dir = i;
+ }
+ }
+
+ if (okay_dirs > 0)
+ {
+ const coord_def drift_delta = Compass[drift_dir];
+ const coord_def new_pos = you.pos() + drift_delta;
+
+ if (drift_delta == coord_def(-move_x, -move_y))
+ mpr("You drift backwards.");
+ else if (drift_delta == coord_def(move_x, move_y))
+ mpr("You drift forwards.");
+ else
+ mpr("You drift.");
+
+ move_player_to_grid(new_pos.x, new_pos.y, true, true, false);
+ }
+}
+
+// Called when the player moves by walking/running. Also calls attack
+// function etc when necessary.
static void move_player(int move_x, int move_y)
{
bool attacking = false;
@@ -3229,15 +3691,48 @@ static void move_player(int move_x, int move_y)
const int new_targ_x = you.x_pos + move_x;
const int new_targ_y = you.y_pos + move_y;
if (!in_bounds(new_targ_x, new_targ_y)
- || grid_is_solid(grd[new_targ_x][new_targ_y]))
+ || !you.can_pass_through(new_targ_x, new_targ_y))
{
you.turn_is_over = true;
mpr("Ouch!");
apply_berserk_penalty = true;
+ crawl_state.cancel_cmd_repeat();
+
return;
}
} // end of if you.duration[DUR_CONF]
+ const int targ_x = you.x_pos + move_x;
+ const int targ_y = you.y_pos + move_y;
+ const dungeon_feature_type targ_grid = grd[ targ_x ][ targ_y ];
+ const unsigned short targ_monst = mgrd[ targ_x ][ targ_y ];
+ const bool targ_pass = you.can_pass_through(targ_x, targ_y);
+
+ // cannot move away from mermaid but you CAN fight neighbouring squares
+ if (you.duration[DUR_BEHELD] && !you.duration[DUR_CONF]
+ && (targ_monst == NON_MONSTER || mons_friendly(&menv[targ_monst])
+ || mons_is_submerged(&menv[targ_monst])))
+ {
+ for (unsigned int i = 0; i < you.beheld_by.size(); i++)
+ {
+ monsters* mon = &menv[you.beheld_by[i]];
+ coord_def pos = mon->pos();
+ int olddist = distance(you.x_pos, you.y_pos, pos.x, pos.y);
+ int newdist = distance(you.x_pos + move_x, you.y_pos + move_y,
+ pos.x, pos.y);
+
+ if (olddist < newdist)
+ {
+ mprf("You cannot move away from %s!",
+ mon->name(DESC_NOCAP_THE, true).c_str());
+
+ move_x = 0;
+ move_y = 0;
+ return;
+ }
+ }
+ } // end of beholding check
+
if (you.running.check_stop_running())
{
move_x = 0;
@@ -3247,12 +3742,6 @@ static void move_player(int move_x, int move_y)
return;
}
- const int targ_x = you.x_pos + move_x;
- const int targ_y = you.y_pos + move_y;
- const dungeon_feature_type targ_grid = grd[ targ_x ][ targ_y ];
- const unsigned char targ_monst = mgrd[ targ_x ][ targ_y ];
- const bool targ_solid = grid_is_solid(targ_grid);
-
if (targ_monst != NON_MONSTER && !mons_is_submerged(&menv[targ_monst]))
{
struct monsters *mon = &menv[targ_monst];
@@ -3267,6 +3756,11 @@ static void move_player(int move_x, int move_y)
}
else // attack!
{
+ // XXX: Moving into a normal wall does nothing and uses no
+ // turns or energy, but moving into a wall which contains
+ // an invisible monster attacks the monster, thus allowing
+ // the player to figure out which adjacent wall an invis
+ // monster is in "for free".
you_attack( targ_monst, true );
you.turn_is_over = true;
@@ -3279,25 +3773,32 @@ static void move_player(int move_x, int move_y)
}
}
- if (!attacking && !targ_solid && moving)
+ if (!attacking && targ_pass && moving)
{
you.time_taken *= player_movement_speed();
you.time_taken /= 10;
if (!move_player_to_grid(targ_x, targ_y, true, false, swap))
return;
+ if (you.mutation[MUT_DRIFTING]
+ && (random2(100) <= you.mutation[MUT_DRIFTING] * 5) )
+ {
+ drift_player(move_x, move_y);
+ }
+
move_x = 0;
move_y = 0;
you.turn_is_over = true;
// item_check( false );
request_autopickup();
+
}
// BCR - Easy doors single move
- if (targ_grid == DNGN_CLOSED_DOOR && Options.easy_open)
+ if (targ_grid == DNGN_CLOSED_DOOR && Options.easy_open && !attacking)
open_door(move_x, move_y, false);
- else if (targ_solid)
+ else if (!targ_pass && !attacking)
{
stop_running();
@@ -3305,6 +3806,7 @@ static void move_player(int move_x, int move_y)
move_y = 0;
you.turn_is_over = 0;
+ crawl_state.cancel_cmd_repeat();
}
if (you.running == RMODE_START)
@@ -3344,3 +3846,326 @@ static void move_player(int move_x, int move_y)
apply_berserk_penalty = !attacking;
} // end move_player()
+
+
+static int get_num_and_char_keyfun(int &ch)
+{
+ if (ch == CK_BKSP || isdigit(ch) || ch >= 128)
+ return 1;
+
+ return -1;
+}
+
+static int get_num_and_char(const char* prompt, char* buf, int buf_len)
+{
+ if (prompt != NULL)
+ mpr(prompt);
+
+ line_reader reader(buf, buf_len);
+
+ reader.set_keyproc(get_num_and_char_keyfun);
+
+ return reader.read_line(true);
+}
+
+static void setup_cmd_repeat()
+{
+ if (is_processing_macro())
+ {
+ flush_input_buffer(FLUSH_ABORT_MACRO);
+ crawl_state.cancel_cmd_again();
+ crawl_state.cancel_cmd_repeat();
+ return;
+ }
+
+ ASSERT(!crawl_state.is_repeating_cmd());
+
+ char buf[80];
+
+ // Function ensures that the buffer contains only digits.
+ int ch = get_num_and_char("Number of times to repeat, then command key: ",
+ buf, 80);
+
+ if (ch == ESCAPE)
+ {
+ // This *might* be part of the trigger for a macro.
+ keyseq trigger;
+ trigger.push_back(ch);
+
+ if (get_macro_buf_size() == 0)
+ {
+ // Was just a single ESCAPE key, so not a macro trigger.
+ canned_msg( MSG_OK );
+ crawl_state.cancel_cmd_again();
+ crawl_state.cancel_cmd_repeat();
+ flush_input_buffer(FLUSH_REPLAY_SETUP_FAILURE);
+ return;
+ }
+ ch = getchm();
+ trigger.push_back(ch);
+
+ // Now that we have the entirety of the (possible) macro trigger,
+ // clear out the keypress recorder so that we won't have recorded
+ // the trigger twice.
+ repeat_again_rec.clear();
+
+ insert_macro_into_buff(trigger);
+
+ ch = getchm();
+ if (ch == ESCAPE)
+ {
+ if (get_macro_buf_size() > 0)
+ // User pressed an Alt key which isn't bound to a macro.
+ mpr("That key isn't bound to a macro.");
+ else
+ // Wasn't a macro trigger, just an ordinary escape.
+ canned_msg( MSG_OK );
+
+ crawl_state.cancel_cmd_again();
+ crawl_state.cancel_cmd_repeat();
+ flush_input_buffer(FLUSH_REPLAY_SETUP_FAILURE);
+ return;
+ }
+ // *WAS* a macro trigger, keep going.
+ }
+
+ if (strlen(buf) == 0)
+ {
+ mpr("You must enter the number of times for the command to repeat.");
+
+ crawl_state.cancel_cmd_again();
+ crawl_state.cancel_cmd_repeat();
+ flush_input_buffer(FLUSH_REPLAY_SETUP_FAILURE);
+
+ return;
+ }
+
+ int count = atoi(buf);
+
+ if (crawl_state.doing_prev_cmd_again)
+ count = crawl_state.prev_cmd_repeat_goal;
+
+ if (count <= 0)
+ {
+ canned_msg( MSG_OK );
+ crawl_state.cancel_cmd_again();
+ crawl_state.cancel_cmd_repeat();
+ flush_input_buffer(FLUSH_REPLAY_SETUP_FAILURE);
+ return;
+ }
+
+ if (crawl_state.doing_prev_cmd_again)
+ {
+ // If a "do previous command again" caused a command
+ // repetition to be redone, the keys to be repeated are
+ // already in the key rercording buffer, so we just need to
+ // discard all the keys saying how many times the command
+ // should be repeated.
+ do {
+ repeat_again_rec.keys.pop_front();
+ } while (repeat_again_rec.keys[0] != ch);
+
+ repeat_again_rec.keys.pop_front();
+ }
+
+ // User can type space or enter and then the command key, in case
+ // they want to repeat a command bound to a number key.
+ c_input_reset(true);
+ if (ch == ' ' || ch == CK_ENTER)
+ {
+ if (!crawl_state.doing_prev_cmd_again)
+ repeat_again_rec.keys.pop_back();
+
+ mpr("Enter command to be repeated: ");
+ // Enable the cursor to read input. The cursor stays on while
+ // the command is being processed, so subsidiary prompts
+ // shouldn't need to turn it on explicitly.
+ cursor_control con(true);
+
+ crawl_state.waiting_for_command = true;
+
+ ch = get_next_keycode();
+
+ crawl_state.waiting_for_command = false;
+ }
+
+ command_type cmd = keycode_to_command( (keycode_type) ch);
+
+ if (cmd != CMD_MOUSE_MOVE)
+ c_input_reset(false);
+
+ if (!is_processing_macro() && !cmd_is_repeatable(cmd))
+ {
+ crawl_state.cancel_cmd_again();
+ crawl_state.cancel_cmd_repeat();
+ flush_input_buffer(FLUSH_REPLAY_SETUP_FAILURE);
+ return;
+ }
+
+ if (!crawl_state.doing_prev_cmd_again && cmd != CMD_PREV_CMD_AGAIN)
+ crawl_state.prev_cmd_keys = repeat_again_rec.keys;
+
+ if (is_processing_macro())
+ {
+ // Put back in first key of the expanded macro, which
+ // get_next_keycode() fetched
+ repeat_again_rec.paused = true;
+ macro_buf_add(ch, true);
+
+ // If we're repeating a macro, get rid the keys saying how
+ // many times to repeat, because the way that macros are
+ // repeated means that the number keys will be repeated if
+ // they aren't discarded.
+ keyseq &keys = repeat_again_rec.keys;
+ ch = keys[keys.size() - 1];
+ while (isdigit(ch) || ch == ' ' || ch == CK_ENTER)
+ {
+ keys.pop_back();
+ ASSERT(keys.size() > 0);
+ ch = keys[keys.size() - 1];
+ }
+ }
+
+ repeat_again_rec.paused = false;
+ // Discard the setup for the command repetition, since what's
+ // going to be repeated is yet to be typed, except for the fist
+ // key typed which has to be put back in (unless we're repeating a
+ // macro, in which case everything to be repeated is already in
+ // the macro buffer).
+ if (!is_processing_macro())
+ {
+ repeat_again_rec.clear();
+ macro_buf_add(ch, crawl_state.doing_prev_cmd_again);
+ }
+
+ crawl_state.cmd_repeat_start = true;
+ crawl_state.cmd_repeat_count = 0;
+ crawl_state.repeat_cmd = cmd;
+ crawl_state.cmd_repeat_goal = count;
+ crawl_state.prev_cmd_repeat_goal = count;
+ crawl_state.prev_repetition_turn = you.num_turns;
+
+ crawl_state.cmd_repeat_started_unsafe = !i_feel_safe();
+
+ crawl_state.input_line_strs.clear();
+}
+
+static void do_prev_cmd_again()
+{
+ if (is_processing_macro())
+ {
+ mpr("Can't re-do previous command from within a macro.");
+ flush_input_buffer(FLUSH_ABORT_MACRO);
+ crawl_state.cancel_cmd_again();
+ crawl_state.cancel_cmd_repeat();
+ return;
+ }
+
+ if (crawl_state.prev_cmd == CMD_NO_CMD)
+ {
+ mpr("No previous command to re-do.");
+ crawl_state.cancel_cmd_again();
+ crawl_state.cancel_cmd_repeat();
+ return;
+ }
+
+ ASSERT(!crawl_state.doing_prev_cmd_again
+ || (crawl_state.is_repeating_cmd()
+ && crawl_state.repeat_cmd == CMD_PREV_CMD_AGAIN));
+
+ crawl_state.doing_prev_cmd_again = true;
+ repeat_again_rec.paused = false;
+
+ if (crawl_state.prev_cmd == CMD_REPEAT_CMD)
+ {
+ crawl_state.cmd_repeat_start = true;
+ crawl_state.cmd_repeat_count = 0;
+ crawl_state.cmd_repeat_goal = crawl_state.prev_cmd_repeat_goal;
+ crawl_state.prev_repetition_turn = you.num_turns;
+ }
+
+ const keyseq &keys = crawl_state.prev_cmd_keys;
+ ASSERT(keys.size() > 0);
+
+ // Insert keys at front of input buffer, rather than at the end,
+ // since if the player holds down the "`" key, then the buffer
+ // might get two "`" in a row, and if the keys to be replayed go after
+ // the second "`" then we get an assertion.
+ macro_buf_add(keys, true);
+
+ bool was_doing_repeats = crawl_state.is_repeating_cmd();
+
+ input();
+
+ // crawl_state.doing_prev_cmd_again can be set to false
+ // while input() does its stuff if something causes
+ // crawl_state.cancel_cmd_again() to be called.
+ while (!was_doing_repeats && crawl_state.is_repeating_cmd()
+ && crawl_state.doing_prev_cmd_again)
+ {
+ input();
+ }
+
+ if (!was_doing_repeats && crawl_state.is_repeating_cmd()
+ && !crawl_state.doing_prev_cmd_again)
+ {
+ crawl_state.cancel_cmd_repeat();
+ }
+
+ crawl_state.doing_prev_cmd_again = false;
+}
+
+static void update_replay_state()
+{
+ if (crawl_state.is_repeating_cmd())
+ {
+ // First repeat is to copy down the keys the user enters,
+ // grab them so we can go on autopilot for the remaining
+ // iterations.
+ if (crawl_state.cmd_repeat_start)
+ {
+ ASSERT(repeat_again_rec.keys.size() > 0);
+
+ crawl_state.cmd_repeat_start = false;
+ crawl_state.repeat_cmd_keys = repeat_again_rec.keys;
+
+ // Setting up the "previous command key sequence"
+ // for a repeated command is different than normal,
+ // since in addition to all of the keystrokes for
+ // the command, it needs the repeat command plus the
+ // number of repeats at the very beginning of the
+ // sequence.
+ if (!crawl_state.doing_prev_cmd_again)
+ {
+ keyseq &prev = crawl_state.prev_cmd_keys;
+ keyseq &curr = repeat_again_rec.keys;
+
+ if (is_processing_macro())
+ prev = curr;
+ else
+ {
+ // Skip first key, because that's command key that's
+ // being repeated, which crawl_state.prev_cmd_keys
+ // aleardy contains.
+ keyseq::iterator begin = curr.begin();
+ begin++;
+
+ prev.insert(prev.end(), begin, curr.end());
+ }
+ }
+
+ repeat_again_rec.paused = true;
+ macro_buf_add(KEY_REPEAT_KEYS);
+ }
+ }
+
+ if (!crawl_state.is_replaying_keys() && !crawl_state.cmd_repeat_start
+ && crawl_state.prev_cmd != CMD_NO_CMD)
+ {
+ if (repeat_again_rec.keys.size() > 0)
+ crawl_state.prev_cmd_keys = repeat_again_rec.keys;
+ }
+
+ if (!is_processing_macro())
+ repeat_again_rec.clear();
+}
diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc
index ef1ac0a1df..e5f1e4a706 100644
--- a/crawl-ref/source/beam.cc
+++ b/crawl-ref/source/beam.cc
@@ -60,6 +60,7 @@
#include "terrain.h"
#include "traps.h"
#include "view.h"
+#include "xom.h"
#define BEAM_STOP 1000 // all beams stopped by subtracting this
// from remaining range
@@ -791,7 +792,7 @@ static void zappy( zap_type z_type, int power, bolt &pbolt )
break;
case ZAP_NEGATIVE_ENERGY: // cap 150
- pbolt.name = "bolt of negative energy";
+ pbolt.name = pbolt.effect_known ? "bolt of negative energy" : "bolt";
pbolt.colour = DARKGREY;
pbolt.range = 7 + random2(10);
pbolt.damage = calc_dice( 4, 15 + (power * 3) / 5 );
@@ -1239,6 +1240,32 @@ static void zappy( zap_type z_type, int power, bolt &pbolt )
*/
+// Affect monster in wall unless it can shield itself using the wall
+// (M_WALL_SHIELDED). The wall will always shield the monster if the
+// beam bounces off the wall, and a monster can't use a metal wall to
+// shield itself from electricty.
+static bool affect_mon_in_wall(bolt &pbolt, item_def *item, int tx, int ty)
+{
+ UNUSED(item);
+
+ int mid = mgrd[tx][ty];
+
+ if (mid == NON_MONSTER)
+ return false;
+
+ if (pbolt.is_enchant
+ || (!pbolt.is_explosion && !pbolt.is_big_cloud
+ && (grd[tx][ty] != DNGN_METAL_WALL
+ || !pbolt.flavour != BEAM_ELECTRICITY)))
+ {
+ monsters *mons = &menv[mid];
+ if (!mons_class_flag(mons->type, M_WALL_SHIELDED))
+ return true;
+ }
+
+ return false;
+}
+
/*
* Beam pseudo code:
*
@@ -1357,9 +1384,13 @@ void fire_beam( bolt &pbolt, item_def *item )
}
else
{
- // BEGIN bounce case
+ // BEGIN bounce case. Bouncing protects any monster
+ // in the wall.
if (!isBouncy(pbolt, grd[tx][ty]))
{
+ // Affect any monster that might be in the wall.
+ rangeRemaining -= affect(pbolt, tx, ty);
+
do
ray.regress();
while (grid_is_solid(grd(ray.pos())));
@@ -1507,6 +1538,14 @@ void fire_beam( bolt &pbolt, item_def *item )
canned_msg(MSG_NOTHING_HAPPENS);
}
+ if (!pbolt.is_tracer && pbolt.beam_source != NON_MONSTER)
+ {
+ if (pbolt.foe_hurt == 0 && pbolt.fr_hurt > 0)
+ xom_is_stimulated(128);
+ else if (pbolt.foe_helped > 0 && pbolt.fr_helped == 0)
+ xom_is_stimulated(128);
+ }
+
// that's it!
#ifdef WIN32CONSOLE
if (!pbolt.is_tracer)
@@ -1662,11 +1701,7 @@ int mons_adjust_flavoured( monsters *monster, bolt &pbolt,
pbolt.obvious_effect = true;
if (YOU_KILL(pbolt.thrower))
- {
- // currently no gods who enjoy use of necromancy
- if (pbolt.effect_known)
- did_god_conduct(DID_NECROMANCY, 2 + random2(3));
- }
+ did_god_conduct(DID_NECROMANCY, 2 + random2(3), pbolt.effect_known);
if (one_chance_in(5))
{
@@ -2187,6 +2222,8 @@ void fire_tracer(const monsters *monster, bolt &pbolt)
// init tracer variables
pbolt.foe_count = pbolt.fr_count = 0;
pbolt.foe_power = pbolt.fr_power = 0;
+ pbolt.fr_helped = pbolt.fr_hurt = 0;
+ pbolt.foe_helped = pbolt.foe_hurt = 0;
pbolt.foe_ratio = 80; // default - see mons_should_fire()
// foe ratio for summon gtr. demons & undead -- they may be
@@ -2400,6 +2437,8 @@ void beam_drop_object( bolt &beam, item_def *item, int x, int y )
// Too much message spam otherwise
if ( YOU_KILL(beam.thrower) && player_can_hear(x, y) )
mprf(MSGCH_SOUND, grid_item_destruction_message(grd[x][y]));
+
+ item_was_destroyed(*item, beam.beam_source);
return;
}
@@ -2482,10 +2521,28 @@ int affect(bolt &beam, int x, int y)
{
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 it's still a wall, quit - we can't do anything else to a
+ // wall (but we still might be able to do something to any
+ // monster inside the wall). Otherwise effects (like clouds,
+ // etc) are still possible.
if (grid_is_solid(grd[x][y]))
+ {
+ int mid = mgrd[x][y];
+ if (mid != NON_MONSTER)
+ {
+ monsters *mon = &menv[mid];
+ if (affect_mon_in_wall(beam, NULL, x, y))
+ rangeUsed += affect_monster( beam, mon );
+ else if (you.can_see(mon))
+ {
+ mprf("The %s protects %s from harm.",
+ raw_feature_description(grd(mon->pos())).c_str(),
+ mon->name(DESC_NOCAP_THE).c_str());
+ }
+ }
+
return (rangeUsed);
+ }
}
// grd[x][y] will NOT be a wall for the remainder of this function.
@@ -2588,13 +2645,14 @@ static int affect_wall(bolt &beam, int x, int y)
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))
+ || grd[x][y] == DNGN_CLEAR_STONE_WALL
+ || grd[x][y] == DNGN_CLEAR_PERMAROCK_WALL
+ || !in_bounds(x, y))
{
return (0);
}
- if (grd[x][y] == DNGN_ROCK_WALL)
+ if (grd[x][y] == DNGN_ROCK_WALL || grd[x][y] == DNGN_CLEAR_ROCK_WALL)
{
grd[x][y] = DNGN_FLOOR;
@@ -2653,8 +2711,9 @@ static int affect_wall(bolt &beam, int x, int y)
{
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)))
+ if ((targ_grid == DNGN_ROCK_WALL || targ_grid == DNGN_WAX_WALL
+ || targ_grid == DNGN_CLEAR_ROCK_WALL)
+ && in_bounds(x, y))
{
grd[ x ][ y ] = DNGN_FLOOR;
if (!silenced(you.x_pos, you.y_pos))
@@ -2683,7 +2742,8 @@ static int affect_wall(bolt &beam, int x, int y)
mpr("The statue twists and shakes as its substance crumbles away!");
}
- if (targ_grid == DNGN_ORCISH_IDOL)
+ if (targ_grid == DNGN_ORCISH_IDOL
+ && beam.beam_source == NON_MONSTER)
{
beogh_idol_revenge();
}
@@ -2918,6 +2978,8 @@ static void affect_items(bolt &beam, int x, int y)
if (objs_vulnerable != -1 &&
mitm[igrd[x][y]].base_type == objs_vulnerable)
{
+ item_was_destroyed(mitm[igrd[x][y]], beam.beam_source);
+
destroy_item( igrd[ x ][ y ] );
if (objs_vulnerable == OBJ_SCROLLS && see_grid(x,y))
@@ -3109,14 +3171,14 @@ static int affect_player( bolt &beam )
#endif
if (hit < block)
{
- you.shield_blocks++;
mprf( "You block the %s.", beam.name.c_str() );
- exercise( SK_SHIELDS, exer + 1 );
+ you.shield_block_succeeded();
return (BEAM_STOP);
}
// some training just for the "attempt"
- exercise( SK_SHIELDS, exer );
+ if (coinflip())
+ exercise( SK_SHIELDS, exer );
}
if (player_light_armour(true) && !beam.aimed_at_feet
@@ -3141,6 +3203,8 @@ static int affect_player( bolt &beam )
}
else
{
+ bool nasty = true, nice = false;
+
// BEGIN enchantment beam
if (beam.flavour != BEAM_HASTE
&& beam.flavour != BEAM_INVISIBILITY
@@ -3151,6 +3215,12 @@ static int affect_player( bolt &beam )
&& you_resist_magic( beam.ench_power ))
{
canned_msg(MSG_YOU_RESIST);
+
+ // You *could* have gotten a free teleportation in the Abyss,
+ // but no, you resisted.
+ if (beam.flavour != BEAM_TELEPORT && you.level_type == LEVEL_ABYSS)
+ xom_is_stimulated(255);
+
return (range_used_on_hit(beam));
}
@@ -3159,6 +3229,10 @@ static int affect_player( bolt &beam )
// these colors are misapplied - see mons_ench_f2() {dlb}
switch (beam.flavour)
{
+ case BEAM_SLEEP:
+ you.put_to_sleep(beam.ench_power);
+ break;
+
case BEAM_BACKLIGHT:
if (!you.duration[DUR_INVIS])
{
@@ -3189,7 +3263,8 @@ static int affect_player( bolt &beam )
you.mutate();
beam.obvious_effect = true;
}
- else if (get_ident_type(OBJ_WANDS, WAND_POLYMORPH_OTHER) == ID_KNOWN_TYPE)
+ else if (get_ident_type(OBJ_WANDS, WAND_POLYMORPH_OTHER)
+ == ID_KNOWN_TYPE)
{
mpr("This is polymorph other only!");
}
@@ -3208,11 +3283,15 @@ static int affect_player( bolt &beam )
potion_effect( POT_SPEED, beam.ench_power );
contaminate_player( 1 );
beam.obvious_effect = true;
+ nasty = false;
+ nice = true;
break; // haste
case BEAM_HEALING:
potion_effect( POT_HEAL_WOUNDS, beam.ench_power );
beam.obvious_effect = true;
+ nasty = false;
+ nice = true;
break; // heal (heal wounds potion eff)
case BEAM_PARALYSIS:
@@ -3229,12 +3308,20 @@ static int affect_player( bolt &beam )
potion_effect( POT_INVISIBILITY, beam.ench_power );
contaminate_player( 1 + random2(2) );
beam.obvious_effect = true;
+ nasty = false;
+ nice = true;
break; // invisibility
// 6 is used by digging
case BEAM_TELEPORT:
you_teleport();
+
+ // An enemy helping you escape while in the Abyss, or an
+ // enemy stabilizing a teleport that was about to happen.
+ if (beam.attitude == ATT_HOSTILE && you.level_type == LEVEL_ABYSS)
+ xom_is_stimulated(255);
+
beam.obvious_effect = true;
break;
@@ -3307,6 +3394,33 @@ static int affect_player( bolt &beam )
break;
} // end of switch (beam.colour)
+ if (nasty)
+ {
+ if (beam.attitude != ATT_HOSTILE)
+ {
+ beam.fr_hurt++;
+ if (beam.beam_source == NON_MONSTER)
+ // Beam from player rebounded and hit player
+ xom_is_stimulated(255);
+ else
+ // Beam from an ally
+ xom_is_stimulated(128);
+ }
+ else
+ beam.foe_hurt++;
+ }
+
+ if (nice)
+ {
+ if (beam.attitude != ATT_HOSTILE)
+ beam.fr_helped++;
+ else
+ {
+ beam.foe_helped++;
+ xom_is_stimulated(128);
+ }
+ }
+
// 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));
@@ -3356,6 +3470,9 @@ static int affect_player( bolt &beam )
}
}
+ bool was_affected = false;
+ int old_hp = you.hp;
+
if (hurted < 0)
hurted = 0;
@@ -3364,10 +3481,16 @@ static int affect_player( bolt &beam )
if (beam.flavour == BEAM_MIASMA && hurted > 0)
{
if (player_res_poison() <= 0)
+ {
poison_player(1);
+ was_affected = true;
+ }
if (one_chance_in( 3 + 2 * player_prot_life() ))
+ {
potion_effect( POT_SLOWING, 5 );
+ was_affected = true;
+ }
}
// poisoning
@@ -3380,17 +3503,22 @@ static int affect_player( bolt &beam )
&& random2(100) < 90 - (3 * player_AC())))
{
poison_player( 1 + random2(3) );
+ was_affected = true;
}
}
if (beam.name.find("throwing net") != std::string::npos)
+ {
player_caught_in_net();
+ was_affected = true;
+ }
if (beam.name.find("curare") != std::string::npos)
{
if (random2(100) < 90 - (3 * player_AC()))
{
curare_hits_player( beam_ouch_agent(beam), 1 + random2(3) );
+ was_affected = true;
}
}
@@ -3400,7 +3528,10 @@ static int affect_player( bolt &beam )
|| you.experience_level < 6))
{
if (!player_equip( EQ_BODY_ARMOUR, ARM_MOTTLED_DRAGON_ARMOUR ))
+ {
you.duration[DUR_LIQUID_FLAMES] += random2avg(7, 3) + 1;
+ was_affected = true;
+ }
}
// simple cases for scroll burns
@@ -3426,6 +3557,24 @@ static int affect_player( bolt &beam )
mprf(MSGCH_DIAGNOSTICS, "Damage: %d", hurted );
#endif
+ if (hurted > 0 || old_hp < you.hp || was_affected)
+ {
+ if (beam.attitude != ATT_HOSTILE)
+ {
+ beam.fr_hurt++;
+
+ // Beam from player rebounded and hit player
+ if (beam.beam_source == NON_MONSTER)
+ xom_is_stimulated(255);
+ // Xom's amusement at the player being damaged is handled
+ // elsewhere.
+ else if (was_affected)
+ xom_is_stimulated(128);
+ }
+ else
+ beam.foe_hurt++;
+ }
+
beam_ouch( hurted, beam );
return (range_used_on_hit( beam ));
@@ -3459,6 +3608,31 @@ static int name_to_skill_level(const std::string& name)
return (2 * you.skills[type]);
}
+static void update_hurt_or_helped(bolt &beam, monsters *mon)
+{
+ if (beam.attitude != mons_attitude(mon))
+ {
+ if (nasty_beam(mon, beam))
+ beam.foe_hurt++;
+ else if (nice_beam(mon, beam))
+ beam.foe_helped++;
+ }
+ else
+ {
+ if (nasty_beam(mon, beam))
+ {
+ beam.fr_hurt++;
+
+ // Harmful beam from this monster rebounded and hit the monster
+ int midx = (int) monster_index(mon);
+ if (midx == beam.beam_source)
+ xom_is_stimulated(128);
+ }
+ else if (nice_beam(mon, beam))
+ beam.fr_helped++;
+ }
+}
+
// return amount of range used up by affectation of this monster
static int affect_monster(bolt &beam, monsters *mon)
{
@@ -3510,6 +3684,7 @@ static int affect_monster(bolt &beam, monsters *mon)
"crumbles away!");
}
beam.obvious_effect = true;
+ update_hurt_or_helped(beam, mon);
mon->hit_points = 0;
monster_die(mon, beam);
return (BEAM_STOP);
@@ -3548,10 +3723,10 @@ static int affect_monster(bolt &beam, monsters *mon)
if (YOU_KILL( beam.thrower ))
{
if (mons_friendly( mon ))
- did_god_conduct( DID_ATTACK_FRIEND, 5, mon );
+ did_god_conduct( DID_ATTACK_FRIEND, 5, true, mon );
if (mons_holiness( mon ) == MH_HOLY)
- did_god_conduct( DID_ATTACK_HOLY, mon->hit_dice, mon );
+ did_god_conduct( DID_ATTACK_HOLY, mon->hit_dice, true, mon );
if (you.religion == GOD_BEOGH && mons_species(mon->type) == MONS_ORC
&& mon->behaviour == BEH_SLEEP && you.species == SP_HILL_ORC
@@ -3593,6 +3768,7 @@ static int affect_monster(bolt &beam, monsters *mon)
beam.msg_generated = true;
break;
default:
+ update_hurt_or_helped(beam, mon);
break;
}
}
@@ -3702,11 +3878,14 @@ static int affect_monster(bolt &beam, monsters *mon)
{
if (YOU_KILL(beam.thrower) && hurt_final > 0)
{
+ const bool okay = beam.aux_source == "reading a scroll of immolation"
+ && !beam.effect_known;
+
if (mons_friendly(mon))
- did_god_conduct( DID_ATTACK_FRIEND, 5, mon );
+ did_god_conduct( DID_ATTACK_FRIEND, 5, !okay, mon );
if (mons_holiness( mon ) == MH_HOLY)
- did_god_conduct( DID_ATTACK_HOLY, mon->hit_dice, mon );
+ did_god_conduct( DID_ATTACK_HOLY, mon->hit_dice, !okay, mon );
}
if (you.religion == GOD_BEOGH && mons_species(mon->type) == MONS_ORC
@@ -3744,6 +3923,28 @@ static int affect_monster(bolt &beam, monsters *mon)
return (0);
}
+ // The monster may block the beam.
+ if (!engulfs && beam_is_blockable(beam))
+ {
+ const int shield_block = mon->shield_bonus();
+ if (shield_block > 0)
+ {
+ const int hit = random2( beam.hit * 130 / 100
+ + mon->shield_block_penalty() );
+ if (hit < shield_block && mons_near(mon)
+ && player_monster_visible(mon))
+ {
+ mprf("%s blocks the %s.",
+ mon->name(DESC_CAP_THE).c_str(),
+ beam.name.c_str());
+ mon->shield_block_succeeded();
+ return (BEAM_STOP);
+ }
+ }
+ }
+
+ update_hurt_or_helped(beam, mon);
+
// the beam hit.
if (mons_near(mon))
{
@@ -4073,9 +4274,7 @@ static int affect_monster_enchantment(bolt &beam, monsters *mon)
if (simple_monster_message(mon, " looks drowsy..."))
beam.obvious_effect = true;
- mon->behaviour = BEH_SLEEP;
- mon->add_ench(ENCH_SLEEPY);
- mon->add_ench(ENCH_SLEEP_WARY);
+ mon->put_to_sleep();
return (MON_AFFECTED);
}
@@ -4570,7 +4769,7 @@ static void explosion_map( bolt &beam, int x, int 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 (dngn_feat <= DNGN_MAXWALL)
{
if (!(x==0 && y==0) && !affects_wall(beam, dngn_feat))
return;
@@ -4639,6 +4838,18 @@ bool nasty_beam(monsters *mon, bolt &beam)
return (true);
}
+bool nice_beam( struct monsters *mon, struct bolt &beam )
+{
+ // haste
+ if (beam.flavour == BEAM_HASTE || beam.flavour == BEAM_HEALING
+ || beam.flavour == BEAM_INVISIBILITY)
+ {
+ return (true);
+ }
+
+ return (false);
+}
+
////////////////////////////////////////////////////////////////////////////
// bolt
@@ -4657,7 +4868,8 @@ bolt::bolt() : range(0), rangeMax(0), type(SYM_ZAP), colour(BLACK),
is_thrown(false), target_first(false), aimed_at_spot(false),
aux_source(), affects_nothing(false), obvious_effect(false),
effect_known(true), fr_count(0), foe_count(0), fr_power(0),
- foe_power(0), is_tracer(false), aimed_at_feet(false),
+ foe_power(0), fr_hurt(0), foe_hurt(0), fr_helped(0),
+ foe_helped(0), is_tracer(false), aimed_at_feet(false),
msg_generated(false), in_explosion_phase(false),
smart_monster(false), can_see_invis(false),
attitude(ATT_HOSTILE), foe_ratio(0), chose_ray(false)
diff --git a/crawl-ref/source/beam.h b/crawl-ref/source/beam.h
index 6f598fb57d..028018a47f 100644
--- a/crawl-ref/source/beam.h
+++ b/crawl-ref/source/beam.h
@@ -47,6 +47,7 @@ enum zap_symbol_type
SYM_EXPLOSION = '#'
};
+// must match wand subtypes! (see item_def::zap())
enum zap_type
{
ZAP_FLAME, // 0
@@ -153,6 +154,8 @@ struct bolt
bool effect_known; // did we _know_ this would happen?
int fr_count, foe_count; // # of times a friend/foe is "hit"
int fr_power, foe_power; // total levels/hit dice affected
+ int fr_hurt, foe_hurt; // # of friends/foes actually hurt
+ int fr_helped, foe_helped; // # of friends/foes actually helped
// INTERNAL use - should not usually be set outside of beam.cc
bool is_tracer; // is this a tracer?
@@ -199,7 +202,7 @@ void fire_beam( struct bolt &pbolt, item_def *item = NULL );
* called from: beam
* *********************************************************************** */
bool nasty_beam( struct monsters *mon, struct bolt &beam );
-
+bool nice_beam( struct monsters *mon, struct bolt &beam );
// last updated 12may2000 {dlb}
/* ***********************************************************************
diff --git a/crawl-ref/source/branch.cc b/crawl-ref/source/branch.cc
index 3f81d87d32..0739562861 100644
--- a/crawl-ref/source/branch.cc
+++ b/crawl-ref/source/branch.cc
@@ -1,15 +1,19 @@
/*
- * Modified for Crawl Reference by $Author: haranp $ on $Date: 2006-12-10 22:28:21 +0200 (Sun, 10 Dec 2006) $
+ * Modified for Crawl Reference by $Author$ on $Date$
*/
#include "AppHdr.h"
#include "branch.h"
+#include "cloud.h"
#include "externs.h"
#include "mon-pick.h"
+#include "player.h"
+#include "spells3.h"
+#include "traps.h"
Branch& your_branch()
{
- return branches[static_cast<int>(you.where_are_you)];
+ return branches[you.where_are_you];
}
branch_type str_to_branch(const std::string &branch, branch_type err)
@@ -22,190 +26,294 @@ branch_type str_to_branch(const std::string &branch, branch_type err)
return (err);
}
+bool set_branch_flags(unsigned long flags, bool silent,
+ branch_type branch)
+{
+ if (branch == NUM_BRANCHES)
+ branch = you.where_are_you;
+
+ bool could_control = allow_control_teleport(true);
+ bool could_map = player_in_mappable_area();
+
+ unsigned long old_flags = branches[branch].branch_flags;
+ branches[branch].branch_flags |= flags;
+
+ bool can_control = allow_control_teleport(true);
+ bool can_map = player_in_mappable_area();
+
+ if (you.level_type == LEVEL_DUNGEON && branch == you.where_are_you
+ && you.skills[SK_TRANSLOCATIONS] > 0
+ && could_control && !can_control && !silent)
+ {
+ mpr("You sense the appearence of a powerful magical force "
+ "which warps space.", MSGCH_WARN);
+ }
+
+ if (you.level_type == LEVEL_DUNGEON && branch == you.where_are_you
+ && could_map && !can_map && !silent)
+ {
+ mpr("A powerful force appears that prevents you from "
+ "remembering where you've been.", MSGCH_WARN);
+ }
+
+ return (old_flags != branches[branch].branch_flags);
+}
+
+bool unset_branch_flags(unsigned long flags, bool silent,
+ branch_type branch)
+{
+ if (branch == NUM_BRANCHES)
+ branch = you.where_are_you;
+
+ const bool could_control = allow_control_teleport(true);
+ const bool could_map = player_in_mappable_area();
+
+ unsigned long old_flags = branches[branch].branch_flags;
+ branches[branch].branch_flags &= ~flags;
+
+ const bool can_control = allow_control_teleport(true);
+ const bool can_map = player_in_mappable_area();
+
+ if (you.level_type == LEVEL_DUNGEON && branch == you.where_are_you
+ && you.skills[SK_TRANSLOCATIONS] > 0
+ && !could_control && can_control && !silent)
+ {
+ // Isn't really a "recovery", but I couldn't think of where
+ // else to send it.
+ mpr("Space seems to straighten in your vicinity.", MSGCH_RECOVERY);
+ }
+
+ if (you.level_type == LEVEL_DUNGEON && branch == you.where_are_you
+ && !could_map && can_map && !silent)
+ {
+ // Isn't really a "recovery", but I couldn't think of where
+ // else to send it.
+ mpr("An oppressive force seems to lift.", MSGCH_RECOVERY);
+ }
+
+ return (old_flags != branches[branch].branch_flags);
+}
+
+unsigned long get_branch_flags(branch_type branch)
+{
+ if (branch == NUM_BRANCHES)
+ {
+ if (you.level_type != LEVEL_DUNGEON)
+ return (0);
+
+ branch = you.where_are_you;
+ }
+
+ return branches[branch].branch_flags;
+}
+
Branch branches[] = {
- { BRANCH_MAIN_DUNGEON, BRANCH_MAIN_DUNGEON, 27, -1,
+ { BRANCH_MAIN_DUNGEON, BRANCH_MAIN_DUNGEON, 27, -1, 0, 0,
NUM_FEATURES, NUM_FEATURES, // sentinel values
"Dungeon", "the Dungeon", "D",
NULL,
true, true, LIGHTGREY, BROWN,
mons_standard_rare, mons_standard_level,
- 8, 'D', false },
+ NULL, NULL, NULL, NULL,
+ 8, 'D', false, false },
- { BRANCH_ECUMENICAL_TEMPLE, BRANCH_MAIN_DUNGEON, 1, 5,
+ { BRANCH_ECUMENICAL_TEMPLE, BRANCH_MAIN_DUNGEON, 1, 5, 0, 0,
DNGN_ENTER_TEMPLE, DNGN_RETURN_FROM_TEMPLE,
"Temple", "the Ecumenical Temple", "Temple",
NULL,
false, false, LIGHTGREY, LIGHTGREY,
mons_standard_rare, mons_standard_level,
- 0, 'T', false },
+ traps_zero_number, NULL, NULL, NULL, // No traps in temple
+ 0, 'T', false, false },
- { BRANCH_ORCISH_MINES, BRANCH_MAIN_DUNGEON, 4, 6,
+ { BRANCH_ORCISH_MINES, BRANCH_MAIN_DUNGEON, 4, 6, 0, 0,
DNGN_ENTER_ORCISH_MINES, DNGN_RETURN_FROM_ORCISH_MINES,
"Orcish Mines", "the Orcish Mines", "Orc",
NULL,
true, false, BROWN, BROWN,
mons_mineorc_rare, mons_mineorc_level,
- 20, 'O', false },
+ NULL, NULL, NULL, NULL,
+ 20, 'O', false, false },
- { BRANCH_ELVEN_HALLS, BRANCH_ORCISH_MINES, 7, 4,
+ { BRANCH_ELVEN_HALLS, BRANCH_ORCISH_MINES, 7, 4, 0, 0,
DNGN_ENTER_ELVEN_HALLS, DNGN_RETURN_FROM_ELVEN_HALLS,
"Elven Halls", "the Elven Halls", "Elf",
NULL,
true, true, DARKGREY, LIGHTGREY,
mons_hallelf_rare, mons_hallelf_level,
- 8, 'E', false },
+ NULL, NULL, NULL, NULL,
+ 8, 'E', false, true },
- { BRANCH_LAIR, BRANCH_MAIN_DUNGEON, 10, 8,
+ { BRANCH_LAIR, BRANCH_MAIN_DUNGEON, 10, 8, 0, 0,
DNGN_ENTER_LAIR, DNGN_RETURN_FROM_LAIR,
"Lair", "the Lair of Beasts", "Lair",
NULL,
true, false, GREEN, BROWN,
mons_lair_rare, mons_lair_level,
- 5, 'L', false },
+ NULL, NULL, NULL, NULL,
+ 5, 'L', false, false },
- { BRANCH_SWAMP, BRANCH_LAIR, 5, 3,
+ { BRANCH_SWAMP, BRANCH_LAIR, 5, 3, 0, 0,
DNGN_ENTER_SWAMP, DNGN_RETURN_FROM_SWAMP,
"Swamp", "the Swamp", "Swamp",
NULL,
true, true, BROWN, BROWN,
mons_swamp_rare, mons_swamp_level,
- 0, 'S', false },
+ NULL, NULL, NULL, NULL,
+ 0, 'S', false, true },
- { BRANCH_SHOALS, BRANCH_LAIR, 5, 4,
+ { BRANCH_SHOALS, BRANCH_LAIR, 5, 4, 0, 0,
DNGN_ENTER_SHOALS, DNGN_RETURN_FROM_SHOALS,
"Shoals", "the Shoals", "Shoal",
NULL,
true, true, BROWN, BROWN,
mons_shoals_rare, mons_shoals_level,
- 0, 'A', false },
+ NULL, NULL, NULL, NULL,
+ 0, 'A', false, true },
- { BRANCH_SLIME_PITS, BRANCH_LAIR, 6, 4,
+ { BRANCH_SLIME_PITS, BRANCH_LAIR, 6, 4, 0, 0,
DNGN_ENTER_SLIME_PITS, DNGN_RETURN_FROM_SLIME_PITS,
"Slime Pits", "the Pits of Slime", "Slime",
NULL,
false, false, GREEN, LIGHTGREEN,
mons_pitslime_rare, mons_pitslime_level,
- 5, 'M', false },
+ NULL, NULL, NULL, NULL,
+ 5, 'M', false, true },
- { BRANCH_SNAKE_PIT, BRANCH_LAIR, 5, 7,
+ { BRANCH_SNAKE_PIT, BRANCH_LAIR, 5, 7, 0, 0,
DNGN_ENTER_SNAKE_PIT, DNGN_RETURN_FROM_SNAKE_PIT,
"Snake Pit", "the Snake Pit", "Snake",
NULL,
true, true, LIGHTGREEN, YELLOW,
mons_pitsnake_rare, mons_pitsnake_level,
- 10, 'P', false },
+ NULL, NULL, NULL, NULL,
+ 10, 'P', false, true },
- { BRANCH_HIVE, BRANCH_MAIN_DUNGEON, 4, 15,
+ { BRANCH_HIVE, BRANCH_MAIN_DUNGEON, 4, 15, 0, 0,
DNGN_ENTER_HIVE, DNGN_RETURN_FROM_HIVE,
"Hive", "the Hive", "Hive",
"You hear a buzzing sound coming from all directions.",
false, false, YELLOW, BROWN,
mons_hive_rare, mons_hive_level,
- 0, 'H', false },
+ NULL, NULL, NULL, NULL,
+ 0, 'H', false, true },
- { BRANCH_VAULTS, BRANCH_MAIN_DUNGEON, 8, 17,
+ { BRANCH_VAULTS, BRANCH_MAIN_DUNGEON, 8, 17, 0, 0,
DNGN_ENTER_VAULTS, DNGN_RETURN_FROM_VAULTS,
"Vaults", "the Vaults", "Vault",
NULL,
true, true, LIGHTGREY, BROWN,
mons_standard_rare, mons_standard_level,
- 5, 'V', false },
+ NULL, NULL, NULL, NULL,
+ 5, 'V', false, true },
- { BRANCH_HALL_OF_BLADES, BRANCH_VAULTS, 1, 4,
+ { BRANCH_HALL_OF_BLADES, BRANCH_VAULTS, 1, 4, 0, 0,
DNGN_ENTER_HALL_OF_BLADES, DNGN_RETURN_FROM_HALL_OF_BLADES,
"Hall of Blades", "the Hall of Blades", "Blade",
NULL,
false, true, LIGHTGREY, LIGHTGREY,
mons_hallblade_rare, mons_hallblade_level,
- 0, 'B', false },
+ NULL, NULL, NULL, NULL,
+ 0, 'B', false, false },
- { BRANCH_CRYPT, BRANCH_VAULTS, 5, 3,
+ { BRANCH_CRYPT, BRANCH_VAULTS, 5, 3, 0, 0,
DNGN_ENTER_CRYPT, DNGN_RETURN_FROM_CRYPT,
"Crypt", "the Crypt", "Crypt",
NULL,
false, true, LIGHTGREY, LIGHTGREY,
mons_crypt_rare, mons_crypt_level,
- 5, 'C', false },
+ NULL, NULL, NULL, NULL,
+ 5, 'C', false, false },
- { BRANCH_TOMB, BRANCH_CRYPT, 3, 5,
+ { BRANCH_TOMB, BRANCH_CRYPT, 3, 5, 0, 0,
DNGN_ENTER_TOMB, DNGN_RETURN_FROM_TOMB,
"Tomb", "the Tomb of the Ancients", "Tomb",
NULL,
false, true, YELLOW, LIGHTGREY,
mons_tomb_rare, mons_tomb_level,
- 0, 'G', false },
+ NULL, NULL, NULL, NULL,
+ 0, 'G', false, true },
- { BRANCH_VESTIBULE_OF_HELL, BRANCH_MAIN_DUNGEON, 1, -1,
+ { BRANCH_VESTIBULE_OF_HELL, BRANCH_MAIN_DUNGEON, 1, -1, 0, 0,
DNGN_ENTER_HELL, NUM_FEATURES, // sentinel
"Hell", "The Vestibule of Hell", "Hell",
NULL,
false, true, LIGHTGREY, LIGHTGREY,
mons_standard_rare, mons_standard_level,
- 0, 'U', false },
+ NULL, NULL, NULL, NULL,
+ 0, 'U', false, false },
- { BRANCH_DIS, BRANCH_VESTIBULE_OF_HELL, 7, -1,
+ { BRANCH_DIS, BRANCH_VESTIBULE_OF_HELL, 7, -1, 0, 0,
DNGN_ENTER_DIS, NUM_FEATURES, // sentinel
"Dis", "the Iron City of Dis", "Dis",
NULL,
false, false, CYAN, CYAN,
mons_dis_rare, mons_dis_level,
- 0, 'I', true },
+ NULL, NULL, NULL, NULL,
+ 0, 'I', true, true },
- { BRANCH_GEHENNA, BRANCH_VESTIBULE_OF_HELL, 7, -1,
+ { BRANCH_GEHENNA, BRANCH_VESTIBULE_OF_HELL, 7, -1, 0, 0,
DNGN_ENTER_GEHENNA, NUM_FEATURES, // sentinel
"Gehenna", "Gehenna", "Geh",
NULL,
false, false, DARKGREY, RED,
mons_gehenna_rare, mons_gehenna_level,
- 0, 'N', true },
+ NULL, NULL, NULL, NULL,
+ 0, 'N', true, true },
- { BRANCH_COCYTUS, BRANCH_VESTIBULE_OF_HELL, 7, -1,
+ { BRANCH_COCYTUS, BRANCH_VESTIBULE_OF_HELL, 7, -1, 0, 0,
DNGN_ENTER_COCYTUS, NUM_FEATURES, // sentinel
"Cocytus", "Cocytus", "Coc",
NULL,
false, false, LIGHTBLUE, LIGHTCYAN,
mons_cocytus_rare, mons_cocytus_level,
- 0, 'X', true },
+ NULL, NULL, NULL, NULL,
+ 0, 'X', true, true },
- { BRANCH_TARTARUS, BRANCH_VESTIBULE_OF_HELL, 7, -1,
+ { BRANCH_TARTARUS, BRANCH_VESTIBULE_OF_HELL, 7, -1, 0, 0,
DNGN_ENTER_TARTARUS, NUM_FEATURES, // sentinel
"Tartarus", "Tartarus", "Tar",
NULL,
false, false, DARKGREY, DARKGREY,
mons_tartarus_rare, mons_tartarus_level,
- 0, 'Y', true },
+ NULL, NULL, NULL, NULL,
+ 0, 'Y', true, true },
- { BRANCH_INFERNO, BRANCH_MAIN_DUNGEON, -1, -1,
+ { BRANCH_INFERNO, BRANCH_MAIN_DUNGEON, -1, -1, 0, 0,
NUM_FEATURES, NUM_FEATURES,
NULL, NULL, NULL,
NULL,
false, false, BLACK, BLACK,
NULL, NULL,
- 0, 'R', false },
+ NULL, NULL, NULL, NULL,
+ 0, 'R', false, false },
- { BRANCH_THE_PIT, BRANCH_MAIN_DUNGEON, -1, -1,
+ { BRANCH_THE_PIT, BRANCH_MAIN_DUNGEON, -1, -1, 0, 0,
NUM_FEATURES, NUM_FEATURES,
NULL, NULL, NULL,
NULL,
false, false, BLACK, BLACK,
NULL, NULL,
- 0, '0', false },
+ NULL, NULL, NULL, NULL,
+ 0, '0', false, false },
- { BRANCH_HALL_OF_ZOT, BRANCH_MAIN_DUNGEON, 5, 27,
+ { BRANCH_HALL_OF_ZOT, BRANCH_MAIN_DUNGEON, 5, 27, BFLAG_HAS_ORB, 0,
DNGN_ENTER_ZOT, DNGN_RETURN_FROM_ZOT,
"Zot", "the Realm of Zot", "Zot",
NULL,
false, true, BLACK, BLACK,
mons_hallzot_rare, mons_hallzot_level,
- 1, 'Z', false },
+ NULL, NULL, NULL, NULL,
+ 1, 'Z', false, true },
- { BRANCH_CAVERNS, BRANCH_MAIN_DUNGEON, -1, -1,
+ { BRANCH_CAVERNS, BRANCH_MAIN_DUNGEON, -1, -1, 0, 0,
NUM_FEATURES, NUM_FEATURES,
NULL, NULL, NULL,
NULL,
false, false, BLACK, BLACK,
NULL, NULL,
- 0, 0, false }
+ NULL, NULL, NULL, NULL,
+ 0, 0, false, false }
};
diff --git a/crawl-ref/source/branch.h b/crawl-ref/source/branch.h
index 009bb89bca..0598f31247 100644
--- a/crawl-ref/source/branch.h
+++ b/crawl-ref/source/branch.h
@@ -3,7 +3,7 @@
* Summary: Dungeon branch classes
* Written by: Haran Pilpel
*
- * Modified for Crawl Reference by $Author: haranp $ on $Date: 2006-11-29 13:12:52 -0500 (Wed, 29 Nov 2006) $
+ * Modified for Crawl Reference by $Author$ on $Date$
*
*/
@@ -12,6 +12,18 @@
#include "enum.h"
+struct fog_machine_data;
+
+enum branch_flag_type
+{
+ BFLAG_NONE = 0,
+
+ BFLAG_NO_TELE_CONTROL = (1 << 0), // Teleport control not allowed.
+ BFLAG_NOT_MAPPABLE = (1 << 1), // Branch levels not mappable.
+ BFLAG_NO_MAGIC_MAP = (1 << 2), // Branch levels can't be magic mapped.
+ BFLAG_HAS_ORB = (1 << 3) // Orb is on the floor in this branch
+};
+
struct Branch
{
branch_type id;
@@ -19,6 +31,8 @@ struct Branch
int depth;
int startdepth; // which level of the parent branch,
// 1 for first level
+ unsigned long branch_flags;
+ unsigned long default_level_flags;
dungeon_feature_type entry_stairs;
dungeon_feature_type exit_stairs;
const char* shortname; // "Slime Pits"
@@ -29,11 +43,16 @@ struct Branch
bool has_uniques;
char floor_colour; // Zot needs special handling
char rock_colour;
- int (*mons_rarity_function)(int);
- int (*mons_level_function)(int);
+ int (*mons_rarity_function)(int);
+ int (*mons_level_function)(int);
+ int (*num_traps_function)(int);
+ trap_type (*rand_trap_function)(int);
+ int (*num_fogs_function)(int);
+ void (*rand_fog_function)(int,fog_machine_data&);
int altar_chance; // in percent
int travel_shortcut; // which key to press for travel
bool any_upstair_exits; // any upstair exits the branch (Hell branches)
+ bool dangerous_bottom_level; // bottom level is more dangerous than normal
};
extern Branch branches[];
@@ -42,4 +61,10 @@ Branch& your_branch();
branch_type str_to_branch(const std::string &branch,
branch_type err = NUM_BRANCHES);
+bool set_branch_flags(unsigned long flags, bool silent = false,
+ branch_type branch = NUM_BRANCHES);
+bool unset_branch_flags(unsigned long flags, bool silent = false,
+ branch_type branch = NUM_BRANCHES);
+unsigned long get_branch_flags(branch_type branch = NUM_BRANCHES);
+
#endif
diff --git a/crawl-ref/source/chardump.cc b/crawl-ref/source/chardump.cc
index adbf4b6815..478ad3657e 100644
--- a/crawl-ref/source/chardump.cc
+++ b/crawl-ref/source/chardump.cc
@@ -556,7 +556,7 @@ static void sdump_screenshot(dump_params &par)
static void sdump_notes(dump_params &par)
{
std::string &text(par.text);
- if ( note_list.size() == 0 || Options.use_notes == false )
+ if ( note_list.empty() )
return;
text += "\nNotes\nTurn | Place | Note\n";
@@ -1213,6 +1213,7 @@ static bool write_dump(
void display_notes()
{
Menu scr;
+ scr.set_tag("notes");
scr.set_title( new MenuEntry("Turn | Place | Note"));
for ( unsigned int i = 0; i < note_list.size(); ++i )
{
@@ -1245,6 +1246,7 @@ void resists_screen()
textcolor(LIGHTGREY);
formatted_scroller scr;
+ scr.set_tag("resists");
for ( unsigned i = 0; i < vfs.size(); ++i )
scr.add_item_formatted_string(vfs[i]);
diff --git a/crawl-ref/source/cio.cc b/crawl-ref/source/cio.cc
index 4296b65654..12909bf5e2 100644
--- a/crawl-ref/source/cio.cc
+++ b/crawl-ref/source/cio.cc
@@ -2,7 +2,7 @@
* File: cio.cc
* Summary: Platform-independent console IO functions.
*
- * Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-06-14T18:14:26.828542Z $
+ * Modified for Crawl Reference by $Author$ on $Date$
*/
#include "AppHdr.h"
@@ -108,6 +108,19 @@ void get_input_line( char *const buff, int len )
{
buff[0] = 0; // just in case
+ if (crawl_state.is_replaying_keys())
+ {
+ ASSERT(crawl_state.input_line_curr <
+ crawl_state.input_line_strs.size());
+
+ unsigned int curr = crawl_state.input_line_curr++;
+ std::string &line = crawl_state.input_line_strs[curr];
+
+ strcpy(buff, line.c_str());
+
+ return;
+ }
+
#if defined(UNIX)
get_input_line_from_curses( buff, len ); // implemented in libunix.cc
#elif defined(WIN32CONSOLE)
@@ -137,6 +150,8 @@ void get_input_line( char *const buff, int len )
else
break;
}
+
+ crawl_state.input_line_strs.push_back(buff);
}
// Hacky wrapper around getch() that returns CK_ codes for keys
diff --git a/crawl-ref/source/cio.h b/crawl-ref/source/cio.h
index c21a54aa94..026ac42179 100644
--- a/crawl-ref/source/cio.h
+++ b/crawl-ref/source/cio.h
@@ -2,7 +2,7 @@
* File: cio.h
* Summary: System independent console IO functions
*
- * Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-06-14T18:14:26.828542Z $
+ * Modified for Crawl Reference by $Author$ on $Date$
*/
#ifndef CIO_H
diff --git a/crawl-ref/source/cloud.cc b/crawl-ref/source/cloud.cc
index 0649d03bba..351f1a3773 100644
--- a/crawl-ref/source/cloud.cc
+++ b/crawl-ref/source/cloud.cc
@@ -15,26 +15,33 @@
#include "AppHdr.h"
#include "externs.h"
+#include "branch.h"
#include "cloud.h"
+#include "mapmark.h"
+#include "misc.h"
+#include "place.h"
#include "stuff.h"
#include "terrain.h"
// Returns true if this cloud spreads out as it dissipates.
-static bool cloud_spreads(const cloud_struct &cloud)
+static unsigned char actual_spread_rate(cloud_type type, int spread_rate)
{
- switch (cloud.type)
+ if (spread_rate >= 0)
+ return (unsigned char) spread_rate;
+
+ switch (type)
{
case CLOUD_STEAM:
case CLOUD_GREY_SMOKE:
case CLOUD_BLACK_SMOKE:
- return (true);
+ return 22;
default:
- return (false);
+ return 0;
}
}
static void new_cloud( int cloud, cloud_type type, int x, int y, int decay,
- kill_category whose )
+ kill_category whose, unsigned char spread_rate )
{
ASSERT( env.cloud[ cloud ].type == CLOUD_NONE );
@@ -43,12 +50,13 @@ static void new_cloud( int cloud, cloud_type type, int x, int y, int decay,
env.cloud[ cloud ].x = x;
env.cloud[ cloud ].y = y;
env.cloud[ cloud ].whose = whose;
+ env.cloud[ cloud ].spread_rate = spread_rate;
env.cgrid[ x ][ y ] = cloud;
env.cloud_no++;
}
static void place_new_cloud(cloud_type cltype, int x, int y, int decay,
- kill_category whose)
+ kill_category whose, int spread_rate)
{
if (env.cloud_no >= MAX_CLOUDS)
return;
@@ -58,7 +66,7 @@ static void place_new_cloud(cloud_type cltype, int x, int y, int decay,
{
if (env.cloud[ci].type == CLOUD_NONE) // ie is empty
{
- new_cloud( ci, cltype, x, y, decay, whose );
+ new_cloud( ci, cltype, x, y, decay, whose, spread_rate );
break;
}
}
@@ -90,7 +98,8 @@ static int spread_cloud(const cloud_struct &cloud)
if (newdecay >= cloud.decay)
newdecay = cloud.decay - 1;
- place_new_cloud( cloud.type, x, y, newdecay, cloud.whose );
+ place_new_cloud( cloud.type, x, y, newdecay, cloud.whose,
+ cloud.spread_rate );
extra_decay += 8;
}
@@ -104,8 +113,11 @@ static void dissipate_cloud(int cc, cloud_struct &cloud, int dissipate)
// apply calculated rate to the actual cloud:
cloud.decay -= dissipate;
- if (cloud_spreads(cloud) && cloud.decay > 10 && one_chance_in(5))
+ if (random2(100) < cloud.spread_rate)
+ {
+ cloud.spread_rate -= div_rand_round(cloud.spread_rate, 10);
cloud.decay -= spread_cloud(cloud);
+ }
// check for total dissipation and handle accordingly:
if (cloud.decay < 1)
@@ -137,10 +149,6 @@ void manage_clouds(void)
dissipate *= 4;
}
- // double the amount when slowed - must be applied last(!):
- if (you.duration[DUR_SLOW])
- dissipate *= 2;
-
dissipate_cloud( cc, env.cloud[cc], dissipate );
}
@@ -159,6 +167,7 @@ void delete_cloud( int cloud )
env.cloud[ cloud ].x = 0;
env.cloud[ cloud ].y = 0;
env.cloud[ cloud ].whose = KC_OTHER;
+ env.cloud[ cloud ].spread_rate = 0;
env.cgrid[ cloud_x ][ cloud_y ] = EMPTY_CLOUD;
env.cloud_no--;
}
@@ -183,12 +192,12 @@ void move_cloud( int cloud, int new_x, int new_y )
// Places a cloud with the given stats assuming one doesn't already
// exist at that point.
void check_place_cloud( cloud_type cl_type, int x, int y, int lifetime,
- kill_category whose )
+ kill_category whose, int spread_rate )
{
if (!in_bounds(x, y) || env.cgrid[x][y] != EMPTY_CLOUD)
return;
- place_cloud( cl_type, x, y, lifetime, whose );
+ place_cloud( cl_type, x, y, lifetime, whose, spread_rate );
}
int steam_cloud_damage(const cloud_struct &cloud)
@@ -208,7 +217,7 @@ int steam_cloud_damage(const cloud_struct &cloud)
// cloud under some circumstances.
void place_cloud(cloud_type cl_type, int ctarget_x,
int ctarget_y, int cl_range,
- kill_category whose)
+ kill_category whose, int _spread_rate)
{
int cl_new = -1;
@@ -234,6 +243,8 @@ void place_cloud(cloud_type cl_type, int ctarget_x,
}
}
+ unsigned char spread_rate = actual_spread_rate( cl_type, _spread_rate );
+
// too many clouds
if (env.cloud_no >= MAX_CLOUDS)
{
@@ -261,7 +272,7 @@ void place_cloud(cloud_type cl_type, int ctarget_x,
// create new cloud
if (cl_new != -1)
new_cloud( cl_new, cl_type, ctarget_x, ctarget_y, cl_range * 10,
- whose );
+ whose, spread_rate );
else
{
// find slot for cloud
@@ -270,7 +281,7 @@ void place_cloud(cloud_type cl_type, int ctarget_x,
if (env.cloud[ci].type == CLOUD_NONE) // ie is empty
{
new_cloud( ci, cl_type, ctarget_x, ctarget_y, cl_range * 10,
- whose );
+ whose, spread_rate );
break;
}
}
@@ -298,6 +309,199 @@ cloud_type random_smoke_type()
return CLOUD_DEBUGGING;
}
+void place_fog_machine(fog_machine_type fm_type, cloud_type cl_type,
+ int x, int y, int size, int power)
+{
+ ASSERT(fm_type >= FM_GEYSER && fm_type < NUM_FOG_MACHINE_TYPES);
+ ASSERT(cl_type > CLOUD_NONE && (cl_type < CLOUD_RANDOM
+ || cl_type == CLOUD_DEBUGGING));
+ ASSERT(size >= 1);
+ ASSERT(power >= 1);
+
+ const char* fog_types[] = {
+ "geyser",
+ "spread",
+ "brownian"
+ };
+
+ try
+ {
+ char buf [160];
+ sprintf(buf, "lua_mapless:fog_machine_%s(\"%s\", %d, %d)",
+ fog_types[fm_type], cloud_name(cl_type).c_str(),
+ size, power);
+
+ map_marker *mark = map_lua_marker::parse_marker(buf, "");
+
+ if (mark == NULL)
+ {
+ mprf(MSGCH_DIAGNOSTICS, "Unable to parse fog machine from '%s'",
+ buf);
+ return;
+ }
+
+ mark->pos = coord_def(x, y);
+ env.markers.add(mark);
+ }
+ catch (const std::string &err)
+ {
+ mprf(MSGCH_DIAGNOSTICS, "Error while making fog machine: %s",
+ err.c_str());
+ }
+}
+
+void place_fog_machine(fog_machine_data data, int x, int y)
+{
+ place_fog_machine(data.fm_type, data.cl_type, x, y, data.size,
+ data.power);
+}
+
+bool valid_fog_machine_data(fog_machine_data data)
+{
+ if (data.fm_type < FM_GEYSER || data.fm_type >= NUM_FOG_MACHINE_TYPES)
+ return false;
+
+ if (data.cl_type <= CLOUD_NONE || (data.cl_type >= CLOUD_RANDOM
+ && data.cl_type != CLOUD_DEBUGGING))
+ return false;
+
+ if (data.size < 1 || data.power < 1)
+ return false;
+
+ return true;
+}
+
+int num_fogs_for_place(int level_number, const level_id &place)
+{
+ if (level_number == -1)
+ {
+ switch(place.level_type)
+ {
+ case LEVEL_DUNGEON:
+ level_number = absdungeon_depth(place.branch, place.depth);
+ break;
+ case LEVEL_ABYSS:
+ level_number = 51;
+ break;
+ case LEVEL_PANDEMONIUM:
+ level_number = 52;
+ break;
+ default:
+ level_number = you.your_level;
+ }
+ }
+
+ switch(place.level_type)
+ {
+ case LEVEL_DUNGEON:
+ {
+ Branch &branch = branches[place.branch];
+ ASSERT((branch.num_fogs_function == NULL
+ && branch.rand_fog_function == NULL)
+ || (branch.num_fogs_function != NULL
+ && branch.rand_fog_function != NULL));
+
+ if (branch.num_fogs_function == NULL)
+ return 0;
+
+ return branch.num_fogs_function(level_number);
+ }
+ case LEVEL_ABYSS:
+ return fogs_abyss_number(level_number);
+ case LEVEL_PANDEMONIUM:
+ return fogs_pan_number(level_number);
+ case LEVEL_LABYRINTH:
+ return fogs_lab_number(level_number);
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+fog_machine_data random_fog_for_place(int level_number, const level_id &place)
+{
+ fog_machine_data data = {NUM_FOG_MACHINE_TYPES, CLOUD_NONE, -1, -1};
+
+ if (level_number == -1)
+ {
+ switch(place.level_type)
+ {
+ case LEVEL_DUNGEON:
+ level_number = absdungeon_depth(place.branch, place.depth);
+ break;
+ case LEVEL_ABYSS:
+ level_number = 51;
+ break;
+ case LEVEL_PANDEMONIUM:
+ level_number = 52;
+ break;
+ default:
+ level_number = you.your_level;
+ }
+ }
+
+ switch(place.level_type)
+ {
+ case LEVEL_DUNGEON:
+ {
+ Branch &branch = branches[place.branch];
+ ASSERT(branch.num_fogs_function != NULL
+ && branch.rand_fog_function != NULL);
+ branch.rand_fog_function(level_number, data);
+ return data;
+ }
+ case LEVEL_ABYSS:
+ return fogs_abyss_type(level_number);
+ case LEVEL_PANDEMONIUM:
+ return fogs_pan_type(level_number);
+ case LEVEL_LABYRINTH:
+ return fogs_lab_type(level_number);
+ default:
+ ASSERT(false);
+ return data;
+ }
+
+ ASSERT(false);
+ return data;
+}
+
+int fogs_pan_number(int level_number)
+{
+ return 0;
+}
+
+fog_machine_data fogs_pan_type(int level_number)
+{
+ fog_machine_data data = {NUM_FOG_MACHINE_TYPES, CLOUD_NONE, -1, -1};
+
+ return data;
+}
+
+int fogs_abyss_number(int level_number)
+{
+ return 0;
+}
+
+fog_machine_data fogs_abyss_type(int level_number)
+{
+ fog_machine_data data = {NUM_FOG_MACHINE_TYPES, CLOUD_NONE, -1, -1};
+
+ return data;
+}
+
+int fogs_lab_number(int level_number)
+{
+ return 0;
+}
+
+fog_machine_data fogs_lab_type(int level_number)
+{
+ fog_machine_data data = {NUM_FOG_MACHINE_TYPES, CLOUD_NONE, -1, -1};
+
+ return data;
+}
+
////////////////////////////////////////////////////////////////////////
// cloud_struct
diff --git a/crawl-ref/source/cloud.h b/crawl-ref/source/cloud.h
index be7502d6a0..0cee66ca0d 100644
--- a/crawl-ref/source/cloud.h
+++ b/crawl-ref/source/cloud.h
@@ -13,6 +13,23 @@
#define CLOUD_H
#include "externs.h"
+#include "travel.h"
+
+enum fog_machine_type
+{
+ FM_GEYSER,
+ FM_SPREAD,
+ FM_BROWNIAN,
+ NUM_FOG_MACHINE_TYPES
+};
+
+struct fog_machine_data
+{
+ fog_machine_type fm_type;
+ cloud_type cl_type;
+ int size;
+ int power;
+};
cloud_type random_smoke_type();
@@ -20,13 +37,34 @@ void delete_cloud( int cloud );
void move_cloud( int cloud, int new_x, int new_y );
void check_place_cloud( cloud_type cl_type, int x, int y, int lifetime,
- kill_category whose );
+ kill_category whose, int spread_rate = -1 );
void place_cloud(cloud_type cl_type, int ctarget_x, int ctarget_y,
- int cl_range, kill_category whose);
+ int cl_range, kill_category whose, int spread_rate = -1 );
void manage_clouds(void);
bool is_opaque_cloud(unsigned char cloud_idx);
int steam_cloud_damage(const cloud_struct &cloud);
+void place_fog_machine(fog_machine_type fm_type, cloud_type cl_type,
+ int x, int y, int size, int power);
+
+void place_fog_machine(fog_machine_data data, int x, int y);
+
+bool valid_fog_machine_data(fog_machine_data data);
+
+int num_fogs_for_place(int level_number = -1,
+ const level_id &place = level_id::current());
+fog_machine_data random_fog_for_place(int level_number = -1,
+ const level_id &place = level_id::current());
+
+int fogs_pan_number(int level_number = -1);
+fog_machine_data fogs_pan_type(int level_number = -1);
+
+int fogs_abyss_number(int level_number = -1);
+fog_machine_data fogs_abyss_type(int level_number = -1);
+
+int fogs_lab_number(int level_number = -1);
+fog_machine_data fogs_lab_type(int level_number = -1);
+
#endif
diff --git a/crawl-ref/source/clua.cc b/crawl-ref/source/clua.cc
index 7e5eb40bc8..be98456849 100644
--- a/crawl-ref/source/clua.cc
+++ b/crawl-ref/source/clua.cc
@@ -379,7 +379,6 @@ void CLua::vfnreturns(const char *format, va_list args)
lua_pop(ls, nrets);
}
-static void push_monster(lua_State *ls, monsters *mons);
static int push_activity_interrupt(lua_State *ls, activity_interrupt_data *t);
int CLua::push_args(lua_State *ls, const char *format, va_list args,
va_list *targ)
@@ -718,6 +717,12 @@ LUARET1(you_race, string,
species_name(you.species, you.experience_level).c_str())
LUARET1(you_class, string, get_class_name(you.char_class))
LUARET1(you_god, string, god_name(you.religion))
+LUARET1(you_good_god, boolean,
+ lua_isstring(ls, 1) ? is_good_god(str_to_god(lua_tostring(ls, 1)))
+ : is_good_god(you.religion))
+LUARET1(you_evil_god, boolean,
+ lua_isstring(ls, 1) ? is_evil_god(str_to_god(lua_tostring(ls, 1)))
+ : is_evil_god(you.religion))
LUARET2(you_hp, number, you.hp, you.hp_max)
LUARET2(you_mp, number, you.magic_points, you.max_magic_points)
LUARET1(you_hunger, string, hunger_level())
@@ -726,6 +731,9 @@ LUARET2(you_intelligence, number, you.intel, you.max_intel)
LUARET2(you_dexterity, number, you.dex, you.max_dex)
LUARET1(you_exp, number, you.experience_level)
LUARET1(you_exp_points, number, you.experience)
+LUARET1(you_skill, number,
+ lua_isstring(ls, 1) ? you.skills[str_to_skill(lua_tostring(ls, 1))]
+ : 0)
LUARET1(you_res_poison, number, player_res_poison(false))
LUARET1(you_res_fire, number, player_res_fire(false))
LUARET1(you_res_cold, number, player_res_cold(false))
@@ -735,6 +743,7 @@ LUARET1(you_res_statdrain, number, player_sust_abil(false))
LUARET1(you_res_mutation, number, wearing_amulet(AMU_RESIST_MUTATION, false))
LUARET1(you_res_slowing, number, wearing_amulet(AMU_RESIST_SLOW, false))
LUARET1(you_gourmand, boolean, wearing_amulet(AMU_THE_GOURMAND, false))
+LUARET1(you_saprovorous, number, you.mutation[MUT_SAPROVOROUS])
LUARET1(you_levitating, boolean, you.flight_mode() == FL_LEVITATE)
LUARET1(you_flying, boolean, you.flight_mode() == FL_FLY)
LUARET1(you_transform, string, transform_name())
@@ -746,9 +755,10 @@ LUAWRAP(you_stop_activity, interrupt_activity(AI_FORCE_INTERRUPT))
LUARET1(you_turns, number, you.num_turns)
LUARET1(you_see_grid, boolean,
see_grid(luaL_checkint(ls, 1), luaL_checkint(ls, 2)))
+LUARET1(you_see_grid_no_trans, boolean,
+ see_grid_no_trans(luaL_checkint(ls, 1), luaL_checkint(ls, 2)))
+
// increase by 1 because check happens on old level
-LUARET1(bzr_floor_colour, string,
- colour_to_str(bazaar_floor_colour(you.your_level + 2)))
void lua_push_floor_items(lua_State *ls);
static int you_floor_items(lua_State *ls)
@@ -796,15 +806,17 @@ static const struct luaL_reg you_lib[] =
{ "race" , you_race },
{ "class" , you_class },
{ "god" , you_god },
+ { "good_god" , you_good_god },
+ { "evil_god" , you_evil_god },
{ "hp" , you_hp },
{ "mp" , you_mp },
{ "hunger" , you_hunger },
{ "strength" , you_strength },
{ "intelligence", you_intelligence },
{ "dexterity" , you_dexterity },
+ { "skill" , you_skill },
{ "xl" , you_exp },
{ "exp" , you_exp_points },
-
{ "res_poison" , you_res_poison },
{ "res_fire" , you_res_fire },
{ "res_cold" , you_res_cold },
@@ -813,6 +825,7 @@ static const struct luaL_reg you_lib[] =
{ "res_statdrain", you_res_statdrain },
{ "res_mutation", you_res_mutation },
{ "res_slowing", you_res_slowing },
+ { "saprovorous", you_saprovorous },
{ "gourmand", you_gourmand },
{ "levitating", you_levitating },
{ "flying", you_flying },
@@ -827,9 +840,9 @@ static const struct luaL_reg you_lib[] =
{ "subdepth", you_subdepth },
{ "absdepth", you_absdepth },
- { "see_grid", you_see_grid },
- { "bazaar_floor", bzr_floor_colour },
-
+ { "see_grid", you_see_grid },
+ { "see_grid_no_trans", you_see_grid_no_trans },
+
{ NULL, NULL },
};
@@ -1497,10 +1510,14 @@ static int food_do_eat(lua_State *ls)
static int food_prompt_floor(lua_State *ls)
{
- bool eaten = false;
- if (!you.turn_is_over && (eaten = eat_from_floor()))
- burden_change();
- lua_pushboolean(ls, eaten);
+ int eaten = 0;
+ if (!you.turn_is_over)
+ {
+ eaten = eat_from_floor();
+ if ( eaten == 1 )
+ burden_change();
+ }
+ lua_pushboolean(ls, (eaten != 0));
return (1);
}
@@ -2061,30 +2078,22 @@ static option_handler handlers[] =
{ "colour_map", &Options.colour_map, option_hboolean },
{ "clean_map", &Options.clean_map, option_hboolean },
{ "show_uncursed", &Options.show_uncursed, option_hboolean },
- { "always_greet", &Options.always_greet, option_hboolean },
{ "easy_open", &Options.easy_open, option_hboolean },
{ "easy_armour", &Options.easy_unequip, option_hboolean },
{ "easy_unequip", &Options.easy_unequip, option_hboolean },
{ "easy_butcher", &Options.easy_butcher, option_hboolean },
- { "terse_hand", &Options.terse_hand, option_hboolean },
- { "increasing_skill_progress", &Options.increasing_skill_progress, option_hboolean },
- { "confirm_self_target", &Options.confirm_self_target, option_hboolean },
+ { "always_confirm_butcher", &Options.always_confirm_butcher, option_hboolean },
{ "default_target", &Options.default_target, option_hboolean },
- { "safe_autopickup", &Options.safe_autopickup, option_hboolean },
{ "autopickup_no_burden", &Options.autopickup_no_burden, option_hboolean },
{ "note_skill_max", &Options.note_skill_max, option_hboolean },
- { "use_notes", &Options.use_notes, option_hboolean },
{ "delay_message_clear", &Options.delay_message_clear, option_hboolean },
{ "no_dark_brand", &Options.no_dark_brand, option_hboolean },
{ "auto_list", &Options.auto_list, option_hboolean },
- { "lowercase_invocations", &Options.lowercase_invocations,
- option_hboolean },
{ "pickup_thrown", &Options.pickup_thrown, option_hboolean },
{ "pickup_dropped", &Options.pickup_dropped, option_hboolean },
{ "show_waypoints", &Options.show_waypoints, option_hboolean },
{ "item_colour", &Options.item_colour, option_hboolean },
{ "target_zero_exp", &Options.target_zero_exp, option_hboolean },
- { "safe_zero_exp", &Options.safe_zero_exp, option_hboolean },
{ "target_wrap", &Options.target_wrap, option_hboolean },
{ "easy_exit_menu", &Options.easy_exit_menu, option_hboolean },
{ "dos_use_background_intensity", &Options.dos_use_background_intensity,
@@ -2267,7 +2276,7 @@ static int push_activity_interrupt(lua_State *ls, activity_interrupt_data *t)
return 0;
}
-static void push_monster(lua_State *ls, monsters *mons)
+void push_monster(lua_State *ls, monsters *mons)
{
MonsterWrap *mw = clua_new_userdata< MonsterWrap >(ls, MONS_METATABLE);
mw->turn = you.num_turns;
diff --git a/crawl-ref/source/clua.h b/crawl-ref/source/clua.h
index 99a4e24bc3..554c85d79f 100644
--- a/crawl-ref/source/clua.h
+++ b/crawl-ref/source/clua.h
@@ -235,6 +235,8 @@ template <class T> T *clua_new_userdata(
return static_cast<T*>( udata );
}
+void push_monster(lua_State *ls, monsters *mons);
+
#define MAP_METATABLE "dgn.mtmap"
#define DEVENT_METATABLE "dgn.devent"
#define MAPMARK_METATABLE "dgn.mapmark"
diff --git a/crawl-ref/source/command.cc b/crawl-ref/source/command.cc
index 7edb77a71f..581ae33bf2 100644
--- a/crawl-ref/source/command.cc
+++ b/crawl-ref/source/command.cc
@@ -26,7 +26,10 @@
#include "abl-show.h"
#include "chardump.h"
#include "cio.h"
+#include "database.h"
+#include "describe.h"
#include "files.h"
+#include "initfile.h"
#include "invent.h"
#include "itemname.h"
#include "item_use.h"
@@ -34,6 +37,8 @@
#include "libutil.h"
#include "menu.h"
#include "message.h"
+#include "mon-pick.h"
+#include "mon-util.h"
#include "ouch.h"
#include "player.h"
#include "spl-cast.h"
@@ -70,6 +75,10 @@ static const char *features[] = {
"Lua user scripts",
#endif
+#ifdef WIZARD
+ "Wizard mode",
+#endif
+
#if defined(REGEX_POSIX)
"POSIX regexps",
#elif defined(REGEX_PCRE)
@@ -380,7 +389,8 @@ void list_armour()
{
estr << you.inv[armour_id].name(DESC_INVENTORY);
colour = menu_colour(estr.str(),
- menu_colour_item_prefix(you.inv[armour_id]));
+ menu_colour_item_prefix(you.inv[armour_id]),
+ "equip");
}
else if (!you_can_wear(i,true))
estr << " (unavailable)";
@@ -392,7 +402,7 @@ void list_armour()
estr << " none";
if (colour == MSGCOL_BLACK)
- colour = menu_colour(estr.str());
+ colour = menu_colour(estr.str(), "", "equip");
mpr( estr.str().c_str(), MSGCH_EQUIPMENT, colour);
}
@@ -421,7 +431,7 @@ void list_jewellery(void)
jstr << you.inv[jewellery_id].name(DESC_INVENTORY);
std::string
prefix = menu_colour_item_prefix(you.inv[jewellery_id]);
- colour = menu_colour(jstr.str(), prefix);
+ colour = menu_colour(jstr.str(), prefix, "equip");
}
else if (!you_tran_can_wear(i))
jstr << " (currently unavailable)";
@@ -429,7 +439,7 @@ void list_jewellery(void)
jstr << " none";
if (colour == MSGCOL_BLACK)
- colour = menu_colour(jstr.str());
+ colour = menu_colour(jstr.str(), "", "equip");
mpr( jstr.str().c_str(), MSGCH_EQUIPMENT, colour);
}
@@ -450,7 +460,8 @@ void list_weapons(void)
{
wstring += you.inv[weapon_id].name(DESC_INVENTORY_EQUIP);
colour = menu_colour(wstring,
- menu_colour_item_prefix(you.inv[weapon_id]));
+ menu_colour_item_prefix(you.inv[weapon_id]),
+ "equip");
}
else
{
@@ -460,7 +471,7 @@ void list_weapons(void)
wstring += " (currently unavailable)";
else
wstring += " empty hands";
- colour = menu_colour(wstring);
+ colour = menu_colour(wstring, "", "equip");
}
mpr(wstring.c_str(), MSGCH_EQUIPMENT, colour);
@@ -486,13 +497,14 @@ void list_weapons(void)
{
wstring += you.inv[i].name(DESC_INVENTORY_EQUIP);
colour = menu_colour(wstring,
- menu_colour_item_prefix(you.inv[i]));
+ menu_colour_item_prefix(you.inv[i]),
+ "equip");
}
else
wstring += " none";
if (colour == MSGCOL_BLACK)
- colour = menu_colour(wstring);
+ colour = menu_colour(wstring, "", "equip");
mpr(wstring.c_str(), MSGCH_EQUIPMENT, colour);
}
@@ -509,11 +521,12 @@ void list_weapons(void)
{
wstring += you.inv[item].name(DESC_INVENTORY_EQUIP);
colour = menu_colour(wstring,
- menu_colour_item_prefix(you.inv[item]));
+ menu_colour_item_prefix(you.inv[item]),
+ "equip");
}
if (colour == MSGCOL_BLACK)
- colour = menu_colour(wstring);
+ colour = menu_colour(wstring, "", "equip");
mpr( wstring.c_str(), MSGCH_EQUIPMENT, colour );
} // end list_weapons()
@@ -548,7 +561,8 @@ static const char *level_map_help =
"<w>Ctrl-X</w> : set travel eXclusion\n"
"<w>Ctrl-E</w> : Erase all travel exclusions\n"
"<w>Ctrl-W</w> : set Waypoint\n"
- "<w>Ctrl-C</w> : Clear level and main maps\n";
+ "<w>Ctrl-C</w> : Clear level and main maps\n"
+ "<w>Ctrl-F</w> : Forget level map\n";
static const char *targeting_help_1 =
"<h>Examine surroundings ('<w>x</w><h>' in main):\n"
@@ -679,6 +693,434 @@ help_file help_files[] = {
{ NULL, 0, false }
};
+static std::string list_commands_err = "";
+
+
+static bool compare_mon_names(MenuEntry *entry_a, MenuEntry* entry_b)
+{
+ monster_type *a = static_cast<monster_type*>( entry_a->data );
+ monster_type *b = static_cast<monster_type*>( entry_b->data );
+
+ if (*a == *b)
+ return false;
+
+ std::string a_name = mons_type_name(*a, DESC_PLAIN);
+ std::string b_name = mons_type_name(*b, DESC_PLAIN);
+ return (lowercase(a_name) < lowercase(b_name));
+}
+
+// Compare monsters by location-independant level, or by hitdice if
+// levels are equal, or by name if both level and hitdice are equal.
+static bool compare_mon_toughness(MenuEntry *entry_a, MenuEntry* entry_b)
+{
+ monster_type *a = static_cast<monster_type*>( entry_a->data );
+ monster_type *b = static_cast<monster_type*>( entry_b->data );
+
+ if (*a == *b)
+ return false;
+
+ int a_toughness = mons_global_level(*a);
+ int b_toughness = mons_global_level(*b);
+
+ if (a_toughness == b_toughness)
+ {
+ a_toughness = mons_type_hit_dice(*a);
+ b_toughness = mons_type_hit_dice(*b);
+ }
+
+ if (a_toughness == b_toughness)
+ {
+ std::string a_name = mons_type_name(*a, DESC_PLAIN);
+ std::string b_name = mons_type_name(*b, DESC_PLAIN);
+ return ( lowercase(a_name) < lowercase(b_name));
+ }
+
+ return (a_toughness < b_toughness);
+}
+
+class DescMenu : public Menu
+{
+public:
+ DescMenu( int _flags, bool _show_mon )
+ : Menu(_flags), sort_alpha(true), showing_monsters(_show_mon)
+ {
+ set_highlighter(NULL);
+
+ set_prompt();
+ }
+
+ bool sort_alpha;
+ bool showing_monsters;
+
+ void set_prompt()
+ {
+ std::string prompt = "Describe which? ";
+
+ if (showing_monsters)
+ {
+ if (sort_alpha)
+ prompt += "(CTRL-S to sort by monster toughness)";
+ else
+ prompt += "(CTRL-S to sort by name)";
+ }
+ set_title(new MenuEntry(prompt, MEL_TITLE));
+ }
+
+ void sort()
+ {
+ if (!showing_monsters)
+ return;
+
+ if (sort_alpha)
+ std::sort(items.begin(), items.end(), compare_mon_names);
+ else
+ std::sort(items.begin(), items.end(), compare_mon_toughness);
+
+ for (unsigned int i = 0, size = items.size(); i < size; i++)
+ {
+ const char letter = index_to_letter(i);
+
+ items[i]->hotkeys.clear();
+ items[i]->add_hotkey(letter);
+ }
+ }
+
+ void toggle_sorting()
+ {
+ if (!showing_monsters)
+ return;
+
+ sort_alpha = !sort_alpha;
+
+ sort();
+ set_prompt();
+ }
+};
+
+static std::vector<std::string> get_desc_keys(std::string regex,
+ db_find_filter filter)
+{
+ std::vector<std::string> key_matches = getLongDescKeysByRegex(regex,
+ filter);
+
+ if (key_matches.size() == 1)
+ return (key_matches);
+ else if (key_matches.size() > 52)
+ return (key_matches);
+
+ std::vector<std::string> body_matches = getLongDescBodiesByRegex(regex,
+ filter);
+
+ if (key_matches.size() == 0 && body_matches.size() == 0)
+ return (key_matches);
+ else if (key_matches.size() == 0 && body_matches.size() == 1)
+ return (body_matches);
+
+ // Merge key_matches and body_matches, discarding duplicates.
+ std::vector<std::string> tmp = key_matches;
+ tmp.insert(tmp.end(), body_matches.begin(), body_matches.end());
+ std::sort(tmp.begin(), tmp.end());
+ std::vector<std::string> all_matches;
+ for (unsigned int i = 0, size = tmp.size(); i < size; i++)
+ if (i == 0 || all_matches[all_matches.size() - 1] != tmp[i])
+ {
+ all_matches.push_back(tmp[i]);
+ }
+
+ return (all_matches);
+}
+
+static std::vector<std::string> get_monster_keys(unsigned char showchar)
+{
+ std::vector<std::string> mon_keys;
+
+ for (int i = 0; i < NUM_MONSTERS; i++)
+ {
+ if (i == MONS_PROGRAM_BUG || mons_global_level(i) == 0)
+ continue;
+
+ monsterentry *me = get_monster_data(i);
+
+ if (me == NULL || me->name == NULL || me->name[0] == '\0')
+ continue;
+
+ if (me->mc != i)
+ continue;
+
+ if (getLongDescription(me->name) == "")
+ continue;
+
+ if (me->showchar == showchar)
+ mon_keys.push_back(me->name);
+ }
+
+ return (mon_keys);
+}
+
+static bool monster_filter(std::string key, std::string body)
+{
+ int mon_num = get_monster_by_name(key.c_str(), true);
+ return (mon_num == MONS_PROGRAM_BUG || mons_global_level(mon_num) == 0);
+}
+
+static bool spell_filter(std::string key, std::string body)
+{
+ return (spell_by_name(key) == SPELL_NO_SPELL);
+}
+
+static bool feature_filter(std::string key, std::string body)
+{
+ return (spell_by_name(key) != SPELL_NO_SPELL
+ || get_monster_by_name(key.c_str(), true) != MONS_PROGRAM_BUG);
+}
+
+static bool do_description(std::string key)
+{
+ std::string desc = getLongDescription(key);
+
+ monster_type mon_num = get_monster_by_name(key, true);
+ if (mon_num != MONS_PROGRAM_BUG)
+ {
+ if (mons_genus(mon_num) == MONS_DRACONIAN)
+ {
+ monsters mon;
+
+ mon.type = mon_num;
+
+ switch (mon_num)
+ {
+ case MONS_BLACK_DRACONIAN:
+ case MONS_MOTTLED_DRACONIAN:
+ case MONS_YELLOW_DRACONIAN:
+ case MONS_GREEN_DRACONIAN:
+ case MONS_PURPLE_DRACONIAN:
+ case MONS_RED_DRACONIAN:
+ case MONS_WHITE_DRACONIAN:
+ case MONS_PALE_DRACONIAN:
+ mon.number = mon_num;
+ break;
+ default:
+ mon.number = 0;
+ break;
+ }
+
+ describe_monsters(mon);
+ return (false);
+ }
+
+ std::string symbol = "";
+ symbol += get_monster_data(mon_num)->showchar;
+ if (isupper(symbol[0]))
+ symbol = "cap-" + symbol;
+
+ std::string symbol_prefix = "__";
+ symbol_prefix += symbol;
+ symbol_prefix += "_prefix";
+ desc = getLongDescription(symbol_prefix) + desc;
+
+ std::string symbol_suffix = "__";
+ symbol_suffix += symbol;
+ symbol_suffix += "_suffix";
+ desc += getLongDescription(symbol_suffix);
+ }
+
+ key = uppercase_first(key);
+ key += "$$";
+
+ clrscr();
+ print_description(key + desc);
+
+ return (true);
+}
+
+static bool find_description()
+{
+ clrscr();
+ viewwindow(true, false);
+
+ mpr("Describe a (M)onster, (S)pell or (F)eature? ", MSGCH_PROMPT);
+
+ int ch = toupper(getch());
+ std::string type;
+ std::string extra;
+ db_find_filter filter;
+
+ switch(ch)
+ {
+ case 'M':
+ type = "monster";
+ extra = " Enter a single letter to list monsters displayed by "
+ "that symbol.";
+ filter = monster_filter;
+ break;
+ case 'S':
+ type = "spell";
+ filter = spell_filter;
+ break;
+ case 'F':
+ type = "feature";
+ filter = feature_filter;
+ break;
+ default:
+ list_commands_err = "Okay, then.";
+ return (false);
+ }
+
+ mprf(MSGCH_PROMPT,
+ "Describe a %s; partial names and regexps are fine.%s",
+ type.c_str(), extra.c_str());
+ mpr("Describe what? ", MSGCH_PROMPT);
+ char buf[80];
+ if (cancelable_get_line(buf, sizeof(buf)) || buf[0] == '\0')
+ {
+ list_commands_err = "Okay, then.";
+ return (false);
+ }
+
+ std::string regex = trimmed_string(buf);
+
+ if (regex == "")
+ {
+ list_commands_err = "Description must contain at least one non-space.";
+ return (false);
+ }
+
+ bool doing_mons = (ch == 'M');
+ bool by_mon_symbol = (doing_mons && regex.size() == 1);
+
+ // Try to get an exact match first.
+ if (!by_mon_symbol && !(*filter)(regex, ""))
+ {
+ // Try to get an exact match first.
+ std::string desc = getLongDescription(regex);
+
+ if (desc != "")
+ {
+ return do_description(regex);
+ }
+ }
+
+ std::vector<std::string> key_list;
+
+ if (by_mon_symbol)
+ key_list = get_monster_keys(regex[0]);
+ else
+ key_list = get_desc_keys(regex, filter);
+
+ if (key_list.size() == 0)
+ {
+ if (by_mon_symbol)
+ {
+ list_commands_err = "No monsters with symbol '";
+ list_commands_err += regex;
+ list_commands_err += "'";
+ }
+ else
+ {
+ list_commands_err = "No matching ";
+ list_commands_err += type;
+ list_commands_err += "s";
+ }
+ return (false);
+ }
+ else if (key_list.size() > 52)
+ {
+ if (by_mon_symbol)
+ {
+ list_commands_err = "Too many monsters with symbol '";
+ list_commands_err += regex;
+ list_commands_err += "' to display";
+ }
+ else
+ {
+ std::ostringstream os;
+ os << "Too many matching " << type << "s (" << key_list.size()
+ << ") to display.";
+ list_commands_err = os.str();
+ }
+ return (false);
+ }
+ else if (key_list.size() == 1)
+ {
+ return do_description(key_list[0]);
+ }
+
+ std::sort(key_list.begin(), key_list.end());
+
+ DescMenu desc_menu(MF_SINGLESELECT | MF_ANYPRINTABLE |
+ MF_ALWAYS_SHOW_MORE | MF_ALLOW_FORMATTING,
+ doing_mons);
+ desc_menu.set_tag("description");
+ std::list<monster_type> monster_types;
+ for (unsigned int i = 0, size = key_list.size(); i < size; i++)
+ {
+ const char letter = index_to_letter(i);
+ std::string str = uppercase_first(key_list[i]);
+
+ MenuEntry *me = new MenuEntry(uppercase_first(key_list[i]),
+ MEL_ITEM, 1, letter);
+
+ if (doing_mons)
+ {
+ monster_type mon = get_monster_by_name(str, true);
+ unsigned char colour = mons_class_colour(mon);
+
+ monster_types.push_back(mon);
+
+ if (colour == BLACK)
+ colour = LIGHTGREY;
+
+ std::string prefix = "(<";
+ prefix += colour_to_str(colour);
+ prefix += ">";
+ prefix += stringize_glyph(mons_char(mon));
+ prefix += "</";
+ prefix += colour_to_str(colour);
+ prefix += ">) ";
+
+ me->text = prefix + str;
+ me->data = &*monster_types.rbegin();
+ }
+ else
+ me->data = (void*) &key_list[i];
+
+ desc_menu.add_entry(me);
+ }
+
+ desc_menu.sort();
+
+ while (true)
+ {
+ std::vector<MenuEntry*> sel = desc_menu.show();
+ redraw_screen();
+ if ( sel.empty() )
+ {
+ if (doing_mons && desc_menu.getkey() == CONTROL('S'))
+ desc_menu.toggle_sorting();
+ else
+ return (false);
+ }
+ else
+ {
+ ASSERT(sel.size() == 1);
+ ASSERT(sel[0]->hotkeys.size() == 1);
+
+ std::string key;
+
+ if (doing_mons)
+ key = mons_type_name(*(monster_type*) sel[0]->data, DESC_PLAIN);
+ else
+ key = *((std::string*) sel[0]->data);
+
+ if (do_description(key))
+ if ( getch() == 0 )
+ getch();
+ }
+ }
+
+ return (false);
+}
+
static int keyhelp_keyfilter(int ch)
{
switch (ch)
@@ -690,10 +1132,17 @@ static int keyhelp_keyfilter(int ch)
display_notes();
return -1;
}
- // fall through
- default:
- return ch;
+ break;
+
+ case '/':
+ if (find_description())
+ if ( getch() == 0 )
+ getch();
+
+ viewwindow(true, false);
+ return -1;
}
+ return ch;
}
static void show_keyhelp_menu(const std::vector<formatted_string> &lines,
@@ -707,6 +1156,7 @@ static void show_keyhelp_menu(const std::vector<formatted_string> &lines,
if (easy_exit)
flags |= MF_EASY_EXIT;
cmd_help.set_flags(flags, false);
+ cmd_help.set_tag("help");
// FIXME: Allow for hiding Page down when at the end of the listing, ditto
// for page up at start of listing.
@@ -733,6 +1183,7 @@ static void show_keyhelp_menu(const std::vector<formatted_string> &lines,
"<w>~</w>: Macros help\n"
"<w>!</w>: Options help\n"
"<w>%</w>: Table of aptitudes\n"
+ "<w>/</w>: Lookup description\n"
"<w>Home</w>: This screen\n",
true, true, cmdhelp_textfilter);
@@ -842,11 +1293,15 @@ void show_interlevel_travel_depth_help()
show_specific_help( interlevel_travel_depth_help );
}
-void list_commands(bool wizard, int hotkey)
+void list_commands(bool wizard, int hotkey, bool do_redraw_screen)
{
if (wizard)
{
list_wizard_commands();
+
+ if (do_redraw_screen)
+ redraw_screen();
+
return;
}
@@ -1007,6 +1462,8 @@ void list_commands(bool wizard, int hotkey)
"<w>p</w> : Pray\n"
"<w>Z</w> : cast a spell\n"
"<w>!</w> : shout or command allies\n"
+ "<w>`</w> : re-do previous command\n"
+ "<w>0</w> : repeat next command # of times\n"
" \n",
true, true, cmdhelp_textfilter);
@@ -1017,6 +1474,7 @@ void list_commands(bool wizard, int hotkey)
"<w>Ctrl-P</w> : show Previous messages\n"
"<w>Ctrl-R</w> : Redraw screen\n"
"<w>Ctrl-C</w> : Clear main and level maps\n"
+ "<w>Ctrl-I</w> : annotate the dungeon level\n"
"<w>#</w> : dump character to file\n"
"<w>:</w> : add note (use <w>?:</w> to read notes)\n"
"<w>~</w> : add macro\n"
@@ -1056,7 +1514,17 @@ void list_commands(bool wizard, int hotkey)
"stashes, and <w>Ctrl-E</w> to erase them.\n",
true, true, cmdhelp_textfilter);
+ list_commands_err = "";
show_keyhelp_menu(cols.formatted_lines(), true, false, hotkey);
+
+ if (do_redraw_screen)
+ {
+ clrscr();
+ redraw_screen();
+ }
+
+ if (list_commands_err != "")
+ mpr(list_commands_err.c_str());
}
void list_tutorial_help()
@@ -1145,9 +1613,11 @@ static void list_wizard_commands()
cols.add_formatted(0,
"a : acquirement\n"
"A : set all skills to level\n"
+ "Ctrl-A : generate new Abyss area\n"
"b : controlled blink\n"
"B : banish yourself to the Abyss\n"
"c : card effect\n"
+ "C : (un)curse item\n"
"g : add a skill\n"
"G : banish all monsters\n"
"Ctrl-G : save ghost (bones file)\n"
@@ -1165,11 +1635,11 @@ static void list_wizard_commands()
"r : change character's species\n"
"s : gain 20000 skill points\n"
"S : set skill to level\n"
- "t : tweak object properties\n"
- "T : make a trap\n",
+ "t : tweak object properties\n",
true, true);
cols.add_formatted(1,
+ "T : make a trap\n"
"v : show gold value of an item\n"
"x : gain an experience level\n"
"Ctrl-X : change experience level\n"
diff --git a/crawl-ref/source/command.h b/crawl-ref/source/command.h
index 174acce2f7..b64e4059d0 100644
--- a/crawl-ref/source/command.h
+++ b/crawl-ref/source/command.h
@@ -62,7 +62,8 @@ void show_levelmap_help();
void show_targeting_help();
void show_interlevel_travel_branch_help();
void show_interlevel_travel_depth_help();
-void list_commands(bool wizard, int hotkey = 0);
+void list_commands(bool wizard, int hotkey = 0,
+ bool do_redraw_screen = false);
void list_tutorial_help(void);
// Actually defined in acr.cc; we may want to move this to command.cc
diff --git a/crawl-ref/source/dat/bazaar.des b/crawl-ref/source/dat/bazaar.des
index deb057bff8..5c822348bf 100644
--- a/crawl-ref/source/dat/bazaar.des
+++ b/crawl-ref/source/dat/bazaar.des
@@ -33,6 +33,32 @@ function bazaar_message(e)
e.welcome("You enter an inter-dimensional bazaar!")
end
+function random_bazaar_colour()
+ local colours = {"blue", "red", "lightblue", "magenta", "green"}
+
+ crawl.mpr("#colours = " .. #colours)
+
+ local ret = colours[crawl.random2(#colours) + 1]
+
+ crawl.mpr("ret = " .. ret)
+
+ return ret
+end
+
+function fixup_bazaar()
+ dgn.fixup_stairs("stone_arch", "exit_portal_vault")
+ dgn.floor_halo("enter_shop", "yellow")
+
+ if (dgn.get_floor_colour() == "black") then
+ dgn.change_floor_colour(random_bazaar_colour())
+ end
+
+ if (dgn.get_rock_colour() == "black") then
+ dgn.change_rock_colour("yellow")
+ end
+end
+
+dgn.set_lt_callback("bazaar", "fixup_bazaar")
}}
default-depth: D:10-27
@@ -174,7 +200,10 @@ ENDMAP
# upstair, which will be converted into a stone arch (and on which the player
# will be placed when entering the bazaar). If there's no upstair, the player
# will arrive on a random square.
-
+#
+# You can force a particular colour for the rock walls or floor using
+# ROCKCOL and FLOORCOL directives.
+#
NAME: bazaar_general_marketplace
TAGS: bazaar allow_dup
FLAGS: no_rotate
@@ -253,10 +282,12 @@ ITEM: any jewellery / good_item any jewellery
ITEM: any book / good_item any book, any staff
SUBST: d=.d, e=.e, f=.f
# special cases for blue/red floor
-: if you.bazaar_floor() == "red" then
+: local colour = random_bazaar_colour()
+: _G.floor_colour(colour)
+: if colour == "red" then
SUBST: l = w
: else
-: if you.bazaar_floor() == "blue" then
+: if colour == "blue" then
SUBST: w = l
: end
: end
@@ -284,10 +315,12 @@ KFEAT: B = distillery shop
ITEM: any wand, ring of levitation
SHUFFLE: leAB/wdBA
# special cases for blue/red floor
-: if you.bazaar_floor() == "red" then
+: local colour = random_bazaar_colour()
+: _G.floor_colour(colour)
+: if colour == "red" then
SUBST: l = w
: else
-: if you.bazaar_floor() == "blue" then
+: if colour == "blue" then
SUBST: w = l
: end
: end
@@ -338,11 +371,13 @@ SUBST: y=z, r=z, s=z, z=V, Y=Z, R=Z, S=Z
KFEAT: Z = stone_arch
SHUFFLE: lw
# special cases for blue/red floor
-: if you.bazaar_floor() == "red" then
-SUBST: l : wWx
+: local colour = random_bazaar_colour()
+: _G.floor_colour(colour)
+: if colour == "red" then
+SUBST: l = w
: else
-: if you.bazaar_floor() == "blue" then
-SUBST: w : Wx
+: if colour == "blue" then
+SUBST: w = l
: end
: end
#
@@ -379,11 +414,13 @@ KFEAT: Z = stone_arch
SUBST: a=T, z=V
SHUFFLE: lw
# special cases for blue/red floor
-: if you.bazaar_floor() == "red" then
-SUBST: l : wWx
+: local colour = random_bazaar_colour()
+: _G.floor_colour(colour)
+: if colour == "red" then
+SUBST: l = w
: else
-: if you.bazaar_floor() == "blue" then
-SUBST: w : Wx
+: if colour == "blue" then
+SUBST: w = l
: end
: end
#
@@ -404,7 +441,6 @@ ENDMAP
#######################################
# circle bazaar
#
-
NAME: bazaar_circle_1
CHANCE: 2
TAGS: bazaar allow_dup
@@ -705,8 +741,10 @@ KFEAT: D = antique weapon shop
KFEAT: E = antique armour shop
KFEAT: F = scroll shop / distillery shop
: bazaar_message(_G)
-# special case for floor
-: if you.bazaar_floor() == "blue" then
+# special cases for blue floor
+: local colour = random_bazaar_colour()
+: _G.floor_colour(colour)
+: if colour == "blue" then
SUBST: w = W
: end
#
@@ -829,10 +867,12 @@ SHUFFLE: zZ
SUBST: z = ., Z = w
SHUFFLE: wl, ABCD
# special cases for blue/red floor
-: if you.bazaar_floor() == "red" then
+: local colour = random_bazaar_colour()
+: _G.floor_colour(colour)
+: if colour == "red" then
SUBST: l = w
: else
-: if you.bazaar_floor() == "blue" then
+: if colour == "blue" then
SUBST: w = l
: end
: end
diff --git a/crawl-ref/source/dat/clua/lm_1way.lua b/crawl-ref/source/dat/clua/lm_1way.lua
index e6e56beced..35fd85a522 100644
--- a/crawl-ref/source/dat/clua/lm_1way.lua
+++ b/crawl-ref/source/dat/clua/lm_1way.lua
@@ -20,7 +20,7 @@ end
function OneWayStair:event(marker, ev)
if ev:type() == dgn.dgn_event_type('player_climb') then
local x, y = ev:pos()
- dgn.terrain_changed(x, y, 'floor', false)
+ dgn.terrain_changed(x, y, self.props.floor or 'floor', false)
dgn.remove_listener(marker, ev:pos())
dgn.remove_marker(marker)
end
diff --git a/crawl-ref/source/dat/clua/lm_flags.lua b/crawl-ref/source/dat/clua/lm_flags.lua
new file mode 100644
index 0000000000..770c80110e
--- /dev/null
+++ b/crawl-ref/source/dat/clua/lm_flags.lua
@@ -0,0 +1,347 @@
+---------------------------------------------------------------------------
+-- lm_flags.lua
+-- Changing level flags and branch flags
+--------------------------------------------------------------------------
+
+--------------------------------------------------------------------------
+-- There are three different types of pre-packaged "change level and
+-- branch flags" marker types. All three share the following parameters:
+--
+-- * level_flags: A space separated list of level flag names to set or unset.
+-- To unset a flag, prefix the name with "!".
+--
+-- * branch_flags: Like level_flags, but for branch flags to set or unset.
+--
+-- * group: Different flag change markers on the same level can be put
+-- into the same group by giving them the same group name.
+-- Of all of the markers in the same group, only the last one
+-- to have its conditions met will cause the flags to change.
+-- This is useful if, for example, there are two magical fountains,
+-- and you only want the flags to change when both dry up.
+--
+-- * msg: A message to give the user when the flags are changed; suppress
+-- any messages Crawl would normally give for the changes effected.
+-- The message is not given if nothing is changed (i.e., if all
+-- the flags to be set were already set and all the flags to be
+-- unset were already unset).
+--
+-- The three different marker types can be created with the following
+-- functions:
+--
+-- * mons_dies_change_flags(): Creates a marker which changes the flags
+-- when a named monster dies. Accepts the parameter "mon_name"
+-- as the name of the monster to watch. The marker can be
+-- placed anywhere on the level, and doesn't have to be near the
+-- monster when it dies.
+--
+-- * feat_change_change_flags(): Creates a marker which acts when the
+-- feature of its grid changes. Accepts the optional string
+-- parameter "final_feat", which will cause the change to only
+-- take place when the changed feature contains final_feat as
+-- a substring. For example, a sparkling fountain can dry up
+-- either by turning directly into a dry_fountain_ii feature,
+-- or by first turning into a blue_fountain feature, and then
+-- into a dry_fountain_i feature. Without final_feat, the
+-- flags will change if the sparkling fountain changes into
+-- a blue fountain. However, if "final_feat" is set to
+-- "dry_fountain", the marker will ignore the feature turning
+-- into blue_fountain, and will only act when it changes into
+-- dry_fountain_i or dry_fountain_ii
+--
+-- * item_pickup_change_flags(): Creates a marker which acts when
+-- an item on its grid gets picked up. Accepts the parameter
+-- "item", which is the plain name of the item its watching
+-- (i.e., "Orb of Zot" and "golden rune" rather than "the Orb of Zot"
+-- or "a golden rune").
+--------------------------------------------------------------------------
+
+ChangeFlags = { }
+ChangeFlags.__index = ChangeFlags
+
+function ChangeFlags:_new()
+ local cf = { }
+ setmetatable(cf, self)
+ self.__index = self
+
+ return cf
+end
+
+function ChangeFlags:new(pars)
+ pars = pars or { }
+
+ pars.level_flags = pars.level_flags or ""
+ pars.branch_flags = pars.branch_flags or ""
+ pars.msg = pars.msg or ""
+
+ if not (pars.level_flags ~= "" or pars.branch_flags ~= "") then
+ error("Must provide at least one of level_flags or branch_flags.")
+ end
+
+ local cf = self:_new()
+ cf.level_flags = pars.level_flags
+ cf.branch_flags = pars.branch_flags
+ cf.msg = pars.msg
+ cf.props = { flag_group = pars.group }
+
+ return cf
+end
+
+function ChangeFlags:do_change(marker)
+ local did_change1 = false
+ local did_change2 = false
+ local silent = self.msg and self.msg ~= ""
+
+ if self.props.flag_group and self.props.flag_group ~= "" then
+ local num_markers = dgn.num_matching_markers("flag_group",
+ self.props.group)
+
+ if num_markers > 1 then
+ return false, false
+ end
+ end
+
+ if self.level_flags and self.level_flags ~= "" then
+ did_change1 = dgn.change_level_flags(self.level_flags, silent)
+ end
+
+ if self.branch_flags and self.branch_flags ~= "" then
+ did_change2 = dgn.change_branch_flags(self.branch_flags, silent)
+ end
+
+ if did_change1 or did_change2 then
+ if self.msg and self.msg ~= "" then
+ crawl.mpr(self.smg)
+ end
+
+ return true, true
+ end
+
+ return true, false
+end
+
+function ChangeFlags:property(marker, pname)
+ return self.props[pname] or ''
+end
+
+function ChangeFlags:write(marker, th)
+ file.marshall(th, self.level_flags)
+ file.marshall(th, self.branch_flags)
+ file.marshall(th, self.msg)
+ lmark.marshall_table(th, self.props)
+end
+
+function ChangeFlags:read(marker, th)
+ self.level_flags = file.unmarshall_string(th)
+ self.branch_flags = file.unmarshall_string(th)
+ self.msg = file.unmarshall_string(th)
+ self.props = lmark.unmarshall_table(th)
+ setmetatable(self, ChangeFlags)
+
+ return self
+end
+
+--------------------------------------------------------------------------
+--------------------------------------------------------------------------
+
+MonDiesChangeFlags = ChangeFlags:_new()
+MonDiesChangeFlags.__index = MonDiesChangeFlags
+
+function MonDiesChangeFlags:_new(pars)
+ local mdcf
+
+ if pars then
+ mdcf = ChangeFlags:new(pars)
+ else
+ mdcf = ChangeFlags:_new()
+ end
+
+ setmetatable(mdcf, self)
+ self.__index = self
+
+ return mdcf
+end
+
+function MonDiesChangeFlags:new(pars)
+ pars = pars or { }
+
+ if not pars.mon_name then
+ error("No monster name provided.")
+ end
+
+ local mdcf = self:_new(pars)
+ mdcf.mon_name = pars.mon_name
+
+ return mdcf
+end
+
+function MonDiesChangeFlags:activate(marker)
+ dgn.register_listener(dgn.dgn_event_type('monster_dies'), marker)
+end
+
+function MonDiesChangeFlags:event(marker, ev)
+ local midx = ev:arg1()
+ local mons = dgn.mons_from_index(midx)
+
+ if not mons then
+ error("MonDiesChangeFlags:event() didn't get a valid monster index")
+ end
+
+ if mons.name == self.mon_name then
+ ChangeFlags.do_change(self, marker)
+ dgn.remove_listener(marker)
+ dgn.remove_marker(marker)
+ end
+end
+
+function MonDiesChangeFlags:write(marker, th)
+ ChangeFlags.write(self, marker, th)
+ file.marshall(th, self.mon_name)
+end
+
+function MonDiesChangeFlags:read(marker, th)
+ ChangeFlags.read(self, marker, th)
+ self.mon_name = file.unmarshall_string(th)
+ setmetatable(self, MonDiesChangeFlags)
+
+ return self
+end
+
+function mons_dies_change_flags(pars)
+ return MonDiesChangeFlags:new(pars)
+end
+
+-----------------------------------------------------------------------------
+-----------------------------------------------------------------------------
+FeatChangeChangeFlags = ChangeFlags:_new()
+FeatChangeChangeFlags.__index = FeatChangeChangeFlags
+
+function FeatChangeChangeFlags:_new(pars)
+ local fccf
+
+ if pars then
+ fccf = ChangeFlags:new(pars)
+ else
+ fccf = ChangeFlags:_new()
+ end
+
+ setmetatable(fccf, self)
+ self.__index = self
+
+ return fccf
+end
+
+function FeatChangeChangeFlags:new(pars)
+ pars = pars or { }
+
+ local fccf = self:_new(pars)
+
+ fccf.final_feat = pars.final_feat
+
+ return fccf
+end
+
+function FeatChangeChangeFlags:activate(marker)
+ dgn.register_listener(dgn.dgn_event_type('feat_change'), marker,
+ marker:pos())
+end
+
+function FeatChangeChangeFlags:event(marker, ev)
+ if self.final_feat and self.final_feat ~= "" then
+ local feat = dgn.feature_name(dgn.grid(ev:pos()))
+ if not string.find(feat, self.final_feat) then
+ return
+ end
+ end
+
+ ChangeFlags.do_change(self, marker)
+ dgn.remove_listener(marker, marker:pos())
+ dgn.remove_marker(marker)
+end
+
+function FeatChangeChangeFlags:write(marker, th)
+ ChangeFlags.write(self, marker, th)
+ file.marshall(th, self.final_feat)
+end
+
+function FeatChangeChangeFlags:read(marker, th)
+ ChangeFlags.read(self, marker, th)
+ self.final_feat = file.unmarshall_string(th)
+ setmetatable(self, FeatChangeChangeFlags)
+
+ return self
+end
+
+function feat_change_change_flags(pars)
+ return FeatChangeChangeFlags:new(pars)
+end
+
+--------------------------------------------------------------------------
+--------------------------------------------------------------------------
+
+ItemPickupChangeFlags = ChangeFlags:_new()
+ItemPickupChangeFlags.__index = ItemPickupChangeFlags
+
+function ItemPickupChangeFlags:_new(pars)
+ local ipcf
+
+ if pars then
+ ipcf = ChangeFlags:new(pars)
+ else
+ ipcf = ChangeFlags:_new()
+ end
+
+ setmetatable(ipcf, self)
+ self.__index = self
+
+ return ipcf
+end
+
+function ItemPickupChangeFlags:new(pars)
+ pars = pars or { }
+
+ if not pars.item then
+ error("No item name provided.")
+ end
+
+ local ipcf = self:_new(pars)
+ ipcf.item = pars.item
+
+ return ipcf
+end
+
+function ItemPickupChangeFlags:activate(marker)
+ dgn.register_listener(dgn.dgn_event_type('item_pickup'), marker,
+ marker:pos())
+end
+
+function ItemPickupChangeFlags:event(marker, ev)
+ local obj_idx = ev:arg1()
+ local it = dgn.item_from_index(obj_idx)
+
+ if not it then
+ error("ItemPickupChangeFlags:event() didn't get a valid item index")
+ end
+
+ if item.name(it) == self.item then
+ ChangeFlags.do_change(self, marker)
+ dgn.remove_listener(marker, marker:pos())
+ dgn.remove_marker(marker)
+ end
+end
+
+function ItemPickupChangeFlags:write(marker, th)
+ ChangeFlags.write(self, marker, th)
+ file.marshall(th, self.item)
+end
+
+function ItemPickupChangeFlags:read(marker, th)
+ ChangeFlags.read(self, marker, th)
+ self.item = file.unmarshall_string(th)
+ setmetatable(self, ItemPickupChangeFlags)
+
+ return self
+end
+
+function item_pickup_change_flags(pars)
+ return ItemPickupChangeFlags:new(pars)
+end
diff --git a/crawl-ref/source/dat/clua/lm_fog.lua b/crawl-ref/source/dat/clua/lm_fog.lua
new file mode 100644
index 0000000000..d1106101fa
--- /dev/null
+++ b/crawl-ref/source/dat/clua/lm_fog.lua
@@ -0,0 +1,184 @@
+------------------------------------------------------------------------------
+-- lm_tmsg.lua:
+-- Fog machines.
+--
+-- There are three different "pure" ways to use a fog machine marker:
+--
+-- 1) Repeatedly lay down medium to large clouds on top of the marker
+-- and let them pile up on one another. (One of the cloud grids in
+-- the gfirst laid cloud has to decay away before this is this really
+-- starts working.
+--
+-- 2) Perform random walks from the marker and place a single-grid cloud
+-- at the destination of each walk.
+--
+-- 3) Place a single-grid cloud on the marker and let it spread out.
+--
+-- Comibining these different methods, along with varying the differrent
+-- parameters, can be used to achieve different effects.
+--
+-- Marker parameters:
+--
+-- cloud_type: The name of the cloud type to use. Defaults to "thin mist".
+-- walk_dist: The distance to move over the course of one random walk.
+-- defaults to 0.
+-- pow_min: The minimum "power" (lifetime) of each cloud; defaults to 1.
+-- pow_max: The maximum power of each cloud; must be provided.
+-- pow_rolls: The number of rolls of [pow_min, pow_max], with the average
+-- value uses; increasing the values makes the average value more likely
+-- and exterme values less likely. Defaults to 1.
+-- delay, delay_min and delay_max: The delay between laying down one cloud
+-- and the next. 10 is equal to normal-speed player turn. Either
+-- delay or delay_max and delay_min must be provided. Providing just
+-- "delay" is equivalent to delay_min and delay_max being equal.
+-- size, size_min and size_max: The number of grids each cloud will cover.
+-- Either size or size_max and size_min must be provided. Providing
+-- just "size" is equivalent to size_min and size_max being equal.
+-- spread_rate: The rate at which a cloud spreads. Must either be
+-- -1 (default spread rate that varies by cloud type) or between
+-- 0 and 100 inclusive.
+-- start_clouds: The number of clouds to lay when the level containing
+-- the cloud machine is entered. This is necessary since clouds
+-- are cleared when the player leaves a level.
+------------------------------------------------------------------------------
+
+FogMachine = { }
+FogMachine.__index = FogMachine
+
+function FogMachine:_new()
+ local m = { }
+ setmetatable(m, self)
+ self.__index = self
+ return m
+end
+
+function FogMachine:new(pars)
+ if not pars then
+ error("No parameters provided")
+ end
+
+ if not pars.pow_max then
+ error("No pow_max provided.")
+ end
+
+ if not (pars.delay or (pars.delay_min and pars.delay_max)) then
+ error("Delay parameters not provided.")
+ end
+
+ if not (pars.size or (pars.size_min and pars.size_max)) then
+ error("Size parameters not provided.")
+ end
+
+ local m = FogMachine:_new()
+ m.cloud_type = pars.cloud_type or "thin mist"
+ m.walk_dist = pars.walk_dist or 0
+ m.pow_min = pars.pow_min or 1
+ m.pow_max = pars.pow_max
+ m.pow_rolls = pars.pow_rolls or 3
+ m.delay_min = pars.delay_min or pars.delay or 1
+ m.delay_max = pars.delay_max or pars.delay
+ m.kill_cat = pars.kill_cat or "other"
+ m.size_min = pars.size_min or pars.size or 1
+ m.size_max = pars.size_max or pars.size
+ m.spread_rate = pars.spread_rate or -1
+ m.start_clouds = pars.start_clouds or 1
+ m.countdown = 0
+
+ return m
+end
+
+function FogMachine:do_fog(marker)
+ local x, y = marker:pos()
+ if self.walk_dist > 0 then
+ x, y = dgn.random_walk(x, y, self.walk_dist)
+ end
+
+ dgn.apply_area_cloud(x, y, self.pow_min, self.pow_max, self.pow_rolls,
+ crawl.random_range(self.size_min, self.size_max, 1),
+ self.cloud_type, self.kill_cat, self.spread_rate)
+end
+
+function FogMachine:activate(marker, verbose)
+ local _x, _y = marker:pos()
+ dgn.register_listener(dgn.dgn_event_type('turn'), marker)
+ dgn.register_listener(dgn.dgn_event_type('entered_level'), marker)
+end
+
+function FogMachine:event(marker, ev)
+ local _x, _y = marker:pos()
+ if ev:type() == dgn.dgn_event_type('turn') then
+ self.countdown = self.countdown - ev:ticks()
+
+ while self.countdown <= 0 do
+ self:do_fog(marker)
+ self.countdown = self.countdown +
+ crawl.random_range(self.delay_min, self.delay_max, 1)
+ end
+ elseif ev:type() == dgn.dgn_event_type('entered_level') then
+ for i = 1, self.start_clouds do
+ self:do_fog(marker)
+ self.countdown = crawl.random_range(self.delay_min, self.delay_max, 1)
+ end
+ end
+end
+
+function FogMachine:write(marker, th)
+ file.marshall(th, self.cloud_type)
+ file.marshall(th, self.walk_dist)
+ file.marshall(th, self.pow_min)
+ file.marshall(th, self.pow_max)
+ file.marshall(th, self.pow_rolls)
+ file.marshall(th, self.delay_min)
+ file.marshall(th, self.delay_max)
+ file.marshall(th, self.kill_cat)
+ file.marshall(th, self.size_min)
+ file.marshall(th, self.size_max)
+ file.marshall(th, self.spread_rate)
+ file.marshall(th, self.start_clouds)
+ file.marshall(th, self.countdown)
+end
+
+function FogMachine:read(marker, th)
+ self.cloud_type = file.unmarshall_string(th)
+ self.walk_dist = file.unmarshall_number(th)
+ self.pow_min = file.unmarshall_number(th)
+ self.pow_max = file.unmarshall_number(th)
+ self.pow_rolls = file.unmarshall_number(th)
+ self.delay_min = file.unmarshall_number(th)
+ self.delay_max = file.unmarshall_number(th)
+ self.kill_cat = file.unmarshall_string(th)
+ self.size_min = file.unmarshall_number(th)
+ self.size_max = file.unmarshall_number(th)
+ self.spread_rate = file.unmarshall_number(th)
+ self.start_clouds = file.unmarshall_number(th)
+ self.countdown = file.unmarshall_number(th)
+
+ setmetatable(self, FogMachine)
+
+ return self
+end
+
+function fog_machine(pars)
+ return FogMachine:new(pars)
+end
+
+function fog_machine_geyser(cloud_type, size, power)
+ return FogMachine:new {
+ cloud_type = cloud_type, pow_max = power, size = size,
+ delay_min = power , delay_max = power * 2
+ }
+end
+
+function fog_machine_spread(cloud_type, size, power)
+ return FogMachine:new {
+ cloud_type = cloud_type, pow_max = power, spread_rate = size,
+ size = 1, delay_min = 5, delay_max = 15
+ }
+end
+
+function fog_machine_brownian(cloud_type, size, power)
+ return FogMachine:new {
+ cloud_type = cloud_type, size = 1, pow_max = power,
+ walk_dist = size, delay_min = 1, delay_max = power / size
+ }
+end
diff --git a/crawl-ref/source/dat/clua/lm_pdesc.lua b/crawl-ref/source/dat/clua/lm_pdesc.lua
index 5b02247fa2..a704004872 100644
--- a/crawl-ref/source/dat/clua/lm_pdesc.lua
+++ b/crawl-ref/source/dat/clua/lm_pdesc.lua
@@ -14,12 +14,10 @@ function PortalDescriptor:new(properties)
end
function PortalDescriptor:write(marker, th)
- file.marshall(th, self.desc or '')
lmark.marshall_table(th, self.props)
end
function PortalDescriptor:read(marker, th)
- self.desc = file.unmarshall_string(th)
self.props = lmark.unmarshall_table(th)
setmetatable(self, PortalDescriptor)
return self
@@ -33,6 +31,6 @@ function PortalDescriptor:property(marker, pname)
return self.props and self.props[pname] or ''
end
-function portal_desc(desc, props)
- return PortalDescriptor:new(desc, props)
+function portal_desc(props)
+ return PortalDescriptor:new(props)
end
diff --git a/crawl-ref/source/dat/clua/luamark.lua b/crawl-ref/source/dat/clua/luamark.lua
index 58eeda6c68..cc677f18c1 100644
--- a/crawl-ref/source/dat/clua/luamark.lua
+++ b/crawl-ref/source/dat/clua/luamark.lua
@@ -6,6 +6,8 @@
dofile('clua/lm_pdesc.lua')
dofile('clua/lm_1way.lua')
dofile('clua/lm_timed.lua')
+dofile('clua/lm_flags.lua')
+dofile('clua/lm_fog.lua')
function dlua_marker_function(table, name)
return table[name]
diff --git a/crawl-ref/source/dat/descript/features.txt b/crawl-ref/source/dat/descript/features.txt
index 897ab8c343..b7154b9d6e 100644
--- a/crawl-ref/source/dat/descript/features.txt
+++ b/crawl-ref/source/dat/descript/features.txt
@@ -85,6 +85,9 @@ A magical trap
A mechanical trap
%%%%
+A natural trap
+
+%%%%
A metal wall
A wall of bluish-grey metal.
@@ -217,7 +220,16 @@ A stone staircase leading up
%%%%
A stone wall
-A harder obstacle than rock walls. Only the mightiest magic can shatter stone walls.
+A harder obstacle than rock walls. Only the mightiest magic can shatter stone walls.
+%%%%
+A translucent rock wall
+
+An unnaturally hard translucent rock wall
+%%%%
+A translucent stone wall
+
+A harder obstacle than rock walls. Only the mightiest magic can shatter stone walls. It has been imbued with arcane magics which render it translucent.
+
%%%%
A trap
diff --git a/crawl-ref/source/dat/descript/monsters.txt b/crawl-ref/source/dat/descript/monsters.txt
index 0f3abbc2f9..287cc849c0 100644
--- a/crawl-ref/source/dat/descript/monsters.txt
+++ b/crawl-ref/source/dat/descript/monsters.txt
@@ -1,4 +1,21 @@
%%%%
+__cap-N_suffix
+
+$"The insensible son of Pandu sank down till he reached the Naga kingdom.
+Nagas, furnished with fangs containing virulent venom, bit him by
+thousands. The vegetable poison, mingled in the blood of the son of the
+Wind god, was neutralised by the snake-poison. The serpents had bitten
+all over his frame, except his chest, the skin of which was so tough that
+their fangs could not penetrate it.
+"On regaining consciousness, the son of Kunti burst his bands and began
+to press the snakes down under the ground. A remnant fled for life, and
+going to their king Vasuki, represented, 'O king of snakes, a man drowned
+under the water, bound in chords of shrubs; probably he had drunk poison.
+For when he fell amongst us, he was insensible. But when we began to bite
+him, he regained his senses, and bursting his fetters, commenced laying
+at us. May it please Your Majesty to enquire who is.'"
+ -_The Mahabharata, Sambhava Parva, Section CXXVIII
+%%%%
&
You feel a lump in the pit of your stomach.
@@ -89,16 +106,28 @@ A svelte fighter-mage, wearing a gold-rimmed monocle.
%%%%
Geryon
-A huge and slithery arch-demon, guarding the gates of Hell.
+A huge, winged arch-demon, guardian of the gates of Hell.
%%%%
Gloorx Vloq
A shadowy figure clothed in profound darkness.
%%%%
+greater naga
+
+A hybrid; human from the chest up, with a scaly, muscular torso trailing off like that of a snake.
+
+It looks strong and aggressive.
+%%%%
Green Death
A bloated form covered in oozing sores and exhaling clouds of lethal poison.
%%%%
+guardian naga
+
+A hybrid; human from the chest up, with a scaly, muscular torso trailing off like that of a snake.
+
+These nagas are often used as guardians by powerful creatures.
+%%%%
Harold
An evil human bounty hunter.
@@ -171,6 +200,10 @@ Orb Guardian
A huge and glowing purple creature, created by the Orb to defend itself.
%%%%
+pandemonium lord
+
+Powerful demons inhabiting the endless halls of Pandemonium, each is different, with its own set of strengths and weaknesses.
+%%%%
Pit Fiend
A huge winged fiend with incredibly tough skin.
@@ -894,7 +927,7 @@ stuck in its teeth.
%%%%
large skeleton
-A skeleton compelled to unlife by the exercise of necromancy.
+A large skeleton compelled to unlife by the exercise of necromancy.
%%%%
large zombie
@@ -935,6 +968,17 @@ A hideous cross-breed, bearing the features of a human and a lion, with great ba
"Ctesias writeth, that in Æthiopia likewise there is a beast which he calleth Mantichora, having three rankes of teeth, which when they meet togither are let in one within another like the teeth of combes: with the face and eares of a man, with red eyes; of colour sanguine, bodied like a lyon, and having a taile armed with a sting like a scorpion: his voice resembleth the noise of a flute and trumpet sounded together: very swift he is, and mans flesh of all others hee most desireth."
-Pliny the Elder, _Natural History_, Book 8, Chapter XXI
%%%%
+merfolk fighter
+
+Half fish, half man, the merfolk are citizens of both water and land, and they'll fiercely protect their chosen territory.
+%%%%
+mermaid
+
+A young woman with a fish tail in place of legs. Mermaids love to sing and charm their audience.
+
+... To the Sirens first shalt thou come, who beguile all men whosoever comes to them. Whoso in ignorance draws near to them and hears the Sirens' voice, he nevermore returns, that his wife and little children may stand at his side rejoicing, but the Sirens beguile him with their clear-toned song, as they sit in a meadow, and about them is a great heap of bones of mouldering men, and round the bones the skin is shrivelling.
+ -Homer, _The Odyssey_, Book XII
+%%%%
metal gargoyle
A hideous metal statue come to life.
@@ -978,21 +1022,18 @@ The embalmed and undead corpse of an ancient servant of darkness.
naga
A hybrid; human from the chest up, with a scaly, muscular torso trailing off like that of a snake.
+%%%%
+naga mage
-"The insensible son of Pandu sank down till he reached the Naga kingdom.
-Nagas, furnished with fangs containing virulent venom, bit him by
-thousands. The vegetable poison, mingled in the blood of the son of the
-Wind god, was neutralised by the snake-poison. The serpents had bitten
-all over his frame, except his chest, the skin of which was so tough that
-their fangs could not penetrate it.
-"On regaining consciousness, the son of Kunti burst his bands and began
-to press the snakes down under the ground. A remnant fled for life, and
-going to their king Vasuki, represented, 'O king of snakes, a man drowned
-under the water, bound in chords of shrubs; probably he had drunk poison.
-For when he fell amongst us, he was insensible. But when we began to bite
-him, he regained his senses, and bursting his fetters, commenced laying
-at us. May it please Your Majesty to enquire who is.'"
- -_The Mahabharata, Sambhava Parva, Section CXXVIII
+A hybrid; human from the chest up, with a scaly, muscular torso trailing off like that of a snake.
+
+An eldritch nimbus trails its motions.
+%%%%
+naga warrior
+
+A hybrid; human from the chest up, with a scaly, muscular torso trailing off like that of a snake.
+
+It bears scars of many past battles.
%%%%
necromancer
@@ -1160,6 +1201,10 @@ redback
A vicious black spider with a splash of red on its swollen abdomen. Its mandibles drip with lethal poison.
%%%%
+rock worm
+
+A large worm which moves through rock as if it were air.
+%%%%
rock troll
An enormous and very nasty-looking humanoid creature. Its rocky hide seems to heal almost instantaneously from most wounds.
@@ -1246,6 +1291,14 @@ small snake
The lesser dungeon snake.
%%%%
+small skeleton
+
+A skeleton compelled to unlife by the exercise of necromancy.
+%%%%
+small zombie
+
+A corpse raised to undeath by necromancy.
+%%%%
smoke demon
A writhing cloud of smoke hanging in the air.
@@ -1318,7 +1371,7 @@ swamp worm
A large slimy worm, adept at swimming through the muck of this foul swamp.
%%%%
-tentacled monster
+tentacled monstrosity
A writhing mass of tentacles, all covered in putrid mucus.
%%%%
@@ -1462,7 +1515,3 @@ ynoxinul
A demon with shiny metallic scales.
%%%%
-zombie
-
-A corpse raised to undeath by necromancy.
-%%%%
diff --git a/crawl-ref/source/dat/descript/spells.txt b/crawl-ref/source/dat/descript/spells.txt
index 0c6ae8dc1d..260dd97757 100644
--- a/crawl-ref/source/dat/descript/spells.txt
+++ b/crawl-ref/source/dat/descript/spells.txt
@@ -471,7 +471,7 @@ Portal
This spell 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.
%%%%
-Portaled Projectile
+Portal Projectile
This spell teleports a fired or thrown missile directly to its target, greatly increasing its accuracy (but not damage).
%%%%
diff --git a/crawl-ref/source/dat/glass.des b/crawl-ref/source/dat/glass.des
new file mode 100644
index 0000000000..7d7bd28039
--- /dev/null
+++ b/crawl-ref/source/dat/glass.des
@@ -0,0 +1,153 @@
+###########################################################################
+# Small areas with translucent rock (glass) columns which you can duck
+# behind, but still see the monster you're ducking from (and they can
+# still see you
+NAME: glass_columns_a
+DEPTH:
+MAP
+.....
+.m.m.
+.....
+.m.m.
+.....
+ENDMAP
+
+NAME: glass_columns_b
+DEPTH:
+MAP
+.......
+.m.m.m.
+.......
+.m.m.m.
+.......
+.m.m.m.
+.......
+ENDMAP
+
+NAME: glass_columns_c
+DEPTH:
+MAP
+.........
+.m.m.m.m.
+.........
+.m.m.m.m.
+.........
+.m.m.m.m.
+.........
+.m.m.m.m.
+.........
+ENDMAP
+
+##########################################################
+# A feature encased in glass, for flavour.
+NAME: feat_on_display
+DEPTH:
+SUBST: ? = TUl
+TAGS: no_monster_gen no_item_gen
+MAP
+.....
+.mmm.
+.m?m.
+.mmm.
+.....
+ENDMAP
+
+#######################################################################
+# An item encased in glass. If the player wants it, it can be dug out.
+NAME: item_on_display_a
+DEPTH:
+TAGS: no_monster_gen no_item_gen
+MAP
+.....
+.mmm.
+.m%m.
+.mmm.
+.....
+ENDMAP
+
+#####################################################################
+# A good item encased in *permanent* glass. If the player wants it,
+# teleport control will be needed.
+NAME: item_on_display_b
+DEPTH:
+TAGS: no_monster_gen no_item_gen
+MAP
+.....
+.ooo.
+.o*o.
+.ooo.
+.....
+ENDMAP
+
+#####################################################################
+# An average monster in a cage of glass; can get out if it has the
+# ability to dig or blink like a blink-frog. Also, the player can
+# dig it out.
+NAME: caged_monster_a
+DEPTH: D, Elf, Snake, Vault
+MAP
+.....
+.mmm.
+.m0m.
+.mmm.
+.....
+ENDMAP
+
+############################################################################
+# Entry vaults using translucent (glass) walls
+
+# A spiral made entirely of glass
+
+NAME: glass_entry_001
+TAGS: entry
+ORIENT: float
+SHUFFLE: {[(<
+SUBST: < = .
+MAP
+mmmmmmmmmmmmmmmmmm
+m................m
+m.mmmmmmmmmmmmmm.m
+m.m............m.m
+m.m.mmmmmmmmmm.m.m
+m.m.m........m.m.m
+m.m.m.mmmmmm.m.m.m
+m.m.m.m....m.m.m.m
+m.m.m.m.mm.m.m.m.m
+m.m.m.m{[m.m.m.m.m
+m.m.m.m(<m.m.m.m.m
+m.m.m.mmmm.m.m.m.m
+m.m.m......m.m.m.m
+m.m.mmmmmmmm.m.m.m
+m.m..........m.m.m
+m.mmmmmmmmmmmm.m.m
+m..............m.m
+mmmmmmmmmmmmmmmm@m
+ENDMAP
+
+# A spiral made of rock, with lots of "windows".
+
+NAME: glass_entry_002
+TAGS: entry
+ORIENT: float
+SHUFFLE: {[(<
+SUBST: < = .
+MAP
+mxmxmxmxmxmxxmxxmx
+x................m
+m.xmxmxmxmxmxmxm.x
+x.m............x.m
+m.x.mxmxmxmxmx.m.x
+x.m.x........m.x.m
+m.x.m.xmxmxx.x.m.x
+x.m.x.m....x.m.x.m
+m.x.m.x.mx.m.x.m.x
+x.m.x.m{[m.x.m.x.m
+m.x.m.x(<x.m.x.m.x
+x.m.x.xmxx.x.m.x.m
+m.x.m......m.x.m.x
+x.m.xxmxmxmx.m.x.m
+m.x..........x.m.x
+x.xmxmxmxmxmxm.x.m
+m..............m.x
+xxmxmxmxmxmxmxmx@m
+ENDMAP
diff --git a/crawl-ref/source/dat/lab.des b/crawl-ref/source/dat/lab.des
index 64968410b0..9feb52c483 100644
--- a/crawl-ref/source/dat/lab.des
+++ b/crawl-ref/source/dat/lab.des
@@ -100,6 +100,28 @@ MAP
ENDMAP
#############################################################################
+# Hidden exit, and trapped loot
+NAME: labyrinth_hidden_loot
+TAGS: minotaur generate_loot allow_dup
+MONS: minotaur
+NSUBST: d = 1 / %
+SUBST: c : cvv
+MAP
+............
+.cccccccccc.
+.cxxxxdxxxc.
+.cxxxx=xxxc.
+.cxx..U.xxc.
+.cd=U...xxc.
+.cxx...U=dc.
+.cxx.<..xxc.
+.cxxxx+xxxc.
+.cxxxx.xxxc.
+.ccccc+cccc.
+............
+ENDMAP
+
+#############################################################################
# Mini labyrinth exit
NAME: labyrinth_mini_lab
TAGS: minotaur generate_loot allow_dup
@@ -157,7 +179,7 @@ ENDMAP
#############################################################################
# Another trapped exit - most evil again!
NAME: labyrinth_trapped_2
-TAGS: minotaur allow_dup generate_loot
+TAGS: lab allow_dup generate_loot
ITEM: potion of porridge
SHUFFLE: XYZ
SHUFFLE: GH, LM, fghijklmn, FHIJKLN
diff --git a/crawl-ref/source/dat/large.des b/crawl-ref/source/dat/large.des
index 7618f9c8ee..85dde7a2b0 100644
--- a/crawl-ref/source/dat/large.des
+++ b/crawl-ref/source/dat/large.des
@@ -202,7 +202,8 @@ SUBST: . = .:100 !:1 6:4
SUBST: ; = .:200 !:1 1:3
SUBST: 1 = 1:20 .
SUBST: 3 = 3:20 .
-KFEAT: ! = amnesia trap
+#KFEAT: ! = amnesia trap
+KFEAT: ! = ^
MONS: plant
MONS: wolf/warg/hell hound
MONS: nothing
@@ -220,7 +221,7 @@ KMONS: C = lich w:20/shadow fiend
SUBST: b = b|
SUBST: | = |*
SUBST: _ = x=
-ITEM: scroll of forgetfulness, potion of experience
+ITEM: any scroll, potion of experience
SHUFFLE: dD/eE/fF/gG
SUBST: D==, d=|, E=x, e=%%*, F=x, f=%, G=x, g=%
SHUFFLE: PQ
diff --git a/crawl-ref/source/dat/levdes.vim b/crawl-ref/source/dat/levdes.vim
index 181ba61ffa..980cf277f2 100644
--- a/crawl-ref/source/dat/levdes.vim
+++ b/crawl-ref/source/dat/levdes.vim
@@ -51,11 +51,24 @@ syn region desNsubst start=/^NSUBST:\s*/ end=/$/ contains=desNsubstDec,desSubstA
syn region desShuffle start=/^SHUFFLE:\s*/ end=/$/ contains=desShuffleDec,desMapFrag keepend
-syn keyword desDeclarator NAME: ORIENT: DEPTH: PLACE: MONS: FLAGS: default-depth: TAGS: CHANCE: WEIGHT: ITEM: KFEAT: KMONS: KITEM: COLOUR:
-syn keyword desOrientation encompass north south east west northeast northwest southeast southwest float no_hmirror no_vmirror no_rotate entry pan no_pool_fixup no_monster_gen generate_awake mini_float no_item_gen
+syn keyword desDeclarator NAME: ORIENT: DEPTH: PLACE: MONS: FLAGS: default-depth: TAGS: CHANCE: WEIGHT: ITEM: KFEAT: KMONS: KITEM: COLOUR: KMASK: MARKER: LFLAGS: BFLAGS: ROCKCOL: FLOORCOL:
+syn keyword desOrientation encompass north south east west northeast northwest southeast southwest float
+syn keyword desOrientation no_hmirror no_vmirror no_rotate
+syn keyword desOrientation entry pan lab bazaar allow_dup dummy mini_float minotaur
+syn keyword desOrientation no_pool_fixup no_monster_gen generate_awake no_item_gen no_tele_control not_mappable no_magic_map no_secret_doors generate_loot
+syn keyword desOrientation Temple Orc Elf Lair Swamp Shoal Slime Snake Hive Vault Blade Crypt Tomb Hell Dis Geh Coc Tar
+syn keyword desOrientation D: contained
syn match desComment "^\s*#.*$"
+syn match desEntry "\<\w*_entry\>"
+" 'transparent' is a Vim syntax keyword???
+syn match desTransparent "transparent"
+syn match desRange "\d*-\d*"
+syn match desNumber "\s\d*"
+syn match desWeight "w:\d*"
+syn match desSlash "/"
+
syn keyword desMapBookend MAP ENDMAP contained
syn match desMapFloor /\./ contained
syn match desMapWall /x/ contained
@@ -102,8 +115,15 @@ hi link desLuaBlockEnd Statement
hi link desComment Comment
hi link desMap String
hi link desSubstArg String
-hi link desSubstSep Type
+hi link desRange String
+hi link desEntry Type
+hi link desNumber String
+hi link desWeight String
+hi link desSlash Comment
+
+hi link desSubstSep Type
hi link desOrientation Type
+hi link desTransparent Type
hi desMapWall guifg=darkgray term=bold gui=bold ctermfg=brown
hi desMapCrystalWall guifg=#009040 term=bold gui=bold ctermfg=green
diff --git a/crawl-ref/source/dat/speak.txt b/crawl-ref/source/dat/speak.txt
index cfc5548958..bd558d162d 100644
--- a/crawl-ref/source/dat/speak.txt
+++ b/crawl-ref/source/dat/speak.txt
@@ -1898,7 +1898,7 @@ weapon_sings
@The_weapon@ merrily whistles a melody.
-In a hysteric voice, @the_weapon@ strikes up a march.
+In a hysterical voice, @the_weapon@ strikes up a march.
@The_weapon@ sings @several@ chords at once.
@@ -1912,7 +1912,7 @@ In a hysteric voice, @the_weapon@ strikes up a march.
@The_weapon@ strikes up a @dance@.
-@The_weapon@ intonates @an_aria_or_fugue@.
+@The_weapon@ intones @an_aria_or_fugue@.
@The_weapon@ @nearly_or_clearly@ @hits_or_misses@ the concert pitch.
@@ -2304,4 +2304,4 @@ double_or_triple
double
triple
-%%%% \ No newline at end of file
+%%%%
diff --git a/crawl-ref/source/database.cc b/crawl-ref/source/database.cc
index f8c97a354c..0e9b598f9c 100644
--- a/crawl-ref/source/database.cc
+++ b/crawl-ref/source/database.cc
@@ -152,6 +152,63 @@ datum database_fetch(DBM *database, const std::string &key)
return result;
}
+std::vector<std::string> database_find_keys(DBM *database,
+ const std::string &regex,
+ bool ignore_case,
+ db_find_filter filter)
+{
+ text_pattern tpat(regex, ignore_case);
+ std::vector<std::string> matches;
+
+ datum dbKey = dbm_firstkey(database);
+
+ while (dbKey.dptr != NULL)
+ {
+ std::string key((const char *)dbKey.dptr, dbKey.dsize);
+
+ if (tpat.matches(key) &&
+ key.find("__") == std::string::npos
+ && (filter == NULL || !(*filter)(key, "")))
+ {
+ matches.push_back(key);
+ }
+
+ dbKey = dbm_nextkey(database);
+ }
+
+ return (matches);
+}
+
+std::vector<std::string> database_find_bodies(DBM *database,
+ const std::string &regex,
+ bool ignore_case,
+ db_find_filter filter)
+{
+ text_pattern tpat(regex, ignore_case);
+ std::vector<std::string> matches;
+
+ datum dbKey = dbm_firstkey(database);
+
+ while (dbKey.dptr != NULL)
+ {
+ std::string key((const char *)dbKey.dptr, dbKey.dsize);
+
+ datum dbBody = dbm_fetch(database, dbKey);
+ std::string body((const char *)dbBody.dptr, dbBody.dsize);
+
+ if (tpat.matches(body) &&
+ key.find("__") == std::string::npos
+ && (filter == NULL || !(*filter)(key, body)))
+ {
+ matches.push_back(key);
+ }
+
+ dbKey = dbm_nextkey(database);
+ }
+
+ return (matches);
+}
+
///////////////////////////////////////////////////////////////////////////
// Internal DB utility functions
static void trim_right(std::string &s)
@@ -403,6 +460,30 @@ std::string getLongDescription(const std::string &key)
return std::string((const char *)result.dptr, result.dsize);
}
+std::vector<std::string> getLongDescKeysByRegex(const std::string &regex,
+ db_find_filter filter)
+{
+ if (!descriptionDB)
+ {
+ std::vector<std::string> empty;
+ return (empty);
+ }
+
+ return database_find_keys(descriptionDB, regex, true, filter);
+}
+
+std::vector<std::string> getLongDescBodiesByRegex(const std::string &regex,
+ db_find_filter filter)
+{
+ if (!descriptionDB)
+ {
+ std::vector<std::string> empty;
+ return (empty);
+ }
+
+ return database_find_bodies(descriptionDB, regex, true, filter);
+}
+
static std::vector<std::string> description_txt_paths()
{
std::vector<std::string> txt_file_names;
diff --git a/crawl-ref/source/database.h b/crawl-ref/source/database.h
index e1cb3f230e..09b90364ea 100644
--- a/crawl-ref/source/database.h
+++ b/crawl-ref/source/database.h
@@ -40,7 +40,22 @@ void databaseSystemShutdown();
DBM *openDB(const char *dbFilename);
datum database_fetch(DBM *database, const std::string &key);
-std::string getLongDescription(const std::string &key);
+typedef bool (*db_find_filter)(std::string key, std::string body);
+
+std::vector<std::string> database_find_keys(DBM *database,
+ const std::string &regex,
+ bool ignore_case = false,
+ db_find_filter filter = NULL);
+std::vector<std::string> database_find_bodies(DBM *database,
+ const std::string &regex,
+ bool ignore_case = false,
+ db_find_filter filter = NULL);
+
+std::string getLongDescription(const std::string &key);
+std::vector<std::string> getLongDescKeysByRegex(const std::string &regex,
+ db_find_filter filter = NULL);
+std::vector<std::string> getLongDescBodiesByRegex(const std::string &regex,
+ db_find_filter filter = NULL);
std::string getShoutString(const std::string &monst,
const std::string &suffix = "");
diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc
index 532448dbc5..e6c0eb867b 100644
--- a/crawl-ref/source/debug.cc
+++ b/crawl-ref/source/debug.cc
@@ -82,6 +82,7 @@
#include "skills2.h"
#include "spl-cast.h"
#include "spl-util.h"
+#include "state.h"
#include "stuff.h"
#include "terrain.h"
#include "traps.h"
@@ -331,7 +332,11 @@ void cast_spec_spell(void)
if (spell == -1)
canned_msg( MSG_OK );
else
- your_spells( static_cast<spell_type>(spell), 0, false );
+ if (your_spells( static_cast<spell_type>(spell), 0, false )
+ == SPRET_ABORT)
+ {
+ crawl_state.cancel_cmd_repeat();
+ }
}
#endif
@@ -345,17 +350,28 @@ void cast_spec_spell(void)
void cast_spec_spell_name(void)
{
char specs[80];
+
mpr( "Cast which spell by name? ", MSGCH_PROMPT );
get_input_line( specs, sizeof( specs ) );
-
+
+ if (specs[0] == '\0')
+ {
+ canned_msg( MSG_OK );
+ crawl_state.cancel_cmd_repeat();
+ return;
+ }
+
spell_type type = spell_by_name(specs, true);
if (type == SPELL_NO_SPELL)
{
mpr((one_chance_in(20)) ? "Maybe you should go back to WIZARD school."
- : "I couldn't find that spell.");
+ : "I couldn't find that spell.");
+ crawl_state.cancel_cmd_repeat();
return;
}
- your_spells(type, 0, false);
+
+ if (your_spells(type, 0, false) == SPRET_ABORT)
+ crawl_state.cancel_cmd_repeat();
}
#endif
@@ -430,7 +446,7 @@ void create_spec_monster_name(int x, int y)
// Need to set a name for the player ghost
if (mspec.mid == MONS_PLAYER_GHOST)
{
- unsigned char mid = mgrd[x][y];
+ unsigned short mid = mgrd[x][y];
if (mid >= MAX_MONSTERS || menv[mid].type != MONS_PLAYER_GHOST)
{
@@ -668,6 +684,244 @@ void debug_list_monsters()
#endif
#ifdef WIZARD
+
+static void rune_from_specs(const char* _specs, item_def &item)
+{
+ char specs[80];
+ char obj_name[ ITEMNAME_SIZE ];
+
+ item.sub_type = MISC_RUNE_OF_ZOT;
+
+ if (strstr(_specs, "rune of zot"))
+ strncpy(specs, _specs, strlen(_specs) - strlen(" of zot"));
+ else
+ strcpy(specs, _specs);
+
+ if (strlen(specs) > 4)
+ {
+ for (int i = 0; i < NUM_RUNE_TYPES; i++)
+ {
+ item.plus = i;
+
+ strcpy(obj_name, item.name(DESC_PLAIN).c_str());
+
+ if (strstr(strlwr(obj_name), specs))
+ return;
+ }
+ }
+
+ while (true)
+ {
+ mpr(
+"[a] iron [b] obsidian [c] icy [d] bone [e] slimy [f] silver",
+ MSGCH_PROMPT);
+ mpr(
+"[g] serpentine [h] elven [i] golden [j] decaying [k] barnacle [l] demonic",
+ MSGCH_PROMPT);
+ mpr(
+"[m] abyssal [n] glowing [o] magical [p] fiery [q] dark [r] buggy",
+ MSGCH_PROMPT);
+ mpr("Which rune (ESC to exit)? ", MSGCH_PROMPT);
+
+ int keyin = tolower( get_ch() );
+
+ if (keyin == ESCAPE || keyin == ' '
+ || keyin == '\r' || keyin == '\n')
+ {
+ canned_msg( MSG_OK );
+ item.base_type = OBJ_UNASSIGNED;
+ return;
+ }
+
+ if (keyin < 'a' || keyin > 'r')
+ continue;
+
+ rune_type types[] = {
+ RUNE_DIS,
+ RUNE_GEHENNA,
+ RUNE_COCYTUS,
+ RUNE_TARTARUS,
+ RUNE_SLIME_PITS,
+ RUNE_VAULTS,
+ RUNE_SNAKE_PIT,
+ RUNE_ELVEN_HALLS,
+ RUNE_TOMB,
+ RUNE_SWAMP,
+ RUNE_SHOALS,
+
+ RUNE_DEMONIC,
+ RUNE_ABYSSAL,
+
+ RUNE_MNOLEG,
+ RUNE_LOM_LOBON,
+ RUNE_CEREBOV,
+ RUNE_GLOORX_VLOQ,
+ NUM_RUNE_TYPES
+ };
+
+ item.plus = static_cast<int>(types[keyin - 'a']);
+
+ return;
+ }
+}
+
+static void deck_from_specs(const char* _specs, item_def &item)
+{
+ std::string specs = _specs;
+ std::string type_str = "";
+
+ trim_string(specs);
+
+ if (specs.find(" of ") != std::string::npos)
+ {
+ type_str = specs.substr(specs.find(" of ") + 4);
+
+ if (type_str.find("card") != std::string::npos
+ || type_str.find("deck") != std::string::npos)
+ {
+ type_str = "";
+ }
+
+ trim_string(type_str);
+ }
+
+ misc_item_type types[] = {
+ MISC_DECK_OF_ESCAPE,
+ MISC_DECK_OF_DESTRUCTION,
+ MISC_DECK_OF_DUNGEONS,
+ MISC_DECK_OF_SUMMONING,
+ MISC_DECK_OF_WONDERS,
+ MISC_DECK_OF_PUNISHMENT,
+ MISC_DECK_OF_WAR,
+ MISC_DECK_OF_CHANGES,
+ MISC_DECK_OF_DEFENSE,
+ NUM_MISCELLANY
+ };
+
+ item.special = DECK_RARITY_COMMON;
+ item.sub_type = NUM_MISCELLANY;
+
+ if (type_str != "")
+ {
+ for (int i = 0; types[i] != NUM_MISCELLANY; i++)
+ {
+ item.sub_type = types[i];
+ item.plus = 1;
+ init_deck(item);
+ // Remove "plain " from front
+ std::string name = item.name(DESC_PLAIN).substr(6);
+ item.props.clear();
+
+ if (name.find(type_str) != std::string::npos)
+ break;
+ }
+ }
+
+ if (item.sub_type == NUM_MISCELLANY)
+ {
+ while (true)
+ {
+ mpr(
+"[a] escape [b] destruction [c] dungeons [d] summoning [e] wonders",
+ MSGCH_PROMPT);
+ mpr(
+"[f] punishment [g] war [h] changes [i] defense",
+ MSGCH_PROMPT);
+ mpr("Which deck (ESC to exit)? ");
+
+ int keyin = tolower( get_ch() );
+
+ if (keyin == ESCAPE || keyin == ' '
+ || keyin == '\r' || keyin == '\n')
+ {
+ canned_msg( MSG_OK );
+ item.base_type = OBJ_UNASSIGNED;
+ return;
+ }
+
+ if (keyin < 'a' || keyin > 'i')
+ continue;
+
+ item.sub_type = types[keyin - 'a'];
+ break;
+ }
+ }
+
+ const char* rarities[] = {
+ "plain",
+ "ornate",
+ "legendary",
+ NULL
+ };
+
+ int rarity_val = -1;
+
+ for (int i = 0; rarities[i] != NULL; i++)
+ if (specs.find(rarities[i]) != std::string::npos)
+ {
+ rarity_val = i;
+ break;
+ }
+
+ if (rarity_val == -1)
+ {
+ while (true)
+ {
+ mpr("[a] plain [b] ornate [c] legendary? (ESC to exit)",
+ MSGCH_PROMPT);
+
+ int keyin = tolower( get_ch() );
+
+ if (keyin == ESCAPE || keyin == ' '
+ || keyin == '\r' || keyin == '\n')
+ {
+ canned_msg( MSG_OK );
+ item.base_type = OBJ_UNASSIGNED;
+ return;
+ }
+
+ switch (keyin)
+ {
+ case 'p': keyin = 'a'; break;
+ case 'o': keyin = 'b'; break;
+ case 'l': keyin = 'c'; break;
+ }
+
+ if (keyin < 'a' || keyin > 'c')
+ continue;
+
+ rarity_val = keyin - 'a';
+ break;
+ }
+ }
+
+ int base = static_cast<int>(DECK_RARITY_COMMON);
+ deck_rarity_type rarity =
+ static_cast<deck_rarity_type>(base + rarity_val);
+ item.special = rarity;
+
+ int num = debug_prompt_for_int("How many cards? ", false);
+
+ if (num <= 0)
+ {
+ canned_msg( MSG_OK );
+ item.base_type = OBJ_UNASSIGNED;
+ return;
+ }
+
+ item.plus = num;
+
+ init_deck(item);
+}
+
+static void rune_or_deck_from_specs(const char* specs, item_def &item)
+{
+ if (strstr(specs, "rune"))
+ rune_from_specs(specs, item);
+ else if (strstr(specs, "deck"))
+ deck_from_specs(specs, item);
+}
+
//---------------------------------------------------------------
//
// create_spec_object
@@ -812,6 +1066,11 @@ void create_spec_object()
mpr( "What type of item? ", MSGCH_PROMPT );
get_input_line( specs, sizeof( specs ) );
+ std::string temp = specs;
+ trim_string(temp);
+ lowercase(temp);
+ strcpy(specs, temp.c_str());
+
if (specs[0] == '\0')
{
canned_msg( MSG_OK );
@@ -830,7 +1089,19 @@ void create_spec_object()
mitm[thing_created].quantity = 1;
set_ident_flags( mitm[thing_created], ISFLAG_IDENT_MASK );
- if (class_wanted == OBJ_ARMOUR)
+ if (class_wanted == OBJ_MISCELLANY)
+ {
+ // Leaves object unmodified if it wasn't a rune or deck
+ rune_or_deck_from_specs(specs, mitm[thing_created]);
+
+ if (mitm[thing_created].base_type == OBJ_UNASSIGNED)
+ {
+ // Rune or deck creation canceled, clean up item
+ destroy_item(thing_created);
+ return;
+ }
+ }
+ else if (class_wanted == OBJ_ARMOUR)
{
if (strstr( "naga barding", specs ))
{
@@ -867,7 +1138,7 @@ void create_spec_object()
mitm[thing_created].sub_type = i;
strcpy(obj_name,mitm[thing_created].name(DESC_PLAIN).c_str());
- ptr = strstr( strlwr(obj_name), strlwr(specs) );
+ ptr = strstr( strlwr(obj_name), specs );
if (ptr != NULL)
{
// earliest match is the winner
@@ -961,8 +1232,8 @@ void create_spec_object()
break;
case OBJ_MISCELLANY:
- // Runes to "demonic", decks have 50 cards, ignored elsewhere?
- mitm[thing_created].plus = 50;
+ if (!is_rune(mitm[thing_created]) && !is_deck(mitm[thing_created]))
+ mitm[thing_created].plus = 50;
break;
case OBJ_FOOD:
@@ -976,7 +1247,9 @@ void create_spec_object()
}
}
- item_colour( mitm[thing_created] );
+ // Deck colour (which control rarity) already set
+ if (!is_deck(mitm[thing_created]))
+ item_colour( mitm[thing_created] );
move_item_to_grid( &thing_created, you.x_pos, you.y_pos );
@@ -1063,7 +1336,7 @@ void tweak_object(void)
return;
char *end;
- int new_value = strtol( specs, &end, 10 );
+ int new_value = strtol( specs, &end, 0 );
if (new_value == 0 && end == specs)
return;
@@ -1175,8 +1448,8 @@ void stethoscope(int mwh)
(menv[i].foe == MHITNOT) ? "none" :
(menv[menv[i].foe].type == -1) ? "unassigned monster"
: menv[menv[i].foe].name(DESC_PLAIN, true).c_str()),
- menv[i].foe,
- menv[i].foe_memory,
+ menv[i].foe,
+ menv[i].foe_memory,
menv[i].target_x, menv[i].target_y );
// print resistances
@@ -1221,6 +1494,8 @@ static void dump_item( const char *name, int num, const item_def &item )
get_ident_type( item.base_type, item.sub_type ) );
mprf(" x: %d; y: %d; link: %d", item.x, item.y, item.link );
+
+ crawl_state.cancel_cmd_repeat();
}
//---------------------------------------------------------------
@@ -1507,43 +1782,224 @@ void debug_set_all_skills(void)
//
//---------------------------------------------------------------
#ifdef WIZARD
+
+static const char *mutation_type_names[] = {
+ "tough skin",
+ "strong",
+ "clever",
+ "agile",
+ "green scales",
+ "black scales",
+ "grey scales",
+ "boney plates",
+ "repulsion field",
+ "poison resistance",
+ "carnivorous",
+ "herbivorous",
+ "heat resistance",
+ "cold resistance",
+ "shock resistance",
+ "regeneration",
+ "fast metabolism",
+ "slow metabolism",
+ "weak",
+ "dopey",
+ "clumsy",
+ "teleport control",
+ "teleport",
+ "magic resistance",
+ "fast",
+ "acute vision",
+ "deformed",
+ "teleport at will",
+ "spit poison",
+ "mapping",
+ "breathe flames",
+ "blink",
+ "horns",
+ "strong stiff",
+ "flexible weak",
+ "scream",
+ "clarity",
+ "berserk",
+ "deterioration",
+ "blurry vision",
+ "mutation resistance",
+ "frail",
+ "robust",
+ "torment resistance",
+ "negative energy resistance",
+ "summon minor demons",
+ "summon demons",
+ "hurl hellfire",
+ "call torment",
+ "raise dead",
+ "control demons",
+ "pandemonium",
+ "death strength",
+ "channel hell",
+ "drain life",
+ "throw flames",
+ "throw frost",
+ "smite",
+ "claws",
+ "fangs",
+ "hooves",
+ "talons",
+ "paws",
+ "breathe poison",
+ "stinger",
+ "big wings",
+ "blue marks",
+ "green marks",
+ "drifting",
+ "saprovorous",
+ "shaggy fur",
+ "high mp",
+ "low mp",
+ "sleepiness",
+ "",
+ // from here on scales
+ "red scales",
+ "nacreous scales",
+ "grey2 scales",
+ "metallic scales",
+ "black2 scales",
+ "white scales",
+ "yellow scales",
+ "brown scales",
+ "blue scales",
+ "purple scales",
+ "speckled scales",
+ "orange scales",
+ "indigo scales",
+ "red2 scales",
+ "iridescent scales",
+ "patterned scales"
+};
+
bool debug_add_mutation(void)
{
bool success = false;
char specs[80];
+ if ((sizeof(mutation_type_names) / sizeof(char*)) != NUM_MUTATIONS)
+ {
+ mprf("Mutation name list has %d entries, but there are %d "
+ "mutations total; update mutation_type_names in debug.cc "
+ "to reflect current list.",
+ (sizeof(mutation_type_names) / sizeof(char*)),
+ (int) NUM_MUTATIONS);
+ crawl_state.cancel_cmd_repeat();
+ return (false);
+ }
+
+ if (you.mutation[MUT_MUTATION_RESISTANCE] > 0 &&
+ !crawl_state.is_replaying_keys())
+ {
+ const char* msg;
+
+ if (you.mutation[MUT_MUTATION_RESISTANCE] == 3)
+ msg = "You are immune to mutations, remove immunity?";
+ else
+ msg = "You are resistant to mutations, remove resistance?";
+
+ if (yesno(msg))
+ {
+ you.mutation[MUT_MUTATION_RESISTANCE] = 0;
+ crawl_state.cancel_cmd_repeat();
+ }
+ }
+
+ bool force = yesno("Force mutation to happen?");
+
+ if (you.mutation[MUT_MUTATION_RESISTANCE] == 3 && !force)
+ {
+ mpr("Can't mutate when immune to mutations without forcing it.");
+ crawl_state.cancel_cmd_repeat();
+ return (false);
+ }
+
// 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 );
+ mpr( "Which mutation ('any' for any, 'xom' for xom mutation)? ",
+ MSGCH_PROMPT );
get_input_line( specs, sizeof( specs ) );
if (specs[0] == '\0')
return (false);
+ if (strcasecmp(specs, "any") == 0)
+ {
+ int old_resist = you.mutation[MUT_MUTATION_RESISTANCE];
+
+ success = mutate(RANDOM_MUTATION, true, force);
+
+ if (old_resist < you.mutation[MUT_MUTATION_RESISTANCE] && !force)
+ crawl_state.cancel_cmd_repeat("Your mutation resistance has "
+ "increased.");
+ return (success);
+ }
+
+ if (strcasecmp(specs, "xom") == 0)
+ return mutate(RANDOM_XOM_MUTATION, true, force);
+
+ std::vector<int> partial_matches;
mutation_type mutation = NUM_MUTATIONS;
for (int i = 0; i < NUM_MUTATIONS; i++)
{
- char mut_name[80];
- const mutation_type m = static_cast<mutation_type>(i);
- strncpy( mut_name, mutation_name( m, 1 ), sizeof( mut_name ) );
-
- char *ptr = strstr( strlwr(mut_name), strlwr(specs) );
- if (ptr != NULL)
+ if (strcasecmp(specs, mutation_type_names[i]) == 0)
{
- // we take the first mutation that matches
- mutation = m;
+ mutation = (mutation_type) i;
break;
}
+
+ if (strstr(mutation_type_names[i] , strlwr(specs) ))
+ partial_matches.push_back(i);
}
+ // If only one matching mutation, use that.
if (mutation == NUM_MUTATIONS)
- mpr("I can't warp you that way!");
+ {
+ if (partial_matches.size() == 1)
+ mutation = (mutation_type) partial_matches[0];
+ }
+
+ if (mutation == NUM_MUTATIONS)
+ {
+ crawl_state.cancel_cmd_repeat();
+
+ if (partial_matches.size() == 0)
+ mpr("No matching mutation names.");
+ else
+ {
+ std::vector<std::string> matches;
+
+ for (unsigned int i = 0, size = partial_matches.size();
+ i < size; i++)
+ {
+ matches.push_back(mutation_type_names[partial_matches[i]]);
+ }
+ std::string prefix = "No exact match for mutation '" +
+ std::string(specs) + "', possible matches are: ";
+
+ // Use mpr_comma_separated_list() because the list
+ // might be *LONG*.
+ mpr_comma_separated_list(prefix, matches, " and ", ", ",
+ MSGCH_DIAGNOSTICS);
+ }
+
+ return (false);
+ }
else
{
- mprf("Found: %s", mutation_name( mutation, 1 ) );
+ mprf("Found #%d: %s (\"%s\")", (int) mutation,
+ mutation_type_names[mutation], mutation_name( mutation, 1 ) );
- const int levels = debug_prompt_for_int( "How many levels? ", false );
+ const int levels =
+ debug_prompt_for_int( "How many levels to increase or decrease? ",
+ false );
if (levels == 0)
{
@@ -1554,7 +2010,7 @@ bool debug_add_mutation(void)
{
for (int i = 0; i < levels; i++)
{
- if (mutate( mutation ))
+ if (mutate( mutation, true, force ))
success = true;
}
}
@@ -1562,7 +2018,7 @@ bool debug_add_mutation(void)
{
for (int i = 0; i < -levels; i++)
{
- if (delete_mutation( mutation ))
+ if (delete_mutation( mutation, force ))
success = true;
}
}
@@ -2336,12 +2792,17 @@ void debug_card()
mpr("Unknown card.");
return;
}
-
+
+ std::string wanted = buf;
+ lowercase(wanted);
+
bool found_card = false;
for ( int i = 0; i < NUM_CARDS; ++i )
{
const card_type c = static_cast<card_type>(i);
- if ( strstr(card_name(c), buf) != NULL )
+ std::string card = card_name(c);
+ lowercase(card);
+ if ( card.find(wanted) != std::string::npos )
{
card_effect(c, DECK_RARITY_LEGENDARY);
found_card = true;
@@ -2463,14 +2924,42 @@ void debug_place_map()
debug_load_map_by_name(what);
}
-void debug_dismiss_all_monsters()
+void debug_dismiss_all_monsters(bool force_all)
{
- // Genocide... "unsummon" all the monsters from the level.
+ char buf[80];
+ if (!force_all)
+ {
+ mpr("Regex of monsters to dismiss (ENTER for all): ", MSGCH_PROMPT);
+ bool validline = !cancelable_get_line(buf, sizeof buf, 80);
+
+ if (!validline)
+ {
+ canned_msg( MSG_OK );
+ return;
+ }
+ }
+
+ // Dismiss all
+ if (buf[0] == '\0' || force_all)
+ {
+ // Genocide... "unsummon" all the monsters from the level.
+ for (int mon = 0; mon < MAX_MONSTERS; mon++)
+ {
+ monsters *monster = &menv[mon];
+
+ if (monster->alive())
+ monster_die(monster, KILL_DISMISSED, 0);
+ }
+ return;
+ }
+
+ // Dismiss by regex
+ text_pattern tpat(buf);
for (int mon = 0; mon < MAX_MONSTERS; mon++)
{
monsters *monster = &menv[mon];
- if (monster->alive())
+ if (monster->alive() && tpat.matches(monster->name(DESC_PLAIN)))
monster_die(monster, KILL_DISMISSED, 0);
}
}
@@ -2523,7 +3012,7 @@ static void debug_destroy_doors()
// f) Counts number of turns needed to explore the level.
void debug_test_explore()
{
- debug_dismiss_all_monsters();
+ debug_dismiss_all_monsters(true);
debug_kill_traps();
forget_map(100);
diff --git a/crawl-ref/source/debug.h b/crawl-ref/source/debug.h
index 5e8b80ee76..03e9c0353e 100644
--- a/crawl-ref/source/debug.h
+++ b/crawl-ref/source/debug.h
@@ -156,7 +156,7 @@ void debug_card();
void debug_set_xl();
void debug_place_map();
void debug_test_explore();
-void debug_dismiss_all_monsters();
+void debug_dismiss_all_monsters(bool force_all = false);
class monsters;
void debug_make_monster_shout(monsters* mon);
diff --git a/crawl-ref/source/decks.cc b/crawl-ref/source/decks.cc
index fcb769181d..c47e3f58fd 100644
--- a/crawl-ref/source/decks.cc
+++ b/crawl-ref/source/decks.cc
@@ -33,6 +33,7 @@
#include "monstuff.h"
#include "mutation.h"
#include "ouch.h"
+#include "output.h"
#include "player.h"
#include "religion.h"
#include "spells1.h"
@@ -41,11 +42,26 @@
#include "spells4.h"
#include "spl-cast.h"
#include "spl-util.h"
+#include "state.h"
#include "stuff.h"
#include "terrain.h"
#include "transfor.h"
#include "traps.h"
#include "view.h"
+#include "xom.h"
+
+// DECK STRUCTURE: deck.plus is the number of cards the deck *started*
+// with, deck.plus2 is the number of cards drawn, deck.special is the
+// deck rarity, deck.props["cards"] holds the list of cards (with the
+// highest index card being the top card, and index 0 being the bottom
+// card), deck.props["card_flags"] holds the flags for each card,
+// deck.props["num_marked"] is the number of marked cards left in the
+// deck, and deck.props["non_brownie_draws"] is the number of
+// non-marked draws you have to make from that deck before earning
+// brownie points from it again.
+//
+// The card type and per-card flags are each stored as unsigned bytes,
+// for a maximum of 256 different kinds of cards and 8 bits of flags.
#define VECFROM(x) (x), (x) + ARRAYSIZE(x)
#define DEFVEC(Z) static std::vector<card_type> Z(VECFROM(a_##Z))
@@ -83,7 +99,7 @@ static card_type a_deck_of_enchantments[] = {
DEFVEC(deck_of_enchantments);
static card_type a_deck_of_summoning[] = {
- CARD_SUMMON_ANIMAL, CARD_SUMMON_DEMON, CARD_SUMMON_WEAPON
+ CARD_CRUSADE, CARD_SUMMON_ANIMAL, CARD_SUMMON_DEMON, CARD_SUMMON_WEAPON
};
DEFVEC(deck_of_summoning);
@@ -119,11 +135,84 @@ DEFVEC(deck_of_punishment);
#undef DEFVEC
#undef VECFROM
+static void check_odd_card(unsigned char flags)
+{
+ if ((flags & CFLAG_ODDITY) && !(flags & CFLAG_SEEN))
+ mpr("This card doesn't seem to belong here.");
+}
+
+int cards_in_deck(const item_def &deck)
+{
+ ASSERT(is_deck(deck));
+
+ const CrawlHashTable &props = deck.props;
+ ASSERT(props.exists("cards"));
+
+ return static_cast<unsigned long>(props["cards"].get_vector().size());
+}
+
+static void shuffle_deck(item_def &deck)
+{
+ ASSERT(is_deck(deck));
+
+ CrawlHashTable &props = deck.props;
+ ASSERT(props.exists("cards"));
+
+ CrawlVector &cards = props["cards"];
+ ASSERT(cards.size() > 1);
+
+ CrawlVector &flags = props["card_flags"];
+ ASSERT(flags.size() == cards.size());
+
+ // Don't use std::shuffle(), since we want to apply exactly the
+ // same shuffling to both the cards vector and the flags vector.
+ std::vector<long> pos;
+ for (unsigned long i = 0; i < cards.size(); i++)
+ pos.push_back(random2(cards.size()));
+
+ for (unsigned long i = 0; i < pos.size(); i++)
+ {
+ std::swap(cards[i], cards[pos[i]]);
+ std::swap(flags[i], flags[pos[i]]);
+ }
+}
+
+card_type get_card_and_flags(const item_def& deck, int idx,
+ unsigned char& _flags)
+{
+ const CrawlHashTable &props = deck.props;
+ const CrawlVector &cards = props["cards"].get_vector();
+ const CrawlVector &flags = props["card_flags"].get_vector();
+
+ // negative idx means read from the end
+ if (idx < 0)
+ idx += static_cast<int>(cards.size());
+
+ _flags = (unsigned char) flags[idx].get_byte();
+
+ return static_cast<card_type>(cards[idx].get_byte());
+}
+
+static void set_card_and_flags(item_def& deck, int idx, card_type card,
+ unsigned char _flags)
+{
+ CrawlHashTable &props = deck.props;
+ CrawlVector &cards = props["cards"];
+ CrawlVector &flags = props["card_flags"];
+
+ if (idx == -1)
+ idx = (int) cards.size() - 1;
+
+ cards[idx] = (char) card;
+ flags[idx] = (char) _flags;
+}
+
const char* card_name(card_type card)
{
switch (card)
{
- case CARD_BLANK: return "blank card";
+ case CARD_BLANK1: return "blank card";
+ case CARD_BLANK2: return "blank card";
case CARD_PORTAL: return "the Portal";
case CARD_WARP: return "the Warp";
case CARD_SWAP: return "Swap";
@@ -149,6 +238,7 @@ const char* card_name(card_type card)
case CARD_MAP: return "the Map";
case CARD_BANSHEE: return "the Banshee";
case CARD_WILD_MAGIC: return "Wild Magic";
+ case CARD_CRUSADE: return "the Crusade";
case CARD_SUMMON_ANIMAL: return "the Herd";
case CARD_SUMMON_DEMON: return "the Pentagram";
case CARD_SUMMON_WEAPON: return "the Dance";
@@ -174,10 +264,10 @@ const char* card_name(card_type card)
return "a very buggy card";
}
-static card_type choose_one_card(const item_def& item, bool message)
+static const std::vector<card_type>* random_sub_deck(unsigned char deck_type)
{
- std::vector<card_type> *pdeck = NULL;
- switch ( item.sub_type )
+ const std::vector<card_type> *pdeck = NULL;
+ switch ( deck_type )
{
case MISC_DECK_OF_ESCAPE:
pdeck = (coinflip() ? &deck_of_transport : &deck_of_emergency);
@@ -212,29 +302,111 @@ static card_type choose_one_card(const item_def& item, bool message)
}
ASSERT( pdeck );
-
+
+ return pdeck;
+}
+
+static card_type random_card(unsigned char deck_type, bool &was_oddity)
+{
+ const std::vector<card_type> *pdeck = random_sub_deck(deck_type);
+
if ( one_chance_in(100) )
{
- if ( message )
- mpr("This card doesn't seem to belong here.");
- pdeck = &deck_of_oddities;
+ pdeck = &deck_of_oddities;
+ was_oddity = true;
}
card_type chosen = (*pdeck)[random2(pdeck->size())];
- // Cut the probability of Damnation on common decks...
- // too much of a killer otherwise.
- if ( chosen == CARD_DAMNATION &&
- pdeck != &deck_of_punishment &&
- deck_rarity(item) == DECK_RARITY_COMMON )
- chosen = (*pdeck)[random2(pdeck->size())];
+ // Paranoia
+ if (chosen < CARD_BLANK1 || chosen >= NUM_CARDS)
+ chosen = NUM_CARDS;
+
+ return chosen;
+}
+
+static card_type random_card(const item_def& item, bool &was_oddity)
+{
+ return random_card(item.sub_type, was_oddity);
+}
+
+static void retry_blank_card(card_type &card, unsigned char deck_type,
+ unsigned char flags)
+{
+ // BLANK1 == hasn't been retried
+ if (card != CARD_BLANK1)
+ return;
+
+ if (flags & (CFLAG_MARKED | CFLAG_SEEN))
+ {
+ // Can't retry a card which has been seen or marked.
+ card = CARD_BLANK2;
+ return;
+ }
+
+ const std::vector<card_type> *pdeck = random_sub_deck(deck_type);
+
+ if (flags & CFLAG_ODDITY)
+ pdeck = &deck_of_oddities;
// High Evocations gives you another shot (but not at being punished...)
- if (pdeck != &deck_of_punishment && chosen == CARD_BLANK &&
- you.skills[SK_EVOCATIONS] > random2(30))
- chosen = (*pdeck)[random2(pdeck->size())];
+ if (pdeck != &deck_of_punishment
+ && you.skills[SK_EVOCATIONS] > random2(30))
+ {
+ card = (*pdeck)[random2(pdeck->size())];
+ }
- return chosen;
+ // BLANK2 == retried and failed
+ if (card == CARD_BLANK1)
+ card = CARD_BLANK2;
+}
+
+static void retry_blank_card(card_type &card, item_def& deck,
+ unsigned char flags)
+{
+ retry_blank_card(card, deck.sub_type, flags);
+}
+
+static card_type draw_top_card(item_def& deck, bool message,
+ unsigned char &_flags)
+{
+ CrawlHashTable &props = deck.props;
+ CrawlVector &cards = props["cards"].get_vector();
+ CrawlVector &flags = props["card_flags"].get_vector();
+
+ int num_cards = cards.size();
+ int idx = num_cards - 1;
+
+ ASSERT(num_cards > 0);
+
+ card_type card = get_card_and_flags(deck, idx, _flags);
+ cards.pop_back();
+ flags.pop_back();
+
+ retry_blank_card(card, deck, _flags);
+
+ if (message)
+ {
+ if (_flags & CFLAG_MARKED)
+ mprf("You draw %s.", card_name(card));
+ else
+ mprf("You draw a card... It is %s.", card_name(card));
+
+ check_odd_card(_flags);
+ }
+
+ return card;
+}
+
+static void push_top_card(item_def& deck, card_type card,
+ unsigned char _flags)
+{
+ CrawlHashTable &props = deck.props;
+ CrawlVector &cards = props["cards"].get_vector();
+ CrawlVector &flags = props["card_flags"].get_vector();
+
+ cards.push_back((char) card);
+ flags.push_back((char) _flags);
}
static bool wielding_deck()
@@ -244,6 +416,234 @@ static bool wielding_deck()
return is_deck(you.inv[you.equip[EQ_WEAPON]]);
}
+static bool check_buggy_deck(item_def& deck)
+{
+ std::ostream& strm = msg::streams(MSGCH_DIAGNOSTICS);
+ if (!is_deck(deck))
+ {
+ crawl_state.zero_turns_taken();
+ strm << "This isn't a deck at all!" << std::endl;
+ return true;
+ }
+
+ CrawlHashTable &props = deck.props;
+
+ if (!props.exists("cards")
+ || props["cards"].get_type() != SV_VEC
+ || props["cards"].get_vector().get_type() != SV_BYTE
+ || cards_in_deck(deck) == 0)
+ {
+ crawl_state.zero_turns_taken();
+
+ if (!props.exists("cards"))
+ strm << "Seems this deck never had any cards in the first place!";
+ else if (props["cards"].get_type() != SV_VEC)
+ strm << "'cards' property isn't a vector.";
+ else
+ {
+ if (props["cards"].get_vector().get_type() != SV_BYTE)
+ strm << "'cards' vector doesn't contain bytes.";
+
+ if (cards_in_deck(deck) == 0)
+ {
+ strm << "Strange, this deck is already empty.";
+
+ int cards_left = 0;
+ if (deck.plus2 >= 0)
+ cards_left = deck.plus - deck.plus2;
+ else
+ cards_left = -deck.plus;
+
+ if (cards_left != 0)
+ {
+ strm << " But there should have been " << cards_left
+ << " cards left.";
+ }
+ }
+ }
+ strm << std::endl
+ << "A swarm of software bugs snatches the deck from you "
+ "and whisks it away."
+ << std::endl;
+
+ if ( deck.link == you.equip[EQ_WEAPON] )
+ unwield_item();
+
+ dec_inv_item_quantity( deck.link, 1 );
+ did_god_conduct(DID_CARDS, 1);
+
+ return true;
+ }
+
+ bool problems = false;
+
+ CrawlVector &cards = props["cards"].get_vector();
+ CrawlVector &flags = props["card_flags"].get_vector();
+
+ unsigned long num_cards = cards.size();
+ unsigned long num_flags = flags.size();
+
+ unsigned int num_buggy = 0;
+ unsigned int num_marked = 0;
+
+ for (unsigned long i = 0; i < num_cards; i++)
+ {
+ unsigned char card = cards[i].get_byte();
+ unsigned char _flags = flags[i].get_byte();
+ if (card >= NUM_CARDS)
+ {
+ cards.erase(i);
+ flags.erase(i);
+ i--;
+ num_cards--;
+ num_buggy++;
+ }
+ else
+ {
+ if (_flags & CFLAG_MARKED)
+ num_marked++;
+ }
+ }
+
+ if (num_buggy > 0)
+ {
+ strm << num_buggy << " buggy cards found in the deck, discarding them."
+ << std::endl;
+
+ deck.plus2 += num_buggy;
+
+ num_cards = cards.size();
+ num_flags = cards.size();
+
+ problems = true;
+ }
+
+ if (num_cards == 0)
+ {
+ crawl_state.zero_turns_taken();
+
+ strm << "Oops, all of the cards seem to be gone." << std::endl
+ << "A swarm of software bugs snatches the deck from you "
+ "and whisks it away." << std::endl;
+
+ if ( deck.link == you.equip[EQ_WEAPON] )
+ unwield_item();
+
+ dec_inv_item_quantity( deck.link, 1 );
+ did_god_conduct(DID_CARDS, 1);
+
+ return true;
+ }
+
+ if (static_cast<long>(num_cards) > deck.plus)
+ {
+ if (deck.plus == 0)
+ strm << "Deck was created with zero cards???" << std::endl;
+ else if (deck.plus < 0)
+ strm << "Deck was created with *negative* cards?!" << std::endl;
+ else
+ strm << "Deck has more cards than it was created with?"
+ << std::endl;
+
+ deck.plus = num_cards;
+ problems = true;
+ }
+
+ if (num_cards > num_flags)
+ {
+#ifdef WIZARD
+ strm << (num_cards - num_flags) << " more cards than flags.";
+#else
+ strm << "More cards than flags.";
+#endif
+ strm << std::endl;
+ for (unsigned int i = num_flags + 1; i <= num_cards; i++)
+ flags[i] = static_cast<char>(0);
+
+ problems = true;
+ }
+ else if (num_flags > num_cards)
+ {
+#ifdef WIZARD
+ strm << (num_cards - num_flags) << " more cards than flags.";
+#else
+ strm << "More cards than flags.";
+#endif
+ strm << std::endl;
+
+ for (unsigned int i = num_flags; i > num_cards; i--)
+ flags.erase(i);
+
+ problems = true;
+ }
+
+ if (props["num_marked"].get_byte() > static_cast<char>(num_cards))
+ {
+ strm << "More cards marked than in the deck?" << std::endl;
+ props["num_marked"] = static_cast<char>(num_marked);
+ problems = true;
+ }
+ else if (props["num_marked"].get_byte() != static_cast<char>(num_marked))
+ {
+#ifdef WIZARD
+
+ strm << "Oops, counted " << static_cast<int>(num_marked)
+ << " marked cards, but num_marked is "
+ << (static_cast<int>(props["num_marked"].get_byte()));
+#else
+ strm << "Oops, book-keeping on marked cards is wrong.";
+#endif
+ strm << std::endl;
+
+ props["num_marked"] = static_cast<char>(num_marked);
+ problems = true;
+ }
+
+ if (deck.plus2 >= 0)
+ {
+ if (deck.plus != (deck.plus2 + static_cast<long>(num_cards)))
+ {
+#ifdef WIZARD
+ strm << "Have you used " << deck.plus2 << " cards, or "
+ << (deck.plus - num_cards) << "? Oops.";
+#else
+ strm << "Oops, book-keeping on used cards is wrong.";
+#endif
+ strm << std::endl;
+ deck.plus2 = deck.plus - num_cards;
+ problems = true;
+ }
+ }
+ else
+ {
+ if (-deck.plus2 != static_cast<long>(num_cards))
+ {
+#ifdef WIZARD
+ strm << "There are " << num_cards << " cards left, not "
+ << (-deck.plus2) << ". Oops.";
+#else
+ strm << "Oops, book-keeping on cards left is wrong.";
+#endif
+ strm << std::endl;
+ deck.plus2 = -num_cards;
+ problems = true;
+ }
+ }
+
+ if (!problems)
+ return false;
+
+ you.wield_change = true;
+
+ if (!yesno("Problems might not have been completely fixed; "
+ "still use deck?"))
+ {
+ crawl_state.zero_turns_taken();
+ return true;
+ }
+ return false;
+}
+
// Choose a deck from inventory and return its slot (or -1.)
static int choose_inventory_deck( const char* prompt )
{
@@ -273,12 +673,27 @@ bool choose_deck_and_draw()
const int slot = choose_inventory_deck( "Draw from which deck?" );
if ( slot == -1 )
+ {
+ crawl_state.zero_turns_taken();
return false;
+ }
evoke_deck(you.inv[slot]);
return true;
}
+static void deck_peek_ident(item_def& deck)
+{
+ if (in_inventory(deck) && !item_ident(deck, ISFLAG_KNOW_TYPE))
+ {
+ set_ident_flags(deck, ISFLAG_KNOW_TYPE);
+
+ mprf("This is %s.", deck.name(DESC_NOCAP_A).c_str());
+
+ you.wield_change = true;
+ }
+}
+
// Peek at a deck (show what the next card will be.)
// Return false if the operation was failed/aborted along the way.
bool deck_peek()
@@ -286,31 +701,181 @@ bool deck_peek()
if ( !wielding_deck() )
{
mpr("You aren't wielding a deck!");
+ crawl_state.zero_turns_taken();
return false;
}
- item_def& item(you.inv[you.equip[EQ_WEAPON]]);
- if ( item.plus2 != 0 )
+ item_def& deck(you.inv[you.equip[EQ_WEAPON]]);
+
+ if (check_buggy_deck(deck))
+ return false;
+
+ if (deck.props["num_marked"].get_byte() > 0)
{
- mpr("You already know what the next card will be.");
+ mpr("You can't peek into a marked deck.");
+ crawl_state.zero_turns_taken();
return false;
}
- const card_type chosen = choose_one_card(item, false);
+ CrawlVector &cards = deck.props["cards"];
+ int num_cards = cards.size();
- msg::stream << "You see " << card_name(chosen) << '.' << std::endl;
- item.plus2 = chosen + 1;
- you.wield_change = true;
+ card_type card1, card2, card3;
+ unsigned char flags1, flags2, flags3;
+
+ card1 = get_card_and_flags(deck, 0, flags1);
+ retry_blank_card(card1, deck, flags1);
- // You lose 1d2 cards when peeking.
- if ( item.plus > 1 )
+ if (num_cards == 1)
{
- mpr("Some cards drop out of the deck.");
- if ( item.plus > 2 && coinflip() )
- item.plus -= 2;
- else
- item.plus -= 1;
+ deck_peek_ident(deck);
+
+ mpr("There's only one card in the deck!");
+
+ set_card_and_flags(deck, 0, card1, flags1 | CFLAG_SEEN | CFLAG_MARKED);
+ deck.props["num_marked"]++;
+ deck.plus2 = -1;
+ you.wield_change = true;
+
+ return true;
}
+ card2 = get_card_and_flags(deck, 1, flags2);
+ retry_blank_card(card2, deck, flags2);
+
+ if (num_cards == 2)
+ {
+ deck.props["non_brownie_draws"] = (char) 2;
+ deck.plus2 = -2;
+
+ deck_peek_ident(deck);
+
+ mprf("Only two cards in the deck: %s and %s.",
+ card_name(card1), card_name(card2));
+
+ mpr("You shuffle the deck.");
+
+ // If both cards are the same, then you know which card you're
+ // going to draw both times.
+ if (card1 == card2)
+ {
+ flags1 |= CFLAG_MARKED;
+ flags2 |= CFLAG_MARKED;
+ you.wield_change = true;
+ deck.props["num_marked"] = (char) 2;
+ }
+
+ // "Shuffle" the two cards (even if they're the same, since
+ // the flags might differ).
+ if (coinflip())
+ {
+ std::swap(card1, card2);
+ std::swap(flags1, flags2);
+ }
+
+ // After the first of two differing cards is drawn, you know
+ // what the second card is going to be.
+ if (card1 != card2)
+ {
+ flags1 |= CFLAG_MARKED;
+ deck.props["num_marked"]++;
+ }
+
+ set_card_and_flags(deck, 0, card1, flags1 | CFLAG_SEEN);
+ set_card_and_flags(deck, 1, card2, flags2 | CFLAG_SEEN);
+
+ return true;
+ }
+
+ deck_peek_ident(deck);
+
+ card3 = get_card_and_flags(deck, 2, flags3);
+ retry_blank_card(card3, deck, flags3);
+
+ int already_seen = 0;
+ if (flags1 & CFLAG_SEEN)
+ already_seen++;
+ if (flags2 & CFLAG_SEEN)
+ already_seen++;
+ if (flags3 & CFLAG_SEEN)
+ already_seen++;
+
+ if (random2(3) < already_seen)
+ deck.props["non_brownie_draws"]++;
+
+ mprf("You draw three cards from the deck. They are: %s, %s and %s.",
+ card_name(card1), card_name(card2), card_name(card3));
+
+ set_card_and_flags(deck, 0, card1, flags1 | CFLAG_SEEN);
+ set_card_and_flags(deck, 1, card2, flags2 | CFLAG_SEEN);
+ set_card_and_flags(deck, 2, card3, flags3 | CFLAG_SEEN);
+
+ mpr("You shuffle the cards back into the deck.");
+ shuffle_deck(deck);
+
+ return true;
+}
+
+// Mark a deck: look at the next four cards, mark them, and shuffle
+// them back into the deck without losing any cards. The player won't
+// know what order they're in, and the if the top card is non-marked
+// then the player won't know what the next card is.
+// Return false if the operation was failed/aborted along the way.
+bool deck_mark()
+{
+ if ( !wielding_deck() )
+ {
+ mpr("You aren't wielding a deck!");
+ crawl_state.zero_turns_taken();
+ return false;
+ }
+ item_def& deck(you.inv[you.equip[EQ_WEAPON]]);
+ if (check_buggy_deck(deck))
+ return false;
+
+ CrawlHashTable &props = deck.props;
+ if (props["num_marked"].get_byte() > 0)
+ {
+ mpr("Deck is already marked.");
+ crawl_state.zero_turns_taken();
+ return false;
+ }
+
+ const int num_cards = cards_in_deck(deck);
+ const int num_to_mark = (num_cards < 4 ? num_cards : 4);
+
+ if (num_cards == 1)
+ mpr("There's only one card left!");
+ else if (num_cards < 4)
+ mprf("The deck only has %d cards.", num_cards);
+
+ std::vector<std::string> names;
+ for ( int i = 0; i < num_to_mark; ++i )
+ {
+ unsigned char flags;
+ card_type card = get_card_and_flags(deck, i, flags);
+
+ flags |= CFLAG_SEEN | CFLAG_MARKED;
+ set_card_and_flags(deck, i, card, flags);
+
+ names.push_back(card_name(card));
+ }
+ mpr_comma_separated_list("You draw and mark ", names);
+ props["num_marked"] = (char) num_to_mark;
+
+ if (num_cards == 1)
+ return true;
+
+ if (num_cards < 4)
+ {
+ mprf("You shuffle the deck.");
+ deck.plus2 = -num_cards;
+ }
+ else
+ mprf("You shuffle the cards back into the deck.");
+
+ shuffle_deck(deck);
+ you.wield_change = true;
+
return true;
}
@@ -326,6 +891,7 @@ static void redraw_stacked_cards(const std::vector<card_type>& draws,
}
}
+
// Stack a deck: look at the next five cards, put them back in any
// order, discard the rest of the deck.
// Return false if the operation was failed/aborted along the way.
@@ -335,23 +901,52 @@ bool deck_stack()
if ( !wielding_deck() )
{
mpr("You aren't wielding a deck!");
+ crawl_state.zero_turns_taken();
return false;
}
- item_def& item(you.inv[you.equip[EQ_WEAPON]]);
- if ( item.plus2 != 0 )
+ item_def& deck(you.inv[you.equip[EQ_WEAPON]]);
+ if (check_buggy_deck(deck))
+ return false;
+
+ CrawlHashTable &props = deck.props;
+ if (props["num_marked"].get_byte() > 0)
{
mpr("You can't stack a marked deck.");
+ crawl_state.zero_turns_taken();
return false;
}
- const int num_to_stack = (item.plus < 5 ? item.plus : 5);
- std::vector<card_type> draws;
- for ( int i = 0; i < num_to_stack; ++i )
- draws.push_back(choose_one_card(item, false));
+ const int num_cards = cards_in_deck(deck);
+ const int num_to_stack = (num_cards < 5 ? num_cards : 5);
- if ( draws.size() == 1 )
+ std::vector<card_type> draws;
+ std::vector<unsigned char> flags;
+ for ( int i = 0; i < num_cards; ++i )
+ {
+ unsigned char _flags;
+ card_type card = draw_top_card(deck, false, _flags);
+
+ if (i < num_to_stack)
+ {
+ draws.push_back(card);
+ flags.push_back(_flags | CFLAG_SEEN | CFLAG_MARKED);
+ }
+ else
+ ; // Rest of deck is discarded.
+ }
+
+ if ( num_cards == 1 )
mpr("There's only one card left!");
- else
+ else if (num_cards < 5)
+ mprf("The deck only has %d cards.", num_to_stack);
+ else if (num_cards == 5)
+ mpr("The deck has exactly five cards.");
+ else
+ mprf("You draw the first five cards out of %d and discard the rest.",
+ num_cards);
+ more();
+
+ if ( draws.size() > 1 )
{
unsigned int selected = draws.size();
clrscr();
@@ -361,6 +956,7 @@ bool deck_stack()
"then another digit to swap it.");
gotoxy(1,10);
cprintf("Press Enter to accept.");
+
redraw_stacked_cards(draws, selected);
// Hand-hacked implementation, instead of using Menu. Oh well.
@@ -383,6 +979,7 @@ bool deck_stack()
if ( selected < draws.size() )
{
std::swap(draws[selected], draws[new_selected]);
+ std::swap(flags[selected], flags[new_selected]);
selected = draws.size();
}
else
@@ -393,15 +990,16 @@ bool deck_stack()
redraw_screen();
}
- item.plus2 = draws[0] + 1;
- item.special = 0;
- for ( unsigned int i = draws.size() - 1; i > 0; --i )
- {
- item.special <<= 8;
- item.special += draws[i] + 1;
- }
- item.plus = num_to_stack; // no more deck after the stack
+ deck.plus2 = -num_to_stack;
+ for ( unsigned int i = 0; i < draws.size(); ++i )
+ push_top_card(deck, draws[draws.size() - 1 - i],
+ flags[flags.size() - 1 - i]);
+
+ props["num_marked"] = static_cast<char>(num_to_stack);
you.wield_change = true;
+
+ check_buggy_deck(deck);
+
return true;
}
@@ -411,35 +1009,51 @@ bool deck_triple_draw()
const int slot = choose_inventory_deck("Triple draw from which deck?");
if ( slot == -1 )
{
+ crawl_state.zero_turns_taken();
return false;
}
- item_def& item(you.inv[slot]);
+ item_def& deck(you.inv[slot]);
- if ( item.plus2 != 0 )
+ if (check_buggy_deck(deck))
+ return false;
+
+ CrawlHashTable &props = deck.props;
+ if (props["num_marked"].get_byte() > 0)
{
mpr("You can't triple draw from a marked deck.");
+ crawl_state.zero_turns_taken();
return false;
}
- if (item.plus == 1)
+ const int num_cards = cards_in_deck(deck);
+
+ if (num_cards == 1)
{
// only one card to draw, so just draw it
- evoke_deck(item);
+ evoke_deck(deck);
return true;
}
- const int num_to_draw = (item.plus < 3 ? item.plus : 3);
- std::vector<card_type> draws;
+ const int num_to_draw = (num_cards < 3 ? num_cards : 3);
+ std::vector<card_type> draws;
+ std::vector<unsigned char> flags;
+
for ( int i = 0; i < num_to_draw; ++i )
- draws.push_back(choose_one_card(item, false));
+ {
+ unsigned char _flags;
+ card_type card = draw_top_card(deck, false, _flags);
+
+ draws.push_back(card);
+ flags.push_back(_flags | CFLAG_SEEN | CFLAG_MARKED);
+ }
mpr("You draw... (choose one card)");
for ( int i = 0; i < num_to_draw; ++i )
msg::streams(MSGCH_PROMPT) << (static_cast<char>(i + 'a')) << " - "
<< card_name(draws[i]) << std::endl;
int selected = -1;
- while ( 1 )
+ while ( true )
{
const int keyin = tolower(get_ch());
if (keyin >= 'a' && keyin < 'a' + num_to_draw)
@@ -451,12 +1065,14 @@ bool deck_triple_draw()
canned_msg(MSG_HUH);
}
- // Note that card_effect() might cause you to unwield the deck.
- card_effect(draws[selected], deck_rarity(item));
+ // Note how many cards were removed from the deck.
+ deck.plus2 += num_to_draw;
+ you.wield_change = true;
- // remove the cards from the deck
- item.plus -= num_to_draw;
- if (item.plus <= 0)
+ // Make deck disappear *before* the card effect, since we
+ // don't want to unwield an empty deck.
+ deck_rarity_type rarity = deck_rarity(deck);
+ if (cards_in_deck(deck) == 0)
{
mpr("The deck of cards disappears in a puff of smoke.");
if ( slot == you.equip[EQ_WEAPON] )
@@ -464,20 +1080,67 @@ bool deck_triple_draw()
dec_inv_item_quantity( slot, 1 );
}
- you.wield_change = true;
+
+ // Note that card_effect() might cause you to unwield the deck.
+ card_effect(draws[selected], rarity, flags[selected], false);
+
return true;
}
// This is Nemelex retribution.
void draw_from_deck_of_punishment()
{
- item_def deck;
- deck.plus = 10; // don't let it puff away
- deck.plus2 = 0;
- deck.colour = BLACK; // for rarity
- deck.base_type = OBJ_MISCELLANY;
- deck.sub_type = MISC_DECK_OF_PUNISHMENT;
- evoke_deck(deck);
+ bool oddity;
+ card_type card = random_card(MISC_DECK_OF_PUNISHMENT, oddity);
+
+ mpr("You draw a card...");
+ card_effect(card, DECK_RARITY_COMMON);
+}
+
+static int xom_check_card(item_def &deck, card_type card,
+ unsigned char flags)
+{
+ int amusement = 64;
+
+ if (!item_type_known(deck))
+ amusement *= 2;
+ // Expecting one type of card but got another, real funny.
+ else if (flags & CFLAG_ODDITY)
+ amusement = 255;
+
+ if (player_in_a_dangerous_place())
+ amusement *= 2;
+
+ switch (card)
+ {
+ case CARD_XOM:
+ // Handled elsewhere
+ amusement = 0;
+ break;
+
+ case CARD_BLANK1:
+ case CARD_BLANK2:
+ // Boring
+ amusement = 0;
+ break;
+
+ case CARD_DAMNATION:
+ // Nothing happened, boring.
+ if (you.level_type != LEVEL_DUNGEON)
+ amusement = 0;
+ break;
+
+ case CARD_MINEFIELD:
+ case CARD_FAMINE:
+ case CARD_CURSE:
+ // Always hilarious.
+ amusement = 255;
+
+ default:
+ break;
+ }
+
+ return amusement;
}
// In general, if the next cards in a deck are known, they will
@@ -487,68 +1150,79 @@ void draw_from_deck_of_punishment()
// card could clobber the sign bit in special.
void evoke_deck( item_def& deck )
{
+ if (check_buggy_deck(deck))
+ return;
+
int brownie_points = 0;
- mpr("You draw a card...");
bool allow_id = in_inventory(deck) && !item_ident(deck, ISFLAG_KNOW_TYPE);
bool fake_draw = false;
- // If the deck wasn't marked, draw a fair card.
- if ( deck.plus2 == 0 )
+ unsigned char flags = 0;
+ card_type card = draw_top_card(deck, true, flags);
+ int amusement = xom_check_card(deck, card, flags);
+ deck_rarity_type rarity = deck_rarity(deck);
+ CrawlHashTable &props = deck.props;
+ bool no_brownie = (props["non_brownie_draws"].get_byte() > 0);
+
+ // Do these before the deck item_def object is gone.
+ if (flags & CFLAG_MARKED)
+ props["num_marked"]--;
+ if (no_brownie)
+ props["non_brownie_draws"]--;
+
+ deck.plus2++;
+
+ // Get rid of the deck *before* the card effect because a card
+ // might cause a wielded deck to be swapped out for something else,
+ // in which case we don't want an empty deck to go through the
+ // swapping process.
+ const bool deck_gone = (cards_in_deck(deck) == 0);
+ if ( deck_gone )
{
- fake_draw =
- !card_effect( choose_one_card(deck, true), deck_rarity(deck) );
+ mpr("The deck of cards disappears in a puff of smoke.");
+ dec_inv_item_quantity( deck.link, 1 );
+ // Finishing the deck will earn a point, even if it
+ // was marked or stacked.
+ brownie_points++;
+ }
+
+ const bool fake_draw = !card_effect(card, rarity, flags, false);
+ if ( fake_draw && !deck_gone )
+ props["non_brownie_draws"]++;
+
+ if (!(flags & CFLAG_MARKED))
+ {
+ // Could a Xom worshipper ever get a stacked deck in the first
+ // place?
+ xom_is_stimulated(amusement);
- if ( deck.sub_type != MISC_DECK_OF_PUNISHMENT )
+ // Nemelex likes gamblers.
+ if (!no_brownie)
{
- // Nemelex likes gamblers.
brownie_points = 1;
if (one_chance_in(3))
brownie_points++;
}
- }
- else
- {
+
// You can't ID off a marked card
allow_id = false;
-
- // draw the marked card
- fake_draw = !card_effect(static_cast<card_type>(deck.plus2 - 1),
- deck_rarity(deck));
-
- // If there are more marked cards, shift them up
- if ( deck.special )
- {
- const short next_card = (deck.special & 0xFF);
- deck.special >>= 8;
- deck.plus2 = next_card;
- }
- else
- {
- deck.plus2 = 0;
- }
- you.wield_change = true;
- }
- deck.plus--;
-
- if ( deck.plus == 0 )
- {
- mpr("The deck of cards disappears in a puff of smoke.");
- dec_inv_item_quantity( deck.link, 1 );
- // Finishing the deck will earn a point, even if it
- // was marked or stacked.
- brownie_points++;
}
- else if (allow_id && (you.skills[SK_EVOCATIONS] > 5 + random2(35)))
+
+ if (!deck_gone && allow_id
+ && (you.skills[SK_EVOCATIONS] > 5 + random2(35)))
{
mpr("Your skill with magical items lets you identify the deck.");
set_ident_flags( deck, ISFLAG_KNOW_TYPE );
msg::streams(MSGCH_EQUIPMENT) << deck.name(DESC_INVENTORY)
<< std::endl;
- you.wield_change = true;
}
- if (!fake_draw)
+ if ( !fake_draw )
did_god_conduct(DID_CARDS, brownie_points);
+
+ // Always wield change, since the number of cards used/left has
+ // changed.
+ you.wield_change = true;
}
int get_power_level(int power, deck_rarity_type rarity)
@@ -794,9 +1468,7 @@ static void minefield_card(int power, deck_rarity_type rarity)
// to target. This is still exploitable by finding popcorn monsters.
static bool damaging_card(card_type card, int power, deck_rarity_type rarity)
{
- extern bool there_are_monsters_nearby();
bool rc = there_are_monsters_nearby();
-
const int power_level = get_power_level(power, rarity);
dist target;
@@ -871,8 +1543,8 @@ static void elixir_card(int power, deck_rarity_type rarity)
you.hp = you.hp_max;
you.magic_points = you.max_magic_points;
}
- you.redraw_hit_points = 1;
- you.redraw_magic_points = 1;
+ you.redraw_hit_points = true;
+ you.redraw_magic_points = true;
}
static void battle_lust_card(int power, deck_rarity_type rarity)
@@ -988,7 +1660,24 @@ static void blade_card(int power, deck_rarity_type rarity)
}
else
{
- brand_weapon(SPWPN_VORPAL, random2(power/4)); // maybe other brands?
+ const brand_type brands[] = {
+ SPWPN_FLAMING, SPWPN_FREEZING, SPWPN_VENOM, SPWPN_DRAINING,
+ SPWPN_VORPAL, SPWPN_DISTORTION, SPWPN_PAIN, SPWPN_DUMMY_CRUSHING
+ };
+
+ if ( !brand_weapon(RANDOM_ELEMENT(brands), random2(power/4)) )
+ {
+ if ( you.equip[EQ_WEAPON] == -1 )
+ {
+ msg::stream << "Your " << your_hand(true) << " twitch."
+ << std::endl;
+ }
+ else
+ {
+ msg::stream << "Your weapon vibrates for a moment."
+ << std::endl;
+ }
+ }
}
}
@@ -1054,9 +1743,45 @@ static void focus_card(int power, deck_rarity_type rarity)
(*max_statp[worst_stat])--;
(*base_statp[best_stat])++;
(*base_statp[worst_stat])--;
+
+ // Did focusing kill the player?
+ kill_method_type kill_types[3] = {
+ KILLED_BY_WEAKNESS,
+ KILLED_BY_CLUMSINESS,
+ KILLED_BY_STUPIDITY
+ };
+
+ std::string cause = "the Focus card";
+
+ if (crawl_state.is_god_acting())
+ {
+ god_type which_god = crawl_state.which_god_acting();
+ if (crawl_state.is_god_retribution()) {
+ cause = "the wrath of ";
+ cause += god_name(which_god);
+ }
+ else
+ {
+ if (which_god == GOD_XOM)
+ cause = "the capriciousness of Xom";
+ else
+ {
+ cause = "the 'helpfullness' of ";
+ cause += god_name(which_god);
+ }
+ }
+ }
+
+ for ( int i = 0; i < 3; ++i )
+ if (*max_statp[i] < 1 || *base_statp[i] < 1)
+ ouch(INSTANT_DEATH, 0, kill_types[i], cause.c_str(), true);
+
+ // The player survived!
you.redraw_strength = true;
you.redraw_intelligence = true;
you.redraw_dexterity = true;
+
+ burden_change();
}
static void shuffle_card(int power, deck_rarity_type rarity)
@@ -1080,7 +1805,41 @@ static void shuffle_card(int power, deck_rarity_type rarity)
new_base[perm[i]] = old_base[i] - modifiers[i] + modifiers[perm[i]];
new_max[perm[i]] = old_max[i] - modifiers[i] + modifiers[perm[i]];
}
-
+
+ // Did the shuffling kill the player?
+ kill_method_type kill_types[3] = {
+ KILLED_BY_WEAKNESS,
+ KILLED_BY_CLUMSINESS,
+ KILLED_BY_STUPIDITY
+ };
+
+ std::string cause = "the Shuffle card";
+
+ if (crawl_state.is_god_acting())
+ {
+ god_type which_god = crawl_state.which_god_acting();
+ if (crawl_state.is_god_retribution()) {
+ cause = "the wrath of ";
+ cause += god_name(which_god);
+ }
+ else
+ {
+ if (which_god == GOD_XOM)
+ cause = "the capriciousness of Xom";
+ else
+ {
+ cause = "the 'helpfulness' of ";
+ cause += god_name(which_god);
+ }
+ }
+ }
+
+ for ( int i = 0; i < 3; ++i )
+ if (new_base[i] < 1 || new_max[i] < 1)
+ ouch(INSTANT_DEATH, 0, kill_types[i], cause.c_str(), true);
+
+ // The player survived!
+
// Sometimes you just long for Python.
you.strength = new_base[0];
you.dex = new_base[1];
@@ -1094,13 +1853,15 @@ static void shuffle_card(int power, deck_rarity_type rarity)
you.redraw_intelligence = true;
you.redraw_dexterity = true;
you.redraw_evasion = true;
+
+ burden_change();
}
static void helix_card(int power, deck_rarity_type rarity)
{
mutation_type bad_mutations[] = {
MUT_FAST_METABOLISM, MUT_WEAK, MUT_DOPEY, MUT_CLUMSY,
- MUT_TELEPORT, MUT_DEFORMED, MUT_LOST, MUT_DETERIORATION,
+ MUT_TELEPORT, MUT_DEFORMED, MUT_SCREAM, MUT_DETERIORATION,
MUT_BLURRY_VISION, MUT_FRAIL
};
@@ -1114,6 +1875,8 @@ static void helix_card(int power, deck_rarity_type rarity)
}
if ( numfound )
delete_mutation(which_mut);
+ else
+ mpr("You feel transcendent for a moment.");
}
static void dowsing_card(int power, deck_rarity_type rarity)
@@ -1210,7 +1973,7 @@ static void trowel_card(int power, deck_rarity_type rarity)
}
if ( !done_stuff )
- mpr("Nothing appears to happen.");
+ canned_msg(MSG_NOTHING_HAPPENS);
return;
}
@@ -1243,6 +2006,7 @@ static void curse_card(int power, deck_rarity_type rarity)
{
const int power_level = get_power_level(power, rarity);
+ mpr("You feel a malignant aura surround you.");
if ( power_level >= 2 )
{
// curse (almost) everything + decay
@@ -1264,6 +2028,39 @@ static void curse_card(int power, deck_rarity_type rarity)
}
}
+static void crusade_card(int power, deck_rarity_type rarity)
+{
+ const int power_level = get_power_level(power, rarity);
+ if ( power_level >= 1 )
+ {
+ // A chance to convert opponents.
+ for ( int i = 0; i < MAX_MONSTERS; ++i )
+ {
+ monsters* const monster = &menv[i];
+ if (monster->type == -1 || !mons_near(monster) ||
+ mons_friendly(monster) ||
+ mons_holiness(monster) != MH_NATURAL ||
+ mons_is_unique(monster->type) ||
+ mons_immune_magic(monster))
+ continue;
+
+ // Note that this bypasses the magic resistance
+ // (though not immunity) check. Specifically,
+ // you can convert Killer Klowns this way.
+ // Might be too good.
+ if ( monster->hit_dice * 35 < random2(power) )
+ {
+ simple_monster_message(monster, " is converted.");
+ if ( one_chance_in(5 - power_level) )
+ monster->attitude = ATT_FRIENDLY;
+ else
+ monster->add_ench(ENCH_CHARM);
+ }
+ }
+ }
+ abjuration(power/4);
+}
+
static void summon_demon_card(int power, deck_rarity_type rarity)
{
const int power_level = get_power_level(power, rarity);
@@ -1331,7 +2128,7 @@ static void summon_dancing_weapon(int power, deck_rarity_type rarity)
friendly ? BEH_FRIENDLY : BEH_HOSTILE,
you.x_pos, you.y_pos,
friendly ? you.pet_target : MHITYOU,
- 250 );
+ 250, false, false, false, true );
// Given the abundance of Nemelex decks, not setting hard reset
// leaves a trail of weapons behind, most of which just get
@@ -1358,14 +2155,15 @@ static int card_power(deck_rarity_type rarity)
result += you.skills[SK_EVOCATIONS] * 9;
if ( rarity == DECK_RARITY_RARE )
- result += random2(result / 2);
+ result += 150;
if ( rarity == DECK_RARITY_LEGENDARY )
- result += random2(result);
+ result += 300;
return result;
}
-bool card_effect(card_type which_card, deck_rarity_type rarity)
+bool card_effect(card_type which_card, deck_rarity_type rarity,
+ unsigned char flags, bool tell_card)
{
bool rc = true;
const int power = card_power(rarity);
@@ -1375,12 +2173,27 @@ bool card_effect(card_type which_card, deck_rarity_type rarity)
<< std::endl;
#endif
- msg::stream << "You have drawn " << card_name( which_card )
- << '.' << std::endl;
+ if (tell_card)
+ msg::stream << "You have drawn " << card_name( which_card )
+ << '.' << std::endl;
+
+ if (which_card == CARD_XOM && !crawl_state.is_god_acting())
+ {
+ if (you.religion == GOD_XOM)
+ {
+ // Being a self-centered deity, Xom *always* finds this
+ // maximally hilarious.
+ god_speaks(GOD_XOM, "Xom roars with laughter!");
+ you.gift_timeout = 255;
+ }
+ else if (you.penance[GOD_XOM])
+ god_speaks(GOD_XOM, "Xom laughs nastily.");
+ }
switch (which_card)
{
- case CARD_BLANK: break;
+ case CARD_BLANK1: break;
+ case CARD_BLANK2: break;
case CARD_PORTAL: portal_card(power, rarity); break;
case CARD_WARP: warp_card(power, rarity); break;
case CARD_SWAP: swap_monster_card(power, rarity); break;
@@ -1403,9 +2216,10 @@ bool card_effect(card_type which_card, deck_rarity_type rarity)
case CARD_GENIE: genie_card(power, rarity); break;
case CARD_CURSE: curse_card(power, rarity); break;
case CARD_WARPWRIGHT: warpwright_card(power, rarity); break;
- case CARD_TOMB: entomb(power/2); break;
+ case CARD_TOMB: entomb(power); break;
case CARD_WRAITH: drain_exp(false); lose_level(); break;
case CARD_WRATH: godly_wrath(); break;
+ case CARD_CRUSADE: crusade_card(power, rarity); break;
case CARD_SUMMON_DEMON: summon_demon_card(power, rarity); break;
case CARD_SUMMON_ANIMAL: summon_animals(random2(power/3)); break;
case CARD_SUMMON_ANY: summon_any_monster(power, rarity); break;
@@ -1440,10 +2254,9 @@ bool card_effect(card_type which_card, deck_rarity_type rarity)
case CARD_WILD_MAGIC:
// yes, high power is bad here
miscast_effect( SPTYP_RANDOM, random2(power/15) + 5,
- random2(power), 0 );
+ random2(power), 0, "a card of wild magic" );
break;
-
case CARD_FAMINE:
if (you.is_undead == US_UNDEAD)
mpr("You feel rather smug.");
@@ -1463,12 +2276,43 @@ bool card_effect(card_type which_card, deck_rarity_type rarity)
break;
}
+ if (you.religion == GOD_XOM
+ && (which_card == CARD_BLANK1 || which_card == CARD_BLANK2 || !rc))
+ {
+ god_speaks(GOD_XOM, "\"How boring, let's spice things up a little.\"");
+ xom_acts(abs(you.piety - 100));
+ }
+
if (you.religion == GOD_NEMELEX_XOBEH && !rc)
simple_god_message(" seems disappointed in you.");
-
+
return rc;
}
+bool top_card_is_known(const item_def &deck)
+{
+ if (!is_deck(deck))
+ return false;
+
+ unsigned char flags;
+ get_card_and_flags(deck, -1, flags);
+
+ return (flags & CFLAG_MARKED);
+}
+
+card_type top_card(const item_def &deck)
+{
+ if (!is_deck(deck))
+ return NUM_CARDS;
+
+ unsigned char flags;
+ card_type card = get_card_and_flags(deck, -1, flags);
+
+ UNUSED(flags);
+
+ return card;
+}
+
bool is_deck(const item_def &item)
{
return item.base_type == OBJ_MISCELLANY
@@ -1476,17 +2320,79 @@ bool is_deck(const item_def &item)
item.sub_type <= MISC_DECK_OF_DEFENSE);
}
+bool bad_deck(const item_def &item)
+{
+ if (!is_deck(item))
+ return false;
+
+ return (!item.props.exists("cards")
+ || item.props["cards"].get_type() != SV_VEC
+ || item.props["cards"].get_vector().get_type() != SV_BYTE
+ || cards_in_deck(item) == 0);
+}
+
deck_rarity_type deck_rarity(const item_def &item)
{
ASSERT( is_deck(item) );
- switch (item.colour)
+
+ return static_cast<deck_rarity_type>(item.special);
+}
+
+unsigned char deck_rarity_to_color(deck_rarity_type rarity)
+{
+ switch (rarity)
{
- case BLACK: case BLUE: case GREEN: case CYAN: case RED:
- default:
- return DECK_RARITY_COMMON;
- case MAGENTA: case BROWN:
- return DECK_RARITY_RARE;
- case LIGHTMAGENTA:
- return DECK_RARITY_LEGENDARY;
+ case DECK_RARITY_COMMON:
+ {
+ const unsigned char colours[] = {LIGHTBLUE, GREEN, CYAN, RED};
+ return RANDOM_ELEMENT(colours);
+ }
+
+ case DECK_RARITY_RARE:
+ return (coinflip() ? MAGENTA : BROWN);
+
+ case DECK_RARITY_LEGENDARY:
+ return LIGHTMAGENTA;
+ }
+
+ return (WHITE);
+}
+
+void init_deck(item_def &item)
+{
+ CrawlHashTable &props = item.props;
+
+ ASSERT(is_deck(item));
+ ASSERT(!props.exists("cards"));
+ ASSERT(item.plus > 0);
+ ASSERT(item.plus <= 127);
+ ASSERT(item.special >= DECK_RARITY_COMMON
+ && item.special <= DECK_RARITY_LEGENDARY);
+
+ props.set_default_flags(SFLAG_CONST_TYPE);
+
+ props["cards"].new_vector(SV_BYTE).resize(item.plus);
+ props["card_flags"].new_vector(SV_BYTE).resize(item.plus);
+
+ for (int i = 0; i < item.plus; i++)
+ {
+ bool was_odd = false;
+ card_type card = random_card(item, was_odd);
+
+ unsigned char flags = 0;
+ if (was_odd)
+ flags = CFLAG_ODDITY;
+
+ set_card_and_flags(item, i, card, flags);
}
+
+ ASSERT(cards_in_deck(item) == item.plus);
+
+ props["num_marked"] = (char) 0;
+ props["non_brownie_draws"] = (char) 0;
+
+ props.assert_validity();
+
+ item.plus2 = 0;
+ item.colour = deck_rarity_to_color((deck_rarity_type) item.special);
}
diff --git a/crawl-ref/source/decks.h b/crawl-ref/source/decks.h
index 929ba71551..feeceaabd6 100644
--- a/crawl-ref/source/decks.h
+++ b/crawl-ref/source/decks.h
@@ -17,6 +17,19 @@
#include "externs.h"
+// DECK STRUCTURE: deck.plus is the number of cards the deck *started*
+// with, deck.plus2 is the number of cards drawn, deck.special is the
+// deck rarity, deck.props["cards"] holds the list of cards (with the
+// highest index card being the top card, and index 0 being the bottom
+// card), deck.props.["card_flags"] holds the flags for each card,
+// deck.props["num_marked"] is the number of marked cards left in the
+// deck, and deck.props["non_brownie_draws"] is the number of
+// non-marked draws you have to make from that deck before earning
+// brownie points from it again.
+//
+// The card type and per-card flags are each stored as unsigned bytes,
+// for a maximum of 256 different kinds of cards and 8 bits of flags.
+
enum deck_rarity_type
{
DECK_RARITY_COMMON,
@@ -34,16 +47,99 @@ enum deck_type
DECK_OF_WONDERS
};
+enum card_flags_type
+{
+ CFLAG_ODDITY = (1 << 0),
+ CFLAG_SEEN = (1 << 1),
+ CFLAG_MARKED = (1 << 2)
+};
+
+enum card_type
+{
+ CARD_BLANK1 = 0, // non-retried
+ CARD_BLANK2, // retried and failed
+ CARD_PORTAL, // "the mover"
+ CARD_WARP, // "the jumper"
+ CARD_SWAP, // "swap"
+ CARD_VELOCITY, // "the runner"
+
+ CARD_TOMB, // "the wall"
+ CARD_BANSHEE, // "the scream"
+ CARD_DAMNATION, // banishment
+ CARD_SOLITUDE, // dispersal
+ CARD_WARPWRIGHT, // create teleport trap
+
+ CARD_VITRIOL, // acid damage
+ CARD_FLAME, // fire damage
+ CARD_FROST, // cold damage
+ CARD_VENOM, // poison damage
+ CARD_HAMMER, // pure damage
+ CARD_PAIN, // single target, like spell of agony
+ CARD_TORMENT, // Symbol of Torment
+
+ CARD_ELIXIR, // healing
+ CARD_BATTLELUST, // melee boosts
+ CARD_METAMORPHOSIS, // transformation
+ CARD_HELM, // defense
+ CARD_BLADE, // weapon boosts
+ CARD_SHADOW, // assassin skills
+
+ CARD_CRUSADE,
+ CARD_SUMMON_ANIMAL,
+ CARD_SUMMON_DEMON,
+ CARD_SUMMON_WEAPON,
+ CARD_SUMMON_ANY,
+
+ CARD_POTION,
+ CARD_FOCUS,
+ CARD_SHUFFLE,
+
+ CARD_EXPERIENCE,
+ CARD_WILD_MAGIC,
+ CARD_HELIX, // remove one *bad* mutation
+
+ CARD_MAP, // magic mapping
+ CARD_DOWSING, // detect SD/traps/items/monsters
+ CARD_SPADE, // dig
+ CARD_TROWEL, // create feature/vault
+ CARD_MINEFIELD, // plant traps
+
+ CARD_GENIE, // acquirement OR rotting/deterioration
+ CARD_BARGAIN, // shopping discount
+ CARD_WRATH, // Godly wrath
+ CARD_WRAITH, // drain XP
+ CARD_XOM,
+ CARD_FEAST,
+ CARD_FAMINE,
+ CARD_CURSE, // Curse your items
+
+ NUM_CARDS
+};
+
const char* card_name(card_type card);
void evoke_deck(item_def& deck);
bool deck_triple_draw();
bool deck_peek();
+bool deck_mark();
bool deck_stack();
bool choose_deck_and_draw();
-bool card_effect(card_type which_card, deck_rarity_type rarity);
+
+// Return true if it was a "genuine" draw, false otherwise.
+bool card_effect(card_type which_card, deck_rarity_type rarity,
+ unsigned char card_flags = 0, bool tell_card = true);
void draw_from_deck_of_punishment();
+bool top_card_is_known(const item_def &item);
+card_type top_card(const item_def &item);
+
bool is_deck(const item_def &item);
+bool bad_deck(const item_def &item);
deck_rarity_type deck_rarity(const item_def &item);
+unsigned char deck_rarity_to_color(deck_rarity_type rarity);
+void init_deck(item_def &item);
+
+int cards_in_deck(const item_def &deck);
+card_type get_card_and_flags(const item_def& deck, int idx,
+ unsigned char& _flags);
#endif
diff --git a/crawl-ref/source/defines.h b/crawl-ref/source/defines.h
index 9a1a137be3..b396283eb0 100644
--- a/crawl-ref/source/defines.h
+++ b/crawl-ref/source/defines.h
@@ -51,12 +51,17 @@
#define MAX_GHOSTS 10
// max size of monter array {dlb}:
-#define MAX_MONSTERS 200
+#define MAX_MONSTERS 350
// number of monster enchantments
#define NUM_MON_ENCHANTS 6
// non-monster for mgrd[][] -- (MNST + 1) {dlb}:
#define NON_MONSTER (MAX_MONSTERS + 1)
+// (MNG) -- for a reason! see usage {dlb}:
+#define MHITNOT (MAX_MONSTERS + 1)
+// (MNG + 1) -- for a reason! see usage {dlb}:
+#define MHITYOU (MAX_MONSTERS + 2)
+
#define MAX_SUBTYPES 50
// max size of item list {dlb}:
@@ -82,7 +87,9 @@
// This is the border that must be left around the map. I'm not sure why it's
// necessary, beyond hysterical raisins.
-#define MAPGEN_BORDER 6
+const int MAPGEN_BORDER = 2;
+
+const int LABYRINTH_BORDER = 12;
// Now some defines about the actual play area:
// Note: these boundaries are exclusive for the zone the player can move/dig,
@@ -206,11 +213,6 @@
#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
@@ -298,5 +300,6 @@
#define KEY_MACRO_MORE_PROTECT -10
#define KEY_MACRO_DISABLE_MORE -1
#define KEY_MACRO_ENABLE_MORE -2
+#define KEY_REPEAT_KEYS -3
#endif
diff --git a/crawl-ref/source/delay.cc b/crawl-ref/source/delay.cc
index c72a15f30b..e9ee8bff90 100644
--- a/crawl-ref/source/delay.cc
+++ b/crawl-ref/source/delay.cc
@@ -38,10 +38,12 @@
#include "religion.h"
#include "spl-util.h"
#include "stash.h"
+#include "state.h"
#include "stuff.h"
#include "travel.h"
#include "tutorial.h"
#include "view.h"
+#include "xom.h"
extern std::vector<SelItem> items_for_multidrop;
@@ -103,39 +105,25 @@ static void clear_pending_delays()
void start_delay( delay_type type, int turns, int parm1, int parm2 )
/***********************************************************/
{
+ ASSERT(!crawl_state.is_repeating_cmd() || type == DELAY_MACRO);
+
delay_queue_item delay;
delay.type = type;
delay.duration = turns;
delay.parm1 = parm1;
delay.parm2 = parm2;
+ delay.started = false;
// Handle zero-turn delays (possible with butchering).
if (turns == 0)
{
+ delay.started = true;
// Don't issue startup message.
if (push_delay(delay) == 0)
finish_delay(delay);
return;
}
-
- switch ( delay.type )
- {
- case DELAY_ARMOUR_ON:
- mpr("You start putting on your armour.", MSGCH_MULTITURN_ACTION);
- break;
- case DELAY_ARMOUR_OFF:
- mpr("You start removing your armour.", MSGCH_MULTITURN_ACTION);
- break;
- case DELAY_MEMORISE:
- mpr("You start memorising the spell.", MSGCH_MULTITURN_ACTION);
- break;
- case DELAY_PASSWALL:
- mpr("You begin to meditate on the wall.", MSGCH_MULTITURN_ACTION);
- break;
- default:
- break;
- }
push_delay( delay );
}
@@ -147,6 +135,8 @@ void stop_delay( void )
delay_queue_item delay = you.delay_queue.front();
+ ASSERT(!crawl_state.is_repeating_cmd() || delay.type == DELAY_MACRO);
+
const bool butcher_swap_warn =
delay.type == DELAY_BUTCHER
&& (you.delay_queue.size() >= 2
@@ -305,6 +295,17 @@ bool is_being_butchered(const item_def &item)
return (false);
}
+// Xom is amused by a potential food source going to waste, and is
+// more amused the hungrier you are.
+static void xom_check_corpse_waste()
+{
+ int food_need = 7000 - you.hunger;
+ if (food_need < 0)
+ food_need = 0;
+
+ xom_is_stimulated(64 + (191 * food_need / 6000));
+}
+
void handle_delay( void )
/***********************/
{
@@ -313,6 +314,33 @@ void handle_delay( void )
delay_queue_item &delay = you.delay_queue.front();
+ if ( !delay.started )
+ {
+ switch ( delay.type )
+ {
+ case DELAY_ARMOUR_ON:
+ mpr("You start putting on your armour.", MSGCH_MULTITURN_ACTION);
+ break;
+ case DELAY_ARMOUR_OFF:
+ mpr("You start removing your armour.", MSGCH_MULTITURN_ACTION);
+ break;
+ case DELAY_BUTCHER:
+ mpr("You start butchering the corpse.", MSGCH_MULTITURN_ACTION);
+ break;
+ case DELAY_MEMORISE:
+ mpr("You start memorising the spell.", MSGCH_MULTITURN_ACTION);
+ break;
+ case DELAY_PASSWALL:
+ mpr("You begin to meditate on the wall.", MSGCH_MULTITURN_ACTION);
+ break;
+ default:
+ break;
+ }
+ delay.started = true;
+ }
+
+ ASSERT(!crawl_state.is_repeating_cmd() || delay.type == DELAY_MACRO);
+
// Run delays and Lua delays don't have a specific end time.
if (is_run_delay(delay.type))
{
@@ -338,24 +366,41 @@ void handle_delay( void )
// 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 possibility just to
- // be nice. -- bwr
+ // original and that's why we do it this way.
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 )
{
- // special < 100 is the rottenness check
- if ( (mitm[delay.parm1].special < 100) &&
- (delay.parm2 >= 100) )
+ if (mitm[ delay.parm1 ].sub_type == CORPSE_SKELETON)
{
- mpr("The corpse rots.", MSGCH_ROTTEN_MEAT);
- delay.parm2 = 99; // don't give the message twice
+ mpr("The corpse rots away into a skeleton!");
+ if (you.mutation[MUT_SAPROVOROUS] == 3)
+ xom_check_corpse_waste();
+ else
+ xom_is_stimulated(32);
+ delay.duration = 0;
}
+ else
+ {
+ // special < 100 is the rottenness check
+ if ( (mitm[delay.parm1].special < 100) &&
+ (delay.parm2 >= 100) )
+ {
+ mpr("The corpse rots.", MSGCH_ROTTEN_MEAT);
+ delay.parm2 = 99; // don't give the message twice
+
+ if (you.species != SP_VAMPIRE
+ && you.is_undead != US_UNDEAD
+ && you.mutation[MUT_SAPROVOROUS] < 3)
+ {
+ xom_check_corpse_waste();
+ }
+ }
- // mark work done on the corpse in case we stop -- bwr
- mitm[ delay.parm1 ].plus2++;
+ // mark work done on the corpse in case we stop -- bwr
+ mitm[ delay.parm1 ].plus2++;
+ }
}
else
{
@@ -534,6 +579,8 @@ static void finish_delay(const delay_queue_item &delay)
{
case DNGN_ROCK_WALL:
case DNGN_STONE_WALL:
+ case DNGN_CLEAR_ROCK_WALL:
+ case DNGN_CLEAR_STONE_WALL:
case DNGN_METAL_WALL:
case DNGN_GREEN_CRYSTAL_WALL:
case DNGN_WAX_WALL:
@@ -572,10 +619,28 @@ static void finish_delay(const delay_queue_item &delay)
const item_def &item = mitm[delay.parm1];
if (is_valid_item(item) && item.base_type == OBJ_CORPSES)
{
+
+ if (item.sub_type == CORPSE_SKELETON)
+ {
+ mpr("The corpse rots away into a skeleton just before you "
+ "finish butchering it!");
+
+ if (you.mutation[MUT_SAPROVOROUS] == 3)
+ xom_check_corpse_waste();
+ else
+ xom_is_stimulated(64);
+
+ break;
+ }
+
mprf("You finish %s the corpse into pieces.",
(you.has_usable_claws() || you.mutation[MUT_FANGS] == 3) ?
"ripping" : "chopping");
+ if (is_good_god(you.religion) && is_player_same_species(item.plus))
+ simple_god_message(" expects more respect for your departed "
+ "relatives.");
+
if (you.species == SP_VAMPIRE &&
(!god_likes_butchery(you.religion) ||
!you.duration[DUR_PRAYER]))
@@ -663,7 +728,8 @@ static void armour_wear_effects(const int item_slot)
set_ident_flags(arm, ISFLAG_EQ_ARMOUR_MASK );
mprf("You finish putting on %s.", arm.name(DESC_NOCAP_YOUR).c_str());
- const equipment_type eq_slot = get_armour_slot(arm);
+ const equipment_type eq_slot = get_armour_slot(arm);
+ const bool known_cursed = item_known_cursed(arm);
if (eq_slot == EQ_BODY_ARMOUR)
{
@@ -738,15 +804,15 @@ static void armour_wear_effects(const int item_slot)
break;
case SPARM_STRENGTH:
- modify_stat(STAT_STRENGTH, 3, false);
+ modify_stat(STAT_STRENGTH, 3, false, arm);
break;
case SPARM_DEXTERITY:
- modify_stat(STAT_DEXTERITY, 3, false);
+ modify_stat(STAT_DEXTERITY, 3, false, arm);
break;
case SPARM_INTELLIGENCE:
- modify_stat(STAT_INTELLIGENCE, 3, false);
+ modify_stat(STAT_INTELLIGENCE, 3, false, arm);
break;
case SPARM_PONDEROUSNESS:
@@ -795,7 +861,16 @@ static void armour_wear_effects(const int item_slot)
{
mpr( "Oops, that feels deathly cold." );
learned_something_new(TUT_YOU_CURSED);
- xom_is_stimulated(128);
+
+ // Cursed cloaks prevent you from removing body armour
+ int cloak_mult = 1;
+ if (get_armour_slot(arm) == EQ_CLOAK)
+ cloak_mult = 2;
+
+ if (known_cursed)
+ xom_is_stimulated(32 * cloak_mult);
+ else
+ xom_is_stimulated(64 * cloak_mult);
}
if (eq_slot == EQ_SHIELD)
@@ -1002,7 +1077,7 @@ inline static void monster_warning(activity_interrupt_type ai,
if (!mon->visible())
return;
#ifndef DEBUG_DIAGNOSTICS
- if (at.context != "uncharm")
+ if (at.context == "already seen")
{
// Only say "comes into view" if the monster wasn't in view
// during the previous turn.
@@ -1030,18 +1105,33 @@ inline static void monster_warning(activity_interrupt_type ai,
break;
}
}
- else
+ }
+ else
+ {
+ const std::string mweap =
+ get_monster_desc(mon, false, DESC_NONE);
+ std::string text = mon->name(DESC_CAP_A);
+
+ if (at.context == "thin air")
{
- const std::string mweap =
- get_monster_desc(mon, false, DESC_NONE);
- std::string text = mon->name(DESC_CAP_A) + " comes into view.";
- if (!mweap.empty())
- text += " " + mon->pronoun(PRONOUN_CAP)
- + " is" + mweap + ".";
- print_formatted_paragraph(text,
- get_number_of_cols(),
- MSGCH_WARN);
+ if (mon->type == MONS_AIR_ELEMENTAL)
+ text += " forms itself from the air.";
+ else
+ text += " appears from thin air.";
}
+ else if (at.context == "surfaces")
+ text += " surfaces.";
+ else if (at.context.find("bursts forth") != std::string::npos)
+ text += " bursts forth from the water.";
+ else
+ text += " comes into view.";
+
+ if (!mweap.empty())
+ text += " " + mon->pronoun(PRONOUN_CAP)
+ + " is" + mweap + ".";
+ print_formatted_paragraph(text,
+ get_number_of_cols(),
+ MSGCH_WARN);
}
if (Options.tutorial_left)
@@ -1080,7 +1170,7 @@ static void paranoid_option_disable( activity_interrupt_type ai,
restart.push_back("Ctrl+V");
}
- if (Options.autopickup_on && Options.safe_autopickup)
+ if (Options.autopickup_on)
{
deactivatees.push_back("autopickup");
Options.autopickup_on = false;
@@ -1102,7 +1192,10 @@ bool interrupt_activity( activity_interrupt_type ai,
const activity_interrupt_data &at )
{
paranoid_option_disable(ai, at);
-
+
+ if (crawl_state.is_repeating_cmd())
+ return interrupt_cmd_repeat(ai, at);
+
const int delay = current_delay_action();
if (delay == DELAY_NOT_DELAYED)
diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc
index e37251368f..b9bafa5278 100644
--- a/crawl-ref/source/describe.cc
+++ b/crawl-ref/source/describe.cc
@@ -54,7 +54,7 @@
#include "stuff.h"
#include "spl-util.h"
#include "tutorial.h"
-
+#include "xom.h"
// ========================================================================
// Internal Functions
@@ -89,7 +89,7 @@ static void append_value( std::string & description, int valu, bool plussed )
// word and such. The character $ is interpreted as a CR.
//
//---------------------------------------------------------------
-static void print_description( const std::string &d )
+void print_description( const std::string &d )
{
std::string::size_type nextLine = std::string::npos;
unsigned int currentPos = 0;
@@ -152,174 +152,194 @@ static void print_description( const std::string &d )
}
}
-//---------------------------------------------------------------
-//
-// randart_descrip
-//
-// Appends the various powers of a random artefact to the description
-// string.
-//
-//---------------------------------------------------------------
-static void randart_descrip( std::string &description, const item_def &item )
+static std::string randart_descrip( const item_def &item )
{
- unsigned int old_length = description.length();
+#define known_proprt(prop) (proprt[(prop)] && known[(prop)])
+ std::string description;
- randart_properties_t proprt;
- randart_wpn_properties( item, proprt );
+ randart_properties_t proprt;
+ randart_known_props_t known;
+ randart_desc_properties( item, proprt, known );
- if (proprt[ RAP_AC ])
+ if (known_proprt( RAP_AC ))
{
description += "$It affects your AC (";
append_value(description, proprt[ RAP_AC ], true);
description += ").";
}
- if (proprt[ RAP_EVASION ])
+ if (known_proprt( RAP_EVASION ))
{
description += "$It affects your evasion (";
append_value(description, proprt[ RAP_EVASION ], true);
description += ").";
}
- if (proprt[ RAP_STRENGTH ])
+ if (known_proprt( RAP_STRENGTH ))
{
description += "$It affects your strength (";
append_value(description, proprt[ RAP_STRENGTH ], true);
description += ").";
}
- if (proprt[ RAP_INTELLIGENCE ])
+ if (known_proprt( RAP_INTELLIGENCE ))
{
description += "$It affects your intelligence (";
append_value(description, proprt[ RAP_INTELLIGENCE ], true);
description += ").";
}
- if (proprt[ RAP_DEXTERITY ])
+ if (known_proprt( RAP_DEXTERITY ))
{
description += "$It affects your dexterity (";
append_value(description, proprt[ RAP_DEXTERITY ], true);
description += ").";
}
- if (proprt[ RAP_ACCURACY ])
+ if (known_proprt( RAP_ACCURACY ))
{
description += "$It affects your accuracy (";
append_value(description, proprt[ RAP_ACCURACY ], true);
description += ").";
}
- if (proprt[ RAP_DAMAGE ])
+ if (known_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 extremely vulnerable to fire. ";
- else if (proprt[ RAP_FIRE ] == -2)
- description += "$It makes you very vulnerable to fire. ";
- else if (proprt[ RAP_FIRE ] == -1)
- description += "$It makes you vulnerable 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 extremely vulnerable to cold. ";
- else if (proprt[ RAP_COLD ] == -2)
- description += "$It makes you very vulnerable to cold. ";
- else if (proprt[ RAP_COLD ] == -1)
- description += "$It makes you vulnerable 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 ])
+ if (known_proprt( RAP_FIRE ))
+ {
+ if (proprt[ RAP_FIRE ] < -2)
+ description += "$It makes you extremely vulnerable to fire. ";
+ else if (proprt[ RAP_FIRE ] == -2)
+ description += "$It makes you very vulnerable to fire. ";
+ else if (proprt[ RAP_FIRE ] == -1)
+ description += "$It makes you vulnerable 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 (known_proprt( RAP_COLD ))
+ {
+ if (proprt[ RAP_COLD ] < -2)
+ description += "$It makes you extremely vulnerable to cold. ";
+ else if (proprt[ RAP_COLD ] == -2)
+ description += "$It makes you very vulnerable to cold. ";
+ else if (proprt[ RAP_COLD ] == -1)
+ description += "$It makes you vulnerable 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 (known_proprt( RAP_ELECTRICITY ))
description += "$It insulates you from electricity. ";
- if (proprt[ RAP_POISON ])
+ if (known_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 to negative energy. ";
+ if (known_proprt( RAP_NEGATIVE_ENERGY ))
+ {
+ 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 to "
+ "negative energy. ";
+ }
- if (proprt[ RAP_MAGIC ])
- description += "$It amplifies your intrinsic magic resistance. ";
+ if (known_proprt( RAP_MAGIC ))
+ description += "$It increases your resistance to enchantments. ";
- if (proprt[ RAP_STEALTH ] < 0)
+ if (known_proprt( RAP_STEALTH ))
{
- if (proprt[ RAP_STEALTH ] < -20)
- description += "$It makes you much less stealthy. ";
- else
- description += "$It makes you less stealthy. ";
+ 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. ";
+ }
}
- else if (proprt[ RAP_STEALTH ] > 0)
+
+ if (known_proprt( RAP_MAGICAL_POWER ))
{
- if (proprt[ RAP_STEALTH ] > 20)
- description += "$It makes you much more stealthy. ";
- else
- description += "$It makes you more stealthy. ";
+ description += "$It affects your mana capacity (";
+ append_value(description, proprt[ RAP_MAGICAL_POWER ], true);
+ description += ").";
}
- if (proprt[ RAP_EYESIGHT ])
+ if (known_proprt( RAP_EYESIGHT ))
description += "$It enhances your eyesight. ";
- if (proprt[ RAP_INVISIBLE ])
+ if (known_proprt( RAP_INVISIBLE ))
description += "$It lets you turn invisible. ";
- if (proprt[ RAP_LEVITATE ])
+ if (known_proprt( RAP_LEVITATE ))
description += "$It lets you levitate. ";
- if (proprt[ RAP_BLINK ])
+ if (known_proprt( RAP_BLINK ))
description += "$It lets you blink. ";
- if (proprt[ RAP_CAN_TELEPORT ])
+ if (known_proprt( RAP_CAN_TELEPORT ))
description += "$It lets you teleport. ";
- if (proprt[ RAP_BERSERK ])
+ if (known_proprt( RAP_BERSERK ))
description += "$It lets you go berserk. ";
- if (proprt[ RAP_MAPPING ])
+ if (known_proprt( RAP_MAPPING ))
description += "$It lets you sense your surroundings. ";
- if (proprt[ RAP_NOISES ])
+ if (known_proprt( RAP_NOISES ))
description += "$It makes noises. ";
- if (proprt[ RAP_PREVENT_SPELLCASTING ])
+ if (known_proprt( RAP_PREVENT_SPELLCASTING ))
description += "$It prevents spellcasting. ";
- if (proprt[ RAP_CAUSE_TELEPORTATION ])
+ if (known_proprt( RAP_CAUSE_TELEPORTATION ))
description += "$It causes teleportation. ";
- if (proprt[ RAP_PREVENT_TELEPORTATION ])
+ if (known_proprt( RAP_PREVENT_TELEPORTATION ))
description += "$It prevents most forms of teleportation. ";
- if (proprt[ RAP_ANGRY ])
+ if (known_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 (known_proprt( RAP_METABOLISM ))
+ {
+ 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 radiation.";
+ if (known_proprt( RAP_MUTAGENIC ))
+ {
+ if (proprt[ RAP_MUTAGENIC ] > 3)
+ description += "$It glows with mutagenic radiation. ";
+ else if (proprt[ RAP_MUTAGENIC ])
+ description += "$It emits mutagenic radiation. ";
+ }
- if (old_length != description.length())
+ if (!description.empty())
description += "$";
if (is_unrandom_artefact( item ))
@@ -331,13 +351,17 @@ static void randart_descrip( std::string &description, const item_def &item )
description += "$";
}
}
+
+ return description;
+#undef known_proprt
}
static const char *trap_names[] =
{
"dart", "arrow", "spear", "axe",
- "teleport", "amnesia", "blade",
+ "teleport", "alarm", "blade",
"bolt", "net", "zot", "needle",
+ "shaft"
};
const char *trap_name(trap_type trap)
@@ -357,6 +381,9 @@ int str_to_trap(const std::string &s)
return (TRAP_RANDOM);
else if (s == "suitable")
return (TRAP_INDEPTH);
+ else if (s == "nonteleport" || s == "noteleport" || s == "nontele"
+ || s == "notele")
+ return (TRAP_NONTELEPORT);
for (int i = 0; i < NUM_TRAPS; ++i)
{
@@ -644,7 +671,7 @@ static std::string describe_demon(const monsters &mons)
break;
case 1:
description += " It smells like rotting flesh";
- if (you.species == SP_GHOUL)
+ if (you.mutation[MUT_SAPROVOROUS] == 3)
description += " - yum!";
else
description += ".";
@@ -1153,7 +1180,8 @@ static std::string describe_weapon( const item_def &item, bool verbose)
}
else
{
- description += "It inflicts extra damage upon your enemies. ";
+ description += "It inflicts extra damage upon "
+ "your enemies. ";
}
break;
case SPWPN_FLAME:
@@ -1180,29 +1208,25 @@ static std::string describe_weapon( const item_def &item, bool verbose)
"extra damage on living creatures. ";
break;
case SPWPN_DISTORTION:
- description += "It warps and distorts space around it. ";
+ description += "It warps and distorts space around it. "
+ "Merely wielding or unwielding it can be highly risky. ";
break;
case SPWPN_REACHING:
description += "It can be evoked to extend its reach. ";
break;
case SPWPN_RETURNING:
- description += "It is enchanted to return to its owner "
- "when thrown.";
+ description += "A skilled user can throw it in such a way "
+ "that it will return to its owner. ";
break;
}
}
if (is_random_artefact( item ))
{
- if (item_ident( item, ISFLAG_KNOW_PROPERTIES ))
- {
- unsigned int old_length = description.length();
- randart_descrip( description, item );
+ description += randart_descrip( item );
- if (description.length() == old_length)
- description += "$";
- }
- else if (item_type_known(item))
+ if (!item_ident(item, ISFLAG_KNOW_PROPERTIES)
+ && item_type_known(item))
{
description += "$This weapon may have some hidden properties.$";
}
@@ -1220,18 +1244,16 @@ static std::string describe_weapon( const item_def &item, bool verbose)
if (verbose && !is_range_weapon(item))
{
-#ifdef USE_NEW_COMBAT_STATS
- const int str_weight = weapon_str_weight( item.base_type, item.sub_type );
+ 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.";
+ description += "$This weapon is best used by the strong.$";
else if (str_weight > 5)
- description += "$This weapon is better for the strong.";
+ description += "$This weapon is better for the strong.$";
else if (str_weight <= 2)
- description += "$This weapon is best used by the dexterous.";
+ description += "$This weapon is best used by the dexterous.$";
else if (str_weight < 5)
- description += "$This weapon is better for the dexterous.";
-#endif
+ description += "$This weapon is better for the dexterous.$";
description += "$";
switch (hands_reqd(item, player_size()))
@@ -1247,7 +1269,7 @@ static std::string describe_weapon( const item_def &item, bool verbose)
description += "It is a two handed weapon.";
break;
case HANDS_DOUBLE:
- description += "It is a buggy weapon.";
+ description += "$It is a buggy weapon.";
break;
}
@@ -1795,9 +1817,8 @@ static std::string describe_armour( const item_def &item, bool verbose )
if (is_random_artefact( item ))
{
- if (item_ident( item, ISFLAG_KNOW_PROPERTIES ))
- randart_descrip( description, item );
- else if (item_type_known(item))
+ description += randart_descrip( item );
+ if (!item_ident(item, ISFLAG_KNOW_PROPERTIES) && item_type_known(item))
description += "$This armour may have some hidden properties.$";
}
else
@@ -2156,14 +2177,14 @@ static std::string describe_food( const item_def &item )
description += "Don't tell me you don't know what that is! ";
break;
case FOOD_CHUNK:
- if (you.species != SP_GHOUL)
+ if (you.mutation[MUT_SAPROVOROUS] < 3)
description += "It looks rather unpleasant. ";
if (item.special < 100)
{
- if (you.species == SP_GHOUL)
+ if (you.mutation[MUT_SAPROVOROUS] == 3)
description += "It looks nice and ripe. ";
- else if (you.species != SP_MUMMY)
+ else if (you.is_undead != US_UNDEAD)
{
description += "In fact, it is "
"rotting away before your eyes. "
@@ -2377,9 +2398,9 @@ static std::string describe_scroll( const item_def &item )
"of one who reads it. ";
break;
- case SCR_FORGETFULNESS:
- description += "This scroll induces "
- "an irritating disorientation. ";
+ case SCR_FOG:
+ description += "This scroll surrounds the reader "
+ "with a dense cloud of fog. ";
break;
case SCR_ACQUIREMENT:
@@ -2755,11 +2776,10 @@ static std::string describe_jewellery( const item_def &item, bool verbose)
// randart properties
if (is_random_artefact( item ))
{
- if (item_ident( item, ISFLAG_KNOW_PROPERTIES ))
- randart_descrip( description, item );
- else if (item_type_known(item))
+ description += randart_descrip(item);
+ if (!item_ident(item, ISFLAG_KNOW_PROPERTIES) && item_type_known(item))
{
- if (item.sub_type >= AMU_RAGE)
+ if (jewellery_is_amulet(item))
description += "$This amulet may have hidden properties.$";
else
description += "$This ring may have hidden properties.$";
@@ -2767,9 +2787,7 @@ static std::string describe_jewellery( const item_def &item, bool verbose)
}
if (item_known_cursed( item ))
- {
description += "$It has a curse placed upon it.";
- }
return (description);
} // end describe_jewellery()
@@ -2932,6 +2950,10 @@ static std::string describe_staff( const item_def &item )
return (description);
}
+static bool compare_card_names(card_type a, card_type b)
+{
+ return std::string(card_name(a)) < std::string(card_name(b));
+}
//---------------------------------------------------------------
//
@@ -3147,16 +3169,47 @@ static std::string describe_misc_item( const item_def &item )
description += "$";
- if ( is_deck(item) && item.plus2 != 0 )
+ if ( is_deck(item) )
{
- description += "$Next card(s): ";
- description += card_name(static_cast<card_type>(item.plus2 - 1));
- long spec = item.special;
- while ( spec )
+ const int num_cards = cards_in_deck(item);
+ if ( top_card_is_known(item) )
{
- description += ", ";
- description += card_name(static_cast<card_type>((spec & 0xFF)-1));
- spec >>= 8;
+ description += "Next card(s): ";
+ for ( int i = 0; i < num_cards; ++i )
+ {
+ unsigned char flags;
+ const card_type card = get_card_and_flags(item, -i-1, flags);
+ if ( flags & CFLAG_MARKED )
+ {
+ if ( i != 0 )
+ description += ", ";
+ description += card_name(card);
+ }
+ else
+ break;
+ }
+ }
+
+ std::vector<card_type> seen_cards;
+ for ( int i = 0; i < num_cards; ++i )
+ {
+ unsigned char flags;
+ const card_type card = get_card_and_flags(item, -i-1, flags);
+ // This *might* leak a bit of information...oh well.
+ if ( (flags & CFLAG_SEEN) && !(flags & CFLAG_MARKED) )
+ seen_cards.push_back(card);
+ }
+ if ( !seen_cards.empty() )
+ {
+ std::sort(seen_cards.begin(), seen_cards.end(),
+ compare_card_names);
+ description += "$Seen cards: ";
+ for ( unsigned int i = 0; i < seen_cards.size(); ++i )
+ {
+ if ( i != 0 )
+ description += ", ";
+ description += card_name(seen_cards[i]);
+ }
}
description += "$";
}
@@ -3560,10 +3613,12 @@ static std::string describe_draconian(const monsters *mon)
description += "scaled humanoid with wings.";
if (subsp != MONS_DRACONIAN)
- description += " " + describe_draconian_colour(subsp);
+ if (describe_draconian_colour(subsp) != "")
+ description += " " + describe_draconian_colour(subsp);
if (subsp != mon->type)
- description += " " + describe_draconian_role(mon);
+ if (describe_draconian_role(mon) != "")
+ description += " " + describe_draconian_role(mon);
return (description);
}
@@ -3598,6 +3653,16 @@ void describe_monsters(monsters& mons)
// -peterb 4/14/07
description << getLongDescription(mons.name(DESC_PLAIN));
+ std::string symbol = "";
+ symbol += get_monster_data(mons.type)->showchar;
+ if (isupper(symbol[0]))
+ symbol = "cap-" + symbol;
+
+ std::string symbol_prefix = "__";
+ symbol_prefix += symbol;
+ symbol_prefix += "_prefix";
+ description << getLongDescription(symbol_prefix);
+
// Now that the player has examined it, he knows it's a mimic.
if (mons_is_mimic(mons.type))
mons.flags |= MF_KNOWN_MIMIC;
@@ -3621,10 +3686,13 @@ void describe_monsters(monsters& mons)
break;
case MONS_ROTTING_DEVIL:
- if (you.species == SP_GHOUL)
- description << "It smells great!";
- else if (player_can_smell())
- description << "It stinks.";
+ if (player_can_smell())
+ {
+ if (you.mutation[MUT_SAPROVOROUS] == 3)
+ description << "It smells great!";
+ else
+ description << "It stinks.";
+ }
break;
case MONS_SWAMP_DRAKE:
@@ -3637,26 +3705,6 @@ void describe_monsters(monsters& mons)
case MONS_NAGA_WARRIOR:
case MONS_GUARDIAN_NAGA:
case MONS_GREATER_NAGA:
- switch (mons.type)
- {
- case MONS_GUARDIAN_NAGA:
- description << getLongDescription("naga")
- << "$These nagas are often used as guardians "
- "by powerful creatures.$";
- break;
- case MONS_GREATER_NAGA:
- description << getLongDescription("naga")
- << "$It looks strong and aggressive.$";
- break;
- case MONS_NAGA_MAGE:
- description << getLongDescription("naga")
- << "$An eldritch nimbus trails its motions.$";
- break;
- case MONS_NAGA_WARRIOR:
- description << getLongDescription("naga")
- << "$It bears scars of many past battles.$";
- break;
- }
if (you.species == SP_NAGA)
description << "It is particularly attractive.";
else
@@ -3723,6 +3771,12 @@ void describe_monsters(monsters& mons)
break;
}
+ description << "\n";
+ std::string symbol_suffix = "__";
+ symbol_suffix += symbol;
+ symbol_suffix += "_suffix";
+ description << getLongDescription(symbol_suffix);
+
#if DEBUG_DIAGNOSTICS
if (mons_class_flag( mons.type, M_SPELLCASTER ))
@@ -4228,31 +4282,31 @@ void describe_god( god_type which_god, bool give_title )
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)
+ // mv: some gods can protect you from harm
+ // The chance for doing so is:
+ // one_chance_in(10) || you.piety > random2(1000)
// 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 ?
+ // What about this?
bool have_any = false;
- if ((which_god == GOD_ZIN
- || which_god == GOD_SHINING_ONE
- || which_god == GOD_ELYVILON
- || which_god == GOD_YREDELEMNUL)
- && you.piety >= 30)
+
+ if (god_protects_from_harm(which_god))
{
have_any = true;
- cprintf( "%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( "%s %s watches over you." EOL, god_name(which_god),
+ (you.piety >= 150) ? "carefully":
+ (you.piety >= 90) ? "often" :
+ (you.piety >= 30) ? "sometimes" :
+ "occasionally");
+ }
- if (which_god == GOD_ZIN)
- {
- cprintf("Praying to %s will provide sustenance if starving."
- EOL, god_name(which_god));
+ if (which_god == GOD_ZIN && you.piety >= 30)
+ {
+ have_any = true;
+ cprintf("Praying to %s will provide sustenance if starving."
+ EOL, god_name(which_god));
}
}
diff --git a/crawl-ref/source/describe.h b/crawl-ref/source/describe.h
index af067e0415..875c86b8c0 100644
--- a/crawl-ref/source/describe.h
+++ b/crawl-ref/source/describe.h
@@ -72,6 +72,8 @@ void describe_spell(spell_type spelled);
* *********************************************************************** */
std::string ghost_description(const monsters &mons, bool concise = false);
+void print_description( const std::string &d );
+
const char *trap_name(trap_type trap);
int str_to_trap(const std::string &s);
diff --git a/crawl-ref/source/dgnevent.cc b/crawl-ref/source/dgnevent.cc
index 96d87fecc4..20533a5cc5 100644
--- a/crawl-ref/source/dgnevent.cc
+++ b/crawl-ref/source/dgnevent.cc
@@ -2,7 +2,7 @@
* File: dgnevent.cc
* Summary: General dungeon events.
*
- * Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-07-20T11:40:25.964128Z $
+ * Modified for Crawl Reference by $Author$ on $Date$
*
*/
@@ -41,11 +41,17 @@ bool dgn_event_dispatcher::has_listeners_at(const coord_def &pos) const
void dgn_event_dispatcher::fire_position_event(
dgn_event_type event, const coord_def &pos)
{
+ const dgn_event et(event, pos);
+ fire_position_event(et, pos);
+}
+
+void dgn_event_dispatcher::fire_position_event(
+ const dgn_event &et, const coord_def &pos)
+{
dgn_square_alarm *alarm = grid_triggers[pos.x][pos.y].get();
- if (alarm && (alarm->eventmask & event))
+ if (alarm && (alarm->eventmask & et.type))
{
dgn_square_alarm alcopy = *alarm;
- const dgn_event et(event, pos);
for (std::list<dgn_event_listener*>::iterator
i = alcopy.listeners.begin();
i != alcopy.listeners.end(); ++i)
@@ -53,6 +59,7 @@ void dgn_event_dispatcher::fire_position_event(
(*i)->notify_dgn_event(et);
}
}
+
}
void dgn_event_dispatcher::fire_event(const dgn_event &e)
diff --git a/crawl-ref/source/dgnevent.h b/crawl-ref/source/dgnevent.h
index 61134966b7..3ccd1d0246 100644
--- a/crawl-ref/source/dgnevent.h
+++ b/crawl-ref/source/dgnevent.h
@@ -2,7 +2,7 @@
* File: dgnevent.h
* Summary: General dungeon events.
*
- * Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-07-20T11:40:25.964128Z $
+ * Modified for Crawl Reference by $Author$ on $Date$
*
*/
@@ -15,15 +15,19 @@
// Keep event names in luadgn.cc in sync.
enum dgn_event_type
{
- DET_NONE = 0x0000,
+ DET_NONE = 0x0000,
- DET_TURN_ELAPSED = 0x0001,
- DET_MONSTER_MOVED = 0x0002,
- DET_PLAYER_MOVED = 0x0004,
- DET_LEAVING_LEVEL = 0x0008,
- DET_ENTERING_LEVEL = 0x0010,
- DET_PLAYER_IN_LOS = 0x0020, // Player just entered LOS.
- DET_PLAYER_CLIMBS = 0x0040 // Player climbing stairs.
+ DET_TURN_ELAPSED = 0x0001,
+ DET_MONSTER_MOVED = 0x0002,
+ DET_PLAYER_MOVED = 0x0004,
+ DET_LEAVING_LEVEL = 0x0008,
+ DET_ENTERING_LEVEL = 0x0010,
+ DET_ENTERED_LEVEL = 0x0020,
+ DET_PLAYER_IN_LOS = 0x0040, // Player just entered LOS.
+ DET_PLAYER_CLIMBS = 0x0080, // Player climbing stairs.
+ DET_MONSTER_DIED = 0x0100,
+ DET_ITEM_PICKUP = 0x0200,
+ DET_FEAT_CHANGE = 0x0400
};
class dgn_event
@@ -32,11 +36,12 @@ public:
dgn_event_type type;
coord_def place;
int elapsed_ticks;
+ long arg1, arg2;
public:
dgn_event(dgn_event_type t, const coord_def &p = coord_def(),
- int ticks = you.time_taken)
- : type(t), place(p), elapsed_ticks(ticks)
+ int ticks = you.time_taken, long a1 = 0, long a2 = 0)
+ : type(t), place(p), elapsed_ticks(ticks), arg1(a1), arg2(a2)
{
}
};
@@ -88,6 +93,7 @@ public:
void move_listeners(const coord_def &from, const coord_def &to);
void fire_position_event(dgn_event_type et, const coord_def &pos);
+ void fire_position_event(const dgn_event &e, const coord_def &pos);
void fire_event(dgn_event_type et);
void fire_event(const dgn_event &e);
diff --git a/crawl-ref/source/direct.cc b/crawl-ref/source/direct.cc
index 017d0086db..e6bd239f9b 100644
--- a/crawl-ref/source/direct.cc
+++ b/crawl-ref/source/direct.cc
@@ -46,6 +46,7 @@
#include "mon-util.h"
#include "player.h"
#include "shopping.h"
+#include "state.h"
#include "stuff.h"
#include "spells4.h"
#include "stash.h"
@@ -234,6 +235,135 @@ static void draw_ray_glyph(const coord_def &pos, int colour,
putch(glych);
}
+// We handle targeting for repeating commands and re-doing the
+// previous command differently (i.e., not just letting the keys
+// stuffed into the macro buffer replay as-is) because if the player
+// targeted a monster using the movement keys and the monster then
+// moved between repititions, then simply replaying the keys in the
+// buffer will target an empty square.
+static void direction_again(dist& moves, targeting_type restricts,
+ targ_mode_type mode, bool just_looking,
+ const char *prompt, targeting_behaviour *beh)
+{
+ moves.isValid = false;
+ moves.isTarget = false;
+ moves.isMe = false;
+ moves.isCancel = false;
+ moves.isEndpoint = false;
+ moves.choseRay = false;
+
+ if (you.prev_targ == MHITNOT && you.prev_grd_targ == coord_def(0, 0))
+ {
+ moves.isCancel = true;
+ crawl_state.cancel_cmd_repeat();
+ return;
+ }
+
+ int targ_types = 0;
+ if (you.prev_targ != MHITNOT && you.prev_targ != MHITYOU)
+ targ_types++;
+ if (you.prev_targ == MHITYOU)
+ targ_types++;
+ if (you.prev_grd_targ != coord_def(0, 0))
+ targ_types++;
+ ASSERT(targ_types == 1);
+
+ // Discard keys until we get to a set-target command
+ command_type key_command = CMD_NO_CMD;
+
+ while (crawl_state.is_replaying_keys())
+ {
+ key_command = beh->get_command();
+
+ if (key_command == CMD_TARGET_PREV_TARGET
+ || key_command == CMD_TARGET_SELECT_ENDPOINT
+ || key_command == CMD_TARGET_SELECT
+ || key_command == CMD_TARGET_MAYBE_PREV_TARGET)
+ {
+ break;
+ }
+ }
+
+ if (!crawl_state.is_replaying_keys())
+ {
+ moves.isCancel = true;
+
+ mpr("Ran out of keys.");
+
+ return;
+ }
+
+ if (key_command == CMD_TARGET_SELECT_ENDPOINT)
+ moves.isEndpoint = true;
+
+ if (you.prev_grd_targ != coord_def(0, 0))
+ {
+ if (!see_grid(you.prev_grd_targ))
+ {
+ moves.isCancel = true;
+
+ crawl_state.cancel_cmd_repeat("You can no longer see the dungeon "
+ "square you previously targeted.");
+ return;
+ }
+ else if (you.prev_grd_targ.x == you.x_pos
+ && you.prev_grd_targ.y == you.y_pos)
+ {
+ moves.isCancel = true;
+
+ crawl_state.cancel_cmd_repeat("You are now standing on your "
+ "previously targeted dungeon "
+ "square.");
+ return;
+ }
+
+ moves.tx = you.prev_grd_targ.x;
+ moves.ty = you.prev_grd_targ.y;
+
+ ray_def ray;
+ find_ray(you.x_pos, you.y_pos, moves.tx, moves.ty, true, ray,
+ 0, true);
+ moves.ray = ray;
+ }
+ else if (you.prev_targ == MHITYOU)
+ {
+ moves.isMe = true;
+ moves.tx = you.x_pos;
+ moves.ty = you.y_pos;
+
+ // Discard 'Y' player gave to yesno()
+ if (mode == TARG_ENEMY)
+ getchm();
+ }
+ else
+ {
+ const monsters *montarget = &menv[you.prev_targ];
+
+ if (!mons_near(montarget) ||
+ !player_monster_visible( montarget ))
+ {
+ moves.isCancel = true;
+
+ crawl_state.cancel_cmd_repeat("Your target is gone.");
+
+ return;
+ }
+
+ moves.tx = montarget->x;
+ moves.ty = montarget->y;
+
+ ray_def ray;
+ find_ray(you.x_pos, you.y_pos, moves.tx, moves.ty, true, ray,
+ 0, true);
+ moves.ray = ray;
+ }
+
+ moves.isValid = true;
+ moves.isTarget = true;
+
+ return;
+}
+
//---------------------------------------------------------------
//
// direction
@@ -264,7 +394,14 @@ void direction(dist& moves, targeting_type restricts,
beh = &stock_behaviour;
beh->just_looking = just_looking;
-
+
+ if (crawl_state.is_replaying_keys() && restricts != DIR_DIR)
+ {
+ direction_again(moves, restricts, mode, just_looking,
+ prompt, beh);
+ return;
+ }
+
// NOTE: Even if just_looking is set, moves is still interesting,
// because we can travel there!
@@ -290,6 +427,10 @@ void direction(dist& moves, targeting_type restricts,
if ( show_beam )
find_ray(you.x_pos, you.y_pos, moves.tx, moves.ty, true, ray);
+ // If we show the beam on startup, we have to initialise it.
+ if ( show_beam )
+ find_ray(you.x_pos, you.y_pos, moves.tx, moves.ty, true, ray);
+
bool skip_iter = false;
bool found_autotarget = false;
bool target_unshifted = Options.target_unshifted_dirs;
@@ -418,6 +559,8 @@ void direction(dist& moves, targeting_type restricts,
moves.ty = you.y_pos + moves.dy;
moves.isValid = true;
moves.isTarget = false;
+ show_beam = false;
+ moves.choseRay = false;
loop_done = true;
}
else
@@ -455,7 +598,8 @@ void direction(dist& moves, targeting_type restricts,
{
if (!needs_path)
{
- mprf(MSGCH_EXAMINE_FILTER, "This spell doesn't need a beam path.");
+ mprf(MSGCH_EXAMINE_FILTER,
+ "This spell doesn't need a beam path.");
break;
}
@@ -477,8 +621,8 @@ void direction(dist& moves, targeting_type restricts,
case CMD_TARGET_FIND_ALTAR:
case CMD_TARGET_FIND_UPSTAIR:
case CMD_TARGET_FIND_DOWNSTAIR:
- int thing_to_find;
- thing_to_find = targeting_cmd_to_feature(key_command);
+ {
+ const int thing_to_find = targeting_cmd_to_feature(key_command);
if (find_square_wrapper(moves.tx, moves.ty, objfind_pos, 1,
find_feature, thing_to_find, true,
Options.target_los_first ?
@@ -493,6 +637,7 @@ void direction(dist& moves, targeting_type restricts,
flush_input_buffer(FLUSH_ON_FAILURE);
}
break;
+ }
case CMD_TARGET_CYCLE_TARGET_MODE:
mode = static_cast<targ_mode_type>((mode + 1) % TARG_NUM_MODES);
@@ -517,7 +662,8 @@ void direction(dist& moves, targeting_type restricts,
if (!mons_near(montarget) ||
!player_monster_visible( montarget ))
{
- mpr("You can't see that creature any more.", MSGCH_EXAMINE_FILTER);
+ mpr("You can't see that creature any more.",
+ MSGCH_EXAMINE_FILTER);
}
else
{
@@ -527,7 +673,16 @@ void direction(dist& moves, targeting_type restricts,
moves.tx = montarget->x;
moves.ty = montarget->y;
if ( !just_looking )
+ {
+ // We have to turn off show_beam, because
+ // when jumping to a previous target we don't
+ // care about the beam; otherwise Bad Things
+ // will happen because the ray is invalid,
+ // and we don't get a chance to update it before
+ // breaking from the loop.
+ show_beam = false;
loop_done = true;
+ }
}
break;
}
@@ -539,10 +694,18 @@ void direction(dist& moves, targeting_type restricts,
moves.isValid = true;
moves.isTarget = true;
loop_done = true;
+
+ you.prev_grd_targ = coord_def(0, 0);
+
// maybe we should except just_looking here?
mid = mgrd[moves.tx][moves.ty];
+
if ( mid != NON_MONSTER )
you.prev_targ = mid;
+ else if (moves.tx == you.x_pos && moves.ty == you.y_pos)
+ you.prev_targ = MHITYOU;
+ else
+ you.prev_grd_targ = coord_def(moves.tx, moves.ty);
break;
case CMD_TARGET_OBJ_CYCLE_BACK:
@@ -661,7 +824,7 @@ void direction(dist& moves, targeting_type restricts,
// Conceivably we might want to confirm on TARG_ANY too.
if ( moves.isTarget &&
moves.tx == you.x_pos && moves.ty == you.y_pos &&
- mode == TARG_ENEMY && Options.confirm_self_target &&
+ mode == TARG_ENEMY &&
!yesno("Really target yourself?", false, 'n'))
{
mesclr();
@@ -685,9 +848,9 @@ void direction(dist& moves, targeting_type restricts,
// We'll go on looping. Redraw whatever is necessary.
- // Tried to step out of bounds
if ( !in_viewport_bounds(grid2viewX(moves.tx), grid2viewY(moves.ty)) )
{
+ // Tried to step out of bounds
moves.tx = old_tx;
moves.ty = old_ty;
}
@@ -1339,8 +1502,8 @@ std::string raw_feature_description(dungeon_feature_type grid,
return ("axe trap");
case TRAP_TELEPORT:
return ("teleportation trap");
- case TRAP_AMNESIA:
- return ("amnesia trap");
+ case TRAP_ALARM:
+ return ("alarm trap");
case TRAP_BLADE:
return ("blade trap");
case TRAP_BOLT:
@@ -1351,6 +1514,8 @@ std::string raw_feature_description(dungeon_feature_type grid,
return ("Zot trap");
case TRAP_NEEDLE:
return ("needle trap");
+ case TRAP_SHAFT:
+ return ("shaft");
default:
error_message_to_player();
return ("undefined trap");
@@ -1375,6 +1540,12 @@ std::string raw_feature_description(dungeon_feature_type grid,
return ("metal wall");
case DNGN_GREEN_CRYSTAL_WALL:
return ("wall of green crystal");
+ case DNGN_CLEAR_ROCK_WALL:
+ return ("translucent rock wall");
+ case DNGN_CLEAR_STONE_WALL:
+ return ("translucent stone wall");
+ case DNGN_CLEAR_PERMAROCK_WALL:
+ return ("translucent unnaturally hard rock wall");
case DNGN_ORCISH_IDOL:
if (you.species == SP_HILL_ORC)
{
@@ -1415,8 +1586,8 @@ std::string raw_feature_description(dungeon_feature_type grid,
return ("mechanical trap");
case DNGN_TRAP_MAGICAL:
return ("magical trap");
- case DNGN_TRAP_III:
- return ("trap");
+ case DNGN_TRAP_NATURAL:
+ return ("natural trap");
case DNGN_ENTER_SHOP:
return ("shop");
case DNGN_ENTER_LABYRINTH:
@@ -1571,7 +1742,7 @@ std::string feature_description(int mx, int my, description_level_type dtype,
{
case DNGN_TRAP_MECHANICAL:
case DNGN_TRAP_MAGICAL:
- case DNGN_TRAP_III:
+ case DNGN_TRAP_NATURAL:
return (feature_description(grid, trap_type_at_xy(mx, my),
dtype, add_stop));
case DNGN_ENTER_SHOP:
@@ -1642,9 +1813,11 @@ static std::string describe_monster_weapon(const monsters *mons)
const item_def *alt = mons->mslot_item(MSLOT_ALT_WEAPON);
if (weap)
- name1 = weap->name(DESC_NOCAP_A);
+ name1 = weap->name(DESC_NOCAP_A, false, false, true,
+ false, ISFLAG_KNOW_CURSE);
if (alt && (!weap || mons_wields_two_weapons(mons)))
- name2 = alt->name(DESC_NOCAP_A);
+ name2 = alt->name(DESC_NOCAP_A, false, false, true,
+ false, ISFLAG_KNOW_CURSE);
if (name1.empty() && !name2.empty())
name1.swap(name2);
@@ -1653,7 +1826,8 @@ static std::string describe_monster_weapon(const monsters *mons)
{
item_def dup = *weap;
++dup.quantity;
- name1 = dup.name(DESC_NOCAP_A, false, false, true, true);
+ name1 = dup.name(DESC_NOCAP_A, false, false, true, true,
+ ISFLAG_KNOW_CURSE);
name2.clear();
}
@@ -1695,6 +1869,9 @@ static void describe_monster(const monsters *mon)
text += ".";
print_formatted_paragraph(text, get_number_of_cols());
+ if (player_beheld_by(mon))
+ mpr("You are beheld by her song.", MSGCH_EXAMINE);
+
if (mon->type == MONS_HYDRA)
{
mprf(MSGCH_EXAMINE, "It has %d head%s.", mon->number,
@@ -1958,7 +2135,9 @@ targeting_behaviour::~targeting_behaviour()
int targeting_behaviour::get_key()
{
- flush_input_buffer(FLUSH_BEFORE_COMMAND);
+ if (!crawl_state.is_replaying_keys())
+ flush_input_buffer(FLUSH_BEFORE_COMMAND);
+
return unmangle_direction_keys(
getchm(KC_TARGETING), KC_TARGETING, false, false);
}
diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc
index 3ac9965657..faba2c3d0d 100644
--- a/crawl-ref/source/dungeon.cc
+++ b/crawl-ref/source/dungeon.cc
@@ -34,6 +34,7 @@
#include "AppHdr.h"
#include "abyss.h"
#include "branch.h"
+#include "cloud.h"
#include "defines.h"
#include "enum.h"
#include "externs.h"
@@ -137,6 +138,7 @@ static void place_minivaults(const std::string &tag = "",
int fewest = -1, int most = -1,
bool force = false);
static void place_traps( int level_number );
+static void place_fog_machines( int level_number );
static void prepare_swamp();
static void prepare_shoals( int level_number );
static void prepare_water( int level_number );
@@ -173,7 +175,7 @@ static char plan_5();
static char plan_6(int level_number);
static bool octa_room(spec_room &sr, int oblique_max,
dungeon_feature_type type_floor);
-static void bazaar_level(int level_number);
+static void portal_vault_level(int level_number);
static void labyrinth_level(int level_number);
static void box_room(int bx1, int bx2, int by1, int by2,
dungeon_feature_type wall_type);
@@ -238,6 +240,9 @@ static void place_altars();
typedef std::list<coord_def> coord_list;
+// MISC FUNCTIONS
+static void dgn_set_floor_colours();
+
//////////////////////////////////////////////////////////////////////////
// Static data
@@ -280,6 +285,9 @@ struct dgn_colour_override_manager
typedef FixedArray< coloured_feature, GXM, GYM > dungeon_colour_grid;
static std::auto_ptr<dungeon_colour_grid> dgn_colour_grid;
+typedef std::map<std::string, std::string> callback_map;
+static callback_map level_type_post_callbacks;
+
/**********************************************************************
* builder() - kickoff for the dungeon generator.
*********************************************************************/
@@ -306,6 +314,7 @@ bool builder(int level_number, int level_type)
use_random_maps = false;
build_dungeon_level(level_number, level_type);
+ dgn_set_floor_colours();
#ifdef DEBUG_DIAGNOSTICS
if (dgn_level_vetoed)
@@ -378,6 +387,64 @@ static void dgn_map_colour_fixup()
dgn_colour_grid.reset(NULL);
}
+bool set_level_flags(unsigned long flags, bool silent)
+{
+ bool could_control = allow_control_teleport(true);
+ bool could_map = player_in_mappable_area();
+
+ unsigned long old_flags = env.level_flags;
+ env.level_flags |= flags;
+
+ bool can_control = allow_control_teleport(true);
+ bool can_map = player_in_mappable_area();
+
+ if (you.skills[SK_TRANSLOCATIONS] > 0
+ && could_control && !can_control && !silent)
+ {
+ mpr("You sense the appearence of a powerful magical force "
+ "which warps space.", MSGCH_WARN);
+ }
+
+ if (could_map && !can_map && !silent)
+ {
+ mpr("A powerful force appears that prevents you from "
+ "remembering where you've been.", MSGCH_WARN);
+ }
+
+ return (old_flags != env.level_flags);
+}
+
+bool unset_level_flags(unsigned long flags, bool silent)
+{
+ bool could_control = allow_control_teleport(true);
+ bool could_map = player_in_mappable_area();
+
+ unsigned long old_flags = env.level_flags;
+ env.level_flags &= ~flags;
+
+ bool can_control = allow_control_teleport(true);
+ bool can_map = player_in_mappable_area();
+
+ if (you.skills[SK_TRANSLOCATIONS] > 0
+ && !could_control && can_control && !silent)
+ {
+ // Isn't really a "recovery", but I couldn't think of where
+ // else to send it.
+ mpr("You sense the disappearence of a powerful magical force "
+ "which warped space.", MSGCH_RECOVERY);
+ }
+
+ if (!could_map && can_map && !silent)
+ {
+ // Isn't really a "recovery", but I couldn't think of where
+ // else to send it.
+ mpr("You sense the disappearence the force that prevented you "
+ "from remembering where you've been.", MSGCH_RECOVERY);
+ }
+
+ return (old_flags != env.level_flags);
+}
+
void dgn_set_grid_colour_at(const coord_def &c, int colour)
{
if (colour != BLACK)
@@ -539,6 +606,33 @@ static void register_place(const vault_placement &place)
if (!place.map.has_tag("transparent"))
mask_vault(place, MMT_OPAQUE);
+
+ // Now do per-square by-symbol masking
+ for (int y = place.pos.y + place.size.y - 1; y >= place.pos.y; --y)
+ for (int x = place.pos.x + place.size.x - 1; x >= place.pos.x; --x)
+ if (place.map.in_map(coord_def(x - place.pos.x, y - place.pos.y)))
+ {
+ int key = place.map.map.glyph(x - place.pos.x, y - place.pos.y);
+ const keyed_mapspec* spec = place.map.mapspec_for_key(key);
+
+ if (spec != NULL)
+ {
+ dgn_map_mask[x][y] |= (short)spec->map_mask.flags_set;
+ dgn_map_mask[x][y] &= ~((short)spec->map_mask.flags_unset);
+ }
+ }
+
+ set_branch_flags(place.map.branch_flags.flags_set, true);
+ unset_branch_flags(place.map.branch_flags.flags_unset, true);
+
+ set_level_flags(place.map.level_flags.flags_set, true);
+ unset_level_flags(place.map.level_flags.flags_unset, true);
+
+ if (place.map.floor_colour != BLACK)
+ env.floor_colour = place.map.floor_colour;
+
+ if (place.map.rock_colour != BLACK)
+ env.rock_colour = place.map.rock_colour;
}
static bool ensure_vault_placed(bool vault_success)
@@ -619,6 +713,9 @@ static void reset_level()
for (int i = 0; i < MAX_MONSTERS; i++)
menv[i].type = -1;
+ for (int i = 0; i < 20; i++)
+ env.mons_alloc[i] = -1;
+
mgrd.init(NON_MONSTER);
igrd.init(NON_ITEM);
@@ -628,6 +725,26 @@ static void reset_level()
// clear all markers
env.markers.clear();
+
+ // Set default level flags
+ if (you.level_type == LEVEL_DUNGEON)
+ env.level_flags = branches[you.where_are_you].default_level_flags;
+ else if (you.level_type == LEVEL_LABYRINTH ||
+ you.level_type == LEVEL_ABYSS)
+ {
+ env.level_flags = LFLAG_NO_TELE_CONTROL | LFLAG_NOT_MAPPABLE;
+
+ if (!(you.level_type == LEVEL_LABYRINTH
+ && you.species != SP_MINOTAUR))
+ {
+ env.level_flags |= LFLAG_NO_MAGIC_MAP;
+ }
+ }
+ else
+ env.level_flags = 0;
+
+ env.floor_colour = BLACK;
+ env.rock_colour = BLACK;
}
static void build_layout_skeleton(int level_number, int level_type,
@@ -778,6 +895,130 @@ static void fixup_branch_stairs()
}
}
+static void fixup_duplicate_stairs()
+{
+ // This function ensures that there is no more than one of each up and down
+ // stone stairs I, II, and III. More than three stairs will result in
+ // turning additional stairs into rock stairs (with an attempt to keep
+ // level connectivity).
+
+ const unsigned int max_stairs = 20;
+ FixedVector<coord_def, max_stairs> up_stairs;
+ FixedVector<coord_def, max_stairs> down_stairs;
+ unsigned int num_up_stairs = 0;
+ unsigned int num_down_stairs = 0;
+
+ for (int x = 1; x < GXM; x++)
+ {
+ for (int y = 1; y < GYM; y++)
+ {
+ const coord_def c(x,y);
+ if (grd(c) >= DNGN_STONE_STAIRS_DOWN_I &&
+ grd(c) <= DNGN_STONE_STAIRS_DOWN_III &&
+ num_down_stairs < max_stairs)
+ {
+ down_stairs[num_down_stairs++] = c;
+ }
+ else if (grd(c) >= DNGN_STONE_STAIRS_UP_I &&
+ grd(c) <= DNGN_STONE_STAIRS_UP_III &&
+ num_up_stairs < max_stairs)
+ {
+ up_stairs[num_up_stairs++] = c;
+ }
+ }
+ }
+
+ for (unsigned int i = 0; i < 2; i++)
+ {
+ FixedVector<coord_def, max_stairs>& stair_list = (i == 0) ?
+ up_stairs : down_stairs;
+
+ unsigned int num_stairs;
+ dungeon_feature_type base;
+ dungeon_feature_type replace;
+ if (i == 0)
+ {
+ num_stairs = num_up_stairs;
+ replace = DNGN_ROCK_STAIRS_UP;
+ base = DNGN_STONE_STAIRS_UP_I;
+ }
+ else
+ {
+ num_stairs = num_down_stairs;
+ replace = DNGN_ROCK_STAIRS_DOWN;
+ base = DNGN_STONE_STAIRS_DOWN_I;
+ }
+
+ if (num_stairs > 3)
+ {
+ // Find pairwise stairs that are connected and turn one of them
+ // into a rock stairs of the appropriate type.
+ for (unsigned int s1 = 0; s1 < num_stairs; s1++)
+ {
+ if (num_stairs <= 3)
+ break;
+
+ for (unsigned int s2 = s1 + 1; s2 < num_stairs; s2++)
+ {
+ if (num_stairs <= 3)
+ break;
+
+ flood_find<feature_grid, coord_predicate> ff(env.grid,
+ in_bounds);
+
+ ff.add_feat(grd(stair_list[s2]));
+
+ // Ensure we're not searching for the feature at s1.
+ dungeon_feature_type save = grd(stair_list[s1]);
+ grd(stair_list[s1]) = DNGN_FLOOR;
+
+ coord_def where = ff.find_first_from(stair_list[s1],
+ dgn_map_mask);
+ if (where.x)
+ {
+ grd(stair_list[s2]) = replace;
+ num_stairs--;
+ stair_list[s2] = stair_list[num_stairs];
+ s2--;
+ }
+
+ grd(stair_list[s1]) = save;
+ }
+ }
+
+ // If that doesn't work, remove random stairs.
+ while (num_stairs > 3)
+ {
+ int remove = random2(num_stairs);
+ grd(stair_list[remove]) = replace;
+
+ stair_list[remove] = stair_list[--num_stairs];
+ }
+ }
+
+ ASSERT(num_stairs <= 3);
+
+ if (num_stairs <= 1)
+ continue;
+
+ // At this point, up_stairs and down_stairs contain no more than
+ // three stairs. Ensure that they are unique.
+ for (int s = 0; s < (num_stairs == 3 ? 4 : 1); s++)
+ {
+ int s1 = s % num_stairs;
+ int s2 = (s1 + 1) % num_stairs;
+ ASSERT(grd(stair_list[s2]) >= base &&
+ grd(stair_list[s2]) <= base + 3);
+
+ if (grd(stair_list[s1]) == grd(stair_list[s2]))
+ {
+ grd(stair_list[s2]) = (dungeon_feature_type)(base +
+ (grd(stair_list[s2])-base+1) % 3);
+ }
+ }
+ }
+}
+
static void dgn_verify_connectivity(unsigned nvaults)
{
// After placing vaults, make sure parts of the level have not been
@@ -820,7 +1061,9 @@ static void build_dungeon_level(int level_number, int level_type)
if (you.level_type == LEVEL_LABYRINTH
|| you.level_type == LEVEL_PORTAL_VAULT
|| dgn_level_vetoed)
+ {
return;
+ }
// hook up the special room (if there is one, and it hasn't
// been hooked up already in roguey_level())
@@ -865,8 +1108,8 @@ static void build_dungeon_level(int level_number, int level_type)
if (dgn_level_vetoed)
return;
- if (!player_in_branch( BRANCH_ECUMENICAL_TEMPLE ))
- place_traps(level_number);
+ place_traps(level_number);
+ place_fog_machines(level_number);
// place items
builder_items(level_number, level_type, num_items_wanted(level_number));
@@ -894,7 +1137,7 @@ static void build_dungeon_level(int level_number, int level_type)
if (level_type == LEVEL_PANDEMONIUM)
fixup_pandemonium_stairs();
- dgn_set_floor_colours();
+ fixup_duplicate_stairs();
} // end builder()
@@ -906,68 +1149,55 @@ static char fix_black_colour(char incol)
return incol;
}
-int bazaar_floor_colour(int curr_level)
+void dgn_set_colours_from_monsters()
{
- const char floorcolours_bzr[] =
- { BLUE, RED, LIGHTBLUE, MAGENTA, GREEN };
+ if (env.mons_alloc[9] < 0 || env.mons_alloc[9] == MONS_PROGRAM_BUG
+ || env.mons_alloc[9] >= NUM_MONSTERS)
+ {
+ if (env.floor_colour == BLACK)
+ env.floor_colour = LIGHTGREY;
+ }
+ else
+ env.floor_colour = fix_black_colour(mcolour[env.mons_alloc[9]]);
- // set colour according to current level
- // randomization would reset between save/reload and after showing map
- return (floorcolours_bzr[curr_level % 5]);
-}
-void dgn_set_colours_from_monsters()
-{
- env.floor_colour = fix_black_colour(mcolour[env.mons_alloc[9]]);
- env.rock_colour = fix_black_colour(mcolour[env.mons_alloc[8]]);
+ if (env.mons_alloc[8] < 0 || env.mons_alloc[8] == MONS_PROGRAM_BUG
+ || env.mons_alloc[8] >= NUM_MONSTERS)
+ {
+ if (env.rock_colour == BLACK)
+ env.rock_colour = BROWN;
+ }
+ else
+ env.rock_colour = fix_black_colour(mcolour[env.mons_alloc[8]]);
}
-void dgn_set_floor_colours()
+static void dgn_set_floor_colours()
{
+ unsigned char old_floor_colour = env.floor_colour;
+ unsigned char old_rock_colour = env.rock_colour;
+
if (you.level_type == LEVEL_PANDEMONIUM || you.level_type == LEVEL_ABYSS)
{
dgn_set_colours_from_monsters();
}
- else if (you.level_type == LEVEL_LABYRINTH)
- {
- env.floor_colour = LIGHTGREY;
- env.rock_colour = BROWN;
- }
- else if (you.level_type == LEVEL_PORTAL_VAULT
- && you.level_type_name == "bazaar")
- {
- // bazaars get gold walls
- env.rock_colour = YELLOW;
-
- // bazaar floor is colourful
- env.floor_colour = bazaar_floor_colour(you.your_level + 1);
- }
- else
+ else if (you.level_type == LEVEL_DUNGEON)
{
// level_type == LEVEL_DUNGEON
+ // Hall of Zot colours handled in dat/zot.des
const int youbranch = you.where_are_you;
env.floor_colour = branches[youbranch].floor_colour;
env.rock_colour = branches[youbranch].rock_colour;
+ }
- // Zot is multicoloured
- if ( you.where_are_you == BRANCH_HALL_OF_ZOT )
- {
- const char floorcolours_zot[] = { LIGHTGREY, LIGHTGREY, BLUE,
- LIGHTBLUE, MAGENTA };
- const char rockcolours_zot[] = { LIGHTGREY, BLUE, LIGHTBLUE,
- MAGENTA, LIGHTMAGENTA };
-
- const int curr_subdungeon_level = player_branch_depth();
+ if (old_floor_colour != BLACK)
+ env.floor_colour = old_floor_colour;
+ if (old_rock_colour != BLACK)
+ env.rock_colour = old_rock_colour;
- if ( curr_subdungeon_level > 5 || curr_subdungeon_level < 1 )
- mpr("Odd colouring!");
- else
- {
- env.floor_colour = floorcolours_zot[curr_subdungeon_level-1];
- env.rock_colour = rockcolours_zot[curr_subdungeon_level-1];
- }
- }
- }
+ if (env.floor_colour == BLACK)
+ env.floor_colour = LIGHTGREY;
+ if (env.rock_colour == BLACK)
+ env.rock_colour = BROWN;
}
static void check_doors()
@@ -1336,9 +1566,9 @@ 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 (i = 1; i < (GXM - 1); i++)
{
- for (j = 10; j < (GYM - 10); j++)
+ for (j = 1; j < (GYM - 1); j++)
{
if (!unforbidden(coord_def(i, j), MMT_NO_POOL))
continue;
@@ -1439,14 +1669,7 @@ static builder_rc_type builder_by_type(int level_number, char level_type)
{
if (level_type == LEVEL_PORTAL_VAULT)
{
- if (you.level_type_name == "bazaar")
- bazaar_level(level_number);
- else
- {
- // Need to find encompass vault with tag matching
- // level_type_name.
- ASSERT(false);
- }
+ portal_vault_level(level_number);
return (BUILD_QUIT);
}
@@ -1519,44 +1742,46 @@ static builder_rc_type builder_by_type(int level_number, char level_type)
return BUILD_CONTINUE;
}
-static void fixup_bazaar_stairs()
+static void portal_vault_level(int level_number)
{
- for (int y = 0; y < GYM; ++y)
+ std::string trimmed_name = trimmed_string(you.level_type_name);
+ ASSERT(!trimmed_name.empty());
+
+ const char* level_name = trimmed_name.c_str();
+
+ int vault = random_map_for_place(level_id::current(), false);
+
+#ifdef WIZARD
+ if (vault == -1 && you.wizard
+ && random_map_for_tag(level_name, false) != -1)
{
- for (int x = 0; x < GXM; ++x)
+ char buf[80];
+
+ do
{
- const dungeon_feature_type feat = grd[x][y];
- if (grid_is_stone_stair(feat) || grid_is_rock_stair(feat))
- {
- if (grid_stair_direction(feat) == CMD_GO_DOWNSTAIRS)
- grd[x][y] = DNGN_EXIT_PORTAL_VAULT;
- else
- {
- grd[x][y] = DNGN_STONE_ARCH;
- env.markers.add(
- new map_feature_marker(
- coord_def(x, y),
- DNGN_STONE_ARCH));
- }
- }
-
- // colour floor squares around shops
- if (feat == DNGN_ENTER_SHOP)
- {
- for (int i=-1; i<=1; i++)
- for (int j=-1; j<=1; j++)
- {
- if (grd[x+i][y+j] == DNGN_FLOOR)
- grd[x+i][y+j] = DNGN_FLOOR_SPECIAL;
- }
- }
- }
+ mprf(MSGCH_PROMPT, "Which %s (ESC or ENTER for random): ",
+ level_name);
+ if (cancelable_get_line(buf, sizeof buf))
+ break;
+
+ std::string name = buf;
+ trim_string(name);
+
+ if (name.empty())
+ break;
+
+ lowercase(name);
+ name = replace_all(name, " ", "_");
+
+ vault = find_map_by_name(you.level_type_name + "_" + name);
+
+ if (vault == -1)
+ mprf(MSGCH_DIAGNOSTICS, "No such %s, try again.",
+ level_name);
+ } while (vault == -1);
}
-}
+#endif
-static void bazaar_level(int level_number)
-{
- int vault = random_map_for_place(level_id::current(), false);
#ifdef WIZARD
if (vault == -1 && you.wizard)
@@ -1587,26 +1812,33 @@ static void bazaar_level(int level_number)
#endif
if (vault == -1)
- vault = random_map_for_tag("bazaar", false);
+ vault = random_map_for_tag(level_name, false);
if (vault != -1)
- {
ensure_vault_placed( build_vaults(level_number, vault) );
- link_items();
- fixup_bazaar_stairs();
- return;
+ else
+ {
+ plan_main(level_number, 0);
+ place_minivaults(level_name, 1, 1, true);
+
+ if (level_vaults.empty())
+ {
+ mprf(MSGCH_WARN, "No maps or tags named '%s'.",
+ level_name);
+ ASSERT(false);
+ end(-1);
+ }
}
- // No primary Bazaar vaults (ugh).
- plan_main(level_number, 0);
- place_minivaults("bazaar", 1, 1, true);
+ link_items();
- // No vaults placed yet? Place some shops of our own.
- if (level_vaults.empty())
- place_shops(level_number, random_range(5, MAX_SHOPS));
+ // TODO: Let portal vault map have arbitrary properties which can
+ // be passed onto the callback.
+ callback_map::const_iterator
+ i = level_type_post_callbacks.find(you.level_type_name);
- link_items();
- fixup_bazaar_stairs();
+ if (i != level_type_post_callbacks.end())
+ dlua.callfn(i->second.c_str(), 0, 0);
}
static int random_portal_vault(const std::string &tag)
@@ -1982,51 +2214,13 @@ static void builder_extras( int level_number, int level_type )
}
}
-// Also checks you.where_are_you!
-static trap_type random_trap_for_level(int level_number)
-{
- trap_type type = TRAP_DART;
-
- if ((random2(1 + level_number) > 1) && one_chance_in(4))
- type = TRAP_NEEDLE;
- if (random2(1 + level_number) > 3)
- type = TRAP_SPEAR;
- if (random2(1 + level_number) > 5)
- type = TRAP_AXE;
-
- // Note we're boosting arrow trap numbers by moving it
- // down the list, and making spear and axe traps rarer.
- if (type == TRAP_DART?
- random2(1 + level_number) > 2
- : one_chance_in(7))
- type = TRAP_ARROW;
-
- if ((type == TRAP_DART || type == TRAP_ARROW) && one_chance_in(15))
- type = TRAP_NET;
-
- if (random2(1 + level_number) > 7)
- type = TRAP_BOLT;
- if (random2(1 + level_number) > 11)
- type = TRAP_BLADE;
-
- if ((random2(1 + level_number) > 14 && one_chance_in(3))
- || (player_in_branch( BRANCH_HALL_OF_ZOT ) && coinflip()))
- {
- type = TRAP_ZOT;
- }
-
- if (one_chance_in(20))
- type = TRAP_TELEPORT;
- if (one_chance_in(40))
- type = TRAP_AMNESIA;
-
- return (type);
-}
-
static void place_traps(int level_number)
{
int i;
- int num_traps = random2avg(9, 2);
+ int num_traps = num_traps_for_place(level_number);
+
+ ASSERT(num_traps >= 0);
+ ASSERT(num_traps <= MAX_TRAPS);
for (i = 0; i < num_traps; i++)
{
@@ -2043,21 +2237,59 @@ static void place_traps(int level_number)
while (grd[env.trap[i].x][env.trap[i].y] != DNGN_FLOOR
&& --tries > 0);
+ if (tries <= 0)
+ break;
+
trap_type &trap_type = env.trap[i].type;
- trap_type = random_trap_for_level(level_number);
+ trap_type = random_trap_for_place(level_number);
grd[env.trap[i].x][env.trap[i].y] = DNGN_UNDISCOVERED_TRAP;
} // end "for i"
} // end place_traps()
+static void place_fog_machines(int level_number)
+{
+ int i;
+ int num_fogs = num_fogs_for_place(level_number);
+
+ ASSERT(num_fogs >= 0);
+
+ for (i = 0; i < num_fogs; i++)
+ {
+ fog_machine_data data = random_fog_for_place(level_number);
+
+ if (!valid_fog_machine_data(data))
+ {
+ mpr("Invalid fog machine data, bailing.", MSGCH_DIAGNOSTICS);
+ return;
+ }
+
+ int tries = 200;
+ int x, y;
+ dungeon_feature_type feat;
+ do
+ {
+ x = random2(GXM);
+ y = random2(GYM);
+ feat = grd[x][y];
+ }
+ while (feat <= DNGN_MAXWALL && --tries > 0);
+
+ if (tries <= 0)
+ break;
+
+ place_fog_machine(data, x, y);
+ } // end "for i"
+} // end place_traps()
+
static void place_specific_feature(dungeon_feature_type feat)
{
int sx, sy;
do
{
- sx = random2(GXM-10);
- sy = random2(GYM-10);
+ sx = random_range(X_BOUND_1 + 1, X_BOUND_2 - 1);
+ sy = random_range(Y_BOUND_1 + 1, Y_BOUND_2 - 1);
}
while(grd[sx][sy] != DNGN_FLOOR || mgrd[sx][sy] != NON_MONSTER);
@@ -2227,25 +2459,25 @@ static void make_trail(int xs, int xr, int ys, int yr, int corrlength,
if (dir_x == 0 && dir_y == 0)
continue;
- if (x_ps < 8)
+ if (x_ps < X_BOUND_1 + 3)
{
dir_x = 1;
dir_y = 0;
}
- if (y_ps < 8)
+ if (y_ps < Y_BOUND_1 + 3)
{
dir_y = 1;
dir_x = 0;
}
- if (x_ps > (GXM - 8))
+ if (x_ps > (X_BOUND_2 - 3))
{
dir_x = -1;
dir_y = 0;
}
- if (y_ps > (GYM - 8))
+ if (y_ps > (Y_BOUND_2 - 3))
{
dir_y = -1;
dir_x = 0;
@@ -2261,25 +2493,25 @@ static void make_trail(int xs, int xr, int ys, int yr, int corrlength,
{
// 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)
+ if (x_ps < X_BOUND_1 + 4)
{
dir_y = 0; //random2(3) - 1;
dir_x = 1;
}
- if (x_ps > (GXM - 9))
+ if (x_ps > (X_BOUND_2 - 4))
{
dir_y = 0; //random2(3) - 1;
dir_x = -1;
}
- if (y_ps < 9)
+ if (y_ps < Y_BOUND_1 + 4)
{
dir_y = 1;
dir_x = 0; //random2(3) - 1;
}
- if (y_ps > (GYM - 9))
+ if (y_ps > (Y_BOUND_2 - 4))
{
dir_y = -1;
dir_x = 0; //random2(3) - 1;
@@ -2549,6 +2781,13 @@ static void place_aquatic_monsters(int level_number, char level_type)
swimming_things[i] = MONS_BIG_FISH + random2(4);
if (player_in_branch( BRANCH_SWAMP ) && !one_chance_in(3))
swimming_things[i] = MONS_SWAMP_WORM;
+ else if (player_in_branch( BRANCH_SHOALS ))
+ {
+ if (one_chance_in(3))
+ swimming_things[i] = MONS_MERFOLK;
+ else if (one_chance_in(5))
+ swimming_things[i] = MONS_MERMAID;
+ }
}
if (level_number >= 25 && one_chance_in(5))
@@ -2710,7 +2949,7 @@ static void specr_2(spec_room &sr)
sy += dy;
// quit if we run off the map before finding floor
- if (sx < 6 || sx > (GXM - 7) || sy < 6 || sy > (GYM - 7))
+ if (!in_bounds(sx, sy))
{
bkout++;
goto grolko;
@@ -2738,7 +2977,7 @@ static void specr_2(spec_room &sr)
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
+ if (j > 0 && grd[sx + dx][sy + dy] > DNGN_MINWALL
&& grd[sx + dx][sy + dy] < DNGN_FLOOR)
grd[sx][sy] = DNGN_BUILDER_SPECIAL_FLOOR;
@@ -3907,9 +4146,13 @@ static bool build_vaults(int level_number, int force_vault, int rune_subst,
stair_exist[sty] = 0;
}
+ // Don't create any new up stairs on dungeon level 1.
+ bool no_up_stairs = player_branch_depth() == 1 &&
+ you.level_type == LEVEL_DUNGEON;
+
for (int j = 0; j < (coinflip()? 4 : 3); j++)
{
- for (int i = 0; i < 2; i++)
+ for (int i = 0; i < (no_up_stairs ? 1 : 2); i++)
{
const dungeon_feature_type stair =
static_cast<dungeon_feature_type>(
@@ -3921,8 +4164,8 @@ static bool build_vaults(int level_number, int force_vault, int rune_subst,
do
{
- pos_x = 10 + random2(GXM - 20);
- pos_y = 10 + random2(GYM - 20);
+ pos_x = random_range(X_BOUND_1 + 1, X_BOUND_2 - 1);
+ pos_y = random_range(Y_BOUND_1 + 1, Y_BOUND_2 - 1);
}
while (grd[pos_x][pos_y] != DNGN_FLOOR
|| (pos_x >= v1x && pos_x <= v2x && pos_y >= v1y
@@ -4115,6 +4358,9 @@ dungeon_feature_type map_feature(map_def *map, const coord_def &c, int rawfeat)
(rawfeat == 'v') ? DNGN_METAL_WALL :
(rawfeat == 'b') ? DNGN_GREEN_CRYSTAL_WALL :
(rawfeat == 'a') ? DNGN_WAX_WALL :
+ (rawfeat == 'm') ? DNGN_CLEAR_ROCK_WALL :
+ (rawfeat == 'n') ? DNGN_CLEAR_STONE_WALL :
+ (rawfeat == 'o') ? DNGN_CLEAR_PERMAROCK_WALL :
(rawfeat == '+') ? DNGN_CLOSED_DOOR :
(rawfeat == '=') ? DNGN_SECRET_DOOR :
(rawfeat == 'w') ? DNGN_DEEP_WATER :
@@ -4178,7 +4424,7 @@ static int vault_grid( vault_placement &place,
else if (f.trap >= 0)
{
const trap_type trap =
- f.trap == TRAP_INDEPTH? random_trap_for_level(level_number)
+ f.trap == TRAP_INDEPTH? random_trap_for_place(level_number)
: static_cast<trap_type>(f.trap);
place_specific_trap(vx, vy, trap);
@@ -4211,6 +4457,9 @@ static int vault_grid( vault_placement &place,
(vgrid == 'v') ? DNGN_METAL_WALL :
(vgrid == 'b') ? DNGN_GREEN_CRYSTAL_WALL :
(vgrid == 'a') ? DNGN_WAX_WALL :
+ (vgrid == 'm') ? DNGN_CLEAR_ROCK_WALL :
+ (vgrid == 'n') ? DNGN_CLEAR_STONE_WALL :
+ (vgrid == 'o') ? DNGN_CLEAR_PERMAROCK_WALL :
(vgrid == '+') ? DNGN_CLOSED_DOOR :
(vgrid == '=') ? DNGN_SECRET_DOOR :
(vgrid == 'w') ? DNGN_DEEP_WATER :
@@ -4251,7 +4500,7 @@ static int vault_grid( vault_placement &place,
place_specific_trap(vx, vy, TRAP_RANDOM);
break;
case '~':
- place_specific_trap(vx, vy, random_trap_for_level(level_number));
+ place_specific_trap(vx, vy, random_trap_for_place(level_number));
break;
}
@@ -4647,8 +4896,8 @@ static void many_pools(dungeon_feature_type pool_type)
for ( int timeout = 0; pools < num_pools && timeout < 30000; ++timeout )
{
- const int i = 6 + random2( GXM - 26 );
- const int j = 6 + random2( GYM - 26 );
+ const int i = random_range(X_BOUND_1 + 1, X_BOUND_2 - 21);
+ const int j = random_range(Y_BOUND_1 + 1, Y_BOUND_2 - 21);
const int k = i + 2 + roll_dice( 2, 9 );
const int l = j + 2 + roll_dice( 2, 9 );
@@ -4845,8 +5094,8 @@ static void place_shops(int level_number, int nshops)
do
{
- shop_place_x = random2(GXM - 20) + 10;
- shop_place_y = random2(GYM - 20) + 10;
+ shop_place_x = random_range(X_BOUND_1 + 1, X_BOUND_2 - 1);
+ shop_place_y = random_range(Y_BOUND_1 + 1, Y_BOUND_2 - 1);
timeout++;
@@ -5097,8 +5346,8 @@ static void spotty_level(bool seeded, int iterations, bool boxy)
do
{
- j = 10 + random2(GXM - 20);
- k = 10 + random2(GYM - 20);
+ j = random_range(X_BOUND_1 + 4, X_BOUND_2 - 4);
+ k = random_range(Y_BOUND_1 + 4, Y_BOUND_2 - 4);
}
while (grd[j][k] != DNGN_ROCK_WALL
&& grd[j + 1][k] != DNGN_ROCK_WALL);
@@ -5133,8 +5382,8 @@ static void spotty_level(bool seeded, int iterations, bool boxy)
{
do
{
- j = random2(GXM - 20) + 10;
- k = random2(GYM - 20) + 10;
+ j = random_range(X_BOUND_1 + 4, X_BOUND_2 - 4);
+ k = random_range(Y_BOUND_1 + 4, Y_BOUND_2 - 4);
}
while (grd[j][k] == DNGN_ROCK_WALL
&& grd[j - 1][k] == DNGN_ROCK_WALL
@@ -5759,8 +6008,8 @@ static void init_minivault_placement(int vault, vault_placement &place)
static void labyrinth_dimension_adjust(int delta, int &ds, int &dw)
{
- if (delta > MAPGEN_BORDER)
- delta = MAPGEN_BORDER;
+ if (delta > LABYRINTH_BORDER / 2)
+ delta = LABYRINTH_BORDER / 2;
if (delta)
{
@@ -5950,10 +6199,10 @@ static void labyrinth_place_entry_point(const dgn_region &region,
static void labyrinth_level(int level_number)
{
dgn_region lab =
- dgn_region::absolute( MAPGEN_BORDER * 2,
- MAPGEN_BORDER * 2,
- GXM - MAPGEN_BORDER * 2 - 1,
- GYM - MAPGEN_BORDER * 2 - 1 );
+ dgn_region::absolute( LABYRINTH_BORDER,
+ LABYRINTH_BORDER,
+ GXM - LABYRINTH_BORDER - 1,
+ GYM - LABYRINTH_BORDER - 1 );
// First decide if we're going to use a Lab minivault.
int vault = random_map_for_tag("minotaur", true, false);
@@ -6034,6 +6283,9 @@ static bool is_wall(int x, int y)
case DNGN_METAL_WALL:
case DNGN_GREEN_CRYSTAL_WALL:
case DNGN_WAX_WALL:
+ case DNGN_CLEAR_ROCK_WALL:
+ case DNGN_CLEAR_STONE_WALL:
+ case DNGN_CLEAR_PERMAROCK_WALL:
return true;
default:
return false;
@@ -6425,7 +6677,11 @@ static void big_room(int level_number)
replace_area(sr.x1, sr.y1, sr.x2, sr.y2, DNGN_CLOSED_DOOR, type_floor);
if (type_floor == DNGN_FLOOR)
- type_2 = static_cast<dungeon_feature_type>(DNGN_ROCK_WALL + random2(4));
+ {
+ const int minwall = DNGN_RNDWALL_MIN;
+ const int range = DNGN_RNDWALL_MAX - DNGN_RNDWALL_MIN + 1;
+ type_2 = static_cast<dungeon_feature_type>(minwall + random2(range));
+ }
// no lava in the Crypt or Tomb, thanks!
if (player_in_branch( BRANCH_CRYPT ) || player_in_branch( BRANCH_TOMB ))
@@ -6741,8 +6997,24 @@ static void jelly_pit(int level_number, spec_room &sr)
bool place_specific_trap(int spec_x, int spec_y,
trap_type spec_type)
{
- if (spec_type == TRAP_RANDOM)
- spec_type = static_cast<trap_type>( random2(NUM_TRAPS) );
+ if (spec_type == TRAP_RANDOM || spec_type == TRAP_NONTELEPORT)
+ {
+ trap_type forbidden1 = NUM_TRAPS;
+ trap_type forbidden2 = NUM_TRAPS;
+
+ if (spec_type == TRAP_NONTELEPORT)
+ {
+ forbidden1 = TRAP_SHAFT;
+ forbidden2 = TRAP_TELEPORT;
+ }
+ else if (!is_valid_shaft_level())
+ forbidden1 = TRAP_SHAFT;
+
+ do
+ {
+ spec_type = static_cast<trap_type>( random2(NUM_TRAPS) );
+ } while (spec_type == forbidden1 || spec_type == forbidden2);
+ }
for (int tcount = 0; tcount < MAX_TRAPS; tcount++)
{
@@ -7318,6 +7590,15 @@ coord_def dgn_find_nearby_stair(dungeon_feature_type stair_to_find,
return result;
}
+void dgn_set_lt_callback(std::string level_type_name,
+ std::string callback_name)
+{
+ ASSERT(level_type_name != "");
+ ASSERT(callback_name != "");
+
+ level_type_post_callbacks[level_type_name] = callback_name;
+}
+
////////////////////////////////////////////////////////////////////
// dgn_region
diff --git a/crawl-ref/source/dungeon.h b/crawl-ref/source/dungeon.h
index d67a99f2cb..15f701de83 100644
--- a/crawl-ref/source/dungeon.h
+++ b/crawl-ref/source/dungeon.h
@@ -299,11 +299,10 @@ bool flood_find<fgrd, bound_check>::path_flood(
bool builder(int level_number, int level_type);
-int bazaar_floor_colour(int curr_level);
// Set floor/wall colour based on the mons_alloc array. Used for
// Abyss and Pan.
void dgn_set_colours_from_monsters();
-void dgn_set_floor_colours();
+void dgn_set_grid_colour_at(const coord_def &c, int colour);
void dgn_set_grid_colour_at(const coord_def &c, int colour);
bool dgn_place_map(int map, bool generating_level, bool clobber,
@@ -325,4 +324,10 @@ bool dgn_place_monster(const mons_spec &mspec,
int monster_level, int vx, int vy,
bool generate_awake);
+bool set_level_flags(unsigned long flags, bool silent = false);
+bool unset_level_flags(unsigned long flags, bool silent = false);
+
+void dgn_set_lt_callback(std::string level_type_name,
+ std::string callback_name);
+
#endif
diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc
index 7a0f9c5b60..bb45b4ad98 100644
--- a/crawl-ref/source/effects.cc
+++ b/crawl-ref/source/effects.cc
@@ -20,6 +20,7 @@
#include "externs.h"
#include "beam.h"
+#include "decks.h"
#include "direct.h"
#include "food.h"
#include "hiscores.h"
@@ -40,16 +41,17 @@
#include "ouch.h"
#include "player.h"
#include "randart.h"
-#include "religion.h"
#include "skills2.h"
#include "spells3.h"
#include "spells4.h"
#include "spl-book.h"
#include "spl-util.h"
+#include "state.h"
#include "stuff.h"
#include "terrain.h"
#include "traps.h"
#include "view.h"
+#include "xom.h"
// torment_monsters is called with power 0 because torment is
// UNRESISTABLE except for being undead or having torment
@@ -153,19 +155,129 @@ void banished(dungeon_feature_type gate_type, const std::string &who)
"escaped from the Abyss!" + who_banished(who));
#endif
- if (gate_type == DNGN_ENTER_ABYSS)
+ std::string cast_into = "";
+
+ switch(gate_type)
+ {
+ case DNGN_ENTER_ABYSS:
+ if (you.level_type == LEVEL_ABYSS)
+ {
+ mpr("You feel trapped.");
+ return;
+ }
+ cast_into = "the Abyss";
+ break;
+
+ case DNGN_EXIT_ABYSS:
+ if (you.level_type != LEVEL_ABYSS)
+ {
+ mpr("You feel dizzy for a moment.");
+ return;
+ }
+ break;
+
+ case DNGN_ENTER_PANDEMONIUM:
+ if (you.level_type == LEVEL_PANDEMONIUM)
+ {
+ mpr("You feel trapped.");
+ return;
+ }
+ cast_into = "Pandemonium";
+ break;
+
+ case DNGN_TRANSIT_PANDEMONIUM:
+ if (you.level_type != LEVEL_PANDEMONIUM)
+ {
+ banished(DNGN_ENTER_PANDEMONIUM, who);
+ return;
+ }
+ break;
+
+ case DNGN_EXIT_PANDEMONIUM:
+ if (you.level_type != LEVEL_PANDEMONIUM)
+ {
+ mpr("You feel dizzy for a moment.");
+ return;
+ }
+ break;
+
+ case DNGN_ENTER_LABYRINTH:
+ if (you.level_type == LEVEL_LABYRINTH)
+ {
+ mpr("You feel trapped.");
+ return;
+ }
+ cast_into = "a Labyrinth";
+ break;
+
+ case DNGN_ENTER_HELL:
+ case DNGN_ENTER_DIS:
+ case DNGN_ENTER_GEHENNA:
+ case DNGN_ENTER_COCYTUS:
+ case DNGN_ENTER_TARTARUS:
+ if (player_in_hell() || player_in_branch(BRANCH_VESTIBULE_OF_HELL))
+ {
+ mpr("You feel dizzy for a moment.");
+ return;
+ }
+ cast_into = "Hell";
+ break;
+
+ default:
+ mprf(MSGCH_DIAGNOSTICS, "Invalid banished() gateway %d",
+ static_cast<int>(gate_type));
+ ASSERT(false);
+ }
+
+ // Now figure out how we got here.
+ if (crawl_state.is_god_acting())
{
- const std::string what = "Cast into the Abyss" + who_banished(who);
- take_note(Note(NOTE_USER_NOTE, 0, 0, what.c_str()), true);
+ // down_stairs() will take care of setting things.
+ you.entry_cause = EC_UNKNOWN;
+ }
+ else if (who.find("self") != std::string::npos || who == you.your_name
+ || who == "you" || who == "You")
+ {
+ you.entry_cause = EC_SELF_EXPLICIT;
+ }
+ else if (who.find("distortion") != std::string::npos)
+ {
+ if (who.find("wield") != std::string::npos)
+ {
+ if (who.find("unknowing") != std::string::npos)
+ you.entry_cause = EC_SELF_ACCIDENT;
+ else
+ you.entry_cause = EC_SELF_RISKY;
+ }
+ else if (who.find("affixation") != std::string::npos)
+ you.entry_cause = EC_SELF_ACCIDENT;
+ else if (who.find("branding") != std::string::npos)
+ you.entry_cause = EC_SELF_RISKY;
+ else
+ you.entry_cause = EC_MONSTER;
+ }
+ else if (who == "drawing a card")
+ you.entry_cause = EC_SELF_RISKY;
+ else if (who.find("miscast") != std::string::npos)
+ you.entry_cause = EC_MISCAST;
+ else if (who == "wizard command")
+ you.entry_cause = EC_SELF_EXPLICIT;
+ else
+ you.entry_cause = EC_MONSTER;
+
+ if (!crawl_state.is_god_acting())
+ you.entry_cause_god = GOD_NO_GOD;
+
+ if (cast_into != "" && you.entry_cause != EC_SELF_EXPLICIT)
+ {
+ const std::string what = "Cast into " + cast_into + who_banished(who);
+ take_note(Note(NOTE_MESSAGE, 0, 0, what.c_str()), true);
}
// no longer held in net
clear_trapping_net();
-
- down_stairs(you.your_level, gate_type); // heh heh
- if (gate_type == DNGN_ENTER_ABYSS || gate_type == DNGN_ENTER_PANDEMONIUM)
- xom_is_stimulated(255);
+ down_stairs(you.your_level, gate_type, you.entry_cause); // heh heh
}
bool forget_spell(void)
@@ -198,13 +310,16 @@ bool forget_spell(void)
// 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 lose_stat(unsigned char which_stat, unsigned char stat_loss, bool force,
+ const char *cause, bool see_source)
{
bool statLowered = false; // must initialize to false {dlb}
char *ptr_stat = NULL;
bool *ptr_redraw = NULL;
char newValue = 0; // holds new value, for comparison to old {dlb}
+ kill_method_type kill_type = NUM_KILLBY;
+
// begin outputing message: {dlb}
std::string msg = "You feel ";
@@ -215,21 +330,24 @@ bool lose_stat(unsigned char which_stat, unsigned char stat_loss, bool force)
switch (which_stat)
{
case STAT_STRENGTH:
- msg += "weakened";
- ptr_stat = &you.strength;
+ msg += "weakened";
+ ptr_stat = &you.strength;
ptr_redraw = &you.redraw_strength;
+ kill_type = KILLED_BY_WEAKNESS;
break;
case STAT_DEXTERITY:
- msg += "clumsy";
- ptr_stat = &you.dex;
+ msg += "clumsy";
+ ptr_stat = &you.dex;
ptr_redraw = &you.redraw_dexterity;
+ kill_type = KILLED_BY_CLUMSINESS;
break;
case STAT_INTELLIGENCE:
- msg += "dopey";
- ptr_stat = &you.intel;
+ msg += "dopey";
+ ptr_stat = &you.intel;
ptr_redraw = &you.redraw_intelligence;
+ kill_type = KILLED_BY_STUPIDITY;
break;
}
@@ -241,10 +359,6 @@ bool lose_stat(unsigned char which_stat, unsigned char stat_loss, bool force)
// 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}
//
@@ -273,13 +387,85 @@ bool lose_stat(unsigned char which_stat, unsigned char stat_loss, bool force)
msg += ".";
mpr(msg.c_str());
+ if (newValue < 1)
+ {
+ if (cause == NULL)
+ ouch(INSTANT_DEATH, 0, kill_type);
+ else
+ ouch(INSTANT_DEATH, 0, kill_type, cause, see_source);
+ }
+
+
return (statLowered);
} // end lose_stat()
+bool lose_stat(unsigned char which_stat, unsigned char stat_loss, bool force,
+ const std::string cause, bool see_source)
+{
+ return lose_stat(which_stat, stat_loss, force, cause.c_str(), see_source);
+}
+
+bool lose_stat(unsigned char which_stat, unsigned char stat_loss,
+ const monsters* cause, bool force)
+{
+ if (cause == NULL || invalid_monster(cause))
+ return lose_stat(which_stat, stat_loss, force, NULL, true);
+
+ bool vis = mons_near(cause) && player_monster_visible(cause);
+ std::string name = cause->name(DESC_NOCAP_A, true);
+
+ if (cause->has_ench(ENCH_SHAPESHIFTER))
+ name += " (shapeshifter)";
+ else if (cause->has_ench(ENCH_GLOWING_SHAPESHIFTER))
+ name += " (glowing shapeshifter)";
+
+ return lose_stat(which_stat, stat_loss, force, name, vis);
+}
+
+bool lose_stat(unsigned char which_stat, unsigned char stat_loss,
+ const item_def &cause, bool removed, bool force)
+{
+ std::string name = cause.name(DESC_NOCAP_THE, false, true, false, false,
+ ISFLAG_KNOW_CURSE | ISFLAG_KNOW_PLUSES);
+ std::string verb;
+
+ switch(cause.base_type)
+ {
+ case OBJ_ARMOUR:
+ case OBJ_JEWELLERY:
+ if (removed)
+ verb = "removing";
+ else
+ verb = "wearing";
+ break;
+
+ case OBJ_WEAPONS:
+ case OBJ_STAVES:
+ if (removed)
+ verb = "unwielding";
+ else
+ verb = "wielding";
+ break;
+
+ case OBJ_WANDS: verb = "zapping"; break;
+ case OBJ_FOOD: verb = "eating"; break;
+ case OBJ_SCROLLS: verb = "reading"; break;
+ case OBJ_POTIONS: verb = "drinking"; break;
+ default: verb = "using";
+ }
+
+ return lose_stat(which_stat, stat_loss, force, verb + " " + name, true);
+}
+
void direct_effect(struct bolt &pbolt)
{
int damage_taken = 0;
+ monsters* source = NULL;
+
+ if (pbolt.beam_source != NON_MONSTER)
+ source = &menv[pbolt.beam_source];
+
switch (pbolt.type)
{
case DMNBM_HELLFIRE:
@@ -308,7 +494,8 @@ void direct_effect(struct bolt &pbolt)
case DMNBM_BRAIN_FEED:
// lose_stat() must come last {dlb}
- if (one_chance_in(3) && lose_stat(STAT_INTELLIGENCE, 1))
+ if (one_chance_in(3) &&
+ lose_stat(STAT_INTELLIGENCE, 1, source))
{
mpr("Something feeds on your intellect!");
xom_is_stimulated(50);
@@ -674,8 +861,8 @@ static int find_acquirement_subtype(object_class_type class_wanted,
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))
+ if (type_wanted == ARM_BOOTS && !player_has_feet()
+ || you.has_claws(false) >= 3 && type_wanted == ARM_GLOVES)
{
type_wanted = OBJ_RANDOM;
}
@@ -716,11 +903,6 @@ static int find_acquirement_subtype(object_class_type class_wanted,
}
break;
- case SP_KENKU:
- if (type_wanted == ARM_BOOTS)
- type_wanted = OBJ_RANDOM;
- break;
-
default:
break;
}
@@ -1117,7 +1299,6 @@ static int find_acquirement_subtype(object_class_type class_wanted,
bool acquirement(object_class_type class_wanted, int agent)
{
int thing_created = 0;
- int unique = 1;
while (class_wanted == OBJ_RANDOM)
{
@@ -1147,12 +1328,14 @@ bool acquirement(object_class_type class_wanted, int agent)
if (!silenced(you.pos()))
mprf(MSGCH_SOUND,
grid_item_destruction_message(grd[you.x_pos][you.y_pos]));
+
+ item_was_destroyed(mitm[igrd[you.x_pos][you.y_pos]], NON_MONSTER);
}
else
{
for (int item_tries = 0; item_tries < 40; item_tries++)
{
- unique = 1;
+ int unique = 1;
int type_wanted = find_acquirement_subtype(class_wanted, unique);
// clobber class_wanted for vampires
@@ -1160,7 +1343,7 @@ bool acquirement(object_class_type class_wanted, int agent)
class_wanted = OBJ_POTIONS;
// BCR - unique is now used for food quantity.
- thing_created = items( unique, class_wanted, type_wanted, true,
+ thing_created = items( 1, class_wanted, type_wanted, true,
MAKE_GOOD_ITEM, 250 );
if (thing_created == NON_ITEM)
@@ -1268,6 +1451,7 @@ bool acquirement(object_class_type class_wanted, int agent)
case SP_DEMONSPAWN:
case SP_MUMMY:
case SP_GHOUL:
+ case SP_VAMPIRE:
{
int brand = get_weapon_brand( thing );
if (brand == SPWPN_HOLY_WRATH
@@ -1508,29 +1692,58 @@ bool recharge_wand(void)
return (true);
} // end recharge_wand()
-void yell(void)
+void yell(bool force)
{
bool targ_prev = false;
int mons_targd = MHITNOT;
struct dist targ;
- if (silenced(you.x_pos, you.y_pos) || you.cannot_speak())
- {
- mpr("You are unable to make a sound!");
- return;
- }
-
const std::string shout_verb = you.shout_verb();
std::string cap_shout = shout_verb;
cap_shout[0] = toupper(cap_shout[0]);
- int noise_level = 12;
+ int noise_level = 12; // "shout"
// Tweak volume for different kinds of vocalisation.
if (shout_verb == "roar")
noise_level = 18;
else if (shout_verb == "hiss")
noise_level = 8;
+ else if (shout_verb == "squeak")
+ noise_level = 4;
+ else if (shout_verb == "__NONE")
+ noise_level = 0;
+ else if (shout_verb == "yell")
+ noise_level = 14;
+ else if (shout_verb == "scream")
+ noise_level = 16;
+
+ if (silenced(you.x_pos, you.y_pos) || you.cannot_speak())
+ noise_level = 0;
+
+ if (noise_level == 0)
+ {
+ if (force)
+ {
+ if (shout_verb == "__NONE" || you.paralysed())
+ mprf("You feel a strong urge to %s, but you are unable to make a sound!",
+ shout_verb == "__NONE" ? "scream" : shout_verb.c_str());
+ else
+ mprf("You feel a %s rip itself from your throat, but you make no sound!",
+ shout_verb.c_str());
+ }
+ else
+ mpr("You are unable to make a sound!");
+
+ return;
+ }
+
+ if (force)
+ {
+ mprf("A %s rips itself from your throat!", shout_verb.c_str());
+ noisy( noise_level, you.x_pos, you.y_pos );
+ return;
+ }
mpr("What do you say?", MSGCH_PROMPT);
mprf(" ! - %s", cap_shout.c_str());
@@ -1613,3 +1826,55 @@ void yell(void)
noisy( 10, you.x_pos, you.y_pos );
mpr("Attack!");
} // end yell()
+
+bool forget_inventory(bool quiet)
+{
+ int items_forgotten = 0;
+
+ for (int i = 0; i < ENDOFPACK; i++)
+ {
+ item_def& item(you.inv[i]);
+ if (!is_valid_item(item) || item_is_equipped(item))
+ continue;
+
+ unsigned long orig_flags = item.flags;
+
+ unset_ident_flags(item, ISFLAG_KNOW_CURSE);
+
+ // Don't forget times used or uses left for wands or decks.
+ if (item.base_type != OBJ_WANDS && item.base_type != OBJ_MISCELLANY)
+ unset_ident_flags(item, ISFLAG_KNOW_PLUSES);
+
+ if (!is_artefact(item))
+ {
+ switch (item.base_type)
+ {
+ case OBJ_WEAPONS:
+ case OBJ_ARMOUR:
+ case OBJ_BOOKS:
+ case OBJ_STAVES:
+ case OBJ_MISCELLANY:
+ // Don't forget identity of decks if it the player has
+ // used any of its cards, or knows how many are left.
+ if (!is_deck(item) || item.plus2 == 0)
+ unset_ident_flags(item, ISFLAG_KNOW_TYPE);
+ break;
+
+ default:
+ break;
+ }
+ }
+ // Non-jewellery artefacts can easily be re-identified by
+ // equipping them.
+ else if (item.base_type != OBJ_JEWELLERY)
+ unset_ident_flags(item, ISFLAG_KNOW_TYPE | ISFLAG_KNOW_PROPERTIES);
+
+ if (item.flags != orig_flags)
+ items_forgotten++;
+ }
+
+ if (items_forgotten > 0)
+ mpr("Wait, did you forget something?");
+
+ return (items_forgotten > 0);
+}
diff --git a/crawl-ref/source/effects.h b/crawl-ref/source/effects.h
index 0ed6b8371e..1472fb4b56 100644
--- a/crawl-ref/source/effects.h
+++ b/crawl-ref/source/effects.h
@@ -18,6 +18,10 @@
struct bolt;
+class monsters;
+class item_def;
+
+
// last updated 12may2000 {dlb}
/* ***********************************************************************
* called from: ability - acr - beam - decks - fight - religion - spells
@@ -38,7 +42,15 @@ bool forget_spell(void);
* spells2 - spells4
* *********************************************************************** */
bool lose_stat(unsigned char which_stat, unsigned char stat_loss,
- bool force = false);
+ bool force = false, const std::string cause = "",
+ bool see_source = true);
+bool lose_stat(unsigned char which_stat, unsigned char stat_loss,
+ bool force = false, const char* cause = NULL,
+ bool see_source = true);
+bool lose_stat(unsigned char which_stat, unsigned char stat_loss,
+ const monsters* cause, bool force = false);
+bool lose_stat(unsigned char which_stat, unsigned char stat_loss,
+ const item_def &cause, bool removed, bool force = false);
// last updated 12may2000 {dlb}
@@ -80,7 +92,7 @@ void mons_direct_effect(struct bolt &pbolt, int i);
/* ***********************************************************************
* called from: acr
* *********************************************************************** */
-void yell(void);
+void yell(bool force = false);
// last updated 12may2000 {dlb}
@@ -92,4 +104,6 @@ void torment( int caster, int tx, int ty );
int torment_monsters(int x, int y, int pow, int caster);
+bool forget_inventory(bool quiet = false);
+
#endif
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index 5ebf7b568e..12b7cdf79d 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -121,6 +121,7 @@ enum ability_type
ABIL_NEMELEX_PEEK_DECK,
ABIL_NEMELEX_DRAW_CARD,
ABIL_NEMELEX_TRIPLE_DRAW,
+ ABIL_NEMELEX_MARK_DECK,
ABIL_NEMELEX_STACK_DECK,
ABIL_BEOGH_SMITING,
ABIL_BEOGH_RECALL_ORCISH_FOLLOWERS,
@@ -173,6 +174,12 @@ enum attribute_type
ATTR_GOD_GIFT_COUNT, //jmf: added to help manage god gift giving
ATTR_DELAYED_FIREBALL, // bwr: reserve fireballs
ATTR_HELD, // caught in a net
+ ATTR_ABYSS_ENTOURAGE, // maximum number of hostile monsters in
+ // sight of the player while in the Abyss.
+ ATTR_UNIQUE_RUNES,
+ ATTR_DEMONIC_RUNES,
+ ATTR_ABYSSAL_RUNES,
+ ATTR_RUNES_IN_ZOT,
NUM_ATTRIBUTES
};
@@ -352,66 +359,6 @@ enum canned_message_type
MSG_EMPTY_HANDED
};
-enum card_type
-{
- CARD_BLANK = 0,
- CARD_PORTAL, // "the mover"
- CARD_WARP, // "the jumper"
- CARD_SWAP, // "swap"
- CARD_VELOCITY, // "the runner"
-
- CARD_TOMB, // "the wall"
- CARD_BANSHEE, // "the scream"
- CARD_DAMNATION, // banishment
- CARD_SOLITUDE, // dispersal
- CARD_WARPWRIGHT, // create teleport trap
-
- CARD_VITRIOL, // acid damage
- CARD_FLAME, // fire damage
- CARD_FROST, // cold damage
- CARD_VENOM, // poison damage
- CARD_HAMMER, // pure damage
- CARD_PAIN, // single target, like spell of agony
- CARD_TORMENT, // Symbol of Torment
-
- CARD_ELIXIR, // healing
- CARD_BATTLELUST, // melee boosts
- CARD_METAMORPHOSIS, // transformation
- CARD_HELM, // defense
- CARD_BLADE, // weapon boosts
- CARD_SHADOW, // assassin skills
-
- CARD_SUMMON_ANIMAL,
- CARD_SUMMON_DEMON,
- CARD_SUMMON_WEAPON,
- CARD_SUMMON_ANY,
-
- CARD_POTION,
- CARD_FOCUS,
- CARD_SHUFFLE,
-
- CARD_EXPERIENCE,
- CARD_WILD_MAGIC,
- CARD_HELIX, // remove one *bad* mutation
-
- CARD_MAP, // magic mapping
- CARD_DOWSING, // detect SD/traps/items/monsters
- CARD_SPADE, // dig
- CARD_TROWEL, // create feature/vault
- CARD_MINEFIELD, // plant traps
-
- CARD_GENIE, // acquirement OR rotting/deterioration
- CARD_BARGAIN, // shopping discount
- CARD_WRATH, // Godly wrath
- CARD_WRAITH, // drain XP
- CARD_XOM,
- CARD_FEAST,
- CARD_FAMINE,
- CARD_CURSE, // Curse your items
-
- NUM_CARDS
-};
-
enum char_set_type
{
CSET_ASCII, // flat 7-bit ASCII
@@ -545,6 +492,8 @@ enum command_type
CMD_MOUSE_MOVE,
CMD_MOUSE_CLICK,
+ CMD_ANNOTATE_LEVEL,
+
/* overmap commands */
CMD_MAP_CLEAR_MAP,
CMD_MAP_ADD_WAYPOINT,
@@ -585,6 +534,8 @@ enum command_type
CMD_MAP_GOTO_TARGET,
+ CMD_MAP_WIZARD_TELEPORT,
+
CMD_MAP_EXIT_MAP,
/* targeting commands */
@@ -637,8 +588,17 @@ enum command_type
CMD_ENABLE_MORE,
// [ds] Silently ignored, requests another round of input.
- CMD_NEXT_CMD
+ CMD_NEXT_CMD,
+
+ // Repeat previous command
+ CMD_PREV_CMD_AGAIN,
+ // Repeat next command a given number of times
+ CMD_REPEAT_CMD,
+
+ // Stick the keyspresses of the command to be repeated into the
+ // input buffer.
+ CMD_REPEAT_KEYS
};
enum conduct_type
@@ -672,6 +632,7 @@ enum conduct_type
DID_CARDS,
DID_STIMULANTS, // unused
DID_DRINK_BLOOD,
+ DID_CANNIBALISM,
DID_EAT_MEAT, // unused
DID_CREATED_LIFE, // unused
@@ -762,6 +723,15 @@ enum game_direction_type
GDT_ASCENDING
};
+enum level_flag_type
+{
+ LFLAG_NONE = 0,
+
+ LFLAG_NO_TELE_CONTROL = (1 << 0), // Teleport control not allowed.
+ LFLAG_NOT_MAPPABLE = (1 << 1), // Level not mappable (like Abyss).
+ LFLAG_NO_MAGIC_MAP = (1 << 2) // Level can't be magic mapped.
+};
+
// NOTE: The order of these is very important to their usage!
// [dshaligram] If adding/removing from this list, also update view.cc!
enum dungeon_char_type
@@ -809,27 +779,45 @@ enum dungeon_char_type
// * Any: edit dat/descript.txt and add a long description if appropriate.
// * Any: check the grid_* functions in misc.cc and make sure
// they return sane values for your new feature.
-//
+// * Any: edit dungeon.cc and add a symbol to map_feature() and
+// vault_grid() for the feature, if you want vault maps to
+// be able to use it. If you do, also update
+// docs/level-design.txt with the new symbol.
+// * Any: edit luadgn.cc and add the feature's name to the dngn_feature_names
+// array, if you want vault map Lua code to be able to use the
+// feature, and/or you want to be able to create the feature
+// using the "create feature by name" wizard command.
// Also take note of MINMOVE and MINSEE above.
//
enum dungeon_feature_type
{
DNGN_UNSEEN, // 0
- DNGN_ROCK_WALL,
- DNGN_STONE_WALL,
DNGN_CLOSED_DOOR,
+ DNGN_SECRET_DOOR,
+ DNGN_WAX_WALL,
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_GREEN_CRYSTAL_WALL, // 5
+ DNGN_ROCK_WALL,
+ DNGN_STONE_WALL,
+ DNGN_PERMAROCK_WALL, // 8 - for undiggable walls
+ DNGN_CLEAR_ROCK_WALL, // 9 - Transparent
+ DNGN_CLEAR_STONE_WALL, // 10 - Transparent
+ DNGN_CLEAR_PERMAROCK_WALL, // 11 - Transparent
+ DNGN_ORCISH_IDOL, // 12 - Can see past
+
+ // XXX: lowest/highest grid value which is a wall
+ DNGN_MINWALL = DNGN_WAX_WALL,
+ DNGN_MAXWALL = DNGN_CLEAR_PERMAROCK_WALL,
+
+ // Random wall types for big rooms
+ DNGN_RNDWALL_MIN = DNGN_METAL_WALL,
+ DNGN_RNDWALL_MAX = DNGN_STONE_WALL,
// XXX: highest grid value which is opaque
DNGN_MAXOPAQUE = DNGN_PERMAROCK_WALL,
-
+
// XXX: lowest grid value which can be seen through
- DNGN_MINSEE = 11,
+ DNGN_MINSEE = DNGN_CLEAR_ROCK_WALL,
DNGN_GRANITE_STATUE = 21, // 21
DNGN_STATUE_RESERVED_1,
@@ -846,12 +834,12 @@ enum dungeon_feature_type
DNGN_FLOOR, // 67
DNGN_FLOOR_SPECIAL, // currently only used for colouring bazaars
DNGN_FLOOR_RESERVED,
- DNGN_EXIT_HELL, // 68
- DNGN_ENTER_HELL, // 69
- DNGN_OPEN_DOOR, // 70
+ DNGN_EXIT_HELL, // 70
+ DNGN_ENTER_HELL, // 71
+ DNGN_OPEN_DOOR, // 72
DNGN_TRAP_MECHANICAL = 75, // 75
DNGN_TRAP_MAGICAL,
- DNGN_TRAP_III,
+ DNGN_TRAP_NATURAL,
DNGN_UNDISCOVERED_TRAP, // 78
DNGN_ENTER_SHOP = 80, // 80
@@ -1000,6 +988,7 @@ enum duration_type
DUR_CONF,
DUR_PARALYSIS,
DUR_SLOW,
+ DUR_BEHELD,
DUR_HASTE,
DUR_MIGHT,
DUR_LEVITATION,
@@ -1046,6 +1035,7 @@ enum duration_type
DUR_SLAYING,
DUR_STEALTH,
DUR_MAGIC_SHIELD,
+ DUR_SLEEP,
NUM_DURATIONS
};
@@ -1089,12 +1079,6 @@ enum enchant_retval
ERV_INCREASED
};
-enum enchant_stat_type
-{
- ENCHANT_TO_HIT,
- ENCHANT_TO_DAM
-};
-
enum equipment_type
{
EQ_NONE = -1,
@@ -1136,6 +1120,10 @@ enum flush_reason_type
FLUSH_ON_PROMPT, // flush on MSGCH_PROMPT messages
FLUSH_ON_UNSAFE_YES_OR_NO_PROMPT, // flush when !safe set to yesno()
FLUSH_LUA, // flush when Lua wants to flush
+ FLUSH_KEY_REPLAY_CANCEL, // flush when key replay is cancelled
+ FLUSH_ABORT_MACRO, // something wrong with macro being
+ // processed, so stop it
+ FLUSH_REPLAY_SETUP_FAILURE, // setup for key replay failed
NUM_FLUSH_REASONS
};
@@ -1247,7 +1235,9 @@ enum item_status_flag_type // per item flags: ie. ident status, cursed status
ISFLAG_RACIAL_MASK = 0x07000000, // mask of racial equipment types
ISFLAG_NOTED_ID = 0x08000000,
- ISFLAG_NOTED_GET = 0x10000000
+ ISFLAG_NOTED_GET = 0x10000000,
+
+ ISFLAG_BEEN_IN_INV = 0x20000000 // Item has been in inventory
};
enum job_type
@@ -1326,6 +1316,19 @@ enum level_area_type // you.level_type
NUM_LEVEL_AREA_TYPES
};
+enum entry_cause_type
+{
+ EC_UNKNOWN,
+ EC_SELF_EXPLICIT,
+ EC_SELF_RISKY, // i.e., wielding an id'd distorion weapon
+ EC_SELF_ACCIDENT, // i.e., wielding an un-id'd distortion weapon
+ EC_MISCAST,
+ EC_GOD_RETRIUBTION,
+ EC_GOD_ACT, // Xom sending the player somewhere for amusement
+ EC_MONSTER,
+ NUM_ENTRY_CAUSE_TYPES
+};
+
// Can't change this order without breaking saves.
enum map_marker_type
{
@@ -1554,6 +1557,8 @@ enum monster_type // (int) menv[].type
MONS_BLACK_BEAR, // 189
MONS_SIMULACRUM_SMALL,
MONS_SIMULACRUM_LARGE,
+ MONS_MERFOLK,
+ MONS_MERMAID, // 193
//jmf: end new monsters
MONS_WHITE_IMP = 220, // 220
MONS_LEMURE,
@@ -1744,6 +1749,9 @@ enum monster_type // (int) menv[].type
MONS_WATER_ELEMENTAL,
MONS_SWAMP_WORM, // 435
+ // Monsters which move through rock:
+ MONS_ROCK_WORM = 440,
+
// Statuary
MONS_ORANGE_STATUE,
MONS_SILVER_STATUE,
@@ -1818,6 +1826,7 @@ enum mon_inv_type // (int) menv[].inv[]
// for monsters that can use two weapons.
MSLOT_MISSILE,
MSLOT_ARMOUR,
+ MSLOT_SHIELD,
MSLOT_MISCELLANY,
MSLOT_POTION,
MSLOT_WAND,
@@ -1967,7 +1976,7 @@ enum mutation_type
MUT_HORNS,
MUT_STRONG_STIFF,
MUT_FLEXIBLE_WEAK,
- MUT_LOST, // 35
+ MUT_SCREAM, // 35
MUT_CLARITY,
MUT_BERSERK,
MUT_DETERIORATION,
@@ -1989,31 +1998,42 @@ enum mutation_type
MUT_DRAIN_LIFE,
MUT_THROW_FLAMES, // 55
MUT_THROW_FROST,
- MUT_SMITE, // 57
- MUT_CLAWS, //jmf: added
- MUT_HOOVES, //jmf: etc.
- MUT_FANGS, // 60
+ MUT_SMITE,
+ MUT_CLAWS,
+ MUT_FANGS, // new in 0.3
+ // hooves, talons, paws can replace feet
+ MUT_HOOVES, // 60
+ MUT_TALONS, // new in 0.4
+ MUT_PAWS, // new in 0.4
MUT_BREATHE_POISON,
MUT_STINGER,
- MUT_BIG_WINGS,
- MUT_BLUE_MARKS, // 64 - decorative, as in "mark of the devil"
- MUT_GREEN_MARKS, // 65
- MUT_RED_SCALES = 70, // 70
+ MUT_BIG_WINGS, // 65
+ MUT_BLUE_MARKS, // decorative, as in "mark of the devil"
+ MUT_GREEN_MARKS,
+ MUT_DRIFTING, // new in 0.4
+ MUT_SAPROVOROUS,
+ MUT_SHAGGY_FUR, // new in 0.4 -- 70
+ MUT_HIGH_MAGIC, // new in 0.4
+ MUT_LOW_MAGIC, // new in 0.4
+ MUT_SLEEPINESS, // new in 0.4
+
+ // several types of scales (affect AC and sometimes more)
+ MUT_RED_SCALES = 75, // 75
MUT_NACREOUS_SCALES,
MUT_GREY2_SCALES,
MUT_METALLIC_SCALES,
MUT_BLACK2_SCALES,
- MUT_WHITE_SCALES, // 75
+ MUT_WHITE_SCALES, // 80
MUT_YELLOW_SCALES,
MUT_BROWN_SCALES,
MUT_BLUE_SCALES,
MUT_PURPLE_SCALES,
- MUT_SPECKLED_SCALES, // 80
+ MUT_SPECKLED_SCALES, // 85
MUT_ORANGE_SCALES,
MUT_INDIGO_SCALES,
MUT_RED2_SCALES,
MUT_IRIDESCENT_SCALES,
- MUT_PATTERNED_SCALES, // 85
+ MUT_PATTERNED_SCALES, // 90
NUM_MUTATIONS,
RANDOM_MUTATION = 100,
@@ -2088,6 +2108,42 @@ enum pronoun_type
PRONOUN_REFLEXIVE // 4 (reflexive is always lowercase)
};
+enum randart_prop_type
+{
+ 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,
+ RAP_MAGICAL_POWER, // 30
+ RAP_NUM_PROPERTIES
+};
+
enum score_format_type
{
SCORE_TERSE, // one line
@@ -2423,7 +2479,7 @@ enum spell_type
SPELL_CONJURE_BALL_LIGHTNING,
SPELL_CHAIN_LIGHTNING,
SPELL_EXCRUCIATING_WOUNDS,
- SPELL_PORTALED_PROJECTILE,
+ SPELL_PORTAL_PROJECTILE,
// Mostly monster-only spells after this point:
SPELL_HELLFIRE_BURST, // 205
@@ -2487,12 +2543,13 @@ enum trap_type // env.trap_type[]
TRAP_SPEAR,
TRAP_AXE,
TRAP_TELEPORT,
- TRAP_AMNESIA, // 5
+ TRAP_ALARM, // 5
TRAP_BLADE,
TRAP_BOLT,
TRAP_NET,
TRAP_ZOT,
TRAP_NEEDLE,
+ TRAP_SHAFT,
NUM_TRAPS, // must remain last 'regular' member {dlb}
TRAP_UNASSIGNED = 100, // keep set at 100 for now {dlb}
TRAP_INDEPTH = 253, // Level-appropriate trap.
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index f937f71c5f..43c925197a 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -23,6 +23,7 @@
#include <set>
#include <memory>
#include <cstdlib>
+#include <deque>
#include <time.h>
@@ -31,6 +32,7 @@
#include "FixAry.h"
#include "libutil.h"
#include "mpr.h"
+#include "store.h"
#define INFO_SIZE 200 // size of message buffers
#define ITEMNAME_SIZE 200 // size of item names/shop names/etc
@@ -62,6 +64,7 @@ const int kPathLen = 256;
class item_def;
class melee_attack;
class coord_def;
+class level_id;
class actor
{
@@ -80,9 +83,15 @@ public:
virtual bool swimming() const = 0;
virtual bool submerged() const = 0;
virtual bool floundering() const = 0;
+
+ virtual bool can_pass_through(const dungeon_feature_type grid) const = 0;
+ virtual bool can_pass_through(const int x, const int y) const = 0;
+ virtual bool can_pass_through(const coord_def &c) const = 0;
virtual size_type body_size(int psize = PSIZE_TORSO,
bool base = false) const = 0;
+ virtual int body_weight() const = 0;
+ virtual int total_weight() const = 0;
virtual int damage_type(int which_attack = -1) = 0;
virtual int damage_brand(int which_attack = -1) = 0;
@@ -125,7 +134,9 @@ public:
virtual void confuse(int strength) = 0;
virtual void rot(actor *attacker, int rotlevel, int immediate_rot) = 0;
virtual void expose_to_element(beam_type element, int strength = 0) = 0;
- virtual void drain_stat(int stat, int amount) { }
+ virtual void drain_stat(int stat, int amount, actor* attacker) { }
+ virtual void put_to_sleep(int power = 0) { };
+ virtual void check_awaken(int disturbance) = 0;
virtual bool wearing_light_armour(bool = false) const { return (true); }
virtual int skill(skill_type sk, bool skill_bump = false) const
@@ -185,6 +196,10 @@ public:
{
return (true);
}
+
+ virtual bool will_trigger_shaft() const;
+ virtual level_id shaft_dest() const;
+ virtual bool do_shaft() = 0;
};
struct coord_def
@@ -326,6 +341,7 @@ struct delay_queue_item
int duration;
int parm1;
int parm2;
+ bool started;
};
@@ -350,6 +366,8 @@ struct item_def
std::string inscription;
+ CrawlHashTable props;
+
public:
item_def() : base_type(OBJ_UNASSIGNED), sub_type(0), plus(0), plus2(0),
special(0L), colour(0), flags(0L), quantity(0),
@@ -361,10 +379,14 @@ public:
std::string name(description_level_type descrip,
bool terse = false, bool ident = false,
bool with_inscription = true,
- bool quantity_in_words = false) const;
+ bool quantity_in_words = false,
+ unsigned long ignore_flags = 0x0) const;
bool has_spells() const;
bool cursed() const;
int book_number() const;
+ int zap() const; // what kind of beam it shoots (if wand).
+ // XXX should really return zap_type!
+
// Returns index in mitm array. Results are undefined if this item is
// not in the array!
@@ -380,7 +402,8 @@ public:
}
private:
std::string name_aux( description_level_type desc,
- bool terse, bool ident ) const;
+ bool terse, bool ident,
+ unsigned long ignore_flags ) const;
};
class runrest
@@ -475,18 +498,23 @@ typedef std::vector<delay_queue_item> delay_queue_type;
class KillMaster;
+
+
class player : public actor
{
public:
bool turn_is_over; // flag signaling that player has performed a timed action
-
+
// If true, player is headed to the Abyss.
bool banished;
std::string banished_by;
+ std::vector<int> beheld_by; // monsters beholding player
+
bool just_autoprayed; // autopray just kicked in
- unsigned char prev_targ;
+ unsigned short prev_targ;
+ coord_def prev_grd_targ;
char your_name[kNameLen];
species_type species;
@@ -575,7 +603,7 @@ public:
char spell_no;
game_direction_type char_direction;
- unsigned char pet_target;
+ unsigned short pet_target;
int your_level; // offset by one (-1 == 0, 0 == 1, etc.) for display
@@ -619,6 +647,9 @@ public:
level_area_type level_type;
std::string level_type_name;
+ entry_cause_type entry_cause;
+ god_type entry_cause_god;
+
branch_type where_are_you;
FixedVector<unsigned char, 30> branch_stairs;
@@ -726,11 +757,16 @@ public:
bool swimming() const;
bool submerged() const;
bool floundering() const;
+ bool can_pass_through(const dungeon_feature_type grid) const;
+ bool can_pass_through(const int x, const int y) const;
+ bool can_pass_through(const coord_def &c) const;
size_type body_size(int psize = PSIZE_TORSO, bool base = false) const;
+ int body_weight() const;
+ int total_weight() const;
int damage_type(int attk = -1);
int damage_brand(int attk = -1);
- bool has_claws() const;
- bool has_usable_claws() const;
+ int has_claws(bool allow_tran = true) const;
+ bool has_usable_claws(bool allow_tran = true) const;
item_def *weapon(int which_attack = -1);
item_def *shield();
@@ -749,7 +785,7 @@ public:
void banish(const std::string &who = "");
void blink();
void teleport(bool right_now = false, bool abyss_shift = false);
- void drain_stat(int stat, int amount);
+ void drain_stat(int stat, int amount, actor* attacker);
void expose_to_element(beam_type element, int strength = 0);
void god_conduct(conduct_type thing_done, int level);
@@ -776,8 +812,11 @@ public:
int res_elec() const;
int res_poison() const;
int res_negative_energy() const;
+ bool confusable() const;
+ bool slowable() const;
+
+ bool omnivorous() const;
- bool is_levitating() const;
flight_type flight_mode() const;
bool paralysed() const;
@@ -785,6 +824,13 @@ public:
bool caught() const;
bool backlit() const;
+ bool asleep() const;
+ void put_to_sleep(int power = 0);
+ void awake();
+ void check_awaken(int disturbance);
+
+ bool cannot_act() const;
+
bool can_throw_rocks() const;
int armour_class() const;
@@ -814,6 +860,8 @@ public:
// modify the player object.
std::vector<PlaceInfo> get_all_place_info(bool visited_only = false,
bool dungeon_only = false) const;
+
+ bool do_shaft();
};
extern player you;
@@ -841,7 +889,6 @@ public:
};
class ghost_demon;
-class level_id;
class mon_enchant
{
@@ -913,6 +960,7 @@ public:
mon_attitude_type attitude;
beh_type behaviour;
unsigned int foe;
+ char ench_countdown;
mon_enchant_list enchantments;
unsigned long flags; // bitfield of boolean flags
@@ -927,6 +975,9 @@ public:
std::auto_ptr<ghost_demon> ghost; // Ghost information.
+ std::string seen_context; // Non-standard context for
+ // AI_SEE_MONSTER
+
public:
void init_experience();
@@ -984,7 +1035,12 @@ public:
bool submerged() const;
bool can_drown() const;
bool floundering() const;
+ bool can_pass_through(const dungeon_feature_type grid) const;
+ bool can_pass_through(const int x, const int y) const;
+ bool can_pass_through(const coord_def &c) const;
size_type body_size(int psize = PSIZE_TORSO, bool base = false) const;
+ int body_weight() const;
+ int total_weight() const;
int damage_type(int attk = -1);
int damage_brand(int attk = -1);
@@ -1046,8 +1102,8 @@ public:
int res_poison() const;
int res_negative_energy() const;
- bool is_levitating() const;
flight_type flight_mode() const;
+ bool is_levitating() const;
bool invisible() const;
bool can_see_invisible() const;
bool visible_to(const actor *looker) const ;
@@ -1075,6 +1131,9 @@ public:
void blink();
void teleport(bool right_now = false, bool abyss_shift = false);
+ void put_to_sleep(int power = 0);
+ void check_awaken(int disturbance);
+
int stat_hp() const { return hit_points; }
int stat_maxhp() const { return max_hit_points; }
@@ -1092,6 +1151,8 @@ public:
static int base_speed(int mcls);
+ bool do_shaft();
+
private:
void init_with(const monsters &mons);
void swap_slots(mon_inv_type a, mon_inv_type b);
@@ -1123,6 +1184,7 @@ struct cloud_struct
int y;
cloud_type type;
int decay;
+ unsigned char spread_rate;
kill_category whose;
killer_type beam_thrower() const;
@@ -1178,6 +1240,8 @@ public:
map_marker *find(map_marker_type type);
void move(const coord_def &from, const coord_def &to);
std::vector<map_marker*> get_all(map_marker_type type = MAT_ANY);
+ std::vector<map_marker*> get_all(const std::string &key,
+ const std::string &val = "");
std::vector<map_marker*> get_markers_at(const coord_def &c);
std::string property_at(const coord_def &c, map_marker_type type,
const std::string &key);
@@ -1208,9 +1272,9 @@ public:
FixedVector< monsters, MAX_MONSTERS > mons; // monster list
feature_grid grid; // terrain grid
- FixedArray< unsigned char, GXM, GYM > mgrid; // monster grid
+ FixedArray< unsigned short, GXM, GYM > mgrid; // monster grid
FixedArray< int, GXM, GYM > igrid; // item grid
- FixedArray< unsigned char, GXM, GYM > cgrid; // cloud grid
+ FixedArray< unsigned short, GXM, GYM > cgrid; // cloud grid
FixedArray< unsigned short, GXM, GYM > grid_colours; // colour overrides
FixedArray< map_cell, GXM, GYM > map; // discovered terrain
@@ -1220,6 +1284,11 @@ public:
FixedArray<unsigned short, ENV_SHOW_DIAMETER, ENV_SHOW_DIAMETER>
show_col; // view window colour
+ // What would be visible, if all of the translucent wall were
+ // made opaque.
+ FixedArray<unsigned, ENV_SHOW_DIAMETER, ENV_SHOW_DIAMETER>
+ no_trans_show;
+
FixedVector< cloud_struct, MAX_CLOUDS > cloud; // cloud list
unsigned char cloud_no;
@@ -1233,6 +1302,10 @@ public:
// Number of turns the player has spent on this level.
int turns_on_level;
+
+ // Flags for things like preventing teleport control; see
+ // level_flag_type in enum.h
+ unsigned long level_flags;
};
extern struct crawl_environment env;
@@ -1294,6 +1367,7 @@ struct sound_mapping
struct colour_mapping
{
+ std::string tag;
text_pattern pattern;
int colour;
};
@@ -1401,6 +1475,8 @@ public:
bool messaging; // Check for messages.
#endif
+ bool suppress_startup_errors;
+
bool mouse_input;
int view_max_width;
@@ -1435,19 +1511,15 @@ public:
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_unequip; // allow auto-removing of armour / jewelry
bool easy_butcher; // open doors with movement
- bool increasing_skill_progress; // skills go from 0-10 or 10-0
- bool confirm_self_target; // require confirmation before selftarget
+ bool always_confirm_butcher; // even if only one corpse
bool default_target; // start targeting on a real target
- bool safe_autopickup; // don't autopickup when monsters visible
bool autopickup_no_burden; // don't autopickup if it changes burden
bool note_all_skill_levels; // take note for all skill levels (1-27)
bool note_skill_max; // take note when skills reach new max
bool note_all_spells; // take note when learning any spell
- bool use_notes; // take (and dump) notes
std::string user_note_prefix; // Prefix for user notes
int note_hp_percent; // percentage hp for notetaking
int ood_interesting; // how many levels OOD is noteworthy?
@@ -1466,7 +1538,6 @@ public:
int magic_point_warning; // percentage mp for danger warning
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 friend_brand; // Attribute for branding friendly monsters
bool no_dark_brand; // Attribute for branding friendly monsters
@@ -1479,7 +1550,6 @@ public:
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
char_set_type char_set;
FixedVector<unsigned, NUM_DCHAR_TYPES> char_table;
@@ -1570,7 +1640,6 @@ public:
std::vector<std::string> dump_order;
bool level_map_title; // Show title in level map
- bool safe_zero_exp; // If true, you feel safe around 0xp monsters
bool target_zero_exp; // If true, targeting targets zero-exp
// monsters.
bool target_wrap; // Wrap around from last to first target
diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc
index 4169a5a0d1..209947003f 100644
--- a/crawl-ref/source/fight.cc
+++ b/crawl-ref/source/fight.cc
@@ -76,6 +76,7 @@
#include "transfor.h"
#include "tutorial.h"
#include "view.h"
+#include "xom.h"
#define HIT_WEAK 7
#define HIT_MED 18
@@ -110,7 +111,7 @@ bool test_melee_hit(int to_hit, int ev)
if (to_hit >= AUTOMATIC_HIT)
return (true);
- else if (random2(1000) < 10 * MIN_HIT_MISS_PERCENTAGE)
+ else if (random2(100) < MIN_HIT_MISS_PERCENTAGE)
margin = (coinflip() ? 1 : -1) * AUTOMATIC_HIT;
else
{
@@ -122,12 +123,11 @@ bool test_melee_hit(int to_hit, int ev)
float miss;
if (to_hit < ev)
- miss = 100.0 - static_cast<float>( MIN_HIT_MISS_PERCENTAGE ) / 2.0;
+ miss = 100.0 - MIN_HIT_MISS_PERCENTAGE / 2.0;
else
{
- miss = static_cast<float>( MIN_HIT_MISS_PERCENTAGE ) / 2.0
- + static_cast<float>( (100 - MIN_HIT_MISS_PERCENTAGE) * ev )
- / static_cast<float>( to_hit );
+ miss = MIN_HIT_MISS_PERCENTAGE / 2.0 +
+ ((100.0 - MIN_HIT_MISS_PERCENTAGE) * ev) / to_hit;
}
mprf( MSGCH_DIAGNOSTICS,
@@ -175,7 +175,7 @@ static int calc_your_to_hit_unarmed(int uattack = UNAT_NO_ATTACK,
int your_to_hit;
your_to_hit = 13 + you.dex / 2 + you.skills[SK_UNARMED_COMBAT] / 2
- + you.skills[SK_FIGHTING] / 5;
+ + you.skills[SK_FIGHTING] / 5;
if (wearing_amulet(AMU_INACCURACY))
your_to_hit -= 5;
@@ -475,11 +475,79 @@ bool melee_attack::attack()
identify_mimic(atk);
identify_mimic(def);
+ // Xom thinks fumbles are funny...
if (attacker->fumbles_attack())
{
- xom_is_stimulated(14); // Xom thinks that is funny.
+ if (attacker->atype() == ACT_MONSTER)
+ {
+ // Make sure the monster uses up some energy, even though
+ // it didn't actually attack.
+ monsterentry *entry = get_monster_data(atk->type);
+ atk->speed_increment -= entry->energy_usage.attack;
+ }
+
+ // ... and thinks fumbling when trying to hit yourself is just
+ // hilarious.
+ if (attacker == defender)
+ xom_is_stimulated(255);
+ else
+ xom_is_stimulated(14);
return (false);
}
+ // Non-fumbled self-attacks due to confusion are still pretty
+ // funny, though.
+ else if (attacker == defender && attacker->confused())
+ {
+ // And is still hilarious if it's the player.
+ if (attacker->atype() == ACT_PLAYER)
+ xom_is_stimulated(255);
+ else
+ xom_is_stimulated(128);
+ }
+
+ // Defending monster protects itself from attacks using the
+ // wall it's in.
+ if (defender->atype() == ACT_MONSTER && grid_is_solid(def->pos())
+ && mons_class_flag(def->type, M_WALL_SHIELDED))
+ {
+ std::string feat_name = raw_feature_description(grd(def->pos()));
+
+ if (attacker->atype() == ACT_PLAYER)
+ {
+ player_apply_attack_delay();
+
+ if (you.can_see(def))
+ {
+ mprf("The %s protects %s from harm.",
+ feat_name.c_str(),
+ def->name(DESC_NOCAP_THE).c_str());
+ }
+ else
+ {
+ mprf("You hit the %s.",
+ feat_name.c_str());
+ }
+ }
+ else if (you.can_see(atk))
+ {
+ // Make sure the monster uses up some energy, even though
+ // it didn't actually land a blow.
+ monsterentry *entry = get_monster_data(atk->type);
+ atk->speed_increment -= entry->energy_usage.attack;
+
+ if (!mons_near(def))
+ simple_monster_message(atk, " hits something");
+ else if (!you.can_see(atk))
+ mprf("%s hits the %s.", def->name(DESC_CAP_THE).c_str(),
+ feat_name.c_str());
+ else
+ mprf("%s tries to hit the %s, but is blocked by the %s.",
+ atk->name(DESC_CAP_THE).c_str(),
+ def->name(DESC_NOCAP_THE).c_str(),
+ feat_name.c_str());
+ }
+ return (true);
+ }
// Allow god to get offended, etc.
attacker->attacking(defender);
@@ -520,9 +588,16 @@ bool melee_attack::player_attack()
if (Options.tutorial_left)
Options.tut_melee_counter++;
- // This actually does more than calculate damage - it also sets up
- // messages, etc.
- player_calc_hit_damage();
+ const bool shield_blocked = attack_shield_blocked(true);
+
+ if (shield_blocked)
+ damage_done = 0;
+ else
+ {
+ // This actually does more than calculate damage - it also sets up
+ // messages, etc.
+ player_calc_hit_damage();
+ }
bool hit_woke_orc = false;
if (you.religion == GOD_BEOGH && mons_species(def->type) == MONS_ORC
@@ -539,7 +614,7 @@ bool melee_attack::player_attack()
if (damage_done > 0 || !defender_visible)
player_announce_hit();
- else if (damage_done <= 0)
+ else if (!shield_blocked && damage_done <= 0)
no_damage_message =
make_stringf("You %s %s.",
attack_verb.c_str(),
@@ -559,6 +634,10 @@ bool melee_attack::player_attack()
}
player_sustain_passive_damage();
+
+ // At this point, pretend we didn't hit at all.
+ if (shield_blocked)
+ did_hit = false;
}
else
player_warn_miss();
@@ -632,7 +711,7 @@ bool melee_attack::player_aux_unarmed()
{
if (uattack != UNAT_KICK) //jmf: hooves mutation
{
- if (you.species != SP_KENKU && !you.mutation[MUT_HOOVES]
+ if (!you.mutation[MUT_HOOVES] && !you.mutation[MUT_TALONS]
|| coinflip())
{
continue;
@@ -649,8 +728,7 @@ bool melee_attack::player_aux_unarmed()
}
// Kenku have large taloned feet that do good damage.
- const bool clawed_kick =
- you.species == SP_KENKU && !you.mutation[MUT_HOOVES];
+ const bool clawed_kick = you.mutation[MUT_TALONS];
if (clawed_kick)
{
@@ -830,6 +908,8 @@ bool melee_attack::player_aux_unarmed()
did_hit = false;
if (to_hit >= def->ev || one_chance_in(30))
{
+ if (attack_shield_blocked(true))
+ continue;
if (player_apply_aux_unarmed())
return (true);
}
@@ -1460,12 +1540,8 @@ void melee_attack::player_exercise_combat_skills()
}
}
-// Returns true if the combat round should end here.
-bool melee_attack::player_monattk_hit_effects(bool mondied)
+void melee_attack::player_check_weapon_effects()
{
- if (mons_holiness(def) == MH_HOLY)
- did_god_conduct(mondied? DID_KILL_ANGEL : DID_ATTACK_HOLY, 1);
-
if (spwld == SPWLD_TORMENT && coinflip())
{
torment(TORMENT_SPWLD, you.x_pos, you.y_pos);
@@ -1475,11 +1551,63 @@ bool melee_attack::player_monattk_hit_effects(bool mondied)
if (spwld == SPWLD_ZONGULDROK || spwld == SPWLD_CURSE)
did_god_conduct(DID_NECROMANCY, 3);
- if (weapon
- && weapon->base_type == OBJ_WEAPONS
- && is_demonic( *weapon ))
+ if (weapon)
+ {
+ if (weapon->base_type == OBJ_WEAPONS
+ && is_demonic( *weapon ))
+ {
+ did_god_conduct(DID_UNHOLY, 1);
+ }
+
+ if (is_fixed_artefact(*weapon))
+ {
+ switch (weapon->special)
+ {
+ case SPWPN_SCEPTRE_OF_ASMODEUS:
+ case SPWPN_STAFF_OF_DISPATER:
+ case SPWPN_SWORD_OF_CEREBOV:
+ did_god_conduct(DID_UNHOLY, 3);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+// Returns true if the combat round should end here.
+bool melee_attack::player_monattk_hit_effects(bool mondied)
+{
+ if (mons_holiness(def) == MH_HOLY)
+ did_god_conduct(mondied? DID_KILL_ANGEL : DID_ATTACK_HOLY, 1);
+
+ player_check_weapon_effects();
+
+ // Vampiric effects for the killing blow.
+ if (mondied && damage_brand == SPWPN_VAMPIRICISM)
{
- did_god_conduct(DID_UNHOLY, 1);
+ if (defender->holiness() == MH_NATURAL
+ && damage_done > 0
+ && you.hp < you.hp_max
+ && !one_chance_in(5))
+ {
+ mpr("You feel better.");
+
+ // more than if not killed
+ const int heal = 1 + random2(damage_done);
+
+#ifdef DEBUG_DIAGNOSTICS
+ mprf(MSGCH_DIAGNOSTICS,
+ "Vampiric healing: damage %d, healed %d",
+ damage_done, heal);
+#endif
+ inc_hp(heal, false);
+
+ if (you.hunger_state != HS_ENGORGED)
+ lessen_hunger(30 + random2avg(59, 2), true);
+
+ did_god_conduct(DID_NECROMANCY, 2);
+ }
}
// Vampiric effects for the killing blow.
@@ -2820,8 +2948,8 @@ bool melee_attack::attack_shield_blocked(bool verbose)
pro_block /= 3;
#ifdef DEBUG_DIAGNOSTICS
- mprf(MSGCH_DIAGNOSTICS, "Pro-block: %d, Con-block: %d",
- pro_block, con_block);
+ mprf(MSGCH_DIAGNOSTICS, "Defender: %s, Pro-block: %d, Con-block: %d",
+ def_name(DESC_PLAIN).c_str(), pro_block, con_block);
#endif
if (pro_block >= con_block)
@@ -2893,6 +3021,17 @@ int melee_attack::mons_calc_damage(const mon_attack_def &attk)
if (water_attack)
damage *= 2;
+ // If the defender is asleep, the attacker gets a stab.
+ if (defender && defender->asleep())
+ {
+ damage = damage * 5 / 2;
+#ifdef DEBUG_DIAGNOSTICS
+ mprf(MSGCH_DIAGNOSTICS, "Stab damage vs %s: %d",
+ defender->name(DESC_PLAIN).c_str(),
+ damage);
+#endif
+ }
+
return (mons_apply_defender_ac(damage, damage_max));
}
@@ -2952,8 +3091,9 @@ std::string melee_attack::mons_attack_verb(const mon_attack_def &attk)
std::string melee_attack::mons_weapon_desc()
{
- if (!player_monster_visible(atk))
- return("");
+ if (!you.can_see(attacker))
+ return ("");
+
if (weapon && attacker->id() != MONS_DANCING_WEAPON)
{
std::string result = "";
@@ -3137,7 +3277,7 @@ void melee_attack::mons_apply_attack_flavour(const mon_attack_def &attk)
{
defender->poison( attacker, roll_dice(1,3) );
if (one_chance_in(4))
- defender->drain_stat( STAT_STRENGTH, 1 );
+ defender->drain_stat( STAT_STRENGTH, 1, attacker );
}
break;
@@ -3229,7 +3369,7 @@ void melee_attack::mons_apply_attack_flavour(const mon_attack_def &attk)
if ((one_chance_in(20) || (damage_done > 0 && one_chance_in(3)))
&& defender->res_negative_energy() < random2(4))
{
- defender->drain_stat(STAT_STRENGTH, 1);
+ defender->drain_stat(STAT_STRENGTH, 1, attacker);
}
break;
@@ -3237,7 +3377,7 @@ void melee_attack::mons_apply_attack_flavour(const mon_attack_def &attk)
if ((one_chance_in(20) || (damage_done > 0 && one_chance_in(3)))
&& defender->res_negative_energy() < random2(4))
{
- defender->drain_stat(STAT_DEXTERITY, 1);
+ defender->drain_stat(STAT_DEXTERITY, 1, attacker);
}
break;
@@ -3331,7 +3471,7 @@ void melee_attack::mons_perform_attack_rounds()
// Melee combat, tell attacker to wield its melee weapon.
atk->wield_melee_weapon();
-
+
for (attack_number = 0; attack_number < nrounds; ++attack_number)
{
// Monster went away?
@@ -3344,7 +3484,17 @@ void melee_attack::mons_perform_attack_rounds()
const mon_attack_def attk = mons_attack_spec(atk, attack_number);
if (attk.type == AT_NONE)
+ {
+ if (attack_number == 0)
+ {
+ // Make sure the monster uses up some energy, even
+ // though it didn't actually attack.
+ monsterentry *entry = get_monster_data(atk->type);
+ atk->speed_increment -= entry->energy_usage.attack;
+ }
+
break;
+ }
if (attk.type == AT_SHOOT)
continue;
@@ -3537,8 +3687,16 @@ bool you_attack(int monster_attacked, bool unarmed_attacks)
static void mons_lose_attack_energy(monsters *attacker, int wpn_speed,
int which_attack)
{
- // Monsters lose energy only for the first two weapon attacks; subsequent
- // hits are free.
+ monsterentry *entry = get_monster_data(attacker->type);
+ char atk_speed = entry->energy_usage.attack;
+
+ // Initial attack causes energy to be used for all attacks. No
+ // additional energy is used for unarmed attacks.
+ if (which_attack == 0)
+ attacker->speed_increment -= atk_speed;
+
+ // Monsters lose additional energy only for the first two weapon
+ // attacks; subsequent hits are free.
if (which_attack > 1)
return;
@@ -3547,21 +3705,26 @@ static void mons_lose_attack_energy(monsters *attacker, int wpn_speed,
{
// only get one third penalty/bonus for second weapons.
if (which_attack > 0)
- wpn_speed = (20 + wpn_speed) / 3;
+ wpn_speed = div_rand_round( (2 * atk_speed + wpn_speed), 3 );
+
+ int delta = div_rand_round( (wpn_speed - 10 + (atk_speed - 10)), 2 );
- attacker->speed_increment -= (wpn_speed - 10) / 2;
+ if (delta > 0)
+ attacker->speed_increment -= delta;
}
}
-void monster_attack(int monster_attacking)
+bool monster_attack(int monster_attacking)
{
monsters *attacker = &menv[monster_attacking];
if (mons_friendly(attacker) && !mons_is_confused(attacker))
- return;
+ return false;
melee_attack attk(attacker, &you);
attk.attack();
+
+ return true;
} // end monster_attack()
bool monsters_fight(int monster_attacking, int monster_attacked)
@@ -3600,7 +3763,7 @@ int weapon_str_weight( object_class_type wpn_class, int wpn_type )
// - 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 spit; bastard swords are in between.
+ // 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
@@ -3708,12 +3871,10 @@ static inline int calc_stat_to_dam_base( void )
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)
+ if (coinflip())
{
mprf( "You strike %s from a blind spot!",
defender->name(DESC_NOCAP_THE).c_str() );
@@ -3725,7 +3886,7 @@ static void stab_message( struct monsters *defender, int stab_bonus )
}
break;
case 2: // confused/fleeing
- if (r<4)
+ if ( !one_chance_in(3) )
{
mprf( "You catch %s completely off-guard!",
defender->name(DESC_NOCAP_THE).c_str() );
@@ -3741,5 +3902,5 @@ static void stab_message( struct monsters *defender, int stab_bonus )
defender->name(DESC_CAP_THE).c_str(),
defender->pronoun(PRONOUN_REFLEXIVE).c_str() );
break;
- } // end switch
+ }
}
diff --git a/crawl-ref/source/fight.h b/crawl-ref/source/fight.h
index e4d25eda9f..03984b03b9 100644
--- a/crawl-ref/source/fight.h
+++ b/crawl-ref/source/fight.h
@@ -54,7 +54,7 @@ bool you_attack(int monster_attacked, bool unarmed_attacks);
/* ***********************************************************************
* called from: monstuff
* *********************************************************************** */
-void monster_attack(int monster_attacking);
+bool monster_attack(int monster_attacking);
// last updated: 08jun2000 {dlb}
@@ -242,6 +242,7 @@ private:
void player_announce_hit();
std::string player_why_missed();
void player_warn_miss();
+ void player_check_weapon_effects();
};
#endif
diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc
index 48885321ad..a29d09ae6f 100644
--- a/crawl-ref/source/files.cc
+++ b/crawl-ref/source/files.cc
@@ -78,6 +78,7 @@
#include "mtransit.h"
#include "notes.h"
#include "output.h"
+#include "overmap.h"
#include "place.h"
#include "player.h"
#include "randart.h"
@@ -90,6 +91,7 @@
#include "travel.h"
#include "tutorial.h"
#include "view.h"
+#include "xom.h"
void save_level(int level_saved, level_area_type lt,
branch_type where_were_you);
@@ -864,6 +866,36 @@ static void grab_followers()
}
}
+// Should be called after grab_followers(), so that items carried by
+// followers won't be considered lost.
+static void do_lost_items(level_area_type old_level_type)
+{
+ if (old_level_type == LEVEL_DUNGEON)
+ return;
+
+ for (int i = 0; i < MAX_ITEMS; i++)
+ {
+ item_def& item(mitm[i]);
+
+ if (!is_valid_item(item))
+ continue;
+
+ // Item is in player intentory, so it's not lost.
+ if (item.x == -1 && item.y == -1)
+ continue;
+
+ item_was_lost(item);
+ }
+
+ // Clear flags on the followers that didn't make it.
+ for (int i = 0; i < MAX_MONSTERS; ++i)
+ {
+ monsters *mons = &menv[i];
+ if (!mons->alive())
+ continue;
+ mons->flags &= ~MF_TAKING_STAIRS;
+ }
+}
bool load( dungeon_feature_type stair_taken, int load_mode,
level_area_type old_level_type, char old_level,
@@ -893,7 +925,8 @@ bool load( dungeon_feature_type stair_taken, int load_mode,
}
}
- you.prev_targ = MHITNOT;
+ you.prev_targ = MHITNOT;
+ you.prev_grd_targ = coord_def(0, 0);
// We clear twice - on save and on load.
// Once would be enough...
@@ -912,12 +945,15 @@ bool load( dungeon_feature_type stair_taken, int load_mode,
save_level( old_level, LEVEL_DUNGEON, where_were_you2 );
}
+ do_lost_items(old_level_type);
+
// Try to open level savefile.
FILE *levelFile = fopen(cha_fil.c_str(), "rb");
// GENERATE new level when the file can't be opened:
if (levelFile == NULL)
{
+ env.turns_on_level = -1;
builder( you.your_level, you.level_type );
just_created_level = true;
@@ -1044,6 +1080,19 @@ bool load( dungeon_feature_type stair_taken, int load_mode,
setup_environment_effects();
+ // Inform user of level's annotation.
+ if (get_level_annotation().length() > 0
+ && !crawl_state.level_annotation_shown)
+ {
+ char buf[200];
+
+ sprintf(buf, "Level annotation: %s\n",
+ get_level_annotation().c_str() );
+ mpr(buf, MSGCH_PLAIN, YELLOW);
+ }
+
+ crawl_state.level_annotation_shown = false;
+
if (load_mode != LOAD_RESTART_GAME)
{
// Update PlaceInfo entries
@@ -1066,6 +1115,11 @@ bool load( dungeon_feature_type stair_taken, int load_mode,
curr_PlaceInfo.assert_validity();
}
+ if (just_created_level)
+ you.attribute[ATTR_ABYSS_ENTOURAGE] = 0;
+
+ dungeon_events.fire_event(DET_ENTERED_LEVEL);
+
return just_created_level;
} // end load()
@@ -1076,7 +1130,8 @@ void save_level(int level_saved, level_area_type old_ltype,
where_were_you, old_ltype,
false );
- you.prev_targ = MHITNOT;
+ you.prev_targ = MHITNOT;
+ you.prev_grd_targ = coord_def(0, 0);
FILE *saveFile = fopen(cha_fil.c_str(), "wb");
diff --git a/crawl-ref/source/food.cc b/crawl-ref/source/food.cc
index 1dc360886b..63866f3099 100644
--- a/crawl-ref/source/food.cc
+++ b/crawl-ref/source/food.cc
@@ -14,6 +14,8 @@
#include "AppHdr.h"
#include "food.h"
+#include <sstream>
+
#include <string.h>
// required for abs() {dlb}:
#include <stdlib.h>
@@ -46,13 +48,14 @@
#include "religion.h"
#include "skills2.h"
#include "spells2.h"
+#include "state.h"
#include "stuff.h"
#include "transfor.h"
#include "tutorial.h"
+#include "xom.h"
static int determine_chunk_effect(int which_chunk_type, bool rotten_chunk);
-static void eat_chunk( int chunk_effect );
-static void ghoul_consume_flesh(int chunk_type);
+static void eat_chunk( int chunk_effect, bool cannibal );
static void eating(unsigned char item_class, int item_type);
static void describe_food_change(int hunger_increment);
static bool food_change(bool suppress_message);
@@ -191,9 +194,8 @@ static bool find_butchering_implement( bool fallback )
return (you.equip[EQ_WEAPON] != old_weapon);
}
-bool butchery(void)
+bool butchery()
{
- bool wpn_switch = false;
bool new_cursed = false;
int old_weapon = you.equip[EQ_WEAPON];
int old_gloves = you.equip[EQ_GLOVES];
@@ -241,30 +243,59 @@ bool butchery(void)
return (false);
}
- bool canceled_butcher = false;
- bool found_nonzero_corpses = false;
- for (int objl = igrd[you.x_pos][you.y_pos]; objl != NON_ITEM;
- objl = mitm[objl].link)
+ // First determine how many things there are to butcher.
+ int num_corpses = 0;
+ int corpse_id = -1;
+ for (int o = igrd[you.x_pos][you.y_pos]; o != NON_ITEM; o = mitm[o].link)
{
- if ( (mitm[objl].base_type != OBJ_CORPSES) ||
- (mitm[objl].sub_type != CORPSE_BODY) )
- continue;
-
- found_nonzero_corpses = true;
-
- // offer the possibility of butchering
- snprintf(info, INFO_SIZE, "Butcher %s?",
- mitm[objl].name(DESC_NOCAP_A).c_str());
- const int answer = yesnoquit( info, true, 'n', false );
- if ( answer == -1 )
+ if (mitm[o].base_type == OBJ_CORPSES &&
+ mitm[o].sub_type == CORPSE_BODY)
{
- canceled_butcher = true;
- break;
+ corpse_id = o;
+ num_corpses++;
}
- if ( answer == 0 )
- continue;
+ }
+
+ bool canceled_butcher = false;
+ // Now pick what you want to butcher. This is only a problem
+ // if there are several corpses on the square.
+ if ( num_corpses == 0 )
+ {
+ mpr("There isn't anything to dissect here.");
+ return false;
+ }
+ else if ( num_corpses > 1 || Options.always_confirm_butcher )
+ {
+ corpse_id = -1;
+ for (int o=igrd[you.x_pos][you.y_pos]; o != NON_ITEM; o = mitm[o].link)
+ {
+ if ( (mitm[o].base_type != OBJ_CORPSES) ||
+ (mitm[o].sub_type != CORPSE_BODY) )
+ continue;
+
+ // offer the possibility of butchering
+ std::string prompt = "Butcher " + mitm[o].name(DESC_NOCAP_A) + '?';
+ const int answer = yesnoquit( prompt.c_str(), true, 'n', false );
+ if ( answer == 1 )
+ {
+ corpse_id = o;
+ break;
+ }
+ else if ( answer == -1 )
+ {
+ canceled_butcher = true;
+ corpse_id = -1;
+ break;
+ }
+ }
+ }
+
+ // Do the actual butchery, if we found a good corpse.
+ if ( corpse_id != -1 )
+ {
bool removed_gloves = false;
+ bool wpn_switch = false;
if ( Options.easy_butcher && !can_butcher )
{
@@ -317,41 +348,35 @@ bool butchery(void)
if ( can_butcher )
{
- // we actually butcher now
- if ( teeth_butcher || barehand_butcher )
- mpr("You start tearing the corpse apart.");
- else
- mpr("You start hacking away.");
-
- bool rotten = (mitm[objl].special < 100);
+ bool rotten = (mitm[corpse_id].special < 100);
if (you.duration[DUR_PRAYER] && !rotten &&
god_likes_butchery(you.religion))
{
- offer_corpse(objl);
- destroy_item(objl);
+ offer_corpse(corpse_id);
+ destroy_item(corpse_id);
}
else
{
if (you.duration[DUR_PRAYER] && rotten
&& god_likes_butchery(you.religion) )
{
- if (coinflip())
- simple_god_message(" refuses to accept that mouldy "
- "sacrifice!", you.religion);
- else
- simple_god_message(" demands fresh blood!", you.religion);
+ simple_god_message(coinflip() ?
+ " refuses to accept that mouldy "
+ "sacrifice!" :
+ " demands fresh blood!", you.religion);
}
// If we didn't switch weapons, we get in one turn of butchery;
// otherwise the work has to happen in the delay.
if (!wpn_switch && !removed_gloves)
- ++mitm[objl].plus2;
+ ++mitm[corpse_id].plus2;
- int work_req = 4 - mitm[objl].plus2;
+ int work_req = 4 - mitm[corpse_id].plus2;
if (work_req < 0)
work_req = 0;
- start_delay(DELAY_BUTCHER, work_req, objl, mitm[objl].special);
+ start_delay(DELAY_BUTCHER, work_req, corpse_id,
+ mitm[corpse_id].special);
if (you.duration[DUR_PRAYER]
&& god_hates_butchery(you.religion))
@@ -376,14 +401,8 @@ bool butchery(void)
if (canceled_butcher)
canned_msg(MSG_OK);
else
- mprf("There isn't anything %sto dissect here.",
- found_nonzero_corpses? "else " : "");
+ mpr("There isn't anything else to dissect here.");
- if (!new_cursed && wpn_switch) // should never happen
- {
- weapon_switch( old_weapon );
- }
-
return false;
} // end butchery()
@@ -491,24 +510,31 @@ bool eat_food(bool run_hook)
if (you.is_undead == US_UNDEAD)
{
mpr("You can't eat.");
+ crawl_state.zero_turns_taken();
return (false);
}
if (you.hunger >= 11000)
{
mpr("You're too full to eat anything.");
+ crawl_state.zero_turns_taken();
return (false);
}
// If user hook ran, we don't know whether something
// was eaten or not...
if (run_hook && userdef_eat_food())
+ {
return (false);
+ }
if (igrd[you.x_pos][you.y_pos] != NON_ITEM)
{
- if (eat_from_floor())
- return (true);
+ const int res = eat_from_floor();
+ if ( res == 1 )
+ return true;
+ if ( res == -1 )
+ return false;
}
return (prompt_eat_from_inventory());
@@ -573,6 +599,7 @@ static bool food_change(bool suppress_message)
case HS_STARVING:
mpr("You are starving!", MSGCH_FOOD);
learned_something_new(TUT_YOU_STARVING);
+ you.check_awaken(500);
break;
case HS_HUNGRY:
mpr("You are feeling hungry.", MSGCH_FOOD);
@@ -625,9 +652,7 @@ static void describe_food_change(int food_increment)
static bool prompt_eat_chunk(const item_def &item, bool rotten)
{
- if (rotten && you.species != SP_GHOUL && you.species != SP_KOBOLD
- && you.species != SP_TROLL && you.species != SP_OGRE
- && you.species != SP_HILL_ORC
+ if (rotten && !you.mutation[MUT_SAPROVOROUS]
&& !yesno("Are you sure you want to eat this rotten meat?",
false, 'n'))
{
@@ -668,13 +693,14 @@ void eat_from_inventory(int which_inventory_slot)
// 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 bool cannibal = is_player_same_species(mons_type);
const int chunk_type = mons_corpse_effect( mons_type );
const bool rotten = (you.inv[which_inventory_slot].special < 100);
if (!prompt_eat_chunk(you.inv[which_inventory_slot], rotten))
return;
- eat_chunk( determine_chunk_effect( chunk_type, rotten ) );
+ eat_chunk( determine_chunk_effect( chunk_type, rotten ), cannibal );
}
else
{
@@ -716,10 +742,11 @@ void eat_floor_item(int item_link)
else if (mitm[item_link].sub_type == FOOD_CHUNK)
{
const int chunk_type = mons_corpse_effect( mitm[item_link].plus );
+ const bool cannibal = is_player_same_species( mitm[item_link].plus );
const bool rotten = (mitm[item_link].special < 100);
if (!prompt_eat_chunk(mitm[item_link], rotten))
return;
- eat_chunk( determine_chunk_effect( chunk_type, rotten ) );
+ eat_chunk( determine_chunk_effect( chunk_type, rotten ), cannibal );
}
else
{
@@ -731,10 +758,11 @@ void eat_floor_item(int item_link)
dec_mitm_item_quantity( item_link, 1 );
}
-bool eat_from_floor(void)
+// return -1 for cancel, 1 for eaten, 0 for not eaten
+int eat_from_floor()
{
if (you.flight_mode() == FL_LEVITATE)
- return (false);
+ return 0;
bool need_more = false;
for (int o = igrd[you.x_pos][you.y_pos]; o != NON_ITEM; o = mitm[o].link)
@@ -748,37 +776,21 @@ bool eat_from_floor(void)
(item.base_type != OBJ_CORPSES || item.sub_type != CORPSE_BODY))
continue;
- mprf( MSGCH_PROMPT,
- "%s %s%s?", you.species == SP_VAMPIRE ? "Drink blood from" : "Eat",
- (item.quantity > 1) ? "one of " : "",
- item.name(DESC_NOCAP_A).c_str() );
-
- // If we're prompting now, we don't need a -more- when
- // breaking out, because the prompt serves as a -more-. Of
- // course, the prompt can re-set need_more to true.
- need_more = false;
-
- unsigned char keyin = tolower( getch() );
-
- if (keyin == 0)
- {
- getch();
- keyin = 0;
- }
-
- if (keyin == 'q')
- return (false);
-
- if (keyin == 'y')
+ std::ostringstream prompt;
+ prompt << (you.species == SP_VAMPIRE ? "Drink blood from" : "Eat")
+ << ' ' << ((item.quantity > 1) ? "one of " : "")
+ << item.name(DESC_NOCAP_A) << '?';
+ const int ans = yesnoquit( prompt.str().c_str(), true, 0, false );
+ if ( ans == -1 ) // quit
+ return -1;
+ else if ( ans == 1 )
{
- if (!can_ingest( item.base_type, item.sub_type, false ))
+ if (can_ingest(item.base_type, item.sub_type, false))
{
- need_more = true;
- continue;
+ eat_floor_item(o);
+ return 1;
}
-
- eat_floor_item(o);
- return (true);
+ need_more = true;
}
}
@@ -867,90 +879,99 @@ static void say_chunk_flavour(bool likes_chunks)
// never called directly - chunk_effect values must pass
// through food::determine_chunk_effect() first {dlb}:
-static void eat_chunk( int chunk_effect )
+static void eat_chunk( int chunk_effect, bool cannibal )
{
- bool likes_chunks = (you.species == SP_OGRE || you.species == SP_TROLL ||
- you.mutation[MUT_CARNIVOROUS] > 0);
+ bool likes_chunks = (you.omnivorous() ||
+ you.mutation[MUT_CARNIVOROUS]);
+ int nutrition = chunk_nutrition(likes_chunks);
+ int hp_amt = 0;
+ bool suppress_msg = false; // do we display the chunk nutrition message?
+ bool do_eat = false;
if (you.species == SP_GHOUL)
{
- ghoul_consume_flesh(chunk_effect);
- start_delay( DELAY_EAT, 2 );
- lessen_hunger( CHUNK_BASE_NUTRITION, true );
+ nutrition = CHUNK_BASE_NUTRITION;
+ hp_amt = 1 + random2(5) + random2(1 + you.experience_level);
+ suppress_msg = true;
}
- else
+
+ switch (chunk_effect)
{
- switch (chunk_effect)
- {
- case CE_MUTAGEN_RANDOM:
- mpr("This meat tastes really weird.");
- mutate(RANDOM_MUTATION);
- xom_is_stimulated(100);
- break;
+ case CE_MUTAGEN_RANDOM:
+ mpr("This meat tastes really weird.");
+ mutate(RANDOM_MUTATION);
+ xom_is_stimulated(100);
+ break;
- case CE_MUTAGEN_BAD:
- mpr("This meat tastes *really* weird.");
- give_bad_mutation();
- xom_is_stimulated(random2(200));
- break;
+ case CE_MUTAGEN_BAD:
+ mpr("This meat tastes *really* weird.");
+ give_bad_mutation();
+ xom_is_stimulated(random2(200));
+ break;
- case CE_HCL:
- rot_player( 10 + random2(10) );
- if (disease_player( 50 + random2(100) ))
- xom_is_stimulated(random2(100));
- break;
+ case CE_HCL:
+ rot_player( 10 + random2(10) );
+ if (disease_player( 50 + random2(100) ))
+ xom_is_stimulated(random2(100));
+ break;
- case CE_POISONOUS:
- mpr("Yeeuch - this meat is poisonous!");
- if (poison_player( 3 + random2(4) ))
- xom_is_stimulated(random2(128));
- break;
+ case CE_POISONOUS:
+ mpr("Yeeuch - this meat is poisonous!");
+ if (poison_player( 3 + random2(4) ))
+ xom_is_stimulated(random2(128));
+ break;
- case CE_ROTTEN:
- case CE_CONTAMINATED:
+ case CE_ROTTEN:
+ case CE_CONTAMINATED:
+ if (you.mutation[MUT_SAPROVOROUS] == 3)
+ {
+ mprf("This %sflesh tastes delicious!",
+ (chunk_effect == CE_ROTTEN) ? "rotting " : "");
+
+ if (you.species == SP_GHOUL)
+ heal_from_food(hp_amt, 0, !one_chance_in(4),
+ one_chance_in(5));
+
+ do_eat = true;
+ }
+ else
+ {
mpr("There is something wrong with this meat.");
if (disease_player( 50 + random2(100) ))
xom_is_stimulated(random2(100));
- break;
+ }
+ break;
- // note that this is the only case that takes time and forces redraw
- case CE_CLEAN:
+ case CE_CLEAN:
+ {
+ if (you.mutation[MUT_SAPROVOROUS] == 3)
{
- say_chunk_flavour(likes_chunks);
- const int nutrition = chunk_nutrition(likes_chunks);
- start_delay( DELAY_EAT, 2, nutrition );
- lessen_hunger( nutrition, true );
- break;
- }
- }
- }
+ mpr("This raw flesh tastes good.");
- return;
-} // end eat_chunk()
+ if (you.species == SP_GHOUL)
+ heal_from_food((!one_chance_in(5)) ? hp_amt : 0, 0,
+ !one_chance_in(3), false);
+ }
+ else
+ say_chunk_flavour(likes_chunks);
-static void ghoul_consume_flesh(int chunk_type)
-{
- int hp_amt = 1 + random2(5) + random2(1 + you.experience_level);
+ do_eat = true;
+ break;
+ }
+ }
- if (chunk_type != CE_ROTTEN && chunk_type != CE_CONTAMINATED)
+ if (cannibal)
+ did_god_conduct( DID_CANNIBALISM, 10 );
+
+ if (do_eat)
{
- mpr("This raw flesh tastes good.");
-
- heal_from_food((!one_chance_in(5)) ? hp_amt : 0, 0,
- !one_chance_in(3), false);
+ start_delay( DELAY_EAT, 2, (suppress_msg) ? 0 : nutrition );
+ lessen_hunger( nutrition, true );
}
- else
- {
- if (chunk_type == CE_ROTTEN)
- mpr("This rotting flesh tastes delicious!");
- else // CE_CONTAMINATED or CE_HCL
- mpr("This flesh tastes delicious!");
- heal_from_food(hp_amt, 0,
- !one_chance_in(4), one_chance_in(5));
- }
-} // end ghoul_consume_flesh()
+ return;
+} // end eat_chunk()
static void eating(unsigned char item_class, int item_type)
{
@@ -1258,8 +1279,7 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, bool reqid,
bool ur_chunkslover = (
(check_hunger? you.hunger_state <= HS_HUNGRY : true)
|| wearing_amulet(AMU_THE_GOURMAND, !reqid)
- || you.species == SP_OGRE
- || you.species == SP_TROLL
+ || you.omnivorous()
|| you.mutation[MUT_CARNIVOROUS]);
switch (what_isit)
@@ -1390,7 +1410,6 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, bool reqid,
// understood why liches are hungry and not true undead beings ... {dlb}:
static int determine_chunk_effect(int which_chunk_type, bool rotten_chunk)
{
- const int poison_resistance_level = player_res_poison();
int this_chunk_effect = which_chunk_type;
// determine the initial effect of eating a particular chunk {dlb}:
@@ -1406,36 +1425,36 @@ static int determine_chunk_effect(int which_chunk_type, bool rotten_chunk)
break;
case CE_POISONOUS:
- if (you.species == SP_GHOUL
- || you.attribute[ATTR_TRANSFORMATION] == TRAN_LICH
- || poison_resistance_level > 0 && you.species != SP_VAMPIRE)
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_LICH
+ || player_res_poison() > 0 && you.species != SP_VAMPIRE)
{
this_chunk_effect = CE_CLEAN;
}
break;
case CE_CONTAMINATED:
- if (you.attribute[ATTR_TRANSFORMATION] == TRAN_LICH)
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_LICH
+ && you.mutation[MUT_SAPROVOROUS] < 3)
+ {
this_chunk_effect = CE_CLEAN;
+ }
else
{
- switch (you.species)
+ switch (you.mutation[MUT_SAPROVOROUS])
{
- case SP_GHOUL:
- // Doing this here causes a odd message later. -- bwr
- // this_chunk_effect = CE_ROTTEN;
+ case 1:
+ if (!one_chance_in(15))
+ this_chunk_effect = CE_CLEAN;
break;
- case SP_KOBOLD:
- case SP_TROLL:
+ case 2:
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;
+ case 3:
+ // Doing this here causes a odd message later. -- bwr
+ // this_chunk_effect = CE_ROTTEN;
break;
default:
@@ -1470,38 +1489,41 @@ static int determine_chunk_effect(int which_chunk_type, bool rotten_chunk)
// 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)
+ if (you.attribute[ATTR_TRANSFORMATION] == TRAN_LICH
+ && you.mutation[MUT_SAPROVOROUS] < 3)
+ {
this_chunk_effect = CE_CLEAN;
+ }
else
{
- switch (you.species)
+ switch (you.mutation[MUT_SAPROVOROUS])
{
- case SP_KOBOLD:
- case SP_TROLL:
- if (!one_chance_in(15))
+ case 1:
+ if (!one_chance_in(5))
this_chunk_effect = CE_CLEAN;
break;
- case SP_HILL_ORC:
- case SP_OGRE:
- if (!one_chance_in(5))
+
+ case 2:
+ if (!one_chance_in(15))
this_chunk_effect = CE_CLEAN;
break;
+
default:
break;
}
}
}
- // the amulet of the gourmad will permit consumption of
- // contaminated meat as though it were "clean" meat - ghouls get
- // rotting meat effect from clean chunks, since they love rotting
- // meat.
+ // The amulet of the gourmand will permit consumption of
+ // contaminated meat as though it were "clean" meat - level 3
+ // saprovores get rotting meat effect from clean chunks, since they
+ // love rotting meat.
if (wearing_amulet(AMU_THE_GOURMAND)
&& random2(GOURMAND_MAX) < you.duration[DUR_GOURMAND])
{
- if (you.species == SP_GHOUL)
+ if (you.mutation[MUT_SAPROVOROUS] == 3)
{
- // [dshaligram] Ghouls relish contaminated meat.
+ // [dshaligram] Level 3 saprovores relish contaminated meat.
if (this_chunk_effect == CE_CLEAN)
this_chunk_effect = CE_CONTAMINATED;
}
@@ -1574,7 +1596,7 @@ static bool vampire_consume_corpse(int mons_type, int mass,
else if (wearing_amulet(AMU_THE_GOURMAND))
{
food_value = mass/3 + random2(you.experience_level * 5);
- mpr("Slurps.");
+ mpr("Slurp.");
did_god_conduct(DID_DRINK_BLOOD, 8);
}
else
diff --git a/crawl-ref/source/food.h b/crawl-ref/source/food.h
index 94dceeceec..2aba226354 100644
--- a/crawl-ref/source/food.h
+++ b/crawl-ref/source/food.h
@@ -88,7 +88,7 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg,
void eat_floor_item(int item_link);
-bool eat_from_floor(void);
+int eat_from_floor();
void eat_from_inventory(int which_inventory_slot);
diff --git a/crawl-ref/source/format.cc b/crawl-ref/source/format.cc
index 400f900dff..33bb2a47d1 100644
--- a/crawl-ref/source/format.cc
+++ b/crawl-ref/source/format.cc
@@ -166,6 +166,48 @@ formatted_string::operator std::string() const
return (s);
}
+void replace_all_in_string(std::string& s, const std::string& search,
+ const std::string& replace)
+{
+ std::string::size_type pos = 0;
+ while ( (pos = s.find(search, pos)) != std::string::npos )
+ {
+ s.replace(pos, search.size(), replace);
+ pos += replace.size();
+ }
+}
+
+std::string formatted_string::html_dump() const
+{
+ std::string s;
+ for (unsigned i = 0; i < ops.size(); ++i)
+ {
+ std::string tmp;
+ switch (ops[i].type)
+ {
+ case FSOP_TEXT:
+ tmp = ops[i].text;
+ // (very) crude HTMLification
+ replace_all_in_string(tmp, "&", "&amp;");
+ replace_all_in_string(tmp, " ", "&nbsp;");
+ replace_all_in_string(tmp, "<", "&lt;");
+ replace_all_in_string(tmp, ">", "&gt;");
+ replace_all_in_string(tmp, "\n", "<br>");
+ s += tmp;
+ break;
+ case FSOP_COLOUR:
+ s += "<font color=";
+ s += colour_to_str(ops[i].x);
+ s += ">";
+ break;
+ case FSOP_CURSOR:
+ // FIXME error handling?
+ break;
+ }
+ }
+ return s;
+}
+
const formatted_string &
formatted_string::operator += (const formatted_string &other)
{
diff --git a/crawl-ref/source/format.h b/crawl-ref/source/format.h
index 8391c2cbb8..6376849b27 100644
--- a/crawl-ref/source/format.h
+++ b/crawl-ref/source/format.h
@@ -38,6 +38,7 @@ public:
void swap(formatted_string& other);
std::string::size_type length() const;
+ std::string html_dump() const;
const formatted_string &operator += (const formatted_string &other);
@@ -58,7 +59,7 @@ private:
int find_last_colour() const;
public:
-
+
struct fs_op
{
fs_op_type type;
diff --git a/crawl-ref/source/ghost.cc b/crawl-ref/source/ghost.cc
index 1b30a89a4c..c3aa4c907a 100644
--- a/crawl-ref/source/ghost.cc
+++ b/crawl-ref/source/ghost.cc
@@ -3,7 +3,7 @@
* Summary: Player ghost and random Pandemonium demon handling.
*
* Created for Dungeon Crawl Reference by $Author:dshaligram $ on
- * $Date: 2007-03-15 $.
+ * $Date$.
*/
#include "AppHdr.h"
@@ -48,6 +48,7 @@ static int search_order_conj[] = {
SPELL_STING,
SPELL_SHOCK,
SPELL_MAGIC_DART,
+ SPELL_SLEEP,
SPELL_BACKLIGHT,
SPELL_NO_SPELL, // end search
};
diff --git a/crawl-ref/source/hiscores.cc b/crawl-ref/source/hiscores.cc
index de083a6752..dd06f0a0c7 100644
--- a/crawl-ref/source/hiscores.cc
+++ b/crawl-ref/source/hiscores.cc
@@ -718,6 +718,7 @@ void scorefile_entry::set_score_fields() const
fields->add_field("sc", "%ld", points);
fields->add_field("ktyp", ::kill_method_name(kill_method_type(death_type)));
fields->add_field("killer", death_source_desc().c_str());
+ fields->add_field("dam", "%d", damage);
fields->add_field("kaux", "%s", auxkilldata.c_str());
@@ -846,6 +847,14 @@ void scorefile_entry::init_death_cause(int dam, int dsrc,
mon_num = 0;
death_source_name[0] = 0;
}
+
+ if (death_type == KILLED_BY_WEAKNESS
+ || death_type == KILLED_BY_STUPIDITY
+ || death_type == KILLED_BY_CLUMSINESS)
+ {
+ if (auxkilldata == "")
+ auxkilldata = "unknown source";
+ }
}
void scorefile_entry::reset()
@@ -935,11 +944,23 @@ void scorefile_entry::init()
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)
+ num_runes += you.inv[d].quantity;
+
+ // Don't assert in rune_array[] due to buggy runes,
+ // since checks for buggy runes are already done
+ // elsewhere.
+ if (you.inv[d].plus < 0 || you.inv[d].plus >= NUM_RUNE_TYPES)
+ {
+ mpr("WARNING: Buggy rune in pack!");
+ // Be nice and assume the buggy rune was originally
+ // different from any of the other rune types.
num_diff_runes++;
+ continue;
+ }
- num_runes += you.inv[d].quantity;
rune_array[ you.inv[d].plus ] += you.inv[d].quantity;
+ if (rune_array[ you.inv[d].plus ] == 0)
+ num_diff_runes++;
}
}
}
@@ -1626,6 +1647,31 @@ scorefile_entry::death_description(death_desc_verbosity verbosity) const
break;
} // end switch
+ switch (death_type)
+ {
+ case KILLED_BY_STUPIDITY:
+ case KILLED_BY_WEAKNESS:
+ case KILLED_BY_CLUMSINESS:
+ if (terse)
+ {
+ desc += " (";
+ desc += auxkilldata;
+ desc += ")";
+ }
+ else
+ {
+ desc += "\n";
+ desc += " ";
+ desc += "... caused by ";
+ desc += auxkilldata;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+
if (oneline && desc.length() > 2)
desc[1] = tolower(desc[1]);
diff --git a/crawl-ref/source/initfile.cc b/crawl-ref/source/initfile.cc
index e6bc768a53..4bc4c05ecf 100644
--- a/crawl-ref/source/initfile.cc
+++ b/crawl-ref/source/initfile.cc
@@ -101,7 +101,8 @@ int str_to_colour( const std::string &str, int default_colour,
"holy", "dark", "death", "necro", "unholy", "vehumet",
"beogh", "crystal", "blood", "smoke", "slime", "jewel",
"elven", "dwarven", "orcish", "gila", "floor", "rock",
- "stone", "mist", "shimmer_blue", "random"
+ "stone", "mist", "shimmer_blue", "decay", "silver", "gold",
+ "iron", "bone", "random"
};
ASSERT(ARRAYSIZE(element_cols) == (EC_RANDOM - EC_FIRE) + 1);
@@ -371,12 +372,14 @@ static unsigned curses_attribute(const std::string &field)
int col = field.find(":");
int colour = str_to_colour(field.substr(col + 1));
if (colour == -1)
- fprintf(stderr, "Bad highlight string -- %s\n", field.c_str());
+ crawl_state.add_startup_error(
+ make_stringf("Bad highlight string -- %s\n", field.c_str()));
else
return CHATTR_HILITE | (colour << 8);
}
else if (field != "none")
- fprintf( stderr, "Bad colour -- %s\n", field.c_str() );
+ crawl_state.add_startup_error(
+ make_stringf( "Bad colour -- %s\n", field.c_str() ) );
return CHATTR_NORMAL;
}
@@ -466,7 +469,8 @@ void game_options::set_activity_interrupt(
delay_type delay = get_delay(delay_name);
if (delay == NUM_DELAYS)
{
- fprintf(stderr, "Unknown delay: %s\n", delay_name.c_str());
+ crawl_state.add_startup_error(
+ make_stringf("Unknown delay: %s\n", delay_name.c_str()));
return;
}
@@ -483,8 +487,9 @@ void game_options::set_activity_interrupt(
activity_interrupt_type ai = get_activity_interrupt(interrupt);
if (ai == NUM_AINTERRUPTS)
{
- fprintf(stderr, "Delay interrupt name \"%s\" not recognised.\n",
- interrupt.c_str());
+ crawl_state.add_startup_error(
+ make_stringf("Delay interrupt name \"%s\" not recognised.\n",
+ interrupt.c_str()));
return;
}
@@ -499,7 +504,8 @@ void game_options::set_activity_interrupt(const std::string &activity_name,
const delay_type delay = get_delay(activity_name);
if (delay == NUM_DELAYS)
{
- fprintf(stderr, "Unknown delay: %s\n", activity_name.c_str());
+ crawl_state.add_startup_error(
+ make_stringf("Unknown delay: %s\n", activity_name.c_str()));
return;
}
@@ -597,24 +603,24 @@ void game_options::reset_options()
(1L << 7) | // jewellery
(1L << 3) | // wands
(1L << 4)); // food
+
+ suppress_startup_errors = false;
+
show_inventory_weights = false;
colour_map = true;
clean_map = false;
show_uncursed = true;
- always_greet = true;
easy_open = true;
easy_unequip = true;
easy_butcher = true;
+ always_confirm_butcher = false;
easy_confirm = CONFIRM_SAFE_EASY;
easy_quit_item_prompts = true;
hp_warning = 10;
magic_point_warning = 0;
- confirm_self_target = true;
default_target = true;
- safe_autopickup = true;
autopickup_no_burden = false;
- use_notes = true;
user_note_prefix = "";
note_all_skill_levels = false;
note_skill_max = false;
@@ -622,9 +628,6 @@ void game_options::reset_options()
note_hp_percent = 5;
ood_interesting = 8;
- terse_hand = true;
- increasing_skill_progress = true;
-
// [ds] Grumble grumble.
auto_list = true;
@@ -683,7 +686,6 @@ void game_options::reset_options()
explore_item_greed = 10;
explore_greedy = false;
- safe_zero_exp = true;
target_zero_exp = false;
target_wrap = true;
target_oos = true;
@@ -703,8 +705,6 @@ void game_options::reset_options()
flush_input[ FLUSH_ON_MESSAGE ] = false;
flush_input[ FLUSH_LUA ] = true;
- lowercase_invocations = true;
-
fire_items_start = 2; // start at slot 'c'
// Clear fire_order and set up the defaults.
@@ -1643,6 +1643,10 @@ void game_options::read_option_line(const std::string &str, bool runscript)
// should weights be shown on inventory items?
show_inventory_weights = read_bool( field, show_inventory_weights );
}
+ else if (key == "suppress_startup_errors")
+ {
+ suppress_startup_errors = read_bool( field, suppress_startup_errors );
+ }
else if (key == "clean_map")
{
// removes monsters/clouds from map
@@ -1687,6 +1691,10 @@ void game_options::read_option_line(const std::string &str, bool runscript)
// automatic knife switching
easy_butcher = read_bool( field, easy_butcher );
}
+ else if (key == "always_confirm_butcher")
+ {
+ always_confirm_butcher = read_bool( field, always_confirm_butcher );
+ }
else if (key == "lua_file" && runscript)
{
#ifdef CLUA_BINDINGS
@@ -1819,11 +1827,6 @@ void game_options::read_option_line(const std::string &str, bool runscript)
// here as well.
heap_brand = curses_attribute(field);
}
- else if (key == "always_greet")
- {
- // show greeting when reloading game
- always_greet = read_bool( field, always_greet );
- }
else if (key == "weapon")
{
// choose this weapon for classes that get choice
@@ -1978,20 +1981,12 @@ void game_options::read_option_line(const std::string &str, bool runscript)
{
auto_list = read_bool( field, auto_list );
}
- else if (key == "confirm_self_target")
- {
- confirm_self_target = read_bool( field, confirm_self_target );
- }
else if (key == "default_target")
{
default_target = read_bool( field, default_target );
if (default_target)
target_unshifted_dirs = false;
}
- else if (key == "safe_autopickup")
- {
- safe_autopickup = read_bool( field, safe_autopickup );
- }
else if (key == "autopickup_no_burden")
{
autopickup_no_burden = read_bool( field, autopickup_no_burden );
@@ -2065,10 +2060,6 @@ void game_options::read_option_line(const std::string &str, bool runscript)
scrollmarg = 0;
scroll_margin_x = scroll_margin_y = scrollmarg;
}
- else if (key == "use_notes")
- {
- use_notes = read_bool( field, use_notes );
- }
else if (key == "user_note_prefix")
{
// field is already cleaned up from trim_string()
@@ -2086,14 +2077,6 @@ void game_options::read_option_line(const std::string &str, bool runscript)
{
delay_message_clear = read_bool( field, delay_message_clear );
}
- else if (key == "terse_hand")
- {
- terse_hand = read_bool( field, terse_hand );
- }
- else if (key == "increasing_skill_progress")
- {
- increasing_skill_progress = read_bool( field, increasing_skill_progress );
- }
else if (key == "flush")
{
if (subkey == "failure")
@@ -2117,11 +2100,6 @@ void game_options::read_option_line(const std::string &str, bool runscript)
= read_bool(field, flush_input[FLUSH_LUA]);
}
}
- else if (key == "lowercase_invocations")
- {
- lowercase_invocations
- = read_bool(field, lowercase_invocations);
- }
else if (key == "wiz_mode")
{
// wiz_mode is recognized as a legal key in all compiles -- bwr
@@ -2133,7 +2111,8 @@ void game_options::read_option_line(const std::string &str, bool runscript)
else if (field == "yes")
wiz_mode = WIZ_YES;
else
- fprintf(stderr, "Unknown wiz_mode option: %s\n", field.c_str());
+ crawl_state.add_startup_error(
+ make_stringf("Unknown wiz_mode option: %s\n", field.c_str()));
#endif
}
else if (key == "ban_pickup")
@@ -2184,7 +2163,8 @@ void game_options::read_option_line(const std::string &str, bool runscript)
if ( insplit.size() == 0 || insplit.size() > 2 ||
(insplit.size() == 1 && i != 0) )
{
- fprintf(stderr, "Bad hp_colour string: %s\n", field.c_str());
+ crawl_state.add_startup_error(
+ make_stringf("Bad hp_colour string: %s\n", field.c_str()));
break;
}
@@ -2207,7 +2187,8 @@ void game_options::read_option_line(const std::string &str, bool runscript)
if ( insplit.size() == 0 || insplit.size() > 2 ||
(insplit.size() == 1 && i != 0) )
{
- fprintf(stderr, "Bad mp_colour string: %s\n", field.c_str());
+ crawl_state.add_startup_error(
+ make_stringf("Bad mp_colour string: %s\n", field.c_str()));
break;
}
@@ -2228,8 +2209,9 @@ void game_options::read_option_line(const std::string &str, bool runscript)
note_skill_levels.push_back(num);
else
{
- fprintf(stderr, "Bad skill level to note -- %s\n",
- thesplit[i].c_str());
+ crawl_state.add_startup_error(
+ make_stringf("Bad skill level to note -- %s\n",
+ thesplit[i].c_str()));
continue;
}
}
@@ -2455,16 +2437,31 @@ void game_options::read_option_line(const std::string &str, bool runscript)
std::vector<std::string> seg = split_string(",", field);
for (int i = 0, count = seg.size(); i < count; ++i)
{
- const std::string &sub = seg[i];
- std::string::size_type cpos = sub.find(":", 0);
- if (cpos != std::string::npos)
+ // format: tag:string:colour
+ // FIXME: arrange so that you can use ':' inside a pattern
+ std::vector<std::string> subseg = split_string(":", seg[i], false);
+ std::string tagname, patname, colname;
+ if ( subseg.size() < 2 )
+ continue;
+ if ( subseg.size() >= 3 )
+ {
+ tagname = subseg[0];
+ colname = subseg[1];
+ patname = subseg[2];
+ }
+ else
{
- colour_mapping mapping;
- mapping.pattern = sub.substr(cpos + 1);
- mapping.colour = str_to_colour(sub.substr(0, cpos));
- if (mapping.colour != -1)
- menu_colour_mappings.push_back(mapping);
+ colname = subseg[0];
+ patname = subseg[1];
}
+
+ colour_mapping mapping;
+ mapping.tag = tagname;
+ mapping.pattern = patname;
+ mapping.colour = str_to_colour(colname);
+
+ if (mapping.colour != -1)
+ menu_colour_mappings.push_back(mapping);
}
}
else if (key == "menu_colour_prefix_class" ||
@@ -2555,10 +2552,6 @@ void game_options::read_option_line(const std::string &str, bool runscript)
{
level_map_title = read_bool(field, level_map_title);
}
- else if (key == "safe_zero_exp")
- {
- safe_zero_exp = read_bool(field, safe_zero_exp);
- }
else if (key == "target_zero_exp")
{
target_zero_exp = read_bool(field, target_zero_exp);
diff --git a/crawl-ref/source/invent.cc b/crawl-ref/source/invent.cc
index 3a578f3784..f8af3d11e1 100644
--- a/crawl-ref/source/invent.cc
+++ b/crawl-ref/source/invent.cc
@@ -156,13 +156,9 @@ const int InvEntry::item_freshness() const
return 0;
int freshness = item->special;
-
- if (freshness >= 100 || you.species == SP_TROLL || you.species == SP_KOBOLD
- || you.species == SP_GHOUL || you.species == SP_OGRE
- || you.species == SP_HILL_ORC)
- {
+
+ if (freshness >= 100 || you.mutation[MUT_SAPROVOROUS])
freshness -= 300;
- }
// Ensure that chunk freshness is never zero, since zero means
// that the item isn't a chunk.
@@ -1195,6 +1191,7 @@ int prompt_invent_item( const char *prompt,
{
if (count)
*count = items[0].quantity;
+
redraw_screen();
mesclr( true );
}
diff --git a/crawl-ref/source/invent.h b/crawl-ref/source/invent.h
index 46b30a33c2..74386687f0 100644
--- a/crawl-ref/source/invent.h
+++ b/crawl-ref/source/invent.h
@@ -89,7 +89,8 @@ public:
virtual int highlight_colour() const
{
return menu_colour(get_text(),
- menu_colour_item_prefix( *( (item_def*) item) ) );
+ menu_colour_item_prefix( *( (item_def*) item) ),
+ tag );
}
@@ -108,7 +109,7 @@ class InvMenu : public Menu
{
public:
InvMenu(int mflags = MF_MULTISELECT)
- : Menu(mflags), type(MT_INVLIST), pre_select(NULL),
+ : Menu(mflags, "inventory"), type(MT_INVLIST), pre_select(NULL),
title_annotate(NULL)
{
}
diff --git a/crawl-ref/source/it_use2.cc b/crawl-ref/source/it_use2.cc
index 0d4b6ca36a..e78f3375e6 100644
--- a/crawl-ref/source/it_use2.cc
+++ b/crawl-ref/source/it_use2.cc
@@ -27,6 +27,7 @@
#include "beam.h"
#include "effects.h"
#include "food.h"
+#include "item_use.h"
#include "itemname.h"
#include "itemprop.h"
#include "misc.h"
@@ -40,12 +41,13 @@
#include "spl-util.h"
#include "stuff.h"
#include "view.h"
+#include "xom.h"
// From an actual potion, pow == 40 -- bwr
bool potion_effect( potion_type pot_eff, int pow )
{
bool effect = true; // current behaviour is all potions id on quaffing
-
+ bool was_known = item_type_known(OBJ_POTIONS, (int) pot_eff);
int new_value = 0;
if (pow > 150)
@@ -109,7 +111,7 @@ bool potion_effect( potion_type pot_eff, int pow )
if ( were_mighty )
contaminate_player(1);
else
- modify_stat(STAT_STRENGTH, 5, true);
+ modify_stat(STAT_STRENGTH, 5, true, "");
// conceivable max gain of +184 {dlb}
you.duration[DUR_MIGHT] += 35 + random2(pow);
@@ -118,7 +120,7 @@ bool potion_effect( potion_type pot_eff, int pow )
if (you.duration[DUR_MIGHT] > 80)
you.duration[DUR_MIGHT] = 80;
- did_god_conduct( DID_STIMULANTS, 4 + random2(4) );
+ did_god_conduct( DID_STIMULANTS, 4 + random2(4), was_known );
break;
}
@@ -216,7 +218,8 @@ bool potion_effect( potion_type pot_eff, int pow )
case POT_DEGENERATION:
if ( pow == 40 )
mpr("There was something very wrong with that liquid!");
- if (lose_stat(STAT_RANDOM, 1 + random2avg(4, 2)))
+ if (lose_stat(STAT_RANDOM, 1 + random2avg(4, 2), false,
+ "drinking a potion of degeneration"))
xom_is_stimulated(64);
break;
@@ -305,31 +308,20 @@ bool potion_effect( potion_type pot_eff, int pow )
case POT_BLOOD:
if (you.species == SP_VAMPIRE)
{
- int temp_rand = random2(9);
- strcpy(info, (temp_rand == 0) ? "human" :
- (temp_rand == 1) ? "rat" :
- (temp_rand == 2) ? "goblin" :
- (temp_rand == 3) ? "elf" :
- (temp_rand == 4) ? "goat" :
- (temp_rand == 5) ? "sheep" :
- (temp_rand == 6) ? "gnoll" :
- (temp_rand == 7) ? "sheep"
- : "yak");
-
- mprf("Yummy - fresh %s blood!", info);
-
- lessen_hunger(1000, true);
- mpr("You feel better.");
- inc_hp(1 + random2(10), false);
+ const char* names[] = { "human", "rat", "goblin",
+ "elf", "goat", "sheep",
+ "sheep", "gnoll", "yak" };
+
+ mprf("Yummy - fresh %s blood!", RANDOM_ELEMENT(names));
+ lessen_hunger(1000, true);
+ mpr("You feel better.");
+ inc_hp(1 + random2(10), false);
}
else
{
- bool likes_blood = (you.species == SP_OGRE
- || you.species == SP_TROLL
- || you.mutation[MUT_CARNIVOROUS]);
-
- if (likes_blood)
+ if (you.omnivorous() || you.mutation[MUT_CARNIVOROUS])
{
+ // Likes it
mpr("This tastes like blood.");
lessen_hunger(200, true);
}
@@ -343,7 +335,7 @@ bool potion_effect( potion_type pot_eff, int pow )
xom_is_stimulated(32);
}
}
- did_god_conduct(DID_DRINK_BLOOD, 1 + random2(3));
+ did_god_conduct(DID_DRINK_BLOOD, 1 + random2(3), was_known);
break;
case POT_RESISTANCE:
@@ -364,12 +356,15 @@ bool potion_effect( potion_type pot_eff, int pow )
return (effect);
} // end potion_effect()
-void unwield_item(bool showMsgs)
+bool unwield_item(bool showMsgs)
{
const int unw = you.equip[EQ_WEAPON];
if ( unw == -1 )
- return;
+ return (false);
+ if (!safe_to_remove_or_wear(you.inv[unw], true))
+ return (false);
+
you.equip[EQ_WEAPON] = -1;
you.special_wield = SPWLD_NONE;
you.wield_change = true;
@@ -412,7 +407,7 @@ void unwield_item(bool showMsgs)
break;
}
- return;
+ return (true);
}
const int brand = get_weapon_brand( item );
@@ -474,7 +469,7 @@ void unwield_item(bool showMsgs)
// int effect = 9 - random2avg( you.skills[SK_TRANSLOCATIONS] * 2, 2 );
miscast_effect( SPTYP_TRANSLOCATION, 9, 90, 100,
- "a distortion effect" );
+ "distortion unwield" );
break;
// when more are added here, *must* duplicate unwielding
@@ -492,18 +487,23 @@ void unwield_item(bool showMsgs)
}
if (item.base_type == OBJ_STAVES && item.sub_type == STAFF_POWER)
+ {
calc_mp();
+ mpr("You fell your mana capacity decrease.");
+ }
- return;
+ return (true);
} // end unwield_item()
// This does *not* call ev_mod!
void unwear_armour(char unw)
{
- you.redraw_armour_class = 1;
- you.redraw_evasion = 1;
+ you.redraw_armour_class = true;
+ you.redraw_evasion = true;
- switch (get_armour_ego_type( you.inv[unw] ))
+ item_def &item(you.inv[unw]);
+
+ switch (get_armour_ego_type( item ))
{
case SPARM_RUNNING:
mpr("You feel rather sluggish.");
@@ -533,15 +533,15 @@ void unwear_armour(char unw)
break;
case SPARM_STRENGTH:
- modify_stat(STAT_STRENGTH, -3, false);
+ modify_stat(STAT_STRENGTH, -3, false, item, true);
break;
case SPARM_DEXTERITY:
- modify_stat(STAT_DEXTERITY, -3, false);
+ modify_stat(STAT_DEXTERITY, -3, false, item, true);
break;
case SPARM_INTELLIGENCE:
- modify_stat(STAT_INTELLIGENCE, -3, false);
+ modify_stat(STAT_INTELLIGENCE, -3, false, item, true);
break;
case SPARM_PONDEROUSNESS:
@@ -598,35 +598,47 @@ void unuse_randart(const item_def &item)
{
ASSERT( is_random_artefact( item ) );
- const bool ident = fully_identified(item);
-
randart_properties_t proprt;
- randart_wpn_properties( item, proprt );
+ randart_known_props_t known;
+ randart_wpn_properties( item, proprt, known );
if (proprt[RAP_AC])
{
- you.redraw_armour_class = 1;
- if (!ident)
+ you.redraw_armour_class = true;
+ if (!known[RAP_AC])
{
mprf("You feel less %s.",
- proprt[RAP_AC] > 0? "well-protected" : "vulnerable");
+ proprt[RAP_AC] > 0? "well-protected" : "vulnerable");
}
}
if (proprt[RAP_EVASION])
{
- you.redraw_evasion = 1;
- if (!ident)
+ you.redraw_evasion = true;
+ if (!known[RAP_EVASION])
{
mprf("You feel less %s.",
proprt[RAP_EVASION] > 0? "nimble" : "awkward");
}
}
+ if (proprt[RAP_MAGICAL_POWER])
+ {
+ you.redraw_magic_points = true;
+ if (!known[RAP_MAGICAL_POWER])
+ {
+ mprf("You feel your mana capacity %s.",
+ proprt[RAP_MAGICAL_POWER] > 0 ? "decrease" : "increase");
+ }
+ }
+
// modify ability scores, always output messages
- modify_stat( STAT_STRENGTH, -proprt[RAP_STRENGTH], false );
- modify_stat( STAT_INTELLIGENCE, -proprt[RAP_INTELLIGENCE], false );
- modify_stat( STAT_DEXTERITY, -proprt[RAP_DEXTERITY], false );
+ modify_stat( STAT_STRENGTH, -proprt[RAP_STRENGTH], false, item,
+ true);
+ modify_stat( STAT_INTELLIGENCE, -proprt[RAP_INTELLIGENCE], false, item,
+ true);
+ modify_stat( STAT_DEXTERITY, -proprt[RAP_DEXTERITY], false, item,
+ true);
if (proprt[RAP_NOISES] != 0)
you.special_wield = SPWLD_NONE;
diff --git a/crawl-ref/source/it_use2.h b/crawl-ref/source/it_use2.h
index 408e32b847..96c6f4f9c6 100644
--- a/crawl-ref/source/it_use2.h
+++ b/crawl-ref/source/it_use2.h
@@ -69,6 +69,6 @@ void unwear_armour(char unw);
/* ***********************************************************************
* called from: decks - it_use3 - item_use - items - spells3 - transfor
* *********************************************************************** */
-void unwield_item(bool showMsgs = true);
+bool unwield_item(bool showMsgs = true);
#endif
diff --git a/crawl-ref/source/it_use3.cc b/crawl-ref/source/it_use3.cc
index e3d33d45d8..126bdcdfb4 100644
--- a/crawl-ref/source/it_use3.cc
+++ b/crawl-ref/source/it_use3.cc
@@ -50,8 +50,10 @@
#include "spl-book.h"
#include "spl-cast.h"
#include "spl-util.h"
+#include "state.h"
#include "stuff.h"
#include "view.h"
+#include "xom.h"
static bool ball_of_energy(void);
static bool ball_of_fixation(void);
@@ -248,94 +250,173 @@ void special_wielded()
return;
} // end special_wielded()
-static void reaching_weapon_attack(void)
+static bool reaching_weapon_attack(const item_def& wpn)
{
- struct dist beam;
- int x_distance, y_distance;
- int x_middle, y_middle;
- int skill;
+ dist beam;
mpr("Attack whom?", MSGCH_PROMPT);
direction(beam, DIR_TARGET, TARG_ENEMY);
+
if (!beam.isValid)
- return;
+ return false;
if (beam.isMe)
{
canned_msg(MSG_UNTHINKING_ACT);
- return;
+ return false;
}
- x_distance = abs(beam.tx - you.x_pos);
- y_distance = abs(beam.ty - you.y_pos);
+ const int x_distance = abs(beam.tx - you.x_pos);
+ const int y_distance = abs(beam.ty - you.y_pos);
if (x_distance > 2 || y_distance > 2)
+ {
mpr("Your weapon cannot reach that far!");
+ return false;
+ }
else if (mgrd[beam.tx][beam.ty] == NON_MONSTER)
{
+ // Must return true, otherwise you get a free discovery
+ // of invisible monsters. Maybe we shouldn't do practice
+ // here to prevent scumming...but that would just encourage
+ // finding popcorn monsters.
mpr("You attack empty space.");
+ return true;
}
- 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))
{
- /* BCR - Added a check for monsters in the way. Only checks cardinal
- * directions. Knight moves are ignored. Assume the weapon
- * slips between the squares.
- */
+ const int x_middle = MAX(beam.tx, you.x_pos) - (x_distance / 2);
+ const int y_middle = MAX(beam.ty, you.y_pos) - (y_distance / 2);
- // if we're attacking more than a space away
- if ((x_distance > 1) || (y_distance > 1))
+ // 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))
{
- x_middle = MAX(beam.tx, you.x_pos) - (x_distance / 2);
- y_middle = MAX(beam.ty, you.y_pos) - (y_distance / 2);
+ const int skill = weapon_skill( wpn.base_type, wpn.sub_type );
- // 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))
+ if ((5 + (3 * skill)) > random2(100))
{
- 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);
- }
+ mpr("You reach to attack!");
+ you_attack(mgrd[beam.tx][beam.ty], false);
}
else
{
- mpr("You reach to attack!");
- you_attack(mgrd[beam.tx][beam.ty], false);
+ 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;
+ return true;
} // end reaching_weapon_attack()
+static bool evoke_horn_of_geryon()
+{
+ // Note: This assumes that the Vestibule has not been changed.
+ bool rc = false;
+
+ if (player_in_branch( BRANCH_VESTIBULE_OF_HELL ))
+ {
+ mpr("You produce a weird and mournful sound.");
+
+ for (int count_x = 0; count_x < GXM; count_x++)
+ {
+ for (int count_y = 0; count_y < GYM; count_y++)
+ {
+ if (grd[count_x][count_y] == DNGN_STONE_ARCH)
+ {
+ rc = true;
+
+ map_marker *marker =
+ env.markers.find(coord_def(count_x, count_y),
+ MAT_FEATURE);
+
+ if (marker)
+ {
+ map_feature_marker *featm =
+ dynamic_cast<map_feature_marker*>(marker);
+ grd[count_x][count_y] = featm->feat;
+ env.markers.remove(marker);
+ }
+ }
+ }
+ }
+
+ if (rc)
+ mpr("Your way has been unbarred.");
+ }
+ else
+ {
+ mpr("You produce a hideous howling noise!");
+ create_monster( MONS_BEAST, 4, BEH_HOSTILE, you.x_pos, you.y_pos,
+ MHITYOU, 250, false, false, false, true );
+ }
+ return rc;
+}
+
+static bool evoke_sceptre_of_asmodeus()
+{
+ bool rc = true;
+ if ( one_chance_in(21) )
+ rc = false;
+ else if (one_chance_in(2))
+ {
+ // summon devils, maybe a Fiend
+ const monster_type mtype = (one_chance_in(4) ? MONS_FIEND :
+ summon_any_demon(DEMON_COMMON));
+ const bool good_summon = (create_monster( mtype, 6, BEH_HOSTILE,
+ you.x_pos, you.y_pos,
+ MHITYOU, 250) != -1);
+
+ if (good_summon)
+ {
+ if (mtype == MONS_FIEND)
+ mpr("\"Your arrogance condemns you, mortal!\"");
+ else
+ mpr("The Sceptre summons one of its servants.");
+ }
+ else
+ mpr("The air shimmers briefly.");
+ }
+ else
+ {
+ // Cast a destructive spell
+ const spell_type spl = static_cast<spell_type>(
+ random_choose_weighted( 114, SPELL_BOLT_OF_FIRE,
+ 57, SPELL_LIGHTNING_BOLT,
+ 57, SPELL_BOLT_OF_DRAINING,
+ 12, SPELL_HELLFIRE,
+ 0 ));
+ your_spells( spl, you.skills[SK_EVOCATIONS] * 8, false );
+ }
+ return true;
+}
+
// returns true if item successfully evoked.
-bool evoke_wielded( void )
+bool evoke_wielded()
{
- 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
- int wield = you.equip[EQ_WEAPON];
+ const int wield = you.equip[EQ_WEAPON];
if (you.duration[DUR_BERSERKER])
{
@@ -345,6 +426,7 @@ bool evoke_wielded( void )
else if (wield == -1)
{
mpr("You aren't wielding anything!");
+ crawl_state.zero_turns_taken();
return (false);
}
@@ -358,15 +440,18 @@ bool evoke_wielded( void )
switch (wpn.base_type)
{
case OBJ_WEAPONS:
- if (get_weapon_brand( wpn ) == SPWPN_REACHING
- && enough_mp(1, false))
+ if (get_weapon_brand(wpn) == 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;
+ if ( reaching_weapon_attack(wpn) )
+ {
+ // needed a cost to prevent evocation training abuse -- bwr
+ dec_mp(1);
+ make_hungry( 50, false );
+ pract = (one_chance_in(5) ? 1 : 0);
+ did_work = true;
+ }
+ else
+ return false;
}
else if (is_fixed_artefact( wpn ))
{
@@ -391,56 +476,13 @@ bool evoke_wielded( void )
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
+ if ( evoke_sceptre_of_asmodeus() )
{
-
- spell_casted = (one_chance_in(4) ? MONS_FIEND
- : MONS_HELLION + random2(10));
-
- bool good_summon = (create_monster( spell_casted,
- 6, 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.");
- }
-
+ make_hungry(200, false);
did_work = true;
- break;
+ pract = 1;
}
-
- 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( static_cast<spell_type>(spell_casted),
- power, false );
- did_work = true;
break;
case SPWPN_STAFF_OF_OLGREB:
@@ -588,51 +630,8 @@ bool evoke_wielded( void )
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++;
-
- map_marker *marker =
- env.markers.find(coord_def(count_x, count_y),
- MAT_FEATURE);
-
- if (marker)
- {
- map_feature_marker *featm =
- dynamic_cast<map_feature_marker*>(marker);
- grd[count_x][count_y] = featm->feat;
- env.markers.remove(marker);
- }
- }
- }
- }
-
- if (opened_gates)
- {
- mpr("Your way has been unbarred.");
- pract = 1;
- }
- }
- else
- {
- mpr("You produce a hideous howling noise!");
- int midx = create_monster( MONS_BEAST, 4,
- BEH_HOSTILE, you.x_pos, you.y_pos,
- MHITYOU, 250 );
- // avoid scumming; also prevents it from showing up on notes
- if ( midx != -1 )
- menv[midx].flags |= MF_CREATED_FRIENDLY;
- // no practice
- }
+ if ( evoke_horn_of_geryon() )
+ pract = 1;
break;
case MISC_BOX_OF_BEASTS:
@@ -674,6 +673,8 @@ bool evoke_wielded( void )
if (!unevokable)
you.turn_is_over = true;
+ else
+ crawl_state.zero_turns_taken();
return (did_work);
} // end evoke_wielded()
@@ -719,7 +720,7 @@ static bool ball_of_seeing(void)
if (use < 2)
{
- lose_stat( STAT_INTELLIGENCE, 1 );
+ lose_stat( STAT_INTELLIGENCE, 1, false, "using a ball of seeing");
}
else if (use < 5 && enough_mp(1, true))
{
@@ -795,16 +796,11 @@ static bool disc_of_storms(void)
return (ret);
} // end disc_of_storms()
-void tome_of_power(char sc_read_2)
+void tome_of_power(int slot)
{
- int temp_rand = 0; // probability determination {dlb}
-
int powc = 5 + you.skills[SK_EVOCATIONS]
+ roll_dice( 5, you.skills[SK_EVOCATIONS] );
- spell_type spell_casted = SPELL_NO_SPELL;
- struct bolt beam;
-
msg::stream << "The book opens to a page covered in "
<< weird_writing() << '.' << std::endl;
@@ -813,7 +809,7 @@ void tome_of_power(char sc_read_2)
if (!yesno("Read it?"))
return;
- set_ident_flags( you.inv[sc_read_2], ISFLAG_IDENT_MASK );
+ set_ident_flags( you.inv[slot], ISFLAG_KNOW_TYPE );
if (you.mutation[MUT_BLURRY_VISION] > 0
&& random2(4) < you.mutation[MUT_BLURRY_VISION])
@@ -825,46 +821,35 @@ void tome_of_power(char sc_read_2)
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))
+ if ( random2(50) < 7 )
{
- 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( random_smoke_type(), KC_YOU,
you.x_pos, you.y_pos, 20, 10 + random2(8) );
xom_is_stimulated(16);
- return;
- case 1:
- case 14:
+ }
+ else if ( random2(43) < 2 )
+ {
mpr("A cloud of choking fumes pours from the book's pages!");
big_cloud(CLOUD_POISON, KC_YOU,
you.x_pos, you.y_pos, 20, 7 + random2(5));
xom_is_stimulated(64);
- return;
-
- case 2:
- case 13:
+ }
+ else if ( random2(41) < 2 )
+ {
mpr("A cloud of freezing gas pours from the book's pages!");
big_cloud(CLOUD_COLD, KC_YOU, you.x_pos, you.y_pos, 20, 8 + random2(5));
xom_is_stimulated(64);
- return;
-
- case 5:
- case 11:
- case 12:
+ }
+ else if ( random2(39) < 3 )
+ {
if (one_chance_in(5))
{
mpr("The book disappears in a mighty explosion!");
- dec_inv_item_quantity( sc_read_2, 1 );
+ dec_inv_item_quantity( slot, 1 );
}
+ bolt beam;
beam.type = SYM_BURST;
beam.damage = dice_def( 3, 15 );
// unsure about this // BEAM_EXPLOSION instead? [dlb]
@@ -876,16 +861,16 @@ void tome_of_power(char sc_read_2)
// 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.aux_source = "an exploding tome of Destruction";
beam.ex_size = 2;
beam.is_tracer = false;
beam.is_explosion = true;
explosion(beam);
xom_is_stimulated(255);
- return;
-
- case 10:
+ }
+ else if (one_chance_in(36))
+ {
if (create_monster( MONS_ABOMINATION_SMALL, 6, BEH_HOSTILE,
you.x_pos, you.y_pos, MHITYOU, 250 ) != -1)
{
@@ -893,65 +878,62 @@ void tome_of_power(char sc_read_2)
mpr("It doesn't look too friendly.");
}
xom_is_stimulated(255);
- return;
}
+ else
+ {
+ viewwindow(1, false);
- 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)
-{
- set_ident_flags( you.inv[sc_read_2], ISFLAG_IDENT_MASK );
-
- const int skill = you.inv[sc_read_2].plus;
-
- const char* skname = skill_name(skill);
- mprf("This is a manual of %s!", skname);
+ int temp_rand = random2(23) + random2(you.skills[SK_EVOCATIONS] / 3);
+
+ if (temp_rand > 25)
+ temp_rand = 25;
+
+ const spell_type spell_casted =
+ ((temp_rand > 24) ? SPELL_LEHUDIBS_CRYSTAL_SPEAR :
+ (temp_rand > 21) ? SPELL_BOLT_OF_FIRE :
+ (temp_rand > 18) ? SPELL_BOLT_OF_COLD :
+ (temp_rand > 16) ? SPELL_LIGHTNING_BOLT :
+ (temp_rand > 10) ? SPELL_FIREBALL :
+ (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 );
+ }
+}
+void skill_manual(int slot)
+{
+ // Removed confirmation request because you know it's
+ // a manual in advance.
you.turn_is_over = true;
+ item_def& manual(you.inv[slot]);
+ set_ident_flags( manual, ISFLAG_KNOW_TYPE );
+ const int skill = manual.plus;
- if (!yesno("Read it?"))
- return;
-
- mprf("You read about %s.", skname);
+ mprf("You read about %s.", skill_name(skill));
exercise(skill, 500);
if (one_chance_in(10))
{
- mpr("The book crumbles into dust.");
- dec_inv_item_quantity( sc_read_2, 1 );
+ mpr("The manual crumbles into dust.");
+ dec_inv_item_quantity( slot, 1 );
}
else
{
- mpr("The book looks somewhat more worn.");
+ mpr("The manual looks somewhat more worn.");
}
xom_is_stimulated(14);
-} // end skill_manual()
+}
static bool box_of_beasts()
{
@@ -1016,7 +998,7 @@ static bool ball_of_energy(void)
if (use < 2 || you.max_magic_points == 0)
{
- lose_stat(STAT_INTELLIGENCE, 1);
+ lose_stat(STAT_INTELLIGENCE, 1, false, "using a ball of energy");
}
else if ((use < 4 && enough_mp(1, true))
|| you.magic_points == you.max_magic_points)
@@ -1049,15 +1031,16 @@ static bool ball_of_energy(void)
}
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.duration[DUR_PARALYSIS] = 100;
- you.duration[DUR_SLOW] = 100;
+ const int duration = random_range(15, 40);
+ you.duration[DUR_PARALYSIS] = duration;
+ you.duration[DUR_SLOW] = duration;
return (true);
-} // end ball_of_fixation()
+}
diff --git a/crawl-ref/source/it_use3.h b/crawl-ref/source/it_use3.h
index 2e5efae7c3..8c5cfc3e37 100644
--- a/crawl-ref/source/it_use3.h
+++ b/crawl-ref/source/it_use3.h
@@ -17,28 +17,28 @@
/* ***********************************************************************
* called from: item_use
* *********************************************************************** */
-void skill_manual(char sc_read_2);
+void skill_manual(int slot);
// last updated 12may2000 {dlb}
/* ***********************************************************************
* called from: item_use - spl-book
* *********************************************************************** */
-void tome_of_power(char sc_read_2);
+void tome_of_power(int slot);
// last updated 12may2000 {dlb}
/* ***********************************************************************
* called from: acr
* *********************************************************************** */
-bool evoke_wielded(void);
+bool evoke_wielded();
// last updated 12may2000 {dlb}
/* ***********************************************************************
* called from: acr
* *********************************************************************** */
-void special_wielded(void);
+void special_wielded();
#endif
diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc
index c6e724b10a..4187ef411e 100644
--- a/crawl-ref/source/item_use.cc
+++ b/crawl-ref/source/item_use.cc
@@ -36,6 +36,7 @@
#include "beam.h"
#include "cio.h"
+#include "cloud.h"
#include "command.h"
#include "debug.h"
#include "delay.h"
@@ -61,6 +62,7 @@
#include "player.h"
#include "randart.h"
#include "religion.h"
+#include "shopping.h"
#include "skills.h"
#include "skills2.h"
#include "spells1.h"
@@ -69,10 +71,12 @@
#include "spl-book.h"
#include "spl-cast.h"
#include "spl-util.h"
+#include "state.h"
#include "stuff.h"
#include "transfor.h"
#include "tutorial.h"
#include "view.h"
+#include "xom.h"
static bool drink_fountain();
static bool enchant_armour();
@@ -232,7 +236,9 @@ bool wield_weapon(bool auto_wield, int slot, bool show_weff_messages)
{
if (you.equip[EQ_WEAPON] != -1)
{
- unwield_item(show_weff_messages);
+ if (!unwield_item(show_weff_messages))
+ return (false);
+
canned_msg( MSG_EMPTY_HANDED );
you.turn_is_over = true;
@@ -256,9 +262,12 @@ bool wield_weapon(bool auto_wield, int slot, bool show_weff_messages)
if (!can_wield(&you.inv[item_slot], true))
return (false);
+ if (!safe_to_remove_or_wear(you.inv[item_slot], false))
+ return (false);
+
// Go ahead and wield the weapon.
- if (you.equip[EQ_WEAPON] != -1)
- unwield_item(show_weff_messages);
+ if (you.equip[EQ_WEAPON] != -1 && !unwield_item(show_weff_messages))
+ return (false);
you.equip[EQ_WEAPON] = item_slot;
@@ -400,6 +409,8 @@ void wield_effects(int item_wield_2, bool showMsgs)
{
unsigned char i_dam = 0;
+ const bool known_cursed = item_known_cursed(you.inv[item_wield_2]);
+
// and here we finally get to the special effects of wielding {dlb}
if (you.inv[item_wield_2].base_type == OBJ_MISCELLANY)
{
@@ -421,6 +432,7 @@ void wield_effects(int item_wield_2, bool showMsgs)
// inc_max_mp(13);
calc_mp();
set_ident_flags( you.inv[item_wield_2], ISFLAG_EQ_WEAPON_MASK );
+ mpr("You feel your mana capacity increase.");
}
else
{
@@ -592,7 +604,11 @@ void wield_effects(int item_wield_2, bool showMsgs)
break;
case SPWPN_DISTORTION:
- miscast_effect( SPTYP_TRANSLOCATION, 9, 90, 100, "a distortion effect" );
+ if (!was_known)
+ xom_is_stimulated(128);
+ miscast_effect( SPTYP_TRANSLOCATION, 9, 90, 100,
+ was_known ? "distortion wield" :
+ "unknowing distortion wield");
break;
case SPWPN_SINGING_SWORD:
@@ -644,7 +660,10 @@ void wield_effects(int item_wield_2, bool showMsgs)
if (item_cursed( you.inv[item_wield_2] ))
{
mpr("It sticks to your hand!");
- xom_is_stimulated(64);
+ if (known_cursed)
+ xom_is_stimulated(32);
+ else
+ xom_is_stimulated(64);
}
}
@@ -710,7 +729,8 @@ void wear_armour(void)
if (!armour_prompt("Wear which item?", &armour_wear_2, OPER_WEAR))
return;
- do_wear_armour( armour_wear_2, false );
+ if (safe_to_remove_or_wear(you.inv[armour_wear_2], false))
+ do_wear_armour( armour_wear_2, false );
}
static int armour_equip_delay(const item_def &item)
@@ -757,8 +777,7 @@ bool can_wear_armour(const item_def &item, bool verbose, bool ignore_temporary)
if (sub_type == ARM_GLOVES)
{
- if (you.species == SP_TROLL || you.species == SP_GHOUL
- || you.mutation[MUT_CLAWS] >= 3)
+ if (you.has_claws(false) >= 3)
{
if (verbose)
mpr( "You can't wear gloves with your huge claws!" );
@@ -776,6 +795,20 @@ bool can_wear_armour(const item_def &item, bool verbose, bool ignore_temporary)
return (false);
}
+ if (you.mutation[MUT_TALONS])
+ {
+ if (verbose)
+ mpr("Boots don't fit your talons!");
+ return (false);
+ }
+
+ if (you.mutation[MUT_PAWS])
+ {
+ if (verbose)
+ mpr("Boots don't fit your paws!");
+ return (false);
+ }
+
if (you.species == SP_NAGA)
{
if (verbose)
@@ -991,6 +1024,9 @@ bool do_wear_armour( int item, bool quiet )
return (false);
}
+ if (!safe_to_remove_or_wear(you.inv[item], false))
+ return (false);
+
you.turn_is_over = true;
int delay = armour_equip_delay( you.inv[item] );
@@ -1024,6 +1060,9 @@ bool takeoff_armour(int item)
}
}
+ if (!safe_to_remove_or_wear(you.inv[item], true))
+ return (false);
+
bool removedCloak = false;
int cloak = -1;
const equipment_type slot = get_armour_slot(you.inv[item]);
@@ -1164,6 +1203,20 @@ static bool fire_item_matches(const item_def &item, unsigned fire_type)
if (!is_valid_item(item))
return (false);
+ if (you.attribute[ATTR_HELD])
+ {
+ if (item.base_type == OBJ_MISSILES)
+ {
+ const item_def *weapon = you.weapon();
+ if (weapon && weapon->sub_type == WPN_BLOWGUN
+ && item.launched_by(*weapon))
+ {
+ return (true);
+ }
+ }
+ return (false);
+ }
+
if (item.base_type == OBJ_MISSILES)
{
if ((fire_type & FIRE_DART) && item.sub_type == MI_DART)
@@ -1474,6 +1527,18 @@ int launcher_final_speed(const item_def &launcher, const item_def *shield)
speed_base = speed_base * speed_adjust / 100;
speed_min = speed_min * speed_adjust / 100;
}
+
+ // do the same when trying to shoot while held in a net
+ if (you.attribute[ATTR_HELD]) // only for blowguns
+ {
+ int speed_adjust = 105; // analogous to buckler and one-handed weapon
+ speed_adjust -= ((speed_adjust - 100) * 5 / 10)
+ * you.skills[SK_THROWING] / 27;
+
+ // also reduce the speed cap.
+ speed_base = speed_base * speed_adjust / 100;
+ speed_min = speed_min * speed_adjust / 100;
+ }
int speed = speed_base - 4 * shoot_skill * speed_stat / 250;
if (speed < speed_min)
@@ -1744,6 +1809,12 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus,
}
}
}
+
+ // lower accuracy if held in a net (needs testing)
+ if (you.attribute[ATTR_HELD])
+ {
+ baseHit--;
+ }
// for all launched weapons, maximum effective specific skill
// is twice throwing skill. This models the fact that no matter
@@ -2006,8 +2077,15 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus,
{
// elves with elven weapons
if (get_equip_race(item) == ISFLAG_ELVEN
- && player_genus(GENPC_ELVEN))
+ && player_genus(GENPC_ELVEN))
baseHit += 1;
+ if ( (get_equip_race(item) == ISFLAG_DWARVEN
+ && player_genus(GENPC_DWARVEN)) ||
+ (get_equip_race(item) == ISFLAG_ORCISH
+ && you.species == SP_HILL_ORC))
+ {
+ baseDam += 1;
+ }
// give an appropriate 'tohit' -
// hand axes and clubs are -5
@@ -2210,7 +2288,7 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus,
pbolt.damage.size += ammoDamBonus + lnchDamBonus;
}
- // Add in bonus (only from Portaled Projectile for now)
+ // Add in bonus (only from Portal Projectile for now)
if (acc_bonus != DEBUG_COOKIE)
pbolt.hit += acc_bonus;
@@ -2285,13 +2363,18 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus,
void jewellery_wear_effects(item_def &item)
{
- item_type_id_state_type ident = ID_TRIED_TYPE;
+ item_type_id_state_type ident = ID_TRIED_TYPE;
+ randart_prop_type fake_rap = RAP_NUM_PROPERTIES;
+ bool learn_pluses = false;
// Randart jewellery shouldn't auto-ID just because the
// base type is known. Somehow the player should still
// be told, preferably by message. (jpeg)
- const bool artefact = is_random_artefact( item );
- const bool identified = fully_identified( item );
+ const bool artefact = is_random_artefact( item );
+ const bool known_pluses = item_ident( item, ISFLAG_KNOW_PLUSES );
+ const bool known_cursed = item_known_cursed( item );
+ const bool known_bad = item_type_known( item )
+ && (item_value( item ) <= 2);
switch (item.sub_type)
{
@@ -2318,11 +2401,12 @@ void jewellery_wear_effects(item_def &item)
{
if (!artefact)
ident = ID_KNOWN_TYPE;
- else if (!identified)
+ else if (!known_pluses)
{
mprf("You feel %s.", item.plus > 0?
"well-protected" : "more vulnerable");
}
+ learn_pluses = true;
}
break;
@@ -2330,7 +2414,9 @@ void jewellery_wear_effects(item_def &item)
if (!you.duration[DUR_INVIS])
{
mpr("You become transparent for a moment.");
- if (!artefact)
+ if (artefact)
+ fake_rap = RAP_INVISIBLE;
+ else
ident = ID_KNOWN_TYPE;
}
break;
@@ -2341,32 +2427,39 @@ void jewellery_wear_effects(item_def &item)
{
if (!artefact)
ident = ID_KNOWN_TYPE;
- else if (!identified)
+ else if (!known_pluses)
mprf("You feel %s.", item.plus > 0? "nimbler" : "more awkward");
+ learn_pluses = true;
}
break;
case RING_STRENGTH:
- modify_stat(STAT_STRENGTH, item.plus, !artefact);
+ modify_stat(STAT_STRENGTH, item.plus, !artefact, item);
if (item.plus != 0 && !artefact)
ident = ID_KNOWN_TYPE;
+ learn_pluses = true;
break;
case RING_DEXTERITY:
- modify_stat(STAT_DEXTERITY, item.plus, !artefact);
+ modify_stat(STAT_DEXTERITY, item.plus, !artefact, item);
if (item.plus != 0 && !artefact)
ident = ID_KNOWN_TYPE;
+ learn_pluses = true;
break;
case RING_INTELLIGENCE:
- modify_stat(STAT_INTELLIGENCE, item.plus, !artefact);
+ modify_stat(STAT_INTELLIGENCE, item.plus, !artefact, item);
if (item.plus != 0 && !artefact)
ident = ID_KNOWN_TYPE;
+ learn_pluses = true;
break;
case RING_MAGICAL_POWER:
+ mpr("You feel your mana capacity increase.");
calc_mp();
- if (!artefact)
+ if (artefact)
+ fake_rap = RAP_MAGICAL_POWER;
+ else
ident = ID_KNOWN_TYPE;
break;
@@ -2374,7 +2467,9 @@ void jewellery_wear_effects(item_def &item)
if (!scan_randarts( RAP_LEVITATE ))
{
mpr("You feel buoyant.");
- if (!artefact)
+ if (artefact)
+ fake_rap = RAP_LEVITATE;
+ else
ident = ID_KNOWN_TYPE;
}
break;
@@ -2383,7 +2478,9 @@ void jewellery_wear_effects(item_def &item)
if (!scan_randarts( RAP_CAN_TELEPORT ))
{
mpr("You feel slightly jumpy.");
- if (!artefact)
+ if (artefact)
+ fake_rap = RAP_CAUSE_TELEPORTATION;
+ else
ident = ID_KNOWN_TYPE;
}
break;
@@ -2392,7 +2489,9 @@ void jewellery_wear_effects(item_def &item)
if (!scan_randarts( RAP_BERSERK ))
{
mpr("You feel a brief urge to hack something to bits.");
- if (!artefact)
+ if (artefact)
+ fake_rap = RAP_BERSERK;
+ else
ident = ID_KNOWN_TYPE;
}
break;
@@ -2405,19 +2504,33 @@ void jewellery_wear_effects(item_def &item)
// Artefacts have completely different appearance than base types
// so we don't allow them to make the base types known
if (artefact)
+ {
use_randart(item);
+
+ if (learn_pluses && (item.plus != 0 || item.plus2 != 0))
+ set_ident_flags( item, ISFLAG_KNOW_PLUSES );
+
+ if (fake_rap != RAP_NUM_PROPERTIES)
+ randart_wpn_learn_prop( item, fake_rap );
+ }
else
+ {
set_ident_type( item.base_type, item.sub_type, ident );
- if (ident == ID_KNOWN_TYPE)
- set_ident_flags( item, ISFLAG_EQ_JEWELLERY_MASK );
+ if (ident == ID_KNOWN_TYPE)
+ set_ident_flags( item, ISFLAG_EQ_JEWELLERY_MASK );
+ }
if (item_cursed( item ))
{
mprf("Oops, that %s feels deathly cold.",
jewellery_is_amulet(item)? "amulet" : "ring");
learned_something_new(TUT_YOU_CURSED);
- xom_is_stimulated(128);
+
+ if (known_cursed || known_bad)
+ xom_is_stimulated(64);
+ else
+ xom_is_stimulated(128);
}
// cursed or not, we know that since we've put the ring on
@@ -2467,6 +2580,77 @@ static int prompt_ring_to_remove(int new_ring)
return (you.equip[eqslot]);
}
+// Checks whether a to-be-worn or to-be-removed item affects
+// character stats and whether wearing/removing it could be fatal.
+// If so, warns the player.
+bool safe_to_remove_or_wear(const item_def &item, bool remove)
+{
+ int prop_str = 0;
+ int prop_dex = 0;
+ int prop_int = 0;
+
+ // don't warn when putting on an unknown item
+ if (item.base_type == OBJ_JEWELLERY && item_ident( item, ISFLAG_KNOW_PLUSES ))
+ {
+ switch (item.sub_type)
+ {
+ case RING_STRENGTH:
+ if (item.plus != 0)
+ prop_str = item.plus;
+ break;
+ case RING_DEXTERITY:
+ if (item.plus != 0)
+ prop_dex = item.plus;
+ break;
+ case RING_INTELLIGENCE:
+ if (item.plus != 0)
+ prop_int = item.plus;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (is_random_artefact( item ))
+ {
+ prop_str += randart_known_wpn_property(item, RAP_STRENGTH);
+ prop_int += randart_known_wpn_property(item, RAP_INTELLIGENCE);
+ prop_dex += randart_known_wpn_property(item, RAP_DEXTERITY);
+ }
+
+ if (remove)
+ {
+ std::string prompt = item.base_type == OBJ_WEAPONS ? "Unwield" : "Remov";
+ prompt += "ing this item could be fatal. ";
+ prompt += item.base_type == OBJ_WEAPONS ? "Unwield" : "Remove";
+ prompt += " anyway? ";
+
+ if ((prop_str >= you.strength || prop_int >= you.intel ||
+ prop_dex >= you.dex)
+ && !yesno(prompt.c_str(), false, 'n'))
+ {
+ return (false);
+ }
+ }
+ else // put on
+ {
+ std::string prompt = item.base_type == OBJ_WEAPONS ? "Wield" : "Wear";
+ prompt += "ing this item could be fatal. ";
+ prompt += item.base_type == OBJ_WEAPONS ? "Wield" : "Put on";
+ prompt += " anyway? ";
+
+ if ((-prop_str >= you.strength || -prop_int >= you.intel ||
+ -prop_dex >= you.dex)
+ && !yesno(prompt.c_str(), false, 'n'))
+ {
+ return (false);
+ }
+ }
+
+
+ return (true);
+}
+
// Assumptions:
// you.inv[ring_slot] is a valid ring.
// EQ_LEFT_RING and EQ_RIGHT_RING are both occupied, and ring_slot is not
@@ -2485,7 +2669,10 @@ static bool swap_rings(int ring_slot)
if (!remove_ring(unwanted, false))
return (false);
-
+
+ if (!safe_to_remove_or_wear(you.inv[ring_slot], false))
+ return (false);
+
start_delay(DELAY_JEWELLERY_ON, 1, ring_slot);
return (true);
@@ -2535,12 +2722,18 @@ bool puton_item(int item_slot, bool prompt_finger)
!remove_ring( you.equip[EQ_AMULET], true ))
return false;
+ if (!safe_to_remove_or_wear(you.inv[item_slot], false))
+ return (false);
+
start_delay(DELAY_JEWELLERY_ON, 1, item_slot);
// Assume it's going to succeed.
return (true);
}
+ if (!safe_to_remove_or_wear(you.inv[item_slot], false))
+ return (false);
+
// First ring goes on left hand if we're choosing automatically.
int hand_used = 0;
@@ -2658,15 +2851,15 @@ void jewellery_remove_effects(item_def &item)
break;
case RING_STRENGTH:
- modify_stat(STAT_STRENGTH, -item.plus, true);
+ modify_stat(STAT_STRENGTH, -item.plus, true, item, true);
break;
case RING_DEXTERITY:
- modify_stat(STAT_DEXTERITY, -item.plus, true);
+ modify_stat(STAT_DEXTERITY, -item.plus, true, item, true);
break;
case RING_INTELLIGENCE:
- modify_stat(STAT_INTELLIGENCE, -item.plus, true);
+ modify_stat(STAT_INTELLIGENCE, -item.plus, true, item, true);
break;
case RING_INVISIBILITY:
@@ -2682,6 +2875,7 @@ void jewellery_remove_effects(item_def &item)
break;
case RING_MAGICAL_POWER:
+ mpr("You feel your mana capacity decrease.");
// dec_max_mp(9);
break;
@@ -2806,8 +3000,12 @@ bool remove_ring(int slot, bool announce)
set_ident_flags( you.inv[you.equip[hand_used]], ISFLAG_KNOW_CURSE );
return (false);
}
-
+
ring_wear_2 = you.equip[hand_used];
+
+ if (!safe_to_remove_or_wear(you.inv[ring_wear_2], true))
+ return (false);
+
you.equip[hand_used] = -1;
jewellery_remove_effects(you.inv[ring_wear_2]);
@@ -2881,19 +3079,21 @@ void zap_wand(void)
const bool dangerous = player_in_a_dangerous_place();
if (alreadyknown)
{
- if (wand.sub_type == WAND_TELEPORTATION)
+ switch ( wand.sub_type )
{
+ case WAND_TELEPORTATION:
targ_mode = TARG_ANY;
- }
- else if (wand.sub_type == WAND_HASTING
- || wand.sub_type == WAND_HEALING
- || wand.sub_type == WAND_INVISIBILITY)
- {
+ break;
+
+ case WAND_HASTING:
+ case WAND_HEALING:
+ case WAND_INVISIBILITY:
targ_mode = TARG_FRIEND;
- }
- else
- {
+ break;
+
+ default:
targ_mode = TARG_ENEMY;
+ break;
}
}
@@ -2913,28 +3113,10 @@ void zap_wand(void)
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 = wand.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)
+ const zap_type type_zapped = static_cast<zap_type>(wand.zap());
+ if (wand.sub_type == WAND_RANDOM_EFFECTS)
{
- type_zapped = random2(16);
beam.effect_known = false;
- if (one_chance_in(20))
- type_zapped = ZAP_NEGATIVE_ENERGY;
- if (one_chance_in(17))
- type_zapped = ZAP_ENSLAVEMENT;
if (dangerous)
{
// Xom loves it when you use a Wand of Random Effects and
@@ -2947,6 +3129,7 @@ void zap_wand(void)
beam.source_y = you.y_pos;
beam.set_target(zap_wand);
+ // zapping() updates beam
zapping( static_cast<zap_type>(type_zapped),
30 + roll_dice(2, you.skills[SK_EVOCATIONS]), beam );
@@ -2975,7 +3158,8 @@ void zap_wand(void)
{
if (!item_ident( wand, ISFLAG_KNOW_PLUSES ))
{
- mpr("Your skill with magical items lets you calculate the power of this device...");
+ mpr("Your skill with magical items lets you calculate "
+ "the power of this device...");
}
mprf("This wand has %d charge%s left.",
@@ -3053,7 +3237,7 @@ void drink(void)
return;
}
- if (inv_count() < 1)
+ if (inv_count() == 0)
{
canned_msg(MSG_NOTHING_CARRIED);
return;
@@ -3189,7 +3373,10 @@ bool drink_fountain()
if (one_chance_in(10))
gone_dry = true;
else if ( random2(50) > 40 ) // no message!
+ {
grd[you.x_pos][you.y_pos] = DNGN_BLUE_FOUNTAIN;
+ set_terrain_changed(you.x_pos, you.y_pos);
+ }
}
if (gone_dry)
@@ -3199,6 +3386,10 @@ bool drink_fountain()
grd[you.x_pos][you.y_pos] = DNGN_DRY_FOUNTAIN_I;
else
grd[you.x_pos][you.y_pos] = DNGN_DRY_FOUNTAIN_II;
+
+ set_terrain_changed(you.x_pos, you.y_pos);
+
+ crawl_state.cancel_cmd_repeat();
}
you.turn_is_over = true;
@@ -3268,8 +3459,8 @@ static bool affix_weapon_enchantment()
success = false;
// is only naughty if you know you're doing it
- if (get_ident_type(OBJ_SCROLLS, SCR_ENCHANT_WEAPON_III)==ID_KNOWN_TYPE)
- did_god_conduct(DID_UNHOLY, 10);
+ did_god_conduct(DID_UNHOLY, 10,
+ get_ident_type(OBJ_SCROLLS, SCR_ENCHANT_WEAPON_III)==ID_KNOWN_TYPE);
break;
@@ -3280,7 +3471,7 @@ static bool affix_weapon_enchantment()
// from unwield_item
miscast_effect( SPTYP_TRANSLOCATION, 9, 90, 100,
- "a distortion effect" );
+ "distortion affixation" );
success = false;
break;
@@ -3295,7 +3486,7 @@ static bool affix_weapon_enchantment()
return (success);
}
-bool enchant_weapon( int which_stat, bool quiet )
+bool enchant_weapon( enchant_stat_type which_stat, bool quiet )
{
const int wpn = you.equip[ EQ_WEAPON ];
bool affected = true;
@@ -3489,20 +3680,17 @@ static bool enchant_armour( void )
static void handle_read_book( int item_slot )
{
- int spell, spell_index;
+ item_def& book(you.inv[item_slot]);
- if (you.inv[item_slot].sub_type == BOOK_DESTRUCTION)
+ if (book.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);
+ else
+ tome_of_power(item_slot);
return;
}
- else if (you.inv[item_slot].sub_type == BOOK_MANUAL)
+ else if (book.sub_type == BOOK_MANUAL)
{
skill_manual(item_slot);
return;
@@ -3511,25 +3699,23 @@ static void handle_read_book( int item_slot )
while (true)
{
// Spellbook
- spell = read_book( you.inv[item_slot], RBOOK_READ_SPELL );
+ const int ltr = read_book( book, RBOOK_READ_SPELL );
- if (spell < 'a' || spell > 'h') //jmf: was 'g', but 8=h
+ if (ltr < 'a' || ltr > 'h') //jmf: was 'g', but 8=h
{
mesclr( true );
return;
}
- spell_index = letter_to_index( spell );
-
- const spell_type nthing =
- which_spell_in_book(you.inv[item_slot].sub_type, spell_index);
- if (nthing == SPELL_NO_SPELL)
+ const spell_type spell = which_spell_in_book(book.sub_type,
+ letter_to_index(ltr));
+ if (spell == SPELL_NO_SPELL)
{
mesclr( true );
return;
}
- describe_spell( nthing );
+ describe_spell( spell );
}
}
@@ -3574,6 +3760,7 @@ void read_scroll(void)
if (scroll.base_type != OBJ_BOOKS && scroll.base_type != OBJ_SCROLLS)
{
mpr("You can't read that!");
+ crawl_state.zero_turns_taken();
return;
}
@@ -3587,6 +3774,7 @@ void read_scroll(void)
if (silenced(you.x_pos, you.y_pos))
{
mpr("Magic scrolls do not work when you're silenced!");
+ crawl_state.zero_turns_taken();
return;
}
@@ -3689,10 +3877,11 @@ void read_scroll(void)
}
break;
- case SCR_FORGETFULNESS:
- mpr("You feel momentarily disoriented.");
- if (!wearing_amulet(AMU_CLARITY))
- forget_map(50 + random2(50));
+ case SCR_FOG:
+ mpr("The scroll dissolves into smoke.");
+ big_cloud( one_chance_in(20) ? CLOUD_POISON :
+ (one_chance_in(19) ? CLOUD_STEAM : random_smoke_type()),
+ KC_YOU, you.x_pos, you.y_pos, 50, 8 + random2(8));
break;
case SCR_MAGIC_MAPPING:
@@ -3714,8 +3903,7 @@ void read_scroll(void)
torment( TORMENT_SCROLL, you.x_pos, you.y_pos );
// is only naughty if you know you're doing it
- if (item_type_known(scroll))
- did_god_conduct(DID_UNHOLY, 10);
+ did_god_conduct(DID_UNHOLY, 10, item_type_known(scroll));
break;
case SCR_IMMOLATION:
@@ -3737,6 +3925,9 @@ void read_scroll(void)
beam.ex_size = 2;
beam.is_explosion = true;
+ if (!alreadyknown)
+ beam.effect_known = false;
+
explosion(beam);
break;
@@ -3788,7 +3979,6 @@ void read_scroll(void)
case SCR_ENCHANT_WEAPON_III:
if (you.equip[ EQ_WEAPON ] != -1)
{
-
// Successfully affixing the enchantment will print
// its own message.
if (!affix_weapon_enchantment())
@@ -3898,6 +4088,7 @@ void read_scroll(void)
do_curse_item( item );
}
break;
+
} // end switch
// finally, destroy and identify the scroll
@@ -3943,62 +4134,96 @@ void use_randart(unsigned char item_wield_2)
use_randart( you.inv[ item_wield_2 ] );
}
-void use_randart(const item_def &item)
+void use_randart(item_def &item)
{
+#define unknown_proprt(prop) (proprt[(prop)] && !known[(prop)])
+
ASSERT( is_random_artefact( item ) );
const bool alreadyknown = item_type_known(item);
const bool dangerous = player_in_a_dangerous_place();
- const bool ident = fully_identified(item);
- randart_properties_t proprt;
- randart_wpn_properties( item, proprt );
+ randart_properties_t proprt;
+ randart_known_props_t known;
+ randart_wpn_properties( item, proprt, known );
- // Give messages for stat changes, possibly only if !identified
+ // Only give property messages for previously unknown properties.
if (proprt[RAP_AC])
{
- you.redraw_armour_class = 1;
- if (!ident)
+ you.redraw_armour_class = true;
+ if (!known[RAP_AC])
{
mprf("You feel %s.", proprt[RAP_AC] > 0?
"well-protected" : "more vulnerable");
+ randart_wpn_learn_prop(item, RAP_AC);
}
}
if (proprt[RAP_EVASION])
{
- you.redraw_evasion = 1;
- if (!ident)
+ you.redraw_evasion = true;
+ if (!known[RAP_EVASION])
{
mprf("You feel somewhat %s.", proprt[RAP_EVASION] > 0?
"nimbler" : "more awkward");
+ randart_wpn_learn_prop(item, RAP_EVASION);
+ }
+ }
+
+ if (proprt[RAP_MAGICAL_POWER])
+ {
+ you.redraw_magic_points = true;
+ if (!known[RAP_MAGICAL_POWER])
+ {
+ mprf("You feel your mana capacity %s.",
+ proprt[RAP_MAGICAL_POWER] > 0? "increase" : "decrease");
+ randart_wpn_learn_prop(item, RAP_MAGICAL_POWER);
}
}
// modify ability scores
// output result even when identified (because of potential fatality)
- modify_stat( STAT_STRENGTH, proprt[RAP_STRENGTH], false );
- modify_stat( STAT_INTELLIGENCE, proprt[RAP_INTELLIGENCE], false );
- modify_stat( STAT_DEXTERITY, proprt[RAP_DEXTERITY], false );
+ modify_stat( STAT_STRENGTH, proprt[RAP_STRENGTH], false, item );
+ modify_stat( STAT_INTELLIGENCE, proprt[RAP_INTELLIGENCE], false, item );
+ modify_stat( STAT_DEXTERITY, proprt[RAP_DEXTERITY], false, item );
+
+ const randart_prop_type stat_props[3] =
+ {RAP_STRENGTH, RAP_INTELLIGENCE, RAP_DEXTERITY};
+ for (int i = 0; i < 3; i++)
+ if (unknown_proprt(stat_props[i]))
+ randart_wpn_learn_prop(item, stat_props[i]);
// For evokable stuff, check whether other equipped items yield
- // the same ability. If not, give a message.
- // Do NOT give all these messages if the randart is identified.
- if (!ident)
+ // the same ability. If not, and if the ability granted hasn't
+ // already been discovered, give a message.
+ if (unknown_proprt(RAP_LEVITATE)
+ && !items_give_ability(item.link, RAP_LEVITATE))
{
- if (proprt[RAP_LEVITATE] && !items_give_ability(item.link, RAP_LEVITATE))
- mpr("You feel buoyant.");
+ mpr("You feel buoyant.");
+ randart_wpn_learn_prop(item, RAP_LEVITATE);
+ }
- if (proprt[RAP_INVISIBLE] && !you.duration[DUR_INVIS])
- mpr("You become transparent for a moment.");
+ if (unknown_proprt(RAP_INVISIBLE) && !you.duration[DUR_INVIS])
+ {
+ mpr("You become transparent for a moment.");
+ randart_wpn_learn_prop(item, RAP_INVISIBLE);
+ }
- if (proprt[RAP_CAN_TELEPORT] && !items_give_ability(item.link, RAP_CAN_TELEPORT))
- mpr("You feel slightly jumpy.");
+ if (unknown_proprt(RAP_CAN_TELEPORT)
+ && !items_give_ability(item.link, RAP_CAN_TELEPORT))
+ {
+ mpr("You feel slightly jumpy.");
+ randart_wpn_learn_prop(item, RAP_CAN_TELEPORT);
+ }
- if (proprt[RAP_BERSERK] && !items_give_ability(item.link, RAP_BERSERK))
- mpr("You feel a brief urge to hack something to bits.");
+ if (unknown_proprt(RAP_BERSERK)
+ && !items_give_ability(item.link, RAP_BERSERK))
+ {
+ mpr("You feel a brief urge to hack something to bits.");
+ randart_wpn_learn_prop(item, RAP_BERSERK);
}
+
if (proprt[RAP_NOISES])
you.special_wield = SPWLD_NOISE;
@@ -4008,6 +4233,7 @@ void use_randart(const item_def &item)
// there is a dangerous monster nearby...
xom_is_stimulated(255);
}
+#undef unknown_proprt
}
bool wearing_slot(int inv_slot)
diff --git a/crawl-ref/source/item_use.h b/crawl-ref/source/item_use.h
index b3c5063cfe..cc514d17d1 100644
--- a/crawl-ref/source/item_use.h
+++ b/crawl-ref/source/item_use.h
@@ -20,6 +20,12 @@
#include "externs.h"
#include "enum.h"
+enum enchant_stat_type
+{
+ ENCHANT_TO_HIT,
+ ENCHANT_TO_DAM
+};
+
enum fire_type
{
FIRE_NONE = 0x0000,
@@ -62,6 +68,8 @@ void drink(void);
bool elemental_missile_beam(int launcher_brand, int ammo_brand);
+bool safe_to_remove_or_wear(const item_def &item, bool remove);
+
// last updated 12may2000 {dlb}
/* ***********************************************************************
* called from: acr
@@ -153,11 +161,11 @@ void wield_effects(int item_wield_2, bool showMsgs);
* called from: delay.cc item_use.cc it_use2.cc
* *********************************************************************** */
void use_randart( unsigned char item_wield_2 );
-void use_randart(const item_def &item);
+void use_randart(item_def &item);
bool puton_item(int slot, bool prompt_finger = true);
-bool enchant_weapon( int which_stat, bool quiet = false );
+bool enchant_weapon( enchant_stat_type which_stat, bool quiet = false );
bool throw_it(bolt &pbolt, int throw_2, bool teleport=false, int acc_bonus=0,
dist *target = NULL);
diff --git a/crawl-ref/source/itemname.cc b/crawl-ref/source/itemname.cc
index efb6c64895..0ca583f975 100644
--- a/crawl-ref/source/itemname.cc
+++ b/crawl-ref/source/itemname.cc
@@ -73,14 +73,16 @@ std::string quant_name( const item_def &item, int quant,
std::string item_def::name(description_level_type descrip,
bool terse, bool ident,
bool with_inscription,
- bool quantity_words) const
+ bool quantity_words,
+ unsigned long ignore_flags) const
{
if (descrip == DESC_NONE)
return ("");
std::ostringstream buff;
- const std::string auxname = this->name_aux(descrip, terse, ident);
+ const std::string auxname = this->name_aux(descrip, terse, ident,
+ ignore_flags);
const bool startvowel = is_vowel(auxname[0]);
if (descrip == DESC_INVENTORY_EQUIP || descrip == DESC_INVENTORY)
@@ -530,7 +532,7 @@ static const char* scroll_type_name(int scrolltype)
case SCR_BLINKING: return "blinking";
case SCR_PAPER: return "paper";
case SCR_MAGIC_MAPPING: return "magic mapping";
- case SCR_FORGETFULNESS: return "forgetfulness";
+ case SCR_FOG: return "fog";
case SCR_ACQUIREMENT: return "acquirement";
case SCR_ENCHANT_WEAPON_II: return "enchant weapon II";
case SCR_VORPALISE_WEAPON: return "vorpalise weapon";
@@ -952,7 +954,8 @@ static void output_with_sign(std::ostream& os, int val)
// Note that "terse" is only currently used for the "in hand" listing on
// the game screen.
std::string item_def::name_aux( description_level_type desc,
- bool terse, bool ident ) const
+ bool terse, bool ident,
+ unsigned long ignore_flags) const
{
// Shortcuts
const int item_typ = this->sub_type;
@@ -963,14 +966,20 @@ std::string item_def::name_aux( description_level_type desc,
const bool qualname = desc == DESC_QUALNAME;
const bool know_curse =
- !basename && !qualname
+ !basename && !qualname && !testbits(ignore_flags, ISFLAG_KNOW_CURSE)
&& (ident || item_ident(*this, ISFLAG_KNOW_CURSE));
const bool know_type = ident || item_type_known(*this);
- const bool know_pluses =
+ const bool __know_pluses =
!basename && !qualname
&& (ident || item_ident(*this, ISFLAG_KNOW_PLUSES));
+ const bool know_cosmetic = !__know_pluses && !terse & !basename;
+
+ // So that know_cosmetic won't be affected by ignore_flags
+ const bool know_pluses = __know_pluses
+ && !testbits(ignore_flags, ISFLAG_KNOW_PLUSES);
+
bool need_plural = true;
int brand;
@@ -1021,15 +1030,17 @@ std::string item_def::name_aux( description_level_type desc,
// 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 (!know_pluses && !terse && !basename)
+ if (know_cosmetic)
{
switch (get_equip_desc( *this ))
{
case ISFLAG_RUNED:
- buff << "runed ";
+ if (!testbits(ignore_flags, ISFLAG_RUNED))
+ buff << "runed ";
break;
case ISFLAG_GLOWING:
- buff << "glowing ";
+ if (!testbits(ignore_flags, ISFLAG_GLOWING))
+ buff << "glowing ";
break;
}
}
@@ -1126,11 +1137,13 @@ std::string item_def::name_aux( description_level_type desc,
// 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 (!know_pluses && !terse & !basename)
+ if (know_cosmetic)
{
switch (get_equip_desc( *this ))
{
case ISFLAG_EMBROIDERED_SHINY:
+ if (testbits(ignore_flags, ISFLAG_EMBROIDERED_SHINY))
+ break;
if (item_typ == ARM_ROBE || item_typ == ARM_CLOAK
|| item_typ == ARM_GLOVES || item_typ == ARM_BOOTS)
{
@@ -1144,11 +1157,13 @@ std::string item_def::name_aux( description_level_type desc,
break;
case ISFLAG_RUNED:
- buff << "runed ";
+ if (!testbits(ignore_flags, ISFLAG_RUNED))
+ buff << "runed ";
break;
case ISFLAG_GLOWING:
- buff << "glowing ";
+ if (!testbits(ignore_flags, ISFLAG_GLOWING))
+ buff << "glowing ";
break;
}
}
@@ -1382,15 +1397,41 @@ std::string item_def::name_aux( description_level_type desc,
buff << "deck of cards";
break;
}
+ else if (bad_deck(*this))
+ {
+ buff << "BUGGY deck of cards";
+ break;
+ }
buff << deck_rarity_name(deck_rarity(*this)) << ' ';
}
buff << misc_type_name(item_typ, know_type);
- if ( is_deck(*this) && item_plus2 != 0 )
+ if ( is_deck(*this)
+ && (top_card_is_known(*this) || this->plus2 != 0))
{
- // an inscribed deck!
- buff << " {"
- << card_name(static_cast<card_type>(item_plus2 - 1))
- << "}";
+ buff << " {";
+ // A marked deck!
+ if (top_card_is_known(*this))
+ buff << card_name(top_card(*this));
+
+ // How many cards have been drawn, or how many are
+ // left.
+ if (this->plus2 != 0)
+ {
+ if(top_card_is_known(*this))
+ buff << ", ";
+
+ buff << abs(this->plus2) << " card";
+
+ if (abs(this->plus2) > 1)
+ buff << "s";
+
+ if (this->plus2 > 0)
+ buff << " drawn";
+ else
+ buff << " left";
+ }
+
+ buff << "}";
}
}
break;
@@ -1400,7 +1441,7 @@ std::string item_def::name_aux( description_level_type desc,
{
buff << book_secondary_string(this->special / 10)
<< book_primary_string(this->special % 10)
- << "book";
+ << (item_typ == BOOK_MANUAL ? "manual" : "book");
}
else if (item_typ == BOOK_MANUAL)
buff << "manual of " << skill_name(it_plus);
@@ -1564,6 +1605,15 @@ bool item_type_known( const item_def& item )
return false;
}
+bool item_type_known(const object_class_type base_type, const int sub_type)
+{
+ const item_type_id_type idt = objtype_to_idtype(base_type);
+ if ( idt != NUM_IDTYPE && sub_type < 50 )
+ return ( type_ids[idt][sub_type] == ID_KNOWN_TYPE );
+ else
+ return false;
+}
+
bool item_type_tried( const item_def& item )
{
if ( item_type_known(item) )
diff --git a/crawl-ref/source/itemname.h b/crawl-ref/source/itemname.h
index d0b47d9c0a..a885693cf5 100644
--- a/crawl-ref/source/itemname.h
+++ b/crawl-ref/source/itemname.h
@@ -94,6 +94,7 @@ std::string quant_name( const item_def &item, int quant,
description_level_type des, bool terse = false );
bool item_type_known( const item_def &item );
+bool item_type_known( const object_class_type base_type, const int sub_type );
bool item_type_tried( const item_def &item );
bool is_interesting_item( const item_def& item );
diff --git a/crawl-ref/source/itemprop.cc b/crawl-ref/source/itemprop.cc
index e8414d7e53..d17b970966 100644
--- a/crawl-ref/source/itemprop.cc
+++ b/crawl-ref/source/itemprop.cc
@@ -37,6 +37,7 @@
#include "stuff.h"
#include "transfor.h"
#include "view.h"
+#include "xom.h"
// XXX: name strings in most of the following are currently unused!
@@ -445,6 +446,26 @@ bool item_known_uncursed( const item_def &item )
void do_curse_item( item_def &item )
{
+ // Xom is amused by the player's items being cursed, especially
+ // if they're worn/equipped.
+ if (!(item.flags & ISFLAG_CURSED) && item.x == -1 && item.y == -1)
+ {
+ int amusement = 64;
+
+ if (item_is_equipped(item))
+ {
+ amusement *= 2;
+
+ // Cursed cloaks prevent you from removing body armour
+ if (item.base_type == OBJ_ARMOUR
+ && get_armour_slot(item) == EQ_CLOAK)
+ {
+ amusement *= 2;
+ }
+ }
+ xom_is_stimulated(amusement);
+ }
+
item.flags |= ISFLAG_CURSED;
}
@@ -531,6 +552,7 @@ unsigned long full_ident_mask( const item_def& item )
switch ( item.base_type )
{
case OBJ_FOOD:
+ case OBJ_CORPSES:
flagset = 0;
break;
case OBJ_MISCELLANY:
@@ -1073,6 +1095,22 @@ bool check_armour_shape( const item_def &item, bool quiet )
return (false);
}
+ if (you.mutation[MUT_TALONS])
+ {
+ if (!quiet)
+ mpr("Boots don't fit your talons!");
+
+ return (false);
+ }
+
+ if (you.mutation[MUT_PAWS])
+ {
+ if (!quiet)
+ mpr("Boots don't fit your paws!");
+
+ return (false);
+ }
+
switch (you.species)
{
case SP_NAGA:
@@ -1095,16 +1133,6 @@ bool check_armour_shape( const item_def &item, bool quiet )
}
break;
- case SP_KENKU:
- if (!quiet)
- {
- if (item.sub_type == ARM_BOOTS)
- mpr( "Boots don't fit your feet!" );
- else
- mpr( "You can't wear barding!" );
- }
- return (false);
-
case SP_MERFOLK:
if (player_in_water() && item.sub_type == ARM_BOOTS)
{
@@ -1123,14 +1151,6 @@ bool check_armour_shape( const item_def &item, bool quiet )
return (false);
}
-
- if (you.mutation[MUT_HOOVES])
- {
- if (!quiet)
- mpr( "You can't wear boots with hooves!" );
-
- return (false);
- }
break;
}
break;
@@ -1159,7 +1179,7 @@ bool check_armour_shape( const item_def &item, bool quiet )
break;
case EQ_GLOVES:
- if (you.mutation[MUT_CLAWS] >= 3)
+ if (you.has_claws(false) >= 3)
{
if (!quiet)
mpr( "You can't wear gloves with your huge claws!" );
@@ -1984,7 +2004,7 @@ bool gives_ability( const item_def &item )
}
case OBJ_JEWELLERY:
{
- if (item.sub_type < NUM_RINGS)
+ if ( !jewellery_is_amulet(item))
{
// unworn ring
item_def *lring = you.slot_item(EQ_LEFT_RING);
@@ -2036,8 +2056,8 @@ bool gives_ability( const item_def &item )
// check for evokable randart properties
for (int rap = RAP_INVISIBLE; rap <= RAP_MAPPING; rap++)
{
- if (randart_wpn_property( item, rap ))
- return true;
+ if (randart_wpn_property( item, static_cast<randart_prop_type>(rap) ))
+ return true;
}
return false;
@@ -2137,11 +2157,11 @@ bool gives_resistance( const item_def &item )
// check for randart resistances
for (int rap = RAP_FIRE; rap <= RAP_CAN_TELEPORT; rap++)
{
- if (rap == RAP_MAGIC || rap >= RAP_INVISIBLE && rap != RAP_CAN_TELEPORT)
- continue;
-
- if (randart_wpn_property( item, rap ))
- return true;
+ if (rap == RAP_MAGIC || rap >= RAP_INVISIBLE && rap != RAP_CAN_TELEPORT)
+ continue;
+
+ if (randart_wpn_property( item, static_cast<randart_prop_type>(rap) ))
+ return true;
}
return false;
diff --git a/crawl-ref/source/itemprop.h b/crawl-ref/source/itemprop.h
index 61c4cbe41d..07848add5e 100644
--- a/crawl-ref/source/itemprop.h
+++ b/crawl-ref/source/itemprop.h
@@ -119,7 +119,7 @@ enum brand_type // equivalent to (you.inv[].special or mitm[].special) % 30
SPWPN_KNIFE_OF_ACCURACY,
SPWPN_STAFF_OF_OLGREB,
SPWPN_VAMPIRES_TOOTH,
- SPWPN_STAFF_OF_WUCAD_MU // 195
+ SPWPN_STAFF_OF_WUCAD_MU // 195, must be last (see randart.cc)
};
enum corpse_type
@@ -310,7 +310,7 @@ enum scroll_type
SCR_BLINKING,
SCR_PAPER, // 15
SCR_MAGIC_MAPPING,
- SCR_FORGETFULNESS,
+ SCR_FOG,
SCR_ACQUIREMENT,
SCR_ENCHANT_WEAPON_II,
SCR_VORPALISE_WEAPON, // 20
@@ -339,12 +339,7 @@ enum special_armour_type
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}
+ SPARM_PRESERVATION // 18
};
enum special_missile_type // to separate from weapons in general {dlb}
@@ -529,7 +524,8 @@ enum vorpal_damage_type
};
// 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().
+// and there are bits of the code that still use that fact.
+// See item_def::zap().
enum wand_type // mitm[].subtype
{
WAND_FLAME, // 0
diff --git a/crawl-ref/source/items.cc b/crawl-ref/source/items.cc
index 2067fde798..a54bf66b49 100644
--- a/crawl-ref/source/items.cc
+++ b/crawl-ref/source/items.cc
@@ -34,6 +34,7 @@
#include "externs.h"
#include "beam.h"
+#include "branch.h"
#include "cloud.h"
#include "debug.h"
#include "delay.h"
@@ -68,10 +69,12 @@
#include "spl-util.h"
#include "stuff.h"
#include "stash.h"
+#include "state.h"
#include "terrain.h"
#include "transfor.h"
#include "tutorial.h"
#include "view.h"
+#include "xom.h"
static bool invisible_to_player( const item_def& item );
static void item_list_on_square( std::vector<const item_def*>& items,
@@ -156,6 +159,8 @@ static bool item_ok_to_clean(int item)
// unsuccessful cleanup (should be exceedingly rare!)
int cull_items(void)
{
+ crawl_state.cancel_cmd_repeat();
+
// 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 );
@@ -259,8 +264,15 @@ bool dec_inv_item_quantity( int obj, int amount )
you.inv[obj].base_type = OBJ_UNASSIGNED;
you.inv[obj].quantity = 0;
+ you.inv[obj].props.clear();
ret = true;
+
+ // If we're repeating a command, the repetitions used up the
+ // item stack being repeated on, so stop rather than move onto
+ // the next stack.
+ crawl_state.cancel_cmd_repeat();
+ crawl_state.cancel_cmd_again();
}
else
{
@@ -278,8 +290,19 @@ bool dec_inv_item_quantity( int obj, int amount )
bool dec_mitm_item_quantity( int obj, int amount )
{
if (mitm[obj].quantity <= amount)
+ amount = mitm[obj].quantity;
+
+ if (player_in_branch(BRANCH_HALL_OF_ZOT) && is_rune(mitm[obj]))
+ you.attribute[ATTR_RUNES_IN_ZOT] -= amount;
+
+ if (mitm[obj].quantity == amount)
{
destroy_item( obj );
+ // If we're repeating a command, the repetitions used up the
+ // item stack being repeated on, so stop rather than move onto
+ // the next stack.
+ crawl_state.cancel_cmd_repeat();
+ crawl_state.cancel_cmd_again();
return (true);
}
@@ -299,6 +322,9 @@ void inc_inv_item_quantity( int obj, int amount )
void inc_mitm_item_quantity( int obj, int amount )
{
+ if (player_in_branch(BRANCH_HALL_OF_ZOT) && is_rune(mitm[obj]))
+ you.attribute[ATTR_RUNES_IN_ZOT] += amount;
+
mitm[obj].quantity += amount;
}
@@ -437,6 +463,7 @@ void unlink_item( int dest )
mitm[dest].x = 0;
mitm[dest].y = 0;
mitm[dest].link = NON_ITEM;
+ mitm[dest].props.clear();
// Look through all items for links to this item.
for (c = 0; c < MAX_ITEMS; c++)
@@ -506,7 +533,53 @@ void destroy_item( int dest, bool never_created )
mitm[dest].clear();
}
-void destroy_item_stack( int x, int y )
+static void handle_gone_item(const item_def &item)
+{
+ if (you.level_type == LEVEL_ABYSS
+ && place_type(item.orig_place) == LEVEL_ABYSS
+ && !(item.flags & ISFLAG_BEEN_IN_INV))
+ {
+ if (item.base_type == OBJ_ORBS)
+ set_unique_item_status(OBJ_ORBS, item.sub_type,
+ UNIQ_LOST_IN_ABYSS);
+ else if (is_fixed_artefact(item))
+ set_unique_item_status(OBJ_WEAPONS, item.special,
+ UNIQ_LOST_IN_ABYSS);
+ }
+
+ if (is_rune(item))
+ {
+ if ((item.flags & ISFLAG_BEEN_IN_INV))
+ {
+ if (is_unique_rune(item))
+ you.attribute[ATTR_UNIQUE_RUNES] -= item.quantity;
+ else if (item.plus == RUNE_ABYSSAL)
+ you.attribute[ATTR_ABYSSAL_RUNES] -= item.quantity;
+ else
+ you.attribute[ATTR_DEMONIC_RUNES] -= item.quantity;
+ }
+
+ if (player_in_branch(BRANCH_HALL_OF_ZOT)
+ && item.x != -1 && item.y != -1)
+ {
+ you.attribute[ATTR_RUNES_IN_ZOT] -= item.quantity;
+ }
+ }
+}
+
+void item_was_lost(const item_def &item)
+{
+ handle_gone_item( item );
+ xom_check_lost_item( item );
+}
+
+void item_was_destroyed(const item_def &item, int cause)
+{
+ handle_gone_item( item );
+ xom_check_destroyed_item( item, cause );
+}
+
+void lose_item_stack( int x, int y )
{
int o = igrd[x][y];
@@ -518,19 +591,34 @@ void destroy_item_stack( int x, int y )
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 );
- }
+ item_was_lost(mitm[o]);
mitm[o].base_type = OBJ_UNASSIGNED;
mitm[o].quantity = 0;
+ mitm[o].props.clear();
+ }
+
+ o = next;
+ }
+}
+
+void destroy_item_stack( int x, int y, int cause )
+{
+ 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] ))
+ {
+ item_was_destroyed(mitm[o], cause);
+
+ mitm[o].base_type = OBJ_UNASSIGNED;
+ mitm[o].quantity = 0;
+ mitm[o].props.clear();
}
o = next;
@@ -626,12 +714,16 @@ static int item_name_specialness(const item_def& item)
std::string itname = item.name(DESC_PLAIN, false, false, false);
lowercase(itname);
+ // FIXME Maybe we should replace this with a test of ISFLAG_COSMETIC_MASK?
const bool item_runed = itname.find("runed ") != std::string::npos;
const bool heav_runed = itname.find("heavily ") != std::string::npos;
const bool item_glows = itname.find("glowing") != std::string::npos;
- if ( item_glows || (item_runed && !heav_runed) )
+ if ( item_glows || (item_runed && !heav_runed) ||
+ get_equip_desc(item) == ISFLAG_EMBROIDERED_SHINY )
+ {
return 1;
+ }
// You can tell artefacts, because they'll have a description which
// rules out anything else.
@@ -943,8 +1035,16 @@ static std::string origin_place_desc(const item_def &item)
bool is_rune(const item_def &item)
{
- return (item.base_type == OBJ_MISCELLANY &&
- item.sub_type == MISC_RUNE_OF_ZOT);
+ return (item.base_type == OBJ_MISCELLANY
+ && item.sub_type == MISC_RUNE_OF_ZOT);
+}
+
+bool is_unique_rune(const item_def &item)
+{
+ return (item.base_type == OBJ_MISCELLANY
+ && item.sub_type == MISC_RUNE_OF_ZOT
+ && item.plus != RUNE_DEMONIC
+ && item.plus != RUNE_ABYSSAL);
}
bool origin_describable(const item_def &item)
@@ -1213,10 +1313,11 @@ bool items_stack( const item_def &item1, const item_def &item2,
return false;
// Check the non-ID flags, but ignore dropped, thrown, cosmetic,
- // and note flags
+ // and note flags. Also, whether item was in inventory before.
#define NON_IDENT_FLAGS ~(ISFLAG_IDENT_MASK | ISFLAG_COSMETIC_MASK | \
ISFLAG_DROPPED | ISFLAG_THROWN | \
- ISFLAG_NOTED_ID | ISFLAG_NOTED_GET)
+ ISFLAG_NOTED_ID | ISFLAG_NOTED_GET | \
+ ISFLAG_BEEN_IN_INV)
if ((item1.flags & NON_IDENT_FLAGS) !=
(item2.flags & NON_IDENT_FLAGS))
{
@@ -1314,6 +1415,25 @@ int find_free_slot(const item_def &i)
#undef slotisfree
}
+static void got_item(item_def& item, int quant)
+{
+ if (!is_rune(item))
+ return;
+
+ // Picking up the rune for the first time.
+ if (!(item.flags & ISFLAG_BEEN_IN_INV))
+ {
+ if (is_unique_rune(item))
+ you.attribute[ATTR_UNIQUE_RUNES] += quant;
+ else if (item.plus == RUNE_ABYSSAL)
+ you.attribute[ATTR_ABYSSAL_RUNES] += quant;
+ else
+ you.attribute[ATTR_DEMONIC_RUNES] += quant;
+ }
+
+ item.flags |= ISFLAG_BEEN_IN_INV;
+}
+
// 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 )
@@ -1390,6 +1510,8 @@ int move_item_to_player( int obj, int quant_got, bool quiet )
dec_mitm_item_quantity( obj, quant_got );
burden_change();
+ got_item(mitm[obj], quant_got);
+
if (!quiet)
mpr( you.inv[m].name(DESC_INVENTORY).c_str() );
@@ -1415,6 +1537,10 @@ int move_item_to_player( int obj, int quant_got, bool quiet )
return (-1);
}
+ coord_def pos(mitm[obj].x, mitm[obj].y);
+ dungeon_events.fire_position_event(
+ dgn_event(DET_ITEM_PICKUP, pos, 0, obj, -1), pos);
+
item_def &item = you.inv[freeslot];
// copy item
item = mitm[obj];
@@ -1450,8 +1576,14 @@ int move_item_to_player( int obj, int quant_got, bool quiet )
if (!quiet)
mpr("Now all you have to do is get back out of the dungeon!");
you.char_direction = GDT_ASCENDING;
+ xom_is_stimulated(255, XM_INTRIGUED);
}
+ if (item.base_type == OBJ_ORBS && you.level_type == LEVEL_DUNGEON)
+ unset_branch_flags(BFLAG_HAS_ORB);
+
+ got_item(item, item.quantity);
+
you.turn_is_over = true;
return (retval);
@@ -1529,6 +1661,17 @@ bool move_item_to_grid( int *const obj, int x, int y )
mitm[*obj].link = igrd[x][y];
igrd[x][y] = *obj;
+ if (is_rune(mitm[*obj]))
+ {
+ if (player_in_branch(BRANCH_HALL_OF_ZOT))
+ you.attribute[ATTR_RUNES_IN_ZOT] += mitm[*obj].quantity;
+ }
+ else if (mitm[*obj].base_type == OBJ_ORBS
+ && you.level_type == LEVEL_DUNGEON)
+ {
+ set_branch_flags(BFLAG_HAS_ORB);
+ }
+
return (true);
}
@@ -1703,6 +1846,8 @@ bool drop_item( int item_dropped, int quant_drop, bool try_offer )
{
if( !silenced(you.pos()) )
mprf(MSGCH_SOUND, grid_item_destruction_message(my_grid));
+
+ item_was_destroyed(you.inv[item_dropped], NON_MONSTER);
}
else if (strstr(you.inv[item_dropped].inscription.c_str(), "=s") != 0)
stashes.add_stash();
@@ -2355,7 +2500,7 @@ void handle_time( long time_delta )
if (one_chance_in(30))
{
mpr("Your disease is taking its toll.", MSGCH_WARN);
- lose_stat(STAT_RANDOM, 1);
+ lose_stat(STAT_RANDOM, 1, false, "disease");
}
}
@@ -2363,7 +2508,7 @@ void handle_time( long time_delta )
if (you.mutation[MUT_DETERIORATION]
&& random2(200) <= you.mutation[MUT_DETERIORATION] * 5 - 2)
{
- lose_stat(STAT_RANDOM, 1);
+ lose_stat(STAT_RANDOM, 1, false, "deterioration mutation");
}
int added_contamination = 0;
@@ -2526,10 +2671,16 @@ void handle_time( long time_delta )
// 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] && !wearing_amulet(AMU_CLARITY) &&
- (random2(100) <= you.mutation[MUT_LOST] * 5) )
- forget_map(5 + random2(you.mutation[MUT_LOST] * 10));
+ if (you.mutation[MUT_SCREAM]
+ && (random2(100) <= 2 + you.mutation[MUT_SCREAM] * 3) )
+ {
+ yell(true);
+ }
+ else if (you.mutation[MUT_SLEEPINESS]
+ && random2(100) < you.mutation[MUT_SLEEPINESS] * 5)
+ {
+ you.put_to_sleep();
+ }
// Update all of the corpses and food chunks on the floor
update_corpses(time_delta);
@@ -2601,42 +2752,43 @@ void handle_time( long time_delta )
//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) ? "The smell of rotting flesh makes you hungry." :
- (temp_rand == 6) ? "You smell decay. Yum-yum."
- : "Wow! There is something tasty in your inventory."),
- MSGCH_ROTTEN_MEAT );
- break;
+ // Races that can't smell don't care, and trolls are stupid and
+ // don't care.
+ if (player_can_smell() && you.species != SP_TROLL)
+ {
+ switch (you.mutation[MUT_SAPROVOROUS])
+ {
+ // level 1 and level 2 saprovores aren't so touchy
+ case 1:
+ case 2:
+ 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;
- 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;
+ // level 3 saprovores like it
+ case 3:
+ temp_rand = random2(8);
+ mpr( ((temp_rand < 5) ? "You smell something rotten." :
+ (temp_rand == 5) ? "The smell of rotting flesh makes you hungry." :
+ (temp_rand == 6) ? "You smell decay. Yum-yum."
+ : "Wow! There is something tasty in your inventory."),
+ MSGCH_ROTTEN_MEAT );
+ break;
- default:
- temp_rand = random2(8);
- mpr( ((temp_rand < 5) ? "You smell something rotten." :
- (temp_rand == 5) ? "The smell of rotting flesh makes you sick." :
- (temp_rand == 6) ? "You smell decay. Yuck!"
- : "Ugh! There is something really disgusting in your inventory."),
- MSGCH_ROTTEN_MEAT );
- break;
+ default:
+ temp_rand = random2(8);
+ mpr( ((temp_rand < 5) ? "You smell something rotten." :
+ (temp_rand == 5) ? "The smell of rotting flesh makes you sick." :
+ (temp_rand == 6) ? "You smell decay. Yuck!"
+ : "Ugh! There is something really disgusting in your inventory."),
+ MSGCH_ROTTEN_MEAT );
+ break;
+ }
}
learned_something_new(TUT_ROTTEN_FOOD);
}
@@ -2802,13 +2954,13 @@ bool can_autopickup()
return (false);
if (you.attribute[ATTR_TRANSFORMATION] == TRAN_AIR
- && you.duration[DUR_TRANSFORMATION] > 0)
+ && you.duration[DUR_TRANSFORMATION] > 0)
return (false);
if (you.flight_mode() == FL_LEVITATE)
return (false);
- if ( Options.safe_autopickup && !i_feel_safe() )
+ if ( !i_feel_safe() )
return (false);
return (true);
@@ -3022,6 +3174,30 @@ item_def find_item_type(object_class_type base_type, std::string name)
return (item);
}
+bool item_is_equipped(const item_def &item)
+{
+ if (item.x != -1 || item.y != -1)
+ return (false);
+
+ for (int i = 0; i < NUM_EQUIP; i++)
+ {
+ if (you.equip[i] == EQ_NONE)
+ continue;
+
+ item_def& eq(you.inv[you.equip[i]]);
+
+ if (!is_valid_item(eq))
+ continue;
+
+ if (eq.slot == item.slot)
+ return (true);
+ else if (&eq == &item)
+ return (true);
+ }
+
+ return (false);
+}
+
////////////////////////////////////////////////////////////////////////
// item_def functions.
@@ -3053,6 +3229,33 @@ bool item_def::launched_by(const item_def &launcher) const
return (sub_type == mt || (mt == MI_STONE && sub_type == MI_SLING_BULLET));
}
+int item_def::zap() const
+{
+ if (base_type != OBJ_WANDS)
+ return ZAP_DEBUGGING_RAY;
+
+ zap_type result;
+ switch (sub_type)
+ {
+ case WAND_ENSLAVEMENT: result = ZAP_ENSLAVEMENT; break;
+ case WAND_DRAINING: result = ZAP_NEGATIVE_ENERGY; break;
+ case WAND_DISINTEGRATION: result = ZAP_DISINTEGRATION; break;
+
+ case WAND_RANDOM_EFFECTS:
+ result = static_cast<zap_type>(random2(16));
+ if ( one_chance_in(20) )
+ result = ZAP_NEGATIVE_ENERGY;
+ if ( one_chance_in(17) )
+ result = ZAP_ENSLAVEMENT;
+ break;
+
+ default:
+ result = static_cast<zap_type>(sub_type);
+ break;
+ }
+ return result;
+}
+
int item_def::index() const
{
return (this - mitm.buffer());
diff --git a/crawl-ref/source/items.h b/crawl-ref/source/items.h
index 8dfcff9a20..1e0d548405 100644
--- a/crawl-ref/source/items.h
+++ b/crawl-ref/source/items.h
@@ -77,7 +77,8 @@ int get_item_slot( int reserve = 50 );
* *********************************************************************** */
void unlink_item(int dest);
void destroy_item(int dest, bool never_created = false);
-void destroy_item_stack( int x, int y );
+void destroy_item_stack( int x, int y, int cause = -1 );
+void lose_item_stack( int x, int y );
// last updated: 08jun2000 {dlb}
/* ***********************************************************************
@@ -164,9 +165,15 @@ void autopickup();
int find_free_slot(const item_def &i);
bool is_rune(const item_def &item);
+bool is_unique_rune(const item_def &item);
bool need_to_autoinscribe();
void request_autoinscribe(bool do_inscribe = true);
void autoinscribe();
+bool item_is_equipped(const item_def &item);
+
+void item_was_lost(const item_def &item);
+void item_was_destroyed(const item_def &item, int cause = -1);
+
#endif
diff --git a/crawl-ref/source/lev-pand.cc b/crawl-ref/source/lev-pand.cc
index 9587135e7a..b2cbc1dee3 100644
--- a/crawl-ref/source/lev-pand.cc
+++ b/crawl-ref/source/lev-pand.cc
@@ -15,6 +15,7 @@
#include "externs.h"
+#include "dungeon.h"
#include "monplace.h"
#include "mon-pick.h"
#include "stuff.h"
@@ -148,6 +149,10 @@ void init_pandemonium(void)
// set at least some specific monsters for the special levels - this
// can also be used to set some colours
+
+ env.floor_colour = BLACK;
+ env.rock_colour = BLACK;
+ dgn_set_colours_from_monsters();
} // end init_pandemonium()
void pandemonium_mons(void)
diff --git a/crawl-ref/source/libdos.cc b/crawl-ref/source/libdos.cc
index 4d05c926ea..ab04e12784 100644
--- a/crawl-ref/source/libdos.cc
+++ b/crawl-ref/source/libdos.cc
@@ -3,7 +3,7 @@
* Summary: Functions for DOS support.
* Written by: Darshan Shaligram
*
- * Added for Crawl Reference by $Author: nlanza $ on $Date: 2006-09-26T03:22:57.300929Z $
+ * Added for Crawl Reference by $Author$ on $Date$
*/
// Every .cc must include AppHdr or bad things happen.
diff --git a/crawl-ref/source/libunix.cc b/crawl-ref/source/libunix.cc
index c4a64a779e..ea2d535469 100644
--- a/crawl-ref/source/libunix.cc
+++ b/crawl-ref/source/libunix.cc
@@ -216,10 +216,13 @@ static void termio_init()
tcsetattr(0, TCSAFLUSH, &game_term);
+ crawl_state.unicode_ok = false;
#ifdef UNICODE_GLYPHS
- if ((crawl_state.unicode_ok = !!setlocale(LC_ALL, UNICODE_LOCALE)))
+ if (setlocale(LC_ALL, UNICODE_LOCALE)
+ && !strcmp(nl_langinfo(CODESET), "UTF-8"))
{
- crawl_state.glyph2strfn = unix_glyph2string;
+ crawl_state.unicode_ok = true;
+ crawl_state.glyph2strfn = unix_glyph2string;
crawl_state.multibyte_strlen = unix_multibyte_strlen;
}
#endif
@@ -616,6 +619,11 @@ int cset_adjust(int raw)
void puttext(int x1, int y1, int x2, int y2, const screen_buffer_t *buf)
{
+ const bool will_scroll = (x2 == get_number_of_cols());
+
+ if (will_scroll)
+ scrollok(stdscr, FALSE);
+
for (int y = y1; y <= y2; ++y)
{
gotoxy(x1, y);
@@ -629,6 +637,9 @@ void puttext(int x1, int y1, int x2, int y2, const screen_buffer_t *buf)
}
set_altcharset(false);
update_screen();
+
+ if (will_scroll)
+ scrollok(stdscr, TRUE);
}
// These next four are front functions so that we can reduce
diff --git a/crawl-ref/source/libutil.cc b/crawl-ref/source/libutil.cc
index ed0b640680..d94ba252a8 100644
--- a/crawl-ref/source/libutil.cc
+++ b/crawl-ref/source/libutil.cc
@@ -310,6 +310,9 @@ std::string pluralise(const std::string &name,
return name.substr(0, name.length() - 1) + "es";
else if (ends_with(name, "y"))
return name.substr(0, name.length() - 1) + "ies";
+ else if (ends_with(name, "fe"))
+ // knife -> knives
+ return name.substr(0, name.length() - 2) + "ves";
else if (ends_with(name, "elf") || ends_with(name, "olf"))
// Elf, wolf. Dwarfs can stay dwarfs, if there were dwarfs.
return name.substr(0, name.length() - 1) + "ves";
diff --git a/crawl-ref/source/libutil.h b/crawl-ref/source/libutil.h
index 6ae7bedec4..42102991a4 100644
--- a/crawl-ref/source/libutil.h
+++ b/crawl-ref/source/libutil.h
@@ -132,6 +132,13 @@ inline std::string lowercase_first(std::string s)
return (s);
}
+inline std::string uppercase_first(std::string s)
+{
+ if (s.length())
+ s[0] = toupper(s[0]);
+ return (s);
+}
+
template <typename Z>
std::string comma_separated_line(Z start, Z end,
const std::string &andc = " and ",
diff --git a/crawl-ref/source/libw32c.cc b/crawl-ref/source/libw32c.cc
index e3dac41763..8749f70469 100644
--- a/crawl-ref/source/libw32c.cc
+++ b/crawl-ref/source/libw32c.cc
@@ -136,6 +136,7 @@ void writeChar(char c)
writeChar(' ');
return;
}
+
bool noop = true;
PCHAR_INFO pci;
diff --git a/crawl-ref/source/lua/eat.lua b/crawl-ref/source/lua/eat.lua
index 5a4b11d658..d07cf97fa9 100644
--- a/crawl-ref/source/lua/eat.lua
+++ b/crawl-ref/source/lua/eat.lua
@@ -31,11 +31,7 @@ function chunk_maybe_safe(chunk)
local race = you.race()
if rot then
- return race == "Ghoul"
- or race == "Kobold"
- or race == "Troll"
- or race == "Hill Orc"
- or race == "Ogre"
+ return you.saprovorous() > 0
end
return true
diff --git a/crawl-ref/source/lua/safechnk.lua b/crawl-ref/source/lua/safechnk.lua
index 0fc5fe7c9d..447981f141 100644
--- a/crawl-ref/source/lua/safechnk.lua
+++ b/crawl-ref/source/lua/safechnk.lua
@@ -17,12 +17,8 @@
---------------------------------------------------------------------------
function sc_safechunk(rot, race, mon)
- if race == "Ghoul" then
- return true
- end
-
if rot then
- if race ~= "Kobold" and race ~= "Troll" then
+ if you.saprovorous() < 2 then
return false
end
end
@@ -32,7 +28,7 @@ function sc_safechunk(rot, race, mon)
end
if sc_hcl[mon] or sc_mut[mon] then
- return false
+ return race == "Ghoul"
end
-- Only contaminated and clean chunks remain, in theory. We'll accept
diff --git a/crawl-ref/source/luadgn.cc b/crawl-ref/source/luadgn.cc
index 5099dd9bdd..da053fb639 100644
--- a/crawl-ref/source/luadgn.cc
+++ b/crawl-ref/source/luadgn.cc
@@ -2,25 +2,31 @@
* File: luadgn.cc
* Summary: Dungeon-builder Lua interface.
*
- * Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-06-21T19:20:47.183838Z $
+ * Modified for Crawl Reference by $Author$ on $Date$
*/
#include "AppHdr.h"
#include <sstream>
+#include "branch.h"
#include "clua.h"
+#include "cloud.h"
#include "direct.h"
#include "dungeon.h"
#include "files.h"
#include "initfile.h"
+#include "items.h"
#include "luadgn.h"
#include "mapdef.h"
#include "mapmark.h"
#include "maps.h"
+#include "misc.h"
+#include "spl-util.h"
#include "stuff.h"
#include "tags.h"
#include "terrain.h"
+#include "view.h"
// Lua interpreter for the dungeon builder.
CLua dlua(false);
@@ -430,6 +436,95 @@ static int dgn_tags_remove(lua_State *ls)
PLUARET(string, map->tags.c_str());
}
+static const std::string level_flag_names[] =
+ {"no_tele_control", "not_mappable", "no_magic_map", ""};
+
+static int dgn_lflags(lua_State *ls)
+{
+ MAP(ls, 1, map);
+
+ try
+ {
+ map->level_flags = map_flags::parse(level_flag_names,
+ luaL_checkstring(ls, 2));
+ }
+ catch (const std::string &error)
+ {
+ luaL_argerror(ls, 2, error.c_str());
+ }
+
+ return (0);
+}
+
+static int dgn_change_level_flags(lua_State *ls)
+{
+ map_flags flags;
+
+ try {
+ flags = map_flags::parse(level_flag_names,
+ luaL_checkstring(ls, 1));
+ }
+ catch (const std::string &error)
+ {
+ luaL_argerror(ls, 2, error.c_str());
+ lua_pushboolean(ls, false);
+ return (1);
+ }
+
+ bool silent = lua_toboolean(ls, 2);
+
+ bool changed1 = set_level_flags(flags.flags_set, silent);
+ bool changed2 = unset_level_flags(flags.flags_unset, silent);
+
+ lua_pushboolean(ls, changed1 || changed2);
+
+ return (1);
+}
+
+static const std::string branch_flag_names[] =
+ {"no_tele_control", "not_mappable", "no_magic_map", ""};
+
+static int dgn_bflags(lua_State *ls)
+{
+ MAP(ls, 1, map);
+
+ try {
+ map->branch_flags = map_flags::parse(branch_flag_names,
+ luaL_checkstring(ls, 2));
+ }
+ catch (const std::string &error)
+ {
+ luaL_argerror(ls, 2, error.c_str());
+ }
+
+ return (0);
+}
+
+static int dgn_change_branch_flags(lua_State *ls)
+{
+ map_flags flags;
+
+ try {
+ flags = map_flags::parse(branch_flag_names,
+ luaL_checkstring(ls, 1));
+ }
+ catch (const std::string &error)
+ {
+ luaL_argerror(ls, 2, error.c_str());
+ lua_pushboolean(ls, false);
+ return (1);
+ }
+
+ bool silent = lua_toboolean(ls, 2);
+
+ bool changed1 = set_branch_flags(flags.flags_set, silent);
+ bool changed2 = unset_branch_flags(flags.flags_unset, silent);
+
+ lua_pushboolean(ls, changed1 || changed2);
+
+ return (1);
+}
+
static int dgn_weight(lua_State *ls)
{
MAP(ls, 1, map);
@@ -707,6 +802,15 @@ static int dgn_kitem(lua_State *ls)
return (0);
}
+static int dgn_kmask(lua_State *ls)
+{
+ MAP(ls, 1, map);
+ std::string err = map->add_key_mask(luaL_checkstring(ls, 2));
+ if (!err.empty())
+ luaL_error(ls, err.c_str());
+ return (0);
+}
+
static int dgn_name(lua_State *ls)
{
MAP(ls, 1, map);
@@ -825,18 +929,152 @@ static int dgn_load_des_file(lua_State *ls)
return (0);
}
+static int dgn_floor_colour(lua_State *ls)
+{
+ MAP(ls, 1, map);
+
+ const char *s = luaL_checkstring(ls, 2);
+ int colour = str_to_colour(s);
+
+ if (colour < 0 || colour == BLACK)
+ {
+ std::string error;
+
+ if (colour == BLACK)
+ {
+ error = "Can't set floor to black.";
+ }
+ else {
+ error = "No such colour as '";
+ error += s;
+ error += "'";
+ }
+
+ luaL_argerror(ls, 2, error.c_str());
+
+ return (0);
+ }
+
+ map->floor_colour = (unsigned char) colour;
+ return (0);
+}
+
+static int dgn_rock_colour(lua_State *ls)
+{
+ MAP(ls, 1, map);
+
+ const char *s = luaL_checkstring(ls, 2);
+ int colour = str_to_colour(s);
+
+ if (colour < 0 || colour == BLACK)
+ {
+ std::string error;
+
+ if (colour == BLACK)
+ {
+ error = "Can't set rock to black.";
+ }
+ else {
+ error = "No such colour as '";
+ error += s;
+ error += "'";
+ }
+
+ luaL_argerror(ls, 2, error.c_str());
+
+ return (0);
+ }
+
+ map->rock_colour = (unsigned char) colour;
+
+ return (0);
+}
+
+static int dgn_get_floor_colour(lua_State *ls)
+{
+ PLUARET(string, colour_to_str(env.floor_colour));
+}
+
+static int dgn_get_rock_colour(lua_State *ls)
+{
+ PLUARET(string, colour_to_str(env.rock_colour));
+}
+
+static int dgn_change_floor_colour(lua_State *ls)
+{
+ const char *s = luaL_checkstring(ls, 1);
+ int colour = str_to_colour(s);
+
+ if (colour < 0 || colour == BLACK)
+ {
+ std::string error;
+
+ if (colour == BLACK)
+ {
+ error = "Can't set floor to black.";
+ }
+ else {
+ error = "No such colour as '";
+ error += s;
+ error += "'";
+ }
+
+ luaL_argerror(ls, 1, error.c_str());
+
+ return (0);
+ }
+
+ env.floor_colour = (unsigned char) colour;
+
+ viewwindow(true, false);
+
+ return (0);
+}
+
+static int dgn_change_rock_colour(lua_State *ls)
+{
+ const char *s = luaL_checkstring(ls, 1);
+ int colour = str_to_colour(s);
+
+ if (colour < 0 || colour == BLACK)
+ {
+ std::string error;
+
+ if (colour == BLACK)
+ {
+ error = "Can't set rock to black.";
+ }
+ else {
+ error = "No such colour as '";
+ error += s;
+ error += "'";
+ }
+
+ luaL_argerror(ls, 1, error.c_str());
+
+ return (0);
+ }
+
+ env.rock_colour = (unsigned char) colour;
+
+ viewwindow(true, false);
+
+ return (0);
+}
+
const char *dngn_feature_names[] =
{
- "unseen", "rock_wall", "stone_wall", "closed_door", "metal_wall",
- "secret_door", "green_crystal_wall", "orcish_idol", "wax_wall",
- "permarock_wall", "", "", "", "", "", "", "", "", "", "", "",
- "silver_statue", "granite_statue", "orange_crystal_statue",
- "statue_reserved_1", "statue_reserved_2", "", "", "", "", "", "",
+ "unseen", "closed_door", "secret_door", "wax_wall", "metal_wall",
+ "green_crystal_wall", "rock_wall", "stone_wall", "permarock_wall",
+ "clear_rock_wall", "clear_stone_wall", "clear_permarock_wall",
+ "orcish_idol", "", "", "", "", "", "", "", "",
+ "granite_statue", "statue_reserved_1", "statue_reserved_2",
+ "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "lava",
"deep_water", "", "", "shallow_water", "water_stuck", "floor",
"floor_special", "floor_reserved", "exit_hell", "enter_hell",
- "open_door", "", "", "trap_mechanical", "trap_magical", "trap_iii",
+ "open_door", "", "", "trap_mechanical", "trap_magical", "trap_natural",
"undiscovered_trap", "", "enter_shop", "enter_labyrinth",
"stone_stairs_down_i", "stone_stairs_down_ii",
"stone_stairs_down_iii", "rock_stairs_down", "stone_stairs_up_i",
@@ -925,8 +1163,9 @@ static int dgn_feature_name(lua_State *ls)
static const char *dgn_event_type_names[] =
{
- "none", "turn", "mons_move", "player_move", "leave_level", "enter_level",
- "player_los", "player_climb"
+ "none", "turn", "mons_move", "player_move", "leave_level",
+ "entering_level", "entered_level", "player_los", "player_climb",
+ "monster_dies", "item_pickup", "feat_change"
};
static dgn_event_type dgn_event_type_by_name(const std::string &name)
@@ -1010,6 +1249,22 @@ static int dgn_remove_marker(lua_State *ls)
return (0);
}
+static int dgn_num_matching_markers(lua_State *ls)
+{
+ const char* key = luaL_checkstring(ls, 1);
+ const char* val_ptr = lua_tostring(ls, 2);
+ const char* val;
+
+ if (val_ptr == NULL)
+ val = "";
+ else
+ val = val_ptr;
+
+ std::vector<map_marker*> markers = env.markers.get_all(key, val);
+
+ PLUARET(number, markers.size());
+}
+
static int dgn_feature_desc(lua_State *ls)
{
const dungeon_feature_type feat =
@@ -1054,6 +1309,354 @@ static int dgn_terrain_changed(lua_State *ls)
return (0);
}
+static int dgn_item_from_index(lua_State *ls)
+{
+ const int index = luaL_checkint(ls, 1);
+
+ item_def *item = &mitm[index];
+
+ if (is_valid_item(*item))
+ lua_pushlightuserdata(ls, item);
+ else
+ lua_pushnil(ls);
+
+ return (1);
+}
+
+static int dgn_mons_from_index(lua_State *ls)
+{
+ const int index = luaL_checkint(ls, 1);
+
+ monsters *mons = &menv[index];
+
+ if (mons->type != -1)
+ push_monster(ls, mons);
+ else
+ lua_pushnil(ls);
+
+ return (1);
+}
+
+static int lua_dgn_set_lt_callback(lua_State *ls)
+{
+ const char *level_type = luaL_checkstring(ls, 1);
+
+ if (level_type == NULL || strlen(level_type) == 0)
+ return (0);
+
+ const char *callback_name = luaL_checkstring(ls, 2);
+
+ if (callback_name == NULL || strlen(callback_name) == 0)
+ return (0);
+
+ dgn_set_lt_callback(level_type, callback_name);
+
+ return (0);
+}
+
+static int dgn_fixup_stairs(lua_State *ls)
+{
+ const dungeon_feature_type up_feat =
+ dungeon_feature_by_name(luaL_checkstring(ls, 1));
+
+ const dungeon_feature_type down_feat =
+ dungeon_feature_by_name(luaL_checkstring(ls, 2));
+
+ if (up_feat == DNGN_UNSEEN && down_feat == DNGN_UNSEEN)
+ return(0);
+
+ for (int y = 0; y < GYM; ++y)
+ {
+ for (int x = 0; x < GXM; ++x)
+ {
+ const dungeon_feature_type feat = grd[x][y];
+ if (grid_is_stone_stair(feat) || grid_is_rock_stair(feat))
+ {
+ dungeon_feature_type new_feat = DNGN_UNSEEN;
+
+ if (grid_stair_direction(feat) == CMD_GO_DOWNSTAIRS)
+ new_feat = down_feat;
+ else
+ new_feat = up_feat;
+
+ if (new_feat != DNGN_UNSEEN)
+ {
+ grd[x][y] = new_feat;
+ env.markers.add(
+ new map_feature_marker(
+ coord_def(x, y),
+ new_feat));
+ }
+ }
+ }
+ }
+
+ return (0);
+}
+
+static int dgn_floor_halo(lua_State *ls)
+{
+ std::string error = "";
+
+ const char* s1 = luaL_checkstring(ls, 1);
+ const dungeon_feature_type target = dungeon_feature_by_name(s1);
+
+ if (target == DNGN_UNSEEN)
+ {
+ error += "No such dungeon feature as '";
+ error += s1;
+ error += "'. ";
+ }
+
+ const char* s2 = luaL_checkstring(ls, 2);
+ short colour = str_to_colour(s2);
+
+ if (colour == -1)
+ {
+ error += "No such colour as '";
+ error += s2;
+ error += "'.";
+ }
+ else if (colour == BLACK)
+ {
+ error += "Can't set floor colour to black.";
+ }
+
+ if (error != "")
+ {
+ luaL_argerror(ls, 2, error.c_str());
+ return(0);
+ }
+
+ for (int y = 0; y < GYM; ++y)
+ {
+ for (int x = 0; x < GXM; ++x)
+ {
+ const dungeon_feature_type feat = grd[x][y];
+ if (feat == target)
+ {
+
+ for (int i=-1; i<=1; i++)
+ for (int j=-1; j<=1; j++)
+ {
+ if (!map_bounds(x+i, y+j))
+ continue;
+
+ const dungeon_feature_type feat2 = grd[x+i][y+j];
+
+ if (feat2 == DNGN_FLOOR
+ || feat2 == DNGN_UNDISCOVERED_TRAP)
+ {
+ env.grid_colours[x+i][y+j] = colour;
+ }
+ }
+ }
+ }
+ }
+
+ return (0);
+}
+
+#define SQRT_2 1.41421356237309504880
+
+static int dgn_random_walk(lua_State *ls)
+{
+ const int x = luaL_checkint(ls, 1);
+ const int y = luaL_checkint(ls, 2);
+ const int dist = luaL_checkint(ls, 3);
+
+ // Fourth param being true means that we can move past
+ // statues.
+ const dungeon_feature_type minmove =
+ lua_isnil(ls, 4) ? DNGN_MINMOVE : DNGN_ORCISH_IDOL;
+
+ if (!in_bounds(x, y))
+ {
+ char buf[80];
+ sprintf(buf, "Point (%d,%d) isn't in bounds.", x, y);
+ luaL_argerror(ls, 1, buf);
+ return (0);
+ }
+ if (dist < 1)
+ {
+ luaL_argerror(ls, 3, "Distance must be positive.");
+ return (0);
+ }
+
+ float dist_left = dist;
+ // Allow movement to all 8 adjacent squares if distance is 1
+ // (needed since diagonal moves are distance sqrt(2))
+ if (dist == 1)
+ dist_left = SQRT_2;
+
+ int moves_left = dist;
+ coord_def pos(x, y);
+ while (dist_left >= 1.0 && moves_left-- > 0)
+ {
+ int okay_dirs = 0;
+ int dir = -1;
+ for (int j = 0; j < 8; j++)
+ {
+ const coord_def new_pos = pos + Compass[j];
+ const float move_dist = (j % 2 == 0) ? 1.0 : SQRT_2;
+
+ if (in_bounds(new_pos) && grd(new_pos) >= minmove
+ && move_dist <= dist_left)
+ {
+ if (one_chance_in(++okay_dirs))
+ dir = j;
+ }
+ }
+
+ if (okay_dirs == 0)
+ break;
+
+ if (one_chance_in(++okay_dirs))
+ continue;
+
+ pos += Compass[dir];
+ dist_left -= (dir % 2 == 0) ? 1.0 : SQRT_2;
+ }
+
+ dlua_push_coord(ls, pos);
+
+ return (2);
+}
+
+static cloud_type dgn_cloud_name_to_type(std::string name)
+{
+ lowercase(name);
+
+ if (name == "random")
+ return (CLOUD_RANDOM);
+ else if (name == "debugging")
+ return (CLOUD_DEBUGGING);
+
+ for (int i = CLOUD_NONE; i < CLOUD_RANDOM; i++)
+ if (cloud_name(static_cast<cloud_type>(i)) == name)
+ return static_cast<cloud_type>(i);
+
+ return (CLOUD_NONE);
+}
+
+static kill_category dgn_kill_name_to_category(std::string name)
+{
+ if (name == "")
+ return KC_OTHER;
+
+ lowercase(name);
+
+ if (name == "you")
+ return KC_YOU;
+ else if (name == "friendly")
+ return KC_FRIENDLY;
+ else if (name == "other")
+ return KC_OTHER;
+ else
+ return KC_NCATEGORIES;
+}
+
+static int lua_cloud_pow_min;
+static int lua_cloud_pow_max;
+static int lua_cloud_pow_rolls;
+
+static int make_a_lua_cloud(int x, int y, int garbage, int spread_rate,
+ cloud_type ctype, kill_category whose)
+{
+ UNUSED( garbage );
+ const int pow = random_range(lua_cloud_pow_min,
+ lua_cloud_pow_max,
+ lua_cloud_pow_rolls);
+ place_cloud( ctype, x, y, pow, whose, spread_rate );
+
+ return 1;
+}
+
+static int dgn_apply_area_cloud(lua_State *ls)
+{
+ const int x = luaL_checkint(ls, 1);
+ const int y = luaL_checkint(ls, 2);
+ lua_cloud_pow_min = luaL_checkint(ls, 3);
+ lua_cloud_pow_max = luaL_checkint(ls, 4);
+ lua_cloud_pow_rolls = luaL_checkint(ls, 5);
+ const int size = luaL_checkint(ls, 6);
+
+ const cloud_type ctype = dgn_cloud_name_to_type(luaL_checkstring(ls, 7));
+ const char* kname = lua_isstring(ls, 8) ? luaL_checkstring(ls, 8)
+ : "";
+ const kill_category kc = dgn_kill_name_to_category(kname);
+
+ const int spread_rate = lua_isnumber(ls, 9) ? luaL_checkint(ls, 9) : -1;
+
+ if (!in_bounds(x, y))
+ {
+ char buf[80];
+ sprintf(buf, "Point (%d,%d) isn't in bounds.", x, y);
+ luaL_argerror(ls, 1, buf);
+ return (0);
+ }
+
+ if (lua_cloud_pow_min < 0)
+ {
+ luaL_argerror(ls, 4, "pow_min must be non-negative");
+ return (0);
+ }
+
+ if (lua_cloud_pow_max < lua_cloud_pow_min)
+ {
+ luaL_argerror(ls, 5, "pow_max must not be less than pow_min");
+ return (0);
+ }
+
+ if (lua_cloud_pow_max == 0)
+ {
+ luaL_argerror(ls, 5, "pow_max must be positive");
+ return (0);
+ }
+
+ if (lua_cloud_pow_rolls <= 0)
+ {
+ luaL_argerror(ls, 6, "pow_rolls must be positive");
+ return (0);
+ }
+
+ if (size < 1)
+ {
+ luaL_argerror(ls, 4, "size must be positive.");
+ return (0);
+ }
+
+ if (ctype == CLOUD_NONE)
+ {
+ std::string error = "Invalid cloud type '";
+ error += luaL_checkstring(ls, 7);
+ error += "'";
+ luaL_argerror(ls, 7, error.c_str());
+ return (0);
+ }
+
+ if (kc == KC_NCATEGORIES)
+ {
+ std::string error = "Invalid kill category '";
+ error += kname;
+ error += "'";
+ luaL_argerror(ls, 8, error.c_str());
+ return (0);
+ }
+
+ if (spread_rate < -1 || spread_rate > 100)
+ {
+ luaL_argerror(ls, 9, "spread_rate must be between -1 and 100,"
+ "inclusive");
+ return (0);
+ }
+
+ apply_area_cloud(make_a_lua_cloud, x, y, 0, size,
+ ctype, kc, spread_rate);
+
+ return (0);
+}
+
static const struct luaL_reg dgn_lib[] =
{
{ "default_depth", dgn_default_depth },
@@ -1062,6 +1665,8 @@ static const struct luaL_reg dgn_lib[] =
{ "place", dgn_place },
{ "tags", dgn_tags },
{ "tags_remove", dgn_tags_remove },
+ { "lflags", dgn_lflags },
+ { "bflags", dgn_bflags },
{ "chance", dgn_weight },
{ "welcome", dgn_welcome },
{ "weight", dgn_weight },
@@ -1071,6 +1676,8 @@ static const struct luaL_reg dgn_lib[] =
{ "subst", dgn_subst },
{ "nsubst", dgn_nsubst },
{ "colour", dgn_colour },
+ { "floor_colour", dgn_floor_colour},
+ { "rock_colour", dgn_rock_colour},
{ "subst_remove", dgn_subst_remove },
{ "map", dgn_map },
{ "mons", dgn_mons },
@@ -1079,6 +1686,7 @@ static const struct luaL_reg dgn_lib[] =
{ "kfeat", dgn_kfeat },
{ "kitem", dgn_kitem },
{ "kmons", dgn_kmons },
+ { "kmask", dgn_kmask },
{ "grid", dgn_grid },
{ "terrain_changed", dgn_terrain_changed },
{ "points_connected", dgn_points_connected },
@@ -1094,8 +1702,23 @@ static const struct luaL_reg dgn_lib[] =
{ "register_listener", dgn_register_listener },
{ "remove_listener", dgn_remove_listener },
{ "remove_marker", dgn_remove_marker },
+ { "num_matching_markers", dgn_num_matching_markers},
{ "feature_desc", dgn_feature_desc },
{ "feature_desc_at", dgn_feature_desc_at },
+ { "item_from_index", dgn_item_from_index },
+ { "mons_from_index", dgn_mons_from_index },
+ { "change_level_flags", dgn_change_level_flags},
+ { "change_branch_flags", dgn_change_branch_flags},
+ { "get_floor_colour", dgn_get_floor_colour},
+ { "get_rock_colour", dgn_get_rock_colour},
+ { "change_floor_colour", dgn_change_floor_colour},
+ { "change_rock_colour", dgn_change_rock_colour},
+ { "set_lt_callback", lua_dgn_set_lt_callback},
+ { "fixup_stairs", dgn_fixup_stairs},
+ { "floor_halo", dgn_floor_halo},
+ { "random_walk", dgn_random_walk},
+ { "apply_area_cloud", dgn_apply_area_cloud},
+
{ NULL, NULL }
};
@@ -1226,10 +1849,16 @@ static const struct luaL_reg file_lib[] =
LUARET1(you_can_hear_pos, boolean,
player_can_hear(luaL_checkint(ls,1), luaL_checkint(ls, 2)))
+LUARET1(you_x_pos, number, you.x_pos)
+LUARET1(you_y_pos, number, you.y_pos)
+LUARET2(you_pos, number, you.x_pos, you.y_pos)
static const struct luaL_reg you_lib[] =
{
{ "hear_pos", you_can_hear_pos },
+ { "x_pos", you_x_pos },
+ { "y_pos", you_y_pos },
+ { "pos", you_pos },
{ NULL, NULL }
};
@@ -1253,11 +1882,25 @@ static int dgnevent_ticks(lua_State *ls)
PLUARET(number, dev->elapsed_ticks);
}
+static int dgnevent_arg1(lua_State *ls)
+{
+ DEVENT(ls, 1, dev);
+ PLUARET(number, dev->arg1);
+}
+
+static int dgnevent_arg2(lua_State *ls)
+{
+ DEVENT(ls, 1, dev);
+ PLUARET(number, dev->arg2);
+}
+
static const struct luaL_reg dgnevent_lib[] =
{
{ "type", dgnevent_type },
- { "pos", dgnevent_place },
+ { "pos", dgnevent_place },
{ "ticks", dgnevent_ticks },
+ { "arg1", dgnevent_arg1 },
+ { "arg2", dgnevent_arg2 },
{ NULL, NULL }
};
diff --git a/crawl-ref/source/luadgn.h b/crawl-ref/source/luadgn.h
index 071fb283e4..72afcc0dfc 100644
--- a/crawl-ref/source/luadgn.h
+++ b/crawl-ref/source/luadgn.h
@@ -2,7 +2,7 @@
* File: luadgn.h
* Summary: Dungeon-builder Lua interface.
*
- * Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-06-21T19:20:47.183838Z $
+ * Modified for Crawl Reference by $Author$ on $Date$
*/
#ifndef LUADGN_H
diff --git a/crawl-ref/source/macro.cc b/crawl-ref/source/macro.cc
index 219a43943e..a87e86172d 100644
--- a/crawl-ref/source/macro.cc
+++ b/crawl-ref/source/macro.cc
@@ -45,14 +45,15 @@
#include <cstdlib>
#include "cio.h"
+#include "delay.h"
#include "externs.h"
#include "message.h"
+#include "state.h"
#include "stuff.h"
// for trim_string:
#include "initfile.h"
-typedef std::deque<int> keyseq;
typedef std::deque<int> keybuf;
typedef std::map<keyseq,keyseq> macromap;
@@ -73,6 +74,8 @@ static keybuf Buffer;
#define USERFUNCBASE -10000
static std::vector<std::string> userfunctions;
+static std::vector<key_recorder*> recorders;
+
inline int userfunc_index(int key)
{
int index = (key <= USERFUNCBASE? USERFUNCBASE - key : -1);
@@ -406,7 +409,7 @@ static void macro_del( macromap &mapref, keyseq key )
* Adds keypresses from a sequence into the internal keybuffer. Ignores
* macros.
*/
-static void macro_buf_add( const keyseq &actions, bool reverse = false )
+void macro_buf_add( const keyseq &actions, bool reverse)
{
keyseq act;
bool need_more_reset = false;
@@ -426,14 +429,33 @@ static void macro_buf_add( const keyseq &actions, bool reverse = false )
Buffer.insert( reverse? Buffer.begin() : Buffer.end(),
act.begin(), act.end() );
-}
+
+ if (reverse)
+ {
+ for (int i = 0, size_i = recorders.size(); i < size_i; i++)
+ for (int j = act.size() - 1 ; j >= 0; j--)
+ recorders[i]->add_key(act[j], reverse);
+ }
+ else
+ {
+ for (int i = 0, size_i = recorders.size(); i < size_i; i++)
+ for (int j = 0, size_j = act.size(); j < size_j ; j++)
+ recorders[i]->add_key(act[j]);
+ }
+}
/*
* Adds a single keypress into the internal keybuffer.
*/
-void macro_buf_add( int key )
+void macro_buf_add( int key, bool reverse )
{
- Buffer.push_back( key );
+ if (reverse)
+ Buffer.push_front( key );
+ else
+ Buffer.push_back( key );
+
+ for (int i = 0, size = recorders.size(); i < size; i++)
+ recorders[i]->add_key(key, reverse);
}
@@ -491,6 +513,13 @@ static void macro_buf_add_long( keyseq actions,
}
}
+static int macro_keys_left = -1;
+
+bool is_processing_macro()
+{
+ return (macro_keys_left >= 0);
+}
+
/*
* Command macros are only applied from the immediate front of the
* buffer, and only when the game is expecting a command.
@@ -506,11 +535,23 @@ static void macro_buf_apply_command_macro( void )
if (result.size() > 0)
{
+ for (int i = 0, size_i = recorders.size(); i < size_i; i++)
+ recorders[i]->remove_trigger_keys(tmp.size());
+
// Found macro, remove match from front:
for (unsigned int i = 0; i < tmp.size(); i++)
+ {
Buffer.pop_front();
+ if (macro_keys_left >= 0)
+ macro_keys_left--;
+ }
+
+ if (macro_keys_left == -1)
+ macro_keys_left = 0;
+ macro_keys_left += result.size();
macro_buf_add(result, true);
+
break;
}
@@ -519,17 +560,27 @@ static void macro_buf_apply_command_macro( void )
}
/*
- * Removes the earlies keypress from the keybuffer, and returns its
+ * Removes the earliest keypress from the keybuffer, and returns its
* value. If buffer was empty, returns -1;
*/
static int macro_buf_get( void )
{
if (Buffer.size() == 0)
+ {
+ // If we're trying to fetch a new keystroke, then the processing
+ // of the previous keystroke is complete.
+ if (macro_keys_left == 0)
+ macro_keys_left = -1;
+
return (-1);
+ }
int key = Buffer.front();
Buffer.pop_front();
-
+
+ if (macro_keys_left >= 0)
+ macro_keys_left--;
+
return (key);
}
@@ -577,8 +628,17 @@ void macro_save( void )
static keyseq getch_mul( int (*rgetch)() = NULL )
{
keyseq keys;
- int a;
+ int a;
+ // Something's gone wrong with replaying keys if crawl needs to
+ // get new keys from the user.
+ if (crawl_state.is_replaying_keys())
+ {
+ mpr("(Key replay ran out of keys)");
+ crawl_state.cancel_cmd_repeat();
+ crawl_state.cancel_cmd_again();
+ }
+
if (!rgetch)
rgetch = m_getch;
@@ -644,7 +704,26 @@ int getch_with_command_macros( void )
*/
void flush_input_buffer( int reason )
{
- if (Options.flush_input[ reason ])
+ ASSERT(reason != FLUSH_KEY_REPLAY_CANCEL ||
+ crawl_state.is_replaying_keys() || crawl_state.cmd_repeat_start);
+
+ ASSERT(reason != FLUSH_ABORT_MACRO || is_processing_macro());
+
+ // Any attempt to flush means that the processing of the previously
+ // fetched keystroke is complete.
+ if (macro_keys_left == 0)
+ macro_keys_left = -1;
+
+ if (crawl_state.is_replaying_keys() && reason != FLUSH_ABORT_MACRO
+ && reason != FLUSH_KEY_REPLAY_CANCEL &&
+ reason != FLUSH_REPLAY_SETUP_FAILURE)
+ {
+ return;
+ }
+
+ if (Options.flush_input[ reason ] || reason == FLUSH_ABORT_MACRO
+ || reason == FLUSH_KEY_REPLAY_CANCEL
+ || reason == FLUSH_REPLAY_SETUP_FAILURE)
{
while (!Buffer.empty())
{
@@ -653,6 +732,7 @@ void flush_input_buffer( int reason )
if (key == KEY_MACRO_ENABLE_MORE)
Options.show_more_prompt = true;
}
+ macro_keys_left = -1;
}
}
@@ -822,8 +902,103 @@ bool is_synthetic_key(int key)
case KEY_MACRO_ENABLE_MORE:
case KEY_MACRO_DISABLE_MORE:
case KEY_MACRO_MORE_PROTECT:
+ case KEY_REPEAT_KEYS:
return (true);
default:
return (false);
}
}
+
+key_recorder::key_recorder(key_recorder_callback cb, void* cb_data)
+ : paused(false), call_back(cb), call_back_data(cb_data)
+{
+ keys.clear();
+ macro_trigger_keys.clear();
+}
+
+void key_recorder::add_key(int key, bool reverse)
+{
+ if (paused)
+ return;
+
+ if (call_back)
+ {
+ // Don't record key if true
+ if ((*call_back)(this, key, reverse))
+ return;
+ }
+
+ if (reverse)
+ keys.push_front(key);
+ else
+ keys.push_back(key);
+}
+
+void key_recorder::remove_trigger_keys(int num_keys)
+{
+ ASSERT(num_keys >= 1);
+
+ if (paused)
+ return;
+
+ for (int i = 0; i < num_keys; i++)
+ {
+ ASSERT(keys.size() >= 1);
+
+ int key = keys[keys.size() - 1];
+
+ if (call_back)
+ {
+ // Key wasn't recorded in the first place, so no need to remove
+ // it
+ if ((*call_back)(this, key, true))
+ continue;
+ }
+
+ macro_trigger_keys.push_front(key);
+ keys.pop_back();
+ }
+}
+
+void key_recorder::clear()
+{
+ keys.clear();
+ macro_trigger_keys.clear();
+}
+
+void add_key_recorder(key_recorder* recorder)
+{
+ for (int i = 0, size = recorders.size(); i < size; i++)
+ ASSERT(recorders[i] != recorder);
+
+ recorders.push_back(recorder);
+}
+
+void remove_key_recorder(key_recorder* recorder)
+{
+ std::vector<key_recorder*>::iterator i;
+
+ for(i = recorders.begin(); i != recorders.end(); i++)
+ if (*i == recorder)
+ {
+ recorders.erase(i);
+ return;
+ }
+
+ end(1, true, "remove_key_recorder(): recorder not found\n");
+}
+
+// Add macro trigger keys to beginning of the buffer, then expand
+// them.
+void insert_macro_into_buff(const keyseq& keys)
+{
+ for (int i = (int) keys.size() - 1; i >= 0; i--)
+ macro_buf_add(keys[i], true);
+
+ macro_buf_apply_command_macro();
+}
+
+int get_macro_buf_size()
+{
+ return (Buffer.size());
+}
diff --git a/crawl-ref/source/macro.h b/crawl-ref/source/macro.h
index ff1c01b076..90d0557cda 100644
--- a/crawl-ref/source/macro.h
+++ b/crawl-ref/source/macro.h
@@ -14,6 +14,8 @@
#ifndef MACRO_H
#define MACRO_H
+#include <deque>
+
#ifndef MACRO_CC
#undef getch
@@ -30,6 +32,28 @@ enum KeymapContext {
KC_CONTEXT_COUNT // Must always be the last
};
+class key_recorder;
+typedef bool (*key_recorder_callback)(key_recorder *recorder,
+ int &ch, bool reverse);
+typedef std::deque<int> keyseq;
+
+class key_recorder {
+public:
+ bool paused;
+ keyseq keys;
+ keyseq macro_trigger_keys;
+ key_recorder_callback call_back;
+ void* call_back_data;
+
+public:
+ key_recorder(key_recorder_callback cb = NULL,
+ void* cb_data = NULL);
+
+ void add_key(int key, bool reverse = false);
+ void remove_trigger_keys(int num_keys);
+ void clear();
+};
+
int getchm(int (*rgetch)() = NULL); // keymaps applied (ie for prompts)
int getchm(KeymapContext context, int (*rgetch)() = NULL);
@@ -43,11 +67,21 @@ void macro_save(void);
void macro_userfn(const char *keys, const char *registryname);
-void macro_buf_add(int key);
+void macro_buf_add(int key, bool reverse = false);
+void macro_buf_add(const keyseq &actions, bool reverse = false );
bool is_userfunction(int key);
bool is_synthetic_key(int key);
const char *get_userfunction(int key);
+void add_key_recorder(key_recorder* recorder);
+void remove_key_recorder(key_recorder* recorder);
+
+bool is_processing_macro();
+
+void insert_macro_into_buff(const keyseq& keys);
+
+int get_macro_buf_size();
+
#endif
diff --git a/crawl-ref/source/makefile.obj b/crawl-ref/source/makefile.obj
index 4bbf544129..89784d01fd 100644
--- a/crawl-ref/source/makefile.obj
+++ b/crawl-ref/source/makefile.obj
@@ -12,8 +12,8 @@ cloud.o \
command.o \
database.o \
debug.o \
-delay.o \
decks.o \
+delay.o \
describe.o \
dgnevent.o \
direct.o \
@@ -74,7 +74,9 @@ spl-book.o \
spl-cast.o \
spl-util.o \
sqldbm.o \
+state.o \
stash.o \
+store.o \
stuff.o \
tags.o \
terrain.o \
diff --git a/crawl-ref/source/makefile.unix b/crawl-ref/source/makefile.unix
index 36ee1ef1f8..8d65dc3716 100644
--- a/crawl-ref/source/makefile.unix
+++ b/crawl-ref/source/makefile.unix
@@ -17,13 +17,14 @@ DELETE = rm -f
COPY = cp
OS_TYPE = UNIX
-# Change this to y if you want to use Unicode glyphs in the map, and you have
-# libncursesw available.
+# Change this to y (case-sensitive!) if you want to use Unicode glyphs
+# in the map, and you have libncursesw available.
UNICODE_GLYPHS = n
# If you're using UNICODE_GLYPHS=y, and have a preferred Unicode
# (UTF-8) locale you want Crawl to use, you can set it here. The
-# default is en_US.UTF-8.
+# default is en_US.UTF-8. If you'd prefer that Crawl use the locale
+# as set in your environment LC_* variables, use UNICODE_LOCALE = .
UNICODE_LOCALE =
# If you have lex and yacc, set DOYACC to y (lowercase y).
@@ -60,14 +61,14 @@ NDBM_FILE := /usr/include/ndbm.h
HAVE_DBH := $(shell [ -f $(DBH_FILE) ] && echo y)
HAVE_NDBM := $(shell [ -f $(NDBM_FILE) ] && echo y)
-ifeq ($(HAVE_DBH),y)
+ifeq ($(strip $(HAVE_DBH)),y)
ifneq ($(shell grep dbm_open $(DBH_FILE)),)
SELDBM := -DDB_DBH
LIBDBM := -ldb
endif
endif
-ifeq ($(HAVE_NDBM),y)
+ifeq ($(strip $(HAVE_NDBM)),y)
SELDBM ?= -DDB_NDBM
ifeq ($(SELDBM),-DDB_NDBM)
LIBDBM := -ldbm
@@ -79,7 +80,7 @@ SQLLIB := sqlite3
SQLLIBA := lib$(SQLLIB).a
FSQLLIBA := $(SQLSRC)/$(SQLLIBA)
-ifeq ($(LIBDBM),)
+ifeq ($(strip $(LIBDBM)),)
LIBDBM := -L$(SQLSRC) -lsqlite3
EXTRA_INCLUDES += -I$(SQLSRC)
EXTRA_DEPENDS += $(FSQLLIBA)
@@ -89,19 +90,24 @@ LIB = -l$(LIBCURS) -L$(LUASRC) -l$(LUALIB) $(LIBDBM)
INCLUDES := $(INCLUDES) -Iutil -I. -I$(LUASRC) $(EXTRA_INCLUDES)
-CFWARN := -Wall -Wwrite-strings -Wshadow -Wuninitialized -pedantic
+CFWARN := -Wall -Wwrite-strings -Wshadow -pedantic
CFOTHERS := -O2 -fsigned-char -D$(OS_TYPE) $(EXTRA_FLAGS) -DCLUA_BINDINGS
-ifneq ($(SAVEDIR),)
-CFOTHERS += '-DSAVE_DIR_PATH="$(SAVEDIR)"'
+ifneq ($(HURRY),y)
+CFWARN += -Wuninitialized
+CFOTHERS += -O2
+endif
+
+ifneq ($(strip $(SAVEDIR)),)
+CFOTHERS += '-DSAVE_DIR_PATH="$(strip $(SAVEDIR))"'
endif
-ifneq ($(DATADIR),)
-CFOTHERS += '-DDATA_DIR_PATH="$(DATADIR)"'
+ifneq ($(strip $(DATADIR)),)
+CFOTHERS += '-DDATA_DIR_PATH="$(strip $(DATADIR))"'
endif
-ifeq ($(UNICODE_GLYPHS),y)
+ifeq ($(strip $(UNICODE_GLYPHS)),y)
# Include path for (n)curses with Unicode support.
INCLUDES += -I/usr/include/ncursesw
@@ -110,8 +116,12 @@ INCLUDES += -I/usr/include/ncursesw
LIBCURS = ncursesw
CFOTHERS += -DUNICODE_GLYPHS
-ifneq ($(UNICODE_LOCALE),)
-CFOTHERS += -DUNICODE_LOCALE=\"$(UNICODE_LOCALE)\"
+ifneq ($(strip $(UNICODE_LOCALE)),)
+ifneq ($(strip $(UNICODE_LOCALE)),.)
+CFOTHERS += -DUNICODE_LOCALE=\"$(strip $(UNICODE_LOCALE))\"
+else
+CFOTHERS += -DUNICODE_LOCALE=\"\"
+endif
endif
# The standard ncurses library also supports Unicode on Mac OS/Darwin.
@@ -137,11 +147,11 @@ YTABH := levcomp.tab.h
OBJECTS := $(UTIL)levcomp.tab.o $(UTIL)levcomp.lex.o $(OBJECTS)
-ifeq ($(LEX),)
+ifeq ($(strip $(LEX)),)
DOYACC :=
endif
-ifeq ($(YACC),)
+ifeq ($(strip $(YACC)),)
DOYACC :=
endif
diff --git a/crawl-ref/source/makeitem.cc b/crawl-ref/source/makeitem.cc
index cdaf1ff59e..633db77418 100644
--- a/crawl-ref/source/makeitem.cc
+++ b/crawl-ref/source/makeitem.cc
@@ -2,7 +2,7 @@
* File: makeitem.cc
* Summary: Item creation routines.
*
- * Modified for Crawl Reference by $Author: haranp $ on $Date: 2007-03-15T20:10:20.648083Z $
+ * Modified for Crawl Reference by $Author$ on $Date$
*/
#include "AppHdr.h"
@@ -23,6 +23,7 @@
#include "randart.h"
#include "spl-book.h"
#include "stuff.h"
+#include "view.h"
static bool weapon_is_visibly_special(const item_def &item);
@@ -38,16 +39,6 @@ static bool got_distortion_roll(const int item_level)
return (one_chance_in(25));
}
-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 int exciting_colour()
{
switch(random2(4))
@@ -727,19 +718,12 @@ void item_colour( item_def &item )
break;
case OBJ_ORBS:
- item.colour = LIGHTMAGENTA;
+ item.colour = EC_MUTAGENIC;
break;
case OBJ_MISCELLANY:
if ( is_deck(item) )
- {
- item.colour = GREEN;
- if ( one_chance_in(10) )
- item.colour = LIGHTMAGENTA; // legendary
- if ( one_chance_in(5) )
- item.colour = (coinflip() ? MAGENTA : BROWN);
break;
- }
switch (item.sub_type)
{
@@ -770,64 +754,78 @@ void item_colour( item_def &item )
switch (item.plus)
{
case RUNE_DIS: // iron
- item.colour = CYAN;
+ item.colour = EC_IRON;
break;
case RUNE_COCYTUS: // icy
- item.colour = LIGHTBLUE;
+ item.colour = EC_ICE;
break;
case RUNE_TARTARUS: // bone
- item.colour = WHITE;
+ item.colour = EC_BONE;
break;
case RUNE_SLIME_PITS: // slimy
- item.colour = GREEN;
+ item.colour = EC_SLIME;
break;
case RUNE_SNAKE_PIT: // serpentine
+ item.colour = EC_POISON;
+ break;
+
case RUNE_ELVEN_HALLS: // elven
- item.colour = LIGHTGREEN;
+ item.colour = EC_ELVEN;
break;
case RUNE_VAULTS: // silver
- item.colour = LIGHTGREY;
+ item.colour = EC_SILVER;
break;
case RUNE_TOMB: // golden
- item.colour = YELLOW;
+ item.colour = EC_GOLD;
break;
case RUNE_SWAMP: // decaying
- item.colour = BROWN;
+ item.colour = EC_DECAY;
break;
- case RUNE_SHOALS:
- item.colour = BLUE; // barnacled
+ case RUNE_SHOALS: // barnacled
+ item.colour = EC_WATER;
+ 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
+ // This one is hardly unique, but colour isn't used for
+ // stacking, so we don't have to worry too much about this. -- bwr
case RUNE_DEMONIC: // random pandemonium demonlords
+ {
+ element_type types[] =
+ {EC_EARTH, EC_ELECTRICITY, EC_ENCHANT, EC_HEAL,
+ EC_BLOOD, EC_DEATH, EC_UNHOLY, EC_VEHUMET, EC_BEOGH,
+ EC_CRYSTAL, EC_SMOKE, EC_DWARVEN, EC_ORCISH, EC_GILA};
+
+ item.colour = RANDOM_ELEMENT(types);
+ break;
+ }
+
case RUNE_ABYSSAL: // random in abyss
- item.colour = random_colour();
+ item.colour = EC_RANDOM;
break;
case RUNE_MNOLEG: // glowing
- item.colour = coinflip() ? MAGENTA : LIGHTMAGENTA;
+ item.colour = EC_MUTAGENIC;
break;
case RUNE_LOM_LOBON: // magical
- item.colour = BLUE;
+ item.colour = EC_MAGIC;
break;
case RUNE_CEREBOV: // fiery
- item.colour = coinflip() ? RED : LIGHTRED;
+ item.colour = EC_FIRE;
break;
case RUNE_GEHENNA: // obsidian
case RUNE_GLOORX_VLOQ: // dark
default:
- item.colour = DARKGREY;
+ item.colour = EC_DARK;
break;
}
break;
@@ -856,2010 +854,1902 @@ void item_colour( item_def &item )
}
} // end item_colour()
-// Returns item slot or NON_ITEM if it fails
-int items( int allow_uniques, // not just true-false,
- // because of BCR acquirement hack
- object_class_type 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!
- unsigned mapmask)
+static weapon_type determine_weapon_subtype(int item_level)
{
- const bool make_good_item = (item_level == MAKE_GOOD_ITEM);
-
- int temp_rand = 0; // probability determination {dlb}
- int range_charges = 0; // for OBJ_WANDS charge count {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;
-
- int icky = 0;
- int p = 0;
-
- // find an empty slot for the item (with culling if required)
- p = get_item_slot(10);
- if (p == NON_ITEM)
- return (NON_ITEM);
-
- // cap item_level unless an acquirement-level item {dlb}:
- if (item_level > 50 && !make_good_item)
- item_level = 50;
-
- // determine base_type for item generated {dlb}:
- if (force_class != OBJ_RANDOM)
- mitm[p].base_type = force_class;
+ weapon_type rc = WPN_UNKNOWN;
+
+ const weapon_type common_subtypes[] = {
+ WPN_KNIFE, WPN_QUARTERSTAFF, WPN_SLING,
+ WPN_SPEAR, WPN_HAND_AXE, WPN_MACE,
+ WPN_DAGGER, WPN_DAGGER, WPN_CLUB,
+ WPN_HAMMER, WPN_WHIP, WPN_SABRE
+ };
+
+ const weapon_type rare_subtypes[] = {
+ WPN_LAJATANG, WPN_DEMON_BLADE, WPN_DEMON_TRIDENT,
+ WPN_DEMON_WHIP, WPN_DOUBLE_SWORD, WPN_EVENINGSTAR,
+ WPN_EXECUTIONERS_AXE, WPN_KATANA, WPN_QUICK_BLADE,
+ WPN_TRIPLE_SWORD
+ };
+
+ if (random2(20) < 20 - item_level)
+ rc = RANDOM_ELEMENT(common_subtypes);
+ else if (item_level > 6 && random2(100) < (10 + item_level)
+ && one_chance_in(30))
+ rc = RANDOM_ELEMENT(rare_subtypes);
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)
+ // pick a weapon based on rarity
+ while (true)
{
- mitm[p].base_type = coinflip() ? OBJ_POTIONS : OBJ_SCROLLS;
- }
- }
+ const int wpntype = random2(NUM_WEAPONS);
- // 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))
+ if (weapon_rarity(wpntype) > random2(10))
{
- // 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(10);
-
- mitm[p].sub_type = ((temp_rand == 9) ? WPN_LAJATANG :
- (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 (;;)
- {
- const int wpntype = random2(NUM_WEAPONS);
-
- if (weapon_rarity(wpntype) >= random2(10) + 1)
- {
- mitm[p].sub_type = static_cast<unsigned char>(wpntype);
- break;
- }
- }
+ rc = static_cast<weapon_type>(wpntype);
+ break;
}
}
+ }
+ return rc;
+}
- if (allow_uniques)
+// Return whether we made an artefact.
+static bool try_make_weapon_artefact(item_def& item, int force_type,
+ int item_level)
+{
+ if (item.sub_type != WPN_CLUB && item_level > 2
+ && random2(4000) <= 100 + (item_level * 3))
+ {
+ // Make a randart or unrandart.
+
+ // 1 in 50 randarts are unrandarts.
+ if (you.level_type != LEVEL_ABYSS
+ && you.level_type != LEVEL_PANDEMONIUM
+ && one_chance_in(50))
{
- // 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;
- }
+ const int idx = find_okay_unrandart(OBJ_WEAPONS, force_type);
- if (item_level > 6
- && random2(3000) <= 30 + (item_level * 3) && one_chance_in(12))
+ if (idx != -1)
{
-#ifdef DEBUG_DIAGNOSTICS
- mprf(MSGCH_DIAGNOSTICS, "Making fixed artefact.");
-#endif
- if (make_item_fixed_artefact( mitm[p], (item_level == 51) ))
- {
- quant = 1;
- break;
- }
+ make_item_unrandart( item, idx );
+ return true;
}
}
- ASSERT(!is_fixed_artefact(mitm[p]) && !is_random_artefact(mitm[p]));
+ // The other 98% are normal randarts.
+ make_item_randart( item );
+ item.plus = random2(7);
+ item.plus2 = random2(7);
- if (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;
- }
+ if (one_chance_in(3))
+ item.plus += random2(7);
- quant = 1;
+ if (one_chance_in(3))
+ item.plus2 += random2(7);
- mitm[p].plus = 0;
- mitm[p].plus2 = 0;
- mitm[p].special = SPWPN_NORMAL;
+ if (one_chance_in(9))
+ item.plus -= random2(7);
- 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;
+ if (one_chance_in(9))
+ item.plus2 -= random2(7);
- case WPN_MACE:
- case WPN_FLAIL:
- case WPN_SPIKED_FLAIL:
- case WPN_GREAT_MACE:
- case WPN_DIRE_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;
+ if (one_chance_in(4))
+ {
+ do_curse_item( item );
+ item.plus = -random2(6);
+ item.plus2 = -random2(6);
+ }
+ else if ((item.plus < 0 || item.plus2 < 0)
+ && !one_chance_in(3))
+ {
+ do_curse_item( item );
+ }
+ return true;
+ }
- 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;
+ // If it isn't an artefact yet, try to make a fixed artefact.
+ if (item_level > 6
+ && random2(3000) <= 30 + (item_level * 3)
+ && one_chance_in(12))
+ {
+#ifdef DEBUG_DIAGNOSTICS
+ mprf(MSGCH_DIAGNOSTICS, "Making fixed artefact.");
+#endif
+ if (make_item_fixed_artefact( item, (item_level == 51) ))
+ return true;
+ }
- 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;
+ return false;
+}
- 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;
+static item_status_flag_type determine_weapon_race(const item_def& item,
+ int item_race)
+{
+ item_status_flag_type rc = ISFLAG_NO_RACE;
+ switch (item_race)
+ {
+ case MAKE_ITEM_ELVEN:
+ if (weapon_skill(item) != SK_MACES_FLAILS)
+ rc = 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 MAKE_ITEM_DWARVEN:
+ if (weapon_skill(item) != SK_POLEARMS)
+ rc = ISFLAG_DWARVEN;
+ 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 MAKE_ITEM_ORCISH:
+ rc = ISFLAG_ORCISH;
+ break;
- case WPN_GREAT_SWORD:
- if (one_chance_in(3))
- set_equip_race( mitm[p], ISFLAG_ORCISH );
- break;
+ case MAKE_ITEM_RANDOM_RACE:
+ if (coinflip())
+ break;
+ switch (item.sub_type)
+ {
+ case WPN_CLUB:
+ if (coinflip())
+ rc = ISFLAG_ORCISH;
+ break;
- case WPN_SCIMITAR:
- 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_DIRE_FLAIL:
+ if (one_chance_in(4))
+ rc = ISFLAG_DWARVEN;
+ if (one_chance_in(3))
+ rc = 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_MORNINGSTAR:
+ case WPN_HAMMER:
+ if (one_chance_in(3))
+ rc = ISFLAG_ORCISH;
+ if (one_chance_in(3))
+ rc = 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_DAGGER:
+ if (one_chance_in(3))
+ rc = ISFLAG_ORCISH;
+ if (one_chance_in(4))
+ rc = ISFLAG_DWARVEN;
+ if (one_chance_in(4))
+ rc = ISFLAG_ELVEN;
+ break;
- case WPN_HALBERD:
- case WPN_GLAIVE:
- case WPN_EXECUTIONERS_AXE:
- case WPN_LOCHABER_AXE:
- if (one_chance_in(5))
- set_equip_race( mitm[p], ISFLAG_ORCISH );
- break;
+ case WPN_SHORT_SWORD:
+ if (one_chance_in(3))
+ rc = ISFLAG_ORCISH;
+ if (one_chance_in(3))
+ rc = ISFLAG_DWARVEN;
+ if (one_chance_in(3))
+ rc = ISFLAG_ELVEN;
+ break;
- case WPN_QUICK_BLADE:
- if (one_chance_in(4))
- set_equip_race( mitm[p], ISFLAG_ELVEN );
- break;
+ case WPN_FALCHION:
+ if (one_chance_in(5))
+ rc = ISFLAG_DWARVEN;
+ if (one_chance_in(3))
+ rc = ISFLAG_ORCISH;
+ if (one_chance_in(3))
+ rc = ISFLAG_ELVEN;
+ break;
- case WPN_KATANA:
- case WPN_LAJATANG:
- 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_LONG_SWORD:
+ if (one_chance_in(4))
+ rc = ISFLAG_ORCISH;
+ if (coinflip())
+ rc = ISFLAG_ELVEN;
+ 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_GREAT_SWORD:
+ if (one_chance_in(3))
+ rc = ISFLAG_ORCISH;
+ break;
- case WPN_LONGBOW:
- set_equip_race( mitm[p], one_chance_in(3) ? ISFLAG_ELVEN
- : ISFLAG_NO_RACE );
- break;
+ case WPN_SCIMITAR:
+ if (coinflip())
+ rc = ISFLAG_ORCISH;
+ 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_WAR_AXE:
+ case WPN_HAND_AXE:
+ case WPN_BROAD_AXE:
+ case WPN_BATTLEAXE:
+ if (one_chance_in(3))
+ rc = ISFLAG_ORCISH;
+ if (coinflip())
+ rc = ISFLAG_DWARVEN;
+ break;
- case WPN_HAND_CROSSBOW:
- if (one_chance_in(3))
- set_equip_race( mitm[p], ISFLAG_ELVEN );
- break;
+ case WPN_SPEAR:
+ case WPN_TRIDENT:
+ if (one_chance_in(4))
+ rc = ISFLAG_ORCISH;
+ if (one_chance_in(4))
+ rc = 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;
- }
- }
+ case WPN_HALBERD:
+ case WPN_GLAIVE:
+ case WPN_EXECUTIONERS_AXE:
+ case WPN_LOCHABER_AXE:
+ if (one_chance_in(5))
+ rc = 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 );
+ case WPN_QUICK_BLADE:
+ if (one_chance_in(4))
+ rc = ISFLAG_ELVEN;
break;
- case MAKE_ITEM_DWARVEN:
- set_equip_race( mitm[p], ISFLAG_DWARVEN );
+ case WPN_KATANA:
+ case WPN_LAJATANG:
+ case WPN_KNIFE:
+ case WPN_SLING:
+ rc = ISFLAG_NO_RACE;
break;
- case MAKE_ITEM_ORCISH:
- set_equip_race( mitm[p], ISFLAG_ORCISH );
+ case WPN_BOW:
+ if (one_chance_in(6))
+ rc = ISFLAG_ORCISH;
+ if (coinflip())
+ rc = ISFLAG_ELVEN;
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 (make_good_item
- && get_equip_race( mitm[p] ) == ISFLAG_ORCISH)
- {
- set_equip_race( mitm[p], ISFLAG_NO_RACE );
- }
+ case WPN_LONGBOW:
+ rc = one_chance_in(3) ? ISFLAG_ELVEN : ISFLAG_NO_RACE;
+ break;
- switch (get_equip_race( mitm[p] ))
- {
- case ISFLAG_ORCISH:
- if (coinflip())
- race_plus--;
- if (coinflip())
- race_plus2++;
+ case WPN_CROSSBOW:
+ if (one_chance_in(4))
+ rc = ISFLAG_ORCISH;
+ if (one_chance_in(4))
+ rc = ISFLAG_DWARVEN;
break;
- case ISFLAG_ELVEN:
- race_plus += random2(3);
+ case WPN_HAND_CROSSBOW:
+ if (one_chance_in(3))
+ rc = ISFLAG_ELVEN;
break;
- case ISFLAG_DWARVEN:
- if (coinflip())
- race_plus++;
- if (coinflip())
- race_plus2++;
+ case WPN_BLOWGUN:
+ if (one_chance_in(10))
+ rc = ISFLAG_ELVEN;
+ if (one_chance_in(4))
+ rc = ISFLAG_ORCISH;
break;
}
+ break;
+ }
+ return rc;
+}
- mitm[p].plus += race_plus;
- mitm[p].plus2 += race_plus2;
+static void weapon_add_racial_modifiers(item_def& item)
+{
+ switch (get_equip_race( item ))
+ {
+ case ISFLAG_ORCISH:
+ if (coinflip())
+ item.plus--;
+ if (coinflip())
+ item.plus2++;
+ break;
+
+ case ISFLAG_ELVEN:
+ item.plus += random2(3);
+ break;
+
+ case ISFLAG_DWARVEN:
+ if (coinflip())
+ item.plus++;
+ if (coinflip())
+ item.plus2++;
+ break;
+ }
+}
- if ((random2(200) <= 50 + item_level
- || make_good_item
- || is_demonic(mitm[p]))
- // 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)
+static brand_type determine_weapon_brand(const item_def& item, int item_level)
+{
+ const bool force_good = (item_level == MAKE_GOOD_ITEM);
+ const int tries = force_good ? 5 : 1;
+ brand_type rc = SPWPN_NORMAL;
+
+ for (int count = 0; count < tries && rc == SPWPN_NORMAL; ++count)
+ {
+ if (!(force_good || is_demonic(item) || random2(300) <= 100+item_level))
+ continue;
+
+ // We are not guaranteed to have a special set by the end of this
+ switch (item.sub_type)
{
- count = 0;
+ case WPN_EVENINGSTAR:
+ if (coinflip())
+ rc = SPWPN_DRAINING;
+ // **** intentional fall through here ****
+ case WPN_MORNINGSTAR:
+ if (one_chance_in(4))
+ rc = SPWPN_VENOM;
- do
- {
- if (random2(300) <= 100 + item_level
- || make_good_item
- || is_demonic( mitm[p] ))
- {
- // 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_DIRE_FLAIL:
- case WPN_HAMMER:
- if (one_chance_in(25))
- set_weapon_special(p, SPWPN_PAIN);
-
- if (got_distortion_roll(item_level))
- 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(4))
- set_weapon_special(p, SPWPN_RETURNING);
-
- 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 (got_distortion_roll(item_level))
- 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 (got_distortion_roll(item_level))
- 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 (mitm[p].sub_type == WPN_HAND_AXE &&
- one_chance_in(10))
- set_weapon_special(p, SPWPN_RETURNING);
-
- if (got_distortion_roll(item_level))
- 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 (got_distortion_roll(item_level))
- 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:
- case WPN_SCYTHE:
- case WPN_TRIDENT:
- case WPN_LOCHABER_AXE:
- 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 ****
- 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 (mitm[p].sub_type == WPN_SPEAR && one_chance_in(6))
- set_weapon_special(p, SPWPN_RETURNING);
-
- if (got_distortion_roll(item_level))
- 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_LONGBOW:
- case WPN_CROSSBOW:
- {
- const int tmp = random2(1000);
-
- set_weapon_special( p, (tmp < 375) ? SPWPN_FLAME :
- (tmp < 750) ? SPWPN_FROST :
- (tmp < 920) ? SPWPN_PROTECTION :
- (tmp < 980) ? SPWPN_VORPAL
- : SPWPN_SPEED );
- 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 (got_distortion_roll(item_level))
- 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;
-
- case WPN_BLESSED_BLADE: // special gift of TSO
- set_weapon_special( p, SPWPN_HOLY_WRATH );
- break;
-
- // unlisted weapons have no associated, standard ego-types {dlb}
- default:
- break;
- }
- } // end if specially enchanted
-
- count++;
- }
- while (make_good_item
- && mitm[p].special == SPWPN_NORMAL
- && count < 5);
+ if (one_chance_in(4))
+ rc = coinflip() ? SPWPN_FLAMING : SPWPN_FREEZING;
- // if acquired item still not ego... enchant it up a bit.
- if (make_good_item && mitm[p].special == SPWPN_NORMAL)
+ if (one_chance_in(20))
+ rc = SPWPN_VAMPIRICISM;
+ // **** intentional fall through here ****
+ case WPN_MACE:
+ case WPN_GREAT_MACE:
+ if ((item.sub_type == WPN_MACE || item.sub_type == WPN_GREAT_MACE)
+ && one_chance_in(4))
{
- mitm[p].plus += 2 + random2(3);
- mitm[p].plus2 += 2 + random2(3);
+ rc = SPWPN_DISRUPTION;
}
+ // **** intentional fall through here ****
+ case WPN_FLAIL:
+ case WPN_SPIKED_FLAIL:
+ case WPN_DIRE_FLAIL:
+ case WPN_HAMMER:
+ if (one_chance_in(25))
+ rc = SPWPN_PAIN;
- const int chance = (make_good_item) ? 200 : item_level;
+ if (got_distortion_roll(item_level))
+ rc = SPWPN_DISTORTION;
- // odd-looking, but this is how the algorithm compacts {dlb}:
- for (loopy = 0; loopy < 4; loopy++)
- {
- mitm[p].plus += random2(3);
+ if (one_chance_in(3) && (rc == SPWPN_NORMAL || one_chance_in(5)))
+ rc = SPWPN_VORPAL;
- if (random2(350) > 20 + chance)
- break;
- }
+ if (one_chance_in(4))
+ rc = SPWPN_HOLY_WRATH;
- // odd-looking, but this is how the algorithm compacts {dlb}:
- for (loopy = 0; loopy < 4; loopy++)
- {
- mitm[p].plus2 += random2(3);
+ if (one_chance_in(3))
+ rc = SPWPN_PROTECTION;
+
+ if (one_chance_in(10))
+ rc = SPWPN_DRAINING;
+ break;
+
+
+ case WPN_DAGGER:
+ if (one_chance_in(4))
+ rc = SPWPN_RETURNING;
+
+ if (one_chance_in(10))
+ rc = SPWPN_PAIN;
+
+ if (one_chance_in(3))
+ rc = SPWPN_VENOM;
+ // **** intentional fall through here ****
+
+ case WPN_SHORT_SWORD:
+ case WPN_SABRE:
+ if (got_distortion_roll(item_level))
+ rc = SPWPN_DISTORTION;
+
+ if (one_chance_in(10))
+ rc = SPWPN_VAMPIRICISM;
+
+ if (one_chance_in(8))
+ rc = SPWPN_ELECTROCUTION;
+
+ if (one_chance_in(8))
+ rc = SPWPN_PROTECTION;
+
+ if (one_chance_in(10))
+ rc = SPWPN_ORC_SLAYING;
+
+ if (one_chance_in(8))
+ rc = coinflip() ? SPWPN_FLAMING : SPWPN_FREEZING;
- 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);
+ rc = SPWPN_HOLY_WRATH;
- // clear specials {dlb}
- set_item_ego_type( mitm[p], OBJ_WEAPONS, SPWPN_NORMAL );
- }
- }
+ if (one_chance_in(8))
+ rc = SPWPN_DRAINING;
- // value was "0" comment said "orc" so I went with comment {dlb}
- if (get_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()))
+ if (one_chance_in(8))
+ rc = SPWPN_SPEED;
+
+ if (one_chance_in(6))
+ rc = SPWPN_VENOM;
+ break;
+
+ case WPN_FALCHION:
+ case WPN_LONG_SWORD:
+ if (one_chance_in(12))
+ rc = SPWPN_VENOM;
+ // **** intentional fall through here ****
+ case WPN_SCIMITAR:
+ if (one_chance_in(25))
+ rc = SPWPN_PAIN;
+
+ if (one_chance_in(7))
+ rc = SPWPN_SPEED;
+ // **** intentional fall through here ****
+ case WPN_GREAT_SWORD:
+ case WPN_DOUBLE_SWORD:
+ case WPN_TRIPLE_SWORD:
+ if (one_chance_in(10))
+ rc = SPWPN_VAMPIRICISM;
+
+ if (got_distortion_roll(item_level))
+ rc = SPWPN_DISTORTION;
+
+ if (one_chance_in(5))
+ rc = coinflip() ? SPWPN_FLAMING : SPWPN_FREEZING;
+
+ if (one_chance_in(7))
+ rc = SPWPN_PROTECTION;
+
+ if (one_chance_in(8))
+ rc = SPWPN_ORC_SLAYING;
+
+ if (one_chance_in(12))
+ rc = SPWPN_DRAINING;
+
+ if (one_chance_in(7))
+ rc = SPWPN_ELECTROCUTION;
+
+ if (one_chance_in(4))
+ rc = SPWPN_HOLY_WRATH;
+
+ if (one_chance_in(4) && (rc == SPWPN_NORMAL || one_chance_in(3)))
+ rc = SPWPN_VORPAL;
+
+ break;
+
+ case WPN_WAR_AXE:
+ case WPN_BROAD_AXE:
+ case WPN_BATTLEAXE:
+ case WPN_EXECUTIONERS_AXE:
+ if (one_chance_in(25))
+ rc = SPWPN_HOLY_WRATH;
+
+ if (one_chance_in(14))
+ rc = SPWPN_DRAINING;
+ // **** intentional fall through here ****
+ case WPN_HAND_AXE:
+ if (one_chance_in(30))
+ rc = SPWPN_PAIN;
+
+ if (one_chance_in(10))
+ rc = SPWPN_VAMPIRICISM;
+
+ if (item.sub_type == WPN_HAND_AXE &&
+ one_chance_in(10))
+ rc = SPWPN_RETURNING;
+
+ if (got_distortion_roll(item_level))
+ rc = SPWPN_DISTORTION;
+
+ if (one_chance_in(3) && (rc == SPWPN_NORMAL || one_chance_in(5)))
{
- set_item_ego_type( mitm[p], OBJ_WEAPONS, SPWPN_NORMAL );
+ rc = SPWPN_VORPAL;
}
- }
- if (weapon_is_visibly_special(mitm[p]))
- {
- set_equip_desc( mitm[p], (coinflip() ? ISFLAG_GLOWING
- : ISFLAG_RUNED) );
- }
- break;
+ if (one_chance_in(6))
+ rc = SPWPN_ORC_SLAYING;
- case OBJ_MISSILES:
- quant = 0;
- mitm[p].plus = 0;
- mitm[p].special = SPMSL_NORMAL;
+ if (one_chance_in(4))
+ rc = coinflip() ? SPWPN_FLAMING : SPWPN_FREEZING;
- if (force_type != OBJ_RANDOM)
- mitm[p].sub_type = force_type;
- else
- mitm[p].sub_type =
- random_choose_weighted(30, MI_STONE,
- 20, MI_DART,
- 20, MI_ARROW,
- 10, MI_NEEDLE,
- 5, MI_SLING_BULLET,
- 2, MI_JAVELIN,
- 0);
+ if (one_chance_in(8))
+ rc = SPWPN_ELECTROCUTION;
+
+ if (one_chance_in(12))
+ rc = SPWPN_VENOM;
- // 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);
+
+ case WPN_WHIP:
+ if (got_distortion_roll(item_level))
+ rc = SPWPN_DISTORTION;
+
+ if (one_chance_in(6))
+ rc = coinflip() ? SPWPN_FLAMING : SPWPN_FREEZING;
+
+ if (one_chance_in(6))
+ rc = SPWPN_VENOM;
+
+ if (coinflip())
+ rc = SPWPN_REACHING;
+
+ if (one_chance_in(5))
+ rc = SPWPN_SPEED;
+
+ if (one_chance_in(5))
+ rc = SPWPN_ELECTROCUTION;
break;
- }
- // set racial type:
- switch (item_race)
- {
- case MAKE_ITEM_ELVEN:
- set_equip_race( mitm[p], ISFLAG_ELVEN );
+ case WPN_HALBERD:
+ case WPN_GLAIVE:
+ case WPN_SCYTHE:
+ case WPN_TRIDENT:
+ case WPN_LOCHABER_AXE:
+ if (one_chance_in(30))
+ rc = SPWPN_HOLY_WRATH;
+
+ if (one_chance_in(4))
+ rc = SPWPN_PROTECTION;
+ // **** intentional fall through here ****
+ if (one_chance_in(5))
+ rc = SPWPN_SPEED;
+ // **** intentional fall through here ****
+ case WPN_SPEAR:
+ if (one_chance_in(25))
+ rc = SPWPN_PAIN;
+
+ if (one_chance_in(10))
+ rc = SPWPN_VAMPIRICISM;
+
+ if (item.sub_type == WPN_SPEAR && one_chance_in(6))
+ rc = SPWPN_RETURNING;
+
+ if (got_distortion_roll(item_level))
+ rc = SPWPN_DISTORTION;
+
+ if (one_chance_in(5) && (rc == SPWPN_NORMAL || one_chance_in(6)))
+ rc = SPWPN_VORPAL;
+
+ if (one_chance_in(6))
+ rc = SPWPN_ORC_SLAYING;
+
+ if (one_chance_in(6))
+ rc = coinflip() ? SPWPN_FLAMING : SPWPN_FREEZING;
+
+ if (one_chance_in(6))
+ rc = SPWPN_VENOM;
+
+ if (one_chance_in(3))
+ rc = SPWPN_REACHING;
break;
- case MAKE_ITEM_DWARVEN:
- set_equip_race( mitm[p], ISFLAG_DWARVEN );
+
+ case WPN_SLING:
+ case WPN_HAND_CROSSBOW:
+ if (coinflip())
+ break;
+ // **** possible intentional fall through here ****
+ case WPN_BOW:
+ case WPN_LONGBOW:
+ case WPN_CROSSBOW:
+ {
+ const int tmp = random2(1000);
+ if ( tmp < 375 )
+ rc = SPWPN_FLAME;
+ else if ( tmp < 750 )
+ rc = SPWPN_FROST;
+ else if ( tmp < 920 )
+ rc = SPWPN_PROTECTION;
+ else if ( tmp < 980 )
+ rc = SPWPN_VORPAL;
+ else
+ rc = SPWPN_SPEED;
break;
+ }
+
+ // quarterstaff - not powerful, as this would make
+ // the 'staves' skill just too good
+ case WPN_QUARTERSTAFF:
+ if (one_chance_in(30))
+ rc = SPWPN_PAIN;
+
+ if (got_distortion_roll(item_level))
+ rc = SPWPN_DISTORTION;
+
+ if (one_chance_in(5))
+ rc = SPWPN_SPEED;
- case MAKE_ITEM_ORCISH:
- set_equip_race( mitm[p], ISFLAG_ORCISH );
+ if (one_chance_in(10))
+ rc = SPWPN_VORPAL;
+
+ if (one_chance_in(5))
+ rc = SPWPN_PROTECTION;
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 );
- }
+ case WPN_DEMON_TRIDENT:
+ case WPN_DEMON_WHIP:
+ case WPN_DEMON_BLADE:
+ if (one_chance_in(10))
+ rc = SPWPN_PAIN;
- if ((mitm[p].sub_type == MI_DART
- || mitm[p].sub_type == MI_BOLT)
- && one_chance_in(6))
+ if (one_chance_in(3)
+ && (item.sub_type == WPN_DEMON_WHIP
+ || item.sub_type == WPN_DEMON_TRIDENT))
{
- set_equip_race( mitm[p], ISFLAG_DWARVEN );
+ rc = SPWPN_REACHING;
}
- 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 );
- }
+ if (one_chance_in(5))
+ rc = SPWPN_DRAINING;
+
+ if (one_chance_in(5))
+ rc = coinflip() ? SPWPN_FLAMING : SPWPN_FREEZING;
+
+ if (one_chance_in(5))
+ rc = SPWPN_ELECTROCUTION;
+
+ if (one_chance_in(5))
+ rc = SPWPN_VAMPIRICISM;
+
+ if (one_chance_in(5))
+ rc = SPWPN_VENOM;
+ break;
+
+ case WPN_BLESSED_BLADE: // special gift of TSO
+ rc = SPWPN_HOLY_WRATH;
+ break;
+
+ default:
+ // unlisted weapons have no associated, standard ego-types {dlb}
break;
}
+ }
+ return rc;
+}
+
+static void generate_weapon_item(item_def& item, bool allow_uniques,
+ int force_type, int item_level,
+ int item_race)
+{
+ // Determine weapon type.
+ if ( force_type != OBJ_RANDOM )
+ item.sub_type = force_type;
+ else
+ item.sub_type = determine_weapon_subtype(item_level);
+
+ // If we make the unique roll, no further generation necessary.
+ if (allow_uniques && try_make_weapon_artefact(item, force_type, item_level))
+ return;
+
+ ASSERT(!is_fixed_artefact(item) && !is_random_artefact(item));
+
+ // Artefacts handled, let's make a normal item.
+ const bool force_good = (item_level == MAKE_GOOD_ITEM);
- // 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)
+ // If it's forced to be a good item, upgrade the worst weapons.
+ if (force_good
+ && force_type == OBJ_RANDOM
+ && (item.sub_type == WPN_CLUB || item.sub_type == WPN_SLING))
+ {
+ item.sub_type = WPN_LONG_SWORD;
+ }
+
+ item.plus = 0;
+ item.plus2 = 0;
+ item.special = SPWPN_NORMAL;
+
+ set_equip_race(item, determine_weapon_race(item, item_race));
+
+ // 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 (force_good && get_equip_race( item ) == ISFLAG_ORCISH)
+ set_equip_race( item, ISFLAG_NO_RACE );
+
+ // Demonic items can't be racial.
+ if ( is_demonic(item) )
+ set_equip_race( item, ISFLAG_NO_RACE );
+
+ weapon_add_racial_modifiers(item);
+
+ if ((force_good || is_demonic(item) || random2(200) <= 50 + item_level)
+ // nobody would bother enchanting a club
+ && item.sub_type != WPN_CLUB
+ && item.sub_type != WPN_GIANT_CLUB
+ && item.sub_type != WPN_GIANT_SPIKED_CLUB)
+ {
+ // Make a better item (possibly ego)
+ set_item_ego_type(item, OBJ_WEAPONS,
+ determine_weapon_brand(item, item_level));
+
+ // if acquired item still not ego... enchant it up a bit.
+ if (force_good && item.special == SPWPN_NORMAL)
{
- const int pois =
- got_curare_roll(item_level) ? SPMSL_CURARE : SPMSL_POISONED;
- set_item_ego_type( mitm[p], OBJ_MISSILES, pois );
+ item.plus += 2 + random2(3);
+ item.plus2 += 2 + random2(3);
}
- else
+
+ const int chance = force_good ? 200 : item_level;
+
+ // odd-looking, but this is how the algorithm compacts {dlb}:
+ for (int i = 0; i < 4; ++i)
{
- // decide specials:
- if (make_good_item)
- temp_rand = random2(150);
- else
- temp_rand = random2(2000 - 55 * item_level);
+ item.plus += random2(3);
- set_item_ego_type( mitm[p], OBJ_MISSILES,
- (temp_rand < 60) ? SPMSL_FLAME :
- (temp_rand < 120) ? SPMSL_ICE :
- (temp_rand < 150) ? SPMSL_POISONED
- : SPMSL_NORMAL );
+ if (random2(350) > 20 + chance)
+ break;
}
- // orcish ammo gets poisoned a lot more often -- in the original
- // code it was poisoned every time!?
- if (get_equip_race(mitm[p]) == ISFLAG_ORCISH && one_chance_in(3))
- set_item_ego_type( mitm[p], OBJ_MISSILES, SPMSL_POISONED );
+ // odd-looking, but this is how the algorithm compacts {dlb}:
+ for (int i = 0; i < 4; ++i)
+ {
+ item.plus2 += random2(3);
- // Un-poison sling bullets, unbrand nets.
- if ((mitm[p].sub_type == MI_SLING_BULLET
- && get_ammo_brand( mitm[p] ) == SPMSL_POISONED)
- || mitm[p].sub_type == MI_THROWING_NET)
+ if (random2(500) > 50 + chance)
+ break;
+ }
+ }
+ else
+ {
+ if (one_chance_in(12))
{
- set_item_ego_type( mitm[p], OBJ_MISSILES, SPMSL_NORMAL );
+ // make a cursed item
+ do_curse_item( item );
+ item.plus -= random2(4);
+ item.plus2 -= random2(4);
+ set_item_ego_type( item, OBJ_WEAPONS, SPWPN_NORMAL );
}
+ }
- // reduced quantity if special
- if (mitm[p].sub_type == MI_JAVELIN
- || get_ammo_brand( mitm[p] ) == SPMSL_CURARE)
+ if (get_equip_race(item) == ISFLAG_ORCISH)
+ {
+ // no holy wrath or slay orc and 1/2 the time no-ego
+ const int brand = get_weapon_brand( item );
+ if (brand == SPWPN_HOLY_WRATH
+ || brand == SPWPN_ORC_SLAYING
+ || (brand != SPWPN_NORMAL && coinflip()))
{
- quant = random_range(2, 8);
+ set_item_ego_type( item, OBJ_WEAPONS, SPWPN_NORMAL );
}
- else 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);
+ if (weapon_is_visibly_special(item))
+ set_equip_desc( item, (coinflip() ? ISFLAG_GLOWING : ISFLAG_RUNED) );
- // elven arrows and dwarven bolts are quality items
- if ((get_equip_race(mitm[p]) == ISFLAG_ELVEN
- && mitm[p].sub_type == MI_ARROW)
- || (get_equip_race(mitm[p]) == ISFLAG_DWARVEN
- && mitm[p].sub_type == MI_BOLT))
- {
- mitm[p].plus += random2(3);
- }
+ // All done!
+}
+
+static item_status_flag_type determine_missile_race(const item_def& item,
+ int item_race)
+{
+ item_status_flag_type rc = ISFLAG_NO_RACE;
+ switch (item_race)
+ {
+ case MAKE_ITEM_ELVEN:
+ rc = ISFLAG_ELVEN;
break;
- case OBJ_ARMOUR:
- quant = 1;
+ case MAKE_ITEM_DWARVEN:
+ rc = ISFLAG_DWARVEN;
+ break;
- mitm[p].plus = 0;
- mitm[p].plus2 = 0;
- mitm[p].special = SPARM_NORMAL;
+ case MAKE_ITEM_ORCISH:
+ rc = ISFLAG_ORCISH;
+ break;
- if (force_type != OBJ_RANDOM)
- mitm[p].sub_type = force_type;
- else
+ case MAKE_ITEM_RANDOM_RACE:
+ // Elves don't make bolts
+ if ((item.sub_type == MI_ARROW || item.sub_type == MI_DART)
+ && one_chance_in(4))
{
- mitm[p].sub_type = get_random_armour_type(item_level);
+ rc = ISFLAG_ELVEN;
}
- if (mitm[p].sub_type == ARM_HELMET)
+ // Orcs make everything
+ if ((item.sub_type == MI_ARROW
+ || item.sub_type == MI_BOLT
+ || item.sub_type == MI_DART)
+ && one_chance_in(4))
{
- 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] );
+ rc = ISFLAG_ORCISH;
+ }
+
+ // Dwarves don't make arrows (or needles, see below)
+ if ((item.sub_type == MI_DART || item.sub_type == MI_BOLT)
+ && one_chance_in(6))
+ {
+ rc = ISFLAG_DWARVEN;
}
- if (allow_uniques == 1
- && item_level > 2
- && random2(2000) <= (100 + item_level * 3)
- && coinflip())
+ if (item.sub_type == MI_NEEDLE)
{
- 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;
- }
- }
+ if (one_chance_in(10))
+ rc = ISFLAG_ELVEN;
+ if (one_chance_in(6))
+ rc = ISFLAG_ORCISH;
+ }
+ break;
+ }
+ return rc;
+}
- hide2armour(mitm[p]);
+static special_missile_type determine_missile_brand(const item_def& item,
+ int item_level)
+{
+ const bool force_good = (item_level == MAKE_GOOD_ITEM);
+ special_missile_type rc = SPMSL_NORMAL;
+ // 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
+
+ // All needles are either poison or curare.
+ if (item.sub_type == MI_NEEDLE)
+ rc = got_curare_roll(item_level) ? SPMSL_CURARE : SPMSL_POISONED;
+ else
+ {
+ const int temp_rand =
+ (force_good ? random2(150) : random2(2000 - 55 * item_level));
+
+ if ( temp_rand < 60 )
+ rc = SPMSL_FLAME;
+ else if (temp_rand < 120)
+ rc = SPMSL_ICE;
+ else if (temp_rand < 150)
+ rc = SPMSL_POISONED;
+ else
+ rc = SPMSL_NORMAL;
+ }
- // mitm[p].special = SPARM_RANDART_II + random2(4);
- make_item_randart( mitm[p] );
- mitm[p].plus = 0;
+ // orcish ammo gets poisoned a lot more often -- in the original
+ // code it was poisoned every time!?
+ if (get_equip_race(item) == ISFLAG_ORCISH && one_chance_in(3))
+ rc = SPMSL_POISONED;
- if (mitm[p].sub_type == ARM_BOOTS
- && one_chance_in(10))
- {
- mitm[p].sub_type =
- coinflip()? ARM_NAGA_BARDING
- : ARM_CENTAUR_BARDING;
- }
+ // Un-poison sling bullets, unbrand nets.
+ if ((item.sub_type == MI_SLING_BULLET && rc == SPMSL_POISONED)
+ || item.sub_type == MI_THROWING_NET)
+ {
+ rc = SPMSL_NORMAL;
+ }
+ return rc;
+}
+
+static void generate_missile_item(item_def& item, int force_type,
+ int item_level, int item_race)
+{
+ item.plus = 0;
+ item.special = SPMSL_NORMAL;
- mitm[p].plus += random2(4);
+ if (force_type != OBJ_RANDOM)
+ item.sub_type = force_type;
+ else
+ item.sub_type =
+ random_choose_weighted(30, MI_STONE,
+ 20, MI_DART,
+ 20, MI_ARROW,
+ 10, MI_NEEDLE,
+ 5, MI_SLING_BULLET,
+ 2, MI_JAVELIN,
+ 0);
+
+ // no fancy rocks -- break out before we get to racial/special stuff
+ if (item.sub_type == MI_LARGE_ROCK)
+ {
+ item.quantity = 2 + random2avg(5,2);
+ return;
+ }
+ else if (item.sub_type == MI_STONE)
+ {
+ item.quantity = 1+random2(9) + random2(12) + random2(15) + random2(12);
+ return;
+ }
- if (one_chance_in(5))
- mitm[p].plus += random2(4);
+ set_equip_race(item, determine_missile_race(item, item_race));
+ set_item_ego_type( item, OBJ_MISSILES,
+ determine_missile_brand(item, item_level) );
- if (one_chance_in(6))
- mitm[p].plus -= random2(8);
+ // reduced quantity if special
+ if (item.sub_type == MI_JAVELIN || get_ammo_brand( item ) == SPMSL_CURARE)
+ item.quantity = random_range(2, 8);
+ else if (get_ammo_brand( item ) != SPMSL_NORMAL )
+ item.quantity = 1+random2(9) + random2(12) + random2(12);
+ else
+ item.quantity = 1+random2(9) + random2(12) + random2(12) + random2(15);
- quant = 1;
+ if (10 + item_level >= random2(100))
+ item.plus += random2(5);
- 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))
+ // elven arrows and dwarven bolts are quality items
+ if ((get_equip_race(item) == ISFLAG_ELVEN && item.sub_type == MI_ARROW) ||
+ (get_equip_race(item) == ISFLAG_DWARVEN && item.sub_type == MI_BOLT))
+ {
+ item.plus += random2(3);
+ }
+}
+
+static bool try_make_armour_artefact(item_def& item, int force_type,
+ int item_level)
+{
+ if ( item_level > 2 && random2(4000) <= (100 + item_level * 3))
+ {
+ // Make a randart or unrandart.
+
+ // 1 in 50 randarts are unrandarts.
+ if ((you.level_type != LEVEL_ABYSS
+ && you.level_type != LEVEL_PANDEMONIUM)
+ && one_chance_in(50))
+ {
+ // The old generation code did not respect force_type here.
+ const int idx = find_okay_unrandart(OBJ_ARMOUR, force_type);
+ if (idx != -1)
{
- do_curse_item( mitm[p] );
+ make_item_unrandart( item, idx );
+ return true;
}
- break;
}
- mitm[p].plus = 0;
+ // The other 98% are normal randarts.
- 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;
+ // No randart hides.
+ hide2armour(item);
+ make_item_randart( item );
- 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;
+ // 10% of boots become barding.
+ if (item.sub_type == ARM_BOOTS && one_chance_in(10))
+ item.sub_type = coinflip() ? ARM_NAGA_BARDING : ARM_CENTAUR_BARDING;
- case ARM_GLOVES:
- if (one_chance_in(4))
- set_equip_race( mitm[p], ISFLAG_ELVEN );
- break;
+ // Determine enchantment and cursedness.
+ if (one_chance_in(5))
+ {
+ do_curse_item( item );
+ item.plus = -random2(6);
+ }
+ else
+ {
+ item.plus = random2(4);
+
+ if (one_chance_in(5))
+ item.plus += random2(4);
+
+ if (one_chance_in(6))
+ item.plus -= random2(8);
+
+ if (item.plus < 0 && !one_chance_in(3))
+ do_curse_item( item );
+ }
+ return true;
+ }
+ return false;
+}
- case ARM_NAGA_BARDING:
- case ARM_CENTAUR_BARDING:
- case ARM_BOOTS:
- if (mitm[p].sub_type == ARM_BOOTS)
- {
- if (one_chance_in(4))
- {
- mitm[p].sub_type = ARM_NAGA_BARDING;
- break;
- }
-
- if (one_chance_in(4))
- {
- mitm[p].sub_type = ARM_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;
+static void determine_helmet_types(item_def& item)
+{
+ set_helmet_type( item, THELM_HELMET );
+ set_helmet_desc( item, THELM_DESC_PLAIN );
- case ARM_HELMET:
- if (get_helmet_type(mitm[p]) == THELM_CAP
- || get_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;
+ if (one_chance_in(3))
+ set_helmet_type( item, random2( THELM_NUM_TYPES ) );
- case ARM_ROBE:
- if (one_chance_in(4))
- set_equip_race( mitm[p], ISFLAG_ELVEN );
- break;
+ if (one_chance_in(3))
+ set_helmet_random_desc( item );
+}
- 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;
- }
- }
+static item_status_flag_type determine_armour_race(const item_def& item,
+ int item_race)
+{
+ item_status_flag_type rc = ISFLAG_NO_RACE;
+ switch (item_race)
+ {
+ case MAKE_ITEM_ELVEN:
+ rc = ISFLAG_ELVEN;
+ break;
+
+ case MAKE_ITEM_DWARVEN:
+ rc = ISFLAG_DWARVEN;
+ break;
- switch (item_race)
+ case MAKE_ITEM_ORCISH:
+ rc = ISFLAG_ORCISH;
+ break;
+
+ case MAKE_ITEM_RANDOM_RACE:
+ if ( coinflip() )
+ break;
+
+ switch (item.sub_type)
{
- case MAKE_ITEM_ELVEN:
- set_equip_race( mitm[p], ISFLAG_ELVEN );
+ case ARM_SHIELD:
+ case ARM_BUCKLER:
+ case ARM_LARGE_SHIELD:
+ if (one_chance_in(4))
+ rc = ISFLAG_ELVEN;
+ if (one_chance_in(3))
+ rc = ISFLAG_DWARVEN;
break;
- case MAKE_ITEM_DWARVEN:
- set_equip_race( mitm[p], ISFLAG_DWARVEN );
- if (coinflip())
- mitm[p].plus++;
+ case ARM_CLOAK:
+ if (one_chance_in(4))
+ rc = ISFLAG_ORCISH;
+ if (one_chance_in(4))
+ rc = ISFLAG_DWARVEN;
+ if (one_chance_in(4))
+ rc = ISFLAG_ELVEN;
break;
- case MAKE_ITEM_ORCISH:
- set_equip_race( mitm[p], ISFLAG_ORCISH );
+ case ARM_GLOVES:
+ if (one_chance_in(4))
+ rc = ISFLAG_ELVEN;
break;
- }
-
- if (50 + item_level >= random2(250)
- || make_good_item
- || (mitm[p].sub_type == ARM_HELMET
- && get_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);
+ case ARM_NAGA_BARDING:
+ case ARM_CENTAUR_BARDING:
+ case ARM_BOOTS:
+ if (one_chance_in(4))
+ rc = ISFLAG_ORCISH;
+ if (one_chance_in(4))
+ rc = ISFLAG_ELVEN;
+ if (one_chance_in(6))
+ rc = ISFLAG_DWARVEN;
+ break;
- if (30 + item_level >= random2(350)
- && (make_good_item
- || (!get_equip_race(mitm[p]) == ISFLAG_ORCISH
- || (mitm[p].sub_type <= ARM_PLATE_MAIL && coinflip()))))
+ case ARM_HELMET:
+ if (get_helmet_type(item) == THELM_CAP
+ || get_helmet_type(item) == THELM_WIZARD_HAT)
{
- switch (mitm[p].sub_type)
- {
- case ARM_SHIELD: // shield - must do special things for this!
- case ARM_LARGE_SHIELD:
- case ARM_BUCKLER:
- {
- const int tmp = random2(1000);
-
- set_item_ego_type( mitm[p], OBJ_ARMOUR,
- (tmp < 40) ? SPARM_RESISTANCE :
- (tmp < 160) ? SPARM_FIRE_RESISTANCE :
- (tmp < 280) ? SPARM_COLD_RESISTANCE :
- (tmp < 400) ? SPARM_POISON_RESISTANCE :
- (tmp < 520) ? SPARM_POSITIVE_ENERGY
- : SPARM_PROTECTION );
- break; // prot
- //break;
- }
- case ARM_CLOAK:
- if (get_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 (get_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:
- case ARM_NAGA_BARDING:
- case ARM_CENTAUR_BARDING:
- {
- const int tmp = random2(600)
- + 200 * (mitm[p].sub_type != ARM_BOOTS);
-
- set_item_ego_type( mitm[p], OBJ_ARMOUR,
- (tmp < 200) ? SPARM_RUNNING :
- (tmp < 400) ? SPARM_LEVITATION :
- (tmp < 600) ? SPARM_STEALTH :
- (tmp < 700) ? SPARM_COLD_RESISTANCE
- : SPARM_FIRE_RESISTANCE );
- 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;
- }
+ if (one_chance_in(6))
+ rc = ISFLAG_ELVEN;
}
- }
- else if (one_chance_in(12))
- {
- // mitm[p].plus = (coinflip() ? 99 : 98); // 98? 99?
- do_curse_item( mitm[p] );
+ else
+ {
+ // helms and helmets
+ if (one_chance_in(8))
+ rc = ISFLAG_ORCISH;
+ if (one_chance_in(6))
+ rc = ISFLAG_DWARVEN;
+ }
+ break;
+ case ARM_ROBE:
+ if (one_chance_in(4))
+ rc = 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 (item.sub_type <= ARM_CHAIN_MAIL && one_chance_in(6))
+ rc = ISFLAG_ELVEN;
+ if (item.sub_type >= ARM_RING_MAIL && one_chance_in(5))
+ rc = ISFLAG_DWARVEN;
if (one_chance_in(5))
- mitm[p].plus -= random2(3);
+ rc = ISFLAG_ORCISH;
- set_item_ego_type( mitm[p], OBJ_ARMOUR, SPARM_NORMAL );
+ default: // skins, hides, crystal plate are always plain
+ break;
}
+ }
+ return rc;
+}
- // if not given a racial type, and special, give shiny/runed/etc desc.
- if (get_equip_desc(mitm[p]) == 0
- && (is_random_artefact(mitm[p])
- || get_armour_ego_type( mitm[p] ) != SPARM_NORMAL
- || (mitm[p].plus != 0 && !one_chance_in(3))))
- {
- switch (random2(3))
- {
- case 0:
- set_equip_desc( mitm[p], ISFLAG_GLOWING );
- break;
+static special_armour_type determine_armour_ego(const item_def& item,
+ int force_type, int item_level)
+{
+ special_armour_type rc = SPARM_NORMAL;
+ switch (item.sub_type)
+ {
+ case ARM_SHIELD:
+ case ARM_LARGE_SHIELD:
+ case ARM_BUCKLER:
+ rc = static_cast<special_armour_type>(
+ random_choose_weighted(40, SPARM_RESISTANCE,
+ 120, SPARM_FIRE_RESISTANCE,
+ 120, SPARM_COLD_RESISTANCE,
+ 120, SPARM_POISON_RESISTANCE,
+ 120, SPARM_POSITIVE_ENERGY,
+ 480, SPARM_PROTECTION,
+ 0));
+ break;
- case 1:
- set_equip_desc( mitm[p], ISFLAG_RUNED );
- break;
+ case ARM_CLOAK:
+ {
+ if (get_equip_race(item) == ISFLAG_DWARVEN)
+ break;
+ const special_armour_type cloak_egos[] = {
+ SPARM_POISON_RESISTANCE, SPARM_DARKNESS,
+ SPARM_MAGIC_RESISTANCE, SPARM_PRESERVATION
+ };
+ rc = RANDOM_ELEMENT(cloak_egos);
+ break;
+ }
- case 2:
- default:
- set_equip_desc( mitm[p], ISFLAG_EMBROIDERED_SHINY );
- break;
- }
+ case ARM_HELMET:
+ if (get_helmet_type(item) == THELM_WIZARD_HAT && coinflip())
+ {
+ rc = one_chance_in(3) ?
+ SPARM_MAGIC_RESISTANCE : SPARM_INTELLIGENCE;
}
+ else
+ rc = coinflip() ? SPARM_SEE_INVISIBLE : SPARM_INTELLIGENCE;
+ 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 (make_good_item)
- hide2armour(mitm[p]); // what of animal hides? {dlb}
+ case ARM_GLOVES:
+ rc = coinflip() ? SPARM_DEXTERITY : SPARM_STRENGTH;
+ break;
- // 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 );
- }
+ case ARM_BOOTS:
+ case ARM_NAGA_BARDING:
+ case ARM_CENTAUR_BARDING:
+ {
+ const int tmp = random2(600) + 200 * (item.sub_type != ARM_BOOTS);
+
+ rc = (tmp < 200) ? SPARM_RUNNING :
+ (tmp < 400) ? SPARM_LEVITATION :
+ (tmp < 600) ? SPARM_STEALTH :
+ (tmp < 700) ? SPARM_COLD_RESISTANCE : SPARM_FIRE_RESISTANCE;
break;
+ }
- case OBJ_WANDS:
- // determine sub_type:
- if (force_type != OBJ_RANDOM)
- mitm[p].sub_type = force_type;
- else
+ case ARM_ROBE:
+ switch (random2(4))
{
- 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 );
- }
- }
+ case 0:
+ rc = coinflip() ? SPARM_COLD_RESISTANCE : SPARM_FIRE_RESISTANCE;
+ break;
+
+ case 1:
+ rc = SPARM_MAGIC_RESISTANCE;
+ break;
- // 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);
-
- // plus2 tracks how many times the player has zapped it.
- // If it is -1, then the player knows it's empty.
- // If it is -2, then the player has messed with it somehow
- // (presumably by recharging), so don't bother to display the
- // count.
- mitm[p].plus2 = 0;
-
- // 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
+ case 2:
+ rc = coinflip() ? SPARM_POSITIVE_ENERGY : SPARM_RESISTANCE;
+ break;
+ case 3:
+ // This is an odd limitation, but I'm not changing it yet.
+ if (force_type == OBJ_RANDOM && random2(50) <= 10 + item_level)
+ rc = SPARM_ARCHMAGI;
+ break;
}
- else
- mitm[p].sub_type = force_type;
+ break;
- // 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_species( temp_rand ); // corpse base type
+ default: // other body armours:
+ rc = coinflip() ? SPARM_COLD_RESISTANCE : SPARM_FIRE_RESISTANCE;
- if (mons_weight( temp_rand ) > 0) // drops a corpse
- break;
- }
+ if (one_chance_in(9))
+ rc = SPARM_POSITIVE_ENERGY;
- // 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;
- }
+ if (one_chance_in(5))
+ rc = SPARM_MAGIC_RESISTANCE;
- // determine quantity:
- if (allow_uniques > 1)
- quant = allow_uniques;
- else
- {
- quant = 1;
+ if (one_chance_in(5))
+ rc = SPARM_POISON_RESISTANCE;
- 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);
- }
- }
- }
+ if (item.sub_type == ARM_PLATE_MAIL && one_chance_in(15))
+ rc = SPARM_PONDEROUSNESS;
break;
+ }
+ return rc;
+}
- case OBJ_POTIONS:
- quant = 1;
- if (one_chance_in(18))
- quant++;
+static void generate_armour_item(item_def& item, bool allow_uniques,
+ int force_type, int item_level, int item_race)
+{
+ if (force_type != OBJ_RANDOM)
+ item.sub_type = force_type;
+ else
+ item.sub_type = get_random_armour_type(item_level);
- if (one_chance_in(25))
- quant++;
+ if (allow_uniques && try_make_armour_artefact(item, force_type, item_level))
+ return;
- if (force_type != OBJ_RANDOM)
- mitm[p].sub_type = force_type;
- else
- {
- temp_rand = random2(9); // general type of potion;
+ if (item.sub_type == ARM_HELMET)
+ determine_helmet_types(item);
- 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;
+ if (item_race == MAKE_ITEM_RANDOM_RACE && item.sub_type == ARM_BOOTS)
+ {
+ if (one_chance_in(8))
+ item.sub_type = ARM_NAGA_BARDING;
+ else if (one_chance_in(7))
+ item.sub_type = ARM_CENTAUR_BARDING;
+ }
+ else
+ set_equip_race(item, determine_armour_race(item, item_race));
- case 3:
- case 4:
- // enhancements
- if (coinflip())
- mitm[p].sub_type = POT_SPEED;
- else
- mitm[p].sub_type = POT_MIGHT;
+ // Dwarven armour is high-quality.
+ if ( get_equip_race(item) == ISFLAG_DWARVEN && coinflip() )
+ item.plus++;
- if (one_chance_in(10))
- mitm[p].sub_type = POT_BERSERK_RAGE;
+ const bool force_good = (item_level == MAKE_GOOD_ITEM);
- if (one_chance_in(5))
- mitm[p].sub_type = POT_INVISIBILITY;
+ if (force_good || (item.sub_type == ARM_HELMET
+ && get_helmet_type(item) == THELM_WIZARD_HAT)
+ || 50 + item_level >= random2(250))
+ {
+ // Make a good item...
+ item.plus += random2(3);
- if (one_chance_in(6))
- mitm[p].sub_type = POT_LEVITATION;
+ if (item.sub_type <= ARM_PLATE_MAIL && 20 + item_level >= random2(300))
+ item.plus += random2(3);
- if (one_chance_in(8))
- mitm[p].sub_type = POT_RESISTANCE;
+ if (30 + item_level >= random2(350)
+ && (force_good
+ || (!get_equip_race(item) == ISFLAG_ORCISH
+ || (item.sub_type <= ARM_PLATE_MAIL && coinflip()))))
+ {
+ // ...an ego item, in fact.
+ set_item_ego_type(item, OBJ_ARMOUR,
+ determine_armour_ego(item, force_type,
+ item_level));
- if (one_chance_in(30))
- mitm[p].sub_type = POT_PORRIDGE;
- break;
+ if ( get_armour_ego_type(item) == SPARM_PONDEROUSNESS )
+ item.plus += 3 + random2(4);
+ }
+ }
+ else if (one_chance_in(12))
+ {
+ // Make a bad (cursed) item
+ do_curse_item( item );
- case 5:
- // gain ability
- mitm[p].sub_type = POT_GAIN_STRENGTH + random2(3); // 1.125%
- // or 0.375% each
+ if (one_chance_in(5))
+ item.plus -= random2(3);
- if (one_chance_in(10))
- mitm[p].sub_type = POT_EXPERIENCE; // 0.125%
+ set_item_ego_type( item, OBJ_ARMOUR, SPARM_NORMAL );
+ }
- if (one_chance_in(10))
- mitm[p].sub_type = POT_MAGIC; // 0.139%
+ // if not given a racial type, and special, give shiny/runed/etc desc.
+ if (get_equip_desc(item) == ISFLAG_NO_DESC
+ && (get_armour_ego_type( item ) != SPARM_NORMAL
+ || (item.plus != 0 && !one_chance_in(3))))
+ {
+ const item_status_flag_type descs[] = {
+ ISFLAG_GLOWING, ISFLAG_RUNED, ISFLAG_EMBROIDERED_SHINY
+ };
- if (!one_chance_in(8))
- mitm[p].sub_type = POT_RESTORE_ABILITIES; // 9.722%
+ set_equip_desc( item, RANDOM_ELEMENT(descs) );
+ }
- quant = 1;
- 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 (force_good)
+ hide2armour(item); // what of animal hides? {dlb}
- 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;
-
- }
+ // skin armours + Crystal PM don't get special enchantments
+ // or species, but can be randarts
+ if (item.sub_type >= ARM_DRAGON_HIDE
+ && item.sub_type <= ARM_SWAMP_DRAGON_ARMOUR)
+ {
+ set_equip_race( item, ISFLAG_NO_RACE );
+ set_item_ego_type( item, OBJ_ARMOUR, SPARM_NORMAL );
+ }
+}
- if (one_chance_in(8))
- mitm[p].sub_type = POT_DEGENERATION; // 2.775%
+static monster_type choose_random_monster_corpse()
+{
+ for (int count = 0; count < 1000; ++count)
+ {
+ monster_type spc = mons_species(random2(NUM_MONSTERS));
+ if (mons_weight(spc) > 0) // drops a corpse
+ return spc;
+ }
+ return MONS_RAT; // if you can't find anything else...
+}
- if (one_chance_in(1000)) // 0.022%
- mitm[p].sub_type = POT_DECAY;
+static int random_wand_subtype()
+{
+ int rc = random2( NUM_WANDS );
- break;
- }
- }
+ // 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 ((rc == WAND_INVISIBILITY || rc == WAND_HASTING || rc == WAND_HEALING)
+ || ((rc == WAND_FIREBALL || rc == WAND_TELEPORTATION) && coinflip()))
+ {
+ rc = random2( NUM_WANDS );
+ }
+ return rc;
+}
- mitm[p].plus = 0;
- break;
+static int wand_max_charges(int subtype)
+{
+ switch (subtype)
+ {
+ case WAND_HEALING: case WAND_HASTING: case WAND_INVISIBILITY:
+ return 8;
+
+ case WAND_FLAME: case WAND_FROST: case WAND_MAGIC_DARTS:
+ case WAND_RANDOM_EFFECTS:
+ return 28;
- 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;
+ default:
+ return 16;
+ }
+}
- // determine quantity:
- temp_rand = random2(48);
+static void generate_wand_item(item_def& item, int force_type)
+{
+ // determine sub_type
+ if (force_type != OBJ_RANDOM)
+ item.sub_type = force_type;
+ else
+ item.sub_type = random_wand_subtype();
- 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;
+ // generate charges randomly...
+ item.plus = random2avg(wand_max_charges(item.sub_type), 3);
- 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);
+ // ...but 0 charges is silly
+ if ( item.plus == 0 )
+ item.plus++;
- if (icky != -1)
- {
- quant = 1;
- make_item_unrandart( mitm[p], icky );
- break;
- }
- }
+ // plus2 tracks how many times the player has zapped it.
+ // If it is -1, then the player knows it's empty.
+ // If it is -2, then the player has messed with it somehow
+ // (presumably by recharging), so don't bother to display the
+ // count.
+ item.plus2 = 0;
+}
- // otherwise, determine jewellery type {dlb}:
- if (force_type == OBJ_RANDOM)
+static void generate_food_item(item_def& item, int force_quant, int force_type)
+{
+ // determine sub_type:
+ if (force_type == OBJ_RANDOM)
+ {
+ item.sub_type = random_choose_weighted( 250, FOOD_MEAT_RATION,
+ 300, FOOD_BREAD_RATION,
+ 100, FOOD_PEAR,
+ 100, FOOD_APPLE,
+ 100, FOOD_CHOKO,
+ 10, FOOD_CHEESE,
+ 10, FOOD_PIZZA,
+ 10, FOOD_SNOZZCUMBER,
+ 10, FOOD_APRICOT,
+ 10, FOOD_ORANGE,
+ 10, FOOD_BANANA,
+ 10, FOOD_STRAWBERRY,
+ 10, FOOD_RAMBUTAN,
+ 10, FOOD_LEMON,
+ 10, FOOD_GRAPE,
+ 10, FOOD_SULTANA,
+ 10, FOOD_LYCHEE,
+ 10, FOOD_BEEF_JERKY,
+ 10, FOOD_SAUSAGE,
+ 5, FOOD_HONEYCOMB,
+ 5, FOOD_ROYAL_JELLY,
+ 0);
+ }
+ else
+ item.sub_type = force_type;
+
+ // Happens with ghoul food acquirement -- use place_chunks() outherwise
+ if (item.sub_type == FOOD_CHUNK)
+ {
+ // set chunk flavour (default to common dungeon rat steaks):
+ item.plus = choose_random_monster_corpse();
+ // set duration
+ item.special = (10 + random2(11)) * 10;
+ }
+
+ // determine quantity
+ if (force_quant > 1)
+ item.quantity = force_quant;
+ else
+ {
+ item.quantity = 1;
+
+ if (item.sub_type != FOOD_MEAT_RATION
+ && item.sub_type != FOOD_BREAD_RATION)
{
- mitm[p].sub_type =
- (!one_chance_in(4) ? get_random_ring_type()
- : get_random_amulet_type());
+ if (one_chance_in(80))
+ item.quantity += random2(3);
- // 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))
+ if (item.sub_type == FOOD_STRAWBERRY
+ || item.sub_type == FOOD_GRAPE
+ || item.sub_type == FOOD_SULTANA)
{
- mitm[p].sub_type = random2(24);
+ item.quantity += 3 + random2avg(15,2);
}
}
- else
- mitm[p].sub_type = force_type;
+ }
+}
- // quantity is always one {dlb}:
- quant = 1;
+static void generate_potion_item(item_def& item, int force_type,
+ int item_level)
+{
+ item.quantity = 1;
- // everything begins as uncursed, unenchanted jewellery {dlb}:
- mitm[p].plus = 0;
- mitm[p].plus2 = 0;
+ if (one_chance_in(18))
+ item.quantity++;
- // 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(25))
+ item.quantity++;
- 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;
+ if (force_type != OBJ_RANDOM)
+ item.sub_type = force_type;
+ else
+ {
+ int stype;
+ do {
+ stype = random_choose_weighted( 1407, POT_HEAL_WOUNDS,
+ 2815, POT_HEALING,
+ 222, POT_CURE_MUTATION,
+ 612, POT_SPEED,
+ 612, POT_MIGHT,
+ 136, POT_BERSERK_RAGE,
+ 340, POT_INVISIBILITY,
+ 340, POT_LEVITATION,
+ 250, POT_RESISTANCE,
+ 70, POT_PORRIDGE,
+ 111, POT_BLOOD,
+ 38, POT_GAIN_STRENGTH,
+ 38, POT_GAIN_DEXTERITY,
+ 38, POT_GAIN_INTELLIGENCE,
+ 13, POT_EXPERIENCE,
+ 14, POT_MAGIC,
+ 972, POT_RESTORE_ABILITIES,
+ 648, POT_POISON,
+ 162, POT_STRONG_POISON,
+ 324, POT_MUTATION,
+ 324, POT_SLOWING,
+ 324, POT_PARALYSIS,
+ 324, POT_CONFUSION,
+ 278, POT_DEGENERATION,
+ 10, POT_DECAY,
+ 0);
+ } while ( (stype == POT_POISON && item_level < 1) ||
+ (stype == POT_STRONG_POISON && item_level < 11) ||
+ (stype == POT_SLOWING && item_level < 7) );
+ if ( stype == POT_GAIN_STRENGTH || stype == POT_GAIN_DEXTERITY ||
+ stype == POT_GAIN_INTELLIGENCE || stype == POT_EXPERIENCE ||
+ stype == POT_MAGIC || stype == POT_RESTORE_ABILITIES )
+ item.quantity = 1;
+ item.sub_type = stype;
+ }
- default:
- break;
- }
+ item.plus = 0;
+}
- // 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;
- }
- }
- }
+static void generate_scroll_item(item_def& item, int force_type,
+ int item_level)
+{
+ // determine sub_type:
+ if (force_type != OBJ_RANDOM)
+ item.sub_type = force_type;
+ else
+ {
+ // only used in certain cases {dlb}
+ const int depth_mod = random2(1 + item_level);
+ const int temp_rand = random2(920);
+
+ item.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_FOG : // 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));
+ }
- // 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;
- }
+ // determine quantity
+ if ( item.sub_type == SCR_VORPALISE_WEAPON ||
+ item.sub_type == SCR_ENCHANT_WEAPON_III ||
+ item.sub_type == SCR_ACQUIREMENT ||
+ item.sub_type == SCR_TORMENT )
+ item.quantity = 1;
+ else
+ {
+ const int tmp = random2(48);
+ if ( tmp == 1 )
+ item.quantity = 2;
+ else if ( tmp == 0 )
+ item.quantity = 3;
+ else
+ item.quantity = 1;
+ }
- // 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;
+ item.plus = 0;
+}
- case OBJ_BOOKS:
+static void generate_book_item(item_def& item, int force_type,
+ int item_level)
+{
+ // determine special (description)
+ item.special = random2(5);
+
+ if (one_chance_in(10))
+ item.special += random2(8) * 10;
+
+ if ( force_type != OBJ_RANDOM )
+ item.sub_type = force_type;
+ else
+ {
do
{
- mitm[p].sub_type = random2(NUM_BOOKS);
-
- if (mitm[p].sub_type != BOOK_DESTRUCTION &&
- mitm[p].sub_type != BOOK_MANUAL &&
- book_rarity(mitm[p].sub_type) != 100 &&
+ item.sub_type = random2(NUM_BOOKS);
+
+ if (item.sub_type != BOOK_DESTRUCTION &&
+ item.sub_type != BOOK_MANUAL &&
+ book_rarity(item.sub_type) != 100 &&
one_chance_in(10))
{
- mitm[p].sub_type = coinflip() ? BOOK_WIZARDRY : BOOK_POWER;
+ item.sub_type = coinflip() ? BOOK_WIZARDRY : BOOK_POWER;
}
-
+
if (!one_chance_in(100) &&
- random2(item_level+1) + 1 < book_rarity(mitm[p].sub_type))
+ random2(item_level+1) + 1 < book_rarity(item.sub_type))
{
- mitm[p].sub_type = BOOK_DESTRUCTION; // continue trying
+ item.sub_type = BOOK_DESTRUCTION; // continue trying
}
}
- while (mitm[p].sub_type == BOOK_DESTRUCTION ||
- mitm[p].sub_type == BOOK_MANUAL ||
- book_rarity(mitm[p].sub_type) == 100);
+ while (item.sub_type == BOOK_DESTRUCTION ||
+ item.sub_type == BOOK_MANUAL ||
+ book_rarity(item.sub_type) == 100);
- mitm[p].special = random2(5);
+ // tome of destruction: rare!
+ if ( item_level > 10 && random2(7000) <= item_level + 20 )
+ item.sub_type = BOOK_DESTRUCTION;
- if (one_chance_in(10))
- mitm[p].special += random2(8) * 10;
+ // skill manuals - also rare
+ if ( item_level > 6 && random2(4000) <= item_level + 20 )
+ item.sub_type = BOOK_MANUAL;
+ }
- if (force_type != OBJ_RANDOM)
- mitm[p].sub_type = force_type;
+ // Determine which skill for a manual
+ if ( item.sub_type == BOOK_MANUAL )
+ {
+ if (one_chance_in(4))
+ item.plus = SK_SPELLCASTING + random2(NUM_SKILLS - SK_SPELLCASTING);
+ else
+ {
+ item.plus = random2(SK_UNARMED_COMBAT);
- quant = 1;
+ if (item.plus == SK_UNUSED_1)
+ item.plus = SK_UNARMED_COMBAT;
+ }
+ }
+}
- // tome of destruction : rare!
- if (force_type == BOOK_DESTRUCTION
- || (random2(7000) <= item_level + 20 && item_level > 10
- && force_type == OBJ_RANDOM))
+static void generate_staff_item(item_def& item, int force_type)
+{
+ if (force_type != OBJ_RANDOM)
+ item.sub_type = force_type;
+ else
+ {
+ // assumption: STAFF_SMITING is the first rod
+ item.sub_type = random2(STAFF_SMITING);
+
+ // rods are rare (10% of all staves)
+ if (one_chance_in(10))
+ item.sub_type = random_rod_subtype();
+
+ // staves of energy/channeling are 25% less common, wizardry/power
+ // are more common
+ if ((item.sub_type == STAFF_ENERGY
+ || item.sub_type == STAFF_CHANNELING) && one_chance_in(4))
{
- mitm[p].sub_type = BOOK_DESTRUCTION;
+ item.sub_type = coinflip() ? STAFF_WIZARDRY : STAFF_POWER;
}
+ }
+
+ if (item_is_rod( item ))
+ init_rod_mp( item );
+
+ // add different looks
+ item.special = random2(10);
+}
- // 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))
+static bool try_make_jewellery_unrandart(item_def& item, int force_type,
+ int item_level)
+{
+ bool rc = false;
+
+ if (item_level > 2
+ && you.level_type != LEVEL_ABYSS
+ && you.level_type != LEVEL_PANDEMONIUM
+ && random2(2000) <= 100 + (item_level * 3)
+ && one_chance_in(20))
+ {
+ // The old generation code did not respect force_type here.
+ const int idx = find_okay_unrandart(OBJ_JEWELLERY, force_type);
+
+ if (idx != -1)
{
- mitm[p].sub_type = BOOK_MANUAL;
+ make_item_unrandart( item, idx );
+ rc = true;
+ }
+ }
+ return rc;
+}
- if (one_chance_in(4))
- {
- mitm[p].plus = SK_SPELLCASTING
- + random2(NUM_SKILLS - SK_SPELLCASTING);
- }
- else
- {
- mitm[p].plus = random2(SK_UNARMED_COMBAT);
+static int determine_ring_plus(int subtype)
+{
+ int rc = 0;
- if (mitm[p].plus == SK_UNUSED_1)
- mitm[p].plus = SK_UNARMED_COMBAT;
- }
+ switch (subtype)
+ {
+ 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}
+ {
+ rc = (coinflip() ? -2 : -3);
+
+ if (one_chance_in(3))
+ rc -= random2(4);
}
+ else
+ rc = 1 + (one_chance_in(3) ? random2(3) : random2avg(6, 2));
break;
- case OBJ_STAVES:
- if (force_type != OBJ_RANDOM)
- mitm[p].sub_type = force_type;
+ default:
+ break;
+ }
+ return rc;
+}
+
+static void generate_jewellery_item(item_def& item, bool allow_uniques,
+ int force_type, int item_level)
+{
+ if (allow_uniques &&
+ try_make_jewellery_unrandart(item, force_type, item_level))
+ return;
+
+ // Determine subtype.
+ // Note: removed double probability reduction for some subtypes
+ if (force_type != OBJ_RANDOM)
+ item.sub_type = force_type;
+ else
+ item.sub_type = (one_chance_in(4) ? get_random_amulet_type() :
+ get_random_ring_type());
+
+ // everything begins as uncursed, unenchanted jewellery {dlb}:
+ item.plus = 0;
+ item.plus2 = 0;
+
+ item.plus = determine_ring_plus(item.sub_type);
+ if ( item.plus < 0 )
+ do_curse_item(item);
+
+ if (item.sub_type == RING_SLAYING ) // requires plus2 too
+ {
+ if (item_cursed( item ) && !one_chance_in(20))
+ item.plus2 = -1 - random2avg(6, 2);
else
{
- // assumption: STAFF_SMITING is the first rod
- mitm[p].sub_type = random2(STAFF_SMITING);
+ item.plus2 = 1 + (one_chance_in(3) ? random2(3) : random2avg(6, 2));
- // rods are rare (10% of all staves)
- if (one_chance_in(10))
- mitm[p].sub_type = random_rod_subtype();
-
- // staves of energy/channeling are less common, wizardry/power
- // are more common
- if ((mitm[p].sub_type == STAFF_ENERGY
- || mitm[p].sub_type == STAFF_CHANNELING) && one_chance_in(4))
+ if (random2(25) < 9) // 36% of such rings {dlb}
{
- mitm[p].sub_type = coinflip() ? STAFF_WIZARDRY : STAFF_POWER;
+ // make "ring of damage"
+ do_uncurse_item( item );
+ item.plus = 0;
+ item.plus2 += 2;
}
}
+ }
- if (item_is_rod( mitm[p] ))
- init_rod_mp( mitm[p] );
+ // All jewellery base types should now work. -- bwr
+ if (allow_uniques && item_level > 2
+ && random2(4000) <= 100 + (item_level * 3))
+ {
+ make_item_randart( item );
+ }
+ else if (item.sub_type == RING_HUNGER || item.sub_type == RING_TELEPORTATION
+ || one_chance_in(50))
+ {
+ // rings of hunger and teleportation are always cursed {dlb}:
+ do_curse_item( item );
+ }
+}
- // add different looks
- mitm[p].special = random2(10);
- quant = 1;
- break;
+static void generate_misc_item(item_def& item, int force_type, int item_race)
+{
+ if (force_type != OBJ_RANDOM)
+ item.sub_type = force_type;
+ else
+ {
+ do
+ {
+ item.sub_type = random2(NUM_MISCELLANY);
+ }
+ while
+ // never randomly generated
+ ((item.sub_type == MISC_RUNE_OF_ZOT)
+ || (item.sub_type == MISC_HORN_OF_GERYON)
+ || (item.sub_type == MISC_DECK_OF_PUNISHMENT)
+ // pure decks are rare in the dungeon
+ || ((item.sub_type == MISC_DECK_OF_ESCAPE ||
+ item.sub_type == MISC_DECK_OF_DESTRUCTION ||
+ item.sub_type == MISC_DECK_OF_DUNGEONS ||
+ item.sub_type == MISC_DECK_OF_SUMMONING ||
+ item.sub_type == MISC_DECK_OF_WONDERS) &&
+ !one_chance_in(5)));
+
+ // filling those silly empty boxes -- bwr
+ if (item.sub_type == MISC_EMPTY_EBONY_CASKET && !one_chance_in(20))
+ item.sub_type = MISC_BOX_OF_BEASTS;
+ }
- case OBJ_ORBS: // always forced in current setup {dlb}
- quant = 1;
+ if ( is_deck(item) )
+ {
+ item.plus = 4 + random2(10);
+ item.special = random_choose_weighted( 8, DECK_RARITY_LEGENDARY,
+ 20, DECK_RARITY_RARE,
+ 72, DECK_RARITY_COMMON,
+ 0);
+ init_deck(item);
+ }
- if (force_type != OBJ_RANDOM)
- mitm[p].sub_type = force_type;
+ if (item.sub_type == MISC_RUNE_OF_ZOT)
+ item.plus = item_race;
+}
- // 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;
+// Returns item slot or NON_ITEM if it fails
+int items( int allow_uniques, // not just true-false,
+ // because of BCR acquirement hack
+ object_class_type 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!
+ unsigned mapmask)
+{
+ const bool force_good = (item_level == MAKE_GOOD_ITEM);
- case OBJ_MISCELLANY:
- 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_DECK_OF_PUNISHMENT)
- // pure decks are rare in the dungeon
- || ((mitm[p].sub_type == MISC_DECK_OF_ESCAPE ||
- mitm[p].sub_type == MISC_DECK_OF_DESTRUCTION ||
- mitm[p].sub_type == MISC_DECK_OF_DUNGEONS ||
- mitm[p].sub_type == MISC_DECK_OF_SUMMONING ||
- mitm[p].sub_type == MISC_DECK_OF_WONDERS) &&
- !one_chance_in(5)));
-
- // 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
+ // find an empty slot for the item (with culling if required)
+ int p = get_item_slot(10);
+ if (p == NON_ITEM)
+ return (NON_ITEM);
+
+ item_def& item(mitm[p]);
+
+ // cap item_level unless an acquirement-level item {dlb}:
+ if (item_level > 50 && !force_good)
+ item_level = 50;
+
+ // determine base_type for item generated {dlb}:
+ if (force_class != OBJ_RANDOM)
+ item.base_type = force_class;
+ else
+ {
+ item.base_type = static_cast<object_class_type>(
+ random_choose_weighted(5, OBJ_STAVES,
+ 15, OBJ_BOOKS,
+ 25, OBJ_JEWELLERY,
+ 35, OBJ_WANDS,
+ 70, OBJ_FOOD,
+ 100, OBJ_ARMOUR,
+ 100, OBJ_WEAPONS,
+ 100, OBJ_POTIONS,
+ 150, OBJ_MISSILES,
+ 200, OBJ_SCROLLS,
+ 200, OBJ_GOLD,
+ 0));
+
+ // misc items placement wholly dependent upon current depth {dlb}:
+ if (item_level > 7 && (20 + item_level) >= random2(3500))
+ item.base_type = OBJ_MISCELLANY;
+
+ if (item_level < 7
+ && (item.base_type == OBJ_BOOKS
+ || item.base_type == OBJ_STAVES
+ || item.base_type == OBJ_WANDS)
+ && random2(7) >= item_level)
{
- mitm[p].sub_type = force_type;
+ item.base_type = coinflip() ? OBJ_POTIONS : OBJ_SCROLLS;
}
+ }
+
+ item.quantity = 1; // generally the case
- if ( is_deck(mitm[p]) )
- mitm[p].plus = 4 + random2(10);
+ // determine sub_type accordingly {dlb}:
+ switch (item.base_type)
+ {
+ case OBJ_WEAPONS:
+ generate_weapon_item(item, allow_uniques, force_type,
+ item_level, item_race);
+ break;
+
+ case OBJ_MISSILES:
+ generate_missile_item(item, force_type, item_level, item_race);
+ break;
- if (mitm[p].sub_type == MISC_RUNE_OF_ZOT)
- mitm[p].plus = item_race;
+ case OBJ_ARMOUR:
+ generate_armour_item(item, allow_uniques, force_type,
+ item_level, item_race);
+ break;
- quant = 1;
+ case OBJ_WANDS:
+ generate_wand_item(item, force_type);
+ break;
+
+ case OBJ_FOOD:
+ generate_food_item(item, allow_uniques, force_type);
+ break;
+
+ case OBJ_POTIONS:
+ generate_potion_item(item, force_type, item_level);
+ break;
+
+ case OBJ_SCROLLS:
+ generate_scroll_item(item, force_type, item_level);
+ break;
+
+ case OBJ_JEWELLERY:
+ generate_jewellery_item(item, allow_uniques, force_type, item_level);
+ break;
+
+ case OBJ_BOOKS:
+ generate_book_item(item, force_type, item_level);
+ break;
+
+ case OBJ_STAVES:
+ generate_staff_item(item, force_type);
+ break;
+
+ case OBJ_ORBS: // always forced in current setup {dlb}
+ item.sub_type = force_type;
+ set_unique_item_status( OBJ_ORBS, item.sub_type, UNIQ_EXISTS );
+ break;
+
+ case OBJ_MISCELLANY:
+ generate_misc_item(item, force_type, item_race);
break;
// that is, everything turns to gold if not enumerated above, so ... {dlb}
default:
- mitm[p].base_type = OBJ_GOLD;
-
- // Acquirement now gives more gold: The base price of a scroll
- // of acquirement is 520 gold. The expected value of the gold
- // it produces is about 480. So you cannot consistently make a
- // profit by buying scrolls of acquirement. However, there is
- // a very low chance you'll get lucky and receive up to 2296!
- // This is quite rare: 50% of the time you'll get less than
- // 360 gold and 90% of the time you'll get less than 900 and
- // 99% of the time you'll get less than 1500. --Zooko
- if (make_good_item)
- quant = 150 + random2(150) + random2(random2(random2(2000)));
+ item.base_type = OBJ_GOLD;
+ if (force_good)
+ item.quantity = 150+random2(150) + random2(random2(random2(2000)));
else
- quant = 1 + random2avg(19, 2) + random2(item_level);
+ item.quantity = 1 + random2avg(19, 2) + random2(item_level);
break;
}
- mitm[p].quantity = quant;
+ // Colour the item
+ item_colour( item );
if (dont_place)
{
- mitm[p].x = 0;
- mitm[p].y = 0;
- mitm[p].link = NON_ITEM;
+ item.x = 0;
+ item.y = 0;
+ item.link = NON_ITEM;
}
else
{
+ int x_pos, y_pos;
int tries = 500;
do
{
@@ -2878,14 +2768,10 @@ int items( int allow_uniques, // not just true-false,
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 nonexistent
- // item might symbolize something more serious. -- bwr
- return (is_valid_item( mitm[p] ) ? p : NON_ITEM);
-} // end items()
+ // Note that item might be invalidated now, since p could have changed.
+ ASSERT( is_valid_item(mitm[p]) );
+ return p;
+}
void init_rod_mp(item_def &item)
{
@@ -2912,7 +2798,7 @@ static bool weapon_is_visibly_special(const item_def &item)
&& item.sub_type != WPN_CLUB
&& item.sub_type != WPN_GIANT_CLUB
&& item.sub_type != WPN_GIANT_SPIKED_CLUB
- && get_equip_desc(item) == 0;
+ && get_equip_desc(item) == ISFLAG_NO_DESC;
}
static void give_monster_item(
@@ -3192,12 +3078,12 @@ static item_make_species_type give_weapon(monsters *mon, int level,
const int temp_rand = random2(100);
item.sub_type = ((temp_rand > 79) ? WPN_LONG_SWORD : // 20%
- (temp_rand > 59) ? WPN_SHORT_SWORD : // 20%
- (temp_rand > 45) ? WPN_SCIMITAR : // 14%
- (temp_rand > 31) ? WPN_MACE : // 14%
- (temp_rand > 18) ? WPN_BOW : // 13%
- (temp_rand > 5) ? WPN_HAND_CROSSBOW // 13%
- : WPN_LONGBOW); // 6%
+ (temp_rand > 59) ? WPN_SHORT_SWORD : // 20%
+ (temp_rand > 45) ? WPN_SCIMITAR : // 14%
+ (temp_rand > 31) ? WPN_MACE : // 14%
+ (temp_rand > 18) ? WPN_BOW : // 13%
+ (temp_rand > 5) ? WPN_HAND_CROSSBOW // 13%
+ : WPN_LONGBOW); // 6%
break;
}
@@ -3281,7 +3167,6 @@ static item_make_species_type give_weapon(monsters *mon, int level,
case MONS_TIAMAT:
{
item.base_type = OBJ_WEAPONS;
-
const int temp_rand = random2(120);
item.sub_type = ((temp_rand > 109) ? WPN_LONG_SWORD : // 8.33%
(temp_rand > 99) ? WPN_SHORT_SWORD : // 8.33%
@@ -3408,6 +3293,34 @@ static item_make_species_type give_weapon(monsters *mon, int level,
}
break;
+ case MONS_MERMAID:
+ if (one_chance_in(3))
+ {
+ item_race = MAKE_ITEM_NO_RACE;
+ item.base_type = OBJ_WEAPONS;
+ item.sub_type = WPN_SPEAR;
+ }
+ break;
+
+ case MONS_MERFOLK:
+ item_race = MAKE_ITEM_NO_RACE;
+ item.base_type = OBJ_WEAPONS;
+ // 1/3 each for trident, spears and javelins
+ if (one_chance_in(3))
+ item.sub_type = WPN_TRIDENT;
+ else if (coinflip())
+ {
+ item.sub_type = WPN_SPEAR;
+ iquan = 1 + random2(3);
+ }
+ else
+ {
+ item.base_type = OBJ_MISSILES;
+ item.sub_type = MI_JAVELIN;
+ iquan = 3 + random2(6);
+ }
+ break;
+
case MONS_CENTAUR:
case MONS_CENTAUR_WARRIOR:
item_race = MAKE_ITEM_NO_RACE;
@@ -3621,6 +3534,10 @@ static item_make_species_type give_weapon(monsters *mon, int level,
break;
}
} // end "switch(mon->type)"
+
+ // Nagas don't get racial stuff.
+ if (mons_genus(mon->type) == MONS_NAGA)
+ item_race = MAKE_ITEM_NO_RACE;
// only happens if something in above switch doesn't set it {dlb}
if (item.base_type == OBJ_UNASSIGNED)
@@ -3660,6 +3577,9 @@ static item_make_species_type give_weapon(monsters *mon, int level,
return (item_race);
}
+ if (iquan > 1 && !force_item)
+ mitm[thing_created].quantity = iquan;
+
give_monster_item(mon, thing_created, force_item);
if (give_aux_melee && (i.base_type != OBJ_WEAPONS || is_range_weapon(i)))
@@ -3739,6 +3659,7 @@ static void give_ammo(monsters *mon, int level,
case MONS_DRACONIAN_KNIGHT:
case MONS_GNOLL:
case MONS_HILL_GIANT:
+ case MONS_MERFOLK:
if (!one_chance_in(20))
break;
// fall through
@@ -3765,6 +3686,78 @@ static void give_ammo(monsters *mon, int level,
}
}
+static bool make_item_for_monster(
+ monsters *mons,
+ object_class_type base,
+ int subtype,
+ int level,
+ item_make_species_type race = MAKE_ITEM_NO_RACE,
+ int allow_uniques = 0)
+{
+ const int bp = get_item_slot();
+ if (bp == NON_ITEM)
+ return (false);
+
+ const int thing_created =
+ items( allow_uniques, base, subtype, true, level, race );
+
+ if (thing_created == NON_ITEM)
+ return (false);
+
+ give_monster_item(mons, thing_created);
+ return (true);
+}
+
+void give_shield(monsters *mon, int level)
+{
+ switch (mon->type)
+ {
+ case MONS_DAEVA:
+ make_item_for_monster(mon, OBJ_ARMOUR, ARM_LARGE_SHIELD,
+ level * 2 + 1, MAKE_ITEM_RANDOM_RACE, 1);
+ break;
+
+ case MONS_DEEP_ELF_SOLDIER:
+ case MONS_DEEP_ELF_FIGHTER:
+ if (one_chance_in(5))
+ make_item_for_monster(mon, OBJ_ARMOUR, ARM_BUCKLER,
+ level, MAKE_ITEM_ELVEN);
+ break;
+ case MONS_NAGA_WARRIOR:
+ case MONS_VAULT_GUARD:
+ if (one_chance_in(3))
+ make_item_for_monster(mon, OBJ_ARMOUR,
+ one_chance_in(3)? ARM_LARGE_SHIELD
+ : ARM_SHIELD,
+ level, MAKE_ITEM_NO_RACE);
+ break;
+ case MONS_DRACONIAN_KNIGHT:
+ if (coinflip())
+ make_item_for_monster(mon, OBJ_ARMOUR,
+ coinflip()? ARM_LARGE_SHIELD : ARM_SHIELD,
+ level, MAKE_ITEM_NO_RACE);
+ break;
+ case MONS_DEEP_ELF_KNIGHT:
+ if (coinflip())
+ make_item_for_monster(mon, OBJ_ARMOUR, ARM_BUCKLER,
+ level, MAKE_ITEM_ELVEN);
+ break;
+ case MONS_NORRIS:
+ make_item_for_monster(mon, OBJ_ARMOUR, ARM_BUCKLER,
+ level * 2 + 1, MAKE_ITEM_RANDOM_RACE, 1);
+ break;
+ case MONS_NORBERT:
+ case MONS_LOUISE:
+ make_item_for_monster(mon, OBJ_ARMOUR, ARM_LARGE_SHIELD,
+ level * 2 + 1, MAKE_ITEM_RANDOM_RACE, 1);
+ break;
+ case MONS_DONALD:
+ make_item_for_monster(mon, OBJ_ARMOUR, ARM_SHIELD,
+ level * 2 + 1, MAKE_ITEM_RANDOM_RACE, 1);
+ break;
+ }
+}
+
void give_armour(monsters *mon, int level)
{
const int bp = get_item_slot();
@@ -3969,7 +3962,7 @@ void give_armour(monsters *mon, int level)
default:
return;
- } // end of switch(menv [mid].type)
+ }
const object_class_type xitc = mitm[bp].base_type;
const int xitt = mitm[bp].sub_type;
@@ -4006,6 +3999,7 @@ void give_item(int mid, int level_number) //mv: cleanup+minor changes
give_ammo(mons, level_number, item_race);
give_armour(mons, 1 + level_number / 2);
+ give_shield(mons, 1 + level_number / 2);
} // end give_item()
jewellery_type get_random_amulet_type()
diff --git a/crawl-ref/source/makeitem.h b/crawl-ref/source/makeitem.h
index 0b567ab841..0427be6923 100644
--- a/crawl-ref/source/makeitem.h
+++ b/crawl-ref/source/makeitem.h
@@ -2,7 +2,7 @@
* File: makeitem.h
* Summary: Item creation routines.
*
- * Modified for Crawl Reference by $Author: haranp $ on $Date: 2007-03-15T20:10:20.648083Z $
+ * Modified for Crawl Reference by $Author$ on $Date$
*/
#ifndef MAKEITEM_H
diff --git a/crawl-ref/source/mapdef.cc b/crawl-ref/source/mapdef.cc
index bc62c32151..91243e8c2e 100644
--- a/crawl-ref/source/mapdef.cc
+++ b/crawl-ref/source/mapdef.cc
@@ -2,7 +2,7 @@
* File: mapdef.cc
* Summary: Support code for Crawl des files.
*
- * Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-06-30T15:49:18.688054Z $
+ * Modified for Crawl Reference by $Author$ on $Date$
*/
#include <iostream>
@@ -1158,7 +1158,8 @@ map_def::map_def()
: name(), tags(), place(), depths(), orient(), chance(),
welcome_messages(), map(), mons(), items(), keyspecs(),
prelude("dlprelude"), main("dlmain"), validate("dlvalidate"),
- veto("dlveto"), index_only(false), cache_offset(0L)
+ veto("dlveto"), rock_colour(BLACK), floor_colour(BLACK),
+ index_only(false), cache_offset(0L)
{
init();
}
@@ -1182,8 +1183,13 @@ void map_def::reinit()
{
items.clear();
keyspecs.clear();
+ level_flags.clear();
+ branch_flags.clear();
+
welcome_messages.clear();
+ rock_colour = floor_colour = BLACK;
+
// Base chance; this is not a percentage.
chance = 10;
@@ -1446,19 +1452,19 @@ std::string map_def::validate_map_def()
switch (orient)
{
case MAP_NORTH: case MAP_SOUTH:
- if (map.height() >= GYM * 2 / 3)
+ if (map.height() > GYM * 2 / 3)
return make_stringf("Map too large - height %d (max %d)",
map.height(), GYM * 2 / 3);
break;
case MAP_EAST: case MAP_WEST:
- if (map.width() >= GXM * 2 / 3)
+ if (map.width() > GXM * 2 / 3)
return make_stringf("Map too large - width %d (max %d)",
map.width(), GXM * 2 / 3);
break;
case MAP_NORTHEAST: case MAP_SOUTHEAST:
case MAP_NORTHWEST: case MAP_SOUTHWEST:
case MAP_FLOAT:
- if (map.width() >= GXM * 2 / 3 || map.height() > GYM * 2 / 3)
+ if (map.width() > GXM * 2 / 3 || map.height() > GYM * 2 / 3)
return make_stringf("Map too large - %dx%d (max %dx%d)",
map.width(), map.height(),
GXM * 2 / 3, GYM * 2 / 3);
@@ -1739,6 +1745,12 @@ bool map_def::has_tag_suffix(const std::string &suffix) const
&& tags.find(suffix + " ") != std::string::npos;
}
+const keyed_mapspec *map_def::mapspec_for_key(int key) const
+{
+ keyed_specs::const_iterator i = keyspecs.find(key);
+ return i != keyspecs.end()? &i->second : NULL;
+}
+
keyed_mapspec *map_def::mapspec_for_key(int key)
{
keyed_specs::iterator i = keyspecs.find(key);
@@ -1776,6 +1788,11 @@ std::string map_def::add_key_mons(const std::string &s)
return add_key_field(s, &keyed_mapspec::set_mons);
}
+std::string map_def::add_key_mask(const std::string &s)
+{
+ return add_key_field(s, &keyed_mapspec::set_mask);
+}
+
std::vector<std::string> map_def::get_shuffle_strings() const
{
return map.get_shuffle_strings();
@@ -2505,6 +2522,55 @@ std::string map_marker_spec::describe() const
}
//////////////////////////////////////////////////////////////////////////
+// map_flags
+map_flags::map_flags()
+ : flags_set(0), flags_unset(0)
+{
+}
+
+void map_flags::clear()
+{
+ flags_set = flags_unset = 0;
+}
+
+typedef std::map<std::string, unsigned long> flag_map;
+
+map_flags map_flags::parse(const std::string flag_list[],
+ const std::string &s) throw(std::string)
+{
+ map_flags mf;
+
+ const std::vector<std::string> segs = split_string("/", s);
+
+ flag_map flag_vals;
+ for (int i = 0; flag_list[i] != ""; i++)
+ flag_vals[flag_list[i]] = 1 << i;
+
+ for (int i = 0, size = segs.size(); i < size; i++)
+ {
+ std::string flag = segs[i];
+ bool negate = false;
+
+ if (flag[0] == '!')
+ {
+ flag = flag.substr(1);
+ negate = true;
+ }
+
+ flag_map::const_iterator val = flag_vals.find(flag);
+ if (val == flag_vals.end())
+ throw make_stringf("Unknown flag: '%s'", flag.c_str());
+
+ if (negate)
+ mf.flags_unset |= val->second;
+ else
+ mf.flags_set |= val->second;
+ }
+
+ return mf;
+}
+
+//////////////////////////////////////////////////////////////////////////
// keyed_mapspec
keyed_mapspec::keyed_mapspec()
@@ -2631,9 +2697,31 @@ std::string keyed_mapspec::set_item(const std::string &s, bool fix)
return (err);
}
+std::string keyed_mapspec::set_mask(const std::string &s, bool garbage)
+{
+ UNUSED(garbage);
+
+ err.clear();
+
+ try
+ {
+ static std::string flag_list[] =
+ {"vault", "no_item_gen", "no_monster_gen", "no_pool_fixup",
+ "no_secret_doors", "opaque", ""};
+ map_mask = map_flags::parse(flag_list, s);
+ }
+ catch (const std::string &error)
+ {
+ err = error;
+ return (err);
+ }
+
+ return (err);
+}
+
feature_spec keyed_mapspec::get_feat()
{
- return feat.get_feat(key_glyph);
+ return feat.get_feat('.');
}
mons_list &keyed_mapspec::get_monsters()
@@ -2646,6 +2734,11 @@ item_list &keyed_mapspec::get_items()
return (item);
}
+map_flags &keyed_mapspec::get_mask()
+{
+ return (map_mask);
+}
+
//////////////////////////////////////////////////////////////////////////
// feature_slot
diff --git a/crawl-ref/source/mapdef.h b/crawl-ref/source/mapdef.h
index dead1f3744..451e088e93 100644
--- a/crawl-ref/source/mapdef.h
+++ b/crawl-ref/source/mapdef.h
@@ -480,6 +480,18 @@ struct feature_slot
feature_spec get_feat(int default_glyph);
};
+struct map_flags
+{
+ unsigned long flags_set, flags_unset;
+
+ map_flags();
+ void clear();
+
+ static map_flags parse(const std::string flag_list[],
+ const std::string &s) throw(std::string);
+};
+
+
struct keyed_mapspec
{
public:
@@ -488,6 +500,7 @@ public:
feature_slot feat;
item_list item;
mons_list mons;
+ map_flags map_mask;
public:
keyed_mapspec();
@@ -495,10 +508,12 @@ public:
std::string set_feat(const std::string &s, bool fix);
std::string set_mons(const std::string &s, bool fix);
std::string set_item(const std::string &s, bool fix);
+ std::string set_mask(const std::string &s, bool garbage);
feature_spec get_feat();
- mons_list &get_monsters();
- item_list &get_items();
+ mons_list &get_monsters();
+ item_list &get_items();
+ map_flags &get_mask();
private:
std::string err;
@@ -541,6 +556,31 @@ struct map_file_place
}
};
+/////////////////////////////////////////////////////////////////////////////
+// map_def: map definitions for maps loaded from .des files.
+//
+// Please read this before changing map_def.
+//
+// When adding Lua-visible fields to map_def, note that there are two
+// kinds of fields:
+//
+// * Fields that determine placement of the map, or are unchanging,
+// such as "place", "depths" (determine placement), or "name" (does
+// not change between different evaluations of the map). Such fields
+// must be reset to their default values in map_def::init() if they
+// determine placement, or just initialised in the constructor if
+// they will not change.
+//
+// * Fields that do not determine placement and may change between
+// different uses of the map (such as "mons", "items",
+// "level_flags", etc.). Such fields must be reset to their default
+// values in map_def::reinit(), which is called before the map is
+// used.
+//
+// If you do not do this, maps will not work correctly, and will break
+// in obscure, hard-to-find ways. The level-compiler will not (cannot)
+// warn you.
+//
class map_def
{
public:
@@ -558,6 +598,8 @@ public:
mons_list mons;
item_list items;
+ map_flags level_flags, branch_flags;
+
keyed_specs keyspecs;
dlua_chunk prelude, main, validate, veto;
@@ -566,6 +608,8 @@ public:
map_def *original;
+ unsigned char rock_colour, floor_colour;
+
private:
// This map has been loaded from an index, and not fully realised.
bool index_only;
@@ -617,6 +661,7 @@ public:
bool is_usable_in(const level_id &lid) const;
keyed_mapspec *mapspec_for_key(int key);
+ const keyed_mapspec *mapspec_for_key(int key) const;
bool has_depth() const;
void add_depth(const level_range &depth);
@@ -626,6 +671,7 @@ public:
std::string add_key_item(const std::string &s);
std::string add_key_mons(const std::string &s);
std::string add_key_feat(const std::string &s);
+ std::string add_key_mask(const std::string &s);
bool can_dock(map_section_type) const;
coord_def dock_pos(map_section_type) const;
diff --git a/crawl-ref/source/mapmark.cc b/crawl-ref/source/mapmark.cc
index fbcbbf6d73..77a3db7aa1 100644
--- a/crawl-ref/source/mapmark.cc
+++ b/crawl-ref/source/mapmark.cc
@@ -2,7 +2,7 @@
* File: mapmark.cc
* Summary: Level markers (annotations).
*
- * Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-07-20T11:40:25.964128Z $
+ * Modified for Crawl Reference by $Author$ on $Date$
*
*/
@@ -161,14 +161,24 @@ map_lua_marker::map_lua_marker()
{
}
-map_lua_marker::map_lua_marker(const std::string &s, const std::string &)
+map_lua_marker::map_lua_marker(const std::string &s, const std::string &,
+ bool mapdef_marker)
: map_marker(MAT_LUA_MARKER, coord_def()), initialised(false)
{
lua_stack_cleaner clean(dlua);
- if (dlua.loadstring(("return " + s).c_str(), "lua_marker"))
- mprf(MSGCH_WARN, "lua_marker load error: %s", dlua.error.c_str());
- if (!dlua.callfn("dgn_run_map", 1, 1))
- mprf(MSGCH_WARN, "lua_marker exec error: %s", dlua.error.c_str());
+ if (mapdef_marker)
+ {
+ if (dlua.loadstring(("return " + s).c_str(), "lua_marker"))
+ mprf(MSGCH_WARN, "lua_marker load error: %s", dlua.error.c_str());
+ if (!dlua.callfn("dgn_run_map", 1, 1))
+ mprf(MSGCH_WARN, "lua_marker exec error: %s", dlua.error.c_str());
+ }
+ else
+ {
+ if (dlua.execstring(("return " + s).c_str(), "lua_marker_mapless", 1))
+ mprf(MSGCH_WARN, "lua_marker_mapless exec error: %s",
+ dlua.error.c_str());
+ }
check_register_table();
}
@@ -369,11 +379,20 @@ std::string map_lua_marker::property(const std::string &pname) const
map_marker *map_lua_marker::parse(
const std::string &s, const std::string &ctx) throw (std::string)
{
- if (s.find("lua:") != 0)
+ std::string raw = s;
+ bool mapdef_marker = true;
+
+ if (s.find("lua:") == 0)
+ strip_tag(raw, "lua:", true);
+ else if (s.find("lua_mapless:") == 0)
+ {
+ strip_tag(raw, "lua_mapless:", true);
+ mapdef_marker = false;
+ }
+ else
return (NULL);
- std::string raw = s;
- strip_tag(raw, "lua:", true);
- map_lua_marker *mark = new map_lua_marker(raw, ctx);
+
+ map_lua_marker *mark = new map_lua_marker(raw, ctx, mapdef_marker);
if (!mark->initialised)
{
delete mark;
@@ -648,6 +667,24 @@ std::vector<map_marker*> map_markers::get_all(map_marker_type mat)
return (rmarkers);
}
+std::vector<map_marker*> map_markers::get_all(const std::string &key,
+ const std::string &val)
+{
+ std::vector<map_marker*> rmarkers;
+
+ for (dgn_marker_map::const_iterator i = markers.begin();
+ i != markers.end(); ++i)
+ {
+ map_marker* marker = i->second;
+ const std::string prop = marker->property(key);
+
+ if ((val == "" && !prop.empty()) || (val != "" && val == prop))
+ rmarkers.push_back(marker);
+ }
+
+ return (rmarkers);
+}
+
std::vector<map_marker*> map_markers::get_markers_at(const coord_def &c)
{
std::pair<dgn_marker_map::const_iterator, dgn_marker_map::const_iterator>
diff --git a/crawl-ref/source/mapmark.h b/crawl-ref/source/mapmark.h
index f277295db7..a2d71e9567 100644
--- a/crawl-ref/source/mapmark.h
+++ b/crawl-ref/source/mapmark.h
@@ -87,7 +87,8 @@ class map_lua_marker : public map_marker, public dgn_event_listener
{
public:
map_lua_marker();
- map_lua_marker(const std::string &s, const std::string &ctx);
+ map_lua_marker(const std::string &s, const std::string &ctx,
+ bool mapdef_marker = true);
~map_lua_marker();
void activate(bool verbose);
diff --git a/crawl-ref/source/menu.cc b/crawl-ref/source/menu.cc
index 6b368433cb..f9afedac4c 100644
--- a/crawl-ref/source/menu.cc
+++ b/crawl-ref/source/menu.cc
@@ -16,12 +16,13 @@
#include "view.h"
#include "initfile.h"
-Menu::Menu( int _flags )
+Menu::Menu( int _flags, const std::string& tagname )
: f_selitem(NULL),
f_drawitem(NULL),
f_keyfilter(NULL),
title(NULL),
flags(_flags),
+ tag(tagname),
first_entry(0),
y_offset(0),
pagesize(0),
@@ -92,6 +93,7 @@ void Menu::set_title( MenuEntry *e )
void Menu::add_entry( MenuEntry *entry )
{
+ entry->tag = tag;
items.push_back( entry );
}
@@ -1028,15 +1030,19 @@ bool slider_menu::line_up()
// Menu colouring
//
-int menu_colour(const std::string &text, const std::string &prefix)
+int menu_colour(const std::string &text, const std::string &prefix,
+ const std::string &tag)
{
- std::string tmp_text = prefix + text;
+ const std::string tmp_text = prefix + text;
- for (int i = 0, size = Options.menu_colour_mappings.size(); i < size; ++i)
+ for (unsigned int i = 0; i < Options.menu_colour_mappings.size(); ++i)
{
- colour_mapping &cm = Options.menu_colour_mappings[i];
- if (cm.pattern.matches(tmp_text))
+ const colour_mapping &cm = Options.menu_colour_mappings[i];
+ if ( (cm.tag.empty() || cm.tag == "any" || cm.tag == tag) &&
+ cm.pattern.matches(tmp_text) )
+ {
return (cm.colour);
+ }
}
return (-1);
}
@@ -1411,7 +1417,7 @@ bool formatted_scroller::page_up()
bool formatted_scroller::line_down()
{
- if (first_entry + pagesize < (int) items.size() &&
+ if (first_entry + pagesize < static_cast<int>(items.size()) &&
items[first_entry + pagesize]->level != MEL_TITLE )
{
++first_entry;
diff --git a/crawl-ref/source/menu.h b/crawl-ref/source/menu.h
index f2fbc5b359..f7a57f0834 100644
--- a/crawl-ref/source/menu.h
+++ b/crawl-ref/source/menu.h
@@ -48,10 +48,12 @@ struct menu_letter
struct item_def;
int menu_colour(const std::string &itemtext,
- const std::string &prefix = "");
+ const std::string &prefix = "",
+ const std::string &tag = "");
struct MenuEntry
{
+ std::string tag;
std::string text;
int quantity, selected_qty;
int colour;
@@ -108,7 +110,7 @@ struct MenuEntry
virtual int highlight_colour() const
{
- return (menu_colour(get_text()));
+ return (menu_colour(get_text(), "", tag));
}
virtual bool selected() const
@@ -176,7 +178,7 @@ enum MenuFlag
class Menu
{
public:
- Menu( int flags = MF_MULTISELECT );
+ Menu( int flags = MF_MULTISELECT, const std::string& tagname = "" );
virtual ~Menu();
// Remove all items from the Menu, leave title intact.
@@ -187,6 +189,7 @@ public:
void set_flags(int new_flags, bool use_options = true);
int get_flags() const { return flags; }
virtual bool is_set( int flag ) const;
+ void set_tag(const std::string& t) { tag = t; }
bool draw_title_suffix( const std::string &s, bool titlefirst = true );
void update_title();
@@ -226,6 +229,7 @@ public:
protected:
MenuEntry *title;
int flags;
+ std::string tag;
int first_entry, y_offset;
int pagesize, max_pagesize;
diff --git a/crawl-ref/source/message.cc b/crawl-ref/source/message.cc
index 76ef608f55..72dcc74086 100644
--- a/crawl-ref/source/message.cc
+++ b/crawl-ref/source/message.cc
@@ -222,6 +222,9 @@ static char god_message_altar_colour( god_type god )
// returns a colour or MSGCOL_MUTED
int channel_to_colour( msg_channel_type channel, int param )
{
+ if (you.asleep())
+ return (DARKGREY);
+
char ret;
switch (Options.channels[ channel ])
@@ -456,6 +459,8 @@ void mpr_comma_separated_list(const std::string prefix,
new_str += comma;
else if (i == (size - 2))
new_str += andc;
+ else if (i == (size - 1))
+ new_str += ".";
if (out.length() + new_str.length() >= width)
{
@@ -484,7 +489,6 @@ static void mpr_check_patterns(const std::string& message,
}
}
- // reusing travel_stop_message here
if (channel != MSGCH_DIAGNOSTICS && channel != MSGCH_EQUIPMENT
&& channel != MSGCH_TALK && channel != MSGCH_TALK_VISUAL
&& channel != MSGCH_SOUND)
@@ -493,6 +497,10 @@ static void mpr_check_patterns(const std::string& message,
channel_to_str(channel) + ":" + message );
}
+ // Any sound has a chance of waking the PC if the PC is asleep.
+ if (channel == MSGCH_SOUND)
+ you.check_awaken(5);
+
// Check messages for all forms of running now.
if (you.running)
{
@@ -563,7 +571,7 @@ static int prepare_message(const std::string& imsg, msg_channel_type channel,
int param)
{
if (suppress_messages)
- return MSGCOL_MUTED;
+ return MSGCOL_MUTED;
int colour = channel_to_colour( channel, param );
@@ -729,6 +737,13 @@ void more(void)
return;
}
#endif
+
+ if (crawl_state.is_replaying_keys())
+ {
+ mesclr();
+ return;
+ }
+
if (Options.show_more_prompt && !suppress_messages)
{
char keypress = 0;
diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc
index b91504bda5..2335c74b42 100644
--- a/crawl-ref/source/misc.cc
+++ b/crawl-ref/source/misc.cc
@@ -43,20 +43,24 @@
#include "clua.h"
#include "cloud.h"
#include "delay.h"
+#include "direct.h"
#include "dgnevent.h"
#include "direct.h"
#include "dungeon.h"
#include "files.h"
#include "food.h"
+#include "format.h"
#include "hiscores.h"
#include "it_use2.h"
#include "itemprop.h"
#include "items.h"
#include "lev-pand.h"
+#include "macro.h"
#include "message.h"
#include "mon-util.h"
#include "monstuff.h"
#include "ouch.h"
+#include "overmap.h"
#include "place.h"
#include "player.h"
#include "religion.h"
@@ -65,6 +69,7 @@
#include "skills2.h"
#include "spells3.h"
#include "stash.h"
+#include "state.h"
#include "stuff.h"
#include "terrain.h"
#include "transfor.h"
@@ -72,6 +77,7 @@
#include "travel.h"
#include "tutorial.h"
#include "view.h"
+#include "xom.h"
// void place_chunks(int mcls, unsigned char rot_status, unsigned char chx,
// unsigned char chy, unsigned char ch_col)
@@ -166,7 +172,8 @@ void search_around( bool only_adjacent )
{
for ( int sry=you.y_pos - max_dist; sry<=you.y_pos + max_dist; ++sry )
{
- if ( see_grid(srx,sry) ) // must have LOS
+ // must have LOS, with no translucent walls in the way.
+ if ( see_grid_no_trans(srx,sry) )
{
// maybe we want distance() instead of grid_distance()?
int dist = grid_distance(srx, sry, you.x_pos, you.y_pos);
@@ -463,7 +470,57 @@ static void leaving_level_now()
you.level_type_name = newtype;
}
-void up_stairs(dungeon_feature_type force_stair)
+static void set_entry_cause(entry_cause_type default_cause,
+ level_area_type old_level_type)
+{
+ ASSERT(default_cause != NUM_ENTRY_CAUSE_TYPES);
+
+ if (!(old_level_type != you.level_type
+ || you.entry_cause == EC_UNKNOWN))
+ {
+ return;
+ }
+
+ if (crawl_state.is_god_acting())
+ {
+ if (crawl_state.is_god_retribution())
+ you.entry_cause = EC_GOD_RETRIUBTION;
+ else
+ you.entry_cause = EC_GOD_ACT;
+
+ you.entry_cause_god = crawl_state.which_god_acting();
+ }
+ else if (default_cause != EC_UNKNOWN)
+ {
+ you.entry_cause = default_cause;
+ you.entry_cause_god = GOD_NO_GOD;
+ }
+ else
+ {
+ you.entry_cause = EC_SELF_EXPLICIT;
+ you.entry_cause_god = GOD_NO_GOD;
+ }
+}
+
+static int runes_in_pack()
+{
+ int num_runes = 0;
+
+ 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)
+ {
+ num_runes += you.inv[i].quantity;
+ }
+ }
+
+ return num_runes;
+}
+
+void up_stairs(dungeon_feature_type force_stair,
+ entry_cause_type entry_cause)
{
dungeon_feature_type stair_find =
force_stair? force_stair : grd[you.x_pos][you.y_pos];
@@ -486,6 +543,31 @@ void up_stairs(dungeon_feature_type force_stair)
return;
}
+ level_id old_level_id = level_id::current();
+ LevelInfo &old_level_info = travel_cache.get_level_info(old_level_id);
+
+ // Does the next level have a warning annotation?
+ coord_def pos(you.x_pos, you.y_pos);
+ level_id next_level_id = level_id::get_next_level_id(pos);
+
+ crawl_state.level_annotation_shown = false;
+
+ if (level_annotation_has("WARN", next_level_id)
+ && next_level_id != level_id::current()
+ && next_level_id.level_type == LEVEL_DUNGEON && !force_stair)
+ {
+ mpr("Warning: level annotation for next level is:", MSGCH_PROMPT);
+ mpr(get_level_annotation(next_level_id).c_str(), MSGCH_PROMPT);
+
+ if (!yesno("Enter next level anyways?", true, 0, true, false))
+ {
+ interrupt_activity( AI_FORCE_INTERRUPT );
+ return;
+ }
+
+ crawl_state.level_annotation_shown = true;
+ }
+
// 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
@@ -526,9 +608,6 @@ void up_stairs(dungeon_feature_type force_stair)
// Interlevel travel data:
const bool collect_travel_data = can_travel_interlevel();
- level_id old_level_id = level_id::current();
- LevelInfo &old_level_info = travel_cache.get_level_info(old_level_id);
- int stair_x = you.x_pos, stair_y = you.y_pos;
if (collect_travel_data)
old_level_info.update();
@@ -558,9 +637,11 @@ void up_stairs(dungeon_feature_type force_stair)
ouch(INSTANT_DEATH, 0, KILLED_BY_LEAVING);
}
- you.prev_targ = MHITNOT;
+ you.prev_targ = MHITNOT;
you.pet_target = MHITNOT;
+ you.prev_grd_targ = coord_def(0, 0);
+
if (player_in_branch( BRANCH_VESTIBULE_OF_HELL ))
{
mpr("Thank you for visiting Hell. Please come again soon.");
@@ -612,6 +693,9 @@ void up_stairs(dungeon_feature_type force_stair)
load(stair_taken, LOAD_ENTER_LEVEL, old_level_type, old_level, old_where);
+ set_entry_cause(entry_cause, old_level_type);
+ entry_cause = you.entry_cause;
+
you.turn_is_over = true;
save_game_state();
@@ -620,6 +704,21 @@ void up_stairs(dungeon_feature_type force_stair)
viewwindow(1, true);
+ // Left Zot without enough runes to get back in (probably because
+ // of dropping some runes within Zot), but need to get back in Zot
+ // to get the Orb? Zom finds that funny.
+ if (stair_find == DNGN_RETURN_FROM_ZOT
+ && branches[BRANCH_HALL_OF_ZOT].branch_flags & BFLAG_HAS_ORB)
+ {
+ int runes_avail = you.attribute[ATTR_UNIQUE_RUNES]
+ + you.attribute[ATTR_DEMONIC_RUNES]
+ + you.attribute[ATTR_ABYSSAL_RUNES]
+ - you.attribute[ATTR_RUNES_IN_ZOT];
+
+ if (runes_avail < NUMBER_OF_RUNES_NEEDED)
+ xom_is_stimulated(255, "Xom snickers loudly.", true);
+ }
+
if (you.skills[SK_TRANSLOCATIONS] > 0 && !allow_control_teleport( true ))
mpr( "You sense a powerful magical force warping space.", MSGCH_WARN );
@@ -638,6 +737,8 @@ void up_stairs(dungeon_feature_type force_stair)
travel_cache.get_level_info(new_level_id);
new_level_info.update();
+ int stair_x = you.x_pos, stair_y = you.y_pos;
+
// First we update the old level's stair.
level_pos lp;
lp.id = new_level_id;
@@ -662,7 +763,7 @@ void up_stairs(dungeon_feature_type force_stair)
guess = true;
}
- old_level_info.update_stair(stair_x, stair_y, lp, guess);
+ old_level_info.update_stair(you.x_pos, you.y_pos, lp, guess);
// We *guess* that going up a staircase lands us on a downstair,
// and that we can descend that downstair and get back to where we
@@ -682,7 +783,8 @@ void up_stairs(dungeon_feature_type force_stair)
}
} // end up_stairs()
-void down_stairs( int old_level, dungeon_feature_type force_stair )
+void down_stairs( int old_level, dungeon_feature_type force_stair,
+ entry_cause_type entry_cause )
{
int i;
const level_area_type old_level_type = you.level_type;
@@ -691,6 +793,12 @@ void down_stairs( int old_level, dungeon_feature_type force_stair )
branch_type old_where = you.where_are_you;
+ bool shaft = ((!force_stair
+ && trap_type_at_xy(you.x_pos, you.y_pos) == TRAP_SHAFT)
+ || force_stair == DNGN_TRAP_NATURAL);
+ level_id shaft_dest;
+ int shaft_level = -1;
+
#ifdef SHUT_LABYRINTH
if (stair_find == DNGN_ENTER_LABYRINTH)
{
@@ -701,7 +809,7 @@ void down_stairs( int old_level, dungeon_feature_type force_stair )
#endif
// probably still need this check here (teleportation) -- bwr
- if (grid_stair_direction(stair_find) != CMD_GO_DOWNSTAIRS)
+ if (grid_stair_direction(stair_find) != CMD_GO_DOWNSTAIRS && !shaft)
{
if (stair_find == DNGN_STONE_ARCH)
mpr("There is nothing on the other side of the stone arch.");
@@ -730,6 +838,45 @@ void down_stairs( int old_level, dungeon_feature_type force_stair )
return;
}
+ if (shaft)
+ {
+ bool known_trap = (grd[you.x_pos][you.y_pos] != DNGN_UNDISCOVERED_TRAP
+ && !force_stair);
+
+ if (!known_trap && !force_stair)
+ {
+ mpr("You can't go down here!");
+ return;
+ }
+
+ if (you.flight_mode() == FL_LEVITATE && !force_stair)
+ {
+ if (known_trap)
+ mpr("You can't fall through a shaft while levitating.");
+ return;
+ }
+
+ if (!is_valid_shaft_level())
+ {
+ if (known_trap)
+ mpr("Strange, the shaft doesn't seem to lead anywhere.");
+ return;
+ }
+
+ shaft_dest = you.shaft_dest();
+ if (shaft_dest == level_id::current())
+ {
+ if (known_trap)
+ mpr("Strange, the shaft doesn't seem to lead anywhere.");
+ return;
+ }
+ shaft_level = absdungeon_depth(shaft_dest.branch,
+ shaft_dest.depth);
+
+ if (you.flight_mode() != FL_FLY || force_stair)
+ mpr("You fall through a shaft!");
+ }
+
// All checks are done, the player is on the move now.
// Fire level-leaving trigger.
@@ -756,24 +903,14 @@ void down_stairs( int old_level, dungeon_feature_type force_stair )
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;
- }
- }
+ int num_runes = runes_in_pack();
if (num_runes < NUMBER_OF_RUNES_NEEDED)
{
switch (NUMBER_OF_RUNES_NEEDED)
{
case 1:
- mpr("You need a Rune to enter this place.");
+ mpr("You need one more Rune to enter this place.");
break;
default:
@@ -784,6 +921,28 @@ void down_stairs( int old_level, dungeon_feature_type force_stair )
}
}
+ // Does the next level have a warning annotation?
+ coord_def pos = you.pos();
+ level_id next_level_id = level_id::get_next_level_id(pos);
+
+ crawl_state.level_annotation_shown = false;
+
+ if (level_annotation_has("WARN", next_level_id)
+ && next_level_id != level_id::current()
+ && next_level_id.level_type == LEVEL_DUNGEON && !force_stair)
+ {
+ mpr("Warning: level annotation for next level is:", MSGCH_PROMPT);
+ mpr(get_level_annotation(next_level_id).c_str(), MSGCH_PROMPT);
+
+ if (!yesno("Enter next level anyways?", true, 0, true, false))
+ {
+ interrupt_activity( AI_FORCE_INTERRUPT );
+ return;
+ }
+
+ crawl_state.level_annotation_shown = true;
+ }
+
// Interlevel travel data:
bool collect_travel_data = can_travel_interlevel();
@@ -804,9 +963,11 @@ void down_stairs( int old_level, dungeon_feature_type force_stair )
you.level_type = LEVEL_DUNGEON;
}
- you.prev_targ = MHITNOT;
+ you.prev_targ = MHITNOT;
you.pet_target = MHITNOT;
+ you.prev_grd_targ = coord_def(0, 0);
+
if (stair_find == DNGN_ENTER_HELL)
{
you.where_are_you = BRANCH_VESTIBULE_OF_HELL;
@@ -864,7 +1025,8 @@ void down_stairs( int old_level, dungeon_feature_type force_stair )
if (stair_find == DNGN_EXIT_ABYSS || stair_find == DNGN_EXIT_PANDEMONIUM)
{
mpr("You pass through the gate.");
- more();
+ if (!(you.wizard && crawl_state.is_replaying_keys()))
+ more();
}
if (old_level_type != you.level_type && you.level_type == LEVEL_DUNGEON)
@@ -885,7 +1047,12 @@ void down_stairs( int old_level, dungeon_feature_type force_stair )
KILLED_BY_FALLING_DOWN_STAIRS );
}
- if (you.level_type == LEVEL_DUNGEON)
+ if (shaft)
+ {
+ you.your_level = shaft_level;
+ you.where_are_you = shaft_dest.branch;
+ }
+ else if (you.level_type == LEVEL_DUNGEON)
you.your_level++;
dungeon_feature_type stair_taken = stair_find;
@@ -896,6 +1063,9 @@ void down_stairs( int old_level, dungeon_feature_type force_stair )
if (you.level_type == LEVEL_PANDEMONIUM)
stair_taken = DNGN_TRANSIT_PANDEMONIUM;
+ if (shaft)
+ stair_taken = DNGN_ROCK_STAIRS_DOWN;
+
switch (you.level_type)
{
case LEVEL_LABYRINTH:
@@ -919,11 +1089,18 @@ void down_stairs( int old_level, dungeon_feature_type force_stair )
break;
default:
- climb_message(stair_find, false, old_level_type);
+ if (shaft)
+ {
+ if (you.flight_mode() == FL_FLY && !force_stair)
+ mpr("You dive down through the shaft.");
+ }
+ else
+ climb_message(stair_find, false, old_level_type);
break;
}
- exit_stair_message(stair_find, false);
+ if (!shaft)
+ exit_stair_message(stair_find, false);
if (entered_branch)
{
@@ -946,14 +1123,74 @@ void down_stairs( int old_level, dungeon_feature_type force_stair )
const bool newlevel =
load(stair_taken, LOAD_ENTER_LEVEL, old_level_type,
old_level, old_where);
-
+
+ set_entry_cause(entry_cause, old_level_type);
+ entry_cause = you.entry_cause;
+
if (newlevel)
- xom_is_stimulated(49);
+ {
+ switch(you.level_type)
+ {
+ case LEVEL_DUNGEON:
+ xom_is_stimulated(49);
+ break;
+
+ case LEVEL_PORTAL_VAULT:
+ // Portal vaults aren't as interesting.
+ xom_is_stimulated(25);
+ break;
+
+ case LEVEL_LABYRINTH:
+ // Finding the way out of a labyrinth interests Xom.
+ xom_is_stimulated(98);
+ break;
+
+ case LEVEL_ABYSS:
+ case LEVEL_PANDEMONIUM:
+ {
+ // Paranoia
+ if (old_level_type == you.level_type)
+ break;
+
+ PlaceInfo &place_info = you.get_place_info();
+
+ // Entering voluntarily only stimulates Xom if you've never
+ // been there before
+ if ((place_info.num_visits == 1 && place_info.levels_seen == 1)
+ || entry_cause != EC_SELF_EXPLICIT)
+ {
+ if (crawl_state.is_god_acting())
+ xom_is_stimulated(255);
+ else if (entry_cause == EC_SELF_EXPLICIT)
+ {
+ // Entering Pandemonium or the Abyss for the first
+ // time *voluntarily* stimulates Xom much more than
+ // entering a normal dungeon level for the first time.
+ xom_is_stimulated(128, XM_INTRIGUED);
+ }
+ else if (entry_cause == EC_SELF_RISKY)
+ xom_is_stimulated(128);
+ else
+ xom_is_stimulated(255);
+ }
+
+ break;
+ }
+
+ default:
+ ASSERT(false);
+ }
+ }
unsigned char pc = 0;
unsigned char pt = random2avg(28, 3);
- if (level_type_exits_up(you.level_type))
+ if (shaft)
+ {
+ you.your_level = shaft_level;
+ you.where_are_you = shaft_dest.branch;
+ }
+ else if (level_type_exits_up(you.level_type))
you.your_level++;
else if (level_type_exits_down(you.level_type)
&& !level_type_exits_down(old_level_type))
@@ -1006,6 +1243,13 @@ void down_stairs( int old_level, dungeon_feature_type force_stair )
new_level();
+ // clear list of beholding monsters
+ if (you.duration[DUR_BEHELD])
+ {
+ you.beheld_by.clear();
+ you.duration[DUR_BEHELD] = 0;
+ }
+
viewwindow(1, true);
if (you.skills[SK_TRANSLOCATIONS] > 0 && !allow_control_teleport( true ))
@@ -1097,8 +1341,6 @@ void new_level(void)
take_note(Note(NOTE_DUNGEON_LEVEL_CHANGE));
cprintf("%s", level_description_string().c_str());
- dgn_set_floor_colours();
-
clear_to_end_of_line();
#ifdef DGL_WHEREIS
whereis_record();
@@ -1241,7 +1483,7 @@ bool go_berserk(bool intentional)
deflate_hp(you.hp_max, false);
if (!you.duration[DUR_MIGHT])
- modify_stat( STAT_STRENGTH, 5, true );
+ modify_stat( STAT_STRENGTH, 5, true, "going berserk" );
you.duration[DUR_MIGHT] += you.duration[DUR_BERSERKER];
haste_player( you.duration[DUR_BERSERKER] );
@@ -1302,8 +1544,7 @@ std::string cloud_name(cloud_type type)
bool mons_is_safe(const struct monsters *mon, bool want_move)
{
bool is_safe = mons_friendly(mon) ||
- (Options.safe_zero_exp &&
- mons_class_flag( mon->type, M_NO_EXP_GAIN ));
+ mons_class_flag(mon->type, M_NO_EXP_GAIN);
#ifdef CLUA_BINDINGS
bool moving = ((!you.delay_queue.empty() &&
@@ -1355,11 +1596,10 @@ bool i_feel_safe(bool announce, bool want_move)
{
for ( int x = xstart; x < xend; ++x )
{
- /* if you can see a nonfriendly monster then you feel
- unsafe */
+ // if you can see a nonfriendly monster then you feel unsafe
if ( see_grid(x,y) )
{
- const unsigned char targ_monst = mgrd[x][y];
+ const unsigned short targ_monst = mgrd[x][y];
if ( targ_monst != NON_MONSTER )
{
const monsters *mon = &menv[targ_monst];
@@ -1630,4 +1870,3 @@ int speed_to_duration(int speed)
return div_rand_round(100, speed);
}
-
diff --git a/crawl-ref/source/misc.h b/crawl-ref/source/misc.h
index cfc1be8fb8..460c76e403 100644
--- a/crawl-ref/source/misc.h
+++ b/crawl-ref/source/misc.h
@@ -19,6 +19,8 @@
struct bolt;
struct dist;
+struct activity_interrupt_data;
+
// last updated 08jan2001 {gdl}
/* ***********************************************************************
@@ -37,8 +39,9 @@ void search_around( bool only_adjacent = false );
/* ***********************************************************************
* called from: acr - effects - spells3
* *********************************************************************** */
-void down_stairs(int old_level, dungeon_feature_type force_stair = DNGN_UNSEEN);
-
+void down_stairs(int old_level,
+ dungeon_feature_type force_stair = DNGN_UNSEEN,
+ entry_cause_type entry_cause = EC_UNKNOWN);
// last updated 12may2000 {dlb}
/* ***********************************************************************
@@ -73,7 +76,8 @@ void turn_corpse_into_chunks( item_def &item );
/* ***********************************************************************
* called from: acr
* *********************************************************************** */
-void up_stairs(dungeon_feature_type force_stair = DNGN_UNSEEN);
+void up_stairs(dungeon_feature_type force_stair = DNGN_UNSEEN,
+ entry_cause_type entry_cause = EC_UNKNOWN);
// last updated 12may2000 {dlb}
/* ***********************************************************************
@@ -116,4 +120,7 @@ int speed_to_duration(int speed);
bool scramble(void);
+bool interrupt_cmd_repeat( activity_interrupt_type ai,
+ const activity_interrupt_data &at );
+
#endif
diff --git a/crawl-ref/source/misc/build_dcss_release.rb b/crawl-ref/source/misc/build_dcss_release.rb
index 49857dc54e..5f620fb209 100755
--- a/crawl-ref/source/misc/build_dcss_release.rb
+++ b/crawl-ref/source/misc/build_dcss_release.rb
@@ -5,8 +5,8 @@
require 'fileutils'
require 'zip/zipfilesystem'
-SVN_BASE_URL = 'https://svn.sourceforge.net/svnroot/crawl-ref/'
-SVN_BRANCH = 'branches/stone_soup-0.2'
+SVN_BASE_URL = 'https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/'
+SVN_BRANCH = 'branches/stone_soup-0.3'
SVN_URL = SVN_BASE_URL + SVN_BRANCH + '/crawl-ref'
# If empty, nothing is done. Useful to sync svk mirrors.
@@ -96,9 +96,10 @@ def path_prefix(prefix)
end
def clean_objects
- [ '.', 'rel', 'dbg', 'util' ].each do |dir|
+ [ '.', 'rel', 'dbg', 'util', 'util/lua/src', 'util/sqlite' ].each do |dir|
if File.directory? dir
FileUtils.rm( Dir[dir + '/*.o'], :force => true )
+ FileUtils.rm( Dir[dir + '/*.a'], :force => true )
end
end
end
@@ -154,9 +155,11 @@ def build_dos
setup_dosmake_env
puts "\nBuilding stone_soup (ndebug) for #{release_version} DOS"
- system( %{ #{DOSMAKE} -f makefile.dos DOYACC=y "EXTRA_FLAGS=-O2 } +
- %{-DCLUA_BINDINGS -DREGEX_PCRE" } +
- %{"LIB=-static -llua -lpcre"} ) or
+ ENV['LIB'] = "-static -Lutil\\lua\\src -llua -lpcre -Lutil\\sqlite -lsql3"
+ ENV['EXTRA_FLAGS'] = "-O2 -DCLUA_BINDINGS -DREGEX_PCRE -DDEBUG -DWIZARD"
+
+ puts %{ #{DOSMAKE} -e -f makefile.dos DOYACC=y }
+ system( %{ #{DOSMAKE} -e -f makefile.dos DOYACC=y } ) or
raise "#{DOSMAKE} failed: #$?"
upx CRAWL_DOS_PATH
@@ -167,20 +170,21 @@ def build_win32
puts "\nBuilding stone_soup (non-debug) for #{release_version} release!"
system( %{#{W32MAKE} -f makefile.mgw DOYACC=y "EXTRA_FLAGS=-O2 } +
- %{-DCLUA_BINDINGS -DREGEX_PCRE" } +
- %{"LIB=-lwinmm -static -llua -lpcre"} ) or
+ %{-DCLUA_BINDINGS -DREGEX_PCRE -DDEBUG -DWIZARD" } +
+ %{"LIB=-lwinmm -static -Lutil/lua/src -llua -lpcre -Lutil/sqlite -lsqlite3"} ) or
raise "#{W32MAKE} failed: #$?"
clean_w32build_area
- puts "\nBuilding stone_soup (debug) for #{release_version}!"
- system( %{#{W32MAKE} -f makefile.mgw debug DEBUG_CRAWL=y "EXTRA_FLAGS=-O2 } +
- %{-DCLUA_BINDINGS -DREGEX_PCRE -DFULLDEBUG -DWIZARD" } +
- %{"LIB=-lwinmm -static -llua -lpcre" } +
- %{DOYACC=y} ) or
- raise "#{W32MAKE} failed: #$?"
+ #puts "\nBuilding stone_soup (debug) for #{release_version}!"
+ #system( %{#{W32MAKE} -f makefile.mgw debug DEBUG_CRAWL=y "EXTRA_FLAGS=-O2 } +
+ # %{-DCLUA_BINDINGS -DREGEX_PCRE -DFULLDEBUG -DWIZARD" } +
+ # %{"LIB=-lwinmm -static -llua -lpcre" } +
+ # %{DOYACC=y} ) or
+ # raise "#{W32MAKE} failed: #$?"
- upx CRAWL_NDB_PATH, CRAWL_DBG_PATH
+ #upx CRAWL_NDB_PATH, CRAWL_DBG_PATH
+ upx CRAWL_NDB_PATH
end
def upx(*files)
@@ -214,8 +218,9 @@ def makezip(path, name, exe)
zip.add( Dir['docs/*'].find_all { |f| not File.directory?(f) },
:keep_paths => true )
- zip.add( Dir['source/lua/*'], :prefix => 'lua' )
- zip.add( Dir['source/dat/*'], :prefix => 'dat' )
+ [ 'lua', 'dat', 'dat/clua', 'dat/descript' ].each do |dir|
+ zip.add( Dir['source/' + dir + '/*'], :prefix => dir )
+ end
end
end
@@ -226,7 +231,7 @@ def package
FileUtils.rm( Dir[ File.join(PACKAGE_PATH, '*.zip') ] )
[ [ "stone_soup-#{release_version}-win32", CRAWL_NDB_PATH ],
- [ "stone_soup-#{release_version}-win32-debug", CRAWL_DBG_PATH ],
+ # [ "stone_soup-#{release_version}-win32-debug", CRAWL_DBG_PATH ],
[ "ss#{release_version.tr '.', ''}dos", CRAWL_DOS_PATH ]
].
each do |pkg, exe|
diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h
index 809971278a..54046d17b8 100644
--- a/crawl-ref/source/mon-data.h
+++ b/crawl-ref/source/mon-data.h
@@ -5,6 +5,8 @@
#ifndef MONDATA_H
#define MONDATA_H
+#define AT_NO_ATK {AT_NONE, AF_PLAIN, 0}
+
#include "enum.h"
/*
@@ -27,9 +29,9 @@
- row 4: mass, experience modifier, charclass, holiness, resist magic
- row 5: damage for each of four attacks
- row 6: hit dice, described by four parameters
- - row 7: AC, evasion, speed, speed_inc, sec(spell), corpse_thingy,
- zombie size, shouts, intel
- - row 8: gmon_use class, body size
+ - row 7: AC, evasion, sec(spell), corpse_thingy, zombie size,
+ shouts, intel
+ - row 8: speed, energy_usage, gmon_use class, body size
- Some further explanations:
@@ -41,7 +43,7 @@
holy wrath weapons
natural - baseline monster type
undead - immunity from draining, pain, torment; extra
- damage from hoyl wrath/disruption; affected by
+ damage from holy 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
@@ -65,12 +67,6 @@
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.
@@ -85,6 +81,15 @@
for monster's chance of seeing you if stealthy, and really stupid monsters
will walk through clouds
+ speed
+ - Increases the store of energy that the monster uses for doing things.
+ less = slower. 5 = half speed, 10 = normal, 20 = double speed.
+
+ energy usage
+ - How quickly the energy granted by speed is used up. Most monsters
+ should just use DEFAULT_ENERGY, where all the different types of actions
+ use 10 energy units.
+
gmon_use explanation:
0 = uses nothing
1 = opens doors
@@ -93,6 +98,8 @@
*/
+#define DEFAULT_ENERGY {10, 10, 10, 10, 10, 10, 10, 100}
+#define MOVE_ENERGY(x) {(x), (x), 10, 10, 10, 10, 10, 100}
// monster 250: The Thing That Should Not Be(tm)
// do not remove, or seekmonster will crash on unknown mc request
@@ -102,12 +109,11 @@
M_NO_EXP_GAIN,
MR_NO_FLAGS,
0, 10, MONS_PROGRAM_BUG, MONS_PROGRAM_BUG, MH_NATURAL, -3,
- { {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 0, 0, 0, 0 },
- 0, 0, 0, 0, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_HUGE
-}
-,
+ 0, 0, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 0, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_HUGE
+},
// real monsters begin here {dlb}:
{
@@ -115,96 +121,88 @@
M_NO_FLAGS,
MR_VUL_POISON,
700, 10, MONS_GIANT_ANT, MONS_GIANT_ANT, MH_NATURAL, -3,
- { {AT_BITE, AF_POISON, 8}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_POISON, 8}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 3, 3, 5, 0 },
- 4, 10, 12, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_LITTLE,
-}
-,
+ 4, 10, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_INSECT,
+ 12, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LITTLE,
+},
{
MONS_GIANT_BAT, 'b', DARKGREY, "giant bat",
M_FLIES | M_SENSE_INVIS | M_WARM_BLOOD,
MR_NO_FLAGS,
150, 4, MONS_GIANT_BAT, MONS_GIANT_BAT, MH_NATURAL, -1,
- { {AT_HIT, AF_PLAIN, 1}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 1}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 1, 2, 3, 0 },
- 1, 14, 30, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_ANIMAL,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 1, 14, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_ANIMAL,
+ 30, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_CENTAUR, 'c', BROWN, "centaur",
M_WARM_BLOOD,
MR_NO_FLAGS,
1500, 10, MONS_CENTAUR, MONS_CENTAUR, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 10}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 4, 3, 5, 0 },
- 3, 7, 15, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_BIG
-}
-,
+ 3, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SHOUT, I_NORMAL,
+ 15, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_BIG
+},
{
MONS_RED_DEVIL, '4', RED, "red devil",
M_FIGHTER | M_FLIES | M_EVIL,
MR_RES_POISON | MR_RES_HELLFIRE | MR_VUL_COLD,
0, 10, MONS_RED_DEVIL, MONS_RED_DEVIL, MH_DEMONIC, -7,
- { {AT_HIT, AF_PLAIN, 18}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 18}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 5, 3, 5, 0 },
- 10, 10, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 10, 10, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_ETTIN, 'C', BROWN, "ettin",
M_WARM_BLOOD | M_EVIL,
MR_NO_FLAGS,
0, 10, MONS_HILL_GIANT, MONS_ETTIN, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 18}, {AT_HIT, AF_PLAIN, 12}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 18}, {AT_HIT, AF_PLAIN, 12}, AT_NO_ATK, AT_NO_ATK },
{ 7, 3, 5, 0 },
- 3, 4, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT2, I_NORMAL,
- MONUSE_STARTING_EQUIPMENT, SIZE_GIANT,
-}
-,
+ 3, 4, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT2, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_GIANT,
+},
{
MONS_FUNGUS, 'f', LIGHTGREY, "fungus",
M_NO_EXP_GAIN,
MR_RES_POISON,
0, 10, MONS_PLANT, MONS_FUNGUS, MH_PLANT, MAG_IMMUNE,
- { {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 8, 3, 5, 0 },
- 1, 0, 0, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 1, 0, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 0, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_GOBLIN, 'g', LIGHTGREY, "goblin",
M_WARM_BLOOD | M_EVIL,
MR_NO_FLAGS,
400, 10, MONS_GOBLIN, MONS_GOBLIN, MH_NATURAL, -1,
- { {AT_HIT, AF_PLAIN, 4}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 4}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 1, 2, 4, 0 },
- 0, 12, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_SMALL
-}
-,
+ 0, 12, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_SMALL
+},
{
MONS_HOUND, 'h', BROWN, "hound",
M_SENSE_INVIS | M_WARM_BLOOD,
MR_NO_FLAGS,
300, 10, MONS_HOUND, MONS_HOUND, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 6}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 6}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 3, 3, 5, 0 },
- 2, 13, 15, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_BARK, I_ANIMAL,
- MONUSE_NOTHING, SIZE_SMALL
-}
-,
+ 2, 13, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_BARK, I_ANIMAL,
+ 15, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_SMALL
+},
// note: these things regenerate
{
@@ -212,60 +210,55 @@
M_FLIES | M_SEE_INVIS | M_SPEAKS | M_EVIL | M_SPECIAL_ABILITY,
MR_RES_POISON | MR_RES_HELLFIRE | MR_VUL_COLD,
0, 13, MONS_IMP, MONS_IMP, MH_DEMONIC, -9,
- { {AT_HIT, AF_PLAIN, 4}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 4}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 3, 3, 3, 0 },
- 3, 14, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_LITTLE,
-}
-,
+ 3, 14, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_LITTLE,
+},
{
MONS_JACKAL, 'j', YELLOW, "jackal",
M_WARM_BLOOD,
MR_NO_FLAGS,
200, 10, MONS_HOUND, MONS_JACKAL, MH_NATURAL, -1,
- { {AT_BITE, AF_PLAIN, 3}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 3}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 1, 3, 5, 0 },
- 2, 12, 14, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_BARK, I_ANIMAL,
- MONUSE_NOTHING, SIZE_SMALL
-}
-,
+ 2, 12, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_BARK, I_ANIMAL,
+ 14, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_SMALL
+},
{
MONS_KILLER_BEE, 'k', YELLOW, "killer bee",
M_FLIES,
MR_VUL_POISON,
150, 11, MONS_KILLER_BEE, MONS_KILLER_BEE, MH_NATURAL, -3,
- { {AT_STING, AF_POISON, 10}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_STING, AF_POISON, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 3, 3, 5, 0 },
- 2, 18, 20, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_BUZZ, I_INSECT,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 2, 18, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_BUZZ, I_INSECT,
+ 20, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_KILLER_BEE_LARVA, 'w', LIGHTGREY, "killer bee larva",
M_NO_SKELETON,
MR_VUL_POISON,
150, 5, MONS_KILLER_BEE_LARVA, MONS_KILLER_BEE_LARVA, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 3}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 3}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 1, 3, 5, 0 },
- 1, 5, 5, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 1, 5, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
+ 5, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_MANTICORE, 'm', BROWN, "manticore",
M_WARM_BLOOD | M_SPECIAL_ABILITY,
MR_NO_FLAGS,
1800, 10, MONS_MANTICORE, MONS_MANTICORE, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 14}, {AT_CLAW, AF_PLAIN, 8}, {AT_CLAW, AF_PLAIN, 8}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 14}, {AT_CLAW, AF_PLAIN, 8}, {AT_CLAW, AF_PLAIN, 8}, AT_NO_ATK },
{ 9, 3, 5, 0 },
- 5, 7, 7, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SILENT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_BIG
-}
-,
+ 5, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SILENT, I_NORMAL,
+ 7, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_BIG
+},
// this thing doesn't have nr. 13 for nothing, has it? ($pellbinder)
{
@@ -273,24 +266,22 @@
M_EVIL,
MR_RES_POISON | MR_RES_COLD,
500, 10, MONS_GHOUL, MONS_NECROPHAGE, MH_UNDEAD, -5,
- { {AT_HIT, AF_ROT, 8}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_ROT, 8}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 5, 3, 5, 0 },
- 2, 10, 10, 7, MST_NO_SPELLS, CE_HCL, Z_NOZOMBIE, S_SILENT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 2, 10, MST_NO_SPELLS, CE_HCL, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
{
MONS_ORC, 'o', LIGHTRED, "orc",
M_WARM_BLOOD | M_EVIL,
MR_NO_FLAGS,
600, 10, MONS_ORC, MONS_ORC, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 5}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 1, 4, 6, 0 },
- 0, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
// XP modifier is 5 for these, because they really aren't all that
// dangerous, but still come out at 200+ XP
@@ -299,48 +290,44 @@
M_EVIL | M_SPECIAL_ABILITY,
MR_RES_POISON | MR_RES_COLD,
0, 5, MONS_PHANTOM, MONS_PHANTOM, MH_UNDEAD, -4,
- { {AT_HIT, AF_BLINK, 10}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_BLINK, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 7, 3, 5, 0 },
- 3, 13, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 3, 13, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
{
MONS_QUASIT, 'q', LIGHTGREY, "quasit",
M_EVIL,
MR_RES_POISON | MR_RES_FIRE | MR_RES_COLD,
0, 10, MONS_QUASIT, MONS_QUASIT, MH_DEMONIC, 5,
- { {AT_BITE, AF_DRAIN_DEX, 3}, {AT_CLAW, AF_DRAIN_DEX, 2}, {AT_CLAW, AF_DRAIN_DEX, 2}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_DRAIN_DEX, 3}, {AT_CLAW, AF_DRAIN_DEX, 2}, {AT_CLAW, AF_DRAIN_DEX, 2}, AT_NO_ATK },
{ 3, 2, 6, 0 },
- 5, 17, 13, 7, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_SMALL
-}
-,
+ 5, 17, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_INSECT,
+ 13, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_SMALL
+},
{
MONS_RAT, 'r', BROWN, "rat",
M_WARM_BLOOD,
MR_NO_FLAGS,
200, 10, MONS_RAT, MONS_RAT, MH_NATURAL, -1,
- { {AT_BITE, AF_PLAIN, 3}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 3}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 1, 1, 3, 0 },
- 1, 10, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_ANIMAL,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 1, 10, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_ANIMAL,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_SCORPION, 's', DARKGREY, "scorpion",
M_NO_FLAGS,
MR_VUL_POISON,
500, 10, MONS_SCORPION, MONS_SCORPION, MH_NATURAL, -3,
- { {AT_STING, AF_POISON_MEDIUM, 10}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_STING, AF_POISON_MEDIUM, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 3, 3, 5, 0 },
- 5, 10, 10, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 5, 10, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
/* ******************************************************************
// the tunneling worm is no more ...
@@ -352,10 +339,10 @@
0, 10, 19, MH_NATURAL, MAG_IMMUNE,
{ 50, 0, 0, 0 },
{ 10, 5, 5, 0 },
- 3, 3, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_HUGE
-}
-,
+ 3, 3, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_INSECT,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_HUGE
+},
+
****************************************************************** */
{
@@ -363,36 +350,33 @@
M_WARM_BLOOD | M_AMPHIBIOUS,
MR_NO_FLAGS,
600, 10, MONS_UGLY_THING, MONS_UGLY_THING, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 12}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 12}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 8, 3, 5, 0 },
- 3, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 3, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
{
MONS_FIRE_VORTEX, 'v', RED, "fire vortex",
M_LEVITATE | M_CONFUSED,
MR_RES_POISON | MR_RES_FIRE | MR_VUL_COLD | MR_RES_ELEC,
0, 5, MONS_FIRE_VORTEX, MONS_FIRE_VORTEX, MH_NONLIVING, MAG_IMMUNE,
- { {AT_HIT, AF_FIRE, 30}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_FIRE, 30}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 3, 3, 5, 0 },
- 0, 5, 15, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_LARGE
-}
-,
+ 0, 5, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 15, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LARGE
+},
{
MONS_WORM, 'w', LIGHTRED, "worm",
M_NO_SKELETON,
MR_NO_FLAGS,
350, 4, MONS_WORM, MONS_WORM, MH_NATURAL, -2,
- { {AT_BITE, AF_PLAIN, 12}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 12}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 5, 3, 5, 0 },
- 1, 5, 6, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_MEDIUM
-}
-,
+ 1, 5, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_INSECT,
+ 6, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_MEDIUM
+},
// random
{
@@ -400,24 +384,22 @@
M_EVIL,
MR_NO_FLAGS,
0, 10, MONS_ABOMINATION_SMALL, MONS_ABOMINATION_SMALL, MH_DEMONIC, -5,
- { {AT_HIT, AF_PLAIN, 23}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 23}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 2, 5, 0 },
- 0, 0, 0, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_LARGE
-}
-,
+ 0, 0, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 0, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LARGE
+},
{
MONS_YELLOW_WASP, 'y', YELLOW, "yellow wasp",
M_FLIES,
MR_VUL_POISON,
220, 12, MONS_YELLOW_WASP, MONS_YELLOW_WASP, MH_NATURAL, -3,
- { {AT_STING, AF_PARALYSE, 13}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_STING, AF_PARALYSE, 13}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 4, 3, 5, 0 },
- 5, 14, 15, 7, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 5, 14, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_INSECT,
+ 15, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
// small zombie
{
@@ -425,60 +407,55 @@
M_EVIL,
MR_RES_POISON | MR_RES_COLD,
0, 6, MONS_ZOMBIE_SMALL, MONS_ZOMBIE_SMALL, MH_UNDEAD, -1,
- { {AT_HIT, AF_PLAIN, 10}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 1, 5, 5, 0 },
- 0, 4, 5, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_SMALL
-}
-,
+ 0, 4, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 5, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_SMALL
+},
{
MONS_ANGEL, 'A', WHITE, "Angel",
M_FIGHTER | M_FLIES | M_SPELLCASTER | M_SEE_INVIS,
MR_RES_POISON | MR_RES_ELEC,
0, 10, MONS_ANGEL, MONS_ANGEL, MH_HOLY, -8,
- { {AT_HIT, AF_PLAIN, 25}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 25}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 12, 6, 5, 0 },
- 10, 20, 15, 7, MST_ANGEL, CE_NOCORPSE, Z_NOZOMBIE, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 10, 20, MST_ANGEL, CE_NOCORPSE, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ 15, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_GIANT_BEETLE, 'B', DARKGREY, "giant beetle",
M_NO_FLAGS,
MR_VUL_POISON,
1000, 10, MONS_GIANT_BEETLE, MONS_GIANT_BEETLE, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 5, 7, 6, 0 },
- 10, 3, 5, 7, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_MEDIUM
-}
-,
+ 10, 3, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_SILENT, I_INSECT,
+ 5, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_MEDIUM
+},
{
MONS_CYCLOPS, 'C', BROWN, "cyclops",
M_WARM_BLOOD | M_EVIL,
MR_NO_FLAGS,
2500, 10, MONS_HILL_GIANT, MONS_CYCLOPS, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 35}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 35}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 9, 3, 5, 0 },
- 5, 3, 7, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SHOUT, I_NORMAL,
- MONUSE_STARTING_EQUIPMENT, SIZE_GIANT,
-}
-,
+ 5, 3, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SHOUT, I_NORMAL,
+ 7, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_GIANT,
+},
{
MONS_DRAGON, 'D', GREEN, "dragon",
M_FLIES | M_SPECIAL_ABILITY, //jmf: warm blood?
MR_RES_POISON | MR_RES_FIRE | MR_VUL_COLD,
2200, 12, MONS_DRAGON, MONS_DRAGON, MH_NATURAL, -4,
- { {AT_BITE, AF_PLAIN, 20}, {AT_CLAW, AF_PLAIN, 13}, {AT_CLAW, AF_PLAIN, 13}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 20}, {AT_CLAW, AF_PLAIN, 13}, {AT_CLAW, AF_PLAIN, 13}, AT_NO_ATK },
{ 12, 5, 5, 0 },
- 10, 8, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SILENT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_HUGE
-}
-,
+ 10, 8, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SILENT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_HUGE
+},
// These guys get understated because the experience code can't see
// that they wield two weapons... I'm raising their xp modifier. -- bwr
@@ -487,228 +464,209 @@
M_WARM_BLOOD | M_EVIL,
MR_NO_FLAGS,
1500, 15, MONS_OGRE, MONS_TWO_HEADED_OGRE, MH_NATURAL, -4,
- { {AT_HIT, AF_PLAIN, 17}, {AT_HIT, AF_PLAIN, 13}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 17}, {AT_HIT, AF_PLAIN, 13}, AT_NO_ATK, AT_NO_ATK },
{ 6, 3, 5, 0 },
- 1, 4, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT2, I_NORMAL,
- MONUSE_STARTING_EQUIPMENT, SIZE_LARGE
-}
-,
+ 1, 4, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT2, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_LARGE
+},
{
MONS_FIEND, '1', LIGHTRED, "Fiend", //jmf: was RED, like Balrog
M_FLIES | M_SEE_INVIS | M_EVIL,
MR_RES_POISON | MR_RES_HELLFIRE | MR_VUL_COLD,
0, 18, MONS_FIEND, MONS_FIEND, MH_DEMONIC, -12,
- { {AT_HIT, AF_PLAIN, 25}, {AT_HIT, AF_PLAIN, 15}, {AT_HIT, AF_PLAIN, 15}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 25}, {AT_HIT, AF_PLAIN, 15}, {AT_HIT, AF_PLAIN, 15}, AT_NO_ATK },
{ 18, 3, 5, 0 },
- 15, 6, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_ROAR, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 15, 6, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_ROAR, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_GIANT_SPORE, 'G', GREEN, "giant spore",
M_LEVITATE,
MR_RES_POISON | MR_RES_ASPHYX,
0, 10, MONS_PLANT, MONS_GIANT_SPORE, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 1}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 1}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 1, 0, 0, 1 },
- 0, 10, 15, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_SMALL
-}
-,
+ 0, 10, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 15, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_SMALL
+},
{
MONS_HOBGOBLIN, 'g', BROWN, "hobgoblin",
M_WARM_BLOOD | M_EVIL,
MR_NO_FLAGS,
500, 10, MONS_GOBLIN, MONS_HOBGOBLIN, MH_NATURAL, -1,
- { {AT_HIT, AF_PLAIN, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 5}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 1, 4, 3, 0 },
- 2, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 2, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_ICE_BEAST, 'I', WHITE, "ice beast",
M_NO_FLAGS,
MR_RES_POISON | MR_RES_ASPHYX | MR_VUL_FIRE | MR_RES_COLD,
0, 12, MONS_ICE_BEAST, MONS_ICE_BEAST, MH_NATURAL, -3,
- { {AT_HIT, AF_COLD, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_COLD, 5}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 5, 3, 5, 0 },
- 5, 10, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_ANIMAL,
- MONUSE_NOTHING, SIZE_LARGE
-}
-,
+ 5, 10, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_ANIMAL,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LARGE
+},
{
MONS_JELLY, 'J', LIGHTRED, "jelly",
M_SEE_INVIS | M_SPLITS | M_AMPHIBIOUS | M_ACID_SPLASH,
MR_RES_POISON | MR_RES_ASPHYX | MR_RES_ACID,
0, 13, MONS_JELLY, MONS_JELLY, MH_NATURAL, -3,
- { {AT_HIT, AF_ACID, 8}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_ACID, 8}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 3, 5, 5, 0 },
- 0, 2, 9, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_EATS_ITEMS, SIZE_MEDIUM
-}
-,
+ 0, 2, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 9, DEFAULT_ENERGY, MONUSE_EATS_ITEMS, SIZE_MEDIUM
+},
{
MONS_KOBOLD, 'K', BROWN, "kobold",
M_WARM_BLOOD,
MR_NO_FLAGS,
400, 10, MONS_KOBOLD, MONS_KOBOLD, MH_NATURAL, -1,
- { {AT_HIT, AF_PLAIN, 4}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 4}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 1, 2, 3, 0 },
- 2, 12, 10, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_SMALL
-}
-,
+ 2, 12, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_SMALL
+},
{
MONS_LICH, 'L', WHITE, "lich",
M_SPELLCASTER | M_ACTUAL_SPELLS | M_SEE_INVIS | M_EVIL,
MR_RES_POISON | MR_RES_COLD | MR_RES_ELEC,
0, 16, MONS_LICH, MONS_LICH, MH_UNDEAD, -11,
- { {AT_TOUCH, AF_DRAIN_XP, 15}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_TOUCH, AF_DRAIN_XP, 15}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 20, 2, 4, 0 },
- 10, 10, 10, 7, MST_LICH_I, CE_NOCORPSE, Z_NOZOMBIE, S_SHOUT, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 10, 10, MST_LICH_I, CE_NOCORPSE, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
{
MONS_MUMMY, 'M', WHITE, "mummy",
M_EVIL,
MR_RES_POISON | MR_VUL_FIRE | MR_RES_COLD,
0, 10, MONS_MUMMY, MONS_MUMMY, MH_UNDEAD, -5,
- { {AT_HIT, AF_PLAIN, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 3, 5, 3, 0 },
- 3, 6, 6, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_ANIMAL,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 3, 6, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_ANIMAL,
+ 6, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
{
MONS_GUARDIAN_NAGA, 'N', LIGHTGREEN, "guardian naga",
M_SPELLCASTER | M_SEE_INVIS | M_ACTUAL_SPELLS | M_WARM_BLOOD,
MR_RES_POISON,
350, 10, MONS_NAGA, MONS_GUARDIAN_NAGA, MH_NATURAL, -6,
- { {AT_HIT, AF_PLAIN, 19}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 19}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 8, 3, 5, 0 },
- 6, 14, 15, 7, MST_GUARDIAN_NAGA, CE_MUTAGEN_RANDOM, Z_SMALL, S_SHOUT, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_BIG
-}
-,
+ 6, 14, MST_GUARDIAN_NAGA, CE_MUTAGEN_RANDOM, Z_SMALL, S_SHOUT, I_HIGH,
+ 15, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_BIG
+},
{
MONS_OGRE, 'O', BROWN, "ogre",
M_WARM_BLOOD | M_EVIL,
MR_NO_FLAGS,
1300, 10, MONS_OGRE, MONS_OGRE, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 17}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 17}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 5, 3, 5, 0 },
- 1, 6, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_NORMAL,
- MONUSE_STARTING_EQUIPMENT, SIZE_LARGE
-}
-,
+ 1, 6, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_LARGE
+},
{
MONS_PLANT, 'P', GREEN, "plant",
M_NO_EXP_GAIN,
MR_RES_POISON,
0, 10, MONS_PLANT, MONS_PLANT, MH_PLANT, MAG_IMMUNE,
- { {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 10, 3, 5, 0 },
- 10, 0, 0, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_SMALL
-}
-,
+ 10, 0, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 0, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_SMALL
+},
{
MONS_QUEEN_BEE, 'Q', YELLOW, "queen bee",
M_FLIES,
MR_VUL_POISON,
200, 14, MONS_KILLER_BEE, MONS_QUEEN_BEE, MH_NATURAL, -3,
- { {AT_STING, AF_POISON_NASTY, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_STING, AF_POISON_NASTY, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 7, 3, 5, 0 },
- 10, 10, 10, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_LITTLE,
-}
-,
+ 10, 10, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LITTLE,
+},
{
MONS_RAKSHASA, 'R', YELLOW, "rakshasa",
M_SPELLCASTER | M_SEE_INVIS | M_EVIL,
MR_RES_POISON,
0, 15, MONS_RAKSHASA, MONS_RAKSHASA, MH_NATURAL, -10,
- { {AT_HIT, AF_PLAIN, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 10, 3, 5, 0 },
- 10, 14, 10, 7, MST_RAKSHASA, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 10, 14, MST_RAKSHASA, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_SNAKE, 'S', GREEN, "snake",
M_COLD_BLOOD | M_AMPHIBIOUS,
MR_NO_FLAGS,
200, 10, MONS_SNAKE, MONS_SNAKE, MH_NATURAL, -3,
- { {AT_BITE, AF_POISON, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_POISON, 5}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 2, 3, 5, 0 },
- 1, 15, 13, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_SMALL
-}
-,
+ 1, 15, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_INSECT,
+ 13, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_SMALL
+},
{
MONS_TROLL, 'T', BROWN, "troll",
M_WARM_BLOOD | M_EVIL,
MR_NO_FLAGS,
1500, 10, MONS_TROLL, MONS_TROLL, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 20}, {AT_CLAW, AF_PLAIN, 15}, {AT_CLAW, AF_PLAIN, 15}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 20}, {AT_CLAW, AF_PLAIN, 15}, {AT_CLAW, AF_PLAIN, 15}, AT_NO_ATK },
{ 7, 3, 5, 0 },
- 3, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 3, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_UNSEEN_HORROR, 'x', MAGENTA, "unseen horror",
M_SEE_INVIS | M_INVIS,
MR_NO_FLAGS,
0, 12, MONS_UNSEEN_HORROR, MONS_UNSEEN_HORROR, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 12}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 12}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 7, 3, 5, 0 },
- 5, 10, 30, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_ANIMAL,
- MONUSE_NOTHING, SIZE_MEDIUM
-}
-,
+ 5, 10, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_ANIMAL,
+ 30, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_MEDIUM
+},
{
MONS_VAMPIRE, 'V', RED, "vampire",
M_SPELLCASTER | M_SEE_INVIS | M_EVIL,
MR_RES_POISON | MR_RES_COLD,
0, 11, MONS_VAMPIRE, MONS_VAMPIRE, MH_UNDEAD, -6,
- { {AT_BITE, AF_VAMPIRIC, 22}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_VAMPIRIC, 22}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 3, 5, 0 },
- 10, 10, 10, 7, MST_VAMPIRE, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 10, 10, MST_VAMPIRE, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_WRAITH, 'W', DARKGREY, "wraith",
M_LEVITATE | M_SEE_INVIS | M_EVIL,
MR_RES_POISON | MR_RES_COLD,
0, 11, MONS_WRAITH, MONS_WRAITH, MH_UNDEAD, -7,
- { {AT_HIT, AF_DRAIN_XP, 13}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_DRAIN_XP, 13}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 3, 5, 0 },
- 10, 10, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 10, 10, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
// Large abom: (the previous one was small)
{
@@ -716,24 +674,22 @@
M_EVIL,
MR_NO_FLAGS,
0, 10, MONS_ABOMINATION_SMALL, MONS_ABOMINATION_LARGE, MH_DEMONIC, -7,
- { {AT_HIT, AF_PLAIN, 40}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 40}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 11, 2, 5, 0 },
- 0, 0, 0, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_BIG
-}
-,
+ 0, 0, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 0, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_BIG
+},
{
MONS_YAK, 'Y', BROWN, "yak",
M_WARM_BLOOD,
MR_NO_FLAGS,
1200, 10, MONS_YAK, MONS_YAK, MH_NATURAL, -3,
- { {AT_BUTT, AF_PLAIN, 18}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BUTT, AF_PLAIN, 18}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 7, 3, 5, 0 },
- 4, 7, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_BELLOW, I_ANIMAL,
- MONUSE_NOTHING, SIZE_BIG
-}
-,
+ 4, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_BELLOW, I_ANIMAL,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_BIG
+},
// big zombie
{
@@ -741,60 +697,55 @@
M_EVIL,
MR_RES_POISON | MR_RES_COLD,
0, 6, MONS_ZOMBIE_SMALL, MONS_ZOMBIE_LARGE, MH_UNDEAD, -1,
- { {AT_HIT, AF_PLAIN, 23}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 23}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 3, 5, 0 },
- 8, 5, 5, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_LARGE
-}
-,
+ 8, 5, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 5, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LARGE
+},
{
MONS_ORC_WARRIOR, 'o', YELLOW, "orc warrior",
M_FIGHTER | M_WARM_BLOOD | M_EVIL,
MR_NO_FLAGS,
0, 10, MONS_ORC, MONS_ORC, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 4, 4, 6, 0 },
- 0, 13, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 13, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_KOBOLD_DEMONOLOGIST, 'K', MAGENTA, "kobold demonologist",
M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD | M_EVIL,
MR_NO_FLAGS,
0, 10, MONS_KOBOLD, MONS_KOBOLD, MH_NATURAL, -5,
- { {AT_HIT, AF_PLAIN, 4}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 4}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 4, 3, 5, 0 },
- 2, 13, 10, 7, MST_KOBOLD_DEMONOLOGIST, CE_POISONOUS, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_SMALL
-}
-,
+ 2, 13, MST_KOBOLD_DEMONOLOGIST, CE_POISONOUS, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_SMALL
+},
{
MONS_ORC_WIZARD, 'o', MAGENTA, "orc wizard",
M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD | M_EVIL,
MR_NO_FLAGS,
0, 10, MONS_ORC, MONS_ORC, MH_NATURAL, -5,
- { {AT_HIT, AF_PLAIN, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 5}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 3, 3, 4, 0 },
- 1, 12, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 1, 12, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_ORC_KNIGHT, 'o', LIGHTCYAN, "orc knight",
M_FIGHTER | M_WARM_BLOOD | M_EVIL,
MR_NO_FLAGS,
0, 10, MONS_ORC, MONS_ORC, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 25}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 25}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 9, 4, 7, 0 },
- 2, 13, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 2, 13, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
/* ******************************************************************
// the tunneling worm is no more ...
@@ -806,10 +757,10 @@
0, 10, 56, MH_NATURAL, MAG_IMMUNE,
{ 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, SIZE_HUGE
-}
-,
+ 3, 3, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_HUGE
+},
+
****************************************************************** */
{
@@ -817,252 +768,231 @@
M_NO_FLAGS, //jmf: warm blood?
MR_NO_FLAGS,
2000, 10, MONS_WYVERN, MONS_WYVERN, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 5, 3, 5, 0 },
- 5, 10, 15, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_ANIMAL,
- MONUSE_NOTHING, SIZE_BIG
-}
-,
+ 5, 10, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_ANIMAL,
+ 15, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_BIG
+},
{
MONS_BIG_KOBOLD, 'K', RED, "big kobold",
M_WARM_BLOOD | M_EVIL,
MR_NO_FLAGS,
0, 10, MONS_KOBOLD, MONS_BIG_KOBOLD, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 7}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 7}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 5, 3, 5, 0 },
- 3, 12, 10, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_SMALL
-}
-,
+ 3, 12, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_SMALL
+},
{
MONS_GIANT_EYEBALL, 'G', WHITE, "giant eyeball",
M_NO_SKELETON | M_LEVITATE,
MR_RES_ASPHYX,
400, 10, MONS_GIANT_EYEBALL, MONS_GIANT_EYEBALL, MH_NATURAL, -3,
- { {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 3, 3, 5, 0 },
- 0, 1, 3, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_MEDIUM
-}
-,
+ 0, 1, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_PLANT,
+ 3, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_MEDIUM
+},
{
MONS_WIGHT, 'W', LIGHTGREY, "wight",
M_EVIL,
MR_RES_POISON | MR_RES_COLD,
0, 10, MONS_WRAITH, MONS_WIGHT, MH_UNDEAD, -4,
- { {AT_HIT, AF_DRAIN_XP, 8}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_DRAIN_XP, 8}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 3, 3, 5, 0 },
- 4, 10, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 4, 10, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_OKLOB_PLANT, 'P', LIGHTGREEN, "oklob plant",
M_SPECIAL_ABILITY,
MR_RES_POISON,
0, 10, MONS_PLANT, MONS_OKLOB_PLANT, MH_PLANT, -3,
- { {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 10, 3, 5, 0 },
- 10, 0, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_SMALL
-}
-,
+ 10, 0, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_SMALL
+},
{
MONS_WOLF_SPIDER, 's', BROWN, "wolf spider",
M_NO_FLAGS,
MR_VUL_POISON,
800, 10, MONS_WOLF_SPIDER, MONS_WOLF_SPIDER, MH_NATURAL, -3,
- { {AT_BITE, AF_POISON_MEDIUM, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_POISON_MEDIUM, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 8, 3, 5, 0 },
- 3, 10, 15, 7, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_HISS, I_INSECT,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 3, 10, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_HISS, I_INSECT,
+ 15, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_SHADOW, ' ', BLACK, "shadow",
M_SEE_INVIS | M_EVIL,
MR_RES_POISON | MR_RES_COLD,
0, 10, MONS_WRAITH, MONS_SHADOW, MH_UNDEAD, -5,
- { {AT_HIT, AF_DRAIN_STR, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_DRAIN_STR, 5}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 3, 3, 5, 0 },
- 12, 10, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_ANIMAL,
- MONUSE_OPEN_DOORS, SIZE_SMALL
-}
-,
+ 12, 10, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_ANIMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_SMALL
+},
{
MONS_HUNGRY_GHOST, 'p', GREEN, "hungry ghost",
M_SENSE_INVIS | M_FLIES | M_EVIL,
MR_RES_POISON | MR_RES_COLD,
0, 10, MONS_PHANTOM, MONS_HUNGRY_GHOST, MH_UNDEAD, -4,
- { {AT_HIT, AF_HUNGER, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_HUNGER, 5}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 7, 3, 5, 0 },
- 0, 17, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 0, 17, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
{
MONS_EYE_OF_DRAINING, 'G', LIGHTGREY, "eye of draining",
M_NO_SKELETON | M_LEVITATE | M_SEE_INVIS,
MR_RES_ASPHYX,
400, 10, MONS_GIANT_EYEBALL, MONS_EYE_OF_DRAINING, MH_NATURAL, MAG_IMMUNE,
- { {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 7, 3, 5, 0 },
- 3, 1, 5, 7, MST_NO_SPELLS, CE_MUTAGEN_RANDOM, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_MEDIUM
-}
-,
+ 3, 1, MST_NO_SPELLS, CE_MUTAGEN_RANDOM, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 5, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_MEDIUM
+},
{
MONS_BUTTERFLY, 'b', BLACK, "butterfly",
M_FLIES | M_CONFUSED,
MR_VUL_POISON | MR_RES_ASPHYX,
150, 10, MONS_BUTTERFLY, MONS_BUTTERFLY, MH_NATURAL, -3,
- { {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 1, 3, 5, 0 },
- 0, 25, 25, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 0, 25, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_INSECT,
+ 25, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_WANDERING_MUSHROOM, 'f', BROWN, "wandering mushroom",
M_NO_FLAGS,
MR_RES_POISON,
0, 10, MONS_PLANT, MONS_WANDERING_MUSHROOM, MH_PLANT, -3,
- { {AT_SPORE, AF_CONFUSE, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_SPORE, AF_CONFUSE, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 8, 3, 5, 0 },
- 5, 0, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 5, 0, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_EFREET, 'E', RED, "efreet",
M_SPELLCASTER | M_LEVITATE | M_EVIL,
MR_RES_POISON | MR_RES_FIRE | MR_VUL_COLD,
0, 12, MONS_EFREET, MONS_EFREET, MH_DEMONIC, -3,
- { {AT_HIT, AF_PLAIN, 12}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 12}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 7, 3, 5, 0 },
- 10, 5, 10, 7, MST_EFREET, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_LARGE
-}
-,
+ 10, 5, MST_EFREET, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_LARGE
+},
{
MONS_BRAIN_WORM, 'w', LIGHTMAGENTA, "brain worm",
M_SPELLCASTER,
MR_NO_FLAGS,
150, 10, MONS_WORM, MONS_BRAIN_WORM, MH_NATURAL, -3,
- { {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 5, 3, 3, 0 },
- 1, 5, 10, 7, MST_BRAIN_WORM, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_SMALL
-}
-,
+ 1, 5, MST_BRAIN_WORM, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_SMALL
+},
{
MONS_GIANT_ORANGE_BRAIN, 'G', LIGHTRED, "giant orange brain",
M_NO_SKELETON | M_SPELLCASTER | M_LEVITATE | M_SEE_INVIS,
MR_RES_ASPHYX,
1000, 13, MONS_GIANT_ORANGE_BRAIN, MONS_GIANT_ORANGE_BRAIN, MH_NATURAL, -8,
- { {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 10, 3, 5, 0 },
- 2, 4, 10, 7, MST_GIANT_ORANGE_BRAIN, CE_MUTAGEN_RANDOM, Z_NOZOMBIE, S_SILENT, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_SMALL
-}
-,
+ 2, 4, MST_GIANT_ORANGE_BRAIN, CE_MUTAGEN_RANDOM, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_SMALL
+},
{
MONS_BOULDER_BEETLE, 'B', LIGHTGREY, "boulder beetle",
M_NO_FLAGS,
MR_VUL_POISON,
2500, 10, MONS_GIANT_BEETLE, MONS_BOULDER_BEETLE, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 35}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 35}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 9, 3, 5, 0 },
- 20, 2, 3, 7, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_LARGE
-}
-,
+ 20, 2, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_SILENT, I_INSECT,
+ 3, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LARGE
+},
{
MONS_FLYING_SKULL, 'z', WHITE, "flying skull",
M_LEVITATE,
MR_RES_POISON | MR_RES_FIRE | MR_RES_COLD | MR_RES_ELEC,
0, 10, MONS_SKELETON_SMALL, MONS_FLYING_SKULL, MH_UNDEAD, -3,
- { {AT_HIT, AF_PLAIN, 7}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 7}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 2, 3, 5, 0 },
- 10, 17, 15, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SCREAM, I_ANIMAL,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 10, 17, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SCREAM, I_ANIMAL,
+ 15, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_HELL_HOUND, 'h', DARKGREY, "hell hound",
M_SENSE_INVIS | M_EVIL | M_SPECIAL_ABILITY,
MR_RES_POISON | MR_RES_HELLFIRE | MR_VUL_COLD,
0, 10, MONS_HOUND, MONS_HELL_HOUND, MH_DEMONIC, -3,
- { {AT_BITE, AF_PLAIN, 13}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 13}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 5, 3, 5, 0 },
- 6, 13, 15, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_BARK, I_NORMAL,
- MONUSE_NOTHING, SIZE_MEDIUM
-}
-,
+ 6, 13, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_BARK, I_NORMAL,
+ 15, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_MEDIUM
+},
{
MONS_MINOTAUR, 'm', LIGHTRED, "minotaur",
M_FIGHTER | M_WARM_BLOOD,
MR_NO_FLAGS,
1500, 10, MONS_MINOTAUR, MONS_MINOTAUR, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 35}, {AT_BUTT, AF_PLAIN, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 35}, {AT_BUTT, AF_PLAIN, 20}, AT_NO_ATK, AT_NO_ATK },
{ 13, 3, 5, 0 },
- 5, 7, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_BELLOW, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 5, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_BELLOW, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_ICE_DRAGON, 'D', WHITE, "ice dragon",
M_FLIES | M_SPECIAL_ABILITY,
MR_RES_POISON | MR_VUL_FIRE | MR_RES_COLD,
2200, 10, MONS_DRAGON, MONS_ICE_DRAGON, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 17}, {AT_CLAW, AF_PLAIN, 17}, {AT_CLAW, AF_PLAIN, 17}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 17}, {AT_CLAW, AF_PLAIN, 17}, {AT_CLAW, AF_PLAIN, 17}, AT_NO_ATK },
{ 12, 5, 5, 0 },
- 10, 8, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SILENT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_HUGE
-}
-,
+ 10, 8, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SILENT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_HUGE
+},
{
MONS_SLIME_CREATURE, 'J', GREEN, "slime creature",
M_AMPHIBIOUS,
MR_RES_POISON,
0, 5, MONS_SLIME_CREATURE, MONS_SLIME_CREATURE, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 22}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 22}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 11, 3, 5, 0 },
- 1, 4, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_SMALL
-}
-,
+ 1, 4, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_SMALL
+},
{
MONS_FREEZING_WRAITH, 'W', LIGHTBLUE, "freezing wraith",
M_LEVITATE | M_SEE_INVIS | M_EVIL,
MR_RES_POISON | MR_VUL_FIRE | MR_RES_COLD,
0, 10, MONS_WRAITH, MONS_FREEZING_WRAITH, MH_UNDEAD, -4,
- { {AT_HIT, AF_COLD, 19}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_COLD, 19}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 8, 3, 5, 0 },
- 12, 10, 8, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 12, 10, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ 8, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
// fake R - conjured by the R's illusion spell.
{
@@ -1070,120 +1000,110 @@
M_EVIL,
MR_RES_POISON,
0, 10, MONS_RAKSHASA_FAKE, MONS_RAKSHASA_FAKE, MH_NATURAL, MAG_IMMUNE,
- { {AT_HIT, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 0}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 1, 0, 0, 1 },
- 0, 30, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_ROAR, I_PLANT,
- MONUSE_NOTHING, SIZE_MEDIUM
-}
-,
+ 0, 30, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_ROAR, I_PLANT,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_MEDIUM
+},
{
MONS_GREAT_ORB_OF_EYES, 'G', LIGHTGREEN, "great orb of eyes",
M_NO_SKELETON | M_SPELLCASTER | M_LEVITATE | M_SEE_INVIS,
MR_RES_POISON,
900, 13, MONS_GIANT_EYEBALL, MONS_GREAT_ORB_OF_EYES, MH_NATURAL, MAG_IMMUNE,
- { {AT_BITE, AF_PLAIN, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 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, SIZE_LARGE
-}
-,
+ 10, 3, MST_GREAT_ORB_OF_EYES, CE_MUTAGEN_RANDOM, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_HELLION, '3', EC_FIRE, "hellion",
M_SPELLCASTER | M_EVIL,
MR_RES_POISON | MR_RES_HELLFIRE | MR_VUL_COLD,
0, 11, MONS_HELLION, MONS_HELLION, MH_DEMONIC, -7,
- { {AT_HIT, AF_PLAIN, 10}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 7, 3, 5, 0 },
- 5, 10, 13, 7, MST_BURNING_DEVIL, CE_NOCORPSE, Z_NOZOMBIE, S_SCREAM, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 5, 10, MST_BURNING_DEVIL, CE_NOCORPSE, Z_NOZOMBIE, S_SCREAM, I_HIGH,
+ 13, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
{
MONS_ROTTING_DEVIL, '4', GREEN, "rotting devil",
M_EVIL,
MR_RES_POISON | MR_RES_COLD,
0, 10, MONS_ROTTING_DEVIL, MONS_ROTTING_DEVIL, MH_DEMONIC, -7,
- { {AT_HIT, AF_ROT, 8}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_ROT, 8}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 5, 3, 5, 0 },
- 2, 10, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 2, 10, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
{
MONS_TORMENTOR, '3', YELLOW, "tormentor",
M_SPELLCASTER | M_FLIES | M_SPEAKS | M_EVIL,
MR_RES_POISON | MR_RES_FIRE,
0, 10, MONS_TORMENTOR, MONS_TORMENTOR, MH_DEMONIC, -6,
- { {AT_HIT, AF_PLAIN, 8}, {AT_HIT, AF_PLAIN, 8}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 8}, {AT_HIT, AF_PLAIN, 8}, AT_NO_ATK, AT_NO_ATK },
{ 7, 3, 5, 0 },
- 12, 12, 13, 7, MST_TORMENTOR, CE_NOCORPSE, Z_NOZOMBIE, S_ROAR, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 12, 12, MST_TORMENTOR, CE_NOCORPSE, Z_NOZOMBIE, S_ROAR, I_HIGH,
+ 13, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
{
MONS_REAPER, '2', LIGHTGREY, "reaper",
M_FIGHTER | M_SEE_INVIS | M_EVIL,
MR_RES_POISON | MR_RES_COLD,
0, 10, MONS_REAPER, MONS_REAPER, MH_DEMONIC, MAG_IMMUNE,
- { {AT_HIT, AF_PLAIN, 32}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 32}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 8, 3, 5, 0 },
- 15, 10, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
- MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
-}
-,
+ 15, 10, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
+},
{
MONS_SOUL_EATER, '2', DARKGREY, "soul eater",
M_LEVITATE | M_SEE_INVIS | M_EVIL,
MR_RES_POISON | MR_RES_COLD,
0, 12, MONS_SOUL_EATER, MONS_SOUL_EATER, MH_DEMONIC, -10,
- { {AT_HIT, AF_DRAIN_XP, 25}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_DRAIN_XP, 25}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 11, 3, 5, 0 },
- 18, 10, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 18, 10, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
{
MONS_HAIRY_DEVIL, '4', LIGHTRED, "hairy devil",
M_EVIL,
MR_RES_POISON,
0, 10, MONS_HAIRY_DEVIL, MONS_HAIRY_DEVIL, MH_DEMONIC, -4,
- { {AT_HIT, AF_PLAIN, 9}, {AT_HIT, AF_PLAIN, 9}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 9}, {AT_HIT, AF_PLAIN, 9}, AT_NO_ATK, AT_NO_ATK },
{ 6, 3, 5, 0 },
- 7, 10, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SHOUT, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_SMALL
-}
-,
+ 7, 10, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_SMALL
+},
{
MONS_ICE_DEVIL, '2', WHITE, "ice devil",
M_EVIL,
MR_RES_POISON | MR_VUL_FIRE | MR_RES_COLD,
0, 11, MONS_ICE_DEVIL, MONS_ICE_DEVIL, MH_DEMONIC, -6,
- { {AT_HIT, AF_COLD, 16}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_COLD, 16}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 11, 3, 5, 0 },
- 12, 10, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 12, 10, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
{
MONS_BLUE_DEVIL, '3', BLUE, "blue devil",
M_FLIES | M_EVIL,
MR_RES_POISON | MR_VUL_FIRE | MR_RES_COLD,
0, 10, MONS_BLUE_DEVIL, MONS_BLUE_DEVIL, MH_DEMONIC, -5,
- { {AT_HIT, AF_PLAIN, 21}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 21}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 7, 3, 5, 0 },
- 14, 10, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 14, 10, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
// random
{
@@ -1191,132 +1111,121 @@
M_EVIL,
MR_NO_FLAGS,
0, 10, MONS_BEAST, MONS_BEAST, MH_DEMONIC, -3,
- { {AT_CLAW, AF_PLAIN, 12}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_CLAW, AF_PLAIN, 12}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 5, 3, 5, 0 },
- 0, 0, 0, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_RANDOM, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 0, 0, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_RANDOM, I_NORMAL,
+ 0, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_IRON_DEVIL, '3', CYAN, "iron devil",
M_EVIL,
MR_RES_ELEC | MR_RES_POISON | MR_RES_HELLFIRE | MR_RES_COLD,
0, 10, MONS_IRON_DEVIL, MONS_IRON_DEVIL, MH_DEMONIC, -6,
- { {AT_HIT, AF_PLAIN, 14}, {AT_HIT, AF_PLAIN, 14}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 14}, {AT_HIT, AF_PLAIN, 14}, AT_NO_ATK, AT_NO_ATK },
{ 8, 3, 5, 0 },
- 16, 8, 8, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SCREECH, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 16, 8, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SCREECH, I_HIGH,
+ 8, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
{
MONS_GLOWING_SHAPESHIFTER, '@', RED, "glowing shapeshifter",
M_NO_FLAGS,
MR_NO_FLAGS,
600, 10, MONS_SHAPESHIFTER, MONS_GLOWING_SHAPESHIFTER, MH_NATURAL, -6,
- { {AT_HIT, AF_PLAIN, 15}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 15}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 10, 3, 5, 0 },
- 0, 10, 10, 7, MST_NO_SPELLS, CE_MUTAGEN_RANDOM, Z_NOZOMBIE, S_SILENT, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 0, 10, MST_NO_SPELLS, CE_MUTAGEN_RANDOM, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
{
MONS_SHAPESHIFTER, '@', LIGHTRED, "shapeshifter",
M_NO_FLAGS,
MR_NO_FLAGS,
600, 10, MONS_SHAPESHIFTER, MONS_SHAPESHIFTER, MH_NATURAL, -6,
- { {AT_HIT, AF_PLAIN, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 5}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 7, 3, 5, 0 },
- 0, 10, 10, 7, MST_NO_SPELLS, CE_MUTAGEN_RANDOM, Z_NOZOMBIE, S_SILENT, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 0, 10, MST_NO_SPELLS, CE_MUTAGEN_RANDOM, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
{
MONS_GIANT_MITE, 's', LIGHTRED, "giant mite",
M_NO_FLAGS,
MR_VUL_POISON,
350, 10, MONS_GIANT_MITE, MONS_GIANT_MITE, MH_NATURAL, -1,
- { {AT_BITE, AF_POISON, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_POISON, 5}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 2, 3, 5, 0 },
- 1, 7, 10, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 1, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_STEAM_DRAGON, 'D', LIGHTGREY, "steam dragon",
M_SPELLCASTER | M_FLIES,
MR_NO_FLAGS,
1000, 10, MONS_DRAGON, MONS_STEAM_DRAGON, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 12}, {AT_CLAW, AF_PLAIN, 6}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 12}, {AT_CLAW, AF_PLAIN, 6}, AT_NO_ATK, AT_NO_ATK },
{ 4, 5, 5, 0 },
- 5, 10, 10, 7, MST_STEAM_DRAGON, CE_CLEAN, Z_BIG, S_SILENT, I_ANIMAL,
- MONUSE_OPEN_DOORS, SIZE_GIANT,
-}
-,
+ 5, 10, MST_STEAM_DRAGON, CE_CLEAN, Z_BIG, S_SILENT, I_ANIMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_GIANT,
+},
{
MONS_VERY_UGLY_THING, 'u', RED, "very ugly thing",
M_WARM_BLOOD | M_AMPHIBIOUS,
MR_NO_FLAGS,
750, 10, MONS_UGLY_THING, MONS_VERY_UGLY_THING, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 17}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 17}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 12, 3, 5, 0 },
- 4, 8, 8, 7, MST_NO_SPELLS, CE_MUTAGEN_RANDOM, Z_BIG, S_SHOUT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 4, 8, MST_NO_SPELLS, CE_MUTAGEN_RANDOM, Z_BIG, S_SHOUT, I_NORMAL,
+ 8, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_ORC_SORCERER, 'o', DARKGREY, "orc sorcerer",
M_SPELLCASTER | M_SEE_INVIS | M_SPEAKS | M_ACTUAL_SPELLS | M_WARM_BLOOD | M_EVIL,
MR_RES_FIRE,
600, 12, MONS_ORC, MONS_ORC, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 7}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 7}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 9, 2, 3, 0 },
- 5, 12, 10, 7, MST_ORC_SORCERER, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 5, 12, MST_ORC_SORCERER, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_HIPPOGRIFF, 'H', BROWN, "hippogriff",
M_FLIES | M_WARM_BLOOD,
MR_NO_FLAGS,
1000, 10, MONS_HIPPOGRIFF, MONS_HIPPOGRIFF, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 10}, {AT_CLAW, AF_PLAIN, 8}, {AT_CLAW, AF_PLAIN, 8}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 10}, {AT_CLAW, AF_PLAIN, 8}, {AT_CLAW, AF_PLAIN, 8}, AT_NO_ATK },
{ 7, 3, 5, 0 },
- 2, 7, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SCREECH, I_ANIMAL,
- MONUSE_OPEN_DOORS, SIZE_BIG
-}
-,
+ 2, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SCREECH, I_ANIMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_BIG
+},
{
MONS_GRIFFON, 'H', YELLOW, "griffon",
M_FLIES | M_WARM_BLOOD,
MR_NO_FLAGS,
1800, 10, MONS_GRIFFON, MONS_GRIFFON, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 18}, {AT_CLAW, AF_PLAIN, 10}, {AT_CLAW, AF_PLAIN, 10}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 18}, {AT_CLAW, AF_PLAIN, 10}, {AT_CLAW, AF_PLAIN, 10}, AT_NO_ATK },
{ 12, 3, 5, 0 },
- 4, 6, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SCREECH, I_ANIMAL,
- MONUSE_OPEN_DOORS, SIZE_BIG
-}
-,
+ 4, 6, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SCREECH, I_ANIMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_BIG
+},
{
MONS_HYDRA, 'D', LIGHTGREEN, "hydra",
M_AMPHIBIOUS, // because it likes the swamp -- bwr
MR_RES_POISON,
1800, 11, MONS_HYDRA, MONS_HYDRA, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 18}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 18}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 13, 3, 5, 0 },
- 0, 5, 10, 7, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_ROAR, I_INSECT,
- MONUSE_OPEN_DOORS, SIZE_BIG
-}
-,
+ 0, 5, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_ROAR, I_INSECT,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_BIG
+},
// small skeleton
{
@@ -1324,12 +1233,11 @@
M_EVIL,
MR_RES_POISON | MR_RES_COLD,
0, 10, MONS_SKELETON_SMALL, MONS_SKELETON_SMALL, MH_UNDEAD, -1,
- { {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 0, 0, 0, 0 },
- 0, 0, 0, 0, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_SMALL
-}
-,
+ 0, 0, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 0, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_SMALL
+},
// large skeleton
{
@@ -1337,73 +1245,66 @@
M_EVIL,
MR_RES_POISON | MR_RES_COLD,
0, 10, MONS_SKELETON_SMALL, MONS_SKELETON_LARGE, MH_UNDEAD, -1,
- { {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 0, 0, 0, 0 },
- 0, 0, 0, 0, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_LARGE
-}
-,
-
+ 0, 0, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 0, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LARGE
+},
{
MONS_HELL_KNIGHT, '@', RED, "hell knight",
M_FIGHTER | M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD | M_EVIL,
MR_RES_FIRE,
550, 10, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 13}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 13}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 10, 3, 6, 0 },
- 0, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_NECROMANCER, '@', DARKGREY, "necromancer",
M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD | M_EVIL,
MR_NO_FLAGS,
550, 10, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -4,
- { {AT_HIT, AF_PLAIN, 6}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 6}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 10, 2, 4, 0 },
- 0, 13, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 13, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_WIZARD, '@', MAGENTA, "wizard",
M_SPELLCASTER | M_SPEAKS | M_ACTUAL_SPELLS | M_WARM_BLOOD,
MR_RES_ELEC,
550, 10, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -4,
- { {AT_HIT, AF_PLAIN, 6}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 6}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 10, 2, 4, 0 },
- 0, 13, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 13, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_ORC_PRIEST, 'o', LIGHTGREEN, "orc priest",
M_SPELLCASTER | M_PRIEST | M_WARM_BLOOD | M_EVIL,
MR_NO_FLAGS,
600, 10, MONS_ORC, MONS_ORC, MH_NATURAL, -4,
- { {AT_HIT, AF_PLAIN, 6}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 6}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 3, 3, 4, 0 },
- 1, 10, 10, 7, MST_ORC_PRIEST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 1, 10, MST_ORC_PRIEST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_ORC_HIGH_PRIEST, 'o', GREEN, "orc high priest",
M_SPELLCASTER | M_SEE_INVIS | M_SPEAKS | M_PRIEST | M_WARM_BLOOD | M_EVIL,
MR_RES_HELLFIRE,
600, 10, MONS_ORC, MONS_ORC, MH_NATURAL, -4,
- { {AT_HIT, AF_PLAIN, 7}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 7}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 11, 3, 4, 0 },
- 1, 12, 10, 7, MST_ORC_HIGH_PRIEST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 1, 12, MST_ORC_HIGH_PRIEST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
// this is a dummy monster, used for corpses
// mv:but it can be generated by polymorph spells and because IMO it's
@@ -1415,144 +1316,132 @@
M_WARM_BLOOD,
MR_NO_FLAGS,
550, 10, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 10}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 1, 3, 5, 0 },
- 0, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_GNOLL, 'g', YELLOW, "gnoll",
M_WARM_BLOOD,
MR_NO_FLAGS,
750, 10, MONS_GNOLL, MONS_GNOLL, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 9}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 9}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 2, 4, 5, 0 },
- 2, 9, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 2, 9, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_CLAY_GOLEM, '8', BROWN, "clay golem",
M_SEE_INVIS,
MR_RES_POISON | MR_RES_FIRE | MR_RES_COLD | MR_RES_ELEC,
0, 10, MONS_CLAY_GOLEM, MONS_CLAY_GOLEM, MH_NONLIVING, MAG_IMMUNE,
- { {AT_HIT, AF_PLAIN, 11}, {AT_HIT, AF_PLAIN, 11}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 11}, {AT_HIT, AF_PLAIN, 11}, AT_NO_ATK, AT_NO_ATK },
{ 8, 7, 3, 0 },
- 7, 5, 8, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 7, 5, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 8, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_WOOD_GOLEM, '8', YELLOW, "wood golem",
M_NO_FLAGS,
MR_RES_POISON | MR_VUL_FIRE | MR_RES_COLD | MR_RES_ELEC,
0, 10, MONS_CLAY_GOLEM, MONS_WOOD_GOLEM, MH_NONLIVING, MAG_IMMUNE,
- { {AT_HIT, AF_PLAIN, 10}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 6, 3, 0 },
- 5, 6, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 5, 6, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_STONE_GOLEM, '8', LIGHTGREY, "stone golem",
M_NO_FLAGS,
MR_RES_POISON | MR_RES_FIRE | MR_RES_COLD | MR_RES_ELEC,
0, 10, MONS_CLAY_GOLEM, MONS_STONE_GOLEM, MH_NONLIVING, MAG_IMMUNE,
- { {AT_HIT, AF_PLAIN, 28}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 28}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 12, 7, 4, 0 },
- 12, 4, 7, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 12, 4, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 7, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_IRON_GOLEM, '8', CYAN, "iron golem",
M_SEE_INVIS,
MR_RES_POISON | MR_RES_FIRE | MR_RES_COLD | MR_RES_ELEC,
0, 10, MONS_CLAY_GOLEM, MONS_IRON_GOLEM, MH_NONLIVING, MAG_IMMUNE,
- { {AT_HIT, AF_PLAIN, 35}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 35}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 15, 7, 4, 0 },
- 15, 3, 7, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 15, 3, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 7, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_CRYSTAL_GOLEM, '8', WHITE, "crystal golem",
M_SEE_INVIS | M_SPEAKS,
MR_RES_POISON | MR_RES_FIRE | MR_RES_COLD | MR_RES_ELEC,
0, 10, MONS_CLAY_GOLEM, MONS_CRYSTAL_GOLEM, MH_NONLIVING, MAG_IMMUNE,
- { {AT_HIT, AF_PLAIN, 40}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 40}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 13, 7, 4, 0 },
- 22, 3, 7, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 22, 3, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 7, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_TOENAIL_GOLEM, '8', LIGHTGREY, "toenail golem",
M_NO_FLAGS,
MR_RES_POISON | MR_RES_FIRE | MR_RES_COLD | MR_RES_ELEC,
0, 10, MONS_CLAY_GOLEM, MONS_TOENAIL_GOLEM, MH_NONLIVING, MAG_IMMUNE,
- { {AT_HIT, AF_PLAIN, 13}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 13}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 9, 5, 3, 0 },
- 8, 5, 8, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 8, 5, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 8, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_MOTTLED_DRAGON, 'D', MAGENTA, "mottled dragon",
M_SPELLCASTER | M_FLIES,
MR_RES_POISON | MR_RES_FIRE,
1100, 10, MONS_DRAGON, MONS_MOTTLED_DRAGON, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 15}, {AT_CLAW, AF_PLAIN, 6}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 15}, {AT_CLAW, AF_PLAIN, 6}, AT_NO_ATK, AT_NO_ATK },
{ 5, 3, 5, 0 },
- 5, 10, 10, 7, MST_MOTTLED_DRAGON, CE_POISONOUS, Z_BIG, S_SILENT, I_ANIMAL,
- MONUSE_OPEN_DOORS, SIZE_GIANT,
-}
-,
+ 5, 10, MST_MOTTLED_DRAGON, CE_POISONOUS, Z_BIG, S_SILENT, I_ANIMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_GIANT,
+},
{
MONS_EARTH_ELEMENTAL, '#', BROWN, "earth elemental",
M_NO_FLAGS,
MR_RES_POISON | MR_RES_FIRE | MR_RES_COLD | MR_RES_ELEC,
0, 10, MONS_EARTH_ELEMENTAL, MONS_EARTH_ELEMENTAL, MH_NONLIVING, MAG_IMMUNE,
- { {AT_HIT, AF_PLAIN, 40}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 40}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 5, 5, 0 },
- 14, 4, 6, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_OPEN_DOORS, SIZE_BIG
-}
-,
+ 14, 4, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 6, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_BIG
+},
{
MONS_FIRE_ELEMENTAL, '#', YELLOW, "fire elemental",
M_FLIES,
MR_RES_POISON | MR_RES_HELLFIRE | MR_VUL_COLD | MR_RES_ELEC,
0, 10, MONS_EARTH_ELEMENTAL, MONS_FIRE_ELEMENTAL, MH_NONLIVING, MAG_IMMUNE,
- { {AT_HIT, AF_FIRE, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_FIRE, 5}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 3, 5, 0 },
- 4, 12, 13, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_OPEN_DOORS, SIZE_BIG
-}
-,
+ 4, 12, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 13, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_BIG
+},
{
MONS_AIR_ELEMENTAL, 'v', LIGHTGREY, "air elemental",
M_LEVITATE | M_SEE_INVIS | M_FLIES,
MR_RES_ELEC | MR_RES_POISON,
0, 5, MONS_EARTH_ELEMENTAL, MONS_AIR_ELEMENTAL, MH_NONLIVING, MAG_IMMUNE,
- { {AT_HIT, AF_PLAIN, 15}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 15}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 3, 5, 0 },
- 2, 18, 25, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_OPEN_DOORS, SIZE_BIG
-}
-,
+ 2, 18, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 25, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_BIG
+},
// water elementals are later (with the other water monsters)
@@ -1561,216 +1450,198 @@
M_SPELLCASTER | M_FLIES | M_SEE_INVIS | M_EVIL,
MR_RES_POISON | MR_VUL_FIRE | MR_RES_COLD,
0, 10, MONS_FIEND, MONS_ICE_FIEND, MH_DEMONIC, -12,
- { {AT_CLAW, AF_COLD, 25}, {AT_CLAW, AF_COLD, 25}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_CLAW, AF_COLD, 25}, {AT_CLAW, AF_COLD, 25}, AT_NO_ATK, AT_NO_ATK },
{ 18, 3, 5, 0 },
- 15, 6, 10, 7, MST_ICE_FIEND, CE_CONTAMINATED, Z_NOZOMBIE, S_ROAR, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 15, 6, MST_ICE_FIEND, CE_CONTAMINATED, Z_NOZOMBIE, S_ROAR, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_SHADOW_FIEND, '1', DARKGREY, "Shadow Fiend",
M_SPELLCASTER | M_LEVITATE | M_SEE_INVIS | M_EVIL,
MR_RES_POISON | MR_RES_COLD | MR_RES_ELEC,
0, 10, MONS_FIEND, MONS_SHADOW_FIEND, MH_DEMONIC, -13,
- { {AT_HIT, AF_DRAIN_XP, 25}, {AT_HIT, AF_DRAIN_XP, 15}, {AT_HIT, AF_DRAIN_XP, 15}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_DRAIN_XP, 25}, {AT_HIT, AF_DRAIN_XP, 15}, {AT_HIT, AF_DRAIN_XP, 15}, AT_NO_ATK },
{ 18, 3, 5, 0 },
- 15, 6, 10, 7, MST_SHADOW_FIEND, CE_CONTAMINATED, Z_NOZOMBIE, S_ROAR, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 15, 6, MST_SHADOW_FIEND, CE_CONTAMINATED, Z_NOZOMBIE, S_ROAR, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_BROWN_SNAKE, 'S', BROWN, "brown snake",
M_COLD_BLOOD | M_AMPHIBIOUS,
MR_RES_POISON,
300, 10, MONS_SNAKE, MONS_BROWN_SNAKE, MH_NATURAL, -3,
- { {AT_BITE, AF_POISON_MEDIUM, 10}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_POISON_MEDIUM, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 4, 3, 5, 0 },
- 2, 15, 14, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_HISS, I_INSECT,
- MONUSE_NOTHING, SIZE_MEDIUM
-}
-,
+ 2, 15, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_HISS, I_INSECT,
+ 14, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_MEDIUM
+},
{
MONS_GIANT_LIZARD, 'l', GREEN, "giant lizard",
M_COLD_BLOOD,
MR_NO_FLAGS,
600, 10, MONS_GIANT_LIZARD, MONS_GIANT_LIZARD, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 5, 3, 5, 0 },
- 4, 10, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_LITTLE,
-}
-,
+ 4, 10, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_INSECT,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LITTLE,
+},
{
MONS_SPECTRAL_WARRIOR, 'W', LIGHTGREEN, "spectral warrior",
M_LEVITATE | M_SEE_INVIS | M_EVIL,
MR_RES_POISON | MR_RES_COLD,
0, 13, MONS_WRAITH, MONS_SPECTRAL_WARRIOR, MH_UNDEAD, -6,
- { {AT_HIT, AF_DRAIN_XP, 18}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_DRAIN_XP, 18}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 9, 3, 5, 0 },
- 12, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 12, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
{
MONS_PULSATING_LUMP, 'J', RED, "pulsating lump",
M_SENSE_INVIS,
MR_RES_POISON | MR_RES_ASPHYX,
0, 3, MONS_JELLY, MONS_PULSATING_LUMP, MH_NATURAL, -3,
- { {AT_HIT, AF_MUTATE, 13}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_MUTATE, 13}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 10, 3, 5, 0 },
- 2, 6, 5, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_LITTLE,
-}
-,
+ 2, 6, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 5, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LITTLE,
+},
{
MONS_STORM_DRAGON, 'D', LIGHTBLUE, "storm dragon",
M_SPELLCASTER | M_FLIES,
MR_RES_ELEC | MR_RES_COLD,
2800, 12, MONS_DRAGON, MONS_STORM_DRAGON, MH_NATURAL, -5,
- { {AT_BITE, AF_PLAIN, 25}, {AT_CLAW, AF_PLAIN, 15}, {AT_CLAW, AF_PLAIN, 15}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 25}, {AT_CLAW, AF_PLAIN, 15}, {AT_CLAW, AF_PLAIN, 15}, AT_NO_ATK },
{ 14, 5, 5, 0 },
- 13, 10, 12, 7, MST_STORM_DRAGON, CE_CLEAN, Z_BIG, S_ROAR, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_HUGE
-}
-,
+ 13, 10, MST_STORM_DRAGON, CE_CLEAN, Z_BIG, S_ROAR, I_NORMAL,
+ 12, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_HUGE
+},
{
MONS_YAKTAUR, 'c', LIGHTRED, "yaktaur",
M_WARM_BLOOD,
MR_NO_FLAGS,
2000, 10, MONS_YAKTAUR, MONS_YAKTAUR, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 15}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 15}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 8, 3, 5, 0 },
- 4, 4, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_BIG
-}
-,
+ 4, 4, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_BIG
+},
{
MONS_DEATH_YAK, 'Y', DARKGREY, "death yak",
M_WARM_BLOOD | M_EVIL,
MR_NO_FLAGS,
1500, 10, MONS_YAK, MONS_DEATH_YAK, MH_NATURAL, -5,
- { {AT_BUTT, AF_PLAIN, 30}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BUTT, AF_PLAIN, 30}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 14, 3, 5, 0 },
- 9, 5, 10, 7, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_BELLOW, I_ANIMAL,
- MONUSE_NOTHING, SIZE_BIG
-}
-,
+ 9, 5, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_BELLOW, I_ANIMAL,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_BIG
+},
{
MONS_ROCK_TROLL, 'T', LIGHTGREY, "rock troll",
M_WARM_BLOOD | M_EVIL,
MR_NO_FLAGS,
2200, 11, MONS_TROLL, MONS_ROCK_TROLL, MH_NATURAL, -4,
- { {AT_BITE, AF_PLAIN, 30}, {AT_CLAW, AF_PLAIN, 20}, {AT_CLAW, AF_PLAIN, 20}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 30}, {AT_CLAW, AF_PLAIN, 20}, {AT_CLAW, AF_PLAIN, 20}, AT_NO_ATK },
{ 11, 3, 5, 0 },
- 13, 6, 8, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 13, 6, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_NORMAL,
+ 8, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_STONE_GIANT, 'C', LIGHTGREY, "stone giant",
M_WARM_BLOOD | M_EVIL,
MR_NO_FLAGS,
3000, 10, MONS_HILL_GIANT, MONS_STONE_GIANT, MH_NATURAL, -4,
- { {AT_HIT, AF_PLAIN, 45}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 45}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 16, 3, 5, 0 },
- 12, 2, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_NORMAL,
- MONUSE_STARTING_EQUIPMENT, SIZE_GIANT,
-}
-,
+ 12, 2, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_GIANT,
+},
{
MONS_FLAYED_GHOST, 'p', RED, "flayed ghost",
M_FLIES | M_EVIL,
MR_RES_POISON,
0, 10, MONS_PHANTOM, MONS_FLAYED_GHOST, MH_UNDEAD, -4,
- { {AT_HIT, AF_PLAIN, 30}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 30}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 11, 3, 5, 0 },
- 0, 14, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 0, 14, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
{
MONS_BUMBLEBEE, 'k', RED, "bumblebee",
M_FLIES,
MR_VUL_POISON,
300, 10, MONS_KILLER_BEE, MONS_BUMBLEBEE, MH_NATURAL, -3,
- { {AT_STING, AF_POISON_MEDIUM, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_STING, AF_POISON_MEDIUM, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 7, 3, 5, 0 },
- 4, 15, 10, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_BUZZ, I_INSECT,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 4, 15, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_BUZZ, I_INSECT,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_REDBACK, 's', RED, "redback",
M_NO_FLAGS,
MR_VUL_POISON,
1000, 14, MONS_WOLF_SPIDER, MONS_REDBACK, MH_NATURAL, -3,
- { {AT_BITE, AF_POISON_STRONG, 18}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_POISON_STRONG, 18}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 3, 5, 0 },
- 2, 12, 15, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 2, 12, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
+ 15, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_INSUBSTANTIAL_WISP, 'p', LIGHTGREY, "insubstantial wisp",
M_LEVITATE | M_SPECIAL_ABILITY,
MR_RES_ELEC | MR_RES_POISON | MR_RES_FIRE | MR_RES_COLD,
0, 17, MONS_INSUBSTANTIAL_WISP, MONS_INSUBSTANTIAL_WISP, MH_NONLIVING, MAG_IMMUNE,
- { {AT_HIT, AF_BLINK, 12}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_BLINK, 12}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 1, 2, 0 },
- 20, 20, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_MOAN, I_PLANT,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 20, 20, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_MOAN, I_PLANT,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_VAPOUR, '#', LIGHTGREY, "vapour",
M_SPELLCASTER | M_LEVITATE | M_SEE_INVIS | M_INVIS | M_CONFUSED,
MR_RES_ELEC | MR_RES_POISON,
0, 21, MONS_VAPOUR, MONS_VAPOUR, MH_NONLIVING, MAG_IMMUNE,
- { {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 12, 2, 3, 0 },
- 0, 12, 10, 7, MST_STORM_DRAGON, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_LITTLE,
-}
-,
+ 0, 12, MST_STORM_DRAGON, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LITTLE,
+},
{
MONS_OGRE_MAGE, 'O', MAGENTA, "ogre-mage",
M_SPELLCASTER | M_ACTUAL_SPELLS | M_SEE_INVIS | M_WARM_BLOOD | M_EVIL,
MR_RES_ELEC,
0, 16, MONS_OGRE, MONS_OGRE, MH_NATURAL, -6,
- { {AT_HIT, AF_PLAIN, 12}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 12}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 10, 3, 5, 0 },
- 1, 7, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_LARGE
-}
-,
+ 1, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_LARGE
+},
{
MONS_SPINY_WORM, 'w', DARKGREY, "spiny worm",
M_NO_FLAGS,
MR_VUL_POISON | MR_RES_ACID,
1300, 13, MONS_WORM, MONS_SPINY_WORM, MH_NATURAL, -3,
- { {AT_STING, AF_ACID, 32}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_STING, AF_ACID, 32}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 12, 3, 5, 0 },
- 10, 6, 9, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_BIG
-}
-,
+ 10, 6, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_PLANT,
+ 9, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_BIG
+},
// these are named more explicitly when they attack, also when you use 'x'
// to examine them.
@@ -1779,36 +1650,33 @@
M_FIGHTER | M_LEVITATE,
MR_RES_POISON | MR_RES_HELLFIRE | MR_RES_COLD | MR_RES_ELEC,
0, 10, MONS_DANCING_WEAPON, MONS_DANCING_WEAPON, MH_NONLIVING, MAG_IMMUNE,
- { {AT_HIT, AF_PLAIN, 30}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 30}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 15, 0, 0, 15 },
- 10, 20, 15, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_SMALL
-}
-,
+ 10, 20, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 15, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_SMALL
+},
{
MONS_TITAN, 'C', MAGENTA, "titan",
M_FIGHTER | M_SPELLCASTER | M_WARM_BLOOD | M_SENSE_INVIS | M_EVIL,
MR_RES_ELEC,
3500, 12, MONS_HILL_GIANT, MONS_TITAN, MH_NATURAL, -7,
- { {AT_HIT, AF_PLAIN, 55}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 55}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 20, 3, 5, 0 },
- 10, 3, 10, 7, MST_TITAN, CE_CLEAN, Z_BIG, S_SHOUT, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_GIANT,
-}
-,
+ 10, 3, MST_TITAN, CE_CLEAN, Z_BIG, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_GIANT,
+},
{
MONS_GOLDEN_DRAGON, 'D', YELLOW, "golden dragon",
M_SPELLCASTER | M_FLIES | M_SENSE_INVIS,
MR_RES_ELEC | MR_RES_POISON | MR_RES_FIRE | MR_RES_COLD,
3000, 17, MONS_DRAGON, MONS_GOLDEN_DRAGON, MH_NATURAL, -8,
- { {AT_BITE, AF_PLAIN, 40}, {AT_CLAW, AF_PLAIN, 20}, {AT_CLAW, AF_PLAIN, 20}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 40}, {AT_CLAW, AF_PLAIN, 20}, {AT_CLAW, AF_PLAIN, 20}, AT_NO_ATK },
{ 18, 4, 4, 0 },
- 15, 7, 10, 7, MST_GOLDEN_DRAGON, CE_POISONOUS, Z_BIG, S_ROAR, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_HUGE
-}
-,
+ 15, 7, MST_GOLDEN_DRAGON, CE_POISONOUS, Z_BIG, S_ROAR, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_HUGE
+},
// 147 - dummy monster, used for corpses etc.
//mv: have to exist because it's (and should be) valid polymorph target.
@@ -1817,13 +1685,11 @@
M_WARM_BLOOD,
MR_NO_FLAGS,
450, 10, MONS_ELF, MONS_ELF, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 10}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 3, 3, 3, 0 },
- 0, 12, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SILENT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
-
+ 0, 12, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SILENT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
// Used to be "lindworm" and a GREEN 'l'... I'm hoping that by
// making it a 'd' and using an alternate spelling people will
@@ -1833,611 +1699,561 @@
M_SPECIAL_ABILITY,
MR_NO_FLAGS,
1000, 11, MONS_DRAGON, MONS_LINDWURM, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 20}, {AT_CLAW, AF_PLAIN, 10}, {AT_CLAW, AF_PLAIN, 10}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 20}, {AT_CLAW, AF_PLAIN, 10}, {AT_CLAW, AF_PLAIN, 10}, AT_NO_ATK },
{ 9, 3, 5, 0 },
- 8, 6, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_ROAR, I_INSECT,
- MONUSE_NOTHING, SIZE_GIANT,
-}
-,
+ 8, 6, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_ROAR, I_INSECT,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_GIANT,
+},
{
MONS_ELEPHANT_SLUG, 'm', LIGHTGREY, "elephant slug",
M_NO_SKELETON,
MR_VUL_POISON,
1500, 10, MONS_GIANT_SLUG, MONS_ELEPHANT_SLUG, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 40}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 40}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 20, 5, 3, 0 },
- 2, 1, 4, 10, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_BIG
-}
-,
+ 2, 1, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_SILENT, I_INSECT,
+ 4, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_BIG
+},
{
MONS_WAR_DOG, 'h', CYAN, "war dog",
M_SENSE_INVIS | M_WARM_BLOOD,
MR_NO_FLAGS,
350, 10, MONS_HOUND, MONS_WAR_DOG, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 12}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 12}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 4, 3, 5, 0 },
- 4, 15, 17, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_BARK, I_ANIMAL,
- MONUSE_NOTHING, SIZE_MEDIUM
-}
-,
+ 4, 15, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_BARK, I_ANIMAL,
+ 17, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_MEDIUM
+},
{
MONS_GREY_RAT, 'r', LIGHTGREY, "grey rat",
M_WARM_BLOOD,
MR_NO_FLAGS,
250, 10, MONS_RAT, MONS_GREY_RAT, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 5}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 1, 3, 6, 0 },
- 2, 12, 12, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SILENT, I_ANIMAL,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 2, 12, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SILENT, I_ANIMAL,
+ 12, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_GREEN_RAT, 'r', LIGHTGREEN, "green rat",
M_WARM_BLOOD,
MR_NO_FLAGS,
250, 10, MONS_RAT, MONS_GREEN_RAT, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 10}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 2, 3, 5, 0 },
- 5, 11, 10, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_ANIMAL,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 5, 11, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_ANIMAL,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_ORANGE_RAT, 'r', LIGHTRED, "orange rat",
M_WARM_BLOOD,
MR_NO_FLAGS,
250, 10, MONS_RAT, MONS_ORANGE_RAT, MH_NATURAL, -3,
- { {AT_BITE, AF_DRAIN_XP, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_DRAIN_XP, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 3, 3, 5, 0 },
- 7, 10, 12, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_ROAR, I_ANIMAL,
- MONUSE_NOTHING, SIZE_LITTLE,
-}
-,
+ 7, 10, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_ROAR, I_ANIMAL,
+ 12, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LITTLE,
+},
{
MONS_BLACK_SNAKE, 'S', DARKGREY, "black snake",
M_COLD_BLOOD,
MR_RES_POISON,
500, 12, MONS_SNAKE, MONS_BLACK_SNAKE, MH_NATURAL, -3,
- { {AT_BITE, AF_POISON_MEDIUM, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_POISON_MEDIUM, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 7, 3, 5, 0 },
- 4, 15, 18, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_HISS, I_INSECT,
- MONUSE_NOTHING, SIZE_MEDIUM
-}
-,
+ 4, 15, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_HISS, I_INSECT,
+ 18, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_MEDIUM
+},
{
MONS_SHEEP, 'Y', LIGHTGREY, "sheep",
M_WARM_BLOOD,
MR_NO_FLAGS,
1200, 10, MONS_SHEEP, MONS_SHEEP, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 13}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 13}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 3, 3, 5, 0 },
- 2, 7, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_BELLOW, I_ANIMAL,
- MONUSE_NOTHING, SIZE_SMALL
-}
-,
+ 2, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_BELLOW, I_ANIMAL,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_SMALL
+},
{
MONS_GHOUL, 'n', RED, "ghoul",
M_EVIL,
MR_RES_POISON | MR_RES_COLD,
500, 12, MONS_GHOUL, MONS_GHOUL, MH_UNDEAD, -5,
- { {AT_CLAW, AF_ROT, 9}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_CLAW, AF_ROT, 9}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 4, 3, 5, 0 },
- 4, 10, 10, 7, MST_NO_SPELLS, CE_HCL, Z_NOZOMBIE, S_SILENT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 4, 10, MST_NO_SPELLS, CE_HCL, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
{
MONS_HOG, 'h', LIGHTRED, "hog",
M_WARM_BLOOD,
MR_NO_FLAGS,
700, 10, MONS_HOG, MONS_HOG, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 14}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 14}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 3, 5, 0 },
- 2, 9, 13, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_ANIMAL,
- MONUSE_NOTHING, SIZE_SMALL
-}
-,
+ 2, 9, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_ANIMAL,
+ 13, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_SMALL
+},
{
MONS_GIANT_MOSQUITO, 'y', DARKGREY, "giant mosquito",
M_FLIES,
MR_VUL_POISON,
100, 10, MONS_GIANT_MOSQUITO, MONS_GIANT_MOSQUITO, MH_NATURAL, -3,
- { {AT_BITE, AF_DISEASE, 10}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_DISEASE, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 1, 3, 5, 0 },
- 0, 13, 12, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_WHINE, I_PLANT,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 0, 13, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_WHINE, I_PLANT,
+ 12, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_GIANT_CENTIPEDE, 's', GREEN, "giant centipede",
M_NO_FLAGS,
MR_VUL_POISON,
350, 10, MONS_GIANT_CENTIPEDE, MONS_GIANT_CENTIPEDE, MH_NATURAL, -3,
- { {AT_STING, AF_POISON_NASTY, 2}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_STING, AF_POISON_NASTY, 2}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 2, 3, 3, 0 },
- 2, 14, 13, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 2, 14, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
+ 13, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_IRON_TROLL, 'T', CYAN, "iron troll",
M_WARM_BLOOD | M_EVIL,
MR_RES_FIRE | MR_RES_COLD,
2400, 10, MONS_TROLL, MONS_IRON_TROLL, MH_NATURAL, -5,
- { {AT_BITE, AF_PLAIN, 35}, {AT_CLAW, AF_PLAIN, 25}, {AT_CLAW, AF_PLAIN, 25}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 35}, {AT_CLAW, AF_PLAIN, 25}, {AT_CLAW, AF_PLAIN, 25}, AT_NO_ATK },
{ 16, 3, 5, 0 },
- 20, 4, 7, 7, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_ROAR, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 20, 4, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_ROAR, I_NORMAL,
+ 7, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_NAGA, 'N', GREEN, "naga",
M_SPELLCASTER | M_SEE_INVIS | M_WARM_BLOOD,
MR_RES_POISON,
750, 10, MONS_NAGA, MONS_NAGA, MH_NATURAL, -6,
- { {AT_HIT, AF_PLAIN, 13}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 13}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 5, 3, 5, 0 },
- 6, 10, 8, 7, MST_NAGA, CE_POISONOUS, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_BIG
-}
-,
+ 6, 10, MST_NAGA, CE_POISONOUS, Z_SMALL, S_SHOUT, I_NORMAL,
+ 8, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_BIG
+},
{
MONS_FIRE_GIANT, 'C', RED, "fire giant",
M_FIGHTER | M_SPELLCASTER | M_WARM_BLOOD | M_SENSE_INVIS | M_EVIL,
MR_RES_FIRE,
2400, 11, MONS_HILL_GIANT, MONS_FIRE_GIANT, MH_NATURAL, -4,
- { {AT_HIT, AF_PLAIN, 30}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 30}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 16, 3, 6, 0 },
- 8, 4, 10, 7, MST_EFREET, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_GIANT,
-}
-,
+ 8, 4, MST_EFREET, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_GIANT,
+},
{
MONS_FROST_GIANT, 'C', LIGHTBLUE, "frost giant",
M_FIGHTER | M_SPELLCASTER | M_WARM_BLOOD | M_SENSE_INVIS | M_EVIL,
MR_RES_COLD,
2600, 11, MONS_HILL_GIANT, MONS_FROST_GIANT, MH_NATURAL, -4,
- { {AT_HIT, AF_PLAIN, 35}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 35}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 16, 4, 5, 0 },
- 9, 3, 10, 7, MST_FROST_GIANT, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_GIANT,
-}
-,
+ 9, 3, MST_FROST_GIANT, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_GIANT,
+},
{
MONS_FIREDRAKE, 'l', RED, "firedrake",
M_FLIES | M_SPECIAL_ABILITY,
MR_RES_FIRE,
900, 10, MONS_FIREDRAKE, MONS_FIREDRAKE, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 8}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 8}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 3, 5, 0 },
- 3, 12, 12, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SILENT, I_ANIMAL,
- MONUSE_OPEN_DOORS, SIZE_HUGE
-}
-,
+ 3, 12, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SILENT, I_ANIMAL,
+ 12, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_HUGE
+},
{
MONS_SHADOW_DRAGON, 'D', DARKGREY, "shadow dragon",
M_SPELLCASTER | M_FLIES | M_SEE_INVIS | M_EVIL,
MR_RES_POISON | MR_RES_COLD,
2000, 12, MONS_DRAGON, MONS_SHADOW_DRAGON, MH_NATURAL, -5,
- { {AT_BITE, AF_DRAIN_XP, 20}, {AT_CLAW, AF_PLAIN, 15}, {AT_CLAW, AF_PLAIN, 15}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_DRAIN_XP, 20}, {AT_CLAW, AF_PLAIN, 15}, {AT_CLAW, AF_PLAIN, 15}, AT_NO_ATK },
{ 17, 5, 5, 0 },
- 15, 10, 10, 7, MST_SHADOW_DRAGON, CE_CLEAN, Z_BIG, S_ROAR, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_HUGE
-}
-,
+ 15, 10, MST_SHADOW_DRAGON, CE_CLEAN, Z_BIG, S_ROAR, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_HUGE
+},
+
{
MONS_YELLOW_SNAKE, 'S', YELLOW, "yellow snake",
M_COLD_BLOOD,
MR_RES_POISON,
400, 10, MONS_SNAKE, MONS_YELLOW_SNAKE, MH_NATURAL, -3,
- { {AT_BITE, AF_POISON_MEDIUM, 15}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_POISON_MEDIUM, 15}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 3, 5, 0 },
- 4, 14, 13, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_HISS, I_INSECT,
- MONUSE_NOTHING, SIZE_MEDIUM
-}
-,
+ 4, 14, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_HISS, I_INSECT,
+ 13, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_MEDIUM
+},
{
MONS_GREY_SNAKE, 'S', LIGHTGREY, "grey snake",
M_COLD_BLOOD,
MR_NO_FLAGS,
600, 10, MONS_SNAKE, MONS_GREY_SNAKE, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 30}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 30}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 11, 3, 5, 0 },
- 4, 16, 18, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_HISS, I_INSECT,
- MONUSE_NOTHING, SIZE_LARGE
-}
-,
+ 4, 16, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_HISS, I_INSECT,
+ 18, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LARGE
+},
{
MONS_DEEP_TROLL, 'T', DARKGREY, "deep troll",
M_WARM_BLOOD | M_SENSE_INVIS | M_EVIL,
MR_NO_FLAGS,
1500, 12, MONS_TROLL, MONS_DEEP_TROLL, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 27}, {AT_CLAW, AF_PLAIN, 20}, {AT_CLAW, AF_PLAIN, 20}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 27}, {AT_CLAW, AF_PLAIN, 20}, {AT_CLAW, AF_PLAIN, 20}, AT_NO_ATK },
{ 10, 3, 5, 0 },
- 6, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_BIG
-}
-,
+ 6, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_BIG
+},
{
MONS_GIANT_BLOWFLY, 'y', LIGHTGREY, "giant blowfly",
M_FLIES,
MR_VUL_POISON,
200, 10, MONS_GIANT_BLOWFLY, MONS_GIANT_BLOWFLY, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 13}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 13}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 5, 3, 5, 0 },
- 2, 15, 19, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_BUZZ, I_PLANT,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 2, 15, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_BUZZ, I_PLANT,
+ 19, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_RED_WASP, 'y', RED, "red wasp",
M_FLIES,
MR_VUL_POISON,
400, 14, MONS_YELLOW_WASP, MONS_RED_WASP, MH_NATURAL, -3,
- { {AT_STING, AF_PARALYSE, 23}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_STING, AF_PARALYSE, 23}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 8, 3, 5, 0 },
- 7, 14, 15, 7, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_BUZZ, I_PLANT,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 7, 14, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_BUZZ, I_PLANT,
+ 15, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_SWAMP_DRAGON, 'D', BROWN, "swamp dragon",
M_SPELLCASTER | M_FLIES,
MR_RES_POISON,
1900, 11, MONS_DRAGON, MONS_SWAMP_DRAGON, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 18}, {AT_CLAW, AF_PLAIN, 9}, {AT_CLAW, AF_PLAIN, 9}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 18}, {AT_CLAW, AF_PLAIN, 9}, {AT_CLAW, AF_PLAIN, 9}, AT_NO_ATK },
{ 9, 5, 5, 0 },
- 7, 7, 10, 7, MST_SWAMP_DRAGON, CE_CONTAMINATED, Z_BIG, S_ROAR, I_ANIMAL,
- MONUSE_OPEN_DOORS, SIZE_GIANT,
-}
-,
+ 7, 7, MST_SWAMP_DRAGON, CE_CONTAMINATED, Z_BIG, S_ROAR, I_ANIMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_GIANT,
+},
{
MONS_SWAMP_DRAKE, 'l', BROWN, "swamp drake",
M_SPELLCASTER | M_FLIES | M_EVIL,
MR_RES_POISON,
900, 11, MONS_DRAGON, MONS_SWAMP_DRAKE, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 14}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 14}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 4, 5, 5, 0 },
- 3, 11, 11, 7, MST_SWAMP_DRAKE, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_ANIMAL,
- MONUSE_OPEN_DOORS, SIZE_BIG
-}
-,
+ 3, 11, MST_SWAMP_DRAKE, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_ANIMAL,
+ 11, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_BIG
+},
{
MONS_DEATH_DRAKE, 'l', DARKGREY, "death drake",
M_SPELLCASTER | M_FLIES | M_EVIL,
MR_RES_POISON,
900, 11, MONS_DRAGON, MONS_DEATH_DRAKE, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 12}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 12}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 9, 5, 7, 0 },
- 6, 14, 13, 10, MST_DEATH_DRAKE, CE_HCL, Z_BIG, S_ROAR, I_ANIMAL,
- MONUSE_OPEN_DOORS, SIZE_BIG
-}
-,
+ 6, 14, MST_DEATH_DRAKE, CE_HCL, Z_BIG, S_ROAR, I_ANIMAL,
+ 13, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_BIG
+},
{
MONS_SOLDIER_ANT, 'a', LIGHTGREY, "soldier ant",
M_NO_FLAGS,
MR_VUL_POISON,
900, 10, MONS_GIANT_ANT, MONS_SOLDIER_ANT, MH_NATURAL, -3,
- { {AT_STING, AF_POISON_NASTY, 14}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_STING, AF_POISON_NASTY, 14}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 3, 5, 0 },
- 8, 10, 10, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_LITTLE,
-}
-,
+ 8, 10, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LITTLE,
+},
{
MONS_HILL_GIANT, 'C', LIGHTRED, "hill giant",
M_WARM_BLOOD | M_EVIL,
MR_NO_FLAGS,
1600, 10, MONS_HILL_GIANT, MONS_HILL_GIANT, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 30}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 30}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 11, 3, 5, 0 },
- 3, 4, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_GIANT,
-}
-,
+ 3, 4, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_GIANT,
+},
{
MONS_QUEEN_ANT, 'Q', DARKGREY, "queen ant",
M_NO_FLAGS,
MR_VUL_POISON,
1200, 10, MONS_GIANT_ANT, MONS_QUEEN_ANT, MH_NATURAL, -3,
- { {AT_STING, AF_POISON_NASTY, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_STING, AF_POISON_NASTY, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 13, 3, 5, 0 },
- 14, 3, 7, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_SMALL
-}
-,
+ 14, 3, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
+ 7, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_SMALL
+},
{
MONS_ANT_LARVA, 'w', LIGHTGREY, "ant larva",
M_NO_SKELETON,
MR_VUL_POISON,
350, 5, MONS_GIANT_ANT, MONS_ANT_LARVA, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 5}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 2, 3, 5, 0 },
- 2, 6, 6, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
-
+ 2, 6, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT,
+ 6, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_GIANT_FROG, 'F', GREEN, "giant frog",
M_COLD_BLOOD | M_AMPHIBIOUS,
MR_NO_FLAGS,
500, 10, MONS_GIANT_FROG, MONS_GIANT_FROG, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 9}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 9}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 4, 3, 5, 0 },
- 0, 12, 15, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_CROAK, I_ANIMAL,
- MONUSE_NOTHING, SIZE_SMALL
-}
-,
+ 0, 12, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_CROAK, I_ANIMAL,
+ 15, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_SMALL
+},
{
MONS_GIANT_BROWN_FROG, 'F', BROWN, "giant brown frog",
M_COLD_BLOOD | M_AMPHIBIOUS,
MR_NO_FLAGS,
890, 10, MONS_GIANT_FROG, MONS_GIANT_BROWN_FROG, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 14}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 14}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 8, 3, 5, 0 },
- 2, 11, 13, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_CROAK, I_ANIMAL,
- MONUSE_NOTHING, SIZE_MEDIUM
-}
-,
+ 2, 11, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_CROAK, I_ANIMAL,
+ 13, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_MEDIUM
+},
{
MONS_SPINY_FROG, 'F', YELLOW, "spiny frog",
M_COLD_BLOOD | M_AMPHIBIOUS,
MR_RES_POISON,
1000, 10, MONS_GIANT_FROG, MONS_SPINY_FROG, MH_NATURAL, -3,
- { {AT_STING, AF_POISON_MEDIUM, 26}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_STING, AF_POISON_MEDIUM, 26}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 7, 3, 5, 0 },
- 6, 9, 12, 7, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_CROAK, I_ANIMAL,
- MONUSE_NOTHING, SIZE_SMALL
-}
-,
+ 6, 9, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_CROAK, I_ANIMAL,
+ 12, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_SMALL
+},
{
MONS_BLINK_FROG, 'F', LIGHTGREEN, "blink frog",
M_COLD_BLOOD | M_AMPHIBIOUS | M_SPECIAL_ABILITY,
MR_NO_FLAGS,
800, 12, MONS_GIANT_FROG, MONS_BLINK_FROG, MH_NATURAL, -5,
- { {AT_HIT, AF_BLINK, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_BLINK, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 3, 5, 0 },
- 3, 12, 14, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_CROAK, I_ANIMAL,
- MONUSE_NOTHING, SIZE_LITTLE,
-}
-,
+ 3, 12, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_CROAK, I_ANIMAL,
+ 14, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LITTLE,
+},
+
{
MONS_GIANT_COCKROACH, 'a', BROWN, "giant cockroach",
M_NO_FLAGS,
MR_NO_FLAGS,
250, 10, MONS_GIANT_COCKROACH, MONS_GIANT_COCKROACH, MH_NATURAL, -1,
- { {AT_BITE, AF_PLAIN, 2}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 2}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 1, 3, 4, 0 },
- 3, 10, 12, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 3, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SILENT, I_INSECT,
+ 12, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
+
{
MONS_SMALL_SNAKE, 'S', LIGHTGREEN, "small snake",
M_COLD_BLOOD,
MR_NO_FLAGS,
100, 13, MONS_SNAKE, MONS_SMALL_SNAKE, MH_NATURAL, -1,
- { {AT_BITE, AF_POISON, 2}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_POISON, 2}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 1, 2, 3, 0 },
- 0, 11, 12, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_LITTLE,
-}
-,
+ 0, 11, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_INSECT,
+ 12, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LITTLE,
+},
{
MONS_WHITE_IMP, '5', WHITE, "white imp",
M_SPELLCASTER | M_FLIES | M_SPEAKS | M_EVIL,
MR_RES_COLD,
0, 10, MONS_IMP, MONS_WHITE_IMP, MH_DEMONIC, -3,
- { {AT_HIT, AF_COLD, 4}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_COLD, 4}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 2, 3, 5, 0 },
- 4, 10, 10, 7, MST_WHITE_IMP, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_LITTLE,
-}
-,
+ 4, 10, MST_WHITE_IMP, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LITTLE,
+},
{
MONS_LEMURE, '5', YELLOW, "lemure",
M_EVIL,
MR_RES_POISON,
0, 10, MONS_LEMURE, MONS_LEMURE, MH_DEMONIC, -3,
- { {AT_HIT, AF_PLAIN, 12}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 12}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 2, 3, 5, 0 },
- 1, 12, 12, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_MOAN, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_SMALL
-}
-,
+ 1, 12, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_MOAN, I_NORMAL,
+ 12, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_SMALL
+},
{
MONS_UFETUBUS, '5', LIGHTCYAN, "ufetubus",
M_EVIL,
MR_VUL_FIRE | MR_RES_COLD,
0, 10, MONS_UFETUBUS, MONS_UFETUBUS, MH_DEMONIC, -3,
- { {AT_HIT, AF_PLAIN, 5}, {AT_HIT, AF_PLAIN, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 5}, {AT_HIT, AF_PLAIN, 5}, AT_NO_ATK, AT_NO_ATK },
{ 1, 4, 6, 0 },
- 2, 15, 15, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 2, 15, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
+ 15, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
{
MONS_MANES, '5', LIGHTRED, "manes",
M_EVIL,
MR_RES_ELEC | MR_RES_FIRE | MR_RES_COLD | MR_RES_POISON,
0, 10, MONS_MANES, MONS_MANES, MH_DEMONIC, -3,
- { {AT_HIT, AF_PLAIN, 5}, {AT_HIT, AF_PLAIN, 3}, {AT_HIT, AF_PLAIN, 3}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 5}, {AT_HIT, AF_PLAIN, 3}, {AT_HIT, AF_PLAIN, 3}, AT_NO_ATK },
{ 3, 3, 5, 0 },
- 2, 8, 8, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_SMALL
-}
-,
+ 2, 8, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
+ 8, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_SMALL
+},
{
MONS_MIDGE, '5', LIGHTGREEN, "midge",
M_FLIES | M_EVIL,
MR_RES_POISON,
0, 10, MONS_MIDGE, MONS_MIDGE, MH_DEMONIC, -3,
- { {AT_HIT, AF_BLINK, 8}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_BLINK, 8}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 2, 3, 5, 0 },
- 4, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_SMALL
-}
-,
+ 4, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_SMALL
+},
{
MONS_NEQOXEC, '3', MAGENTA, "neqoxec",
M_SPELLCASTER | M_LEVITATE | M_EVIL,
MR_RES_POISON,
0, 12, MONS_NEQOXEC, MONS_NEQOXEC, MH_DEMONIC, -6,
- { {AT_HIT, AF_PLAIN, 15}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 15}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 3, 5, 0 },
- 4, 12, 10, 7, MST_NEQOXEC, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 4, 12, MST_NEQOXEC, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
{
MONS_ORANGE_DEMON, '3', LIGHTRED, "orange demon",
M_EVIL,
MR_NO_FLAGS,
0, 12, MONS_ORANGE_DEMON, MONS_ORANGE_DEMON, MH_DEMONIC, -6,
- { {AT_STING, AF_POISON_STR, 10}, {AT_HIT, AF_PLAIN, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_STING, AF_POISON_STR, 10}, {AT_HIT, AF_PLAIN, 5}, AT_NO_ATK, AT_NO_ATK },
{ 8, 4, 5, 0 },
- 3, 7, 7, 7, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SCREECH, I_NORMAL,
- MONUSE_NOTHING, SIZE_MEDIUM
-}
-,
+ 3, 7, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SCREECH, I_NORMAL,
+ 7, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_MEDIUM
+},
{
MONS_HELLWING, '3', LIGHTGREY, "hellwing",
M_SPELLCASTER | M_FLIES | M_EVIL,
MR_RES_POISON,
0, 12, MONS_HELLWING, MONS_HELLWING, MH_DEMONIC, -6,
- { {AT_HIT, AF_PLAIN, 17}, {AT_HIT, AF_PLAIN, 10}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 17}, {AT_HIT, AF_PLAIN, 10}, AT_NO_ATK, AT_NO_ATK },
{ 7, 4, 5, 0 },
- 8, 10, 10, 7, MST_HELLWING, CE_CONTAMINATED, Z_NOZOMBIE, S_MOAN, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 8, 10, MST_HELLWING, CE_CONTAMINATED, Z_NOZOMBIE, S_MOAN, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_SMOKE_DEMON, '4', LIGHTGREY, "smoke demon",
M_SPELLCASTER | M_FLIES | M_EVIL,
MR_RES_POISON | MR_RES_FIRE,
0, 12, MONS_SMOKE_DEMON, MONS_SMOKE_DEMON, MH_DEMONIC, -6,
- { {AT_HIT, AF_PLAIN, 8}, {AT_HIT, AF_PLAIN, 5}, {AT_HIT, AF_PLAIN, 5}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 8}, {AT_HIT, AF_PLAIN, 5}, {AT_HIT, AF_PLAIN, 5}, AT_NO_ATK },
{ 7, 3, 5, 0 },
- 5, 9, 9, 7, MST_SMOKE_DEMON, CE_CONTAMINATED, Z_NOZOMBIE, S_ROAR, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_SMALL
-}
-,
+ 5, 9, MST_SMOKE_DEMON, CE_CONTAMINATED, Z_NOZOMBIE, S_ROAR, I_NORMAL,
+ 9, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_SMALL
+},
{
MONS_YNOXINUL, '3', CYAN, "ynoxinul",
M_SPELLCASTER | M_FLIES | M_SENSE_INVIS | M_EVIL,
MR_RES_ELEC | MR_RES_POISON | MR_RES_COLD,
0, 12, MONS_YNOXINUL, MONS_YNOXINUL, MH_DEMONIC, -6,
- { {AT_HIT, AF_PLAIN, 12}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 12}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 3, 5, 0 },
- 3, 10, 10, 7, MST_YNOXINUL, CE_CONTAMINATED, Z_NOZOMBIE, S_BELLOW, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 3, 10, MST_YNOXINUL, CE_CONTAMINATED, Z_NOZOMBIE, S_BELLOW, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
{
MONS_EXECUTIONER, '1', LIGHTGREY, "Executioner",
M_FIGHTER | M_SPELLCASTER | M_SEE_INVIS | M_EVIL,
MR_RES_ELEC | MR_RES_FIRE | MR_RES_COLD | MR_RES_POISON,
0, 14, MONS_EXECUTIONER, MONS_EXECUTIONER, MH_DEMONIC, -9,
- { {AT_HIT, AF_PLAIN, 30}, {AT_HIT, AF_PLAIN, 10}, {AT_HIT, AF_PLAIN, 10}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 30}, {AT_HIT, AF_PLAIN, 10}, {AT_HIT, AF_PLAIN, 10}, AT_NO_ATK },
{ 12, 3, 5, 0 },
- 10, 15, 20, 7, MST_HELL_KNIGHT_I, CE_CONTAMINATED, Z_NOZOMBIE, S_SCREAM, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 10, 15, MST_HELL_KNIGHT_I, CE_CONTAMINATED, Z_NOZOMBIE, S_SCREAM, I_HIGH,
+ 20, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_GREEN_DEATH, '1', GREEN, "Green Death",
M_SPELLCASTER | M_SEE_INVIS | M_EVIL,
MR_RES_POISON,
0, 14, MONS_GREEN_DEATH, MONS_GREEN_DEATH, MH_DEMONIC, -9,
- { {AT_HIT, AF_PLAIN, 32}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 32}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 13, 3, 5, 0 },
- 5, 7, 12, 7, MST_GREEN_DEATH, CE_POISONOUS, Z_NOZOMBIE, S_ROAR, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 5, 7, MST_GREEN_DEATH, CE_POISONOUS, Z_NOZOMBIE, S_ROAR, I_HIGH,
+ 12, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_BLUE_DEATH, '1', BLUE, "Blue Death",
M_SPELLCASTER | M_FLIES | M_SEE_INVIS | M_EVIL,
MR_RES_POISON | MR_VUL_FIRE | MR_RES_COLD | MR_RES_ELEC,
0, 14, MONS_BLUE_DEATH, MONS_BLUE_DEATH, MH_DEMONIC, -9,
- { {AT_HIT, AF_PLAIN, 20}, {AT_HIT, AF_PLAIN, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 20}, {AT_HIT, AF_PLAIN, 20}, AT_NO_ATK, AT_NO_ATK },
{ 12, 3, 5, 0 },
- 10, 10, 12, 7, MST_BLUE_DEATH, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 10, 10, MST_BLUE_DEATH, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ 12, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_BALRUG, '1', RED, "Balrug",
M_FIGHTER | M_SPELLCASTER | M_FLIES | M_SEE_INVIS | M_EVIL,
MR_RES_POISON | MR_RES_HELLFIRE | MR_VUL_COLD,
0, 14, MONS_BALRUG, MONS_BALRUG, MH_DEMONIC, -9,
- { {AT_HIT, AF_FIRE, 25}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_FIRE, 25}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 14, 3, 5, 0 },
- 5, 12, 12, 7, MST_BALRUG, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_BIG
-}
-,
+ 5, 12, MST_BALRUG, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ 12, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_BIG
+},
{
MONS_CACODEMON, '1', YELLOW, "Cacodemon",
M_SPELLCASTER | M_LEVITATE | M_SEE_INVIS | M_EVIL,
MR_RES_POISON | MR_RES_ELEC,
0, 14, MONS_CACODEMON, MONS_CACODEMON, MH_DEMONIC, -9,
- { {AT_HIT, AF_PLAIN, 22}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 22}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 13, 3, 5, 0 },
- 11, 10, 10, 7, MST_CACODEMON, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
-
+ 11, 10, MST_CACODEMON, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_DEMONIC_CRAWLER, '3', DARKGREY, "demonic crawler",
@@ -2446,154 +2262,141 @@
0, 12, MONS_DEMONIC_CRAWLER, MONS_DEMONIC_CRAWLER, MH_DEMONIC, -6,
{ {AT_HIT, AF_PLAIN, 13}, {AT_HIT, AF_PLAIN, 13}, {AT_HIT, AF_PLAIN, 13} },
{ 9, 3, 5, 0 },
- 10, 6, 9, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SCREAM, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_BIG
-}
-,
+ 10, 6, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SCREAM, I_NORMAL,
+ 9, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_BIG
+},
{
MONS_SUN_DEMON, '2', YELLOW, "sun demon",
M_SENSE_INVIS | M_LEVITATE | M_EVIL,
MR_RES_ELEC | MR_RES_POISON | MR_VUL_COLD | MR_RES_HELLFIRE,
0, 14, MONS_SUN_DEMON, MONS_SUN_DEMON, MH_DEMONIC, -6,
- { {AT_HIT, AF_FIRE, 30}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_FIRE, 30}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 10, 3, 5, 0 },
- 10, 12, 12, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 10, 12, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
+ 12, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
{
MONS_SHADOW_IMP, '5', DARKGREY, "shadow imp",
M_SPELLCASTER | M_FLIES | M_SPEAKS | M_EVIL,
MR_RES_COLD | MR_RES_POISON,
0, 11, MONS_IMP, MONS_SHADOW_IMP, MH_DEMONIC, -3,
- { {AT_HIT, AF_PLAIN, 6}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 6}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 2, 3, 5, 0 },
- 3, 11, 10, 7, MST_SHADOW_IMP, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_LITTLE,
-}
-,
+ 3, 11, MST_SHADOW_IMP, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LITTLE,
+},
{
MONS_SHADOW_DEMON, '3', DARKGREY, "shadow demon",
M_SEE_INVIS | M_INVIS | M_EVIL,
MR_RES_POISON | MR_RES_COLD,
0, 12, MONS_SHADOW_DEMON, MONS_SHADOW_DEMON, MH_DEMONIC, -7,
- { {AT_HIT, AF_PLAIN, 21}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 21}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 3, 5, 0 },
- 7, 12, 11, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_CROAK, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_SMALL
-}
-,
+ 7, 12, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_CROAK, I_HIGH,
+ 11, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_SMALL
+},
{
MONS_LOROCYPROCA, '2', BLUE, "Lorocyproca",
M_SENSE_INVIS | M_INVIS | M_EVIL,
MR_RES_POISON | MR_RES_COLD | MR_RES_FIRE | MR_RES_ELEC,
0, 12, MONS_LOROCYPROCA, MONS_LOROCYPROCA, MH_DEMONIC, -7,
- { {AT_HIT, AF_PLAIN, 25}, {AT_HIT, AF_PLAIN, 25}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 25}, {AT_HIT, AF_PLAIN, 25}, AT_NO_ATK, AT_NO_ATK },
{ 12, 3, 5, 0 },
- 10, 12, 9, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_MOAN, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 10, 12, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_MOAN, I_HIGH,
+ 9, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
{
MONS_SHADOW_WRAITH, 'W', BLUE, "shadow wraith",
M_LEVITATE | M_SEE_INVIS | M_INVIS | M_EVIL,
MR_RES_POISON,
0, 15, MONS_WRAITH, MONS_SHADOW_WRAITH, MH_UNDEAD, -8,
- { {AT_HIT, AF_DRAIN_XP, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_DRAIN_XP, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 10, 3, 5, 0 },
- 7, 7, 10, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_MOAN, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 7, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_MOAN, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
{
MONS_GIANT_AMOEBA, 'J', BLUE, "giant amoeba",
M_NO_SKELETON | M_SENSE_INVIS | M_AMPHIBIOUS,
MR_RES_POISON,
1000, 10, MONS_GIANT_AMOEBA, MONS_GIANT_AMOEBA, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 25}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 25}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 12, 3, 5, 0 },
- 0, 4, 10, 10, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_LITTLE,
-}
-,
+ 0, 4, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LITTLE,
+},
{
MONS_GIANT_SLUG, 'm', GREEN, "giant slug",
M_NO_SKELETON | M_AMPHIBIOUS,
MR_NO_FLAGS,
700, 10, MONS_GIANT_SLUG, MONS_GIANT_SLUG, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 23}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 23}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 10, 5, 3, 0 },
- 0, 2, 6, 10, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_LARGE
-}
-,
+ 0, 2, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_SILENT, I_INSECT,
+ 6, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LARGE
+},
{
MONS_GIANT_SNAIL, 'm', LIGHTGREEN, "giant snail",
M_NO_SKELETON | M_AMPHIBIOUS,
MR_NO_FLAGS,
900, 10, MONS_GIANT_SLUG, MONS_GIANT_SNAIL, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 18}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 18}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 14, 5, 3, 0 },
- 7, 2, 4, 10, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_LARGE
-}
-,
+ 7, 2, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_SILENT, I_INSECT,
+ 4, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LARGE
+},
{
MONS_SPATIAL_VORTEX, 'v', BLACK, "spatial vortex",
M_LEVITATE | M_CONFUSED,
MR_RES_POISON | MR_RES_FIRE | MR_RES_COLD | MR_RES_ELEC,
0, 5, MONS_FIRE_VORTEX, MONS_SPATIAL_VORTEX, MH_NONLIVING, MAG_IMMUNE,
- { {AT_HIT, AF_DISTORT, 30}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_DISTORT, 30}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 6, 6, 0 },
- 0, 5, 15, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_LARGE
-}
-,
+ 0, 5, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 15, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LARGE
+},
{
MONS_PIT_FIEND, '1', BROWN, "Pit Fiend",
M_FLIES | M_SEE_INVIS | M_EVIL | M_SPECIAL_ABILITY,
MR_RES_POISON | MR_RES_HELLFIRE | MR_RES_COLD | MR_RES_ELEC,
0, 18, MONS_FIEND, MONS_PIT_FIEND, MH_DEMONIC, -12,
- { {AT_HIT, AF_PLAIN, 28}, {AT_HIT, AF_PLAIN, 21}, {AT_HIT, AF_PLAIN, 21}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 28}, {AT_HIT, AF_PLAIN, 21}, {AT_HIT, AF_PLAIN, 21}, AT_NO_ATK },
{ 19, 4, 5, 0 },
- 17, 5, 8, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_ROAR, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 17, 5, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_ROAR, I_HIGH,
+ 8, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_BORING_BEETLE, 'B', BROWN, "boring beetle",
M_NO_FLAGS,
MR_VUL_POISON,
1300, 10, MONS_GIANT_BEETLE, MONS_BORING_BEETLE, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 26}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 26}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 8, 3, 5, 0 },
- 13, 4, 6, 7, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_LARGE
-}
-,
+ 13, 4, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_SILENT, I_INSECT,
+ 6, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LARGE
+},
{
MONS_GARGOYLE, 'g', DARKGREY, "gargoyle",
M_FLIES,
MR_RES_POISON | MR_RES_ELEC,
0, 12, MONS_GARGOYLE, MONS_GARGOYLE, MH_NONLIVING, -6,
- { {AT_BITE, AF_PLAIN, 10}, {AT_CLAW, AF_PLAIN, 6}, {AT_CLAW, AF_PLAIN, 6}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 10}, {AT_CLAW, AF_PLAIN, 6}, {AT_CLAW, AF_PLAIN, 6}, AT_NO_ATK },
{ 4, 3, 5, 0 },
- 18, 6, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 18, 6, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
// only appear in Dis castle
{
@@ -2601,12 +2404,11 @@
M_FLIES,
MR_RES_POISON | MR_RES_ELEC,
0, 12, MONS_GARGOYLE, MONS_METAL_GARGOYLE, MH_NONLIVING, -6,
- { {AT_BITE, AF_PLAIN, 19}, {AT_CLAW, AF_PLAIN, 10}, {AT_CLAW, AF_PLAIN, 10}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 19}, {AT_CLAW, AF_PLAIN, 10}, {AT_CLAW, AF_PLAIN, 10}, AT_NO_ATK },
{ 8, 3, 5, 0 },
- 20, 4, 7, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 20, 4, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ 7, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
// only appear in Gehenna castle & one minivault
{
@@ -2614,13 +2416,11 @@
M_FLIES,
MR_RES_POISON | MR_RES_ELEC | MR_RES_FIRE,
0, 12, MONS_GARGOYLE, MONS_MOLTEN_GARGOYLE, MH_NONLIVING, -6,
- { {AT_BITE, AF_FIRE, 12}, {AT_CLAW, AF_PLAIN, 8}, {AT_CLAW, AF_PLAIN, 8}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_FIRE, 12}, {AT_CLAW, AF_PLAIN, 8}, {AT_CLAW, AF_PLAIN, 8}, AT_NO_ATK },
{ 5, 3, 5, 0 },
- 14, 7, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
-
+ 14, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
// 250 can't exist
@@ -2630,48 +2430,44 @@
M_FIGHTER | M_SEE_INVIS | M_SPELLCASTER | M_SPEAKS | M_EVIL | M_UNIQUE,
MR_RES_ELEC | MR_RES_POISON | MR_RES_FIRE,
0, 25, MONS_MNOLEG, MONS_MNOLEG, MH_DEMONIC, MAG_IMMUNE,
- { {AT_HIT, AF_PLAIN, 35}, {AT_HIT, AF_PLAIN, 23}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 35}, {AT_HIT, AF_PLAIN, 23}, AT_NO_ATK, AT_NO_ATK },
{ 17, 0, 0, 199 },
- 10, 13, 13, 7, MST_MNOLEG, CE_CONTAMINATED, Z_NOZOMBIE, S_BUZZ, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 10, 13, MST_MNOLEG, CE_CONTAMINATED, Z_NOZOMBIE, S_BUZZ, I_HIGH,
+ 13, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_LOM_LOBON, '&', LIGHTBLUE, "Lom Lobon",
M_FIGHTER | M_LEVITATE | M_SEE_INVIS | M_SPELLCASTER | M_SPEAKS | M_EVIL | M_UNIQUE,
MR_RES_POISON | MR_RES_FIRE | MR_RES_COLD | MR_RES_ELEC,
0, 25, MONS_LOM_LOBON, MONS_LOM_LOBON, MH_DEMONIC, MAG_IMMUNE,
- { {AT_HIT, AF_PLAIN, 40}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 40}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 19, 0, 0, 223 },
- 10, 7, 8, 7, MST_LOM_LOBON, CE_CONTAMINATED, Z_NOZOMBIE, S_SCREAM, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 10, 7, MST_LOM_LOBON, CE_CONTAMINATED, Z_NOZOMBIE, S_SCREAM, I_HIGH,
+ 8, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_CEREBOV, '&', RED, "Cerebov",
M_FIGHTER | M_SPELLCASTER | M_SEE_INVIS | M_SPEAKS | M_EVIL | M_UNIQUE,
MR_RES_ELEC | MR_RES_POISON | MR_RES_HELLFIRE,
0, 25, MONS_CEREBOV, MONS_CEREBOV, MH_DEMONIC, -6,
- { {AT_HIT, AF_PLAIN, 60}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 60}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 21, 0, 0, 253 },
- 15, 8, 10, 7, MST_CEREBOV, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_GIANT,
-}
-,
+ 15, 8, MST_CEREBOV, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_GIANT,
+},
{
MONS_GLOORX_VLOQ, '&', DARKGREY, "Gloorx Vloq",
M_FIGHTER | M_LEVITATE | M_SEE_INVIS | M_SPELLCASTER | M_SPEAKS | M_EVIL | M_UNIQUE,
MR_RES_POISON | MR_RES_COLD | MR_RES_ELEC,
0, 25, MONS_GLOORX_VLOQ, MONS_GLOORX_VLOQ, MH_DEMONIC, -14,
- { {AT_HIT, AF_PLAIN, 40}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 40}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 16, 0, 0, 234 },
- 10, 10, 10, 7, MST_GLOORX_VLOQ, CE_CONTAMINATED, Z_NOZOMBIE, S_MOAN, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 10, 10, MST_GLOORX_VLOQ, CE_CONTAMINATED, Z_NOZOMBIE, S_MOAN, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
/* ******************************************************************
{MONS_MOLLUSC_LORD, 'U', GREEN, "The Mollusc Lord", M_NO_FLAGS,
@@ -2685,84 +2481,77 @@
M_SPELLCASTER | M_ACTUAL_SPELLS | M_SEE_INVIS | M_WARM_BLOOD,
MR_RES_POISON,
750, 13, MONS_NAGA, MONS_NAGA, MH_NATURAL, -6,
- { {AT_HIT, AF_PLAIN, 10}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 7, 3, 5, 0 },
- 6, 10, 8, 7, MST_NAGA_MAGE, CE_POISONOUS, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_BIG
-}
-,
+ 6, 10, MST_NAGA_MAGE, CE_POISONOUS, Z_SMALL, S_SHOUT, I_NORMAL,
+ 8, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_BIG
+},
{
MONS_NAGA_WARRIOR, 'N', BLUE, "naga warrior",
M_FIGHTER | M_SPELLCASTER | M_SEE_INVIS | M_WARM_BLOOD,
MR_RES_POISON,
750, 12, MONS_NAGA, MONS_NAGA, MH_NATURAL, -6,
- { {AT_HIT, AF_PLAIN, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 10, 5, 5, 0 },
- 6, 10, 8, 7, MST_NAGA, CE_POISONOUS, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_BIG
-}
-,
+ 6, 10, MST_NAGA, CE_POISONOUS, Z_SMALL, S_SHOUT, I_NORMAL,
+ 8, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_BIG
+},
{
MONS_ORC_WARLORD, 'o', RED, "orc warlord",
M_FIGHTER | M_WARM_BLOOD | M_EVIL,
MR_NO_FLAGS,
600, 15, MONS_ORC, MONS_ORC, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 32}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 32}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 15, 4, 7, 0 },
- 3, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 3, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_DEEP_ELF_SOLDIER, 'e', CYAN, "deep elf soldier",
M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD | M_FIGHTER,
MR_NO_FLAGS,
450, 10, MONS_ELF, MONS_ELF, MH_NATURAL, -6,
- { {AT_HIT, AF_PLAIN, 6}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 6}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 3, 3, 3, 0 },
- 0, 12, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 12, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_DEEP_ELF_FIGHTER, 'e', LIGHTBLUE, "deep elf fighter",
M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD | M_FIGHTER,
MR_NO_FLAGS,
450, 10, MONS_ELF, MONS_ELF, MH_NATURAL, -6,
- { {AT_HIT, AF_PLAIN, 9}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 9}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 3, 3, 0 },
- 0, 13, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 13, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_DEEP_ELF_KNIGHT, 'e', BLUE, "deep elf knight",
M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD | M_FIGHTER,
MR_NO_FLAGS,
450, 10, MONS_ELF, MONS_ELF, MH_NATURAL, -6,
- { {AT_HIT, AF_PLAIN, 14}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 14}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 11, 3, 3, 0 },
- 0, 15, 11, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 15, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ 11, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_DEEP_ELF_BLADEMASTER, 'e', LIGHTCYAN, "deep elf blademaster",
M_WARM_BLOOD | M_FIGHTER,
MR_NO_FLAGS,
450, 10, MONS_ELF, MONS_ELF, MH_NATURAL, -6,
- { {AT_HIT, AF_PLAIN, 25}, {AT_HIT, AF_PLAIN, 25}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 25}, {AT_HIT, AF_PLAIN, 25}, AT_NO_ATK, AT_NO_ATK },
{ 16, 5, 3, 0 },
- 0, 25, 15, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 25, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ 15, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_DEEP_ELF_MASTER_ARCHER, 'e', LIGHTMAGENTA, "deep elf master archer",
@@ -2770,96 +2559,90 @@
MR_NO_FLAGS,
450, 10, MONS_ELF, MONS_ELF, MH_NATURAL, -5,
// Attack damage gets rolled into their ranged attacks.
- { {AT_SHOOT, AF_PLAIN, 25}, {AT_HIT, AF_PLAIN, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_SHOOT, AF_PLAIN, 25}, {AT_HIT, AF_PLAIN, 5}, AT_NO_ATK, AT_NO_ATK },
{ 15, 4, 2, 0 },
- 0, 15, 11, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 15, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ 11, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
+
+
{
MONS_DEEP_ELF_MAGE, 'e', LIGHTRED, "deep elf mage",
M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD,
MR_RES_ELEC,
450, 10, MONS_ELF, MONS_ELF, MH_NATURAL, -6,
- { {AT_HIT, AF_PLAIN, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 5}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 4, 3, 3, 0 },
- 0, 13, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 13, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_DEEP_ELF_SUMMONER, 'e', YELLOW, "deep elf summoner",
M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD,
MR_NO_FLAGS,
450, 10, MONS_ELF, MONS_ELF, MH_NATURAL, -6,
- { {AT_HIT, AF_PLAIN, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 5}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 3, 3, 0 },
- 0, 13, 10, 7, MST_DEEP_ELF_SUMMONER, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 13, MST_DEEP_ELF_SUMMONER, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_DEEP_ELF_CONJURER, 'e', LIGHTGREEN, "deep elf conjurer",
M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD,
MR_RES_ELEC,
450, 10, MONS_ELF, MONS_ELF, MH_NATURAL, -6,
- { {AT_HIT, AF_PLAIN, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 5}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 3, 3, 0 },
- 0, 13, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 13, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_DEEP_ELF_PRIEST, 'e', LIGHTGREY, "deep elf priest",
M_SPELLCASTER | M_PRIEST | M_WARM_BLOOD,
MR_NO_FLAGS,
450, 10, MONS_ELF, MONS_ELF, MH_NATURAL, -6,
- { {AT_HIT, AF_PLAIN, 9}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 9}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 5, 3, 3, 0 },
- 0, 13, 10, 7, MST_DEEP_ELF_PRIEST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 13, MST_DEEP_ELF_PRIEST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_DEEP_ELF_HIGH_PRIEST, 'e', DARKGREY, "deep elf high priest",
M_SPELLCASTER | M_SPEAKS | M_PRIEST | M_WARM_BLOOD | M_SEE_INVIS | M_EVIL,
MR_NO_FLAGS,
450, 10, MONS_ELF, MONS_ELF, MH_NATURAL, -6,
- { {AT_HIT, AF_PLAIN, 14}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 14}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 11, 3, 3, 0 },
- 3, 13, 10, 7, MST_DEEP_ELF_HIGH_PRIEST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 3, 13, MST_DEEP_ELF_HIGH_PRIEST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_DEEP_ELF_DEMONOLOGIST, 'e', MAGENTA, "deep elf demonologist",
M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD | M_SEE_INVIS | M_EVIL,
MR_NO_FLAGS,
450, 10, MONS_ELF, MONS_ELF, MH_NATURAL, -6,
- { {AT_HIT, AF_PLAIN, 12}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 12}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 12, 3, 3, 0 },
- 0, 13, 10, 7, MST_DEEP_ELF_DEMONOLOGIST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 13, MST_DEEP_ELF_DEMONOLOGIST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_DEEP_ELF_ANNIHILATOR, 'e', GREEN, "deep elf annihilator",
M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD | M_SEE_INVIS,
MR_RES_ELEC,
450, 10, MONS_ELF, MONS_ELF, MH_NATURAL, -6,
- { {AT_HIT, AF_PLAIN, 12}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 12}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 15, 3, 3, 0 },
- 0, 13, 10, 7, MST_DEEP_ELF_ANNIHILATOR, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 13, MST_DEEP_ELF_ANNIHILATOR, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_DEEP_ELF_SORCERER, 'e', RED, "deep elf sorcerer",
@@ -2867,36 +2650,33 @@
| M_EVIL,
MR_NO_FLAGS,
450, 10, MONS_ELF, MONS_ELF, MH_NATURAL, -6,
- { {AT_HIT, AF_PLAIN, 12}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 12}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 14, 3, 3, 0 },
- 0, 13, 10, 7, MST_DEEP_ELF_SORCERER, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 13, MST_DEEP_ELF_SORCERER, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_DEEP_ELF_DEATH_MAGE, 'e', WHITE, "deep elf death mage",
M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD | M_SEE_INVIS | M_EVIL,
MR_NO_FLAGS,
450, 10, MONS_ELF, MONS_ELF, MH_NATURAL, -6,
- { {AT_HIT, AF_PLAIN, 12}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 12}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 15, 3, 3, 0 },
- 0, 13, 10, 7, MST_DEEP_ELF_DEATH_MAGE, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 13, MST_DEEP_ELF_DEATH_MAGE, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_BROWN_OOZE, 'J', BROWN, "brown ooze",
M_NO_SKELETON | M_SENSE_INVIS | M_ACID_SPLASH,
MR_RES_POISON | MR_RES_ASPHYX | MR_RES_ACID,
0, 11, MONS_JELLY, MONS_BROWN_OOZE, MH_NATURAL, -7,
- { {AT_HIT, AF_ACID, 25}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_ACID, 25}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 7, 3, 5, 0 },
- 10, 1, 10, 7, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_EATS_ITEMS, SIZE_LITTLE,
-}
-,
+ 10, 1, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 10, DEFAULT_ENERGY, MONUSE_EATS_ITEMS, SIZE_LITTLE,
+},
{
MONS_AZURE_JELLY, 'J', LIGHTBLUE, "azure jelly",
@@ -2906,130 +2686,119 @@
0, 11, MONS_JELLY, MONS_AZURE_JELLY, MH_NATURAL, -4,
{ {AT_HIT, AF_COLD, 12}, {AT_HIT, AF_COLD, 12}, {AT_HIT, AF_PLAIN, 12}, {AT_HIT, AF_PLAIN, 12} },
{ 15, 3, 5, 0 },
- 5, 10, 12, 7, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_EATS_ITEMS, SIZE_LITTLE,
-}
-,
+ 5, 10, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 12, DEFAULT_ENERGY, MONUSE_EATS_ITEMS, SIZE_LITTLE,
+},
{
MONS_DEATH_OOZE, 'J', DARKGREY, "death ooze",
M_NO_SKELETON | M_SENSE_INVIS | M_EVIL,
MR_RES_POISON | MR_RES_COLD | MR_RES_ASPHYX | MR_RES_ACID,
0, 13, MONS_JELLY, MONS_DEATH_OOZE, MH_UNDEAD, -8,
- { {AT_HIT, AF_ROT, 32}, {AT_HIT, AF_PLAIN, 32}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_ROT, 32}, {AT_HIT, AF_PLAIN, 32}, AT_NO_ATK, AT_NO_ATK },
{ 11, 3, 3, 0 },
- 2, 4, 12, 7, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_EATS_ITEMS, SIZE_LITTLE,
-}
-,
+ 2, 4, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 12, DEFAULT_ENERGY, MONUSE_EATS_ITEMS, SIZE_LITTLE,
+},
{
MONS_ACID_BLOB, 'J', LIGHTGREEN, "acid blob",
M_NO_SKELETON | M_SENSE_INVIS | M_SPECIAL_ABILITY | M_ACID_SPLASH,
MR_RES_POISON | MR_RES_ASPHYX | MR_RES_ACID,
0, 12, MONS_JELLY, MONS_ACID_BLOB, MH_NATURAL, -7,
- { {AT_HIT, AF_ACID, 42}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_ACID, 42}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 18, 3, 5, 0 },
- 1, 3, 14, 7, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_EATS_ITEMS, SIZE_LITTLE,
-}
-,
+ 1, 3, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 14, DEFAULT_ENERGY, MONUSE_EATS_ITEMS, SIZE_LITTLE,
+},
{
MONS_ROYAL_JELLY, 'J', YELLOW, "royal jelly",
M_NO_SKELETON | M_SENSE_INVIS | M_ACID_SPLASH,
MR_RES_POISON | MR_RES_ASPHYX | MR_RES_ACID,
0, 20, MONS_JELLY, MONS_ROYAL_JELLY, MH_NATURAL, -7,
- { {AT_HIT, AF_ACID, 50}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_ACID, 50}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 21, 0, 0, 111 },
- 8, 4, 12, 7, MST_NO_SPELLS, CE_CLEAN, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_EATS_ITEMS, SIZE_SMALL
-}
-,
+ 8, 4, MST_NO_SPELLS, CE_CLEAN, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 12, DEFAULT_ENERGY, MONUSE_EATS_ITEMS, SIZE_SMALL
+},
{
MONS_TERENCE, '@', LIGHTCYAN, "Terence",
M_WARM_BLOOD | M_SPEAKS | M_UNIQUE,
MR_NO_FLAGS,
0, 20, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 5}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 1, 0, 0, 20 },
- 0, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_JESSICA, '@', LIGHTGREY, "Jessica",
M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD | M_UNIQUE,
MR_NO_FLAGS,
0, 20, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 5}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 1, 0, 0, 10 },
- 0, 10, 10, 7, MST_ORC_WIZARD_I, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 10, MST_ORC_WIZARD_I, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_IJYB, 'g', BLUE, "Ijyb",
M_WARM_BLOOD | M_SPEAKS | M_UNIQUE,
MR_NO_FLAGS,
0, 5, MONS_GOBLIN, MONS_GOBLIN, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 4}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 4}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 3, 0, 0, 28 },
- 2, 12, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_SMALL
-}
-,
+ 2, 12, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_SMALL
+},
{
MONS_SIGMUND, '@', YELLOW, "Sigmund",
M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD | M_UNIQUE,
MR_NO_FLAGS,
0, 20, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 5}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 3, 0, 0, 30 },
- 0, 11, 10, 7, MST_ORC_WIZARD_II, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 11, MST_ORC_WIZARD_II, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_BLORK_THE_ORC, 'o', BROWN, "Blork the orc",
M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD | M_UNIQUE,
MR_NO_FLAGS,
0, 20, MONS_ORC, MONS_ORC, MH_NATURAL, -4,
- { {AT_HIT, AF_PLAIN, 7}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 7}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 3, 0, 0, 32 },
- 0, 9, 8, 7, MST_ORC_WIZARD_III, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 9, MST_ORC_WIZARD_III, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 8, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_EDMUND, '@', RED, "Edmund",
M_FIGHTER | M_WARM_BLOOD | M_SPEAKS | M_UNIQUE,
MR_NO_FLAGS,
0, 20, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -4,
- { {AT_HIT, AF_PLAIN, 6}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 6}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 4, 0, 0, 44 },
- 0, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_PSYCHE, '@', LIGHTMAGENTA, "Psyche",
M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD | M_UNIQUE,
MR_NO_FLAGS,
0, 20, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -4,
- { {AT_HIT, AF_PLAIN, 7}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 7}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 5, 0, 0, 39 },
- 0, 12, 13, 7, MST_ORC_WIZARD_III, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 12, MST_ORC_WIZARD_III, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 13, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_EROLCHA, 'O', LIGHTBLUE, "Erolcha",
@@ -3037,168 +2806,154 @@
| M_SPEAKS | M_EVIL | M_UNIQUE,
MR_RES_ELEC,
0, 20, MONS_OGRE, MONS_OGRE, MH_NATURAL, -7,
- { {AT_HIT, AF_PLAIN, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 0, 0, 54 },
- 3, 7, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_LARGE
-}
-,
+ 3, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_LARGE
+},
{
MONS_DONALD, '@', BLUE, "Donald",
M_FIGHTER | M_WARM_BLOOD | M_SPEAKS | M_UNIQUE,
MR_NO_FLAGS,
0, 20, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -5,
- { {AT_HIT, AF_PLAIN, 8}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 8}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 5, 0, 0, 54 },
- 0, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_URUG, 'o', RED, "Urug",
M_FIGHTER | M_WARM_BLOOD | M_SPEAKS | M_UNIQUE,
MR_NO_FLAGS,
0, 20, MONS_ORC, MONS_ORC, MH_NATURAL, -5,
- { {AT_HIT, AF_PLAIN, 12}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 12}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 0, 0, 66 },
- 0, 11, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 11, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_MICHAEL, '@', LIGHTGREY, "Michael",
M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD | M_UNIQUE,
MR_NO_FLAGS,
0, 20, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -5,
- { {AT_HIT, AF_PLAIN, 9}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 9}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 0, 0, 50 },
- 0, 10, 10, 7, MST_ORC_WIZARD_III, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 10, MST_ORC_WIZARD_III, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_JOSEPH, '@', CYAN, "Joseph",
M_FIGHTER | M_WARM_BLOOD | M_SPEAKS | M_UNIQUE,
MR_NO_FLAGS,
0, 20, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -5,
- { {AT_HIT, AF_PLAIN, 9}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 9}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 7, 0, 0, 66 },
- 0, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_SNORG, 'T', GREEN, "Snorg",
M_WARM_BLOOD | M_SPEAKS | M_EVIL | M_UNIQUE,
MR_NO_FLAGS,
0, 20, MONS_TROLL, MONS_TROLL, MH_NATURAL, -6,
- { {AT_BITE, AF_PLAIN, 20}, {AT_CLAW, AF_PLAIN, 15}, {AT_CLAW, AF_PLAIN, 15}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 20}, {AT_CLAW, AF_PLAIN, 15}, {AT_CLAW, AF_PLAIN, 15}, AT_NO_ATK },
{ 8, 0, 0, 96 },
- 0, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 0, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_ERICA, '@', MAGENTA, "Erica",
M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD | M_UNIQUE,
MR_NO_FLAGS,
0, 20, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -5,
- { {AT_HIT, AF_PLAIN, 10}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 9, 0, 0, 64 },
- 0, 11, 11, 7, MST_WIZARD_II, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 11, MST_WIZARD_II, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 11, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_JOSEPHINE, '@', WHITE, "Josephine",
M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD | M_UNIQUE,
MR_NO_FLAGS,
0, 20, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -5,
- { {AT_HIT, AF_PLAIN, 11}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 11}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 9, 0, 0, 69 },
- 0, 10, 10, 7, MST_NECROMANCER_I, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 10, MST_NECROMANCER_I, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_HAROLD, '@', LIGHTGREEN, "Harold",
M_FIGHTER | M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD | M_UNIQUE,
MR_NO_FLAGS,
0, 20, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -5,
- { {AT_HIT, AF_PLAIN, 12}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 12}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 9, 0, 0, 76 },
- 0, 8, 10, 7, MST_HELL_KNIGHT_II, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 8, MST_HELL_KNIGHT_II, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_NORBERT, '@', BROWN, "Norbert",
M_FIGHTER | M_WARM_BLOOD | M_SPEAKS | M_UNIQUE,
MR_NO_FLAGS,
0, 20, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -5,
- { {AT_HIT, AF_PLAIN, 25}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 25}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 10, 0, 0, 105 },
- 0, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_JOZEF, '@', LIGHTMAGENTA, "Jozef",
M_FIGHTER | M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD | M_UNIQUE,
MR_NO_FLAGS,
0, 20, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -5,
- { {AT_HIT, AF_PLAIN, 18}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 18}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 11, 0, 0, 90 },
- 0, 9, 10, 7, MST_GUARDIAN_NAGA, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 9, MST_GUARDIAN_NAGA, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_AGNES, '@', LIGHTBLUE, "Agnes",
M_FIGHTER | M_WARM_BLOOD | M_SPEAKS | M_UNIQUE,
MR_NO_FLAGS,
0, 20, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -5,
- { {AT_HIT, AF_PLAIN, 25}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 25}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 11, 0, 0, 140 },
- 0, 10, 15, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 15, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_MAUD, '@', RED, "Maud",
M_FIGHTER | M_WARM_BLOOD | M_SPEAKS | M_UNIQUE,
MR_NO_FLAGS,
0, 20, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -5,
- { {AT_HIT, AF_PLAIN, 24}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 24}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 13, 0, 0, 118 },
- 0, 10, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_LOUISE, '@', BLUE, "Louise",
M_SPELLCASTER | M_ACTUAL_SPELLS | M_SPEAKS | M_WARM_BLOOD | M_UNIQUE,
MR_RES_ELEC,
0, 20, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -5,
- { {AT_HIT, AF_PLAIN, 17}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 17}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 13, 0, 0, 106 },
- 0, 10, 10, 7, MST_WIZARD_IV, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 10, MST_WIZARD_IV, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_FRANCIS, '@', YELLOW, "Francis",
@@ -3206,12 +2961,11 @@
| M_SEE_INVIS | M_EVIL | M_UNIQUE,
MR_NO_FLAGS,
0, 20, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -5,
- { {AT_HIT, AF_PLAIN, 19}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 19}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 14, 0, 0, 110 },
- 0, 10, 10, 7, MST_ORC_HIGH_PRIEST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 10, MST_ORC_HIGH_PRIEST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_FRANCES, '@', YELLOW, "Frances",
@@ -3219,12 +2973,11 @@
| M_SEE_INVIS | M_EVIL | M_UNIQUE,
MR_NO_FLAGS,
0, 20, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -5,
- { {AT_HIT, AF_PLAIN, 29}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 29}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 14, 0, 0, 121 },
- 0, 10, 10, 7, MST_ORC_HIGH_PRIEST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 10, MST_ORC_HIGH_PRIEST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_RUPERT, '@', RED, "Rupert",
@@ -3232,12 +2985,11 @@
| M_SEE_INVIS | M_UNIQUE,
MR_RES_ELEC,
0, 20, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -5,
- { {AT_HIT, AF_PLAIN, 21}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 21}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 16, 0, 0, 123 },
- 0, 10, 10, 7, MST_RUPERT, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 10, MST_RUPERT, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_WAYNE, '@', YELLOW, "Wayne",
@@ -3245,12 +2997,11 @@
| M_SEE_INVIS | M_UNIQUE,
MR_NO_FLAGS,
0, 20, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -5,
- { {AT_HIT, AF_PLAIN, 22}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 22}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 17, 0, 0, 140 },
- 1, 10, 7, 7, MST_ORC_PRIEST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 1, 10, MST_ORC_PRIEST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 7, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_DUANE, '@', YELLOW, "Duane",
@@ -3258,24 +3009,22 @@
| M_SEE_INVIS | M_UNIQUE,
MR_NO_FLAGS,
0, 20, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -5,
- { {AT_HIT, AF_PLAIN, 22}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 22}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 18, 0, 0, 136 },
- 0, 10, 10, 7, MST_ORC_WIZARD_I, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 10, MST_ORC_WIZARD_I, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_XTAHUA, 'D', RED, "Xtahua",
M_SEE_INVIS | M_FLIES | M_SPECIAL_ABILITY | M_UNIQUE,
MR_RES_POISON | MR_RES_FIRE | MR_VUL_COLD,
0, 20, MONS_DRAGON, MONS_DRAGON, MH_NATURAL, -7,
- { {AT_BITE, AF_PLAIN, 35}, {AT_CLAW, AF_PLAIN, 20}, {AT_CLAW, AF_PLAIN, 17}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 35}, {AT_CLAW, AF_PLAIN, 20}, {AT_CLAW, AF_PLAIN, 17}, AT_NO_ATK },
{ 19, 0, 0, 133 },
- 15, 7, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_HUGE
-}
-,
+ 15, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_HUGE
+},
{
MONS_NORRIS, '@', LIGHTRED, "Norris",
@@ -3283,12 +3032,11 @@
| M_SEE_INVIS | M_EVIL | M_UNIQUE,
MR_NO_FLAGS,
0, 20, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -5,
- { {AT_HIT, AF_PLAIN, 36}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 36}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 20, 0, 0, 214 },
- 1, 9, 9, 7, MST_MYSTIC, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 1, 9, MST_MYSTIC, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 9, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_FREDERICK, '@', DARKGREY, "Frederick",
@@ -3296,12 +3044,11 @@
| M_SEE_INVIS | M_EVIL | M_UNIQUE,
MR_NO_FLAGS,
0, 20, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -5,
- { {AT_HIT, AF_PLAIN, 27}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 27}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 21, 0, 0, 159 },
- 0, 10, 10, 7, MST_LICH_IV, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 10, MST_LICH_IV, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_MARGERY, '@', RED, "Margery",
@@ -3309,12 +3056,11 @@
| M_SEE_INVIS | M_UNIQUE,
MR_NO_FLAGS,
0, 20, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -5,
- { {AT_HIT, AF_PLAIN, 30}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 30}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 22, 0, 0, 164 },
- 0, 10, 10, 7, MST_EFREET, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 0, 10, MST_EFREET, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_BORIS, 'L', RED, "Boris",
@@ -3322,49 +3068,45 @@
| M_UNIQUE,
MR_RES_POISON | MR_RES_COLD | MR_RES_ELEC,
0, 23, MONS_LICH, MONS_LICH, MH_UNDEAD, -11,
- { {AT_HIT, AF_PLAIN, 25}, {AT_TOUCH, AF_DRAIN_XP, 15}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 25}, {AT_TOUCH, AF_DRAIN_XP, 15}, AT_NO_ATK, AT_NO_ATK },
{ 22, 0, 0, 154 },
- 12, 10, 10, 7, MST_LICH_IV, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
- MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
-}
-,
-
+ 12, 10, MST_LICH_IV, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
+},
{
MONS_GERYON, '&', GREEN, "Geryon",
- M_FIGHTER | M_SPELLCASTER | M_SEE_INVIS | M_SPEAKS | M_EVIL | M_UNIQUE,
+ M_FIGHTER | M_SPELLCASTER | M_SEE_INVIS | M_SPEAKS | M_EVIL | M_FLIES
+ | M_UNIQUE,
MR_NO_FLAGS,
0, 25, MONS_GERYON, MONS_GERYON, MH_DEMONIC, -6,
- { {AT_HIT, AF_PLAIN, 35}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 35}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 15, 0, 0, 240 },
- 15, 6, 10, 7, MST_GERYON, CE_CONTAMINATED, Z_NOZOMBIE, S_ROAR, I_NORMAL,
- MONUSE_STARTING_EQUIPMENT, SIZE_GIANT,
-}
-,
+ 15, 6, MST_GERYON, CE_CONTAMINATED, Z_NOZOMBIE, S_ROAR, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_GIANT,
+},
{
MONS_DISPATER, '&', MAGENTA, "Dispater",
M_FIGHTER | M_SPELLCASTER | M_SEE_INVIS | M_SPEAKS | M_EVIL | M_UNIQUE,
MR_RES_ELEC | MR_RES_POISON | MR_RES_HELLFIRE | MR_RES_COLD,
0, 25, MONS_DISPATER, MONS_DISPATER, MH_DEMONIC, -10,
- { {AT_HIT, AF_PLAIN, 50}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 50}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 16, 0, 0, 222 },
- 15, 3, 6, 7, MST_DISPATER, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_LARGE
-}
-,
+ 15, 3, MST_DISPATER, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ 6, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_LARGE
+},
{
MONS_ASMODEUS, '&', LIGHTMAGENTA, "Asmodeus",
M_FIGHTER | M_SPELLCASTER | M_FLIES | M_SEE_INVIS | M_SPEAKS | M_EVIL | M_UNIQUE,
MR_RES_ELEC | MR_RES_POISON | MR_RES_HELLFIRE,
0, 25, MONS_ASMODEUS, MONS_ASMODEUS, MH_DEMONIC, -12,
- { {AT_HIT, AF_PLAIN, 50}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 50}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 17, 0, 0, 245 },
- 12, 7, 9, 7, MST_ASMODEUS, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_LARGE
-}
-,
+ 12, 7, MST_ASMODEUS, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ 9, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_LARGE
+},
// Antaeus is now demonic so that he'll resist torment. -- bwr
{
@@ -3372,36 +3114,34 @@
M_FIGHTER | M_SPELLCASTER | M_SPEAKS | M_UNIQUE,
MR_RES_ELEC | MR_VUL_FIRE | MR_RES_COLD,
0, 25, MONS_HILL_GIANT, MONS_ANTAEUS, MH_DEMONIC, -9,
- { {AT_HIT, AF_COLD, 75}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_COLD, 75}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 22, 0, 0, 250 },
- 10, 4, 7, 7, MST_ANTAEUS, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_GIANT,
-}
-,
+ 10, 4, MST_ANTAEUS, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ 7, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_GIANT,
+},
{
MONS_ERESHKIGAL, '&', WHITE, "Ereshkigal",
M_SPELLCASTER | M_SEE_INVIS | M_SPEAKS | M_EVIL | M_UNIQUE,
MR_RES_ELEC | MR_RES_POISON | MR_RES_COLD,
0, 25, MONS_ERESHKIGAL, MONS_ERESHKIGAL, MH_DEMONIC, -10,
- { {AT_HIT, AF_PLAIN, 40}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 40}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 18, 0, 0, 238 },
- 15, 6, 9, 7, MST_ERESHKIGAL, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_LARGE
-}
-,
+ 15, 6, MST_ERESHKIGAL, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ 9, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_LARGE
+},
{
MONS_ANCIENT_LICH, 'L', DARKGREY, "ancient lich",
M_SPELLCASTER | M_ACTUAL_SPELLS | M_SEE_INVIS | M_EVIL,
MR_RES_POISON | MR_RES_COLD | MR_RES_FIRE | MR_RES_ELEC,
0, 20, MONS_LICH, MONS_LICH, MH_UNDEAD, -14,
- { {AT_TOUCH, AF_DRAIN_XP, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_TOUCH, AF_DRAIN_XP, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 27, 2, 4, 0 },
- 20, 10, 12, 7, MST_LICH_I, CE_NOCORPSE, Z_NOZOMBIE, S_SHOUT, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 20, 10, MST_LICH_I, CE_NOCORPSE, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ 12, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
+
/* number is set in define_monster */
{
@@ -3409,24 +3149,22 @@
M_NO_SKELETON | M_SENSE_INVIS,
MR_RES_POISON | MR_RES_ASPHYX | MR_RES_ACID,
0, 5, MONS_JELLY, MONS_OOZE, MH_NATURAL, -6,
- { {AT_HIT, AF_PLAIN, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 5}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 3, 3, 5, 0 },
- 1, 3, 8, 7, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_LITTLE,
-}
-,
+ 1, 3, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 8, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LITTLE,
+},
{
MONS_VAULT_GUARD, '@', CYAN, "vault guard",
M_FIGHTER | M_WARM_BLOOD | M_SENSE_INVIS,
MR_NO_FLAGS,
0, 12, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 13, 3, 5, 0 },
- 1, 13, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 1, 13, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
/* These nasties are never randomly generated, only sometimes specially
placed in the Crypt. */
@@ -3435,72 +3173,66 @@
M_LEVITATE | M_SPELLCASTER | M_SEE_INVIS | M_EVIL,
MR_RES_ELEC | MR_RES_POISON | MR_RES_HELLFIRE | MR_RES_COLD,
0, 50, MONS_LICH, MONS_CURSE_SKULL, MH_UNDEAD, MAG_IMMUNE,
- { {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 13, 0, 0, 66 },
- 40, 3, 10, 7, MST_CURSE_SKULL, CE_NOCORPSE, Z_NOZOMBIE, S_MOAN, I_HIGH,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 40, 3, MST_CURSE_SKULL, CE_NOCORPSE, Z_NOZOMBIE, S_MOAN, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_VAMPIRE_KNIGHT, 'V', CYAN, "vampire knight",
M_FIGHTER | M_SPELLCASTER | M_SEE_INVIS | M_EVIL,
MR_RES_POISON | MR_RES_COLD,
0, 13, MONS_VAMPIRE, MONS_VAMPIRE, MH_UNDEAD, -6,
- { {AT_HIT, AF_PLAIN, 33}, {AT_BITE, AF_VAMPIRIC, 15}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 33}, {AT_BITE, AF_VAMPIRIC, 15}, AT_NO_ATK, AT_NO_ATK },
{ 11, 3, 7, 0 },
- 10, 10, 10, 7, MST_VAMPIRE_KNIGHT, CE_NOCORPSE, Z_NOZOMBIE, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 10, 10, MST_VAMPIRE_KNIGHT, CE_NOCORPSE, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_VAMPIRE_MAGE, 'V', MAGENTA, "vampire mage",
M_SPELLCASTER | M_SEE_INVIS | M_FLIES | M_EVIL,
MR_RES_POISON | MR_RES_COLD,
0, 15, MONS_VAMPIRE, MONS_VAMPIRE, MH_UNDEAD, -6,
- { {AT_BITE, AF_VAMPIRIC, 22}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_VAMPIRIC, 22}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 8, 3, 4, 0 },
- 10, 10, 10, 7, MST_VAMPIRE_MAGE, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 10, 10, MST_VAMPIRE_MAGE, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_SHINING_EYE, 'G', LIGHTMAGENTA, "shining eye",
M_NO_SKELETON | M_LEVITATE | M_SPELLCASTER | M_SEE_INVIS,
MR_RES_ASPHYX,
0, 14, MONS_SHINING_EYE, MONS_SHINING_EYE, MH_NATURAL, MAG_IMMUNE,
- { {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 10, 3, 5, 0 },
- 3, 1, 7, 7, MST_SHINING_EYE, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_MEDIUM
-}
-,
+ 3, 1, MST_SHINING_EYE, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 7, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_MEDIUM
+},
{
MONS_ORB_GUARDIAN, 'X', MAGENTA, "Orb Guardian",
M_FIGHTER | M_NO_SKELETON | M_SEE_INVIS,
MR_NO_FLAGS,
0, 20, MONS_ORB_GUARDIAN, MONS_ORB_GUARDIAN, MH_NATURAL, -6,
- { {AT_HIT, AF_PLAIN, 45}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 45}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 15, 3, 5, 0 },
- 13, 13, 14, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_OPEN_DOORS, SIZE_GIANT,
-}
-,
+ 13, 13, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 14, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_GIANT,
+},
{
MONS_DAEVA, 'A', YELLOW, "Daeva",
M_FIGHTER | M_LEVITATE | M_SPELLCASTER | M_SEE_INVIS,
MR_RES_POISON,
0, 12, MONS_ANGEL, MONS_DAEVA, MH_HOLY, -8,
- { {AT_HIT, AF_PLAIN, 25}, {AT_HIT, AF_PLAIN, 10}, {AT_HIT, AF_PLAIN, 10}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 25}, {AT_HIT, AF_PLAIN, 10}, {AT_HIT, AF_PLAIN, 10}, AT_NO_ATK },
{ 14, 6, 5, 0 },
- 10, 13, 10, 7, MST_DAEVA, CE_NOCORPSE, Z_NOZOMBIE, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 10, 13, MST_DAEVA, CE_NOCORPSE, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
/* spectral thing - similar to zombies/skeletons */
{
@@ -3508,36 +3240,33 @@
M_LEVITATE | M_SEE_INVIS,
MR_RES_POISON | MR_RES_COLD,
0, 11, MONS_WRAITH, MONS_SPECTRAL_THING, MH_UNDEAD, MAG_IMMUNE,
- { {AT_HIT, AF_DRAIN_XP, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_DRAIN_XP, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 8, 3, 5, 0 },
- 8, 5, 7, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 8, 5, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 7, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
{
MONS_GREATER_NAGA, 'N', RED, "greater naga",
M_FIGHTER | M_SPELLCASTER | M_ACTUAL_SPELLS | M_SEE_INVIS | M_WARM_BLOOD,
MR_RES_POISON,
750, 10, MONS_NAGA, MONS_NAGA, MH_NATURAL, MAG_IMMUNE,
- { {AT_HIT, AF_PLAIN, 24}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 24}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 15, 3, 5, 0 },
- 6, 10, 8, 7, MST_NAGA_MAGE, CE_POISONOUS, Z_SMALL, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_BIG
-}
-,
+ 6, 10, MST_NAGA_MAGE, CE_POISONOUS, Z_SMALL, S_SHOUT, I_HIGH,
+ 8, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_BIG
+},
{
MONS_SKELETAL_DRAGON, 'D', LIGHTGREY, "skeletal dragon",
M_SENSE_INVIS | M_EVIL,
MR_RES_POISON | MR_RES_FIRE | MR_RES_COLD | MR_RES_ELEC,
0, 12, MONS_SKELETAL_WARRIOR, MONS_SKELETAL_DRAGON, MH_UNDEAD, -4,
- { {AT_BITE, AF_PLAIN, 30}, {AT_CLAW, AF_PLAIN, 20}, {AT_CLAW, AF_PLAIN, 20}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 30}, {AT_CLAW, AF_PLAIN, 20}, {AT_CLAW, AF_PLAIN, 20}, AT_NO_ATK },
{ 20, 8, 8, 0 },
- 20, 4, 8, 7, MST_NO_SPELLS, CE_CLEAN, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_OPEN_DOORS, SIZE_HUGE
-}
-,
+ 20, 4, MST_NO_SPELLS, CE_CLEAN, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 8, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_HUGE
+},
{
MONS_TENTACLED_MONSTROSITY, 'X', GREEN, "tentacled monstrosity",
@@ -3546,82 +3275,75 @@
0, 10, MONS_TENTACLED_MONSTROSITY, MONS_TENTACLED_MONSTROSITY, MH_NATURAL, -5,
{ {AT_HIT, AF_PLAIN, 22}, {AT_HIT, AF_PLAIN, 17}, {AT_HIT, AF_PLAIN, 13} },
{ 25, 3, 5, 0 },
- 5, 5, 9, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_GIANT,
-}
-,
+ 5, 5, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ 9, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_GIANT,
+},
{
MONS_SPHINX, 'H', LIGHTGREY, "sphinx",
M_FLIES | M_SENSE_INVIS | M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD,
MR_NO_FLAGS,
0, 10, MONS_SPHINX, MONS_SPHINX, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 25}, {AT_HIT, AF_PLAIN, 12}, {AT_HIT, AF_PLAIN, 12}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 25}, {AT_HIT, AF_PLAIN, 12}, {AT_HIT, AF_PLAIN, 12}, AT_NO_ATK },
{ 16, 3, 5, 0 },
- 5, 5, 13, 7, MST_SPHINX, CE_CLEAN, Z_NOZOMBIE, S_SHOUT, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_BIG
-}
-,
+ 5, 5, MST_SPHINX, CE_CLEAN, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ 13, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_BIG
+},
{
MONS_ROTTING_HULK, 'n', BROWN, "rotting hulk",
M_EVIL,
MR_RES_POISON | MR_RES_COLD,
0, 12, MONS_GHOUL, MONS_ROTTING_HULK, MH_UNDEAD, -5,
- { {AT_HIT, AF_DISEASE, 25}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_DISEASE, 25}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 10, 3, 5, 0 },
- 5, 7, 8, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 5, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ 8, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_GUARDIAN_MUMMY, 'M', YELLOW, "guardian mummy",
M_FIGHTER | M_SEE_INVIS | M_EVIL,
MR_RES_POISON | MR_RES_COLD,
0, 13, MONS_MUMMY, MONS_GUARDIAN_MUMMY, MH_UNDEAD, -5,
- { {AT_HIT, AF_PLAIN, 30}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 30}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 7, 5, 3, 0 },
- 6, 9, 9, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_WEAPONS_ARMOUR, SIZE_BIG
-}
-,
+ 6, 9, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 9, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_BIG
+},
{
MONS_GREATER_MUMMY, 'M', DARKGREY, "greater mummy",
M_SPELLCASTER | M_ACTUAL_SPELLS | M_SEE_INVIS | M_EVIL,
MR_RES_POISON | MR_RES_COLD | MR_RES_ELEC,
0, 20, MONS_MUMMY, MONS_MUMMY, MH_UNDEAD, MAG_IMMUNE,
- { {AT_HIT, AF_PLAIN, 35}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 35}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 15, 5, 3, 100 },
- 10, 6, 10, 7, MST_MUMMY, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 10, 6, MST_MUMMY, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_MUMMY_PRIEST, 'M', RED, "mummy priest",
M_SPELLCASTER | M_PRIEST | M_SEE_INVIS | M_EVIL,
MR_RES_POISON | MR_RES_COLD | MR_RES_ELEC,
0, 16, MONS_MUMMY, MONS_MUMMY, MH_UNDEAD, MAG_IMMUNE,
- { {AT_HIT, AF_PLAIN, 30}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 30}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 10, 5, 3, 0 },
- 8, 7, 9, 7, MST_MUMMY, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 8, 7, MST_MUMMY, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ 9, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{
MONS_CENTAUR_WARRIOR, 'c', YELLOW, "centaur warrior",
M_WARM_BLOOD | M_FIGHTER,
MR_NO_FLAGS,
1500, 12, MONS_CENTAUR, MONS_CENTAUR, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 16}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 16}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 9, 3, 5, 0 },
- 4, 8, 15, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_BIG
-}
-,
+ 4, 8, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SHOUT, I_HIGH,
+ 15, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_BIG
+},
{
MONS_YAKTAUR_CAPTAIN, 'c', RED, "yaktaur captain",
@@ -3630,10 +3352,9 @@
2000, 10, MONS_YAKTAUR, MONS_YAKTAUR, MH_NATURAL, -3,
{ {AT_HIT, AF_PLAIN, 23}, {AT_HIT, AF_PLAIN, 0}, {AT_HIT, AF_PLAIN, 0} },
{ 14, 3, 5, 0 },
- 5, 5, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SHOUT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
+ 5, 5, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
{ // Base draconian -- for use like MONS_HUMAN, MONS_ELF although we
// now store the draconian subspecies in the high byte of mon->number
@@ -3644,10 +3365,9 @@
900, 10, MONS_DRACONIAN, MONS_DRACONIAN, MH_NATURAL, -1,
{ {AT_HIT, AF_PLAIN, 15}, {AT_HIT, AF_PLAIN, 0}, {AT_HIT, AF_PLAIN, 0} },
{ 3, 6, 4, 0 },
- 7, 8, 10, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
- MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
-}
-,
+ 7, 8, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
+},
{
MONS_BLACK_DRACONIAN, 'd', DARKGREY, "black draconian",
@@ -3656,10 +3376,9 @@
900, 10, MONS_DRACONIAN, MONS_BLACK_DRACONIAN, MH_NATURAL, -2,
{ {AT_HIT, AF_PLAIN, 20}, {AT_HIT, AF_PLAIN, 0}, {AT_HIT, AF_PLAIN, 0} },
{ 14, 5, 4, 0 },
- 9, 10, 10, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
- MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
-}
-,
+ 9, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
+},
{
MONS_YELLOW_DRACONIAN, 'd', YELLOW, "yellow draconian",
@@ -3668,10 +3387,9 @@
900, 10, MONS_DRACONIAN, MONS_YELLOW_DRACONIAN, MH_NATURAL, -2,
{ {AT_HIT, AF_PLAIN, 20}, {AT_HIT, AF_PLAIN, 0}, {AT_HIT, AF_PLAIN, 0} },
{ 14, 5, 4, 0 },
- 9, 10, 10, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
- MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
-}
-,
+ 9, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
+},
{
MONS_PALE_DRACONIAN, 'd', LIGHTGREY, "pale draconian",
@@ -3680,10 +3398,9 @@
900, 10, MONS_DRACONIAN, MONS_PALE_DRACONIAN, MH_NATURAL, -2,
{ {AT_HIT, AF_PLAIN, 20}, {AT_HIT, AF_PLAIN, 0}, {AT_HIT, AF_PLAIN, 0} },
{ 14, 5, 4, 0 },
- 9, 14, 10, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
- MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
-}
-,
+ 9, 14, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
+},
{
MONS_GREEN_DRACONIAN, 'd', LIGHTGREEN, "green draconian",
@@ -3692,10 +3409,9 @@
900, 10, MONS_DRACONIAN, MONS_GREEN_DRACONIAN, MH_NATURAL, -2,
{ {AT_HIT, AF_PLAIN, 20}, {AT_HIT, AF_PLAIN, 0}, {AT_HIT, AF_PLAIN, 0} },
{ 14, 5, 4, 0 },
- 9, 10, 10, 10, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_ROAR, I_HIGH,
- MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
-}
-,
+ 9, 10, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_ROAR, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
+},
{
MONS_PURPLE_DRACONIAN, 'd', MAGENTA, "purple draconian",
@@ -3704,10 +3420,9 @@
900, 10, MONS_DRACONIAN, MONS_PURPLE_DRACONIAN, MH_NATURAL, -2,
{ {AT_HIT, AF_PLAIN, 20}, {AT_HIT, AF_PLAIN, 0}, {AT_HIT, AF_PLAIN, 0} },
{ 14, 5, 4, 0 },
- 8, 10, 10, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
- MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
-}
-,
+ 8, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
+},
{
MONS_RED_DRACONIAN, 'd', RED, "red draconian",
@@ -3716,10 +3431,9 @@
900, 10, MONS_DRACONIAN, MONS_RED_DRACONIAN, MH_NATURAL, -2,
{ {AT_HIT, AF_PLAIN, 20}, {AT_HIT, AF_PLAIN, 0}, {AT_HIT, AF_PLAIN, 0} },
{ 14, 5, 4, 0 },
- 9, 10, 10, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
- MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
-}
-,
+ 9, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
+},
{
MONS_WHITE_DRACONIAN, 'd', WHITE, "white draconian",
@@ -3728,10 +3442,9 @@
900, 10, MONS_DRACONIAN, MONS_WHITE_DRACONIAN, MH_NATURAL, -2,
{ {AT_HIT, AF_PLAIN, 20}, {AT_HIT, AF_PLAIN, 0}, {AT_HIT, AF_PLAIN, 0} },
{ 14, 5, 4, 0 },
- 9, 10, 10, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
- MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
-}
-,
+ 9, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
+},
{
MONS_MOTTLED_DRACONIAN, 'd', LIGHTMAGENTA, "mottled draconian",
@@ -3740,10 +3453,9 @@
900, 10, MONS_DRACONIAN, MONS_MOTTLED_DRACONIAN, MH_NATURAL, -2,
{ {AT_HIT, AF_PLAIN, 20}, {AT_HIT, AF_PLAIN, 0}, {AT_HIT, AF_PLAIN, 0} },
{ 14, 5, 4, 0 },
- 9, 10, 10, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
- MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
-}
-,
+ 9, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
+},
{
MONS_DRACONIAN_CALLER, 'd', BROWN, "draconian caller",
@@ -3752,10 +3464,9 @@
900, 10, MONS_DRACONIAN, MONS_DRACONIAN, MH_NATURAL, -3,
{ {AT_HIT, AF_PLAIN, 20}, {AT_HIT, AF_PLAIN, 0}, {AT_HIT, AF_PLAIN, 0} },
{ 16, 4, 3, 0 },
- 9, 10, 10, 10, MST_DRAC_CALLER, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
- MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
-}
-,
+ 9, 10, MST_DRAC_CALLER, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
+},
{
MONS_DRACONIAN_MONK, 'd', BLUE, "draconian monk",
@@ -3765,10 +3476,9 @@
{ {AT_HIT, AF_PLAIN, 35}, {AT_HIT, AF_PLAIN, 20},
{AT_TAIL_SLAP, AF_PLAIN, 15} },
{ 16, 6, 3, 0 },
- 6, 20, 10, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
- MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
-}
-,
+ 6, 20, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
+},
{
MONS_DRACONIAN_ZEALOT, 'd', LIGHTBLUE, "draconian zealot",
@@ -3777,10 +3487,9 @@
900, 10, MONS_DRACONIAN, MONS_DRACONIAN, MH_NATURAL, -3,
{ {AT_HIT, AF_PLAIN, 15}, {AT_HIT, AF_PLAIN, 0}, {AT_HIT, AF_PLAIN, 0} },
{ 16, 4, 2, 0 },
- 12, 10, 10, 10, MST_DEEP_ELF_HIGH_PRIEST, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
- MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
-}
-,
+ 12, 10, MST_DEEP_ELF_HIGH_PRIEST, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
+},
{
MONS_DRACONIAN_SHIFTER, 'd', LIGHTCYAN, "draconian shifter",
@@ -3789,10 +3498,9 @@
900, 10, MONS_DRACONIAN, MONS_DRACONIAN, MH_NATURAL, -4,
{ {AT_HIT, AF_PLAIN, 15}, {AT_HIT, AF_PLAIN, 0}, {AT_HIT, AF_PLAIN, 0} },
{ 16, 4, 4, 0 },
- 8, 16, 10, 10, MST_DRAC_SHIFTER, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
- MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
-}
-,
+ 8, 16, MST_DRAC_SHIFTER, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
+},
{
MONS_DRACONIAN_ANNIHILATOR, 'd', GREEN, "draconian annihilator",
@@ -3801,10 +3509,9 @@
900, 10, MONS_DRACONIAN, MONS_DRACONIAN, MH_NATURAL, -4,
{ {AT_HIT, AF_PLAIN, 15}, {AT_HIT, AF_PLAIN, 0}, {AT_HIT, AF_PLAIN, 0} },
{ 16, 4, 2, 0 },
- 8, 10, 10, 10, MST_DEEP_ELF_ANNIHILATOR, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
- MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
-}
-,
+ 8, 10, MST_DEEP_ELF_ANNIHILATOR, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
+},
{
MONS_DRACONIAN_KNIGHT, 'd', CYAN, "draconian knight",
@@ -3813,10 +3520,9 @@
900, 10, MONS_DRACONIAN, MONS_DRACONIAN, MH_NATURAL, -4,
{ {AT_HIT, AF_PLAIN, 15}, {AT_HIT, AF_PLAIN, 0}, {AT_HIT, AF_PLAIN, 0} },
{ 16, 6, 4, 0 },
- 12, 12, 10, 6, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
- MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
-}
-,
+ 12, 12, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
+},
{
MONS_DRACONIAN_SCORCHER, 'd', LIGHTRED, "draconian scorcher",
@@ -3825,22 +3531,20 @@
900, 10, MONS_DRACONIAN, MONS_DRACONIAN, MH_NATURAL, -4,
{ {AT_HIT, AF_PLAIN, 15}, {AT_HIT, AF_PLAIN, 0}, {AT_HIT, AF_PLAIN, 0} },
{ 16, 4, 2, 0 },
- 8, 12, 10, 10, MST_DRAC_SCORCHER, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
- MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
-}
-,
+ 8, 12, MST_DRAC_SCORCHER, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
+},
{
MONS_KILLER_KLOWN, '@', BLACK, "Killer Klown",
M_SEE_INVIS | M_SPEAKS | M_WARM_BLOOD | M_SPECIAL_ABILITY,
MR_NO_FLAGS,
0, 15, MONS_HUMAN, MONS_KILLER_KLOWN, MH_NATURAL, -6,
- { {AT_HIT, AF_KLOWN, 30}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_KLOWN, 30}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 20, 5, 5, 0 },
- 10, 15, 15, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 10, 15, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ 15, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
{
MONS_ELECTRIC_GOLEM, '8', LIGHTCYAN, "electric golem",
@@ -3849,94 +3553,87 @@
0, 10, MONS_CLAY_GOLEM, MONS_ELECTRIC_GOLEM, MH_NONLIVING, -8,
{ {AT_HIT, AF_ELEC, 15}, {AT_HIT, AF_ELEC, 15}, {AT_HIT, AF_PLAIN, 15}, {AT_HIT, AF_PLAIN, 15} },
{ 15, 7, 4, 0 },
- 5, 20, 20, 7, MST_ELECTRIC_GOLEM, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 5, 20, MST_ELECTRIC_GOLEM, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 20, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
{
MONS_BALL_LIGHTNING, '*', LIGHTCYAN, "ball lightning",
M_FLIES | M_CONFUSED | M_SPELLCASTER | M_SPECIAL_ABILITY,
MR_RES_ELEC,
0, 20, MONS_BALL_LIGHTNING, MONS_BALL_LIGHTNING, MH_NONLIVING, MAG_IMMUNE,
- { {AT_HIT, AF_PLAIN, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 5}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 12, 0, 0, 1 },
- 0, 10, 20, 7, MST_STORM_DRAGON, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_PLANT,
- MONUSE_OPEN_DOORS, SIZE_LITTLE,
-}
-,
+ 0, 10, MST_STORM_DRAGON, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_PLANT,
+ 20, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LITTLE,
+},
{
MONS_ORB_OF_FIRE, '*', RED, "orb of fire",
M_SPELLCASTER | M_FLIES | M_SEE_INVIS,
MR_RES_ELEC | MR_RES_FIRE | MR_RES_HELLFIRE | MR_RES_COLD | MR_RES_POISON,
0, 10, MONS_ORB_OF_FIRE, MONS_ORB_OF_FIRE, MH_NONLIVING, MAG_IMMUNE,
- { {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 30, 0, 0, 150 },
- 20, 20, 20, 7, MST_ORB_OF_FIRE, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_LITTLE,
-}
-,
+ 20, 20, MST_ORB_OF_FIRE, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL,
+ 20, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LITTLE,
+},
{
MONS_QUOKKA, 'r', LIGHTGREY, "quokka",
M_WARM_BLOOD,
MR_NO_FLAGS,
300, 10, MONS_QUOKKA, MONS_QUOKKA, MH_NATURAL, -1,
- { {AT_BITE, AF_PLAIN, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 5}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 1, 3, 5, 0 },
- 2, 13, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_NORMAL,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 2, 13, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_ANIMAL,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_EYE_OF_DEVASTATION, 'G', YELLOW, "eye of devastation",
M_NO_SKELETON | M_LEVITATE | M_SPELLCASTER | M_SEE_INVIS,
MR_RES_ASPHYX,
0, 11, MONS_GIANT_EYEBALL, MONS_EYE_OF_DEVASTATION, MH_NATURAL, MAG_IMMUNE,
- { {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 10, 3, 5, 0 },
- 12, 1, 7, 7, MST_EYE_OF_DEVASTATION, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_BIG
-}
-,
+ 12, 1, MST_EYE_OF_DEVASTATION, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 7, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_BIG
+},
{
MONS_MOTH_OF_WRATH, 'y', BROWN, "moth of wrath",
M_FLIES | M_SPECIAL_ABILITY,
MR_NO_FLAGS,
0, 10, MONS_MOTH_OF_WRATH, MONS_MOTH_OF_WRATH, MH_NATURAL, -3,
- { {AT_BITE, AF_RAGE, 25}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_RAGE, 25}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 9, 3, 5, 0 },
- 0, 10, 12, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SHOUT, I_HIGH,
- MONUSE_NOTHING, SIZE_MEDIUM
-}
-,
+ 0, 10, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SHOUT, I_HIGH,
+ 12, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_MEDIUM
+},
{
MONS_DEATH_COB, '%', YELLOW, "death cob",
M_SPEAKS | M_EVIL,
MR_RES_POISON | MR_RES_COLD,
0, 10, MONS_DEATH_COB, MONS_DEATH_COB, MH_UNDEAD, -3,
- { {AT_HIT, AF_PLAIN, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 10, 4, 5, 0 },
- 10, 15, 25, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_MOAN, I_NORMAL,
- MONUSE_OPEN_DOORS, SIZE_TINY
-}
-,
+ 10, 15, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_MOAN, I_NORMAL,
+ 25, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_TINY
+},
+// Curse toes move at half the speed with which they attack.
{
MONS_CURSE_TOE, 'z', YELLOW, "curse toe",
M_LEVITATE | M_SPELLCASTER | M_SEE_INVIS | M_EVIL,
MR_RES_ELEC | MR_RES_POISON | MR_RES_HELLFIRE | MR_RES_COLD,
0, 60, MONS_LICH, MONS_CURSE_TOE, MH_UNDEAD, MAG_IMMUNE,
- { {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 14, 0, 0, 77 },
- 50, 1, 12, 7, MST_CURSE_TOE, CE_NOCORPSE, Z_NOZOMBIE, S_MOAN, I_HIGH,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 50, 1, MST_CURSE_TOE, CE_NOCORPSE, Z_NOZOMBIE, S_MOAN, I_HIGH,
+ 12, MOVE_ENERGY(20), MONUSE_NOTHING, SIZE_TINY
+},
{
// gold mimics are the only mimics that actually use their name -- bwr
@@ -3944,133 +3641,121 @@
M_NO_SKELETON,
MR_RES_POISON | MR_RES_ELEC | MR_RES_FIRE | MR_RES_COLD,
0, 13, MONS_GOLD_MIMIC, MONS_GOLD_MIMIC, MH_NONLIVING, -3,
- { {AT_HIT, AF_POISON, 12}, {AT_HIT, AF_PLAIN, 12}, {AT_HIT, AF_PLAIN, 12}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_POISON, 12}, {AT_HIT, AF_PLAIN, 12}, {AT_HIT, AF_PLAIN, 12}, AT_NO_ATK },
{ 8, 3, 5, 0 },
- 5, 1, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 5, 1, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_WEAPON_MIMIC, ')', BLACK, "mimic",
M_NO_SKELETON,
MR_RES_POISON | MR_RES_ELEC | MR_RES_FIRE | MR_RES_COLD,
0, 13, MONS_GOLD_MIMIC, MONS_GOLD_MIMIC, MH_NONLIVING, -3,
- { {AT_HIT, AF_POISON, 17}, {AT_HIT, AF_PLAIN, 17}, {AT_HIT, AF_PLAIN, 17}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_POISON, 17}, {AT_HIT, AF_PLAIN, 17}, {AT_HIT, AF_PLAIN, 17}, AT_NO_ATK },
{ 8, 3, 5, 0 },
- 5, 1, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
- MONUSE_NOTHING, SIZE_LITTLE,
-}
-,
+ 5, 1, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LITTLE,
+},
{
MONS_ARMOUR_MIMIC, '[', BLACK, "mimic",
M_NO_SKELETON,
MR_RES_POISON | MR_RES_ELEC | MR_RES_FIRE | MR_RES_COLD,
0, 13, MONS_GOLD_MIMIC, MONS_GOLD_MIMIC, MH_NONLIVING, -3,
- { {AT_HIT, AF_POISON, 12}, {AT_HIT, AF_PLAIN, 12}, {AT_HIT, AF_PLAIN, 12}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_POISON, 12}, {AT_HIT, AF_PLAIN, 12}, {AT_HIT, AF_PLAIN, 12}, AT_NO_ATK },
{ 8, 3, 5, 0 },
- 15, 1, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
- MONUSE_NOTHING, SIZE_SMALL
-}
-,
+ 15, 1, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_SMALL
+},
{
MONS_SCROLL_MIMIC, '?', LIGHTGREY, "mimic",
M_NO_SKELETON,
MR_RES_POISON | MR_RES_ELEC | MR_RES_FIRE | MR_RES_COLD,
0, 13, MONS_GOLD_MIMIC, MONS_GOLD_MIMIC, MH_NONLIVING, -3,
- { {AT_HIT, AF_POISON, 12}, {AT_HIT, AF_PLAIN, 12}, {AT_HIT, AF_PLAIN, 12}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_POISON, 12}, {AT_HIT, AF_PLAIN, 12}, {AT_HIT, AF_PLAIN, 12}, AT_NO_ATK },
{ 8, 3, 5, 0 },
- 5, 1, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 5, 1, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_POTION_MIMIC, '!', BLACK, "mimic",
M_NO_SKELETON,
MR_RES_POISON | MR_RES_ELEC | MR_RES_FIRE | MR_RES_COLD,
0, 13, MONS_GOLD_MIMIC, MONS_GOLD_MIMIC, MH_NONLIVING, -3,
- { {AT_HIT, AF_POISON, 12}, {AT_HIT, AF_PLAIN, 12}, {AT_HIT, AF_PLAIN, 12}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_POISON, 12}, {AT_HIT, AF_PLAIN, 12}, {AT_HIT, AF_PLAIN, 12}, AT_NO_ATK },
{ 8, 3, 5, 0 },
- 5, 1, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 5, 1, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_HELL_HOG, 'h', RED, "hell-hog",
M_SPELLCASTER | M_THICK_SKIN | M_EVIL,
MR_NO_FLAGS,
0, 10, MONS_HELL_HOG, MONS_HELL_HOG, MH_DEMONIC, -3,
- { {AT_BITE, AF_PLAIN, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 11, 3, 5, 0 },
- 2, 9, 14, 7, MST_HELL_HOG, CE_CLEAN, Z_NOZOMBIE, S_SILENT, I_ANIMAL,
- MONUSE_NOTHING, SIZE_MEDIUM
-}
-,
+ 2, 9, MST_HELL_HOG, CE_CLEAN, Z_NOZOMBIE, S_SILENT, I_ANIMAL,
+ 14, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_MEDIUM
+},
{
MONS_SERPENT_OF_HELL, 'D', RED, "Serpent of Hell",
M_SPELLCASTER | M_FLIES | M_SENSE_INVIS | M_EVIL,
MR_RES_POISON | MR_RES_HELLFIRE,
0, 18, MONS_SERPENT_OF_HELL, MONS_SERPENT_OF_HELL, MH_DEMONIC, -13,
- { {AT_BITE, AF_PLAIN, 35}, {AT_CLAW, AF_PLAIN, 15}, {AT_CLAW, AF_PLAIN, 15}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 35}, {AT_CLAW, AF_PLAIN, 15}, {AT_CLAW, AF_PLAIN, 15}, AT_NO_ATK },
{ 20, 4, 4, 0 },
- 12, 9, 14, 7, MST_SERPENT_OF_HELL, CE_CLEAN, Z_NOZOMBIE, S_ROAR, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_HUGE
-}
-,
+ 12, 9, MST_SERPENT_OF_HELL, CE_CLEAN, Z_NOZOMBIE, S_ROAR, I_HIGH,
+ 14, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_HUGE
+},
{
MONS_BOGGART, 'g', DARKGREY, "boggart",
M_SPELLCASTER | M_ACTUAL_SPELLS | M_SEE_INVIS,
MR_NO_FLAGS,
0, 14, MONS_BOGGART, MONS_BOGGART, MH_NATURAL, -7,
- { {AT_HIT, AF_PLAIN, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 5}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 2, 3, 5, 0 },
- 0, 12, 12, 7, MST_BOGGART, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_LITTLE,
-}
-,
+ 0, 12, MST_BOGGART, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 12, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_LITTLE,
+},
{
MONS_QUICKSILVER_DRAGON, 'D', LIGHTCYAN, "quicksilver dragon",
M_SPELLCASTER | M_FLIES | M_SENSE_INVIS,
MR_NO_FLAGS,
0, 14, MONS_DRAGON, MONS_QUICKSILVER_DRAGON, MH_NATURAL, -7,
- { {AT_BITE, AF_PLAIN, 25}, {AT_CLAW, AF_PLAIN, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 25}, {AT_CLAW, AF_PLAIN, 20}, AT_NO_ATK, AT_NO_ATK },
{ 16, 3, 5, 0 },
- 10, 15, 15, 7, MST_QUICKSILVER_DRAGON, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_GIANT,
-}
-,
+ 10, 15, MST_QUICKSILVER_DRAGON, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
+ 15, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_GIANT,
+},
{
MONS_IRON_DRAGON, 'D', CYAN, "iron dragon",
M_SPELLCASTER | M_SENSE_INVIS,
MR_RES_POISON | MR_RES_FIRE | MR_RES_COLD,
0, 14, MONS_DRAGON, MONS_IRON_DRAGON, MH_NATURAL, -7,
- { {AT_BITE, AF_PLAIN, 25}, {AT_CLAW, AF_PLAIN, 25}, {AT_CLAW, AF_PLAIN, 25}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 25}, {AT_CLAW, AF_PLAIN, 25}, {AT_CLAW, AF_PLAIN, 25}, AT_NO_ATK },
{ 18, 5, 3, 0 },
- 20, 6, 8, 7, MST_IRON_DRAGON, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_HUGE
-}
-,
+ 20, 6, MST_IRON_DRAGON, CE_CONTAMINATED, Z_SMALL, S_ROAR, I_HIGH,
+ 8, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_HUGE
+},
{
MONS_SKELETAL_WARRIOR, 'z', CYAN, "skeletal warrior",
M_FIGHTER | M_SPELLCASTER | M_ACTUAL_SPELLS | M_EVIL,
MR_RES_POISON | MR_RES_COLD,
0, 10, MONS_SKELETAL_WARRIOR, MONS_SKELETAL_WARRIOR, MH_UNDEAD, -7,
- { {AT_HIT, AF_PLAIN, 25}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 25}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 10, 5, 3, 0 },
- 15, 10, 10, 7, MST_SKELETAL_WARRIOR, CE_CONTAMINATED, Z_SMALL, S_SILENT, I_NORMAL,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
-,
-
+ 15, 10, MST_SKELETAL_WARRIOR, CE_CONTAMINATED, Z_SMALL, S_SILENT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
/* player ghost - only one per level. stats are stored in ghost struct */
{
@@ -4078,12 +3763,11 @@
M_FIGHTER | M_SPEAKS | M_SPELLCASTER | M_ACTUAL_SPELLS | M_FLIES | M_UNIQUE,
MR_RES_POISON,
0, 15, MONS_PHANTOM, MONS_PLAYER_GHOST, MH_UNDEAD, -5,
- { {AT_HIT, AF_PLAIN, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 5}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 4, 2, 3, 0 },
- 1, 2, 10, 7, MST_GHOST, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_MEDIUM
-}
-,
+ 1, 2, MST_GHOST, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_MEDIUM
+},
/* random demon in pan - only one per level. stats are stored in ghost struct */
{
@@ -4091,12 +3775,11 @@
M_FIGHTER | M_SPELLCASTER | M_SPEAKS | M_EVIL,
MR_RES_POISON,
0, 14, MONS_PANDEMONIUM_DEMON, MONS_PANDEMONIUM_DEMON, MH_DEMONIC, -5,
- { {AT_HIT, AF_PLAIN, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 5}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 4, 2, 3, 0 },
- 1, 2, 10, 7, MST_GHOST, CE_CONTAMINATED, Z_NOZOMBIE, S_RANDOM, I_HIGH,
- MONUSE_OPEN_DOORS, SIZE_LARGE
-}
-,
+ 1, 2, MST_GHOST, CE_CONTAMINATED, Z_NOZOMBIE, S_RANDOM, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_LARGE
+},
// begin lava monsters {dlb}
{
@@ -4104,49 +3787,45 @@
M_NO_FLAGS,
MR_RES_FIRE | MR_VUL_COLD,
0, 10, MONS_LAVA_WORM, MONS_LAVA_WORM, MH_NATURAL, -3,
- { {AT_BITE, AF_FIRE, 15}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_FIRE, 15}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 3, 5, 0 },
- 1, 10, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_SILENT, I_ANIMAL,
- MONUSE_NOTHING, SIZE_LARGE
-}
-,
+ 1, 10, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_SILENT, I_ANIMAL,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LARGE
+},
{
MONS_LAVA_FISH, ';', RED, "lava fish",
M_NO_FLAGS,
MR_RES_FIRE | MR_VUL_COLD,
0, 10, MONS_BIG_FISH, MONS_LAVA_FISH, MH_NATURAL, -3,
- { {AT_BITE, AF_FIRE, 10}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_FIRE, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 4, 3, 5, 0 },
- 4, 15, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_SILENT, I_ANIMAL,
- MONUSE_NOTHING, SIZE_LITTLE,
-}
-,
+ 4, 15, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_SILENT, I_ANIMAL,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LITTLE,
+},
{
MONS_LAVA_SNAKE, 'S', RED, "lava snake",
M_SPECIAL_ABILITY,
MR_RES_FIRE | MR_VUL_COLD,
0, 10, MONS_SNAKE, MONS_LAVA_SNAKE, MH_NATURAL, -3,
- { {AT_BITE, AF_FIRE, 7}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_FIRE, 7}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 3, 3, 5, 0 },
- 2, 17, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_HISS, I_ANIMAL,
- MONUSE_NOTHING, SIZE_MEDIUM
-}
-,
+ 2, 17, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_HISS, I_ANIMAL,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_MEDIUM
+},
{ // mv: was another lava thing
MONS_SALAMANDER, 'S', LIGHTRED, "salamander",
M_FIGHTER | M_WARM_BLOOD,
MR_RES_FIRE | MR_VUL_COLD,
0, 10, MONS_SALAMANDER, MONS_SALAMANDER, MH_NATURAL, -3,
- { {AT_HIT, AF_FIRE, 23}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_FIRE, 23}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 14, 3, 5, 0 },
- 5, 5, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_SILENT, I_HIGH,
- MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
-}
+ 5, 5, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_SILENT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+},
-,
// end lava monsters {dlb}
// begin water monsters {dlb}
@@ -4155,144 +3834,148 @@
M_COLD_BLOOD,
MR_NO_FLAGS,
0, 10, MONS_BIG_FISH, MONS_BIG_FISH, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 8}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 8}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 4, 3, 5, 0 },
- 1, 12, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_SILENT, I_ANIMAL,
- MONUSE_NOTHING, SIZE_SMALL
-}
-,
+ 1, 12, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_SILENT, I_ANIMAL,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_SMALL
+},
{
MONS_GIANT_GOLDFISH, ';', LIGHTRED, "giant goldfish",
M_COLD_BLOOD,
MR_NO_FLAGS,
0, 10, MONS_BIG_FISH, MONS_GIANT_GOLDFISH, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 15}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 15}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 7, 3, 5, 0 },
- 5, 7, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_SILENT, I_ANIMAL,
- MONUSE_NOTHING, SIZE_LITTLE,
-}
-,
+ 5, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_SILENT, I_ANIMAL,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LITTLE,
+},
{
MONS_ELECTRICAL_EEL, ';', LIGHTBLUE, "electrical eel",
M_COLD_BLOOD | M_SPECIAL_ABILITY,
MR_RES_ELEC,
0, 10, MONS_ELECTRICAL_EEL, MONS_ELECTRICAL_EEL, MH_NATURAL, -3,
- { {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 3, 3, 5, 0 },
- 1, 15, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_SILENT, I_ANIMAL,
- MONUSE_NOTHING, SIZE_SMALL
-}
-,
+ 1, 15, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_SILENT, I_ANIMAL,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_SMALL
+},
{
MONS_JELLYFISH, 'J', CYAN, "jellyfish",
M_NO_FLAGS,
MR_RES_POISON,
0, 10, MONS_JELLYFISH, MONS_JELLYFISH, MH_NATURAL, -3,
- { {AT_STING, AF_POISON_STR, 1}, {AT_HIT, AF_PLAIN, 1}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_STING, AF_POISON_STR, 1}, {AT_HIT, AF_PLAIN, 1}, AT_NO_ATK, AT_NO_ATK },
{ 4, 3, 5, 0 },
- 0, 5, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_LITTLE,
-}
-,
+ 0, 5, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_SILENT, I_PLANT,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LITTLE,
+},
{
MONS_WATER_ELEMENTAL, '{', LIGHTBLUE, "water elemental",
- M_FLIES,
+ M_FLIES | M_AMPHIBIOUS,
MR_RES_POISON | MR_VUL_FIRE | MR_RES_ELEC,
0, 10, MONS_EARTH_ELEMENTAL, MONS_WATER_ELEMENTAL, MH_NONLIVING, MAG_IMMUNE,
- { {AT_HIT, AF_PLAIN, 25}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 25}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 5, 3, 0 },
- 0, 7, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_OPEN_DOORS, SIZE_BIG
-}
-,
+ 0, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_BIG
+},
{
MONS_SWAMP_WORM, 'w', BROWN, "swamp worm",
M_AMPHIBIOUS,
MR_NO_FLAGS,
0, 10, MONS_WORM, MONS_SWAMP_WORM, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 5, 5, 5, 0 },
- 3, 12, 12, 0, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_LARGE
+ 3, 12, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_SILENT, I_PLANT,
+ 12, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LARGE
},
+
// end water monsters {dlb}
+// begin "move through rock" monsters {mpc}
+{
+ MONS_ROCK_WORM, 'w', BROWN, "rock worm",
+ //M_NO_FLAGS,
+ M_WALL_SHIELDED,
+ MR_RES_POISON | MR_RES_FIRE | MR_RES_COLD | MR_RES_ELEC,
+ 0, 10, MONS_WORM, MONS_ROCK_WORM, MH_NATURAL, -3,
+ { {AT_BITE, AF_PLAIN, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
+ { 5, 5, 5, 0 },
+ 3, 12, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_SILENT, I_PLANT,
+ 12, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LARGE
+},
+// end "move through rock" monsters {mpc}
+
{
MONS_WOLF, 'h', LIGHTGREY, "wolf",
M_WARM_BLOOD | M_SENSE_INVIS,
MR_NO_FLAGS,
450, 10, MONS_HOUND, MONS_WOLF, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 8}, {AT_CLAW, AF_PLAIN, 2}, {AT_CLAW, AF_PLAIN, 2}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 8}, {AT_CLAW, AF_PLAIN, 2}, {AT_CLAW, AF_PLAIN, 2}, AT_NO_ATK },
{ 4, 3, 5, 0 },
- 3, 15, 17, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_BARK, I_ANIMAL,
- MONUSE_NOTHING, SIZE_SMALL
-}
-,
+ 3, 15, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_BARK, I_ANIMAL,
+ 17, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_SMALL
+},
{
MONS_WARG, 'h', DARKGREY, "warg",
M_SENSE_INVIS | M_WARM_BLOOD,
MR_RES_POISON,
600, 12, MONS_HOUND, MONS_WARG, MH_NATURAL, -6,
- { {AT_BITE, AF_PLAIN, 12}, {AT_CLAW, AF_PLAIN, 3}, {AT_CLAW, AF_PLAIN, 3}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 12}, {AT_CLAW, AF_PLAIN, 3}, {AT_CLAW, AF_PLAIN, 3}, AT_NO_ATK },
{ 4, 4, 5, 0 },
- 4, 12, 13, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_BARK, I_ANIMAL,
- MONUSE_NOTHING, SIZE_LARGE
-}
-,
+ 4, 12, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_BARK, I_ANIMAL,
+ 13, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LARGE
+},
{
MONS_BEAR, 'U', BROWN, "bear",
M_WARM_BLOOD,
MR_NO_FLAGS,
2000, 10, MONS_BEAR, MONS_BEAR, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 10}, {AT_CLAW, AF_PLAIN, 6}, {AT_CLAW, AF_PLAIN, 6}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 10}, {AT_CLAW, AF_PLAIN, 6}, {AT_CLAW, AF_PLAIN, 6}, AT_NO_ATK },
{ 7, 3, 3, 0 },
- 4, 4, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_GROWL, I_ANIMAL,
- MONUSE_NOTHING, SIZE_LARGE
-}
-,
+ 4, 4, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_GROWL, I_ANIMAL,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LARGE
+},
{
MONS_GRIZZLY_BEAR, 'U', LIGHTGREY, "grizzly bear",
M_WARM_BLOOD,
MR_NO_FLAGS,
2500, 10, MONS_BEAR, MONS_GRIZZLY_BEAR, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 12}, {AT_CLAW, AF_PLAIN, 8}, {AT_CLAW, AF_PLAIN, 8}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 12}, {AT_CLAW, AF_PLAIN, 8}, {AT_CLAW, AF_PLAIN, 8}, AT_NO_ATK },
{ 7, 4, 4, 0 },
- 5, 8, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_GROWL, I_ANIMAL,
- MONUSE_NOTHING, SIZE_LARGE
-}
-,
+ 5, 8, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_GROWL, I_ANIMAL,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LARGE
+},
{
MONS_POLAR_BEAR, 'U', WHITE, "polar bear",
M_WARM_BLOOD | M_AMPHIBIOUS,
MR_RES_COLD,
2500, 10, MONS_BEAR, MONS_POLAR_BEAR, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 20}, {AT_CLAW, AF_PLAIN, 5}, {AT_CLAW, AF_PLAIN, 5}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 20}, {AT_CLAW, AF_PLAIN, 5}, {AT_CLAW, AF_PLAIN, 5}, AT_NO_ATK },
{ 7, 5, 3, 0 },
- 7, 8, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_GROWL, I_ANIMAL,
- MONUSE_NOTHING, SIZE_BIG
-}
-,
+ 7, 8, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_GROWL, I_ANIMAL,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_BIG
+},
{
MONS_BLACK_BEAR, 'U', DARKGREY, "black bear",
M_WARM_BLOOD,
MR_NO_FLAGS,
1800, 10, MONS_BEAR, MONS_BLACK_BEAR, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 4}, {AT_CLAW, AF_PLAIN, 4}, {AT_CLAW, AF_PLAIN, 4}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 4}, {AT_CLAW, AF_PLAIN, 4}, {AT_CLAW, AF_PLAIN, 4}, AT_NO_ATK },
{ 6, 3, 3, 0 },
- 2, 8, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_GROWL, I_ANIMAL,
- MONUSE_NOTHING, SIZE_MEDIUM
-}
-,
+ 2, 8, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_GROWL, I_ANIMAL,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_MEDIUM
+},
// small simulacrum
{
@@ -4300,12 +3983,11 @@
M_EVIL,
MR_RES_POISON | MR_VUL_FIRE | MR_RES_COLD,
0, 6, MONS_SIMULACRUM_SMALL, MONS_SIMULACRUM_SMALL, MH_UNDEAD, -1,
- { {AT_HIT, AF_PLAIN, 6}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 6}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 2, 3, 5, 0 },
- 10, 4, 7, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_SMALL
-}
-,
+ 10, 4, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 7, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_SMALL
+},
// large simulacrum
{
@@ -4313,10 +3995,33 @@
M_EVIL,
MR_RES_POISON | MR_VUL_FIRE | MR_RES_COLD,
0, 6, MONS_SIMULACRUM_SMALL, MONS_SIMULACRUM_LARGE, MH_UNDEAD, -1,
- { {AT_HIT, AF_PLAIN, 14}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 14}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 5, 3, 5, 0 },
- 10, 5, 7, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
- MONUSE_NOTHING, SIZE_LARGE
+ 10, 5, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ 7, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LARGE
+},
+
+{
+ MONS_MERFOLK, 'm', LIGHTBLUE, "merfolk fighter",
+ M_HUMANOID | M_WARM_BLOOD | M_AMPHIBIOUS,
+ MR_RES_POISON | MR_RES_COLD,
+ 500, 10, MONS_MERFOLK, MONS_MERFOLK, MH_NATURAL, -3,
+ { {AT_HIT, AF_PLAIN, 14}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
+ { 8, 2, 4, 0 },
+ 4, 12, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+}
+,
+
+{
+ MONS_MERMAID, 'm', LIGHTCYAN, "mermaid",
+ M_SPELLCASTER | M_HUMANOID | M_WARM_BLOOD | M_AMPHIBIOUS,
+ MR_RES_POISON | MR_RES_COLD,
+ 500, 10, MONS_MERMAID, MONS_MERMAID, MH_NATURAL, -5,
+ { {AT_HIT, AF_PLAIN, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
+ { 8, 2, 4, 0 },
+ 4, 12, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL,
+ 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
}
,
@@ -4325,36 +4030,33 @@
M_COLD_BLOOD | M_AMPHIBIOUS,
MR_NO_FLAGS,
150, 10, MONS_GIANT_LIZARD, MONS_GIANT_NEWT, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 3}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 3}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 1, 1, 2, 0 },
- 0, 15, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 0, 15, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_INSECT,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_GIANT_GECKO, 'l', YELLOW, "giant gecko",
M_COLD_BLOOD,
MR_NO_FLAGS,
250, 10, MONS_GIANT_LIZARD, MONS_GIANT_GECKO, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 5}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 1, 3, 5, 0 },
- 1, 14, 12, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_INSECT,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 1, 14, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SILENT, I_INSECT,
+ 12, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
{
MONS_GIANT_IGUANA, 'l', BLUE, "giant iguana",
M_COLD_BLOOD,
MR_NO_FLAGS,
400, 10, MONS_GIANT_LIZARD, MONS_GIANT_IGUANA, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 15}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 15}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 3, 3, 5, 0 },
- 5, 9, 10, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_HISS, I_INSECT,
- MONUSE_NOTHING, SIZE_LITTLE,
-}
-,
+ 5, 9, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_HISS, I_INSECT,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LITTLE,
+},
{
// gila monsters colours: lightmagenta, magenta, lightred, red, yellow
@@ -4362,82 +4064,77 @@
M_COLD_BLOOD,
MR_NO_FLAGS,
500, 10, MONS_GIANT_LIZARD, MONS_GILA_MONSTER, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 5, 4, 4, 0 },
- 3, 12, 10, 7, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_HISS, I_INSECT,
- MONUSE_NOTHING, SIZE_LITTLE,
-}
-,
+ 3, 12, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_HISS, I_INSECT,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LITTLE,
+},
{
MONS_KOMODO_DRAGON, 'l', LIGHTRED, "komodo dragon",
M_COLD_BLOOD | M_AMPHIBIOUS,
MR_NO_FLAGS,
800, 10, MONS_GIANT_LIZARD, MONS_KOMODO_DRAGON, MH_NATURAL, -3,
- { {AT_BITE, AF_DISEASE, 30}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_DISEASE, 30}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 8, 3, 5, 0 },
- 7, 8, 10, 7, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_HISS, I_INSECT,
- MONUSE_NOTHING, SIZE_MEDIUM
-}
-,
+ 7, 8, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_HISS, I_INSECT,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_MEDIUM
+},
{
MONS_ORANGE_STATUE, '8', LIGHTRED, "orange crystal statue",
M_SPECIAL_ABILITY | M_SPEAKS,
MR_RES_POISON | MR_RES_FIRE | MR_RES_COLD | MR_RES_ELEC,
0, 10, MONS_CLAY_GOLEM, MONS_ORANGE_STATUE, MH_NONLIVING, MAG_IMMUNE,
- { {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 10, 0, 0, 160 },
- 20, 1, 6, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
- MONUSE_NOTHING, SIZE_LARGE
-}
-,
+ 20, 1, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ 6, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LARGE
+},
{
MONS_SILVER_STATUE, '8', WHITE, "silver statue",
M_SPECIAL_ABILITY | M_SPEAKS,
MR_RES_POISON | MR_RES_FIRE | MR_RES_COLD | MR_RES_ELEC,
0, 10, MONS_CLAY_GOLEM, MONS_SILVER_STATUE, MH_NONLIVING, MAG_IMMUNE,
- { {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 6, 0, 0, 150 },
- 15, 1, 10, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
- MONUSE_NOTHING, SIZE_LARGE
-}
-,
+ 15, 1, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LARGE
+},
{
MONS_ICE_STATUE, '8', LIGHTBLUE, "ice statue",
M_SPELLCASTER | M_SPEAKS,
MR_RES_POISON | MR_VUL_FIRE | MR_RES_COLD | MR_RES_ELEC,
0, 10, MONS_CLAY_GOLEM, MONS_ICE_STATUE, MH_NONLIVING, MAG_IMMUNE,
- { {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
{ 8, 0, 0, 70 },
- 12, 1, 16, 7, MST_ICE_STATUE, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
- MONUSE_NOTHING, SIZE_LARGE
-}
-,
+ 12, 1, MST_ICE_STATUE, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_HIGH,
+ 16, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_LARGE
+},
{
MONS_MURRAY, 'z', LIGHTRED, "Murray",
M_SPELLCASTER | M_SEE_INVIS | M_EVIL | M_SPEAKS | M_UNIQUE,
MR_RES_ELEC | MR_RES_POISON | MR_RES_HELLFIRE | MR_RES_COLD,
0, 50, MONS_LICH, MONS_CURSE_SKULL, MH_UNDEAD, MAG_IMMUNE,
- { {AT_BITE, AF_PLAIN, 20}, {AT_BITE, AF_PLAIN, 20}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_PLAIN, 20}, {AT_BITE, AF_PLAIN, 20}, AT_NO_ATK, AT_NO_ATK },
{ 14, 0, 0, 180 },
- 30, 10, 10, 7, MST_CURSE_SKULL, CE_NOCORPSE, Z_NOZOMBIE, S_MOAN, I_HIGH,
- MONUSE_NOTHING, SIZE_TINY
-}
-,
+ 30, 10, MST_CURSE_SKULL, CE_NOCORPSE, Z_NOZOMBIE, S_MOAN, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY
+},
+
{
MONS_TIAMAT, 'd', MAGENTA, "Tiamat",
M_HUMANOID | M_SEE_INVIS | M_EVIL | M_UNIQUE | M_FLIES,
MR_RES_POISON,
0, 10, MONS_DRACONIAN, MONS_DRACONIAN, MH_NATURAL, -5,
{ {AT_HIT, AF_PLAIN, 35}, {AT_TAIL_SLAP, AF_PLAIN, 25},
- {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ AT_NO_ATK, AT_NO_ATK },
{ 22, 0, 0, 200 },
- 8, 10, 10, 10, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_ROAR, I_HIGH,
- MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
+ 8, 10, MST_NO_SPELLS, CE_NOCORPSE, Z_SMALL, S_ROAR, I_HIGH,
+ 10, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_MEDIUM
},
{
@@ -4445,10 +4142,9 @@
M_WARM_BLOOD | M_EVIL | M_UNIQUE,
MR_NO_FLAGS,
2500, 10, MONS_HILL_GIANT, MONS_CYCLOPS, MH_NATURAL, -3,
- { {AT_HIT, AF_PLAIN, 35}, {AT_HIT, AF_PLAIN, 30},
- {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 35}, {AT_HIT, AF_PLAIN, 30}, AT_NO_ATK, AT_NO_ATK },
{ 12, 0, 0, 105 },
- 7, 3, 8, 8, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SHOUT, I_HIGH,
- MONUSE_STARTING_EQUIPMENT, SIZE_GIANT,
+ 7, 3, MST_NO_SPELLS, CE_CLEAN, Z_BIG, S_SHOUT, I_HIGH,
+ 8, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, SIZE_GIANT,
},
#endif
diff --git a/crawl-ref/source/mon-pick.cc b/crawl-ref/source/mon-pick.cc
index 9c8e17620a..d7989c10c2 100644
--- a/crawl-ref/source/mon-pick.cc
+++ b/crawl-ref/source/mon-pick.cc
@@ -17,6 +17,7 @@
#include "externs.h"
#include "branch.h"
#include "misc.h"
+#include "mon-util.h"
#include "place.h"
// NB - When adding new branches or levels above 50, you must
@@ -35,6 +36,134 @@ int mons_level(int mcls, const level_id &place)
return monster_level;
}
+typedef int (*mons_level_function)(int);
+
+struct global_level_info
+{
+ mons_level_function level_func;
+ branch_type branch;
+ int avg_depth;
+};
+
+static int mons_misc_level(int mcls)
+{
+ switch(mons_char(mcls))
+ {
+ case '&':
+ return 35;
+
+ case '1':
+ return 30;
+
+ case '2':
+ return 25;
+
+ case '3':
+ return 20;
+
+ case '4':
+ return 15;
+
+ case '5':
+ return 10;
+ }
+
+ if (mons_is_unique(mcls))
+ return (mons_type_hit_dice(mcls) * 14 / 10 + 1);
+
+ switch(mcls)
+ {
+ case MONS_HUMAN:
+ case MONS_ELF:
+ return 1;
+
+ case MONS_BIG_FISH:
+ case MONS_GIANT_GOLDFISH:
+ case MONS_JELLYFISH:
+ return 8;
+
+ case MONS_ANT_LARVA:
+ return 10;
+
+ case MONS_ELECTRICAL_EEL:
+ case MONS_LAVA_FISH:
+ case MONS_LAVA_SNAKE:
+ case MONS_LAVA_WORM:
+ case MONS_SALAMANDER:
+ case MONS_HOG:
+ return 14;
+
+ case MONS_FIRE_VORTEX:
+ return 18;
+
+ case MONS_MINOTAUR:
+ case MONS_BALL_LIGHTNING:
+ case MONS_ORANGE_STATUE:
+ case MONS_SILVER_STATUE:
+ case MONS_ICE_STATUE:
+ case MONS_SPATIAL_VORTEX:
+ case MONS_MOLTEN_GARGOYLE:
+ case MONS_WATER_ELEMENTAL:
+ return 20;
+
+ case MONS_METAL_GARGOYLE:
+ case MONS_VAULT_GUARD:
+ return 24;
+
+ case MONS_QUEEN_ANT:
+ return 25;
+
+ case MONS_ANGEL:
+ return 27;
+
+ case MONS_DAEVA:
+ return 28;
+ }
+
+ return 0;
+}
+
+static global_level_info g_lev_infos[] = {
+ {mons_standard_level, BRANCH_MAIN_DUNGEON, 1},
+ {mons_misc_level, BRANCH_MAIN_DUNGEON, 1},
+ {mons_mineorc_level, BRANCH_ORCISH_MINES, 8},
+ {mons_lair_level, BRANCH_LAIR, 10},
+ {mons_hallelf_level, BRANCH_ELVEN_HALLS, 11},
+ {mons_swamp_level, BRANCH_SWAMP, 14},
+ {mons_shoals_level, BRANCH_SHOALS, 14},
+ {mons_pitsnake_level, BRANCH_SNAKE_PIT, 15},
+ {mons_pitslime_level, BRANCH_SLIME_PITS, 16},
+ {mons_crypt_level, BRANCH_CRYPT, 19},
+ {mons_tomb_level, BRANCH_TOMB, 21},
+ {mons_hallzot_level, BRANCH_HALL_OF_ZOT, 27},
+ {mons_dis_level, BRANCH_DIS, 29},
+ {mons_gehenna_level, BRANCH_GEHENNA, 29},
+ {mons_cocytus_level, BRANCH_COCYTUS, 29},
+ {mons_tartarus_level, BRANCH_TARTARUS, 29},
+
+ {NULL, NUM_BRANCHES, 0}
+};
+
+int mons_global_level(int mcls)
+{
+ for (int i = 0; g_lev_infos[i].level_func != NULL; i++)
+ {
+ int level = (*g_lev_infos[i].level_func)(mcls);
+ int rel_level = level - absdungeon_depth(g_lev_infos[i].branch, 1);
+
+ if (g_lev_infos[i].branch == BRANCH_HALL_OF_ZOT)
+ rel_level++;
+
+ if (level >= 1 && level < 99 && rel_level != 0)
+ {
+ level = rel_level + g_lev_infos[i].avg_depth - 1;
+ return (level);
+ }
+ }
+
+ return (0);
+}
+
// 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, const level_id &place)
@@ -1423,6 +1552,9 @@ int mons_pitslime_level(int mcls)
mlev += 5;
break;
+ case MONS_ROYAL_JELLY:
+ mlev += 6;
+
default:
mlev += 0;
break;
@@ -1525,6 +1657,7 @@ int mons_crypt_level(int mcls)
case MONS_REAPER:
case MONS_ANCIENT_LICH:
case MONS_LICH:
+ case MONS_CURSE_SKULL:
mlev += 5;
break;
@@ -1836,6 +1969,10 @@ int mons_tomb_level(int mcls)
mlev += 3;
break;
+ case MONS_GREATER_MUMMY:
+ mlev += 4;
+ break;
+
default:
mlev += 99;
}
@@ -1892,6 +2029,8 @@ int mons_shoals_level(int mcls)
case MONS_GIANT_BAT:
break;
+ case MONS_MERFOLK:
+ case MONS_MERMAID:
case MONS_CENTAUR:
case MONS_ETTIN:
case MONS_SHEEP:
@@ -1932,8 +2071,12 @@ int mons_shoals_rare(int mcls)
case MONS_ETTIN:
case MONS_SHEEP:
+ case MONS_MERFOLK:
return 50;
+ case MONS_MERMAID:
+ return 40;
+
case MONS_HIPPOGRIFF:
case MONS_GIANT_BAT:
case MONS_BUTTERFLY:
@@ -1974,6 +2117,9 @@ int mons_swamp_level(int mcls)
case MONS_RAT:
case MONS_SWAMP_DRAKE:
case MONS_WORM:
+ case MONS_SWAMP_WORM:
+ case MONS_MERFOLK:
+ case MONS_MERMAID:
mlev++;
break;
@@ -2051,6 +2197,7 @@ int mons_swamp_rare(int mcls)
return 61;
case MONS_SLIME_CREATURE:
+ case MONS_MERFOLK:
return 54;
case MONS_SNAKE:
@@ -2078,6 +2225,7 @@ int mons_swamp_rare(int mcls)
case MONS_KOMODO_DRAGON:
case MONS_VERY_UGLY_THING:
case MONS_VAPOUR:
+ case MONS_MERMAID:
return 15;
case MONS_PHANTOM:
@@ -2140,6 +2288,7 @@ int mons_hallzot_level(int mcls)
case MONS_SKELETAL_DRAGON:
case MONS_STORM_DRAGON:
case MONS_CURSE_TOE:
+ case MONS_ORB_GUARDIAN:
mlev += 5;
break;
case MONS_DEATH_COB:
@@ -2526,6 +2675,12 @@ int mons_standard_level(int mcls)
case MONS_TITAN:
return 30;
+ case MONS_DEEP_ELF_BLADEMASTER:
+ case MONS_DEEP_ELF_MASTER_ARCHER:
+ return 33;
+
+ case MONS_MERFOLK:
+ case MONS_MERMAID:
case MONS_BIG_FISH:
case MONS_ELECTRICAL_EEL:
case MONS_GIANT_GOLDFISH:
@@ -2548,6 +2703,8 @@ int mons_standard_rare(int mcls)
{
// "another lava thing" has no stats! (GDL)
// case MONS_ANOTHER_LAVA_THING:
+ case MONS_MERFOLK:
+ case MONS_MERMAID:
case MONS_BIG_FISH:
case MONS_ELECTRICAL_EEL:
case MONS_GIANT_GOLDFISH:
diff --git a/crawl-ref/source/mon-pick.h b/crawl-ref/source/mon-pick.h
index 1f8bac453c..aefaec9204 100644
--- a/crawl-ref/source/mon-pick.h
+++ b/crawl-ref/source/mon-pick.h
@@ -27,6 +27,7 @@ int mons_rarity(int mcls, const level_id &place = level_id::current());
* *********************************************************************** */
int mons_level(int mcls, const level_id &place = level_id::current());
+int mons_global_level(int mcls);
// last updated 12may2000 {dlb}
/* ***********************************************************************
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index fc30799dc5..e06b511c72 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -294,7 +294,8 @@ bool mons_class_flag(int mc, int bf)
return ((me->bitfields & bf) != 0);
} // end mons_class_flag()
-static int scan_mon_inv_randarts( const monsters *mon, int ra_prop )
+static int scan_mon_inv_randarts( const monsters *mon,
+ randart_prop_type ra_prop)
{
int ret = 0;
@@ -369,6 +370,17 @@ bool mons_is_stationary(const monsters *mons)
return (mons_class_is_stationary(mons->type));
}
+bool mons_class_is_confusable(int mc)
+{
+ return (smc->resist_magic < MAG_IMMUNE
+ && mons_intel(mc) > I_PLANT);
+}
+
+bool mons_class_is_slowable(int mc)
+{
+ return (smc->resist_magic < MAG_IMMUNE);
+}
+
// returns whether a monster is non-solid
// and thus can't be affected by some traps
bool mons_is_insubstantial(int type)
@@ -477,6 +489,11 @@ bool mons_is_humanoid( int mc )
case 'T': // trolls
return (true);
+ case 'm': // merfolk
+ if (mc == MONS_MERFOLK || mc == MONS_MERMAID)
+ return (true);
+ return (false);
+
case 'g': // goblines, hobgoblins, gnolls, boggarts -- but not gargoyles
if (mc != MONS_GARGOYLE
&& mc != MONS_METAL_GARGOYLE
@@ -1479,6 +1496,7 @@ void define_monster(monsters &mons)
// reset monster enchantments
mons.enchantments.clear();
+ mons.ench_countdown = 0;
} // end define_monster()
static std::string str_monam(const monsters& mon, description_level_type desc,
@@ -1962,6 +1980,7 @@ bool ms_waste_of_time( const monsters *mon, spell_type monspell )
bool ret = false;
int intel, est_magic_resist, power, diff;
+ const actor *foe = mon->get_foe();
// 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
@@ -1969,11 +1988,10 @@ bool ms_waste_of_time( const monsters *mon, spell_type monspell )
{
case SPELL_BACKLIGHT:
{
- const actor *foe = mon->get_foe();
- ret = !foe || foe->backlit() || foe->invisible();
+ ret = !foe || foe->backlit();
break;
}
-
+
case SPELL_BERSERKER_RAGE:
if (!mon->needs_berserk(false))
ret = true;
@@ -2021,6 +2039,10 @@ bool ms_waste_of_time( const monsters *mon, spell_type monspell )
case SPELL_BANISHMENT:
case SPELL_DISINTEGRATE:
case SPELL_PARALYSE:
+ case SPELL_SLEEP:
+ if (monspell == SPELL_SLEEP && (!foe || foe->asleep()))
+ return (true);
+
// occasionally we don't estimate... just fire and see:
if (one_chance_in(5))
return (false);
@@ -2039,9 +2061,7 @@ bool ms_waste_of_time( const monsters *mon, spell_type monspell )
if (mon->foe == MHITYOU)
est_magic_resist = player_res_magic();
else
- {
est_magic_resist = mons_resist_magic(&menv[mon->foe]);
- }
// now randomize (normal intels less accurate than high):
if (intel == I_NORMAL)
@@ -2166,6 +2186,7 @@ const char *mons_pronoun(monster_type mon_type, pronoun_type variant)
case MONS_EROLCHA:
case MONS_ERICA:
case MONS_TIAMAT:
+ case MONS_MERMAID:
gender = GENDER_FEMALE;
break;
default:
@@ -2307,7 +2328,7 @@ monsters::monsters()
target_x(0), target_y(0), inv(), spells(), attitude(ATT_HOSTILE),
behaviour(BEH_WANDER), foe(MHITYOU), enchantments(), flags(0L),
experience(0), number(0), colour(BLACK), foe_memory(0), god(GOD_NO_GOD),
- ghost()
+ ghost(), seen_context("")
{
}
@@ -2383,6 +2404,36 @@ bool monsters::floundering() const
&& !mons_flies(this));
}
+bool mons_class_can_pass(const int mclass, const dungeon_feature_type grid)
+{
+ // Permanent walls can't be passed through.
+ if (grid == DNGN_CLEAR_PERMAROCK_WALL || grid == DNGN_PERMAROCK_WALL)
+ return false;
+
+ switch (mclass)
+ {
+ case MONS_ROCK_WORM:
+ return (!grid_is_solid(grid) || grid_is_rock(grid));
+ }
+
+ return !grid_is_solid(grid);
+}
+
+bool monsters::can_pass_through(const dungeon_feature_type grid) const
+{
+ return mons_class_can_pass(type, grid);
+}
+
+bool monsters::can_pass_through(const int _x, const int _y) const
+{
+ return can_pass_through(grd[_x][_y]);
+}
+
+bool monsters::can_pass_through(const coord_def &c) const
+{
+ return can_pass_through(grd(c));
+}
+
bool monsters::can_drown() const
{
// Mummies can fall apart in water; ghouls and demons can drown in
@@ -2399,6 +2450,145 @@ size_type monsters::body_size(int /* psize */, bool /* base */) const
return (e? e->size : SIZE_MEDIUM);
}
+int monsters::body_weight() const
+{
+ int mclass = type;
+
+ switch(mclass)
+ {
+ case MONS_SPECTRAL_THING:
+ case MONS_SPECTRAL_WARRIOR:
+ case MONS_ELECTRIC_GOLEM:
+ case MONS_RAKSHASA_FAKE:
+ return 0;
+
+ case MONS_ZOMBIE_SMALL:
+ case MONS_ZOMBIE_LARGE:
+ case MONS_SKELETON_SMALL:
+ case MONS_SKELETON_LARGE:
+ case MONS_SIMULACRUM_SMALL:
+ case MONS_SIMULACRUM_LARGE:
+ mclass = number;
+ break;
+ default:
+ break;
+ }
+
+ int weight = mons_weight(mclass);
+
+ // Water elementals are "insubstantial", but still have weight.
+ if (weight == 0 && type == MONS_WATER_ELEMENTAL)
+ weight = 1500;
+
+ // weight == 0 in the monster entry indicates "no corpse". Can't
+ // use CE_NOCORPSE, because the corpse-effect field is used for
+ // corpseless monsters to indicate what happens if their blood
+ // is sucked. Grrrr.
+ if (weight == 0 && !mons_is_insubstantial(type))
+ {
+ const monsterentry *entry = get_monster_data(mclass);
+ switch(entry->size)
+ {
+ case SIZE_TINY:
+ weight = 150;
+ break;
+ case SIZE_LITTLE:
+ weight = 300;
+ break;
+ case SIZE_SMALL:
+ weight = 425;
+ break;
+ case SIZE_MEDIUM:
+ weight = 550;
+ break;
+ case SIZE_LARGE:
+ weight = 1300;
+ break;
+ case SIZE_BIG:
+ weight = 1500;
+ break;
+ case SIZE_GIANT:
+ weight = 1800;
+ break;
+ case SIZE_HUGE:
+ weight = 2200;
+ break;
+ default:
+ mpr("ERROR: invalid monster body weight");
+ perror("monsters::body_weight(): invalid monster body weight");
+ end(0);
+ }
+
+ switch(mclass)
+ {
+ case MONS_IRON_DEVIL:
+ weight += 550;
+ break;
+
+ case MONS_STONE_GOLEM:
+ case MONS_EARTH_ELEMENTAL:
+ case MONS_CRYSTAL_GOLEM:
+ weight *= 2;
+ break;
+
+ case MONS_IRON_DRAGON:
+ case MONS_IRON_GOLEM:
+ weight *= 3;
+ break;
+
+ case MONS_QUICKSILVER_DRAGON:
+ case MONS_SILVER_STATUE:
+ weight *= 4;
+ break;
+
+ case MONS_WOOD_GOLEM:
+ weight *= 2;
+ weight /= 3;
+ break;
+
+ case MONS_FLYING_SKULL:
+ case MONS_CURSE_SKULL:
+ case MONS_SKELETAL_DRAGON:
+ case MONS_SKELETAL_WARRIOR:
+ weight /= 2;
+ break;
+
+ case MONS_SHADOW_FIEND:
+ case MONS_SHADOW_IMP:
+ case MONS_SHADOW_DEMON:
+ weight /= 3;
+ break;
+ }
+
+ switch(monster_symbols[mclass].glyph)
+ {
+ case 'L':
+ weight /= 2;
+ break;
+
+ case 'p':
+ weight = 0;
+ break;
+ }
+ }
+
+ if (type == MONS_SKELETON_SMALL || type == MONS_SKELETON_LARGE)
+ weight /= 2;
+
+ return (weight);
+}
+
+int monsters::total_weight() const
+{
+ int burden = 0;
+
+ for (int i = 0; i < NUM_MONSTER_SLOTS; i++)
+ if (inv[i] != NON_ITEM)
+ burden += item_mass(mitm[inv[i]]) * mitm[inv[i]].quantity;
+
+ return (body_weight() + burden);
+}
+
int monsters::damage_type(int which_attack)
{
const item_def *mweap = weapon(which_attack);
@@ -2523,7 +2713,8 @@ void monsters::equip_weapon(item_def &item, int near)
{
if (need_message(near))
mprf("%s wields %s.", name(DESC_CAP_THE).c_str(),
- item.name(DESC_NOCAP_A).c_str());
+ item.name(DESC_NOCAP_A, false, false, true,
+ false, ISFLAG_CURSED).c_str());
const int brand = get_weapon_brand(item);
if (brand == SPWPN_PROTECTION)
@@ -2581,14 +2772,19 @@ void monsters::equip_armour(item_def &item, int near)
mprf("%s wears %s.", name(DESC_CAP_THE).c_str(),
item.name(DESC_NOCAP_A).c_str());
- ac += property( item, PARM_AC );
+ const equipment_type eq = get_armour_slot(item);
+ if (eq != EQ_SHIELD)
+ {
+ ac += property( item, PARM_AC );
+
+ const int armour_plus = item.plus;
+ ASSERT(abs(armour_plus) < 20);
+ if (abs(armour_plus) < 20)
+ ac += armour_plus;
+ }
- const int armour_plus = item.plus;
- ASSERT(abs(armour_plus) < 20);
- if (abs(armour_plus) < 20)
- ac += armour_plus;
+ // Shields can affect evasion.
ev += property( item, PARM_EVASION ) / 2;
-
if (ev < 1)
ev = 1; // This *shouldn't* happen.
}
@@ -2612,7 +2808,8 @@ void monsters::unequip_weapon(item_def &item, int near)
{
if (need_message(near))
mprf("%s unwields %s.", name(DESC_CAP_THE).c_str(),
- item.name(DESC_NOCAP_A).c_str());
+ item.name(DESC_NOCAP_A, false, false, true,
+ false, ISFLAG_CURSED).c_str());
const int brand = get_weapon_brand(item);
if (brand == SPWPN_PROTECTION)
@@ -2657,14 +2854,18 @@ void monsters::unequip_armour(item_def &item, int near)
mprf("%s takes off %s.", name(DESC_CAP_THE).c_str(),
item.name(DESC_NOCAP_A).c_str());
- ac -= property( item, PARM_AC );
+ const equipment_type eq = get_armour_slot(item);
+ if (eq != EQ_SHIELD)
+ {
+ ac -= property( item, PARM_AC );
- const int armour_plus = item.plus;
- ASSERT(abs(armour_plus) < 20);
- if (abs(armour_plus) < 20)
- ac -= armour_plus;
+ const int armour_plus = item.plus;
+ ASSERT(abs(armour_plus) < 20);
+ if (abs(armour_plus) < 20)
+ ac -= armour_plus;
+ }
+
ev -= property( item, PARM_EVASION ) / 2;
-
if (ev < 1)
ev = 1; // This *shouldn't* happen.
}
@@ -2699,8 +2900,11 @@ bool monsters::unequip(item_def &item, int slot, int near, bool force)
void monsters::lose_pickup_energy()
{
- if (speed_increment > 25 && speed < speed_increment)
- speed_increment -= speed;
+ monsterentry* entry = get_monster_data(type);
+ int delta = speed * entry->energy_usage.pickup_percent / 100;
+
+ if (speed_increment > 25 && delta < speed_increment)
+ speed_increment -= delta;
}
void monsters::pickup_message(const item_def &item, int near)
@@ -2718,6 +2922,11 @@ bool monsters::pickup(item_def &item, int slot, int near, bool force_merge)
{
if (items_stack(item, mitm[inv[slot]], force_merge))
{
+ dungeon_events.fire_position_event(
+ dgn_event(DET_ITEM_PICKUP, pos(), 0, item.index(),
+ monster_index(this)),
+ pos());
+
pickup_message(item, near);
inc_mitm_item_quantity( inv[slot], item.quantity );
destroy_item(item.index());
@@ -2727,6 +2936,11 @@ bool monsters::pickup(item_def &item, int slot, int near, bool force_merge)
}
return (false);
}
+
+ dungeon_events.fire_position_event(
+ dgn_event(DET_ITEM_PICKUP, pos(), 0, item.index(),
+ monster_index(this)),
+ pos());
const int index = item.index();
unlink_item(index);
@@ -2909,6 +3123,17 @@ bool monsters::wants_armour(const item_def &item) const
return (!mslot_item(MSLOT_ARMOUR));
}
+static mon_inv_type equip_slot_to_mslot(equipment_type eq)
+{
+ switch (eq)
+ {
+ case EQ_WEAPON: return MSLOT_WEAPON;
+ case EQ_BODY_ARMOUR: return MSLOT_ARMOUR;
+ case EQ_SHIELD: return MSLOT_SHIELD;
+ default: return (NUM_MONSTER_SLOTS);
+ }
+}
+
bool monsters::pickup_armour(item_def &item, int near, bool force)
{
ASSERT(item.base_type == OBJ_ARMOUR);
@@ -2916,21 +3141,27 @@ bool monsters::pickup_armour(item_def &item, int near, bool force)
if (!force && !wants_armour(item))
return (false);
- // XXX: Monsters can only equip body armour (as of 0.3).
- if (get_armour_slot(item) != EQ_BODY_ARMOUR)
+ const equipment_type eq = get_armour_slot(item);
+ // XXX: Monsters can only equip body armour and shields (as of 0.4).
+ // They can still be forced to wear stuff - this is needed for bardings.
+ if (!force && eq != EQ_BODY_ARMOUR && eq != EQ_SHIELD)
return (false);
+ const mon_inv_type mslot = equip_slot_to_mslot(eq);
+ if (mslot == NUM_MONSTER_SLOTS)
+ return false;
+
// XXX: Very simplistic armour evaluation for the moment.
- if (const item_def *existing_armour = slot_item(EQ_BODY_ARMOUR))
+ if (const item_def *existing_armour = slot_item(eq))
{
if (!force && existing_armour->armour_rating() >= item.armour_rating())
return (false);
- if (!drop_item(MSLOT_ARMOUR, near))
+ if (!drop_item(mslot, near))
return (false);
}
- return pickup(item, MSLOT_ARMOUR, near);
+ return pickup(item, mslot, near);
}
bool monsters::pickup_weapon(item_def &item, int near, bool force)
@@ -3087,7 +3318,10 @@ void monsters::swap_weapons(int near)
// Monsters can swap weapons really fast. :-)
if ((weap || alt) && speed_increment >= 2)
- speed_increment -= 2;
+ {
+ monsterentry *entry = get_monster_data(type);
+ speed_increment -= div_rand_round(entry->energy_usage.attack, 5);
+ }
}
void monsters::wield_melee_weapon(int near)
@@ -3101,16 +3335,6 @@ void monsters::wield_melee_weapon(int near)
}
}
-static mon_inv_type equip_slot_to_mslot(equipment_type eq)
-{
- switch (eq)
- {
- case EQ_WEAPON: return MSLOT_WEAPON;
- case EQ_BODY_ARMOUR: return MSLOT_ARMOUR;
- default: return (NUM_MONSTER_SLOTS);
- }
-}
-
item_def *monsters::slot_item(equipment_type eq)
{
return mslot_item(equip_slot_to_mslot(eq));
@@ -3124,7 +3348,7 @@ item_def *monsters::mslot_item(mon_inv_type mslot) const
item_def *monsters::shield()
{
- return (NULL);
+ return (mslot_item(MSLOT_SHIELD));
}
std::string monsters::name(description_level_type desc) const
@@ -3171,9 +3395,7 @@ bool monsters::fumbles_attack(bool verbose)
{
if (verbose)
{
- const bool player_can_see =
- mons_near(this) && player_monster_visible(this);
- if (player_can_see)
+ if (you.can_see(this))
mprf("%s splashes around in the water.",
this->name(DESC_CAP_THE).c_str());
else if (!silenced(you.x_pos, you.y_pos) && !silenced(x, y))
@@ -3266,12 +3488,11 @@ bool monsters::caught() const
int monsters::shield_bonus() const
{
- // XXX: Monsters don't actually get shields yet.
const item_def *shld = const_cast<monsters*>(this)->shield();
if (shld)
{
const int shld_c = property(*shld, PARM_AC);
- return (random2(shld_c + random2(hit_dice / 2)) / 2);
+ return (random2(1 + shld_c) + random2(hit_dice / 2));
}
return (-100);
}
@@ -3349,6 +3570,7 @@ flight_type monsters::flight_mode() const
bool monsters::is_levitating() const
{
+ // Checking class flags is not enough - see mons_flies.
return (flight_mode() == FL_LEVITATE);
}
@@ -3507,6 +3729,7 @@ void monsters::ghost_init()
inv.init(NON_ITEM);
enchantments.clear();
+ ench_countdown = 0;
find_place_to_live();
}
@@ -3611,6 +3834,7 @@ void monsters::reset()
destroy_inventory();
enchantments.clear();
+ ench_countdown = 0;
inv.init(NON_ITEM);
flags = 0;
@@ -3759,7 +3983,7 @@ bool monsters::add_ench(const mon_enchant &ench)
return (true);
}
-void monsters::add_enchantment_effect(const mon_enchant &ench, bool)
+void monsters::add_enchantment_effect(const mon_enchant &ench, bool quiet)
{
// check for slow/haste
switch (ench.ench)
@@ -3774,6 +3998,7 @@ void monsters::add_enchantment_effect(const mon_enchant &ench, bool)
speed = 100 + ((speed - 100) * 2);
else
speed *= 2;
+
break;
case ENCH_SLOW:
@@ -3781,8 +4006,15 @@ void monsters::add_enchantment_effect(const mon_enchant &ench, bool)
speed = 100 + ((speed - 100) / 2);
else
speed /= 2;
+
break;
+ case ENCH_SUBMERGED:
+ if (type == MONS_AIR_ELEMENTAL && mons_near(this) && !quiet)
+ mprf("%s merges itself into the air.",
+ name(DESC_CAP_A, true).c_str() );
+ break;
+
case ENCH_CHARM:
behaviour = BEH_SEEK;
target_x = you.x_pos;
@@ -3821,6 +4053,7 @@ void monsters::remove_enchantment_effect(const mon_enchant &me, bool quiet)
speed = 100 + ((speed - 100) / 2);
else
speed /= 2;
+
break;
case ENCH_SLOW:
@@ -3828,6 +4061,7 @@ void monsters::remove_enchantment_effect(const mon_enchant &me, bool quiet)
speed = 100 + ((speed - 100) * 2);
else
speed *= 2;
+
break;
case ENCH_PARALYSIS:
@@ -3929,6 +4163,36 @@ void monsters::remove_enchantment_effect(const mon_enchant &me, bool quiet)
monster_die( this, quiet? KILL_DISMISSED : KILL_RESET, 0 );
break;
+ case ENCH_SUBMERGED:
+ if (you.can_see(this))
+ {
+ if (!mons_is_safe( static_cast<const monsters*>(this))
+ && is_run_delay(current_delay_action()))
+ {
+ // Already set somewhere else.
+ if (seen_context != "")
+ return;
+
+ if (type == MONS_AIR_ELEMENTAL)
+ seen_context = "thin air";
+ else if (monster_habitable_grid(this, DNGN_FLOOR))
+ seen_context = "bursts forth";
+ else
+ seen_context = "surfaces";
+ }
+ else if (!quiet)
+ if (type == MONS_AIR_ELEMENTAL)
+ mprf("%s forms itself from the air!",
+ name(DESC_CAP_A, true).c_str() );
+ }
+ else if (mons_near(this) && monster_habitable_grid(this, DNGN_FLOOR))
+ {
+ mpr("Something invisble bursts forth from the water.");
+ interrupt_activity( AI_FORCE_INTERRUPT );
+ }
+
+ break;
+
default:
break;
}
@@ -4067,18 +4331,20 @@ std::string monsters::describe_enchantments() const
return (oss.str());
}
-// used to adjust time durations in handle_enchantment() for monster speed
+// used to adjust time durations in calc_duration() for monster speed
static inline int mod_speed( int val, int speed )
{
if (!speed)
- speed = you.time_taken;
+ speed = 10;
const int modded = (speed ? (val * 10) / speed : val);
return (modded? modded : 1);
}
bool monsters::decay_enchantment(const mon_enchant &me, bool decay_degree)
{
- const int spd = speed == 0? you.time_taken : speed;
+ // Faster monsters can wiggle out of the net more quickly.
+ const int spd = (me.ench == ENCH_HELD) ? speed :
+ 10;
const int actdur = speed_to_duration(spd);
if (lose_ench_duration(me, actdur))
return (true);
@@ -4113,7 +4379,7 @@ bool monsters::decay_enchantment(const mon_enchant &me, bool decay_degree)
void monsters::apply_enchantment(const mon_enchant &me)
{
- const int spd = speed == 0? you.time_taken : speed;
+ const int spd = 10;
switch (me.ench)
{
case ENCH_BERSERK:
@@ -4173,8 +4439,8 @@ void monsters::apply_enchantment(const mon_enchant &me)
// the enchantment doubles as the durability of a net
// the more corroded it gets, the more easily it will break
- int hold = mitm[net].plus; // this will usually be negative
- int mon_size = body_size(PSIZE_BODY);
+ const int hold = mitm[net].plus; // this will usually be negative
+ const int mon_size = body_size(PSIZE_BODY);
// smaller monsters can escape more quickly
if (mon_size < random2(SIZE_BIG) // BIG = 5
@@ -4244,7 +4510,12 @@ void monsters::apply_enchantment(const mon_enchant &me)
// berserking doubles damage dealt
if (has_ench(ENCH_BERSERK))
damage *= 2;
-
+
+ // Faster monsters can damage the net more often per
+ // time period.
+ if (speed != 0)
+ damage = div_rand_round(damage * speed, spd);
+
mitm[net].plus -= damage;
if (mitm[net].plus < -7)
@@ -4307,13 +4578,11 @@ void monsters::apply_enchantment(const mon_enchant &me)
del_ench(ENCH_SUBMERGED); // forced to surface
else if (hit_points <= max_hit_points / 2)
break;
- else if (((type == MONS_ELECTRICAL_EEL
- || type == MONS_LAVA_SNAKE)
- && (random2(1000) < mod_speed( 20, spd )
- || (mons_near(this)
- && hit_points == max_hit_points
- && !one_chance_in(10))))
- || random2(2000) < mod_speed(10, spd)
+ else if (((type == MONS_ELECTRICAL_EEL || type == MONS_LAVA_SNAKE)
+ && (one_chance_in(50) || (mons_near(this)
+ && hit_points == max_hit_points
+ && !one_chance_in(10))))
+ || one_chance_in(200)
|| (mons_near(this)
&& hit_points == max_hit_points
&& !one_chance_in(5)))
@@ -4324,7 +4593,7 @@ void monsters::apply_enchantment(const mon_enchant &me)
}
case ENCH_POISON:
{
- int poisonval = me.degree;
+ const int poisonval = me.degree;
int dam = (poisonval >= 4) ? 1 : 0;
if (coinflip())
@@ -4333,12 +4602,6 @@ void monsters::apply_enchantment(const mon_enchant &me)
if (mons_res_poison(this) < 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 / spd) + ((random2(spd) < (dam % spd)) ? 1 : 0);
-
if (dam > 0)
{
hurt_monster( this, dam );
@@ -4362,8 +4625,7 @@ void monsters::apply_enchantment(const mon_enchant &me)
}
case ENCH_ROT:
{
- if (hit_points > 1
- && random2(1000) < mod_speed( 333, spd ))
+ if (hit_points > 1 && one_chance_in(3))
{
hurt_monster(this, 1);
if (hit_points < max_hit_points && coinflip())
@@ -4382,12 +4644,6 @@ void monsters::apply_enchantment(const mon_enchant &me)
if (mons_res_fire( this ) < 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 / spd) + ((random2(spd) < (dam % spd)) ? 1 : 0);
-
if (dam > 0)
{
hurt_monster( this, dam );
@@ -4416,16 +4672,13 @@ void monsters::apply_enchantment(const mon_enchant &me)
case ENCH_GLOWING_SHAPESHIFTER: // this ench never runs out
// number of actions is fine for shapeshifters
- if (type == MONS_GLOWING_SHAPESHIFTER
- || random2(1000) < mod_speed( 250, spd ))
- {
+ if (type == MONS_GLOWING_SHAPESHIFTER || one_chance_in(4))
monster_polymorph(this, RANDOM_MONSTER, PPT_SAME);
- }
break;
case ENCH_SHAPESHIFTER: // this ench never runs out
if (type == MONS_SHAPESHIFTER
- || random2(1000) < mod_speed( 1000 / ((15 * hit_dice) / 5), spd ))
+ || random2(1000) < ( 1000 / ((15 * hit_dice) / 5)))
{
monster_polymorph(this, RANDOM_MONSTER, PPT_SAME);
}
@@ -4666,10 +4919,11 @@ bool monsters::can_see(const actor *target) const
int tx = mon->x;
int ty = mon->y;
- // Assume we can see any monster within LOS radius. This is inaccurate,
- // but can be followed up with a tracer if essential. Trunk does full
- // (expensive) ray tracing up front to figure this out.
- return (distance(x, y, tx, ty) <= LOS_RADIUS * LOS_RADIUS);
+ if (distance(x, y, tx, ty) > LOS_RADIUS * LOS_RADIUS)
+ return false;
+
+ // Ignoring clouds for now.
+ return (num_feats_between(x, y, tx, ty, DNGN_UNSEEN, DNGN_MAXOPAQUE) == 0);
}
void monsters::mutate()
@@ -4713,6 +4967,82 @@ void monsters::apply_location_effects()
if (alive())
mons_check_pool(this);
+
+ if (alive() && has_ench(ENCH_SUBMERGED)
+ && !monster_can_submerge(type, grd[x][y]))
+ {
+ del_ench(ENCH_SUBMERGED);
+ }
+}
+
+// returns true if the trap should be revealed to the player
+bool monsters::do_shaft()
+{
+ if (!is_valid_shaft_level())
+ return (false);
+
+ // Handle instances of do_shaft() being invoked magically when
+ // the monster isn't standing over a shaft.
+ if (trap_type_at_xy(x, y) != TRAP_SHAFT)
+ {
+ switch(grd[x][y])
+ {
+ case DNGN_FLOOR:
+ case DNGN_OPEN_DOOR:
+ case DNGN_TRAP_MECHANICAL:
+ case DNGN_TRAP_MAGICAL:
+ case DNGN_TRAP_NATURAL:
+ case DNGN_UNDISCOVERED_TRAP:
+ case DNGN_ENTER_SHOP:
+ break;
+
+ default:
+ return (false);
+ }
+
+ if (airborne() || total_weight() == 0)
+ {
+ if (mons_near(this))
+ {
+ if (player_monster_visible(this))
+ mprf("A shaft briefly opens up underneath %s!",
+ name(DESC_NOCAP_THE).c_str());
+ else
+ mpr("A shaft briefly opens up in the floor!");
+ }
+ return (false);
+ }
+ }
+
+ level_id lev = shaft_dest();
+
+ if (lev == level_id::current())
+ return (false);
+
+ set_transit(lev);
+ bool reveal = false;
+ if (simple_monster_message(this, " falls through a shaft!"))
+ reveal = true;;
+
+ // Monster is no longer on this level
+ destroy_inventory();
+ monster_cleanup(this);
+
+ return (reveal);
+}
+
+void monsters::put_to_sleep(int)
+{
+ if (has_ench(ENCH_BERSERK))
+ return;
+ behaviour = BEH_SLEEP;
+ add_ench(ENCH_SLEEPY);
+ add_ench(ENCH_SLEEP_WARY);
+}
+
+void monsters::check_awaken(int)
+{
+ // XXX
}
/////////////////////////////////////////////////////////////////////////
diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h
index d5db3061c8..3c39e81179 100644
--- a/crawl-ref/source/mon-util.h
+++ b/crawl-ref/source/mon-util.h
@@ -116,6 +116,8 @@ enum mons_class_flags
M_ARCHER = (1<<23), // gets various archery boosts
+ M_WALL_SHIELDED = (1<<24), // Shielded from attacks if in wall
+
M_SPECIAL_ABILITY = (1<<26), // XXX: eventually make these spells?
M_NO_SKELETON = (1<<29), // boneless corpses
@@ -243,6 +245,23 @@ struct mon_attack_def
}
};
+// Amount of monster->speed_increment used by different actions; defaults
+// to 10.
+struct mon_energy_usage
+{
+ char move;
+ char swim;
+ char attack;
+ char missile; // Arrows/crossbows/etc
+ char spell;
+ char special;
+ char item; // Using an item (i.e., drinking a potion)
+
+ // Percent of monster->speed used when picking up an item; defaults
+ // to 100%
+ char pickup_percent;
+};
+
struct monsterentry
{
short mc; // monster number
@@ -278,17 +297,16 @@ struct monsterentry
// hp will be around 135 each time.
unsigned hpdice[4];
- char AC; // armour class
-
- char ev; // evasion
-
- char speed, speed_inc; // duh!
-
+ char AC; // armour class
+ char ev; // evasion
mon_spellbook_type sec;
corpse_effect_type corpse_thingy;
zombie_size_type zombie_size;
shout_type shouts;
mon_intel_type intel;
+
+ char speed; // How quickly speed_increment increases
+ mon_energy_usage energy_usage; // And how quickly it decreases
mon_itemuse_type gmon_use;
size_type size;
};
@@ -581,6 +599,8 @@ bool mons_looks_distracted(const monsters *m);
bool check_mons_resist_magic( const monsters *monster, int pow );
bool mons_class_is_stationary(int monsclass);
+bool mons_class_is_confusable(int monsclass);
+bool mons_class_is_slowable(int monsclass);
bool mons_is_stationary(const monsters *mons);
bool mons_is_insubstantial(int type);
bool mons_is_submerged( const monsters *mon );
@@ -634,4 +654,6 @@ std::string get_mon_shape_str(const monsters *mon);
std::string get_mon_shape_str(const int type);
std::string get_mon_shape_str(const mon_body_shape shape);
+bool mons_class_can_pass(const int mclass, const dungeon_feature_type grid);
+
#endif
diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc
index 1a8b0c8044..429fc57203 100644
--- a/crawl-ref/source/monplace.cc
+++ b/crawl-ref/source/monplace.cc
@@ -56,6 +56,13 @@ bool grid_compatible(int grid_wanted, int actual_grid, bool generation)
|| (!generation
&& actual_grid == DNGN_SHALLOW_WATER);
+ if (grid_wanted >= DNGN_ROCK_WALL
+ && grid_wanted <= DNGN_CLEAR_PERMAROCK_WALL)
+ {
+ return (actual_grid >= DNGN_ROCK_WALL &&
+ actual_grid <= DNGN_CLEAR_PERMAROCK_WALL);
+ }
+
return (grid_wanted == actual_grid
|| (grid_wanted == DNGN_DEEP_WATER
&& (actual_grid == DNGN_SHALLOW_WATER
@@ -98,13 +105,16 @@ bool monster_habitable_grid(int monster_class, int actual_grid, int flies,
&& (actual_grid == DNGN_LAVA
|| actual_grid == DNGN_DEEP_WATER))
- // Amphibious critters are happy in the water.
+ // Amphibious critters are happy in water or on land.
|| (mons_class_flag(monster_class, M_AMPHIBIOUS)
- && grid_compatible(DNGN_DEEP_WATER, actual_grid))
+ && ((preferred_habitat == DNGN_FLOOR
+ && grid_compatible(DNGN_DEEP_WATER, actual_grid))
+ || (preferred_habitat == DNGN_DEEP_WATER
+ && grid_compatible(DNGN_FLOOR, actual_grid))))
- // And water elementals are native to the water but happy on land
+ // Rock worms are native to walls but are happy on the floor
// as well.
- || (monster_class == MONS_WATER_ELEMENTAL
+ || (monster_class == MONS_ROCK_WORM
&& grid_compatible(DNGN_FLOOR, actual_grid)));
}
@@ -113,6 +123,8 @@ bool monster_can_submerge(int monster_class, int grid)
{
switch (monster_class)
{
+ case MONS_MERFOLK:
+ case MONS_MERMAID:
case MONS_BIG_FISH:
case MONS_GIANT_GOLDFISH:
case MONS_ELECTRICAL_EEL:
@@ -229,6 +241,8 @@ monster_type pick_random_monster(const level_id &place,
monster_type mon_type = MONS_PROGRAM_BUG;
+ monster_type mon_type = MONS_PROGRAM_BUG;
+
lev_mons = power;
if (place.branch == BRANCH_MAIN_DUNGEON
@@ -319,6 +333,24 @@ monster_type pick_random_monster(const level_id &place,
return (mon_type);
}
+static bool can_place_on_trap(int mon_type, trap_type trap)
+{
+ if (trap == TRAP_TELEPORT)
+ return (false);
+
+ if (trap == TRAP_SHAFT)
+ {
+ if (mon_type == RANDOM_MONSTER)
+ return (false);
+
+ return (mons_class_flag(mon_type, M_FLIES)
+ || mons_class_flag(mon_type, M_LEVITATE)
+ || get_monster_data(mon_type)->size == SIZE_TINY);
+ }
+
+ return (true);
+}
+
bool place_monster(int &id, int mon_type, int power, beh_type behaviour,
int target, bool summoned, int px, int py, bool allow_bands,
proximity_type proximity, int extra, int dur,
@@ -366,7 +398,7 @@ bool place_monster(int &id, int mon_type, int power, beh_type behaviour,
int trap = trap_at_xy(px, py);
if (trap >= 0)
{
- if (env.trap[trap].type == TRAP_TELEPORT)
+ if (!can_place_on_trap(mon_type, env.trap[trap].type))
continue;
}
@@ -501,7 +533,7 @@ bool place_monster(int &id, int mon_type, int power, beh_type behaviour,
int trap = trap_at_xy(px, py);
if (trap >= 0)
{
- if (env.trap[trap].type == TRAP_TELEPORT)
+ if (!can_place_on_trap(mon_type, env.trap[trap].type))
continue;
}
@@ -651,6 +683,7 @@ static int place_monster_aux( int mon_type, beh_type behaviour, int target,
menv[id].inv.init(NON_ITEM);
// scrap monster enchantments
menv[id].enchantments.clear();
+ menv[id].ench_countdown = 0;
// setup habitat and placement
if (first_band_member)
@@ -679,7 +712,7 @@ static int place_monster_aux( int mon_type, beh_type behaviour, int target,
// (how do they get there?)
int trap = trap_at_xy(fx, fy);
if (trap >= 0)
- if (env.trap[trap].type == TRAP_TELEPORT)
+ if (!can_place_on_trap(mon_type, env.trap[trap].type))
continue;
// cool.. passes all tests
@@ -1413,8 +1446,7 @@ void mark_interesting_monst(struct monsters* monster, beh_type behaviour)
mons_level(monster->type) < 99 &&
!(monster->type >= MONS_EARTH_ELEMENTAL &&
monster->type <= MONS_AIR_ELEMENTAL)
- && (!Options.safe_zero_exp ||
- !mons_class_flag( monster->type, M_NO_EXP_GAIN )))
+ && !mons_class_flag( monster->type, M_NO_EXP_GAIN ))
interesting = true;
if ( interesting )
@@ -1583,11 +1615,12 @@ bool player_angers_monster(monsters *creation)
int create_monster( int cls, int dur, beh_type beha, int cr_x, int cr_y,
int hitting, int zsec, bool permit_bands,
- bool force_place, bool force_behaviour )
+ bool force_place, bool force_behaviour,
+ bool player_made )
{
int summd = -1;
coord_def pos = find_newmons_square(cls, cr_x, cr_y);
- if (force_place && !grid_is_solid(grd[cr_x][cr_y])
+ if (force_place && mons_class_can_pass(cls, grd[cr_x][cr_y])
&& mgrd[cr_x][cr_y] == NON_MONSTER)
{
pos.x = cr_x;
@@ -1616,6 +1649,11 @@ int create_monster( int cls, int dur, beh_type beha, int cr_x, int cr_y,
if (dur >= 1 && dur <= 6)
creation->add_ench( mon_enchant(ENCH_ABJ, dur) );
+ // player summons do not give XP or other bonuses
+ // (you can still train skills on them though)
+ if ( player_made )
+ creation->flags |= MF_CREATED_FRIENDLY;
+
// look at special cases: CHARMED, FRIENDLY, HOSTILE, GOD_GIFT
// alert summoned being to player's presence
if (beha > NUM_BEHAVIOURS)
@@ -1678,8 +1716,9 @@ bool empty_surrounds(int emx, int emy, unsigned char spc_wanted,
if (mgrd[tx][ty] != NON_MONSTER)
continue;
- // players won't summon out of LOS
- if (!see_grid(tx, ty) && playerSummon)
+ // players won't summon out of LOS, or past transparent
+ // walls.
+ if (!see_grid_no_trans(tx, ty) && playerSummon)
continue;
if (grd[tx][ty] == spc_wanted)
diff --git a/crawl-ref/source/monplace.h b/crawl-ref/source/monplace.h
index 3e91d49568..fa896279c2 100644
--- a/crawl-ref/source/monplace.h
+++ b/crawl-ref/source/monplace.h
@@ -123,7 +123,8 @@ int mons_place( int mon_type, beh_type behaviour, int target, bool summoned,
* *********************************************************************** */
int create_monster( int cls, int dur, beh_type beha, int cr_x, int cr_y,
int hitting, int zsec, bool permit_bands = false,
- bool force_place = false, bool force_behaviour = false );
+ bool force_place = false, bool force_behaviour = false,
+ bool player_made = false );
class level_id;
monster_type pick_random_monster(const level_id &place,
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index adf19e2e98..11b60daf04 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -36,6 +36,7 @@
#include "debug.h"
#include "delay.h"
#include "describe.h"
+#include "dgnevent.h"
#include "fight.h"
#include "hiscores.h"
#include "it_use2.h"
@@ -59,19 +60,21 @@
#include "spl-util.h"
#include "spells2.h"
#include "spells4.h"
+#include "state.h"
#include "stuff.h"
#include "terrain.h"
#include "traps.h"
#include "tutorial.h"
#include "view.h"
#include "stash.h"
+#include "xom.h"
static bool handle_special_ability(monsters *monster, bolt & beem);
static bool handle_pickup(monsters *monster);
static void handle_behaviour(monsters *monster);
static void set_nearest_monster_foe(monsters *monster);
static void mons_in_cloud(monsters *monster);
-static void monster_move(monsters *monster);
+static bool monster_move(monsters *monster);
static bool plant_spit(monsters *monster, bolt &pbolt);
static int map_wand_to_mspell(int wand_type);
@@ -86,7 +89,7 @@ static bool immobile_monster[MAX_MONSTERS];
#define FAR_AWAY 1000000 // used in monster_move()
// This function creates an artificial item to represent a mimic's appearance.
-// Eventually, mimics could be redone to be more like Dancing wepaons...
+// Eventually, mimics could be redone to be more like dancing weapons...
// there'd only be one type and it would look like the item it carries. -- bwr
void get_mimic_item( const monsters *mimic, item_def &item )
{
@@ -116,7 +119,10 @@ void get_mimic_item( const monsters *mimic, item_def &item )
if (prop < 20)
{
- item.flags |= ISFLAG_RANDART;
+ make_item_randart(item);
+ // Override special - this could cause a "bad" (no-properties)
+ // randart, but we only need the name anyway. We have to
+ // do this in order to get a consistent name for the mimic item.
item.special = ((mimic->x << 8 + mimic->y) & RANDART_SEED_MASK);
}
else if (prop < 50)
@@ -144,7 +150,8 @@ void get_mimic_item( const monsters *mimic, item_def &item )
if (prop < 20)
{
- item.flags |= ISFLAG_RANDART;
+ make_item_randart(item);
+ // See comment above for randart weapon mimics.
item.special = ((mimic->x << 8 + mimic->y) & RANDART_SEED_MASK);
}
else if (prop < 40)
@@ -240,6 +247,10 @@ bool curse_an_item( bool decay_potions )
/* don't change you.inv_special (just for fun) */
if (you.inv[item].base_type == OBJ_POTIONS)
{
+ // Xom is amused by useful potions being ruined.
+ if (item_value(you.inv[item], true) / you.inv[item].quantity > 2)
+ xom_is_stimulated(32 * you.inv[item].quantity);
+
you.inv[item].sub_type = POT_DECAY;
unset_ident_flags( you.inv[item], ISFLAG_IDENT_MASK ); // all different
}
@@ -261,6 +272,8 @@ static void monster_drop_ething(monsters *monster,
hostile_grid = true;
}
+ int midx = (int) monster_index(monster);
+
for (i = MSLOT_GOLD; i >= MSLOT_WEAPON; i--)
{
int item = monster->inv[i];
@@ -269,6 +282,7 @@ static void monster_drop_ething(monsters *monster,
{
if (hostile_grid)
{
+ item_was_destroyed(mitm[item], midx);
destroyed = true;
destroy_item( item );
}
@@ -294,7 +308,6 @@ static void monster_drop_ething(monsters *monster,
static void place_monster_corpse(const monsters *monster)
{
int corpse_class = mons_species(monster->type);
-
if (corpse_class == MONS_DRACONIAN)
corpse_class = draco_subspecies(monster);
@@ -303,12 +316,8 @@ static void place_monster_corpse(const monsters *monster)
else if (monster->has_ench(ENCH_GLOWING_SHAPESHIFTER))
corpse_class = MONS_GLOWING_SHAPESHIFTER;
- if (mons_weight(corpse_class) == 0
- || grid_destroys_items(grd[monster->x][monster->y])
- || coinflip())
- {
+ if (mons_weight(corpse_class) == 0 || coinflip())
return;
- }
int o = get_item_slot();
if (o == NON_ITEM)
@@ -326,6 +335,13 @@ static void place_monster_corpse(const monsters *monster)
if (mitm[o].colour == BLACK)
mitm[o].colour = monster->colour;
+ if (grid_destroys_items(grd[monster->x][monster->y]))
+ {
+ item_was_destroyed(mitm[o]);
+ mitm[o].base_type = OBJ_UNASSIGNED;
+ return;
+ }
+
// 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 );
if (see_grid(monster->x, monster->y))
@@ -475,6 +491,8 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent)
if (net != NON_ITEM)
remove_item_stationary(mitm[net]);
}
+ // update list of monsters beholding player
+ update_beholders(monster, true);
const int monster_killed = monster_index(monster);
const bool death_message =
@@ -537,7 +555,13 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent)
}
if (you.prev_targ == monster_killed)
+ {
you.prev_targ = MHITNOT;
+ crawl_state.cancel_cmd_repeat();
+ }
+
+ if (killer == KILL_YOU)
+ crawl_state.cancel_cmd_repeat();
const bool pet_kill = is_pet_kill(killer, i);
@@ -693,7 +717,7 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent)
// no piety loss if god gifts killed by other monsters
if (mons_friendly(monster) && !testbits(monster->flags,MF_GOD_GIFT))
did_god_conduct(DID_FRIEND_DIES, 1 + (monster->hit_dice / 2),
- monster);
+ true, monster);
// Trying to prevent summoning abuse here, so we're trying to
// prevent summoned creatures from being being done_good kills.
@@ -917,6 +941,10 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent)
}
}
+ dungeon_events.fire_event(
+ dgn_event(DET_MONSTER_DIED, monster->pos(), 0,
+ monster_index(monster), killer));
+
const coord_def mwhere = monster->pos();
if (!hard_reset)
monster_drop_ething(monster, YOU_KILL(killer) || pet_kill);
@@ -965,7 +993,7 @@ static bool jelly_divide(monsters * parent)
{
// 10-50 for now - must take clouds into account:
if (mgrd[parent->x + jex][parent->y + jey] == NON_MONSTER
- && !grid_is_solid(grd[parent->x + jex][parent->y + jey])
+ && parent->can_pass_through(parent->x + jex, parent->y + jey)
&& (parent->x + jex != you.x_pos || parent->y + jey != you.y_pos))
{
foundSpot = true;
@@ -1197,10 +1225,18 @@ bool monster_polymorph( monsters *monster, monster_type targetc,
bool player_messaged = simple_monster_message(monster, str_polymon.c_str());
+ // Even if the monster transforms from one type that can behold the
+ // player into a different type which can also behold the player,
+ // the polymorph disrupts the beholding process. Do this before
+ // changing monster->type, since unbeholding can only happen while
+ // the monster is still a mermaid.
+ update_beholders(monster, true);
+
// the actual polymorphing:
const int old_hp = monster->hit_points;
const int old_hp_max = monster->max_hit_points;
const bool old_mon_caught = mons_is_caught(monster);
+ const char old_ench_countdown = monster->ench_countdown;
/* deal with mons_sec */
monster->type = targetc;
@@ -1216,6 +1252,8 @@ bool monster_polymorph( monsters *monster, monster_type targetc,
monster->add_ench(abj);
monster->add_ench(shifter);
+ monster->ench_countdown = old_ench_countdown;
+
if (mons_class_flag( monster->type, M_INVIS ))
monster->add_ench(ENCH_INVIS);
@@ -1322,31 +1360,94 @@ bool monster_blink(monsters *monster)
// 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)
+ bool restrict_LOS)
{
- int tries = 0;
- do
+ // This might involve ray tracing (via num_feats_between()), so
+ // cache results to avoid duplicating ray traces.
+ FixedArray<bool, 14, 14> tried;
+ tried.init(false);
+
+ // Is the monster on the other side of a tranparent wall?
+ bool trans_wall_block = trans_wall_blocking(ox, oy);
+ bool origin_is_player = (you.pos() == coord_def(ox, oy));
+ int min_walls_between = 0;
+
+ // Skip ray tracing if possible.
+ if (trans_wall_block)
+ min_walls_between = num_feats_between(ox, oy, you.x_pos, you.y_pos,
+ DNGN_CLEAR_ROCK_WALL,
+ DNGN_CLEAR_PERMAROCK_WALL);
+ int tries = 0;
+ while (tries++ < 150)
{
- tx = ox - 6 + random2(14);
- ty = oy - 6 + random2(14);
+ int dx = random2(14);
+ int dy = random2(14);
+
+ tx = ox - 6 + dx;
+ ty = oy - 6 + dy;
// origin is not 'near'
if (tx == ox && ty == oy)
continue;
- tries++;
+ if (tried[dx][dy])
+ continue;
- if (tries > 149)
- break;
+ tried[dx][dy] = true;
+
+ if (!in_bounds(tx, ty)
+ || (!see_grid(tx, ty) && restrict_LOS)
+ || grd[tx][ty] < DNGN_SHALLOW_WATER
+ || mgrd[tx][ty] != NON_MONSTER
+ || (tx == you.x_pos && ty == you.y_pos)
+ || (!allow_adjacent && distance(ox, oy, tx, ty) <= 2))
+ continue;
+
+ if (!trans_wall_block && !origin_is_player)
+ return (true);
+
+ // If the monster is on a visible square which is on the other
+ // side of one or more translucent from the player, then it
+ // can only blink through translucent walls if the end point
+ // is either not visible to the player, or there are at least
+ // as many translucent walls between the player and the end
+ // point as between the player and the start point. However,
+ // monsters can still blink through translucent walls to get
+ // away from the player, since in the absence of tranlucent
+ // walls monsters can blink to places which are not in either
+ // the monster's nor the player's LOS.
+ if (!see_grid(tx, ty) && !origin_is_player)
+ return (true);
+
+ // Player can't randomly pass through translucent walls.
+ if (origin_is_player)
+ {
+ if (see_grid_no_trans(tx, ty))
+ return (true);
+
+ continue;
+ }
+
+ int walls_passed = num_feats_between(tx, ty, ox, oy,
+ DNGN_CLEAR_ROCK_WALL,
+ DNGN_CLEAR_PERMAROCK_WALL);
+ if (walls_passed == 0)
+ return (true);
+
+ // Player can't randomly pass through translucent walls.
+ if (origin_is_player)
+ continue;
+
+ int walls_between = num_feats_between(tx, ty, you.x_pos, you.y_pos,
+ DNGN_CLEAR_ROCK_WALL,
+ DNGN_CLEAR_PERMAROCK_WALL);
+
+ if (walls_between >= min_walls_between)
+ return (true);
}
- while ((!see_grid(tx, ty) && restrict_LOS)
- || grd[tx][ty] < DNGN_SHALLOW_WATER
- || mgrd[tx][ty] != NON_MONSTER
- || (tx == you.x_pos && ty == you.y_pos)
- || (!allow_adjacent && distance(ox, oy, tx, ty) <= 2));
- return (tries < 150);
+ return (false);
} // end random_near_space()
static bool habitat_okay( const monsters *monster, int targ )
@@ -1571,7 +1672,7 @@ void behaviour_event( monsters *mon, int event, int src,
// will turn monster against <src>, unless they
// are BOTH friendly and stupid, or else fleeing anyway.
// Hitting someone over the head, of course,
- // always triggers this code.
+ // always triggers this code.
if ( event == ME_WHACK ||
((isFriendly != sourceFriendly || isSmart) &&
(mon->behaviour != BEH_FLEE && mon->behaviour != BEH_PANIC)))
@@ -1617,7 +1718,7 @@ void behaviour_event( monsters *mon, int event, int src,
// if player is invisible.
setTarget = true;
if (see_grid(mon->x, mon->y))
- learned_something_new(TUT_FLEEING_MONSTER);
+ learned_something_new(TUT_FLEEING_MONSTER);
break;
case ME_CORNERED:
@@ -1663,6 +1764,11 @@ void behaviour_event( monsters *mon, int event, int src,
// 1. Evalutates current AI state
// 2. Sets monster targetx,y based on current foe
//
+// XXX: Monsters of I_NORMAL or above should select a new target
+// if their current target is another monser which is sitting in
+// a wall and is immune to most attacks while in a wall
+// (M_WALL_SHIELDED), unless the monster has a spell or special/nearby
+// ability which isn't affected by M_WALL_SHIELDED.
//---------------------------------------------------------------
static void handle_behaviour(monsters *mon)
{
@@ -1999,6 +2105,13 @@ static void handle_behaviour(monsters *mon)
// we can jump back to WANDER if the foe
// isn't present.
+ // XXX: If a monster can move through solid grids then it
+ // should preferentially flee towards the nearest solid grid
+ // it can move through. If it has M_WALL_SHIELDED is will
+ // be (mostly) safe as soon as it enters the wall, and even
+ // if it doesn't once it moves again it will be on the other
+ // side of the wall and likely beyond the reach of the player.
+
if (isFriendly)
{
// Special-cased below so that it will flee *towards* you
@@ -2122,40 +2235,6 @@ bool simple_monster_message(const monsters *monster, const char *event,
return (false);
} // end simple_monster_message()
-static bool handle_enchantment(monsters *monster)
-{
- // Yes, this is the speed we want. This function will be called in
- // two circumstances: (1) the monster can move and has 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
- monster->apply_enchantments();
- return (!monster->alive());
-} // end handle_enchantment()
-
//---------------------------------------------------------------
//
// handle_movement
@@ -2308,6 +2387,8 @@ static void handle_nearby_ability(monsters *monster)
case MONS_LAVA_FISH:
case MONS_LAVA_SNAKE:
case MONS_SALAMANDER:
+ case MONS_MERFOLK:
+ case MONS_MERMAID:
case MONS_BIG_FISH:
case MONS_GIANT_GOLDFISH:
case MONS_ELECTRICAL_EEL:
@@ -2315,18 +2396,26 @@ static void handle_nearby_ability(monsters *monster)
case MONS_WATER_ELEMENTAL:
case MONS_SWAMP_WORM:
if (monster_can_submerge(monster->type, grd[monster->x][monster->y])
- && (one_chance_in(5) || (grid_distance( monster->x, monster->y,
- you.x_pos, you.y_pos ) > 1
- // FIXME This is better expressed as a
- // function such as
- // monster_has_ranged_attack:
- && monster->type != MONS_ELECTRICAL_EEL
- && monster->type != MONS_LAVA_SNAKE
- && !one_chance_in(20))
+ && ( !player_beheld_by(monster) // no submerging if player entranced
+ && (one_chance_in(5)
+ || ((grid_distance( monster->x, monster->y,
+ you.x_pos, you.y_pos ) > 1
+ // FIXME This is better expressed as a
+ // function such as
+ // monster_has_ranged_attack:
+ && monster->type != MONS_ELECTRICAL_EEL
+ && monster->type != MONS_LAVA_SNAKE
+ && (monster->type != MONS_MERMAID
+ || you.species == SP_MERFOLK)
+ // Don't submerge if we just unsubmerged for
+ // the sake of shouting.
+ && monster->seen_context != "bursts forth shouting"
+ && !one_chance_in(20)) ))
|| monster->hit_points <= monster->max_hit_points / 2)
|| env.cgrid[monster->x][monster->y] != EMPTY_CLOUD)
{
monster->add_ench(ENCH_SUBMERGED);
+ update_beholders(monster);
}
break;
@@ -2655,10 +2744,97 @@ static bool handle_special_ability(monsters *monster, bolt & beem)
}
break;
+ case MONS_MERMAID:
+ {
+ // won't sing if either of you silenced, or it's friendly or confused
+ if (monster->has_ench(ENCH_CONFUSION) || mons_friendly(monster)
+ || silenced(monster->x, monster->y) || silenced(you.x_pos, you.y_pos))
+ {
+ break;
+ }
+
+ // reduce probability because of spamminess
+ if (you.species == SP_MERFOLK && !one_chance_in(4))
+ break;
+
+ // a wounded invisible mermaid is less likely to give away her position
+ if (monster->invisible()
+ && monster->hit_points <= monster->max_hit_points / 2
+ && !one_chance_in(3))
+ {
+ break;
+ }
+
+ bool already_beheld = player_beheld_by(monster);
+
+ if (one_chance_in(5)
+ || monster->foe == MHITYOU && !already_beheld && coinflip())
+ {
+ if (player_monster_visible(monster))
+ {
+ simple_monster_message(monster,
+ make_stringf(" chants %s song.",
+ already_beheld? "her luring" : "a haunting").c_str(),
+ MSGCH_MONSTER_SPELL);
+ }
+ else
+ {
+ // if you're already beheld by an invisible mermaid she can
+ // still prolong the enchantment; otherwise you "resist"
+ if (already_beheld)
+ mpr("You hear a luring song.", MSGCH_SOUND);
+ else
+ {
+ if (one_chance_in(4)) // reduce spamminess
+ {
+ if (coinflip())
+ mpr("You hear a haunting song.", MSGCH_SOUND);
+ else
+ mpr("You hear an eerie melody.", MSGCH_SOUND);
+
+ canned_msg(MSG_YOU_RESIST); // flavour only
+ }
+ break;
+ }
+ }
+
+ // once beheld by a particular monster, cannot resist anymore
+ if (!already_beheld
+ && (you.species == SP_MERFOLK || you_resist_magic(100)))
+ {
+ canned_msg(MSG_YOU_RESIST);
+ break;
+ }
+
+ if (!you.duration[DUR_BEHELD])
+ {
+ you.duration[DUR_BEHELD] = 7;
+ you.beheld_by.push_back(monster_index(monster));
+ mpr("You are beheld!", MSGCH_WARN);
+ }
+ else
+ {
+ you.duration[DUR_BEHELD] += 5;
+ if (!already_beheld)
+ you.beheld_by.push_back(monster_index(monster));
+ }
+ used = true;
+
+ if (you.duration[DUR_BEHELD] > 12)
+ you.duration[DUR_BEHELD] = 12;
+ }
+ break;
+ }
default:
break;
}
+ if (used)
+ {
+ monsterentry *entry = get_monster_data(monster->type);
+ monster->speed_increment -= entry->energy_usage.special;
+ }
+
return (used);
} // end handle_special_ability()
@@ -2760,6 +2936,9 @@ static bool handle_potion(monsters *monster, bolt & beem)
if (ident != ID_UNKNOWN_TYPE && was_visible)
set_ident_type(OBJ_POTIONS, potion_type, ident);
+
+ monsterentry *entry = get_monster_data(monster->type);
+ monster->speed_increment -= entry->energy_usage.item;
}
return (imbibed);
@@ -2900,6 +3079,9 @@ static bool handle_scroll(monsters *monster)
if (ident != ID_UNKNOWN_TYPE && was_visible)
set_ident_type(OBJ_SCROLLS, scroll_type, ident);
+
+ monsterentry *entry = get_monster_data(monster->type);
+ monster->speed_increment -= entry->energy_usage.item;
}
return read;
@@ -2962,12 +3144,13 @@ static bool handle_wand(monsters *monster, bolt &beem)
beem.is_beam = theBeam.is_beam;
beem.is_explosion = theBeam.is_explosion;
- unsigned long old_flags = wand.flags;
#if HISCORE_WEAPON_DETAIL
- set_ident_flags( wand, ISFLAG_IDENT_MASK );
+ beem.aux_source =
+ wand.name(DESC_QUALNAME, false, true, false, false);
#else
- unset_ident_flags( wand, ISFLAG_IDENT_MASK );
- set_ident_flags( wand, ISFLAG_KNOW_TYPE );
+ beem.aux_source =
+ wand.name(DESC_QUALNAME, false, true, false, false,
+ ISFLAG_KNOW_CURSE | ISFLAG_KNOW_PLUSES);
#endif
beem.aux_source = wand.name(DESC_PLAIN);
wand.flags = old_flags;
@@ -3071,6 +3254,9 @@ static bool handle_wand(monsters *monster, bolt &beem)
wand.plus2++;
}
+ monsterentry *entry = get_monster_data(monster->type);
+ monster->speed_increment -= entry->energy_usage.item;
+
return (true);
}
}
@@ -3589,6 +3775,9 @@ static bool handle_spell( monsters *monster, bolt & beem )
{
simple_monster_message(monster, " blinks!");
monster_blink(monster);
+
+ monsterentry *entry = get_monster_data(monster->type);
+ monster->speed_increment -= entry->energy_usage.spell;
}
else
return (false);
@@ -3598,6 +3787,8 @@ static bool handle_spell( monsters *monster, bolt & beem )
mons_cast(monster, beem, spell_cast);
mmov_x = 0;
mmov_y = 0;
+ monsterentry *entry = get_monster_data(monster->type);
+ monster->speed_increment -= entry->energy_usage.spell;
}
} // end "if mons_class_flag(monster->type, M_SPELLCASTER) ...
@@ -3783,9 +3974,6 @@ static void monster_add_energy(monsters *monster)
energy_gained = 1;
monster->speed_increment += energy_gained;
-
- if (you.duration[DUR_SLOW] > 0)
- monster->speed_increment += energy_gained;
}
// Do natural regeneration for monster.
@@ -3824,6 +4012,29 @@ static void monster_regenerate(monsters *monster)
}
}
+static void swim_or_move_energy(monsters *mon)
+{
+ monsterentry *entry = get_monster_data(mon->type);
+ dungeon_feature_type feat = grd[mon->x][mon->y];
+ if (feat >= DNGN_LAVA && feat <= DNGN_SHALLOW_WATER
+ && !mon->airborne())
+ {
+ mon->speed_increment -= entry->energy_usage.swim;
+ }
+ else
+ mon->speed_increment -= entry->energy_usage.move;
+}
+
+#if DEBUG
+# define DEBUG_ENERGY_USE(problem) \
+ if (monster->speed_increment == old_energy) \
+ mprf(MSGCH_DIAGNOSTICS, \
+ problem " for monster '%s' consumed no energy", \
+ monster->name(DESC_PLAIN).c_str(), true);
+#else
+# define DEBUG_ENERGY_USE(problem) ((void) 0)
+#endif
+
static void handle_monster_move(int i, monsters *monster)
{
bool brkk = false;
@@ -3842,7 +4053,7 @@ static void handle_monster_move(int i, monsters *monster)
monster_add_energy(monster);
- // Handle enchantments and clouds on nonmoving monsters:
+ // Handle clouds on nonmoving monsters:
if (monster->speed == 0)
{
if (env.cgrid[monster->x][monster->y] != EMPTY_CLOUD
@@ -3850,9 +4061,25 @@ static void handle_monster_move(int i, monsters *monster)
{
mons_in_cloud( monster );
}
+ }
+
+ // Apply monster enchantments once for every normal-speed
+ // player turn.
+ monster->ench_countdown -= you.time_taken;
+ while (monster->ench_countdown < 0)
+ {
+ monster->ench_countdown += 10;
+ monster->apply_enchantments();
- if (handle_enchantment( monster ))
+ // If the monster *merely* died just break from the loop
+ // rather than quit altogether, since we have to deal with
+ // giant spores and ball lightning exploding at the end of the
+ // function, but do return if the monster's data has been
+ // reset, since then the monster type is invalid.
+ if (monster->type == -1)
return;
+ else if (monster->hit_points < 1)
+ break;
}
// memory is decremented here for a reason -- we only want it
@@ -3879,21 +4106,47 @@ static void handle_monster_move(int i, monsters *monster)
}
monster->check_speed();
-
+
+ monsterentry* entry = get_monster_data(monster->type);
+
+ int old_energy = INT_MAX;
+ int non_move_energy = std::min(entry->energy_usage.move,
+ entry->energy_usage.swim);
+
while (monster->has_action_energy())
{ // The continues & breaks are WRT this.
if (!monster->alive())
break;
- monster->speed_increment -= 10;
+ if (monster->speed_increment >= old_energy)
+ {
+#if DEBUG
+ if (monster->speed_increment == old_energy)
+ mprf(MSGCH_DIAGNOSTICS, "'%s' has same energy as last loop",
+ monster->name(DESC_PLAIN, true).c_str());
+ else
+ mprf(MSGCH_DIAGNOSTICS, "'%s' has MORE energy than last loop",
+ monster->name(DESC_PLAIN, true).c_str());
+#endif
+ monster->speed_increment = old_energy - 10;
+ old_energy = monster->speed_increment;
+ continue;
+ }
+ old_energy = monster->speed_increment;
if (env.cgrid[monster->x][monster->y] != EMPTY_CLOUD)
{
if (monster->has_ench(ENCH_SUBMERGED))
+ {
+ monster->speed_increment -= entry->energy_usage.swim;
break;
+ }
if (monster->type == -1)
+ {
+ monster->speed_increment -= entry->energy_usage.move;
break; // problem with vortices
+ }
mons_in_cloud(monster);
@@ -3911,13 +4164,13 @@ static void handle_monster_move(int i, monsters *monster)
monster->colour = newcol;
}
- if (handle_enchantment(monster))
- break;
-
monster_regenerate(monster);
if (mons_is_paralysed(monster))
+ {
+ monster->speed_increment -= non_move_energy;
continue;
+ }
handle_behaviour(monster);
@@ -3929,7 +4182,10 @@ static void handle_monster_move(int i, monsters *monster)
}
if (monster->speed >= 100)
+ {
+ monster->speed_increment -= non_move_energy;
continue;
+ }
if (monster->type == MONS_ZOMBIE_SMALL
|| monster->type == MONS_ZOMBIE_LARGE
@@ -3951,11 +4207,17 @@ static void handle_monster_move(int i, monsters *monster)
if (monster->attitude != ATT_FRIENDLY)
{
if (handle_pickup(monster))
+ {
+ DEBUG_ENERGY_USE("handle_pickup()");
continue;
+ }
}
}
- if (!mons_is_caught(monster))
+ if (mons_is_caught(monster))
+ // Struggling against the net takes time.
+ swim_or_move_energy(monster);
+ else
{
// calculates mmov_x, mmov_y based on monster target.
handle_movement(monster);
@@ -3974,7 +4236,7 @@ static void handle_monster_move(int i, monsters *monster)
for (int xi = -1; xi <= 1; ++xi)
{
coord_def c = monster->pos() + coord_def(xi, yi);
- if (in_bounds(c) && !grid_is_solid(grd(c))
+ if (in_bounds(c) && monster->can_pass_through(c)
&& one_chance_in(++pfound))
{
mmov_x = xi;
@@ -4000,8 +4262,8 @@ static void handle_monster_move(int i, monsters *monster)
mmov_y = 0;
}
- if (grid_is_solid(
- grd[ monster->x + mmov_x ][ monster->y + mmov_y ]))
+ if (!monster->can_pass_through(monster->x + mmov_x,
+ monster->y + mmov_y))
{
mmov_x = mmov_y = 0;
}
@@ -4012,10 +4274,11 @@ static void handle_monster_move(int i, monsters *monster)
monsters_fight(
i,
mgrd[monster->x + mmov_x][monster->y + mmov_y]);
-
+
brkk = true;
mmov_x = 0;
mmov_y = 0;
+ DEBUG_ENERGY_USE("monsters_fight()");
}
}
@@ -4048,24 +4311,40 @@ static void handle_monster_move(int i, monsters *monster)
: handle_monster_spell(monster, beem)
|| handle_special_ability(monster, beem))
{
+ DEBUG_ENERGY_USE("spell or special");
continue;
}
if (handle_potion(monster, beem))
+ {
+ DEBUG_ENERGY_USE("handle_potion()");
continue;
+ }
if (handle_scroll(monster))
+ {
+ DEBUG_ENERGY_USE("handle_scroll()");
continue;
+ }
if (handle_wand(monster, beem))
+ {
+ DEBUG_ENERGY_USE("handle_wand()");
continue;
+ }
if (handle_reaching(monster))
+ {
+ DEBUG_ENERGY_USE("handle_reaching()");
continue;
+ }
}
if (handle_throw(monster, beem))
+ {
+ DEBUG_ENERGY_USE("handle_throw()");
continue;
+ }
}
if (!mons_is_caught(monster))
@@ -4090,6 +4369,7 @@ static void handle_monster_move(int i, monsters *monster)
mmov_x = 0;
mmov_y = 0;
brkk = true;
+ DEBUG_ENERGY_USE("monsters_fight()");
}
}
@@ -4113,6 +4393,7 @@ static void handle_monster_move(int i, monsters *monster)
monster->target_x = 10 + random2(GXM - 10);
monster->target_y = 10 + random2(GYM - 10);
}
+ DEBUG_ENERGY_USE("monster_attack()");
}
if ((monster->type == MONS_GIANT_SPORE
@@ -4138,10 +4419,17 @@ static void handle_monster_move(int i, monsters *monster)
}
if (invalid_monster(monster) || mons_is_stationary(monster))
+ {
+ if (monster->speed_increment == old_energy)
+ monster->speed_increment -= non_move_energy;
continue;
+ }
- monster_move(monster);
+ if (!monster_move(monster))
+ monster->speed_increment -= non_move_energy;
}
+ update_beholders(monster);
+
// reevaluate behaviour, since the monster's
// surroundings have changed (it may have moved,
// or died for that matter. Don't bother for
@@ -4159,7 +4447,7 @@ static void handle_monster_move(int i, monsters *monster)
// 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 );
return;
@@ -4168,7 +4456,7 @@ static void handle_monster_move(int i, monsters *monster)
{
monster_die( monster, KILL_MISC, 0 );
}
- }
+ }
}
//---------------------------------------------------------------
@@ -4201,7 +4489,15 @@ void handle_monsters(void)
// If the player got banished, discard pending monster actions.
if (you.banished)
+ {
+ // clear list of beholding monsters
+ if (you.duration[DUR_BEHELD])
+ {
+ you.beheld_by.clear();
+ you.duration[DUR_BEHELD] = 0;
+ }
break;
+ }
} // end of for loop
// Clear any summoning flags so that lower indiced
@@ -4259,10 +4555,11 @@ static bool handle_pickup(monsters *monster)
if (mons_itemuse(monster->type) == MONUSE_EATS_ITEMS)
{
- int hps_gained = 0;
- int max_eat = roll_dice( 1, 10 );
- int eaten = 0;
- bool eaten_net = false;
+ int midx = monster_index(monster);
+ int hps_gained = 0;
+ int max_eat = roll_dice( 1, 10 );
+ int eaten = 0;
+ bool eaten_net = false;
for (item = igrd[monster->x][monster->y];
item != NON_ITEM && eaten < max_eat && hps_gained < 50;
@@ -4300,6 +4597,9 @@ static bool handle_pickup(monsters *monster)
eaten++;
}
+ if (quant >= mitm[item].quantity)
+ item_was_destroyed(mitm[item], midx);
+
dec_mitm_item_quantity( item, quant );
}
@@ -4339,7 +4639,7 @@ static bool handle_pickup(monsters *monster)
return (false);
} // end "if jellies"
- // Note: Monsters only look at top of stacks.
+ // Note: Monsters only look at stuff near the top of stacks.
for (item = igrd[monster->x][monster->y]; item != NON_ITEM; )
{
@@ -4451,6 +4751,8 @@ static bool monster_swaps_places( monsters *mon, int mx, int my )
return (false);
// Okay, do the swap!
+ swim_or_move_energy(mon);
+
mon->x = nx;
mon->y = ny;
mgrd[nx][ny] = monster_index(mon);
@@ -4469,55 +4771,52 @@ static bool monster_swaps_places( monsters *mon, int mx, int my )
return (false);
}
-static void do_move_monster(monsters *monster, int xi, int yi)
+static bool do_move_monster(monsters *monster, int xi, int yi)
{
const int fx = monster->x + xi,
fy = monster->y + yi;
if (!in_bounds(fx, fy))
- return;
+ return false;
if (fx == you.x_pos && fy == you.y_pos)
{
monster_attack( monster_index(monster) );
- return;
+ return true;
}
if (!xi && !yi)
{
const int mx = monster_index(monster);
monsters_fight( mx, mx );
- return;
+ return true;
}
if (mgrd[fx][fy] != NON_MONSTER)
{
monsters_fight( monster_index(monster), mgrd[fx][fy] );
- return;
+ return true;
}
if (!xi && !yi)
- return;
+ return false;
+
+ /* this appears to be the real one, ie where the movement occurs: */
+ swim_or_move_energy(monster);
mgrd[monster->x][monster->y] = NON_MONSTER;
- /* this appears to be the real one, ie where the movement occurs: */
monster->x = fx;
monster->y = fy;
- if (monster->type == MONS_CURSE_TOE)
- {
- // Curse toes are a special case; they can only move at half their
- // attack rate. To simulate that, the toe loses more energy.
- monster->speed_increment -= 5;
- }
-
/* 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);
monster->check_redraw(monster->pos() - coord_def(xi, yi));
monster->apply_location_effects();
+
+ return true;
}
void mons_check_pool(monsters *mons, killer_type killer, int killnum)
@@ -4573,28 +4872,129 @@ void mons_check_pool(monsters *mons, killer_type killer, int killnum)
}
}
-static bool mon_can_move_to_pos(const monsters *monster, const int okmove,
- const int count_x, const int count_y,
- bool just_check = false);
+// returns true for monsters that obviously (to the player) feel
+// "thematically at home" in a branch
+// currently used for native monsters recognizing traps
+static bool is_native_in_branch(const monsters *monster, const branch_type branch)
+{
+ switch (branch)
+ {
+ case BRANCH_ELVEN_HALLS:
+ if (mons_species(monster->type) == MONS_ELF)
+ return true;
+ return false;
+
+ case BRANCH_ORCISH_MINES:
+ if (mons_species(monster->type) == MONS_ORC)
+ return true;
+ return false;
+
+ case BRANCH_SLIME_PITS:
+ if (mons_species(monster->type) == MONS_JELLY)
+ return true;
+ return false;
+
+ case BRANCH_SNAKE_PIT:
+ if (mons_species(monster->type) == MONS_NAGA
+ || mons_species(monster->type) == MONS_SNAKE)
+ {
+ return true;
+ }
+ return false;
+
+ case BRANCH_HALL_OF_ZOT:
+ if (mons_species(monster->type) == MONS_DRACONIAN)
+ return true;
+ return false;
+
+ case BRANCH_TOMB:
+ if (mons_species(monster->type) == MONS_MUMMY)
+ return true;
+ return false;
+
+ case BRANCH_HIVE:
+ if (monster->type == MONS_KILLER_BEE
+ || monster->type == MONS_KILLER_BEE_LARVA)
+ {
+ return true;
+ }
+ return false;
+
+ case BRANCH_HALL_OF_BLADES:
+ if (monster->type == MONS_DANCING_WEAPON)
+ return true;
+ return false;
+
+ default:
+ return false;
+ }
+}
+
+// randomize potential damage
+static int estimated_trap_damage(trap_type trap)
+{
+ switch (trap)
+ {
+ case TRAP_BLADE:
+ return (10 + random2(30));
+ case TRAP_DART:
+ return (random2(4));
+ case TRAP_ARROW:
+ return (random2(7));
+ case TRAP_SPEAR:
+ return (random2(10));
+ case TRAP_BOLT:
+ return (random2(13));
+ case TRAP_AXE:
+ return (random2(15));
+ default:
+ return (0);
+ }
+}
+
+static bool mon_can_move_to_pos(const monsters *monster, const int count_x,
+ const int count_y, bool just_check = false);
// Check whether a given trap (described by trap position) can be
// regarded as safe. Takes in account monster intelligence and allegiance.
-// (just_check is used for intelligent friendlies trying to avoid traps.)
+// (just_check is used for intelligent monsters trying to avoid traps.)
static bool is_trap_safe(const monsters *monster, const int trap_x,
- const int trap_y, const int okmove,
- bool just_check = false)
+ const int trap_y, bool just_check = false)
{
- const trap_struct &trap = env.trap[trap_at_xy(trap_x,trap_y)];
+ const int intel = mons_intel(monster->type);
// Dumb monsters don't care at all.
- if (mons_intel(monster->type) == I_PLANT)
+ if (intel == I_PLANT)
return (true);
+
+ const trap_struct &trap = env.trap[trap_at_xy(trap_x,trap_y)];
- // permanent intelligent friendlies will try to avoid traps
- // the player knows about (we're assuming s/he warned them about them)
- if (grd[trap_x][trap_y] != DNGN_UNDISCOVERED_TRAP
- && trap_category(trap.type) != DNGN_TRAP_MAGICAL // magic doesn't matter
- && intelligent_ally(monster))
+ if (trap.type == TRAP_SHAFT && monster->will_trigger_shaft())
+ {
+ if (mons_is_fleeing(monster) && intel >= I_NORMAL)
+ return (true);
+ return (false);
+ }
+
+ // Monsters are not afraid of non-mechanical traps. XXX: If we add
+ // any non-mechanical traps that can damage monsters, must add
+ // check here.
+ const bool mechanical = trap_category(trap.type) == DNGN_TRAP_MECHANICAL;
+
+ const bool player_knows_trap = (grd[trap_x][trap_y] != DNGN_UNDISCOVERED_TRAP);
+
+ // Smarter trap handling for intelligent monsters
+ // * monsters native to a branch can be assumed to know the trap
+ // locations and thus be able to avoid them
+ // * permanent friendlies can be assumed to have been warned by the
+ // player about all traps s/he knows about
+ // * very intelligent monsters can be assumed to have a high T&D skill
+ // (or have memorized part of the dungeon layout ;) )
+ if (intel >= I_NORMAL && mechanical
+ && (is_native_in_branch(monster, you.where_are_you)
+ || monster->attitude == ATT_FRIENDLY
+ && player_knows_trap
+ || intel >= I_HIGH && one_chance_in(3)))
{
if (just_check)
return false; // square is blocked
@@ -4622,10 +5022,10 @@ static bool is_trap_safe(const monsters *monster, const int trap_x,
// If a monster still gets stuck in a corridor it will usually be
// because it has less than half its maximum hp
- if ((mon_can_move_to_pos(monster, okmove, x-1, y, true)
- || mon_can_move_to_pos(monster, okmove, x+1, y, true))
- && (mon_can_move_to_pos(monster, okmove, x, y-1, true)
- || mon_can_move_to_pos(monster, okmove, x, y+1, true)))
+ if ((mon_can_move_to_pos(monster, x-1, y, true)
+ || mon_can_move_to_pos(monster, x+1,y, true))
+ && (mon_can_move_to_pos(monster, x,y-1, true)
+ || mon_can_move_to_pos(monster, x,y+1, true)))
{
return (false);
}
@@ -4634,22 +5034,19 @@ static bool is_trap_safe(const monsters *monster, const int trap_x,
// friendlies will try not to be parted from you
if (intelligent_ally(monster) && trap.type == TRAP_TELEPORT
- && mons_near(monster))
+ && player_knows_trap && mons_near(monster))
{
return (false);
}
-
- // Healthy monsters don't mind a little pain. XXX: Smart humanoids
- // with low hp should probably not try to go through high-damage
- // traps.
- if (monster->hit_points >= monster->max_hit_points / 2)
+
+ // Healthy monsters don't mind a little pain.
+ if (mechanical && monster->hit_points >= monster->max_hit_points / 2
+ && (intel == I_ANIMAL
+ || monster->hit_points > estimated_trap_damage(trap.type)))
+ {
return (true);
-
- // Monsters are not afraid of non-mechanical traps. XXX: If we add
- // any non-mechanical traps that can damage monsters, must add
- // check here.
- const bool mechanical = trap_category(trap.type) == DNGN_TRAP_MECHANICAL;
-
+ }
+
// Friendly monsters don't enjoy Zot trap perks, handle accordingly.
if (mons_friendly(monster))
return (mechanical? mons_flies(monster) : trap.type != TRAP_ZOT);
@@ -4657,22 +5054,41 @@ static bool is_trap_safe(const monsters *monster, const int trap_x,
return (!mechanical || mons_flies(monster));
}
-static void mons_open_door(const coord_def &pos)
+static void mons_open_door(monsters* monster, const coord_def &pos)
{
- if (grd(pos) == DNGN_SECRET_DOOR && !see_grid(pos))
+ bool was_secret = (grd(pos) == DNGN_SECRET_DOOR);
+
+ if (was_secret && !see_grid(pos))
set_terrain_changed(pos);
grd(pos) = DNGN_OPEN_DOOR;
+
+ if (see_grid(pos))
+ {
+ viewwindow(true, false);
+
+ if (was_secret)
+ mpr("The rock wall was actually a secret door!");
+
+ if (!you.can_see(monster))
+ {
+ mpr("Something unseen opens the door.");
+ interrupt_activity(AI_FORCE_INTERRUPT);
+ }
+ }
+
+ monsterentry *entry = get_monster_data(monster->type);
+ monster->speed_increment -= entry->energy_usage.move;
}
// Check whether a monster can move to given square (described by its relative
// coordinates to the current monster position). just_check is true only for
// calls from is_trap_safe when checking the surrounding squares of a trap.
-bool mon_can_move_to_pos(const monsters *monster, const int okmove,
- const int count_x, const int count_y, bool just_check)
+bool mon_can_move_to_pos(const monsters *monster, const int count_x,
+ const int count_y, bool just_check)
{
const int targ_x = monster->x + count_x;
const int targ_y = monster->y + count_y;
-
+
// bounds check - don't consider moving out of grid!
if (targ_x < 0 || targ_x >= GXM || targ_y < 0 || targ_y >= GYM)
return false;
@@ -4681,6 +5097,13 @@ bool mon_can_move_to_pos(const monsters *monster, const int okmove,
const int habitat = monster_habitat( monster->type );
+ // effectively slows down monster movement across water.
+ // Fire elementals can't cross at all.
+ bool no_water = false;
+ if (monster->type == MONS_FIRE_ELEMENTAL || one_chance_in(5))
+ //okmove = DNGN_WATER_STUCK;
+ no_water = true;
+
const int targ_cloud_num = env.cgrid[ targ_x ][ targ_y ];
const int targ_cloud_type =
targ_cloud_num == EMPTY_CLOUD? CLOUD_NONE
@@ -4692,7 +5115,8 @@ bool mon_can_move_to_pos(const monsters *monster, const int okmove,
: env.cloud[curr_cloud_num].type;
if (monster->type == MONS_BORING_BEETLE
- && target_grid == DNGN_ROCK_WALL)
+ && (target_grid == DNGN_ROCK_WALL
+ || target_grid == DNGN_CLEAR_ROCK_WALL))
{
// don't burrow out of bounds
if (targ_x <= 7 || targ_x >= (GXM - 8)
@@ -4703,13 +5127,21 @@ bool mon_can_move_to_pos(const monsters *monster, const int okmove,
// don't burrow at an angle (legacy behaviour)
if (count_x != 0 && count_y != 0)
+ {
return false;
+ }
}
- else if (grd[ targ_x ][ targ_y ] < okmove)
+ else if (!monster->can_pass_through(target_grid)
+ || (no_water && target_grid >= DNGN_DEEP_WATER
+ && target_grid <= DNGN_WATER_STUCK))
+ {
return false;
+ }
else if (!habitat_okay( monster, target_grid ))
+ {
return false;
-
+ }
+
if (monster->type == MONS_WANDERING_MUSHROOM
&& see_grid(targ_x, targ_y))
{
@@ -4748,7 +5180,7 @@ bool mon_can_move_to_pos(const monsters *monster, const int okmove,
{
return false;
}
-
+
// smacking the player is always a good move if we're
// hostile (even if we're heading somewhere else)
// also friendlies want to keep close to the player
@@ -4762,7 +5194,7 @@ bool mon_can_move_to_pos(const monsters *monster, const int okmove,
{
if (targ_x == monster->x && targ_y == monster->y)
return true;
-
+
return false; // blocks square
}
@@ -4776,12 +5208,11 @@ bool mon_can_move_to_pos(const monsters *monster, const int okmove,
return false;
}
}
-
+
// wandering through a trap is OK if we're pretty healthy,
// really stupid, or immune to the trap
const int which_trap = trap_at_xy(targ_x,targ_y);
- if (which_trap >= 0
- && !is_trap_safe(monster, targ_x, targ_y, okmove, just_check))
+ if (which_trap >= 0 && !is_trap_safe(monster, targ_x, targ_y, just_check))
{
return false;
}
@@ -4840,7 +5271,7 @@ bool mon_can_move_to_pos(const monsters *monster, const int okmove,
if (monster->hit_points >= random2avg(19, 2))
return true;
break;
-
+
default:
return true; // harmless clouds
}
@@ -4850,16 +5281,16 @@ bool mon_can_move_to_pos(const monsters *monster, const int okmove,
if (mons_intel(monster->type) != I_PLANT)
return false;
}
-
+
// if we end up here the monster can safely move
return true;
}
-static void monster_move(monsters *monster)
+static bool monster_move(monsters *monster)
{
FixedArray < bool, 3, 3 > good_move;
int count_x, count_y, count;
- int okmove = DNGN_SHALLOW_WATER;
+ int okmove = DNGN_SHALLOW_WATER; // what does this actually do?
const int habitat = monster_habitat( monster->type );
bool deep_water_available = false;
@@ -4897,27 +5328,15 @@ static void monster_move(monsters *monster)
&& (habitat == DNGN_FLOOR
|| monster_habitable_grid(monster, grd(newpos))))
{
- do_move_monster(monster, mmov_x, mmov_y);
+ return do_move_monster(monster, mmov_x, mmov_y);
}
}
- return;
+ return 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;
-
- // effectively slows down monster movement across water.
- // Fire elementals can't cross at all.
- bool no_water = false;
- if (monster->type == MONS_FIRE_ELEMENTAL || one_chance_in(5))
- //okmove = DNGN_WATER_STUCK;
- no_water = true;
+ return false;
if (mons_flies(monster) > 0
|| habitat != DNGN_FLOOR
@@ -4930,28 +5349,26 @@ static void monster_move(monsters *monster)
{
for (count_y = 0; count_y < 3; count_y++)
{
- const int targ_x = monster->x + count_x - 1;
- const int targ_y = monster->y + count_y - 1;
-
- // [ds] Bounds check was after grd[targ_x][targ_y] which would
- // trigger an ASSERT. Moved it up.
+ const int targ_x = monster->x + count_x - 1;
+ const int targ_y = monster->y + count_y - 1;
- // 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;
- }
-
- int target_grid = grd[targ_x][targ_y];
+ // [ds] Bounds check was after grd[targ_x][targ_y] which would
+ // trigger an ASSERT. Moved it up.
- if (target_grid == DNGN_DEEP_WATER)
- deep_water_available = true;
+ // 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;
+ }
+ dungeon_feature_type target_grid = grd[targ_x][targ_y];
- const monsters* mons = dynamic_cast<const monsters*>(monster);
- good_move[count_x][count_y] =
- mon_can_move_to_pos(mons, okmove, count_x-1, count_y-1);
+ if (target_grid == DNGN_DEEP_WATER)
+ deep_water_available = true;
+ const monsters* mons = dynamic_cast<const monsters*>(monster);
+ good_move[count_x][count_y] =
+ mon_can_move_to_pos(mons, count_x-1, count_y-1);
}
} // now we know where we _can_ move.
@@ -4974,14 +5391,14 @@ static void monster_move(monsters *monster)
// for zombies, monster type is kept in mon->number
if (mons_itemuse(monster->number) >= MONUSE_OPEN_DOORS)
{
- mons_open_door(newpos);
- return;
+ mons_open_door(monster, newpos);
+ return true;
}
}
else if (mons_itemuse(monster->type) >= MONUSE_OPEN_DOORS)
{
- mons_open_door(newpos);
- return;
+ mons_open_door(monster, newpos);
+ return true;
}
} // endif - secret/closed doors
@@ -4993,6 +5410,17 @@ static void monster_move(monsters *monster)
grd[monster->x + mmov_x][monster->y + mmov_y] = DNGN_FLOOR;
jelly_grows(monster);
+
+ if (see_grid(monster->x + mmov_x, monster->y + mmov_y))
+ {
+ viewwindow(true, false);
+
+ if (!you.can_see(monster))
+ {
+ mpr("The door mysteriously vanishes.");
+ interrupt_activity( AI_FORCE_INTERRUPT );
+ }
+ }
} // done door-eating jellies
@@ -5138,7 +5566,9 @@ forget_it:
// take care of beetle burrowing
if (monster->type == MONS_BORING_BEETLE)
{
- if (grd[monster->x + mmov_x][monster->y + mmov_y] == DNGN_ROCK_WALL
+ dungeon_feature_type feat =
+ grd[monster->x + mmov_x][monster->y + mmov_y];
+ if ((feat == DNGN_ROCK_WALL || feat == DNGN_ROCK_WALL)
&& good_move[mmov_x + 1][mmov_y + 1] == true)
{
grd[monster->x + mmov_x][monster->y + mmov_y] = DNGN_FLOOR;
@@ -5149,13 +5579,14 @@ forget_it:
}
}
+ bool ret = false;
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) );
+ ret = monster_attack( monster_index(monster) );
mmov_x = 0;
mmov_y = 0;
}
@@ -5173,18 +5604,19 @@ forget_it:
#ifdef DEBUG_DIAGNOSTICS
mprf(MSGCH_DIAGNOSTICS,
"BUG: %s was marked as follower when not following!",
- monster->name(DESC_PLAIN).c_str());
+ monster->name(DESC_PLAIN).c_str(), true);
#endif
}
else
{
+ ret = true;
mmov_x = 0;
mmov_y = 0;
#if DEBUG_DIAGNOSTICS
mprf(MSGCH_DIAGNOSTICS,
"%s is skipping movement in order to follow.",
- monster->name(DESC_CAP_THE).c_str() );
+ monster->name(DESC_CAP_THE).c_str(), true );
#endif
}
}
@@ -5194,9 +5626,12 @@ forget_it:
if (targmon != NON_MONSTER)
{
if (mons_aligned(monster_index(monster), targmon))
- monster_swaps_places(monster, mmov_x, mmov_y);
+ ret = monster_swaps_places(monster, mmov_x, mmov_y);
else
+ {
monsters_fight(monster_index(monster), targmon);
+ ret = true;
+ }
// If the monster swapped places, the work's already done.
mmov_x = 0;
@@ -5228,7 +5663,9 @@ forget_it:
}
if (mmov_x || mmov_y || (monster->confused() && one_chance_in(6)))
- do_move_monster(monster, mmov_x, mmov_y);
+ return do_move_monster(monster, mmov_x, mmov_y);
+
+ return ret;
} // end monster_move()
static void setup_plant_spit(monsters *monster, bolt &pbolt)
@@ -5349,7 +5786,6 @@ static void mons_in_cloud(monsters *monster)
hurted -= random2(1 + monster->ac);
break; // to damage routine at end {dlb}
- // what of armour of poison resistance here? {dlb}
case CLOUD_POISON:
simple_monster_message(monster, " is engulfed in a cloud of poison!");
@@ -5444,6 +5880,8 @@ dungeon_feature_type monster_habitat(int which_class)
{
switch (which_class)
{
+ case MONS_MERFOLK:
+ case MONS_MERMAID:
case MONS_BIG_FISH:
case MONS_GIANT_GOLDFISH:
case MONS_ELECTRICAL_EEL:
@@ -5459,6 +5897,9 @@ dungeon_feature_type monster_habitat(int which_class)
case MONS_SALAMANDER:
return (DNGN_LAVA);
+ case MONS_ROCK_WORM:
+ return (DNGN_ROCK_WALL);
+
default:
return (DNGN_FLOOR); // closest match to terra firma {dlb}
}
@@ -5530,6 +5971,17 @@ bool monster_descriptor(int which_class, unsigned char which_descriptor)
bool message_current_target()
{
+
+ if (crawl_state.is_replaying_keys())
+ {
+ if (you.prev_targ == MHITNOT || you.prev_targ == MHITYOU)
+ return false;
+
+ const monsters *montarget = &menv[you.prev_targ];
+ return (you.prev_targ != MHITNOT && you.prev_targ != MHITYOU
+ && mons_near(montarget) && player_monster_visible(montarget));
+ }
+
if (you.prev_targ != MHITNOT && you.prev_targ != MHITYOU)
{
const monsters *montarget = &menv[you.prev_targ];
diff --git a/crawl-ref/source/mstuff2.cc b/crawl-ref/source/mstuff2.cc
index 48ed1c91be..a47b520a8d 100644
--- a/crawl-ref/source/mstuff2.cc
+++ b/crawl-ref/source/mstuff2.cc
@@ -146,13 +146,33 @@ void mons_trap(struct monsters *monster)
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.");
+ // alarm traps aren't set off by hostile monsters, because that would
+ // be way too nasty for the player.
+ case TRAP_ALARM:
+ if (!mons_friendly(monster) || silenced(monster->x, monster->y))
+ {
+ if (trapKnown && you.can_see(monster)
+ && !silenced(you.x_pos, you.y_pos))
+ {
+ mpr("The alarm trap makes no noise.");
+ }
+ return;
+ }
+
+ noisy(12, monster->x, monster->y);
+
+ if (!silenced(you.x_pos, you.y_pos))
+ {
+ if (monsterNearby)
+ {
+ mpr("You hear a blaring wail!", MSGCH_SOUND);
+ if (you.can_see(monster))
+ revealTrap = true;
+ }
+ else
+ mpr("You hear a distant blaring wail!", MSGCH_SOUND);
+ }
+
break;
// blade traps sometimes fail to trigger altogether,
// resulting in an "early return" from this f(x) for
@@ -305,6 +325,31 @@ void mons_trap(struct monsters *monster)
damage_taken = 0; // just to be certain {dlb}
break;
+ case TRAP_SHAFT:
+ // Paranoia
+ if (!is_valid_shaft_level())
+ {
+ if (trapKnown && monsterNearby)
+ mpr("The shaft disappears in a puff of logic!");
+
+ grd[env.trap[which_trap].x][env.trap[which_trap].y] = DNGN_FLOOR;
+ env.trap[which_trap].type = TRAP_UNASSIGNED;
+ return;
+ }
+
+ if (!monster->will_trigger_shaft()
+ || trapKnown && intelligent_ally(monster))
+ {
+ if (trapKnown && !monster->airborne())
+ simple_monster_message(monster,
+ " doesn't fall through the shaft.");
+ return;
+ }
+
+ if (monster->do_shaft())
+ revealTrap = true;
+ break;
+
default:
break;
}
@@ -365,7 +410,8 @@ void mons_trap(struct monsters *monster)
// reveal undiscovered traps, where appropriate: {dlb}
if (monsterNearby && !trapKnown && revealTrap)
{
- grd[monster->x][monster->y] = trap_category(env.trap[which_trap].type);
+ grd[env.trap[which_trap].x][env.trap[which_trap].y]
+ = trap_category(env.trap[which_trap].type);
}
// apply damage and handle death, where appropriate: {dlb}
@@ -1059,6 +1105,10 @@ bool mons_throw(struct monsters *monster, struct bolt &pbolt, int hand_used)
const bool skilled = mons_class_flag(monster->type, M_FIGHTER);
+ const monsterentry *entry = get_monster_data(monster->type);
+ const int throw_energy = entry->energy_usage.missile;
+ monster->speed_increment -= throw_energy;
+
item_def item = mitm[hand_used]; // copy changed for venom launchers
item.quantity = 1;
@@ -1255,11 +1305,24 @@ bool mons_throw(struct monsters *monster, struct bolt &pbolt, int hand_used)
pbolt.type = SYM_ZAP;
}
- // Note: we already have 10 energy taken off. -- bwr
+ // Note: we already have throw_energy taken off. -- bwr
+ int speed_delta = 0;
if (lnchType == WPN_CROSSBOW)
- monster->speed_increment += ((bow_brand == SPWPN_SPEED) ? 4 : -2);
+ {
+ if (bow_brand == SPWPN_SPEED)
+ // Speed crossbows take 50% less time to use than
+ // ordinary crossbows.
+ speed_delta = div_rand_round(throw_energy * 2, 5);
+ else
+ // Ordinary crossbows take 20% more time to use
+ // than ordinary bows.
+ speed_delta = -div_rand_round(throw_energy, 5);
+ }
else if (bow_brand == SPWPN_SPEED)
- monster->speed_increment += 5;
+ // Speed bows take 50% time to use than ordinary bows.
+ speed_delta = div_rand_round(throw_energy, 2);
+
+ monster->speed_increment += speed_delta;
}
// monster intelligence bonus
@@ -1549,6 +1612,16 @@ bolt mons_spells( int spell_cast, int power )
beam.is_beam = true;
break;
+ case SPELL_SLEEP:
+ beam.name = "0";
+ beam.range = 5;
+ beam.rangeMax = 9;
+ beam.type = 0;
+ beam.flavour = BEAM_SLEEP;
+ beam.thrower = KILL_MON_MISSILE;
+ beam.is_beam = true;
+ break;
+
case SPELL_POLYMORPH_OTHER:
beam.name = "0";
beam.range = 6;
diff --git a/crawl-ref/source/mtransit.cc b/crawl-ref/source/mtransit.cc
index 483e6327f1..8361f015bd 100644
--- a/crawl-ref/source/mtransit.cc
+++ b/crawl-ref/source/mtransit.cc
@@ -3,7 +3,7 @@
* Summary: Tracks monsters that are in suspended animation between levels.
* Written by: Darshan Shaligram
*
- * Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-03-15T20:10:20.648083Z $
+ * Modified for Crawl Reference by $Author$ on $Date$
*/
#include "AppHdr.h"
diff --git a/crawl-ref/source/mtransit.h b/crawl-ref/source/mtransit.h
index d02e3a78ff..aebea8806d 100644
--- a/crawl-ref/source/mtransit.h
+++ b/crawl-ref/source/mtransit.h
@@ -3,7 +3,7 @@
* Summary: Tracking monsters in transit between levels.
* Written by: Darshan Shaligram
*
- * Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-03-15T20:10:20.648083Z $
+ * Modified for Crawl Reference by $Author$ on $Date$
*/
#ifndef MTRANSIT_H
diff --git a/crawl-ref/source/mutation.cc b/crawl-ref/source/mutation.cc
index bfff211012..2370879118 100644
--- a/crawl-ref/source/mutation.cc
+++ b/crawl-ref/source/mutation.cc
@@ -46,6 +46,7 @@
#include "stuff.h"
#include "transfor.h"
#include "view.h"
+#include "xom.h"
int how_mutated(void);
@@ -116,6 +117,7 @@ const char *mutation_descrip[][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
@@ -182,7 +184,6 @@ const char *mutation_descrip[][3] = {
"You can sense a large area of your surroundings."},
// 30
-
{"You can breathe flames.", "You can breathe fire.",
"You can breathe blasts of fire."},
@@ -202,9 +203,9 @@ const char *mutation_descrip[][3] = {
"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 occasionally shout uncontrollably.",
+ "You sometimes yell uncontrollably.",
+ "You frequently scream uncontrollably."},
{"You possess an exceptional clarity of mind.",
"You possess an unnatural clarity of mind.",
@@ -219,13 +220,14 @@ const char *mutation_descrip[][3] = {
{"Your vision is a little blurry.", "Your vision is quite blurry.",
"Your vision is extremely blurry."},
-// 40
+// 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 frail (-10 percent hp).",
+ "You are very frail (-20 percent hp).",
"You are extremely frail (-30 percent hp)."},
{"You are robust (+10 percent hp).",
@@ -266,18 +268,22 @@ const char *mutation_descrip[][3] = {
{"You have sharp fingernails.", "You have very sharp fingernails.",
"You have claws for hands."},
- {"You have hooves in place of feet.", "", ""},
- // 60 - leave some space for more demonic powers...
-
{"You have very sharp teeth.", "You have extremely sharp teeth.",
"You have razor-sharp teeth."},
-
+
+ // 60 - leave some space for more demonic powers...
+
+ {"You have hooves in place of feet.", "", ""},
+ {"You have talons in place of feet.", "", ""},
+ {"You have soft paws in place of feet.", "", ""},
+
{"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
+ // 65
{"Your wings are large and strong.", "", ""}, //jmf: dracos only
//jmf: these next two are for evil gods to mark their followers; good gods
@@ -292,13 +298,33 @@ const char *mutation_descrip[][3] = {
"There are several green sigils on your chest and abdomen.",
"Your chest, abdomen and neck are covered in intricate, arcane green writing."},
- {"", "", ""},
- {"", "", ""},
- {"", "", ""},
- {"", "", ""},
+ {"You occasionally drift when moving.",
+ "You sometimes drift when moving.",
+ "You frequently drift when moving."},
+
+ {"You can tolerate rotten meat.", "You can eat rotten meat.",
+ "You thrive on rotten meat."},
// 70
+ {"You are covered in fur.",
+ "You are covered in thick fur.",
+ "Your thick and shaggy fur keeps you warm."},
+
+ {"You have an increased reservoir of magic (+10 percent mp).",
+ "You have a strongly increased reservoir of magic (+20 percent mp).",
+ "You have an extremely increased reservoir of magic (+30 percent mp)."},
+
+ {"Your magical capacity is low (-10 percent mp).",
+ "Your magical capacity is very low (-20 percent mp).",
+ "Your magical capacity is extremely low (-30 percent mp)."},
+ {"You occasionally fall asleep.",
+ "You sometimes fall asleep.",
+ "You frequently fall asleep."},
+
+ {"", "", ""},
+
+ // 75
{"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)."},
@@ -339,8 +365,7 @@ const char *mutation_descrip[][3] = {
"You are mostly covered in purple scales (AC + 4).",
"You are completely covered in purple scales (AC + 6)."},
-// 80
-
+ // 85
{"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)."},
@@ -363,7 +388,7 @@ const char *mutation_descrip[][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)."},
+ "You are completely covered in patterned scales (AC + 3)."}
};
/*
@@ -399,6 +424,7 @@ const char *gain_mutation[][3] = {
"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."},
@@ -427,6 +453,7 @@ const char *gain_mutation[][3] = {
{"You feel less intelligent.", "You feel less intelligent.",
"You feel less intelligent."},
+
// 20
{"You feel clumsy.", "You feel clumsy.",
"You feel clumsy."},
@@ -458,8 +485,8 @@ const char *gain_mutation[][3] = {
{"You feel aware of your surroundings.",
"You feel more aware of your surroundings.",
"You feel even more aware of your surroundings."},
-// 30
+// 30
{"Your throat feels hot.", "Your throat feels hot.",
"Your throat feels hot."},
@@ -476,8 +503,8 @@ const char *gain_mutation[][3] = {
{"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?"},
+ {"You feel the urge to shout.", "You feel a strong urge to yell.",
+ "You feel a strong urge to scream."},
{"Your thoughts seem clearer.", "Your thoughts seem clearer.",
"Your thoughts seem clearer."},
@@ -489,8 +516,8 @@ const char *gain_mutation[][3] = {
"You feel your body start to fall apart."},
{"Your vision blurs.", "Your vision blurs.", "Your vision blurs."},
-// 40
+// 40
{"You feel genetically stable.", "You feel genetically stable.",
"You feel genetically immutable."},
@@ -516,13 +543,15 @@ const char *gain_mutation[][3] = {
{"Your fingernails lengthen.", "Your fingernails sharpen.",
"Your hands twist into claws."},
- {"Your feet shrivel into cloven hooves.", "", ""},
- // 60
-
{"Your teeth lengthen and sharpen.",
"Your teeth lengthen and sharpen some more.",
"Your teeth are very long and razor-sharp."},
+ // 60
+ {"Your feet shrivel into cloven hooves.", "", ""},
+ {"Your feet stretch and sharpen into talons.", "", ""},
+ {"Your feet sprout fur and twist into soft paws.", "", ""},
+
{"You taste something nasty.", "You taste something very nasty.",
"You taste something extremely nasty."},
@@ -530,6 +559,7 @@ const char *gain_mutation[][3] = {
"The barb on your tail looks sharper.",
"The barb on your tail looks very sharp."},
+ // 65
{"Your wings grow larger and stronger.", "", ""},
{"Your hands itch.", "Your hands and forearms itch.",
@@ -539,13 +569,29 @@ const char *gain_mutation[][3] = {
{"Your chest itches.", "Your chest and abdomen itch.",
"Your chest, abdomen and neck itch."},
- {"", "", ""},
- {"", "", ""},
- {"", "", ""},
- {"", "", ""},
+ {"Your movements feel uncertain.",
+ "Your movements feel even more uncertain.",
+ "Your movements feel even more uncertain."},
+ // saprovorous: can never be gained or lost, only started with
+ {"", "", ""},
+
// 70
+ {"Fur sprouts all over your body.",
+ "Your fur grows into a thick mane.",
+ "Your thick fur grows shaggy and warm."},
+ {"You feel more energetic.", "You feel more energetic.",
+ "You feel more energetic."},
+
+ {"You feel less energetic.", "You feel less energetic.",
+ "You feel less energetic."},
+
+ {"You feel a bit tired.", "You feel drowsy.", "You feel really drowsy."},
+
+ {"", "", ""},
+
+ // 75
{"Red scales grow over part of your body.",
"Red scales spread over more of your body.",
"Red scales cover you completely."},
@@ -576,8 +622,8 @@ const char *gain_mutation[][3] = {
{"Purple scales grow over part of your body.",
"Purple scales spread over more of your body.",
"Purple scales cover you completely."},
- // 80
+ // 85
{"Speckled scales grow over part of your body.",
"Speckled scales spread over more of your body.",
"Speckled scales cover you completely."},
@@ -595,7 +641,7 @@ const char *gain_mutation[][3] = {
"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."},
+ "Patterned scales cover you completely."}
};
const char *lose_mutation[][3] = {
@@ -680,8 +726,8 @@ const char *lose_mutation[][3] = {
{"You feel slightly disorientated.", "You feel slightly disorientated.",
"You feel slightly disorientated."},
-// 30
+// 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."},
@@ -699,8 +745,8 @@ const char *lose_mutation[][3] = {
{"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 urge to shout disappears.", "Your urge to yell lessens.",
+ "Your urge to scream lessens."},
{"Your thinking seems confused.", "Your thinking seems confused.",
"Your thinking seems confused."},
@@ -713,8 +759,8 @@ const char *lose_mutation[][3] = {
{"Your vision sharpens.", "Your vision sharpens a little.",
"Your vision sharpens a little."},
-// 40
+// 40
{"You feel genetically unstable.", "You feel genetically unstable.",
"You feel genetically unstable."},
@@ -742,25 +788,49 @@ const char *lose_mutation[][3] = {
{"Your fingernails shrink to normal size.",
"Your fingernails look duller.", "Your hands feel fleshier."},
- {"Your hooves expand and flesh out into feet!", "", ""},
- // 60
{"Your teeth shrink to normal size.",
"Your teeth shrink and become duller.",
"Your teeth shrink and become duller."},
-
+
+ // 60
+ {"Your hooves expand and flesh out into feet!", "", ""},
+ {"Your talons dull and shrink into feet.", "", ""},
+ {"Your paws shed and extend into feet.", "", ""},
+
{"", "", ""},
{"", "", ""},
+
+ // 65
{"", "", ""},
{"", "", ""},
// 65
{"", "", ""},
- {"", "", ""},
- {"", "", ""},
- {"", "", ""},
+
+ {"Your movements feel completely certain again.",
+ "Your movements feel more certain.",
+ "Your movements feel more certain."},
+
+ // saprovorous: can never be gained or lost, only started with
{"", "", ""},
// 70
+ {"You shed all your fur.",
+ "Your thick fur recedes somewhat.",
+ "Your shaggy fur recedes somewhat."},
+
+ {"You feel less energetic.", "You feel less energetic.",
+ "You feel less energetic."},
+
+ {"You feel more energetic.", "You feel more energetic.",
+ "You feel more energetic."},
+
+ {"You feel wide awake.", "You feel more awake.", "You feel more awake."},
+
+ {"", "", ""},
+
+ // 75
+ // 70
{"Your red scales disappear.", "Your red scales recede somewhat.",
"Your red scales recede somewhat."},
@@ -794,7 +864,7 @@ const char *lose_mutation[][3] = {
{"Your purple scales disappear.", "Your purple scales recede somewhat.",
"Your purple scales recede somewhat."},
- // 80
+ // 85
{"Your speckled scales disappear.",
"Your speckled scales recede somewhat.",
"Your speckled scales recede somewhat."},
@@ -815,9 +885,12 @@ const char *lose_mutation[][3] = {
{"Your patterned scales disappear.",
"Your patterned scales recede somewhat.",
- "Your patterned scales recede somewhat."},
+ "Your patterned scales recede somewhat."}
};
+/* mutation definitions:
+ first number = probability (0 means it doesn't appear naturally?)
+ second number = maximum levels */
static mutation_def mutation_defs[] = {
{ MUT_TOUGH_SKIN, 10, 3, false },
{ MUT_STRONG, 8, 14, false },
@@ -857,7 +930,7 @@ static mutation_def mutation_defs[] = {
{ MUT_HORNS, 7, 3, false },
{ MUT_STRONG_STIFF, 10, 3, false },
{ MUT_FLEXIBLE_WEAK, 10, 3, false },
- { MUT_LOST, 6, 3, true },
+ { MUT_SCREAM, 6, 3, true },
{ MUT_CLARITY, 6, 1, false },
{ MUT_BERSERK, 7, 3, true },
{ MUT_DETERIORATION, 10, 3, true },
@@ -866,6 +939,7 @@ static mutation_def mutation_defs[] = {
{ MUT_MUTATION_RESISTANCE, 4, 3, false },
{ MUT_FRAIL, 10, 3, true },
{ MUT_ROBUST, 5, 3, false },
+
/* Some demonic powers start here: */
{ MUT_TORMENT_RESISTANCE, 0, 1, false },
{ MUT_NEGATIVE_ENERGY_RESISTANCE, 0, 3, false },
@@ -883,22 +957,33 @@ static mutation_def mutation_defs[] = {
{ MUT_THROW_FLAMES, 0, 1, false },
{ MUT_THROW_FROST, 0, 1, false },
{ MUT_SMITE, 0, 1, false },
+/* end of demonic powers */
+
{ MUT_CLAWS, 2, 3, false },
- { MUT_HOOVES, 1, 1, false },
-// 60
{ MUT_FANGS, 1, 3, false },
- { MUT_BREATHE_POISON, 0, 1, false },
- { MUT_STINGER, 0, 3, false },
- { MUT_BIG_WINGS, 0, 1, false },
- { MUT_BLUE_MARKS, 0, 3, false },
+// 60
+ { MUT_HOOVES, 1, 1, false },
+ { MUT_TALONS, 1, 1, false },
+ { MUT_PAWS, 1, 1, false },
+
+ { MUT_BREATHE_POISON, 0, 1, false }, // Naga only
+ { MUT_STINGER, 0, 3, false }, // Naga and Draconian only
+// 65
+ { MUT_BIG_WINGS, 0, 1, false }, // Draconian only
+ { MUT_BLUE_MARKS, 0, 3, false }, // used by evil gods to mark followers
{ MUT_GREEN_MARKS, 0, 3, false },
- // Four placeholders:
- { RANDOM_MUTATION, 0, 3, false },
- { RANDOM_MUTATION, 0, 3, false },
- { RANDOM_MUTATION, 0, 3, false },
- { RANDOM_MUTATION, 0, 3, false },
+ { MUT_DRIFTING, 2, 3, true },
+ { MUT_SAPROVOROUS, 0, 3, false }, // species-dependent innate mutation
+
// 70
+ { MUT_SHAGGY_FUR, 2, 3, false },
+ { MUT_HIGH_MAGIC, 1, 3, false },
+ { MUT_LOW_MAGIC, 9, 3, true },
+ { MUT_SLEEPINESS, 3, 3, true },
+ { RANDOM_MUTATION, 0, 3, false },
+
+// 75 -- scales of various colours and effects
{ MUT_RED_SCALES, 2, 3, false },
{ MUT_NACREOUS_SCALES, 1, 3, false },
{ MUT_GREY2_SCALES, 2, 3, false },
@@ -909,13 +994,13 @@ static mutation_def mutation_defs[] = {
{ MUT_BROWN_SCALES, 2, 3, false },
{ MUT_BLUE_SCALES, 2, 3, false },
{ MUT_PURPLE_SCALES, 2, 3, false },
-// 80
+// 85
{ MUT_SPECKLED_SCALES, 2, 3, false },
{ MUT_ORANGE_SCALES, 2, 3, false },
{ MUT_INDIGO_SCALES, 2, 3, false },
{ MUT_RED2_SCALES, 1, 3, false },
{ MUT_IRIDESCENT_SCALES, 1, 3, false },
- { MUT_PATTERNED_SCALES, 1, 3, false },
+ { MUT_PATTERNED_SCALES, 1, 3, false }
};
#ifdef DEBUG_DIAGNOSTICS
@@ -995,7 +1080,6 @@ formatted_string describe_mutations()
if ( you.mutation[MUT_CLAWS] )
result += "</cyan><lightblue>";
result += EOL;
- result += "You can eat rotten meat." EOL;
have_any = true;
break;
@@ -1014,7 +1098,6 @@ formatted_string describe_mutations()
result += "Your body is rotting away." EOL;
result += troll_claw_descrip[you.mutation[MUT_CLAWS]];
result += EOL;
- result += "You preferably eat rotten meat." EOL;
result += "You heal slowly." EOL;
have_any = true;
break;
@@ -1036,7 +1119,7 @@ formatted_string describe_mutations()
break;
case SP_KENKU:
- result += "You cannot wear boots or helmets." EOL;
+ result += "You cannot wear helmets." EOL;
if (you.experience_level > 4)
{
result += "You can fly";
@@ -1136,17 +1219,10 @@ formatted_string describe_mutations()
break;
case SP_KOBOLD:
- result += "You can eat rotten meat." EOL;
result += "You recuperate from illness quickly." EOL;
have_any = true;
break;
- case SP_HILL_ORC:
- case SP_OGRE:
- result += "You can tolerate rotten meat." EOL;
- have_any = true;
- break;
-
case SP_VAMPIRE:
if (you.hunger_state >= HS_SATIATED)
{
@@ -1305,19 +1381,23 @@ static int calc_mutation_amusement_value(mutation_type which_mutation)
case MUT_BREATHE_FLAMES:
case MUT_BLINK:
case MUT_HORNS:
- case MUT_LOST:
+ case MUT_SCREAM:
case MUT_BERSERK:
case MUT_DETERIORATION:
case MUT_BLURRY_VISION:
case MUT_FRAIL:
+ case MUT_LOW_MAGIC:
case MUT_CLAWS:
- case MUT_HOOVES:
case MUT_FANGS:
+ case MUT_HOOVES:
+ case MUT_TALONS:
+ case MUT_PAWS:
case MUT_BREATHE_POISON:
case MUT_STINGER:
case MUT_BIG_WINGS:
case MUT_BLUE_MARKS:
case MUT_GREEN_MARKS:
+ case MUT_DRIFTING:
amusement *= 2; // funny!
break;
@@ -1358,7 +1438,7 @@ static mutation_type get_random_xom_mutation()
case 1: mutat = MUT_DOPEY; break;
case 2: mutat = MUT_CLUMSY; break;
case 3: mutat = MUT_DEFORMED; break;
- case 4: mutat = MUT_LOST; break;
+ case 4: mutat = MUT_SCREAM; break;
case 5: mutat = MUT_DETERIORATION; break;
case 6: mutat = MUT_BLURRY_VISION; break;
case 7: mutat = MUT_FRAIL; break;
@@ -1415,7 +1495,7 @@ bool mutate(mutation_type which_mutation, bool failMsg, bool force_mutation,
mpr( "Your body decomposes!", MSGCH_MUTATION );
if (coinflip())
- lose_stat( STAT_RANDOM, 1 );
+ lose_stat( STAT_RANDOM, 1 , false, "mutating");
else
{
ouch( 3, 0, KILLED_BY_ROTTING );
@@ -1490,6 +1570,10 @@ bool mutate(mutation_type which_mutation, bool failMsg, bool force_mutation,
return false;
}
+ // Saprovorous can't be randomly acquired
+ if (mutat == MUT_SAPROVOROUS)
+ return false;
+
if (you.mutation[mutat] > 13 && !force_mutation)
return false;
@@ -1550,17 +1634,14 @@ bool mutate(mutation_type which_mutation, bool failMsg, bool force_mutation,
}
// putting boots on after they are forced off. -- bwr
- if (mutat == MUT_HOOVES
- && (you.species == SP_NAGA || you.mutation[MUT_HOOVES]
- || you.species == SP_KENKU || player_genus(GENPC_DRACONIAN)))
+ if ((mutat == MUT_HOOVES || mutat == MUT_TALONS || mutat == MUT_PAWS)
+ && !player_has_feet())
{
return false;
}
if (mutat == MUT_FANGS && you.species == SP_KENKU)
- {
return false;
- }
if (mutat == MUT_BREATHE_POISON && you.species != SP_NAGA)
return false;
@@ -1568,6 +1649,9 @@ bool mutate(mutation_type which_mutation, bool failMsg, bool force_mutation,
if (mutat == MUT_BIG_WINGS && !player_genus(GENPC_DRACONIAN))
return false;
+ if (you.mutation[mutat] >= mutation_defs[mutat].levels)
+ return false;
+
// find where these things are actually changed
// -- do not globally force redraw {dlb}
you.redraw_hit_points = 1;
@@ -1587,7 +1671,7 @@ bool mutate(mutation_type which_mutation, bool failMsg, bool force_mutation,
return true;
}
// replaces earlier, redundant code - 12mar2000 {dlb}
- modify_stat(STAT_STRENGTH, 1, false);
+ modify_stat(STAT_STRENGTH, 1, false, "gaining a mutation");
break;
case MUT_CLEVER:
@@ -1597,7 +1681,7 @@ bool mutate(mutation_type which_mutation, bool failMsg, bool force_mutation,
return true;
}
// replaces earlier, redundant code - 12mar2000 {dlb}
- modify_stat(STAT_INTELLIGENCE, 1, false);
+ modify_stat(STAT_INTELLIGENCE, 1, false, "gaining a mutation");
break;
case MUT_AGILE:
@@ -1607,7 +1691,7 @@ bool mutate(mutation_type which_mutation, bool failMsg, bool force_mutation,
return true;
}
// replaces earlier, redundant code - 12mar2000 {dlb}
- modify_stat(STAT_DEXTERITY, 1, false);
+ modify_stat(STAT_DEXTERITY, 1, false, "gaining a mutation");
break;
case MUT_WEAK:
@@ -1616,7 +1700,7 @@ bool mutate(mutation_type which_mutation, bool failMsg, bool force_mutation,
delete_mutation(MUT_STRONG);
return true;
}
- modify_stat(STAT_STRENGTH, -1, true);
+ modify_stat(STAT_STRENGTH, -1, true, "gaining a mutation");
mpr(gain_mutation[mutat][0], MSGCH_MUTATION);
break;
@@ -1626,7 +1710,7 @@ bool mutate(mutation_type which_mutation, bool failMsg, bool force_mutation,
delete_mutation(MUT_CLEVER);
return true;
}
- modify_stat(STAT_INTELLIGENCE, -1, true);
+ modify_stat(STAT_INTELLIGENCE, -1, true, "gaining a mutation");
mpr(gain_mutation[mutat][0], MSGCH_MUTATION);
break;
@@ -1636,7 +1720,7 @@ bool mutate(mutation_type which_mutation, bool failMsg, bool force_mutation,
delete_mutation(MUT_AGILE);
return true;
}
- modify_stat(STAT_DEXTERITY, -1, true);
+ modify_stat(STAT_DEXTERITY, -1, true, "gaining a mutation");
mpr(gain_mutation[mutat][0], MSGCH_MUTATION);
break;
@@ -1680,10 +1764,6 @@ bool mutate(mutation_type which_mutation, bool failMsg, bool force_mutation,
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)
{
@@ -1703,19 +1783,14 @@ bool mutate(mutation_type which_mutation, bool failMsg, bool force_mutation,
mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION);
break;
- case MUT_TELEPORT_CONTROL:
- mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION);
- break;
-
- case MUT_HOOVES: //jmf: like horns
+ //jmf: like horns
+ case MUT_HOOVES:
+ case MUT_TALONS:
+ case MUT_PAWS:
mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION);
remove_one_equip(EQ_BOOTS);
break;
- case MUT_FANGS:
- mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION);
- break;
-
case MUT_CLAWS:
mpr((you.species == SP_TROLL ? troll_claw_gain
: gain_mutation[mutat])[you.mutation[mutat]],
@@ -1743,15 +1818,15 @@ bool mutate(mutation_type which_mutation, bool failMsg, bool force_mutation,
remove_one_equip(EQ_HELMET);
}
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);
+ modify_stat(STAT_STRENGTH, 1, true, "gaining a mutation");
+ modify_stat(STAT_DEXTERITY, -1, true, "gaining a mutation");
mpr(gain_mutation[mutat][0], MSGCH_MUTATION);
break;
@@ -1761,8 +1836,8 @@ bool mutate(mutation_type which_mutation, bool failMsg, bool force_mutation,
delete_mutation(MUT_STRONG_STIFF);
return true;
}
- modify_stat(STAT_STRENGTH, -1, true);
- modify_stat(STAT_DEXTERITY, 1, true);
+ modify_stat(STAT_STRENGTH, -1, true, "gaining a mutation");
+ modify_stat(STAT_DEXTERITY, 1, true, "gaining a mutation");
mpr(gain_mutation[mutat][0], MSGCH_MUTATION);
break;
@@ -1792,26 +1867,50 @@ bool mutate(mutation_type which_mutation, bool failMsg, bool force_mutation,
take_note(Note(NOTE_GET_MUTATION, mutat, you.mutation[mutat]));
return true;
+ case MUT_LOW_MAGIC:
+ if (you.mutation[MUT_HIGH_MAGIC] > 0)
+ {
+ delete_mutation(MUT_HIGH_MAGIC);
+ return true;
+ }
+ mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION);
+ you.mutation[mutat]++;
+ calc_mp();
+ /* special-case check */
+ take_note(Note(NOTE_GET_MUTATION, mutat, you.mutation[mutat]));
+ return true;
+
+ case MUT_HIGH_MAGIC:
+ if (you.mutation[MUT_LOW_MAGIC] > 0)
+ {
+ delete_mutation(MUT_LOW_MAGIC);
+ return true;
+ }
+ mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION);
+ you.mutation[mutat]++;
+ calc_mp();
+ /* special-case check */
+ take_note(Note(NOTE_GET_MUTATION, mutat, you.mutation[mutat]));
+ return true;
+
case MUT_BLACK_SCALES:
case MUT_BONEY_PLATES:
- modify_stat(STAT_DEXTERITY, -1, true);
- // deliberate fall-through
- default:
+ modify_stat(STAT_DEXTERITY, -1, true, "gaining a mutation");
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);
+ modify_stat(STAT_DEXTERITY, -1, true, "gaining a mutation");
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);
+ modify_stat(STAT_DEXTERITY, -2, true, "gaining a mutation");
else
- modify_stat(STAT_DEXTERITY, -1, true);
+ modify_stat(STAT_DEXTERITY, -1, true, "gaining a mutation");
mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION);
break;
@@ -1819,8 +1918,12 @@ bool mutate(mutation_type which_mutation, bool failMsg, bool force_mutation,
case MUT_RED2_SCALES:
case MUT_YELLOW_SCALES:
if (you.mutation[mutat] != 0)
- modify_stat(STAT_DEXTERITY, -1, true);
+ modify_stat(STAT_DEXTERITY, -1, true, "gaining a mutation");
+
+ mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION);
+ break;
+ default:
mpr(gain_mutation[mutat][you.mutation[mutat]], MSGCH_MUTATION);
break;
}
@@ -1903,62 +2006,47 @@ bool delete_mutation(mutation_type which_mutation, bool force)
switch (mutat)
{
case MUT_STRONG:
- modify_stat(STAT_STRENGTH, -1, true);
+ modify_stat(STAT_STRENGTH, -1, true, "losing a mutation");
mpr(lose_mutation[mutat][0], MSGCH_MUTATION);
break;
case MUT_CLEVER:
- modify_stat(STAT_INTELLIGENCE, -1, true);
+ modify_stat(STAT_INTELLIGENCE, -1, true, "losing a mutation");
mpr(lose_mutation[mutat][0], MSGCH_MUTATION);
break;
case MUT_AGILE:
- modify_stat(STAT_DEXTERITY, -1, true);
+ modify_stat(STAT_DEXTERITY, -1, true, "losing a mutation");
mpr(lose_mutation[mutat][0], MSGCH_MUTATION);
break;
case MUT_WEAK:
- modify_stat(STAT_STRENGTH, 1, false);
+ modify_stat(STAT_STRENGTH, 1, false, "losing a mutation");
break;
case MUT_DOPEY:
- modify_stat(STAT_INTELLIGENCE, 1, false);
+ modify_stat(STAT_INTELLIGENCE, 1, false, "losing a mutation");
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:
- mpr(lose_mutation[mutat][you.mutation[mutat] - 1], MSGCH_MUTATION);
+ modify_stat(STAT_DEXTERITY, 1, false, "losing a mutation");
break;
case MUT_STRONG_STIFF:
- modify_stat(STAT_STRENGTH, -1, true);
- modify_stat(STAT_DEXTERITY, 1, true);
+ modify_stat(STAT_STRENGTH, -1, true, "losing a mutation");
+ modify_stat(STAT_DEXTERITY, 1, true, "losing a mutation");
mpr(lose_mutation[mutat][0], MSGCH_MUTATION);
break;
case MUT_FLEXIBLE_WEAK:
- modify_stat(STAT_STRENGTH, 1, true);
- modify_stat(STAT_DEXTERITY, -1, true);
+ modify_stat(STAT_STRENGTH, 1, true, "losing a mutation");
+ modify_stat(STAT_DEXTERITY, -1, true, "losing a mutation");
mpr(lose_mutation[mutat][0], MSGCH_MUTATION);
break;
case MUT_FRAIL:
+ case MUT_ROBUST:
mpr(lose_mutation[mutat][0], MSGCH_MUTATION);
if (you.mutation[mutat] > 0)
you.mutation[mutat]--;
@@ -1967,18 +2055,19 @@ bool delete_mutation(mutation_type which_mutation, bool force)
take_note(Note(NOTE_LOSE_MUTATION, mutat, you.mutation[mutat]));
return true;
- case MUT_ROBUST:
+ case MUT_LOW_MAGIC:
+ case MUT_HIGH_MAGIC:
mpr(lose_mutation[mutat][0], MSGCH_MUTATION);
if (you.mutation[mutat] > 0)
you.mutation[mutat]--;
- calc_hp();
+ calc_mp();
/* special-case check */
take_note(Note(NOTE_LOSE_MUTATION, mutat, you.mutation[mutat]));
return true;
case MUT_BLACK_SCALES:
case MUT_BONEY_PLATES:
- modify_stat(STAT_DEXTERITY, 1, true);
+ modify_stat(STAT_DEXTERITY, 1, true, "losing a mutation");
mpr(lose_mutation[mutat][you.mutation[mutat] - 1], MSGCH_MUTATION);
break;
@@ -1988,21 +2077,17 @@ bool delete_mutation(mutation_type which_mutation, bool force)
MSGCH_MUTATION);
break;
- 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);
+ modify_stat(STAT_DEXTERITY, 1, true, "losing a mutation");
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);
+ modify_stat(STAT_DEXTERITY, 2, true, "losing a mutation");
else
- modify_stat(STAT_DEXTERITY, 1, true);
+ modify_stat(STAT_DEXTERITY, 1, true, "losing a mutation");
mpr(lose_mutation[mutat][you.mutation[mutat] - 1], MSGCH_MUTATION);
break;
@@ -2010,7 +2095,7 @@ bool delete_mutation(mutation_type which_mutation, bool force)
case MUT_RED2_SCALES:
case MUT_YELLOW_SCALES:
if (you.mutation[mutat] != 1)
- modify_stat(STAT_DEXTERITY, 1, true);
+ modify_stat(STAT_DEXTERITY, 1, true, "losing a mutation");
mpr(lose_mutation[mutat][you.mutation[mutat] - 1], MSGCH_MUTATION);
break;
@@ -2027,6 +2112,10 @@ bool delete_mutation(mutation_type which_mutation, bool force)
}
}
break;
+
+ default:
+ mpr(lose_mutation[mutat][you.mutation[mutat] - 1], MSGCH_MUTATION);
+ break;
}
// find where these things are actually altered
@@ -2100,12 +2189,7 @@ const char *mutation_name(mutation_type which_mutat, int 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 ]);
+ return (mutation_descrip[ which_mutat ][ level - 1 ]);
} // end mutation_name()
/* Use an attribute counter for how many demonic mutations a dspawn has */
@@ -2141,7 +2225,8 @@ void demonspawn(void)
}
// Makhlebites have the summonings invocation
- if ((you.religion != GOD_MAKHLEB || you.piety < 100) &&
+ if ((you.religion != GOD_MAKHLEB ||
+ you.piety < piety_breakpoint(3)) &&
you.skills[SK_SUMMONINGS] < 5 && one_chance_in(3))
{ // good summoners don't get summon demon
whichm = MUT_SUMMON_DEMONS;
@@ -2219,8 +2304,8 @@ void demonspawn(void)
// Yredelemnulites have the raise dead invocation
if (you.religion != GOD_YREDELEMNUL &&
- you.skills[SK_SUMMONINGS] < 3 && you.skills[SK_NECROMANCY] < 3
- && one_chance_in(10))
+ you.skills[SK_SUMMONINGS] < 3 &&
+ you.skills[SK_NECROMANCY] < 3 && one_chance_in(10))
{
whichm = MUT_RAISE_DEAD;
howm = 1;
@@ -2424,9 +2509,9 @@ void demonspawn(void)
{
/* 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);
+ modify_stat(STAT_STRENGTH, 1, true, "demonspawn mutation");
+ modify_stat(STAT_INTELLIGENCE, 1, true, "demonspawn mutation");
+ modify_stat(STAT_DEXTERITY, 1, true, "demonspawn mutation");
mpr("You feel much better now.", MSGCH_INTRINSIC_GAIN);
}
} // end demonspawn()
@@ -2466,119 +2551,10 @@ bool give_bad_mutation(bool forceMutation, bool failMsg)
(temp_rand == 6) ? MUT_CLUMSY :
(temp_rand == 5) ? MUT_TELEPORT :
(temp_rand == 4) ? MUT_DEFORMED :
- (temp_rand == 3) ? MUT_LOST :
+ (temp_rand == 3) ? MUT_SCREAM :
(temp_rand == 2) ? MUT_DETERIORATION :
(temp_rand == 1) ? MUT_BLURRY_VISION
: MUT_FRAIL);
return mutate(which_bad_one, failMsg, forceMutation);
} // end give_bad_mutation()
-
-//jmf: might be useful somewhere (eg Xom or transmigration effect)
-bool give_cosmetic_mutation()
-{
- mutation_type mutation = NUM_MUTATIONS;
- 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_NAGA && !you.mutation[MUT_HOOVES]
- && you.species != SP_KENKU && !player_genus(GENPC_DRACONIAN)
- && one_chance_in(5))
- {
- mutation = MUT_HOOVES;
- how_much = 1;
- }
-
- if (one_chance_in(5))
- {
- mutation = MUT_FANGS;
- how_much = 1 + random2(3);
- }
-
- 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/crawl-ref/source/mutation.h b/crawl-ref/source/mutation.h
index 615f8beccb..6f653e3c30 100644
--- a/crawl-ref/source/mutation.h
+++ b/crawl-ref/source/mutation.h
@@ -60,13 +60,6 @@ bool delete_mutation(mutation_type which_mutation, bool force = false);
// default of level == -1, means to use the player's current level
const char *mutation_name( mutation_type which_mutat, int level = -1 );
-
-// last updated 12may2000 {dlb}
-/* ***********************************************************************
- * called from: items - religion
- * *********************************************************************** */
-bool give_cosmetic_mutation( void );
-
// last updated 12may2000 {dlb}
/* ***********************************************************************
* called from: items - spells
diff --git a/crawl-ref/source/newgame.cc b/crawl-ref/source/newgame.cc
index 3131868cf1..c2dd8f7909 100644
--- a/crawl-ref/source/newgame.cc
+++ b/crawl-ref/source/newgame.cc
@@ -93,6 +93,7 @@
#include "skills2.h"
#include "spl-book.h"
#include "spl-util.h"
+#include "state.h"
#include "stuff.h"
#include "tutorial.h"
#include "version.h"
@@ -115,11 +116,6 @@ static void jobs_stat_init(job_type which_job);
static void openingScreen(void);
static void species_stat_init(species_type which_species);
-#ifdef USE_SPELLCASTER_AND_RANGER_WANDERER_TEMPLATES
-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 );
@@ -258,8 +254,7 @@ static bool is_species_valid_choice(species_type species, bool display = true)
: (species >= SP_UNK0_DRACONIAN
&& species <= SP_BASE_DRACONIAN))
|| species == SP_ELF
- || species == SP_HILL_DWARF
- || species == SP_VAMPIRE));
+ || species == SP_HILL_DWARF));
}
static species_type random_species()
@@ -532,11 +527,19 @@ static void racialise_starting_equipment()
case SP_GREY_ELF:
case SP_DEEP_ELF:
case SP_SLUDGE_ELF:
- set_equip_race( you.inv[i], ISFLAG_ELVEN );
+ if (you.inv[i].base_type != OBJ_WEAPONS
+ || weapon_skill(you.inv[i]) != SK_MACES_FLAILS)
+ {
+ set_equip_race( you.inv[i], ISFLAG_ELVEN );
+ }
break;
case SP_MOUNTAIN_DWARF:
- set_equip_race( you.inv[i], ISFLAG_DWARVEN );
+ if (you.inv[i].base_type != OBJ_WEAPONS
+ || weapon_skill(you.inv[i]) != SK_POLEARMS)
+ {
+ set_equip_race( you.inv[i], ISFLAG_DWARVEN );
+ }
break;
case SP_HILL_ORC:
@@ -715,6 +718,13 @@ bool new_game(void)
init_player();
+ if (!crawl_state.startup_errors.empty()
+ && !Options.suppress_startup_errors)
+ {
+ crawl_state.show_startup_errors();
+ clrscr();
+ }
+
if (!Options.player_name.empty())
{
strncpy(you.your_name, Options.player_name.c_str(), kNameLen);
@@ -867,6 +877,9 @@ game_start:
{
if (is_valid_item(you.inv[i]))
{
+ // Why is this here? Elsewhere it's only ever used for runes
+ you.inv[i].flags |= ISFLAG_BEEN_IN_INV;
+
// identify all items in pack
set_ident_type( you.inv[i].base_type,
you.inv[i].sub_type, ID_KNOWN_TYPE );
@@ -1558,7 +1571,7 @@ static bool choose_book( item_def& book, int firstbook, int numbooks )
cprintf(EOL "Which book? ");
textcolor( LIGHTGREY );
- keyin = get_ch();
+ keyin = c_getch();
if (keyin == CK_BKSP || keyin == ' ')
return false;
@@ -1594,12 +1607,11 @@ static bool choose_book( item_def& book, int firstbook, int numbooks )
}
-static const weapon_type startwep[5] = { WPN_SHORT_SWORD, WPN_MACE,
- WPN_HAND_AXE, WPN_SPEAR, WPN_TRIDENT };
-
-static bool choose_weapon( void )
+static bool choose_weapon()
{
- unsigned char keyin = 0;
+ const weapon_type startwep[5] = { WPN_SHORT_SWORD, WPN_MACE,
+ WPN_HAND_AXE, WPN_SPEAR, WPN_TRIDENT };
+ int keyin = 0;
int num_choices = 4;
if (you.char_class == JOB_GLADIATOR || you.species == SP_MERFOLK)
@@ -1654,7 +1666,7 @@ static bool choose_weapon( void )
cprintf(EOL "Which weapon? ");
textcolor( LIGHTGREY );
- keyin = get_ch();
+ keyin = c_getch();
if (keyin == CK_BKSP || keyin == ' ')
return false;
@@ -1870,8 +1882,12 @@ static void give_basic_mutations(species_type speci)
// for the fast/slow metabolism when we get around to it.
switch ( speci )
{
+ case SP_HILL_ORC:
+ you.mutation[MUT_SAPROVOROUS] = 1;
+ break;
case SP_OGRE:
you.mutation[MUT_FAST_METABOLISM] = 1;
+ you.mutation[MUT_SAPROVOROUS] = 1;
break;
case SP_OGRE_MAGE:
you.mutation[MUT_FAST_METABOLISM] = 1;
@@ -1913,13 +1929,20 @@ static void give_basic_mutations(species_type speci)
you.mutation[MUT_POISON_RESISTANCE] = 1;
you.mutation[MUT_COLD_RESISTANCE] = 1;
you.mutation[MUT_NEGATIVE_ENERGY_RESISTANCE] = 3;
+ you.mutation[MUT_SAPROVOROUS] = 3;
you.mutation[MUT_CARNIVOROUS] = 3;
break;
+ case SP_KENKU:
+ you.mutation[MUT_TALONS] = 1;
+ break;
case SP_TROLL:
you.mutation[MUT_REGENERATION] = 2;
you.mutation[MUT_FAST_METABOLISM] = 3;
+ you.mutation[MUT_SAPROVOROUS] = 2;
+ you.mutation[MUT_SHAGGY_FUR] = 1;
break;
case SP_KOBOLD:
+ you.mutation[MUT_SAPROVOROUS] = 2;
you.mutation[MUT_CARNIVOROUS] = 3;
break;
case SP_VAMPIRE:
@@ -2290,50 +2313,10 @@ static bool validate_player_name(bool verbose)
return (true);
} // end validate_player_name()
-#ifdef USE_SPELLCASTER_AND_RANGER_WANDERER_TEMPLATES
-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;
-
- 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 )
{
- // Mummies can't quaff and don't care
- if (you.species == SP_MUMMY)
+ // If you can't quaff, you don't care
+ if (you.is_undead == US_UNDEAD)
return;
you.inv[ slot ].quantity = 1;
@@ -2342,7 +2325,7 @@ static void give_random_potion( int slot )
you.inv[ slot ].plus2 = 0;
int temp_rand = 8;
- if (you.is_undead)
+ if (you.is_undead) // no Berserk for undeads
temp_rand--;
switch (random2(temp_rand))
@@ -2368,36 +2351,6 @@ static void give_random_potion( int slot )
}
}
-#ifdef USE_SPELLCASTER_AND_RANGER_WANDERER_TEMPLATES
-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;
-
- 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;
@@ -2554,25 +2507,23 @@ static void newgame_clear_item(int slot)
//
static void create_wanderer( void )
{
- const int util_skills[] =
+ const skill_type 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 increase its 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[] =
+ const skill_type 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[] =
+ const skill_type 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,
@@ -2581,9 +2532,8 @@ static void create_wanderer( void )
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[] =
+ const skill_type all_skills[] =
{ SK_SUMMONINGS, SK_NECROMANCY, SK_TRANSLOCATIONS, SK_TRANSMIGRATION,
SK_DIVINATIONS, SK_POISON_MAGIC,
SK_SLINGS, SK_BOWS, SK_CROSSBOWS,
@@ -2594,30 +2544,29 @@ static void create_wanderer( void )
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;
+ skill_type skill;
for (int i = 0; i < 2; i++)
{
do
{
- skill = random2( num_util_skills );
+ skill = RANDOM_ELEMENT(util_skills);
}
- while (you.skills[ util_skills[ skill ]] >= 2);
+ while (you.skills[skill] >= 2);
- you.skills[ util_skills[ skill ]] += 1;
+ you.skills[skill]++;
}
for (int i = 0; i < 3; i++)
{
do
{
- skill = random2( num_fight_util_skills );
+ skill = RANDOM_ELEMENT(fight_util_skills);
}
- while (you.skills[ fight_util_skills[ skill ]] >= 2);
+ while (you.skills[skill] >= 2);
- you.skills[ fight_util_skills[ skill ]] += 1;
+ you.skills[skill]++;
}
// Spell skills are possible past this point, but we won't
@@ -2626,55 +2575,51 @@ static void create_wanderer( void )
{
do
{
- skill = random2( num_not_rare_skills );
+ skill = RANDOM_ELEMENT(not_rare_skills);
}
- while (you.skills[ not_rare_skills[ skill ]] >= 2
- || (not_rare_skills[ skill ] >= SK_SPELLCASTING
- && you.skills[ not_rare_skills[ skill ]]));
+ while (you.skills[skill] >= 2
+ || (skill >= SK_SPELLCASTING && you.skills[skill] > 0));
- you.skills[ not_rare_skills[ skill ]] += 1;
+ you.skills[skill]++;
}
for (int i = 0; i < 2; i++)
{
do
{
- skill = random2( num_all_skills );
+ skill = RANDOM_ELEMENT(all_skills);
}
- while (you.skills[all_skills[ skill ]] >= 2
- || (all_skills[ skill ] >= SK_SPELLCASTING
- && you.skills[ all_skills[ skill ]]));
+ while (you.skills[skill] >= 2
+ || (skill >= SK_SPELLCASTING && you.skills[skill] > 0));
- you.skills[ all_skills[ skill ]] += 1;
+ you.skills[skill]++;
}
// 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 );
+ skill = RANDOM_ELEMENT(all_skills);
}
- while (skill == SK_INVOCATIONS && you.skills[all_skills[ skill ]]);
+ while (you.skills[skill] > 0);
- you.skills[ skill ] = 1;
+ you.skills[skill] = you.skills[SK_INVOCATIONS];
+ you.skills[SK_INVOCATIONS] = 0;
}
// ogres and draconians cannot wear armour
if ((you.species == SP_OGRE_MAGE || player_genus(GENPC_DRACONIAN))
&& you.skills[ SK_ARMOUR ])
{
- you.skills[ SK_ARMOUR ] = 0;
-
do
{
- skill = random2( num_all_skills );
+ skill = RANDOM_ELEMENT(all_skills);
}
- while (skill == SK_ARMOUR && you.skills[all_skills[ skill ]]);
+ while (you.skills[skill] > 0);
- you.skills[ skill ] = 1;
+ you.skills[skill] = you.skills[SK_ARMOUR];
+ you.skills[SK_ARMOUR] = 0;
}
int wpn_skill = SK_FIGHTING; // preferred weapon type
@@ -2750,127 +2695,6 @@ static void create_wanderer( void )
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
- // throwing weapons are lowered to -1 to make them
- // not as good as the one's hunters get, ammo is
- // also much smaller -- bwr
- newgame_make_item(1, EQ_NONE, OBJ_WEAPONS, WPN_BOW, 1, -1, -1);
-
- // Create default ammo template (darts) (armour is slot 2)
- newgame_make_item(4, EQ_NONE, OBJ_MISSILES, MI_DART,
- 10 + roll_dice( 2, 6 ));
-
- 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[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[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;
- // lower throwing skill (useless with arrows anyway)
- you.skills[SK_THROWING]--;
- }
- 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;
- // lower throwing skill
- you.skills[SK_THROWING]--;
- }
- 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
@@ -2884,62 +2708,37 @@ static void create_wanderer( void )
static job_type letter_to_class(int keyn)
{
- if (keyn == 'a')
- return JOB_FIGHTER;
- else if (keyn == 'b')
- return JOB_WIZARD;
- else if (keyn == 'c')
- return JOB_PRIEST;
- else if (keyn == 'd')
- return JOB_THIEF;
- else if (keyn == 'e')
- return JOB_GLADIATOR;
- else if (keyn == 'f')
- return JOB_NECROMANCER;
- else if (keyn == 'g')
- return JOB_PALADIN;
- else if (keyn == 'h')
- return JOB_ASSASSIN;
- else if (keyn == 'i')
- return JOB_BERSERKER;
- else if (keyn == 'j')
- return JOB_HUNTER;
- else if (keyn == 'k')
- return JOB_CONJURER;
- else if (keyn == 'l')
- return JOB_ENCHANTER;
- else if (keyn == 'm')
- return JOB_FIRE_ELEMENTALIST;
- else if (keyn == 'n')
- return JOB_ICE_ELEMENTALIST;
- else if (keyn == 'o')
- return JOB_SUMMONER;
- else if (keyn == 'p')
- return JOB_AIR_ELEMENTALIST;
- else if (keyn == 'q')
- return JOB_EARTH_ELEMENTALIST;
- else if (keyn == 'r')
- return JOB_CRUSADER;
- else if (keyn == 's')
- return JOB_DEATH_KNIGHT;
- else if (keyn == 't')
- return JOB_VENOM_MAGE;
- else if (keyn == 'u')
- return JOB_CHAOS_KNIGHT;
- else if (keyn == 'v')
- return JOB_TRANSMUTER;
- else if (keyn == 'w')
- return JOB_HEALER;
- else if (keyn == 'y')
- return JOB_REAVER;
- else if (keyn == 'z')
- return JOB_STALKER;
- else if (keyn == 'A')
- return JOB_MONK;
- else if (keyn == 'B')
- return JOB_WARPER;
- else if (keyn == 'C')
- return JOB_WANDERER;
+ switch ( keyn )
+ {
+ case 'a': return JOB_FIGHTER;
+ case 'b': return JOB_WIZARD;
+ case 'c': return JOB_PRIEST;
+ case 'd': return JOB_THIEF;
+ case 'e': return JOB_GLADIATOR;
+ case 'f': return JOB_NECROMANCER;
+ case 'g': return JOB_PALADIN;
+ case 'h': return JOB_ASSASSIN;
+ case 'i': return JOB_BERSERKER;
+ case 'j': return JOB_HUNTER;
+ case 'k': return JOB_CONJURER;
+ case 'l': return JOB_ENCHANTER;
+ case 'm': return JOB_FIRE_ELEMENTALIST;
+ case 'n': return JOB_ICE_ELEMENTALIST;
+ case 'o': return JOB_SUMMONER;
+ case 'p': return JOB_AIR_ELEMENTALIST;
+ case 'q': return JOB_EARTH_ELEMENTALIST;
+ case 'r': return JOB_CRUSADER;
+ case 's': return JOB_DEATH_KNIGHT;
+ case 't': return JOB_VENOM_MAGE;
+ case 'u': return JOB_CHAOS_KNIGHT;
+ case 'v': return JOB_TRANSMUTER;
+ case 'w': return JOB_HEALER;
+ case 'y': return JOB_REAVER;
+ case 'z': return JOB_STALKER;
+ case 'A': return JOB_MONK;
+ case 'B': return JOB_WARPER;
+ case 'C': return JOB_WANDERER;
+ }
return JOB_UNKNOWN;
}
@@ -3029,8 +2828,7 @@ spec_query:
cprintf(" (Press T to enter a tutorial.)");
cprintf(EOL EOL);
textcolor( CYAN );
- cprintf("You can be:");
- cprintf(" (Press ? for more information)");
+ cprintf("You can be: (Press ? for more information)");
cprintf(EOL EOL);
textcolor( LIGHTGREY );
@@ -3409,7 +3207,7 @@ bool give_items_skills()
{
char keyn;
int weap_skill = 0;
- int to_hit_bonus = 0; // used for assigning primary weapons {dlb}
+ int to_hit_bonus = 0; // used for assigning primary weapons {dlb}
int choice; // used for third-screen choices
switch (you.char_class)
@@ -3432,7 +3230,8 @@ bool give_items_skills()
if (you.species == SP_VAMPIRE && coinflip())
you.inv[1].sub_type = ARM_LEATHER_ARMOUR;
}
- else if (you.species == SP_KOBOLD)
+ else if (you.species == SP_HALFLING || you.species == SP_KOBOLD ||
+ you.species == SP_GNOME)
{
newgame_make_item(1, EQ_BODY_ARMOUR, OBJ_ARMOUR,
ARM_LEATHER_ARMOUR);
@@ -3459,7 +3258,8 @@ bool give_items_skills()
if (you.species != SP_TROLL)
weap_skill = 2;
- if (you.species == SP_KOBOLD)
+ if (you.species == SP_HALFLING || you.species == SP_KOBOLD ||
+ you.species == SP_GNOME)
{
you.skills[SK_THROWING] = 1;
you.skills[SK_DARTS] = 1;
@@ -3555,7 +3355,7 @@ bool give_items_skills()
newgame_make_item(1, EQ_BODY_ARMOUR, OBJ_ARMOUR, ARM_ROBE);
- if (you.species != SP_MUMMY)
+ if (you.is_undead != US_UNDEAD)
newgame_make_item(2, EQ_NONE, OBJ_POTIONS, POT_HEALING, 2);
you.skills[SK_FIGHTING] = 2;
@@ -3628,7 +3428,7 @@ bool give_items_skills()
}
getkey:
- keyn = get_ch();
+ keyn = c_getch();
if ((keyn == '\r' || keyn == '\n')
&& Options.prev_pr != GOD_NO_GOD)
@@ -4221,7 +4021,7 @@ bool give_items_skills()
}
getkey1:
- keyn = get_ch();
+ keyn = c_getch();
if ((keyn == '\r' || keyn == '\n')
&& Options.prev_dk != DK_NO_SELECTION)
@@ -4344,7 +4144,7 @@ bool give_items_skills()
getkey2:
- keyn = get_ch();
+ keyn = c_getch();
if ((keyn == '\r' || keyn == '\n')
&& Options.prev_ck != GOD_NO_GOD)
diff --git a/crawl-ref/source/notes.h b/crawl-ref/source/notes.h
index ef4f794d05..8cfc929e77 100644
--- a/crawl-ref/source/notes.h
+++ b/crawl-ref/source/notes.h
@@ -30,7 +30,7 @@ enum NOTE_TYPES
NOTE_GET_MUTATION, /* needs: mutation idx */
NOTE_LOSE_MUTATION, /* needs: mutation idx */
NOTE_ID_ITEM, /* needs: item name (string) */
- NOTE_GET_ITEM, /* needs: item name (string) NOT HOOKED */
+ NOTE_GET_ITEM, /* needs: item name (string) */
NOTE_GAIN_SKILL, /* needs: skill id, level */
NOTE_SEEN_MONSTER, /* needs: monster name (string) */
NOTE_KILL_MONSTER, /* needs: monster name (string) */
diff --git a/crawl-ref/source/ouch.cc b/crawl-ref/source/ouch.cc
index a8759320ec..47a600c38c 100644
--- a/crawl-ref/source/ouch.cc
+++ b/crawl-ref/source/ouch.cc
@@ -77,6 +77,7 @@
#include "stuff.h"
#include "tutorial.h"
#include "view.h"
+#include "xom.h"
static void end_game( scorefile_entry &se );
@@ -588,7 +589,11 @@ void lose_level()
// 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 );
+ // Return in case death was canceled via wizard mode
+ return;
+ }
you.experience = exp_needed( you.experience_level + 1 ) - 1;
you.experience_level--;
@@ -628,7 +633,7 @@ void drain_exp(bool announce_full)
return;
}
- if (protection >= 3 || you.is_undead)
+ if (protection >= 3)
{
if ( announce_full )
mpr("You fully resist.");
@@ -636,7 +641,11 @@ void drain_exp(bool announce_full)
}
if (you.experience == 0)
+ {
ouch(-9999, 0, KILLED_BY_DRAINING);
+ // Return in case death was escaped via wizard mode;
+ return;
+ }
if (you.experience_level == 1)
{
@@ -683,12 +692,24 @@ static void xom_checks_damage(kill_method_type death_type,
//if (you.hp <= dam)
// xom_is_stimulated(32);
- if ((death_type != KILLED_BY_MONSTER && death_type != KILLED_BY_BEAM)
- || death_source < 0 || death_source >= MAX_MONSTERS)
+ if (death_type == KILLED_BY_TARGETTING)
+ {
+ // Xom thinks the player hurting him/herself is funny.
+ xom_is_stimulated(255 * dam / (dam + you.hp));
+ return;
+ }
+ else if (death_type == KILLED_BY_FALLING_DOWN_STAIRS)
+ {
+ // Xom thinks falling down the stairs is hilarious
+ xom_is_stimulated(255);
+ return;
+ }
+ else if ((death_type != KILLED_BY_MONSTER && death_type != KILLED_BY_BEAM)
+ || death_source < 0 || death_source >= MAX_MONSTERS)
{
return ;
}
-
+
int amusementvalue = 1;
const monsters *monster = &menv[death_source];
@@ -696,6 +717,13 @@ static void xom_checks_damage(kill_method_type death_type,
if (!monster->alive())
return;
+ if (mons_attitude(monster) == ATT_FRIENDLY)
+ {
+ // Xom thinks collateral damage is funny
+ xom_is_stimulated(255 * dam / (dam + you.hp));
+ return;
+ }
+
int leveldif = monster->hit_dice - you.experience_level;
if (leveldif == 0)
@@ -738,6 +766,9 @@ void ouch( int dam, int death_source, kill_method_type death_type,
ait_hp_loss hpl(dam, death_type);
interrupt_activity( AI_HP_LOSS, &hpl );
+ if (dam > 0)
+ you.check_awaken(500);
+
if (you.duration[DUR_DEATHS_DOOR] && death_type != KILLED_BY_LAVA
&& death_type != KILLED_BY_WATER)
{
@@ -754,23 +785,17 @@ void ouch( int dam, int death_source, kill_method_type death_type,
if (dam > -9000) // that is, a "death" caused by hp loss {dlb}
{
- switch (you.religion)
+ if (god_protects_from_harm(you.religion))
{
- case GOD_ZIN:
- case GOD_SHINING_ONE:
- case GOD_ELYVILON:
- case GOD_YREDELEMNUL:
- if (dam >= you.hp && you.duration[DUR_PRAYER]
- && random2(you.piety) >= 30)
+ if (dam >= you.hp
+ && (one_chance_in(10) || you.piety > random2(1000)))
{
simple_god_message( " protects you from harm!" );
return;
}
- break;
- default:
- break;
}
+ dec_hp( dam, true );
dec_hp( dam, true );
@@ -808,6 +833,25 @@ void ouch( int dam, int death_source, kill_method_type death_type,
return;
} // else hp <= 0
+ // for note taking
+ std::string damage_desc = "";
+ if (!see_source)
+ {
+ snprintf(info, INFO_SIZE, "something (%d)", dam);
+ damage_desc = info;
+ }
+ else
+ {
+ damage_desc = scorefile_entry(dam, death_source,
+ death_type, aux, true)
+ .death_description(scorefile_entry::DDV_TERSE);
+ }
+
+ take_note(
+ Note(NOTE_HP_CHANGE, you.hp, you.hp_max, damage_desc.c_str()) );
+
+ return;
+ } // else hp <= 0
}
#ifdef WIZARD
@@ -994,6 +1038,7 @@ void end_game( struct scorefile_entry &se )
}
invent( -1, true );
+ textcolor( LIGHTGREY );
clrscr();
if (!dump_char( morgue_name(se.death_time), !dead, true, &se ))
diff --git a/crawl-ref/source/output.cc b/crawl-ref/source/output.cc
index ee215b8ee2..792bf67d41 100644
--- a/crawl-ref/source/output.cc
+++ b/crawl-ref/source/output.cc
@@ -198,9 +198,6 @@ void print_stats(void)
you.redraw_strength = 0;
- if (you.strength < 1)
- ouch(INSTANT_DEATH, 0, KILLED_BY_WEAKNESS);
-
burden_change();
}
@@ -228,9 +225,6 @@ void print_stats(void)
cprintf( " " );
you.redraw_intelligence = 0;
-
- if (you.intel < 1)
- ouch(INSTANT_DEATH, 0, KILLED_BY_STUPIDITY);
}
if (you.redraw_dexterity)
@@ -257,9 +251,6 @@ void print_stats(void)
cprintf( " " );
you.redraw_dexterity = 0;
-
- if (you.dex < 1)
- ouch(INSTANT_DEATH, 0, KILLED_BY_CLUMSINESS);
}
if (you.redraw_armour_class)
@@ -328,10 +319,9 @@ void print_stats(void)
clear_to_end_of_line();
gotoxy(xcol, 13);
- if (you.equip[EQ_WEAPON] != -1)
+ if (you.weapon())
{
-
- const item_def& wpn = you.inv[you.equip[EQ_WEAPON]];
+ const item_def& wpn = *you.weapon();
textcolor(wpn.colour);
const std::string prefix = menu_colour_item_prefix(wpn);
@@ -339,9 +329,7 @@ void print_stats(void)
if (prefcol != -1)
textcolor(prefcol);
- cprintf("%s",
- wpn.name(DESC_INVENTORY,
- Options.terse_hand).substr(0,38).c_str());
+ cprintf("%s", wpn.name(DESC_INVENTORY, true).substr(0,38).c_str());
textcolor(LIGHTGREY);
}
else
@@ -550,6 +538,12 @@ void print_stats(void)
textcolor( RED ); // no different levels
cprintf( "Conf " );
}
+
+ if (you.duration[DUR_BEHELD])
+ {
+ textcolor( RED ); // no different levels
+ cprintf( "Bhld " );
+ }
if (you.duration[DUR_LIQUID_FLAMES])
{
@@ -918,30 +912,7 @@ std::vector<formatted_string> get_full_detail(bool calc_unid, long sc)
determine_color_string(rcorr), itosym1(rcorr));
cols.add_formatted(2, buf, false);
- int saplevel = 0;
- switch (you.species)
- {
- case SP_GHOUL:
- saplevel = 3;
- snprintf(buf, sizeof buf, "%sSaprovore : %s",
- determine_color_string(3), itosym3(3) );
- break;
-
- case SP_KOBOLD:
- case SP_TROLL:
- saplevel = 2;
- snprintf(buf, sizeof buf, "%sSaprovore : %s",
- determine_color_string(2), itosym3(2) );
- break;
-
- case SP_HILL_ORC:
- case SP_OGRE:
- saplevel = 1;
- break;
- default:
- saplevel = 0;
- break;
- }
+ int saplevel = you.mutation[MUT_SAPROVOROUS];
const char* pregourmand;
const char* postgourmand;
if ( wearing_amulet(AMU_THE_GOURMAND, calc_unid) )
@@ -999,6 +970,7 @@ void print_overview_screen()
cmd_help.set_flags(MF_NOSELECT | MF_ALWAYS_SHOW_MORE | MF_NOWRAP, false);
cmd_help.set_more( formatted_string::parse_string(
"<cyan>[ + : Page down. - : Page up. Esc exits.]"));
+ cmd_help.set_tag("resists");
std::string text;
char title[50];
@@ -1171,30 +1143,7 @@ void print_overview_screen()
determine_color_string(rslow), itosym1(rslow));
cols.add_formatted(0, buf, false);
- int saplevel = 0;
- switch (you.species)
- {
- case SP_GHOUL:
- saplevel = 3;
- snprintf(buf, sizeof buf, "%sSaprovore : %s",
- determine_color_string(3), itosym3(3) );
- break;
-
- case SP_KOBOLD:
- case SP_TROLL:
- saplevel = 2;
- snprintf(buf, sizeof buf, "%sSaprovore : %s",
- determine_color_string(2), itosym3(2) );
- break;
-
- case SP_HILL_ORC:
- case SP_OGRE:
- saplevel = 1;
- break;
- default:
- saplevel = 0;
- break;
- }
+ int saplevel = you.mutation[MUT_SAPROVOROUS];
const char* pregourmand;
const char* postgourmand;
if ( wearing_amulet(AMU_THE_GOURMAND, calc_unid) )
@@ -1411,8 +1360,11 @@ std::string status_mut_abilities()
if (you.duration[DUR_CONF])
text += "confused, ";
+ // how exactly did you get to show the status?
if (you.duration[DUR_PARALYSIS])
text += "paralysed, ";
+ if (you.duration[DUR_SLEEP])
+ text += "sleeping, ";
if (you.duration[DUR_EXHAUSTED])
text += "exhausted, ";
@@ -1464,8 +1416,6 @@ std::string status_mut_abilities()
text += "bonded with blade, ";
int move_cost = (player_speed() * player_movement_speed()) / 10;
- if ( you.duration[DUR_SLOW] )
- move_cost *= 2;
text += (move_cost < 8) ? "very quick, " :
(move_cost < 10) ? "quick, " :
@@ -1598,16 +1548,6 @@ std::string status_mut_abilities()
have_any = true;
break;
- case SP_TROLL:
- text += "saprovore 2";
- have_any = true;
- break;
-
- case SP_GHOUL:
- text += "saprovore 3";
- have_any = true;
- break;
-
case SP_GREY_ELF:
if (you.experience_level > 4)
{
@@ -1714,16 +1654,6 @@ std::string status_mut_abilities()
}
break;
- case SP_KOBOLD:
- text += "saprovore 2";
- have_any = true;
- break;
-
- case SP_HILL_ORC:
- case SP_OGRE:
- text += "saprovore 1";
- have_any = true;
- break;
default:
break;
} //end switch - innate abilities
@@ -1798,6 +1728,13 @@ std::string status_mut_abilities()
text += "poison resistance";
have_any = true;
break;
+ case MUT_SAPROVOROUS:
+ if (have_any)
+ text += ", ";
+ snprintf(info, INFO_SIZE, "saprovore %d", level);
+ text += info;
+ have_any = true;
+ break;
case MUT_CARNIVOROUS:
if (have_any)
text += ", ";
@@ -1950,10 +1887,10 @@ std::string status_mut_abilities()
Str_change -= level;
Dex_change += level;
break;
- case MUT_LOST:
+ case MUT_SCREAM:
if (have_any)
text += ", ";
- snprintf(info, INFO_SIZE, "forgetfulness %d", level);
+ snprintf(info, INFO_SIZE, "screaming %d", level);
text += info;
have_any = true;
break;
@@ -2006,6 +1943,36 @@ std::string status_mut_abilities()
text += info;
have_any = true;
break;
+ case MUT_LOW_MAGIC:
+ if (have_any)
+ text += ", ";
+ snprintf(info, INFO_SIZE, "-%d%% mp", level*10);
+ text += info;
+ have_any = true;
+ break;
+ case MUT_HIGH_MAGIC:
+ if (have_any)
+ text += ", ";
+ snprintf(info, INFO_SIZE, "+%d mp%%", level*10);
+ text += info;
+ have_any = true;
+ break;
+ case MUT_DRIFTING:
+ if (have_any)
+ text += ", ";
+ snprintf(info, INFO_SIZE, "drifting %d", level);
+ text += info;
+ have_any = true;
+ break;
+ case MUT_SLEEPINESS:
+ if (have_any)
+ text += ", ";
+ snprintf(info, INFO_SIZE, "sleepiness %d", level);
+ text += info;
+ have_any = true;
+ break;
+
+ /* demonspawn mutations */
case MUT_TORMENT_RESISTANCE:
if (have_any)
text += ", ";
@@ -2097,6 +2064,7 @@ std::string status_mut_abilities()
text += "invoke powers of Tartarus";
have_any = true;
break;
+ /* end of demonspawn mutations */
case MUT_CLAWS:
if (have_any)
text += ", ";
@@ -2104,17 +2072,29 @@ std::string status_mut_abilities()
text += info;
have_any = true;
break;
+ case MUT_FANGS:
+ if (have_any)
+ text += ", ";
+ snprintf(info, INFO_SIZE, "sharp teeth %d", level);
+ text += info;
+ have_any = true;
+ break;
case MUT_HOOVES:
if (have_any)
text += ", ";
text += "hooves";
have_any = true;
break;
- case MUT_FANGS:
+ case MUT_TALONS:
if (have_any)
text += ", ";
- snprintf(info, INFO_SIZE, "sharp teeth %d", level);
- text += info;
+ text += "talons";
+ have_any = true;
+ break;
+ case MUT_PAWS:
+ if (have_any)
+ text += ", ";
+ text += "soft paws";
have_any = true;
break;
case MUT_BREATHE_POISON:
@@ -2150,6 +2130,8 @@ std::string status_mut_abilities()
text += info;
have_any = true;
break;
+
+ // scales etc. -> calculate sum of AC bonus
case MUT_RED_SCALES:
AC_change += level;
if (level == 3)
@@ -2216,6 +2198,9 @@ std::string status_mut_abilities()
case MUT_PATTERNED_SCALES:
AC_change += level;
break;
+ case MUT_SHAGGY_FUR:
+ AC_change += level;
+ break;
default: break;
}
}
diff --git a/crawl-ref/source/overmap.cc b/crawl-ref/source/overmap.cc
index b414e4e443..c1fb568ca8 100644
--- a/crawl-ref/source/overmap.cc
+++ b/crawl-ref/source/overmap.cc
@@ -26,6 +26,7 @@
#include "externs.h"
#include "branch.h"
+#include "cio.h"
#include "dgnevent.h"
#include "direct.h"
#include "dungeon.h"
@@ -43,11 +44,13 @@ typedef std::map<branch_type, level_id> stair_map_type;
typedef std::map<level_pos, shop_type> shop_map_type;
typedef std::map<level_pos, god_type> altar_map_type;
typedef std::map<level_pos, portal_type> portal_map_type;
+typedef std::map<level_id, std::string> annotation_map_type;
stair_map_type stair_level;
shop_map_type shops_present;
altar_map_type altars_present;
portal_map_type portals_present;
+annotation_map_type level_annotations;
static void seen_altar( god_type god, const coord_def& pos );
static void seen_staircase(dungeon_feature_type which_staircase,
@@ -368,6 +371,61 @@ std::string overview_description_string()
disp += "You didn't discover anything interesting.";
}
+ bool notes_exist = false;
+ bool has_notes[NUM_BRANCHES];
+
+ for (int i = 0; i < NUM_BRANCHES; ++i)
+ {
+ Branch branch = branches[i];
+
+ has_notes[i] = false;
+ for (int depth = 1; depth <= branch.depth; depth++)
+ {
+ const level_id li(branch.id, depth);
+
+ if (get_level_annotation(li).length() > 0)
+ {
+ notes_exist = true;
+ has_notes[i] = true;
+ break;
+ }
+ }
+ }
+
+ if (notes_exist)
+ {
+ disp += "\n\n <white>Level Annotations</white>\n" ;
+
+ for (int i = 0; i < NUM_BRANCHES; ++i)
+ {
+ if (!has_notes[i])
+ continue;
+
+ Branch branch = branches[i];
+
+ disp += "\n<yellow>";
+ disp += branch.shortname;
+ disp += "</yellow>\n";
+
+ for (int depth = 1; depth <= branch.depth; depth++)
+ {
+ const level_id li(branch.id, depth);
+
+ if (get_level_annotation(li).length() > 0)
+ {
+ char depth_str[3];
+ sprintf(depth_str, "%2d", depth);
+
+ disp += "<white>";
+ disp += depth_str;
+ disp += ":</white> ";
+ disp += get_level_annotation(li);
+ disp += + "\n";
+ }
+ }
+ }
+ }
+
return disp;
}
@@ -510,3 +568,95 @@ void seen_other_thing( dungeon_feature_type which_thing, const coord_def& pos )
break;
}
} // end seen_other_thing()
+
+////////////////////////////////////////////////////////////////////////
+
+void set_level_annotation(std::string str,
+ level_id li)
+{
+ if (str == "")
+ {
+ clear_level_annotation(li);
+ return;
+ }
+
+ level_annotations[li] = str;
+}
+
+void clear_level_annotation(level_id li)
+{
+ level_annotations.erase(li);
+}
+
+std::string get_level_annotation(level_id li)
+{
+ annotation_map_type::const_iterator i = level_annotations.find(li);
+
+ if (i == level_annotations.end())
+ return "";
+
+ return (i->second);
+}
+
+bool level_annotation_has(std::string find,
+ level_id li)
+{
+ std::string str = get_level_annotation(li);
+
+ return (str.find(find) != std::string::npos);
+}
+
+void annotate_level()
+{
+ level_id li = level_id::current();
+ level_id li2 = level_id::current();
+
+ if (is_stair(grd[you.x_pos][you.y_pos]))
+ {
+ li2 = level_id::get_next_level_id(you.pos());
+
+ if (li2.level_type != LEVEL_DUNGEON || li2.depth <= 0)
+ li2 = level_id::current();
+ }
+
+ if (you.level_type != LEVEL_DUNGEON && li2.level_type != LEVEL_DUNGEON)
+ {
+ mpr("You can't annotate this level.");
+ return;
+ }
+
+ if (you.level_type != LEVEL_DUNGEON)
+ li = li2;
+ else if (li2 != level_id::current())
+ {
+ if (yesno("Annotate level on other end of current stairs?"))
+ li = li2;
+ }
+
+ if (get_level_annotation(li).length() > 0)
+ {
+ mpr("Current level annotation is:", MSGCH_PROMPT);
+ mpr(get_level_annotation(li).c_str() );
+ }
+
+ mpr( "Set level annotation to what? ", MSGCH_PROMPT );
+
+ char buf[77];
+ get_input_line( buf, sizeof(buf) );
+
+ if (strlen(buf) == 0)
+ {
+ if (get_level_annotation(li).length() > 0)
+ {
+ if (!yesno("Really clear the annotation?"))
+ return;
+ }
+ else
+ {
+ canned_msg(MSG_OK);
+ return;
+ }
+ }
+
+ set_level_annotation(buf, li);
+}
diff --git a/crawl-ref/source/overmap.h b/crawl-ref/source/overmap.h
index f9f16a71ad..035779f004 100644
--- a/crawl-ref/source/overmap.h
+++ b/crawl-ref/source/overmap.h
@@ -21,4 +21,16 @@ void display_overmap();
bool unnotice_feature(const level_pos &pos);
std::string overview_description_string();
+///////////////////////////////////////////////////////////
+void set_level_annotation(std::string str,
+ level_id li = level_id::current());
+void clear_level_annotation(level_id li = level_id::current());
+
+std::string get_level_annotation(level_id li = level_id::current());
+
+bool level_annotation_has(std::string str,
+ level_id li = level_id::current());
+
+void annotate_level();
+
#endif
diff --git a/crawl-ref/source/place.cc b/crawl-ref/source/place.cc
index 023bcd9534..fc89dbd60b 100644
--- a/crawl-ref/source/place.cc
+++ b/crawl-ref/source/place.cc
@@ -37,6 +37,13 @@ int place_depth(unsigned short place)
return lev == 0xFF? -1 : lev;
}
+int place_type(unsigned short place)
+{
+ const unsigned type = (unsigned) ((place >> 8) & 0xFF);
+ const int lev = place & 0xFF;
+ return lev == 0xFF? (int) type : (int) LEVEL_DUNGEON;
+}
+
unsigned short get_packed_place( branch_type branch, int subdepth,
level_area_type level_type )
{
diff --git a/crawl-ref/source/place.h b/crawl-ref/source/place.h
index 078db1f571..f62f0b57b9 100644
--- a/crawl-ref/source/place.h
+++ b/crawl-ref/source/place.h
@@ -25,6 +25,8 @@ unsigned short get_packed_place( branch_type branch, int subdepth,
int place_branch(unsigned short place);
int place_depth(unsigned short place);
+int place_type(unsigned short place);
+
std::string short_place_name(unsigned short place);
std::string short_place_name(level_id id);
std::string place_name( unsigned short place, bool long_name = false,
diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc
index efacc4313a..68408d4dcc 100644
--- a/crawl-ref/source/player.cc
+++ b/crawl-ref/source/player.cc
@@ -53,6 +53,7 @@
#include "notes.h"
#include "ouch.h"
#include "output.h"
+#include "place.h"
#include "randart.h"
#include "religion.h"
#include "skills.h"
@@ -61,6 +62,7 @@
#include "spells3.h"
#include "spl-util.h"
#include "spells4.h"
+#include "state.h"
#include "stuff.h"
#include "terrain.h"
#include "transfor.h"
@@ -68,6 +70,7 @@
#include "travel.h"
#include "tutorial.h"
#include "view.h"
+#include "xom.h"
std::string pronoun_you(description_level_type desc)
{
@@ -112,7 +115,7 @@ bool move_player_to_grid( int x, int y, bool stepped, bool allow_shift,
const dungeon_feature_type new_grid = grd[x][y];
// really must be clear
- ASSERT( !grid_is_solid( new_grid ) );
+ ASSERT( you.can_pass_through( new_grid ) );
// if (grid_is_solid( new_grid ))
// return (false);
@@ -152,11 +155,15 @@ bool move_player_to_grid( int x, int y, bool stepped, bool allow_shift,
return (false);
}
} // unknown trap
- else if (new_grid == DNGN_TRAP_MAGICAL)
+ else if (new_grid == DNGN_TRAP_MAGICAL
+ || new_grid == DNGN_TRAP_NATURAL)
{
- std::string prompt = "Really step onto that "; // preposition?
+ std::string prompt = "Really step ";
+ prompt += (trap_type_at_xy(x,y) == TRAP_ALARM ?
+ "onto" : "into");
+ prompt += " that ";
prompt += feature_description(new_grid, trap_type_at_xy(x,y),
- DESC_PLAIN, false);
+ DESC_BASENAME, false);
prompt += '?';
// Zot traps require capital confirmation
@@ -323,7 +330,8 @@ bool is_grid_dangerous(int grid)
bool player_in_mappable_area( void )
{
- return (you.level_type != LEVEL_LABYRINTH && you.level_type != LEVEL_ABYSS);
+ return (!(testbits(env.level_flags, LFLAG_NOT_MAPPABLE)
+ || testbits(get_branch_flags(), BFLAG_NOT_MAPPABLE)));
}
bool player_in_branch( int branch )
@@ -404,6 +412,90 @@ bool player_genus(genus_type which_genus, species_type species)
return (false);
} // end player_genus()
+bool is_player_same_species(const int mon)
+{
+ switch (you.species)
+ {
+ case SP_HUMAN:
+ if (mons_species(mon) == MONS_HUMAN)
+ return (true);
+ return (false);
+ case SP_CENTAUR:
+ if (mons_species(mon) == MONS_CENTAUR)
+ return (true);
+ return (false);
+ case SP_OGRE:
+ case SP_OGRE_MAGE:
+ if (mons_species(mon) == MONS_OGRE)
+ return (true);
+ return (false);
+ case SP_TROLL:
+ if (mons_species(mon) == MONS_TROLL)
+ return (true);
+ return (false);
+ case SP_MUMMY:
+ if (mons_species(mon) == MONS_MUMMY)
+ return (true);
+ return (false);
+ case SP_GHOUL:
+ if (mons_species(mon) == MONS_GHOUL)
+ return (true);
+ return (false);
+ case SP_VAMPIRE:
+ if (mons_species(mon) == MONS_VAMPIRE)
+ return (true);
+ return (false);
+ case SP_MINOTAUR:
+ if (mons_species(mon) == MONS_MINOTAUR)
+ return (true);
+ return (false);
+ case SP_NAGA:
+ if (mons_species(mon) == MONS_NAGA)
+ return (true);
+ return (false);
+ case SP_HILL_ORC:
+ if (mons_species(mon) == MONS_ORC)
+ return (true);
+ return (false);
+ case SP_MERFOLK:
+ if (mons_species(mon) == MONS_MERFOLK
+ || mons_species(mon) == MONS_MERMAID)
+ {
+ return (true);
+ }
+ return (false);
+
+ case SP_GREY_ELF:
+ case SP_HIGH_ELF:
+ case SP_DEEP_ELF:
+ case SP_SLUDGE_ELF:
+ if (mons_species(mon) == MONS_ELF)
+ return (true);
+ return (false);
+
+ 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:
+ if (mons_species(mon) == MONS_DRACONIAN)
+ return (true);
+ return (false);
+
+ case SP_KOBOLD:
+ if (mons_species(mon) == MONS_KOBOLD)
+ return (true);
+ return (false);
+ default: // no monster equivalent
+ return (false);
+
+ }
+}
+
// checks whether the player's current species can
// use (usually wear) a given piece of equipment
// Note that EQ_BODY_ARMOUR and EQ_HELMET only check
@@ -455,17 +547,32 @@ bool you_can_wear(int eq, bool special_armour)
return true;
}
+bool player_has_feet()
+{
+ if (you.species == SP_NAGA || player_genus(GENPC_DRACONIAN))
+ return false;
+
+ if (you.mutation[MUT_HOOVES] || you.mutation[MUT_TALONS]
+ || you.mutation[MUT_PAWS])
+ {
+ return false;
+ }
+
+ return true;
+}
+
bool you_tran_can_wear(int eq, bool check_mutation)
{
// not a transformation, but also temporary -> check first
if (check_mutation)
{
- if (you.mutation[MUT_CLAWS] >= 3 && eq == EQ_GLOVES)
+ if (eq == EQ_GLOVES && you.has_claws(false) >= 3)
return false;
if (eq == EQ_BOOTS
&& (player_is_swimming() && you.species == SP_MERFOLK
- || you.mutation[MUT_HOOVES]))
+ || you.mutation[MUT_HOOVES] || you.mutation[MUT_TALONS]
+ || you.mutation[MUT_PAWS]))
{
return false;
}
@@ -942,7 +1049,7 @@ int player_res_magic(void)
break;
}
- /* randarts - multiplicative effect */
+ /* randarts */
rm += scan_randarts(RAP_MAGIC);
/* armour */
@@ -1080,6 +1187,9 @@ int player_res_cold(bool calc_unid)
// mutations:
rc += you.mutation[MUT_COLD_RESISTANCE];
+
+ if (you.mutation[MUT_SHAGGY_FUR] == 3)
+ rc++;
if (you.duration[DUR_FIRE_SHIELD])
rc -= 2;
@@ -1590,6 +1700,9 @@ int player_speed(void)
{
int ps = 10;
+ if (you.duration[DUR_SLOW])
+ ps *= 2;
+
if (you.duration[DUR_HASTE])
ps /= 2;
@@ -1764,6 +1877,7 @@ int player_AC(void)
AC += 100 * you.mutation[MUT_IRIDESCENT_SCALES];
AC += 100 * you.mutation[MUT_PATTERNED_SCALES];
AC += 100 * you.mutation[MUT_BLUE_SCALES];
+ AC += 100 * you.mutation[MUT_SHAGGY_FUR];
// these gives: +1, +3, +5
if (you.mutation[MUT_GREEN_SCALES] > 0)
@@ -2166,8 +2280,9 @@ 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 );
+ ret += 13 * player_equip( EQ_STAFF, STAFF_POWER );
+ ret += 9 * player_equip( EQ_RINGS, RING_MAGICAL_POWER );
+ ret += scan_randarts( RAP_MAGICAL_POWER );
return (ret);
}
@@ -2266,7 +2381,7 @@ int player_see_invis(bool calc_unid)
// 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().
+// to find if the square the monster is in los see mons_near().
bool player_monster_visible( const monsters *mon )
{
if (mon->has_ench(ENCH_SUBMERGED)
@@ -2278,6 +2393,126 @@ bool player_monster_visible( const monsters *mon )
return (true);
}
+// returns true if player is beheld by a given monster
+bool player_beheld_by( const monsters *mon )
+{
+ if (!you.duration[DUR_BEHELD])
+ return false;
+
+ // can this monster even behold you?
+ if (mon->type != MONS_MERMAID)
+ return false;
+
+#ifdef DEBUG_DIAGNOSTICS
+ mprf(MSGCH_DIAGNOSTICS, "beheld_by.size: %d, DUR_BEHELD: %d, current mon: %d",
+ you.beheld_by.size(), you.duration[DUR_BEHELD],
+ monster_index(mon));
+#endif
+
+ if (you.beheld_by.empty()) // shouldn't happen
+ {
+ you.duration[DUR_BEHELD] = 0;
+ return false;
+ }
+
+ for (unsigned int i = 0; i < you.beheld_by.size(); i++)
+ {
+ unsigned int which_mon = you.beheld_by[i];
+ if (monster_index(mon) == which_mon)
+ return true;
+ }
+
+ return false;
+}
+
+// removes a monster from the list of beholders
+// if force == true (e.g. monster dead) or one of
+// several cases is met
+void update_beholders(const monsters *mon, bool force)
+{
+ if (!player_beheld_by(mon)) // not in list?
+ return;
+
+ // is an update even necessary?
+ if (force || !mons_near(mon) || mons_friendly(mon) || mon->submerged()
+ || mon->has_ench(ENCH_CONFUSION) || mons_is_paralysed(mon) || mon->asleep()
+ || silenced(you.x_pos, you.y_pos) || silenced(mon->x, mon->y))
+ {
+ const std::vector<int> help = you.beheld_by;
+ you.beheld_by.clear();
+
+ for (unsigned int i = 0; i < help.size(); i++)
+ {
+ unsigned int which_mon = help[i];
+ if (monster_index(mon) != which_mon)
+ you.beheld_by.push_back(i);
+ }
+
+ if (you.beheld_by.empty())
+ {
+ mpr("You are no longer entranced.", MSGCH_RECOVERY);
+ you.duration[DUR_BEHELD] = 0;
+ }
+ }
+}
+
+void check_beholders()
+{
+ for (int i = you.beheld_by.size() - 1; i >= 0; i--)
+ {
+ const monsters* mon = &menv[you.beheld_by[i]];
+ if (!mon->alive() || mon->type != MONS_MERMAID)
+ {
+#if DEBUG
+ if (!mon->alive())
+ mpr("Dead mermaid still beholding?", MSGCH_DIAGNOSTICS);
+ else if (mon->type != MONS_MERMAID)
+ mprf(MSGCH_DIAGNOSTICS, "Non-mermaid '%s' beholding?",
+ mon->name(DESC_PLAIN, true).c_str());
+#endif
+
+ you.beheld_by.erase(you.beheld_by.begin() + i);
+ if (you.beheld_by.empty())
+ {
+ mpr("You are no longer entranced.", MSGCH_RECOVERY);
+ you.duration[DUR_BEHELD] = 0;
+ break;
+ }
+ continue;
+ }
+ const coord_def pos = mon->pos();
+ int walls = num_feats_between(you.x_pos, you.y_pos,
+ pos.x, pos.y, DNGN_UNSEEN,
+ DNGN_MAXWALL);
+
+ if (walls > 0)
+ {
+#if DEBUG
+ mprf(MSGCH_DIAGNOSTICS, "%d walls between beholding '%s' "
+ "and player", walls, mon->name(DESC_PLAIN, true).c_str());
+#endif
+ you.beheld_by.erase(you.beheld_by.begin() + i);
+ if (you.beheld_by.empty())
+ {
+ mpr("You are no longer entranced.", MSGCH_RECOVERY);
+ you.duration[DUR_BEHELD] = 0;
+ break;
+ }
+ continue;
+ }
+ }
+
+ if (you.duration[DUR_BEHELD] > 0 && you.beheld_by.empty())
+ {
+#if DEBUG
+ mpr("Beheld with no mermaids left?", MSGCH_DIAGNOSTICS);
+#endif
+
+ mpr("You are no longer entranced.", MSGCH_RECOVERY);
+ you.duration[DUR_BEHELD] = 0;
+ }
+}
+
int player_sust_abil(bool calc_unid)
{
int sa = 0;
@@ -2396,19 +2631,24 @@ bool you_resist_magic(int power)
return 1; */
}
-void forget_map(unsigned char chance_forgotten)
+// force is true for forget_map command on level map
+void forget_map(unsigned char chance_forgotten, bool force)
{
- unsigned char xcount, ycount = 0;
+ if ( force && !yesno("Really forget level map?", true, 'n') )
+ return;
- for (xcount = 0; xcount < GXM; xcount++)
+ for (unsigned char xcount = 0; xcount < GXM; xcount++)
{
- for (ycount = 0; ycount < GYM; ycount++)
+ for (unsigned char ycount = 0; ycount < GYM; ycount++)
{
- if (random2(100) < chance_forgotten)
- env.map[xcount][ycount].clear();
+ if (!see_grid(xcount, ycount) &&
+ (force || random2(100) < chance_forgotten))
+ {
+ env.map[xcount][ycount].clear();
+ }
}
}
-} // end forget_map()
+} // end forget_map()
void gain_exp( unsigned int exp_gained, unsigned int* actual_gain,
unsigned int* actual_avail_gain)
@@ -2495,7 +2735,7 @@ void level_change(bool skip_ability_increase)
{
case SP_HUMAN:
if (!(you.experience_level % 5))
- modify_stat(STAT_RANDOM, 1, false);
+ modify_stat(STAT_RANDOM, 1, false, "level gain");
break;
case SP_HIGH_ELF:
@@ -2514,7 +2754,8 @@ void level_change(bool skip_ability_increase)
if (!(you.experience_level % 3))
{
modify_stat( (coinflip() ? STAT_INTELLIGENCE
- : STAT_DEXTERITY), 1, false );
+ : STAT_DEXTERITY), 1, false,
+ "level gain");
}
break;
@@ -2535,7 +2776,8 @@ void level_change(bool skip_ability_increase)
if (!(you.experience_level % 4))
{
modify_stat( (coinflip() ? STAT_INTELLIGENCE
- : STAT_DEXTERITY), 1, false );
+ : STAT_DEXTERITY), 1, false,
+ "level gain");
}
break;
@@ -2549,7 +2791,7 @@ void level_change(bool skip_ability_increase)
mp_adjust++;
if (!(you.experience_level % 4))
- modify_stat(STAT_INTELLIGENCE, 1, false);
+ modify_stat(STAT_INTELLIGENCE, 1, false, "level gain");
break;
case SP_SLUDGE_ELF:
@@ -2561,7 +2803,8 @@ void level_change(bool skip_ability_increase)
if (!(you.experience_level % 4))
{
modify_stat( (coinflip() ? STAT_INTELLIGENCE
- : STAT_DEXTERITY), 1, false );
+ : STAT_DEXTERITY), 1, false,
+ "level gain");
}
break;
@@ -2577,12 +2820,12 @@ void level_change(bool skip_ability_increase)
mp_adjust--;
if (!(you.experience_level % 4))
- modify_stat(STAT_STRENGTH, 1, false);
+ modify_stat(STAT_STRENGTH, 1, false, "level gain");
break;
case SP_HALFLING:
if (!(you.experience_level % 5))
- modify_stat(STAT_DEXTERITY, 1, false);
+ modify_stat(STAT_DEXTERITY, 1, false, "level gain");
if (you.experience_level < 17)
hp_adjust--;
@@ -2595,7 +2838,8 @@ void level_change(bool skip_ability_increase)
if (!(you.experience_level % 5))
{
modify_stat( (coinflip() ? STAT_STRENGTH
- : STAT_DEXTERITY), 1, false );
+ : STAT_DEXTERITY), 1, false,
+ "level gain");
}
if (you.experience_level < 17)
@@ -2617,7 +2861,7 @@ void level_change(bool skip_ability_increase)
mp_adjust--;
if (!(you.experience_level % 5))
- modify_stat(STAT_STRENGTH, 1, false);
+ modify_stat(STAT_STRENGTH, 1, false, "level gain");
break;
case SP_MUMMY:
@@ -2653,7 +2897,7 @@ void level_change(bool skip_ability_increase)
hp_adjust++;
if (!(you.experience_level % 4))
- modify_stat(STAT_RANDOM, 1, false);
+ modify_stat(STAT_RANDOM, 1, false, "level gain");
if (!(you.experience_level % 3))
{
@@ -2672,7 +2916,8 @@ void level_change(bool skip_ability_increase)
if (!(you.experience_level % 4))
{
modify_stat( (coinflip() ? STAT_INTELLIGENCE
- : STAT_DEXTERITY), 1, false );
+ : STAT_DEXTERITY), 1, false,
+ "level gain");
}
break;
@@ -2691,7 +2936,7 @@ void level_change(bool skip_ability_increase)
mp_adjust--;
if (!(you.experience_level % 3))
- modify_stat(STAT_STRENGTH, 1, false);
+ modify_stat(STAT_STRENGTH, 1, false, "level gain");
break;
case SP_OGRE_MAGE:
@@ -2704,7 +2949,8 @@ void level_change(bool skip_ability_increase)
if (!(you.experience_level % 5))
{
modify_stat( (coinflip() ? STAT_INTELLIGENCE
- : STAT_STRENGTH), 1, false );
+ : STAT_STRENGTH), 1, false,
+ "level gain");
}
break;
@@ -2792,7 +3038,7 @@ void level_change(bool skip_ability_increase)
{
mpr("Your scales feel tougher.", MSGCH_INTRINSIC_GAIN);
you.redraw_armour_class = 1;
- modify_stat(STAT_RANDOM, 1, false);
+ modify_stat(STAT_RANDOM, 1, false, "level gain");
}
break;
@@ -2820,7 +3066,7 @@ void level_change(bool skip_ability_increase)
if ((you.experience_level > 7 && !(you.experience_level % 3))
|| you.experience_level == 4 || you.experience_level == 7)
{
- modify_stat(STAT_RANDOM, 1, false);
+ modify_stat(STAT_RANDOM, 1, false, "level gain");
}
break;
@@ -2828,7 +3074,8 @@ void level_change(bool skip_ability_increase)
if (!(you.experience_level % 4))
{
modify_stat( (coinflip() ? STAT_DEXTERITY
- : STAT_STRENGTH), 1, false );
+ : STAT_STRENGTH), 1, false,
+ "level gain");
}
// lowered because of HD raise -- bwr
@@ -2844,7 +3091,7 @@ void level_change(bool skip_ability_increase)
case SP_DEMIGOD:
if (!(you.experience_level % 2))
- modify_stat(STAT_RANDOM, 1, false);
+ modify_stat(STAT_RANDOM, 1, false, "level gain");
// lowered because of HD raise -- bwr
// if (you.experience_level < 17)
@@ -2869,7 +3116,8 @@ void level_change(bool skip_ability_increase)
if (!(you.experience_level % 5))
{
modify_stat( (coinflip() ? STAT_INTELLIGENCE
- : STAT_DEXTERITY), 1, false );
+ : STAT_DEXTERITY), 1, false,
+ "level gain");
}
break;
@@ -2887,7 +3135,8 @@ void level_change(bool skip_ability_increase)
if (!(you.experience_level % 4))
{
modify_stat( (coinflip() ? STAT_DEXTERITY
- : STAT_STRENGTH), 1, false );
+ : STAT_STRENGTH), 1, false,
+ "level gain");
}
break;
@@ -2938,7 +3187,7 @@ void level_change(bool skip_ability_increase)
}
if (!(you.experience_level % 4))
- modify_stat(STAT_RANDOM, 1, false);
+ modify_stat(STAT_RANDOM, 1, false, "level gain");
break;
case SP_GHOUL:
@@ -2953,7 +3202,7 @@ void level_change(bool skip_ability_increase)
mp_adjust--;
if (!(you.experience_level % 5))
- modify_stat(STAT_STRENGTH, 1, false);
+ modify_stat(STAT_STRENGTH, 1, false, "level gain");
break;
case SP_KENKU:
@@ -2964,10 +3213,13 @@ void level_change(bool skip_ability_increase)
hp_adjust--;
if (!(you.experience_level % 4))
- modify_stat(STAT_RANDOM, 1, false);
+ modify_stat(STAT_RANDOM, 1, false, "level gain");
if (you.experience_level == 5)
- mpr("You have gained the ability to fly.", MSGCH_INTRINSIC_GAIN);
+ {
+ 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);
@@ -2984,7 +3236,7 @@ void level_change(bool skip_ability_increase)
hp_adjust++;
if (!(you.experience_level % 5))
- modify_stat(STAT_RANDOM, 1, false);
+ modify_stat(STAT_RANDOM, 1, false, "level gain");
break;
default:
@@ -3001,7 +3253,6 @@ void level_change(bool skip_ability_increase)
if (you.magic_points < 0)
you.magic_points = 0;
- if (Options.use_notes)
{
unwind_var<int> hpmax(you.hp_max);
unwind_var<int> hp(you.hp);
@@ -3017,6 +3268,7 @@ void level_change(bool skip_ability_increase)
you.hp, you.hp_max, you.magic_points, you.max_magic_points);
take_note(Note(NOTE_XP_LEVEL_CHANGE, you.experience_level, 0, buf));
}
+
// recalculate for game
calc_hp();
calc_mp();
@@ -3128,7 +3380,12 @@ int check_stealth(void)
stealth /= 2; // splashy-splashy
}
else
- stealth -= you.mutation[MUT_HOOVES] * 10; // clippety-clop
+ {
+ if (you.mutation[MUT_HOOVES])
+ stealth -= 10; // clippety-clop
+ else if (you.mutation[MUT_PAWS])
+ stealth += 10;
+ }
// Radiating silence is the negative complement of shouting all the
// time... a sudden change from background noise to no noise is going
@@ -3163,17 +3420,17 @@ static void ability_increase()
{
case 's':
case 'S':
- modify_stat(STAT_STRENGTH, 1, false);
+ modify_stat(STAT_STRENGTH, 1, false, "level gain");
return;
case 'i':
case 'I':
- modify_stat(STAT_INTELLIGENCE, 1, false);
+ modify_stat(STAT_INTELLIGENCE, 1, false, "level gain");
return;
case 'd':
case 'D':
- modify_stat(STAT_DEXTERITY, 1, false);
+ modify_stat(STAT_DEXTERITY, 1, false, "level gain");
return;
}
}
@@ -3295,9 +3552,15 @@ void display_char_status()
if (you.duration[DUR_CONF])
mpr( "You are confused." );
+ if (you.duration[DUR_BEHELD])
+ mpr( "You are beheld." );
+
+ // how exactly did you get to show the status?
if (you.duration[DUR_PARALYSIS])
mpr( "You are paralysed." );
-
+ if (you.duration[DUR_SLEEP])
+ mpr( "You are asleep." );
+
if (you.duration[DUR_EXHAUSTED])
mpr( "You are exhausted." );
@@ -3372,8 +3635,6 @@ void display_char_status()
}
int move_cost = (player_speed() * player_movement_speed()) / 10;
- if ( you.duration[DUR_SLOW] )
- move_cost *= 2;
const bool water = player_in_water();
const bool swim = player_is_swimming();
@@ -3849,7 +4110,7 @@ int slaying_bonus(char which_affected)
// Checks each equip slot for an evokable item (jewellery or randart).
// Returns true if any of these has the same ability as the one handed in.
-bool items_give_ability(const int slot, char abil)
+bool items_give_ability(const int slot, randart_prop_type abil)
{
for (int i = EQ_WEAPON; i < NUM_EQUIP; i++)
{
@@ -3891,11 +4152,11 @@ bool items_give_ability(const int slot, char abil)
// none of the equipped items possesses this ability
return (false);
-} // end scan_randarts()
+} // end items_give_ability()
/* 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, bool calc_unid)
+int scan_randarts(randart_prop_type which_property, bool calc_unid)
{
int i = 0;
int retval = 0;
@@ -3925,12 +4186,14 @@ int scan_randarts(char which_property, bool calc_unid)
return (retval);
} // end scan_randarts()
-void modify_stat(stat_type which_stat, char amount, bool suppress_msg)
+void modify_stat(stat_type which_stat, char amount, bool suppress_msg,
+ const char *cause, bool see_source)
{
char *ptr_stat = NULL;
char *ptr_stat_max = NULL;
bool *ptr_redraw = NULL;
+ kill_method_type kill_type = NUM_KILLBY;
// sanity - is non-zero amount?
if (amount == 0)
@@ -3948,23 +4211,26 @@ void modify_stat(stat_type which_stat, char amount, bool suppress_msg)
switch (which_stat)
{
case STAT_STRENGTH:
- ptr_stat = &you.strength;
+ ptr_stat = &you.strength;
ptr_stat_max = &you.max_strength;
- ptr_redraw = &you.redraw_strength;
+ ptr_redraw = &you.redraw_strength;
+ kill_type = KILLED_BY_WEAKNESS;
msg += ((amount > 0) ? "stronger." : "weaker.");
break;
case STAT_DEXTERITY:
- ptr_stat = &you.dex;
+ ptr_stat = &you.dex;
ptr_stat_max = &you.max_dex;
- ptr_redraw = &you.redraw_dexterity;
+ ptr_redraw = &you.redraw_dexterity;
+ kill_type = KILLED_BY_CLUMSINESS;
msg += ((amount > 0) ? "agile." : "clumsy.");
break;
case STAT_INTELLIGENCE:
- ptr_stat = &you.intel;
+ ptr_stat = &you.intel;
ptr_stat_max = &you.max_intel;
- ptr_redraw = &you.redraw_intelligence;
+ ptr_redraw = &you.redraw_intelligence;
+ kill_type = KILLED_BY_STUPIDITY;
msg += ((amount > 0) ? "clever." : "stupid.");
break;
@@ -3975,9 +4241,17 @@ void modify_stat(stat_type which_stat, char amount, bool suppress_msg)
if (!suppress_msg && amount != 0)
mpr( msg.c_str(), (amount > 0) ? MSGCH_INTRINSIC_GAIN : MSGCH_WARN );
- *ptr_stat += amount;
+ *ptr_stat += amount;
*ptr_stat_max += amount;
- *ptr_redraw = 1;
+ *ptr_redraw = 1;
+
+ if (amount < 0 && *ptr_stat < 1)
+ {
+ if (cause == NULL)
+ ouch(INSTANT_DEATH, 0, kill_type);
+ else
+ ouch(INSTANT_DEATH, 0, kill_type, cause, see_source);
+ }
if (ptr_stat == &you.strength)
burden_change();
@@ -3985,6 +4259,68 @@ void modify_stat(stat_type which_stat, char amount, bool suppress_msg)
return;
} // end modify_stat()
+void modify_stat(stat_type which_stat, char amount, bool suppress_msg,
+ const std::string& cause, bool see_source)
+{
+ modify_stat(which_stat, amount, suppress_msg, cause.c_str(), see_source);
+}
+
+void modify_stat(stat_type which_stat, char amount, bool suppress_msg,
+ const monsters* cause)
+{
+ if (cause == NULL || invalid_monster(cause))
+ {
+ modify_stat(which_stat, amount, suppress_msg, NULL, true);
+ return;
+ }
+
+ bool vis = mons_near(cause) && player_monster_visible(cause);
+ std::string name = cause->name(DESC_NOCAP_A, true);
+
+ if (cause->has_ench(ENCH_SHAPESHIFTER))
+ name += " (shapeshifter)";
+ else if (cause->has_ench(ENCH_GLOWING_SHAPESHIFTER))
+ name += " (glowing shapeshifter)";
+
+ modify_stat(which_stat, amount, suppress_msg, name, vis);
+}
+
+void modify_stat(stat_type which_stat, char amount, bool suppress_msg,
+ const item_def &cause, bool removed)
+{
+ std::string name = cause.name(DESC_NOCAP_THE, false, true, false, false,
+ ISFLAG_KNOW_CURSE | ISFLAG_KNOW_PLUSES);
+ std::string verb;
+
+ switch(cause.base_type)
+ {
+ case OBJ_ARMOUR:
+ case OBJ_JEWELLERY:
+ if (removed)
+ verb = "removing";
+ else
+ verb = "wearing";
+ break;
+
+ case OBJ_WEAPONS:
+ case OBJ_STAVES:
+ if (removed)
+ verb = "unwielding";
+ else
+ verb = "wielding";
+ break;
+
+ case OBJ_WANDS: verb = "zapping"; break;
+ case OBJ_FOOD: verb = "eating"; break;
+ case OBJ_SCROLLS: verb = "reading"; break;
+ case OBJ_POTIONS: verb = "drinking"; break;
+ default: verb = "using";
+ }
+
+ modify_stat(which_stat, amount, suppress_msg,
+ verb + " " + name, true);
+}
+
void dec_hp(int hp_loss, bool fatal, const char *aux)
{
if (!fatal && you.hp < 1)
@@ -4040,6 +4376,8 @@ bool enough_hp(int minimum, bool suppress_msg)
if (!suppress_msg)
mpr("You haven't enough vitality at the moment.");
+ crawl_state.cancel_cmd_again();
+ crawl_state.cancel_cmd_repeat();
return false;
}
@@ -4053,6 +4391,8 @@ bool enough_mp(int minimum, bool suppress_msg)
if (!suppress_msg)
mpr("You haven't enough magic at the moment.");
+ crawl_state.cancel_cmd_again();
+ crawl_state.cancel_cmd_repeat();
return false;
}
@@ -4066,6 +4406,8 @@ void inc_mp(int mp_gain, bool max_too)
if (mp_gain < 1)
return;
+ bool wasnt_max = (you.magic_points < you.max_magic_points);
+
you.magic_points += mp_gain;
if (max_too)
@@ -4074,6 +4416,9 @@ void inc_mp(int mp_gain, bool max_too)
if (you.magic_points > you.max_magic_points)
you.magic_points = you.max_magic_points;
+ if (wasnt_max && you.magic_points == you.max_magic_points)
+ interrupt_activity(AI_FULL_MP);
+
take_note(Note(NOTE_MP_CHANGE, you.magic_points, you.max_magic_points));
you.redraw_magic_points = 1;
@@ -4087,6 +4432,8 @@ void inc_hp(int hp_gain, bool max_too)
if (hp_gain < 1)
return;
+ bool wasnt_max = (you.hp < you.hp_max);
+
you.hp += hp_gain;
if (max_too)
@@ -4095,6 +4442,9 @@ void inc_hp(int hp_gain, bool max_too)
if (you.hp > you.hp_max)
you.hp = you.hp_max;
+ if (wasnt_max && you.hp == you.hp_max)
+ interrupt_activity(AI_FULL_HP);
+
// to avoid message spam, no information when HP increases
// take_note(Note(NOTE_HP_CHANGE, you.hp, you.hp_max));
@@ -4499,6 +4849,7 @@ bool confuse_player( int amount, bool resistable )
if (you.duration[DUR_CONF] > old_value)
{
// XXX: which message channel for this message?
+ you.check_awaken(500);
mprf("You are %sconfused.", (old_value > 0) ? "more " : "" );
learned_something_new(TUT_YOU_ENCHANTED);
@@ -4790,6 +5141,40 @@ actor::~actor()
{
}
+bool actor::will_trigger_shaft() const
+{
+ return (!airborne() && total_weight() > 0 && is_valid_shaft_level());
+}
+
+level_id actor::shaft_dest() const
+{
+ if (you.level_type != LEVEL_DUNGEON)
+ return level_id::current();
+
+ level_id lev = level_id::current();
+ int curr_depth = subdungeon_depth(you.where_are_you, you.your_level);
+
+ lev.depth += ((pos().x + pos().y) % 3) + 1;
+
+ if (lev.depth > your_branch().depth)
+ lev.depth = your_branch().depth;
+
+ if (lev.depth == curr_depth)
+ return lev;
+
+ // Only shafts on the level immediately above a dangerous branch
+ // bottom will take you to that dangerous bottom, and shafts can't
+ // be created during level generation time.
+ if (your_branch().dangerous_bottom_level
+ && lev.depth == your_branch().depth
+ && (your_branch().depth - curr_depth) > 1)
+ {
+ lev.depth--;
+ }
+
+ return lev;
+}
+
bool actor::airborne() const
{
return (is_levitating() || (flight_mode() == FL_FLY && !paralysed()));
@@ -4894,12 +5279,16 @@ void player::init()
your_level = 0;
level_type = LEVEL_DUNGEON;
- where_are_you = BRANCH_MAIN_DUNGEON;
+ entry_cause = EC_SELF_EXPLICIT;
+ entry_cause_god = GOD_NO_GOD;
+ where_are_you = BRANCH_MAIN_DUNGEON;
char_direction = GDT_DESCENDING;
prev_targ = MHITNOT;
pet_target = MHITNOT;
+ prev_grd_targ = coord_def(0, 0);
+
x_pos = 0;
y_pos = 0;
@@ -5028,14 +5417,12 @@ coord_def player::pos() const
bool player::is_levitating() const
{
- return (attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON ||
- attribute[ATTR_TRANSFORMATION] == TRAN_BAT ||
- duration[DUR_LEVITATION]);
+ return (duration[DUR_LEVITATION]);
}
bool player::in_water() const
{
- return (!player_is_airborne() && !beogh_water_walk()
+ return (!airborne() && !beogh_water_walk()
&& grid_is_water(grd[you.x_pos][you.y_pos]));
}
@@ -5070,6 +5457,21 @@ bool player::floundering() const
return in_water() && !can_swim();
}
+bool player::can_pass_through(const dungeon_feature_type grid) const
+{
+ return !grid_is_solid(grid);
+}
+
+bool player::can_pass_through(const int _x, const int _y) const
+{
+ return can_pass_through(grd[_x][_y]);
+}
+
+bool player::can_pass_through(const coord_def &c) const
+{
+ return can_pass_through(grd(c));
+}
+
size_type player::body_size(int psize, bool base) const
{
size_type ret = (base) ? SIZE_CHARACTER : transform_size( psize );
@@ -5116,11 +5518,72 @@ size_type player::body_size(int psize, bool base) const
return (ret);
}
+int player::body_weight() const
+{
+ if (attribute[ATTR_TRANSFORMATION] == TRAN_AIR)
+ return 0;
+
+ int weight = 0;
+ switch(body_size(PSIZE_BODY))
+ {
+ case SIZE_TINY:
+ weight = 150;
+ break;
+ case SIZE_LITTLE:
+ weight = 300;
+ break;
+ case SIZE_SMALL:
+ weight = 425;
+ break;
+ case SIZE_MEDIUM:
+ weight = 550;
+ break;
+ case SIZE_LARGE:
+ weight = 1300;
+ break;
+ case SIZE_BIG:
+ weight = 1500;
+ break;
+ case SIZE_GIANT:
+ weight = 1800;
+ break;
+ case SIZE_HUGE:
+ weight = 2200;
+ break;
+ default:
+ mpr("ERROR: invalid player body weight");
+ perror("player::body_weight(): invalid player body weight");
+ end(0);
+ }
+
+ switch(attribute[ATTR_TRANSFORMATION])
+ {
+ case TRAN_STATUE:
+ weight *= 2;
+ break;
+ case TRAN_LICH:
+ weight /= 2;
+ break;
+ default:
+ break;
+ }
+
+ return (weight);
+}
+
+int player::total_weight() const
+{
+ return (body_weight() + burden);
+}
+
bool player::cannot_speak() const
{
if (silenced(x_pos, y_pos))
return (true);
+ if (you.duration[DUR_PARALYSIS]) // we allow talking during sleep ;)
+ return (true);
+
// No transform that prevents the player from speaking yet.
return (false);
}
@@ -5131,11 +5594,21 @@ std::string player::shout_verb() const
switch (transform)
{
case TRAN_DRAGON:
+ case TRAN_SERPENT_OF_HELL:
return "roar";
case TRAN_SPIDER:
return "hiss";
- default:
- return "yell";
+ case TRAN_BAT:
+ return "squeak";
+ case TRAN_AIR:
+ return "__NONE";
+ default: // depends on SCREAM mutation
+ if (you.mutation[MUT_SCREAM] <= 1)
+ return "shout";
+ else if (you.mutation[MUT_SCREAM] == 2)
+ return "yell";
+ else
+ return "scream";
}
}
@@ -5288,7 +5761,7 @@ void player::attacking(actor *other)
{
const monsters *mons = dynamic_cast<monsters*>(other);
if (mons_friendly(mons))
- did_god_conduct(DID_ATTACK_FRIEND, 5, mons);
+ did_god_conduct(DID_ATTACK_FRIEND, 5, true, mons);
else
pet_target = monster_index(mons);
}
@@ -5498,14 +5971,34 @@ int player::res_negative_energy() const
return (player_prot_life());
}
+bool player::confusable() const
+{
+ return (player_mental_clarity() == 0);
+}
+
+bool player::slowable() const
+{
+ return (!wearing_amulet(AMU_RESIST_SLOW));
+}
+
+bool player::omnivorous() const
+{
+ return (species == SP_TROLL || species == SP_OGRE);
+}
+
flight_type player::flight_mode() const
{
- if ( !is_levitating() )
- return (FL_NONE);
- else
+ if (attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON ||
+ attribute[ATTR_TRANSFORMATION] == TRAN_BAT)
+ {
+ return FL_FLY;
+ }
+ else if (is_levitating())
return (you.duration[DUR_CONTROLLED_FLIGHT]
|| wearing_amulet(AMU_CONTROLLED_FLIGHT)
? FL_FLY : FL_LEVITATE);
+ else
+ return (FL_NONE);
}
bool player::light_flight() const
@@ -5573,9 +6066,16 @@ void player::hurt(const actor *agent, int amount)
}
}
-void player::drain_stat(int stat, int amount)
+void player::drain_stat(int stat, int amount, actor* attacker)
{
- lose_stat(stat, amount);
+ if (attacker == NULL)
+ lose_stat(stat, amount, false, "");
+ else if (attacker->atype() == ACT_MONSTER)
+ lose_stat(stat, amount, dynamic_cast<monsters*>(attacker), false);
+ else if (attacker->atype() == ACT_PLAYER)
+ lose_stat(stat, amount, false, "suicide");
+ else
+ lose_stat(stat, amount, false, "");
}
void player::rot(actor *who, int rotlevel, int immed_rot)
@@ -5615,28 +6115,36 @@ void player::slow_down(int str)
::slow_player( str );
}
-bool player::has_claws() const
+int player::has_claws(bool allow_tran) const
{
- // these transformations bring claws with them
- if (attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON
- || attribute[ATTR_TRANSFORMATION] == TRAN_SERPENT_OF_HELL)
+ if (allow_tran)
{
- return true;
+ // these transformations bring claws with them
+ if (attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON
+ || attribute[ATTR_TRANSFORMATION] == TRAN_SERPENT_OF_HELL)
+ {
+ return 3;
+ }
+
+ // transformations other than these will override claws
+ if (attribute[ATTR_TRANSFORMATION] != TRAN_NONE
+ && attribute[ATTR_TRANSFORMATION] != TRAN_STATUE
+ && attribute[ATTR_TRANSFORMATION] != TRAN_LICH)
+ {
+ return 0;
+ }
}
// these are the only other sources for claws
- if (species != SP_TROLL && species != SP_GHOUL && !mutation[MUT_CLAWS])
- return false;
-
- // transformations other than these will override claws
- return ( attribute[ATTR_TRANSFORMATION] == TRAN_NONE
- || attribute[ATTR_TRANSFORMATION] == TRAN_STATUE
- || attribute[ATTR_TRANSFORMATION] == TRAN_LICH );
+ if (species == SP_TROLL || species == SP_GHOUL)
+ return 3;
+ else
+ return mutation[MUT_CLAWS];
}
-bool player::has_usable_claws() const
+bool player::has_usable_claws(bool allow_tran) const
{
- return (equip[EQ_GLOVES] == -1 && has_claws());
+ return (equip[EQ_GLOVES] == -1 && has_claws(allow_tran));
}
god_type player::deity() const
@@ -5725,12 +6233,55 @@ void player::moveto(const coord_def &c)
dungeon_events.fire_position_event(DET_PLAYER_MOVED, c);
}
+bool player::asleep() const
+{
+ return (duration[DUR_SLEEP] > 0);
+}
+
+bool player::cannot_act() const
+{
+ return (asleep() || paralysed());
+}
+
bool player::can_throw_rocks() const
{
return (species == SP_OGRE || species == SP_TROLL
|| species == SP_OGRE_MAGE);
}
+void player::put_to_sleep(int)
+{
+ if (duration[DUR_BERSERKER] || asleep()) // No cumulative sleeps.
+ return;
+
+ // Not all species can be put to sleep. Check holiness.
+ const mon_holy_type holy = holiness();
+ if (holy == MH_UNDEAD || holy == MH_NONLIVING)
+ return;
+
+ mpr("You fall asleep.");
+ stop_delay();
+ you.flash_colour = DARKGREY;
+ viewwindow(true, false);
+
+ // Do this *after* redrawing the view, or viewwindow() will no-op.
+ duration[DUR_SLEEP] = 3 + random2avg(5, 2);
+}
+
+void player::awake()
+{
+ duration[DUR_SLEEP] = 0;
+ mpr("You wake up.");
+ you.flash_colour = BLACK;
+ viewwindow(true, false);
+}
+
+void player::check_awaken(int disturbance)
+{
+ if (asleep() && random2(50) <= disturbance)
+ awake();
+}
+
////////////////////////////////////////////////////////////////////////////
PlaceInfo::PlaceInfo()
@@ -5881,7 +6432,6 @@ PlaceInfo PlaceInfo::operator - (const PlaceInfo &other) const
return copy;
}
-
PlaceInfo& player::get_place_info() const
{
return get_place_info(where_are_you, level_type);
@@ -5945,3 +6495,43 @@ std::vector<PlaceInfo> player::get_all_place_info(bool visited_only,
return list;
}
+
+bool player::do_shaft()
+{
+ dungeon_feature_type force_stair = DNGN_UNSEEN;
+
+ if (!is_valid_shaft_level())
+ return (false);
+
+ // Handle instances of do_shaft() being invoked magically when
+ // the player isn't standing over a shaft.
+ if (trap_type_at_xy(x_pos, y_pos) != TRAP_SHAFT)
+ {
+ switch(grd[x_pos][y_pos])
+ {
+ case DNGN_FLOOR:
+ case DNGN_OPEN_DOOR:
+ case DNGN_TRAP_MECHANICAL:
+ case DNGN_TRAP_MAGICAL:
+ case DNGN_TRAP_NATURAL:
+ case DNGN_UNDISCOVERED_TRAP:
+ case DNGN_ENTER_SHOP:
+ break;
+
+ default:
+ return (false);
+ }
+
+ if (airborne() || total_weight() == 0)
+ {
+ mpr("A shaft briefly opens up underneath you!");
+ return (true);
+ }
+
+ force_stair = DNGN_TRAP_NATURAL;
+ }
+
+ down_stairs(your_level, force_stair);
+
+ return (true);
+}
diff --git a/crawl-ref/source/player.h b/crawl-ref/source/player.h
index 691532df5f..a012a4b470 100644
--- a/crawl-ref/source/player.h
+++ b/crawl-ref/source/player.h
@@ -16,6 +16,9 @@
#include "externs.h"
+class monsters;
+class item_def;
+
enum genus_type
{
GENPC_DRACONIAN, // 0
@@ -242,8 +245,8 @@ int player_teleport(bool calc_unid = true);
/* ***********************************************************************
* called from: ability - acr - items - misc - spells1 - spells3
* *********************************************************************** */
-bool items_give_ability(const int slot, char abil);
-int scan_randarts(char which_property, bool calc_unid = true);
+bool items_give_ability(const int slot, randart_prop_type abil);
+int scan_randarts(randart_prop_type which_property, bool calc_unid = true);
/* ***********************************************************************
@@ -260,6 +263,9 @@ int slaying_bonus(char which_affected);
int player_see_invis(bool calc_unid = true);
bool player_monster_visible( const monsters *mon );
+bool player_beheld_by( const monsters *mon );
+void update_beholders( const monsters *mon, bool force = false);
+void check_beholders();
/* ***********************************************************************
* called from: acr - decks - it_use2 - ouch
@@ -276,7 +282,7 @@ void display_char_status(void);
/* ***********************************************************************
* called from: item_use - items - misc - spells - spells3
* *********************************************************************** */
-void forget_map(unsigned char chance_forgotten);
+void forget_map(unsigned char chance_forgotten = 100, bool force = false);
// last updated 19may2000 {dlb}
@@ -291,7 +297,14 @@ void gain_exp(unsigned int exp_gained, unsigned int* actual_gain = NULL,
* called from: acr - it_use2 - item_use - mutation - transfor - player -
* misc - stuff
* *********************************************************************** */
-void modify_stat(stat_type which_stat, char amount, bool suppress_msg);
+void modify_stat(stat_type which_stat, char amount, bool suppress_msg,
+ const std::string& cause, bool see_source = true);
+void modify_stat(stat_type which_stat, char amount, bool suppress_msg,
+ const char* cause, bool see_source = true);
+void modify_stat(stat_type which_stat, char amount, bool suppress_msg,
+ const monsters* cause);
+void modify_stat(stat_type which_stat, char amount, bool suppress_msg,
+ const item_def &cause, bool removed = false);
// last updated 19may2000 {dlb}
@@ -313,8 +326,10 @@ void redraw_skill(const std::string &your_name, const std::string &class_name);
* *********************************************************************** */
bool player_genus( genus_type which_genus,
species_type species = SP_UNKNOWN );
+bool is_player_same_species( const int mon );
bool you_can_wear( int eq, bool special_armour = false );
+bool player_has_feet(void);
bool you_tran_can_wear( int eq, bool check_mutation = false );
/* ***********************************************************************
diff --git a/crawl-ref/source/prebuilt/levcomp.lex.cc b/crawl-ref/source/prebuilt/levcomp.lex.cc
index 59b63daaf5..92fb87ae33 100644
--- a/crawl-ref/source/prebuilt/levcomp.lex.cc
+++ b/crawl-ref/source/prebuilt/levcomp.lex.cc
@@ -1,94 +1,33 @@
#line 2 "levcomp.lex.cc"
-
-#line 4 "levcomp.lex.cc"
-
-#define YY_INT_ALIGNED short int
-
/* A lexical scanner generated by flex */
+/* Scanner skeleton version:
+ * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $
+ */
+
#define FLEX_SCANNER
#define YY_FLEX_MAJOR_VERSION 2
#define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 33
-#if YY_FLEX_SUBMINOR_VERSION > 0
-#define FLEX_BETA
-#endif
-
-/* First, we deal with platform-specific or compiler-specific issues. */
-/* begin standard C headers. */
#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-
-/* end standard C headers. */
-/* flex integer type definitions */
-
-#ifndef FLEXINT_H
-#define FLEXINT_H
-
-/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
-
-#if __STDC_VERSION__ >= 199901L
-
-/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
- * if you want the limit (max/min) macros for int types.
- */
-#ifndef __STDC_LIMIT_MACROS
-#define __STDC_LIMIT_MACROS 1
-#endif
-
-#include <inttypes.h>
-typedef int8_t flex_int8_t;
-typedef uint8_t flex_uint8_t;
-typedef int16_t flex_int16_t;
-typedef uint16_t flex_uint16_t;
-typedef int32_t flex_int32_t;
-typedef uint32_t flex_uint32_t;
-#else
-typedef signed char flex_int8_t;
-typedef short int flex_int16_t;
-typedef int flex_int32_t;
-typedef unsigned char flex_uint8_t;
-typedef unsigned short int flex_uint16_t;
-typedef unsigned int flex_uint32_t;
-#endif /* ! C99 */
-/* Limits of integral types. */
-#ifndef INT8_MIN
-#define INT8_MIN (-128)
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
#endif
-#ifndef INT16_MIN
-#define INT16_MIN (-32767-1)
-#endif
-#ifndef INT32_MIN
-#define INT32_MIN (-2147483647-1)
-#endif
-#ifndef INT8_MAX
-#define INT8_MAX (127)
-#endif
-#ifndef INT16_MAX
-#define INT16_MAX (32767)
-#endif
-#ifndef INT32_MAX
-#define INT32_MAX (2147483647)
-#endif
-#ifndef UINT8_MAX
-#define UINT8_MAX (255U)
-#endif
-#ifndef UINT16_MAX
-#define UINT16_MAX (65535U)
-#endif
-#ifndef UINT32_MAX
-#define UINT32_MAX (4294967295U)
#endif
-#endif /* ! FLEXINT_H */
#ifdef __cplusplus
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
/* The "const" storage-class-modifier is valid. */
#define YY_USE_CONST
@@ -96,17 +35,34 @@ typedef unsigned int flex_uint32_t;
#if __STDC__
+#define YY_USE_PROTOS
#define YY_USE_CONST
#endif /* __STDC__ */
#endif /* ! __cplusplus */
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
#ifdef YY_USE_CONST
#define yyconst const
#else
#define yyconst
#endif
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
/* Returned upon end-of-file. */
#define YY_NULL 0
@@ -121,88 +77,71 @@ typedef unsigned int flex_uint32_t;
* but we do it the disgusting crufty way forced on us by the ()-less
* definition of BEGIN.
*/
-#define BEGIN (yy_start) = 1 + 2 *
+#define BEGIN yy_start = 1 + 2 *
/* Translate the current start state into a value that can be later handed
* to BEGIN to return to the state. The YYSTATE alias is for lex
* compatibility.
*/
-#define YY_START (((yy_start) - 1) / 2)
+#define YY_START ((yy_start - 1) / 2)
#define YYSTATE YY_START
/* Action number for EOF rule of a given start state. */
#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
/* Special action meaning "start processing a new file". */
-#define YY_NEW_FILE yyrestart(yyin )
+#define YY_NEW_FILE yyrestart( yyin )
#define YY_END_OF_BUFFER_CHAR 0
/* Size of default input buffer. */
-#ifndef YY_BUF_SIZE
#define YY_BUF_SIZE 16384
-#endif
-/* The state buf must be large enough to hold one state per character in the main buffer.
- */
-#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
-
-#ifndef YY_TYPEDEF_YY_BUFFER_STATE
-#define YY_TYPEDEF_YY_BUFFER_STATE
typedef struct yy_buffer_state *YY_BUFFER_STATE;
-#endif
extern int yyleng;
-
extern FILE *yyin, *yyout;
#define EOB_ACT_CONTINUE_SCAN 0
#define EOB_ACT_END_OF_FILE 1
#define EOB_ACT_LAST_MATCH 2
- /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires
- * access to the local variable yy_act. Since yyless() is a macro, it would break
- * existing scanners that call yyless() from OUTSIDE yylex.
- * One obvious solution it to make yy_act a global. I tried that, and saw
- * a 5% performance hit in a non-yylineno scanner, because yy_act is
- * normally declared as a register variable-- so it is not worth it.
- */
- #define YY_LESS_LINENO(n) \
- do { \
- int yyl;\
- for ( yyl = n; yyl < yyleng; ++yyl )\
- if ( yytext[yyl] == '\n' )\
- --yylineno;\
- }while(0)
-
-/* Return all but the first "n" matched characters back to the input stream. */
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator). This
+ * avoids problems with code like:
+ *
+ * if ( condition_holds )
+ * yyless( 5 );
+ * else
+ * do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
#define yyless(n) \
do \
{ \
/* Undo effects of setting up yytext. */ \
- int yyless_macro_arg = (n); \
- YY_LESS_LINENO(yyless_macro_arg);\
- *yy_cp = (yy_hold_char); \
+ *yy_cp = yy_hold_char; \
YY_RESTORE_YY_MORE_OFFSET \
- (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
YY_DO_BEFORE_ACTION; /* set up yytext again */ \
} \
while ( 0 )
-#define unput(c) yyunput( c, (yytext_ptr) )
+#define unput(c) yyunput( c, yytext_ptr )
/* The following is because we cannot portably get our hands on size_t
* (without autoconf's help, which isn't available because we want
* flex-generated scanners to compile on their own).
*/
-
-#ifndef YY_TYPEDEF_YY_SIZE_T
-#define YY_TYPEDEF_YY_SIZE_T
typedef unsigned int yy_size_t;
-#endif
-#ifndef YY_STRUCT_YY_BUFFER_STATE
-#define YY_STRUCT_YY_BUFFER_STATE
+
struct yy_buffer_state
{
FILE *yy_input_file;
@@ -239,16 +178,12 @@ struct yy_buffer_state
*/
int yy_at_bol;
- int yy_bs_lineno; /**< The line count. */
- int yy_bs_column; /**< The column count. */
-
/* Whether to try to fill the input buffer when we reach the
* end of it.
*/
int yy_fill_buffer;
int yy_buffer_status;
-
#define YY_BUFFER_NEW 0
#define YY_BUFFER_NORMAL 1
/* When an EOF's been seen but there's still some text to process
@@ -262,38 +197,28 @@ struct yy_buffer_state
* just pointing yyin at a new input file.
*/
#define YY_BUFFER_EOF_PENDING 2
-
};
-#endif /* !YY_STRUCT_YY_BUFFER_STATE */
-/* Stack of input buffers. */
-static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
-static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
-static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+static YY_BUFFER_STATE yy_current_buffer = 0;
/* We provide macros for accessing buffer states in case in the
* future we want to put the buffer states in a more general
* "scanner state".
- *
- * Returns the top of the stack, or NULL.
*/
-#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
- ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
- : NULL)
+#define YY_CURRENT_BUFFER yy_current_buffer
-/* Same as previous macro, but useful when we know that the buffer stack is not
- * NULL or when we need an lvalue. For internal use only.
- */
-#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
/* yy_hold_char holds the character lost when yytext is formed. */
static char yy_hold_char;
+
static int yy_n_chars; /* number of characters read into yy_ch_buf */
+
+
int yyleng;
/* Points to current character in buffer. */
static char *yy_c_buf_p = (char *) 0;
-static int yy_init = 0; /* whether we need to initialize */
+static int yy_init = 1; /* whether we need to initialize */
static int yy_start = 0; /* start state number */
/* Flag which is used to allow yywrap()'s to do buffer switches
@@ -301,185 +226,291 @@ static int yy_start = 0; /* start state number */
*/
static int yy_did_buffer_switch_on_eof;
-void yyrestart (FILE *input_file );
-void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer );
-YY_BUFFER_STATE yy_create_buffer (FILE *file,int size );
-void yy_delete_buffer (YY_BUFFER_STATE b );
-void yy_flush_buffer (YY_BUFFER_STATE b );
-void yypush_buffer_state (YY_BUFFER_STATE new_buffer );
-void yypop_buffer_state (void );
+void yyrestart YY_PROTO(( FILE *input_file ));
-static void yyensure_buffer_stack (void );
-static void yy_load_buffer_state (void );
-static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file );
+void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
+void yy_load_buffer_state YY_PROTO(( void ));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
+void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
+void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
-#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
+YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
+YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
+YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
-YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size );
-YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str );
-YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len );
-
-void *yyalloc (yy_size_t );
-void *yyrealloc (void *,yy_size_t );
-void yyfree (void * );
+static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
+static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
+static void yy_flex_free YY_PROTO(( void * ));
#define yy_new_buffer yy_create_buffer
#define yy_set_interactive(is_interactive) \
{ \
- if ( ! YY_CURRENT_BUFFER ){ \
- yyensure_buffer_stack (); \
- YY_CURRENT_BUFFER_LVALUE = \
- yy_create_buffer(yyin,YY_BUF_SIZE ); \
- } \
- YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ if ( ! yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ yy_current_buffer->yy_is_interactive = is_interactive; \
}
#define yy_set_bol(at_bol) \
{ \
- if ( ! YY_CURRENT_BUFFER ){\
- yyensure_buffer_stack (); \
- YY_CURRENT_BUFFER_LVALUE = \
- yy_create_buffer(yyin,YY_BUF_SIZE ); \
- } \
- YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ if ( ! yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ yy_current_buffer->yy_at_bol = at_bol; \
}
-#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
-/* Begin user sect3 */
+#define YY_USES_REJECT
typedef unsigned char YY_CHAR;
-
FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
-
typedef int yy_state_type;
-
extern int yylineno;
-
int yylineno = 1;
-
extern char *yytext;
#define yytext_ptr yytext
-static yy_state_type yy_get_previous_state (void );
-static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
-static int yy_get_next_buffer (void );
-static void yy_fatal_error (yyconst char msg[] );
+static yy_state_type yy_get_previous_state YY_PROTO(( void ));
+static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
+static int yy_get_next_buffer YY_PROTO(( void ));
+static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
/* Done after the current pattern has been matched and before the
* corresponding action - sets up yytext.
*/
#define YY_DO_BEFORE_ACTION \
- (yytext_ptr) = yy_bp; \
- yyleng = (size_t) (yy_cp - yy_bp); \
- (yy_hold_char) = *yy_cp; \
+ yytext_ptr = yy_bp; \
+ yyleng = (int) (yy_cp - yy_bp); \
+ yy_hold_char = *yy_cp; \
*yy_cp = '\0'; \
- (yy_c_buf_p) = yy_cp;
+ yy_c_buf_p = yy_cp;
-#define YY_NUM_RULES 63
-#define YY_END_OF_BUFFER 64
-/* This struct is not used in this scanner,
- but its presence is necessary. */
-struct yy_trans_info
- {
- flex_int32_t yy_verify;
- flex_int32_t yy_nxt;
- };
-static yyconst flex_int16_t yy_accept[805] =
+#define YY_NUM_RULES 68
+#define YY_END_OF_BUFFER 69
+static yyconst short int yy_acclist[975] =
{ 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 64, 62,
- 60, 61, 62, 58, 59, 62, 62, 62, 62, 62,
- 62, 62, 62, 62, 62, 62, 62, 62, 60, 30,
- 32, 62, 62, 62, 62, 62, 62, 63, 6, 63,
- 63, 4, 2, 3, 63, 2, 2, 2, 2, 9,
- 10, 63, 9, 9, 63, 12, 63, 62, 26, 62,
- 58, 59, 62, 62, 62, 62, 62, 62, 62, 62,
- 62, 62, 62, 62, 62, 30, 32, 62, 62, 62,
- 62, 62, 62, 62, 24, 21, 24, 23, 59, 62,
-
- 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
- 62, 62, 24, 30, 32, 62, 62, 62, 62, 62,
- 62, 14, 15, 62, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 14,
- 13, 13, 13, 13, 13, 17, 19, 20, 63, 18,
- 63, 29, 63, 63, 60, 61, 59, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 60, 30, 32, 0,
- 0, 0, 0, 30, 0, 0, 0, 0, 0, 0,
- 0, 35, 6, 5, 0, 0, 2, 3, 2, 0,
-
- 2, 2, 2, 2, 9, 9, 10, 9, 9, 9,
- 0, 11, 12, 25, 0, 26, 25, 25, 25, 25,
+ 69, 67, 68, 65, 67, 68, 66, 68, 67, 68,
+ 63, 67, 68, 64, 67, 68, 67, 68, 67, 68,
+ 67, 68, 67, 68, 67, 68, 67, 68, 67, 68,
+ 67, 68, 67, 68, 67, 68, 67, 68, 67, 68,
+ 67, 68, 67, 68, 67, 68, 67, 68, 65, 67,
+ 68, 30, 67, 68, 32, 67, 68, 67, 68, 67,
+ 68, 67, 68, 67, 68, 67, 68, 67, 68, 68,
+ 6, 68, 68, 68, 4, 68, 2, 68, 3, 6,
+ 68, 68, 2, 68, 2, 4, 68, 2, 68, 2,
+ 68, 9, 68, 10, 68, 68, 9, 68, 9, 68,
+
+ 68, 12, 68, 68, 67, 68, 26, 66, 68, 67,
+ 68, 63, 67, 68, 64, 67, 68, 67, 68, 67,
+ 68, 67, 68, 67, 68, 67, 68, 67, 68, 67,
+ 68, 67, 68, 67, 68, 67, 68, 67, 68, 67,
+ 68, 67, 68, 67, 68, 67, 68, 67, 68, 30,
+ 67, 68, 32, 67, 68, 67, 68, 67, 68, 67,
+ 68, 67, 68, 67, 68, 67, 68, 67, 68, 24,
+ 65, 67, 68, 21, 66, 68, 24, 67, 68, 23,
+ 63, 67, 68, 64, 67, 68, 67, 68, 67, 68,
+ 67, 68, 67, 68, 67, 68, 67, 68, 67, 68,
+
+ 67, 68, 67, 68, 67, 68, 67, 68, 67, 68,
+ 67, 68, 67, 68, 67, 68, 67, 68, 24, 65,
+ 67, 68, 30, 67, 68, 32, 67, 68, 67, 68,
+ 67, 68, 67, 68, 67, 68, 67, 68, 67, 68,
+ 14, 65, 67, 68, 15, 66, 68, 67, 68, 13,
+ 67, 68, 13, 64, 67, 68, 13, 67, 68, 13,
+ 67, 68, 13, 67, 68, 13, 67, 68, 13, 67,
+ 68, 13, 67, 68, 13, 67, 68, 13, 67, 68,
+ 13, 67, 68, 13, 67, 68, 13, 67, 68, 13,
+ 67, 68, 13, 67, 68, 13, 67, 68, 13, 67,
+
+ 68, 13, 67, 68, 14, 65, 67, 68, 13, 67,
+ 68, 13, 67, 68, 13, 67, 68, 13, 67, 68,
+ 13, 67, 68, 17, 68, 19, 68, 20, 68, 68,
+ 18, 68, 68, 29, 68, 68, 68, 65, 66, 64,
+ 65, 30, 32, 30, 35, 6, 5, 2, 3, 6,
+ 2, 5, 2, 2, 2, 2, 9, 9, 10, 9,
+ 9, 9, 11, 12, 25, 26, 66, 25, 64, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 30, 25, 25,
- 25, 25, 25, 25, 25, 25, 0, 24, 21, 24,
- 21, 59, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 24, 30, 0, 0, 0, 0, 0, 0, 0,
- 35, 14, 15, 0, 15, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 30, 30, 25, 25, 25, 25, 25, 25,
- 13, 13, 13, 13, 13, 13, 14, 13, 13, 13,
- 13, 13, 13, 13, 16, 0, 19, 20, 0, 0,
- 28, 0, 28, 0, 27, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 2, 9, 9, 9, 7, 25, 25, 25, 25,
+ 25, 25, 35, 24, 65, 21, 24, 21, 66, 64,
+ 24, 65, 30, 35, 14, 65, 15, 15, 66, 13,
+ 13, 64, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 14, 65, 13, 13, 13, 13,
+ 13, 13, 13, 16, 19, 20, 28, 28, 29, 27,
+ 28, 2, 9, 9, 9, 7, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 22, 22, 22, 22, 22, 22, 22, 22,
- 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 25, 25, 25, 25, 25, 25, 25, 22, 22, 64,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
- 22, 22, 22, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 31, 0, 0, 0, 0, 0, 2, 9, 8, 9,
- 7, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 0, 0, 25, 25, 25, 25, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
- 22, 22, 22, 22, 22, 22, 22, 0, 0, 22,
- 22, 22, 22, 13, 13, 13, 13, 13, 13, 13,
+ 22, 22, 22, 22, 22, 22, 30, 22, 22, 22,
+ 22, 22, 22, 22, 22, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 0, 0, 0, 0,
- 52, 0, 0, 0, 0, 51, 38, 0, 0, 0,
- 0, 0, 47, 0, 0, 0, 34, 0, 0, 0,
- 0, 2, 25, 25, 25, 25, 25, 25, 25, 25,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 31, 2, 9, 8,
+ 9, 7, 8, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 0, 25, 22, 22, 22,
+
+ 25, 25, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
- 0, 22, 13, 13, 13, 13, 13, 13, 13, 13,
+ 22, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 0, 0, 40, 46, 55, 56, 57, 0, 0, 0,
- 42, 0, 48, 0, 0, 0, 0, 0, 37, 1,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 22,
- 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 56,
+ 55, 38, 47, 34, 2, 25, 25, 25, 25, 25,
+ 25, 25, 56, 25, 25, 25, 25, 25, 25, 25,
+ 55, 25, 38, 25, 25, 25, 25, 25, 25, 25,
+ 47, 25, 25, 25, 25, 34, 25, 25, 25, 22,
22, 22, 22, 22, 22, 22, 22, 22, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 44,
- 50, 53, 49, 41, 0, 45, 0, 0, 0, 0,
- 1, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 22, 22, 22, 22, 22, 22, 22, 22,
- 22, 22, 22, 13, 13, 13, 13, 13, 54, 43,
- 0, 0, 0, 0, 25, 25, 25, 0, 25, 25,
- 22, 22, 22, 0, 22, 22, 13, 13, 0, 33,
- 0, 0, 25, 25, 0, 25, 22, 22, 0, 22,
- 13, 0, 36, 25, 25, 22, 22, 13, 0, 25,
- 22, 13, 0, 25, 22, 13, 0, 25, 22, 13,
-
- 39, 25, 22, 0
+ 22, 22, 22, 22, 22, 22, 56, 22, 22, 22,
+ 22, 22, 22, 22, 55, 22, 38, 22, 22, 22,
+ 22, 22, 22, 22, 47, 22, 22, 22, 22, 34,
+ 22, 22, 22, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 40, 46, 59, 60,
+ 62, 61, 42, 50, 37, 1, 2, 25, 25, 25,
+ 25, 40, 25, 46, 25, 25, 59, 25, 60, 25,
+ 62, 25, 61, 25, 25, 25, 25, 25, 42, 25,
+ 25, 25, 50, 25, 25, 25, 25, 25, 25, 37,
+
+ 22, 22, 22, 22, 40, 22, 46, 22, 22, 59,
+ 22, 60, 22, 62, 22, 61, 22, 22, 22, 22,
+ 22, 42, 22, 22, 22, 50, 22, 22, 22, 22,
+ 22, 22, 37, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 49, 44,
+ 52, 48, 57, 51, 41, 45, 1, 2, 25, 49,
+ 25, 44, 25, 52, 25, 25, 48, 25, 57, 25,
+ 51, 25, 41, 25, 25, 25, 45, 25, 25, 25,
+ 25, 22, 49, 22, 44, 22, 52, 22, 22, 48,
+ 22, 57, 22, 51, 22, 41, 22, 22, 22, 45,
+
+ 22, 22, 22, 22, 13, 13, 13, 13, 13, 13,
+ 13, 54, 58, 43, 25, 25, 54, 25, 58, 25,
+ 43, 25, 25, 25, 22, 22, 54, 22, 58, 22,
+ 43, 22, 22, 22, 13, 13, 13, 53, 33, 25,
+ 53, 25, 25, 33, 25, 22, 53, 22, 22, 33,
+ 22, 13, 36, 25, 25, 36, 22, 22, 36, 13,
+ 25, 22, 13, 25, 22, 13, 25, 22, 13, 39,
+ 25, 39, 22, 39
} ;
-static yyconst flex_int32_t yy_ec[256] =
+static yyconst short int yy_accept[933] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+ 4, 7, 9, 11, 14, 17, 19, 21, 23, 25,
+ 27, 29, 31, 33, 35, 37, 39, 41, 43, 45,
+ 47, 49, 52, 55, 58, 60, 62, 64, 66, 68,
+ 70, 71, 73, 74, 75, 77, 79, 82, 83, 85,
+ 88, 90, 92, 94, 96, 97, 99, 101, 102, 104,
+ 105, 107, 110, 112, 115, 118, 120, 122, 124, 126,
+ 128, 130, 132, 134, 136, 138, 140, 142, 144, 146,
+ 148, 150, 153, 156, 158, 160, 162, 164, 166, 168,
+
+ 170, 174, 177, 180, 184, 187, 189, 191, 193, 195,
+ 197, 199, 201, 203, 205, 207, 209, 211, 213, 215,
+ 217, 219, 223, 226, 229, 231, 233, 235, 237, 239,
+ 241, 245, 248, 250, 253, 257, 260, 263, 266, 269,
+ 272, 275, 278, 281, 284, 287, 290, 293, 296, 299,
+ 302, 305, 309, 312, 315, 318, 321, 324, 326, 328,
+ 330, 331, 333, 334, 336, 337, 338, 339, 340, 341,
+ 341, 341, 341, 341, 341, 341, 341, 341, 341, 341,
+ 341, 341, 341, 341, 341, 341, 341, 341, 341, 341,
+ 341, 341, 342, 343, 344, 344, 344, 344, 344, 345,
+
+ 345, 345, 345, 345, 345, 345, 345, 346, 347, 348,
+ 348, 348, 349, 351, 353, 353, 354, 355, 356, 357,
+ 358, 359, 360, 361, 362, 363, 363, 364, 365, 366,
+ 366, 368, 370, 371, 372, 373, 374, 375, 376, 377,
+ 378, 379, 380, 381, 382, 383, 384, 385, 386, 387,
+ 388, 389, 390, 391, 392, 394, 395, 396, 397, 398,
+ 399, 400, 401, 402, 404, 404, 406, 407, 408, 410,
+ 411, 411, 411, 411, 411, 411, 411, 411, 411, 411,
+ 411, 411, 411, 411, 411, 411, 411, 411, 411, 411,
+ 411, 411, 411, 413, 414, 414, 414, 414, 414, 414,
+
+ 414, 414, 415, 417, 418, 418, 420, 421, 423, 424,
+ 425, 426, 427, 428, 429, 430, 431, 432, 433, 434,
+ 435, 436, 437, 438, 439, 440, 441, 442, 443, 444,
+ 445, 447, 448, 449, 450, 451, 452, 453, 454, 455,
+ 455, 456, 457, 457, 457, 458, 458, 460, 460, 462,
+ 462, 462, 462, 462, 462, 462, 462, 462, 462, 462,
+ 462, 462, 462, 462, 462, 462, 462, 462, 462, 462,
+ 462, 462, 462, 462, 462, 462, 462, 462, 462, 462,
+ 462, 463, 464, 465, 466, 467, 468, 469, 470, 471,
+ 472, 473, 474, 475, 476, 477, 478, 479, 480, 481,
+
+ 482, 483, 484, 485, 486, 487, 488, 489, 490, 491,
+ 492, 493, 494, 495, 496, 497, 498, 499, 501, 502,
+ 503, 504, 505, 506, 507, 508, 509, 510, 511, 512,
+ 513, 514, 515, 516, 517, 518, 519, 520, 521, 522,
+ 523, 524, 525, 526, 528, 529, 530, 531, 532, 533,
+ 534, 535, 536, 537, 538, 539, 540, 541, 542, 543,
+ 544, 545, 546, 547, 548, 549, 550, 551, 552, 553,
+ 554, 555, 556, 557, 558, 559, 560, 561, 562, 563,
+ 564, 565, 566, 567, 567, 567, 567, 567, 567, 567,
+ 567, 567, 567, 567, 567, 567, 567, 567, 567, 567,
+
+ 567, 567, 567, 567, 567, 567, 567, 567, 567, 567,
+ 568, 568, 568, 568, 568, 568, 569, 570, 571, 572,
+ 574, 575, 576, 577, 578, 579, 580, 581, 582, 583,
+ 584, 585, 586, 587, 588, 589, 590, 591, 592, 593,
+ 594, 595, 596, 597, 598, 599, 599, 599, 600, 601,
+ 602, 603, 604, 605, 606, 607, 608, 609, 610, 611,
+ 612, 613, 614, 615, 616, 617, 618, 619, 620, 621,
+ 622, 623, 624, 625, 626, 627, 628, 628, 628, 629,
+ 630, 631, 632, 633, 634, 635, 636, 637, 638, 639,
+ 640, 641, 642, 643, 644, 645, 646, 647, 648, 649,
+
+ 650, 651, 652, 653, 654, 655, 656, 657, 658, 659,
+ 660, 660, 660, 660, 660, 660, 660, 661, 661, 661,
+ 661, 661, 661, 661, 662, 663, 663, 663, 663, 663,
+ 663, 663, 664, 664, 664, 664, 665, 665, 665, 665,
+ 665, 666, 667, 668, 669, 670, 671, 672, 674, 675,
+ 676, 677, 678, 679, 680, 682, 684, 685, 686, 687,
+ 688, 689, 690, 692, 693, 694, 695, 697, 698, 699,
+ 699, 700, 701, 702, 703, 704, 705, 706, 708, 709,
+ 710, 711, 712, 713, 714, 716, 718, 719, 720, 721,
+ 722, 723, 724, 726, 727, 728, 729, 731, 732, 733,
+
+ 733, 734, 735, 736, 737, 738, 739, 740, 741, 742,
+ 743, 744, 745, 746, 747, 748, 749, 750, 751, 752,
+ 753, 754, 755, 756, 757, 757, 757, 757, 758, 759,
+ 759, 760, 761, 762, 763, 763, 763, 763, 763, 764,
+ 764, 764, 765, 765, 765, 765, 765, 765, 766, 768,
+ 769, 770, 771, 773, 775, 776, 778, 780, 782, 784,
+ 785, 786, 787, 788, 790, 791, 792, 794, 795, 796,
+ 797, 798, 799, 801, 802, 803, 804, 806, 808, 809,
+ 811, 813, 815, 817, 818, 819, 820, 821, 823, 824,
+ 825, 827, 828, 829, 830, 831, 832, 834, 835, 836,
+
+ 837, 838, 839, 840, 841, 842, 843, 844, 845, 846,
+ 847, 848, 849, 850, 851, 852, 852, 853, 854, 855,
+ 856, 856, 856, 857, 857, 857, 857, 857, 859, 861,
+ 863, 865, 866, 868, 870, 872, 874, 875, 876, 878,
+ 879, 880, 881, 882, 884, 886, 888, 889, 891, 893,
+ 895, 897, 898, 899, 901, 902, 903, 904, 905, 906,
+ 907, 908, 909, 910, 911, 912, 912, 913, 914, 915,
+ 915, 915, 915, 915, 916, 918, 920, 922, 923, 923,
+ 924, 925, 926, 928, 930, 932, 933, 933, 934, 935,
+ 936, 937, 938, 939, 939, 940, 940, 940, 942, 943,
+
+ 945, 945, 946, 948, 949, 951, 951, 952, 953, 953,
+ 954, 955, 957, 958, 960, 961, 961, 962, 963, 964,
+ 964, 965, 966, 967, 967, 968, 969, 970, 971, 973,
+ 975, 975
+ } ;
+
+static yyconst int yy_ec[256] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
1, 1, 4, 1, 1, 1, 1, 1, 1, 1,
@@ -511,7 +542,7 @@ static yyconst flex_int32_t yy_ec[256] =
1, 1, 1, 1, 1
} ;
-static yyconst flex_int32_t yy_meta[49] =
+static yyconst int yy_meta[49] =
{ 0,
1, 2, 3, 4, 1, 1, 5, 6, 6, 1,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
@@ -520,697 +551,776 @@ static yyconst flex_int32_t yy_meta[49] =
6, 6, 6, 6, 6, 6, 1, 1
} ;
-static yyconst flex_int16_t yy_base[829] =
+static yyconst short int yy_base[953] =
{ 0,
- 0, 34, 80, 85, 89, 91, 7, 14, 138, 172,
- 219, 253, 301, 348, 94, 100, 106, 112, 2088, 2089,
- 10, 2089, 2084, 2089, 2077, 2, 2070, 2062, 2054, 95,
- 95, 97, 2055, 2059, 94, 2069, 2064, 2043, 394, 0,
- 2089, 102, 2032, 2034, 103, 84, 2028, 2089, 2089, 2071,
- 118, 2089, 0, 2089, 2070, 357, 0, 2048, 115, 2023,
- 2089, 2067, 88, 2021, 2065, 2089, 2064, 28, 2089, 2063,
- 151, 225, 361, 365, 370, 379, 401, 405, 410, 421,
- 427, 432, 440, 450, 454, 166, 247, 459, 464, 469,
- 473, 477, 481, 0, 488, 2089, 495, 2089, 2056, 221,
-
- 2049, 2041, 2033, 374, 124, 122, 2034, 2038, 130, 2048,
- 2043, 2022, 499, 348, 0, 353, 2011, 2013, 333, 378,
- 2007, 503, 2089, 2050, 0, 2043, 421, 2036, 2028, 2020,
- 498, 357, 374, 2021, 2025, 207, 2035, 2030, 2009, 520,
- 432, 1998, 2000, 334, 480, 396, 527, 2089, 2038, 2089,
- 415, 2089, 515, 531, 417, 2089, 2031, 2028, 2016, 2011,
- 2025, 2020, 2019, 2004, 2007, 2004, 2006, 2006, 1998, 2008,
- 2015, 1992, 2006, 2000, 516, 1980, 0, 0, 2089, 1961,
- 1963, 504, 1957, 0, 401, 1965, 1959, 1982, 437, 1953,
- 1942, 2089, 2089, 2089, 1977, 537, 0, 2089, 0, 1972,
-
- 540, 1955, 1944, 452, 1909, 1908, 2089, 188, 1907, 546,
- 1941, 2089, 2089, 548, 552, 2089, 556, 562, 566, 570,
- 574, 578, 582, 587, 596, 600, 604, 608, 613, 618,
- 628, 636, 640, 644, 649, 653, 658, 665, 670, 674,
- 678, 682, 686, 696, 690, 700, 557, 712, 2089, 716,
- 2089, 701, 624, 706, 720, 645, 609, 721, 722, 728,
- 735, 736, 740, 742, 747, 753, 752, 763, 754, 765,
- 771, 0, 776, 772, 783, 784, 789, 788, 790, 799,
- 800, 810, 2089, 1881, 2089, 0, 1873, 1870, 1858, 1853,
- 1865, 1859, 1851, 1833, 1836, 1833, 1830, 1817, 1802, 1809,
-
- 1796, 1772, 1786, 1779, 784, 1750, 0, 461, 1749, 1745,
- 1754, 503, 1722, 1713, 815, 816, 820, 2089, 1748, 587,
- 2089, 825, 2089, 830, 2089, 1726, 1717, 1701, 1692, 1679,
- 1680, 1675, 1654, 1653, 1642, 1651, 1650, 1640, 1636, 1616,
- 1587, 1578, 1584, 1584, 1555, 834, 836, 1545, 1554, 1536,
- 1533, 1546, 842, 846, 850, 2089, 854, 859, 863, 868,
- 872, 877, 895, 899, 903, 907, 911, 915, 926, 932,
- 938, 942, 946, 951, 956, 960, 973, 977, 981, 985,
- 990, 994, 864, 884, 947, 998, 986, 916, 961, 927,
- 999, 1003, 1004, 1005, 1011, 1017, 1016, 1030, 1034, 1035,
-
- 1036, 1040, 1042, 1044, 1049, 1056, 920, 1060, 1064, 1065,
- 1066, 1070, 1076, 1538, 1524, 1516, 1521, 1514, 1520, 1515,
- 1505, 1504, 1486, 1494, 1491, 1487, 1488, 1470, 1445, 1444,
- 1449, 1443, 1417, 1077, 1081, 1392, 1401, 1385, 1365, 1386,
- 1364, 1375, 1361, 1375, 1352, 1354, 1345, 1353, 1354, 1349,
- 1319, 1319, 1324, 1321, 1300, 1315, 1303, 1292, 1260, 1082,
- 2089, 1086, 1240, 1240, 1247, 1090, 1265, 1091, 2089, 1095,
- 2089, 1099, 1115, 1109, 1119, 1130, 1144, 1148, 1152, 1157,
- 1164, 1173, 1177, 1182, 1186, 1191, 1195, 1206, 1210, 1215,
- 1221, 1227, 1231, 1237, 1241, 1245, 1249, 1105, 1100, 1120,
-
- 1139, 1153, 1232, 1250, 1216, 1187, 1254, 1255, 1265, 1266,
- 1267, 1272, 1278, 1287, 1124, 1289, 1293, 1297, 1299, 1301,
- 1306, 1307, 1308, 1262, 1233, 1244, 1230, 1238, 1209, 1204,
- 1194, 1198, 1199, 1194, 1175, 1174, 1179, 1169, 1147, 1160,
- 1147, 1139, 1115, 1106, 1102, 1313, 1116, 1088, 1096, 1064,
- 2089, 1063, 1050, 1042, 1021, 2089, 2089, 1001, 988, 1002,
- 980, 987, 2089, 951, 950, 933, 2089, 925, 924, 1314,
- 892, 888, 1318, 1322, 1326, 1330, 1340, 1348, 1352, 1361,
- 1365, 1370, 1374, 1378, 1382, 1386, 1393, 1398, 1408, 1412,
- 1416, 1420, 1424, 1428, 1432, 1438, 1442, 1404, 1433, 1443,
-
- 1447, 1399, 1453, 1459, 1465, 1449, 1466, 1472, 1476, 1477,
- 1478, 1482, 1488, 1489, 1490, 1494, 1495, 1505, 1506, 1510,
- 1511, 1516, 891, 875, 886, 881, 877, 870, 865, 844,
- 831, 825, 840, 824, 832, 811, 811, 787, 776, 776,
- 798, 787, 2089, 2089, 2089, 2089, 2089, 786, 769, 759,
- 2089, 746, 2089, 740, 733, 699, 704, 688, 2089, 726,
- 1518, 1522, 1531, 1537, 1542, 1546, 1550, 1555, 1562, 1566,
- 1573, 1577, 1581, 1585, 1589, 1594, 1598, 1603, 1607, 1551,
- 1608, 1612, 1614, 1618, 1619, 1620, 1624, 1625, 1626, 1635,
- 1637, 1639, 1641, 1643, 1648, 1652, 1654, 1658, 702, 689,
-
- 675, 671, 667, 658, 655, 649, 615, 601, 590, 2089,
- 2089, 2089, 2089, 2089, 615, 2089, 597, 595, 1659, 564,
- 590, 1663, 1667, 1671, 1675, 1679, 1684, 1691, 1695, 1699,
- 1706, 1710, 1680, 1711, 1715, 1716, 1717, 1721, 1722, 1723,
- 1727, 1732, 1734, 571, 567, 561, 1736, 520, 2089, 2089,
- 493, 1738, 473, 1742, 1744, 1750, 1754, 1758, 1762, 1766,
- 1770, 1771, 1772, 1776, 1782, 1788, 485, 1789, 459, 2089,
- 1790, 429, 1795, 1799, 1806, 1810, 1814, 1815, 1816, 1820,
- 437, 412, 2089, 1829, 1822, 1836, 1837, 347, 329, 1841,
- 1842, 307, 204, 1846, 1850, 128, 119, 1854, 1863, 12,
-
- 2089, 1867, 1873, 2089, 1887, 1893, 1899, 1905, 1911, 1917,
- 1923, 1929, 1935, 1941, 1947, 1953, 1959, 1965, 1971, 1977,
- 1983, 1989, 1995, 0, 2001, 2007, 2013, 2019
+ 0, 47, 55, 60, 52, 64, 47, 68, 112, 159,
+ 206, 253, 300, 347, 74, 80, 70, 159, 2320, 2321,
+ 87, 2321, 2316, 2321, 2309, 2301, 73, 2301, 2293, 2285,
+ 85, 2297, 85, 69, 2285, 2289, 2285, 81, 2298, 2293,
+ 2272, 393, 0, 2321, 155, 2261, 2263, 144, 135, 2257,
+ 2321, 2321, 2300, 168, 2321, 0, 2321, 2299, 172, 0,
+ 2277, 241, 2252, 2321, 2296, 135, 2250, 2294, 2321, 2293,
+ 184, 2321, 2292, 188, 192, 262, 268, 275, 354, 358,
+ 362, 367, 400, 405, 387, 375, 413, 417, 425, 283,
+ 439, 444, 448, 452, 456, 460, 464, 471, 476, 0,
+
+ 480, 2321, 486, 2321, 2285, 2277, 243, 2277, 2269, 2261,
+ 246, 2273, 170, 246, 2261, 2265, 2261, 253, 2274, 2269,
+ 2248, 490, 102, 0, 174, 2237, 2239, 161, 256, 2233,
+ 494, 2321, 2276, 0, 2269, 2261, 257, 2261, 2253, 2245,
+ 489, 2257, 270, 340, 2245, 2249, 2245, 343, 2258, 2253,
+ 2232, 511, 371, 2221, 2223, 331, 373, 418, 515, 2321,
+ 2261, 2321, 352, 2321, 410, 519, 426, 2321, 2254, 2240,
+ 2250, 2238, 2233, 401, 2243, 2242, 2227, 426, 2233, 2227,
+ 2229, 2229, 2221, 2231, 2238, 2235, 2217, 2234, 2228, 448,
+ 2208, 0, 0, 2321, 2198, 2200, 476, 2191, 0, 374,
+
+ 2201, 2198, 2221, 436, 2183, 2177, 2321, 2321, 2321, 2217,
+ 522, 0, 2321, 0, 2211, 525, 2196, 2185, 457, 2160,
+ 2154, 2321, 488, 2148, 530, 2188, 2321, 2321, 535, 539,
+ 2321, 543, 551, 555, 559, 563, 572, 567, 583, 588,
+ 597, 601, 605, 609, 614, 622, 626, 636, 644, 649,
+ 654, 658, 663, 667, 672, 676, 682, 686, 690, 694,
+ 708, 702, 712, 716, 544, 724, 2321, 730, 2321, 634,
+ 735, 589, 737, 741, 610, 668, 743, 695, 750, 742,
+ 758, 748, 760, 659, 768, 766, 776, 764, 774, 786,
+ 788, 790, 0, 794, 795, 800, 804, 806, 811, 810,
+
+ 818, 822, 826, 2321, 2182, 2321, 0, 2175, 2151, 2161,
+ 2149, 2134, 559, 2104, 2103, 2088, 609, 2091, 2085, 2081,
+ 2081, 2070, 2080, 2084, 2078, 2060, 2077, 2067, 813, 2042,
+ 0, 553, 2040, 2027, 2049, 511, 2019, 2010, 835, 836,
+ 840, 2321, 2049, 572, 2321, 845, 2321, 850, 2321, 2014,
+ 2000, 1981, 1973, 1981, 1971, 1968, 1963, 1955, 1937, 1928,
+ 1933, 1921, 1910, 1917, 1894, 1887, 1884, 1869, 1873, 1848,
+ 1841, 1844, 1844, 1820, 854, 856, 1801, 1810, 1793, 1771,
+ 1786, 861, 865, 869, 2321, 874, 882, 886, 890, 895,
+ 900, 916, 922, 926, 930, 938, 942, 946, 950, 955,
+
+ 959, 964, 970, 980, 984, 988, 992, 1000, 1005, 1009,
+ 1019, 1023, 1027, 1031, 1035, 1039, 878, 905, 1001, 891,
+ 1043, 1045, 1044, 1050, 975, 1049, 1054, 971, 1060, 1075,
+ 1062, 1076, 1080, 896, 1085, 1086, 1087, 1091, 1092, 1096,
+ 1100, 1101, 1107, 1111, 1120, 1124, 1125, 1126, 1130, 1131,
+ 1132, 1137, 1794, 1774, 1763, 1753, 1752, 1740, 1738, 1746,
+ 1741, 1724, 1719, 1728, 1712, 1704, 1713, 1710, 1706, 1704,
+ 1688, 1689, 1672, 1667, 1674, 1674, 1641, 1141, 1143, 1634,
+ 1643, 1622, 1597, 1603, 1598, 1580, 1576, 1560, 1552, 1563,
+ 1540, 1542, 1536, 1527, 1533, 1524, 1519, 1518, 1487, 1487,
+
+ 1492, 1490, 1481, 1467, 1482, 1468, 1460, 1436, 1148, 2321,
+ 1153, 1428, 1426, 1422, 1154, 1443, 1158, 2321, 1163, 2321,
+ 1171, 1176, 1180, 1189, 1193, 1200, 1210, 1214, 1221, 1226,
+ 1230, 1234, 1244, 1250, 1259, 1263, 1268, 1272, 1276, 1280,
+ 1293, 1297, 1301, 1306, 1310, 1321, 1316, 1325, 1330, 1334,
+ 1338, 1240, 1281, 1194, 1235, 1181, 1339, 1343, 1288, 1344,
+ 1349, 1345, 1311, 1354, 1355, 1369, 1356, 1375, 1376, 1381,
+ 1385, 1387, 1393, 1391, 1167, 1395, 1402, 1406, 1408, 1412,
+ 1410, 1416, 1431, 1434, 1409, 1420, 1397, 1379, 1392, 1359,
+ 1359, 1355, 1336, 1345, 1337, 1327, 1323, 1281, 1280, 1285,
+
+ 1275, 1263, 1246, 1261, 1248, 1237, 1211, 1205, 1207, 1417,
+ 1205, 1214, 1195, 1207, 1203, 1195, 2321, 1193, 1177, 1169,
+ 1157, 1134, 1130, 2321, 2321, 1120, 1118, 1128, 1096, 1097,
+ 1101, 2321, 1081, 1053, 1033, 2321, 1037, 1030, 1418, 1011,
+ 1027, 1422, 1426, 1431, 1441, 1457, 1464, 1468, 1474, 1478,
+ 1485, 1489, 1496, 1500, 1504, 1508, 1512, 1516, 1521, 1528,
+ 1532, 1538, 1542, 1547, 1554, 1558, 1562, 1566, 1570, 1576,
+ 1580, 1432, 1427, 1447, 1581, 1585, 1591, 1517, 1596, 1597,
+ 1603, 1607, 1533, 1587, 1613, 1614, 1619, 1620, 1624, 1626,
+ 1628, 1630, 1634, 1636, 1640, 1641, 1642, 1650, 1652, 1651,
+
+ 1656, 1010, 1019, 1003, 1016, 1009, 1002, 998, 985, 981,
+ 977, 953, 938, 927, 920, 935, 913, 915, 926, 900,
+ 900, 883, 882, 856, 871, 865, 863, 2321, 2321, 844,
+ 2321, 2321, 2321, 2321, 855, 850, 841, 836, 2321, 814,
+ 810, 2321, 809, 803, 770, 769, 740, 2321, 777, 1662,
+ 1666, 1673, 1677, 1684, 1688, 1692, 1697, 1702, 1706, 1710,
+ 1714, 1721, 1725, 1732, 1736, 1740, 1744, 1749, 1758, 1762,
+ 1766, 1770, 1774, 1775, 1779, 1781, 1657, 1745, 1785, 1790,
+ 1791, 1792, 1797, 1798, 1802, 1811, 1813, 1815, 1817, 1822,
+ 1823, 1824, 1828, 1830, 1836, 1840, 1842, 770, 764, 744,
+
+ 724, 728, 726, 720, 713, 700, 700, 701, 687, 657,
+ 658, 611, 2321, 2321, 2321, 628, 2321, 2321, 2321, 2321,
+ 634, 632, 2321, 619, 617, 1844, 561, 590, 1846, 1850,
+ 1854, 1858, 1862, 1868, 1873, 1877, 1883, 1890, 1894, 1899,
+ 1903, 1908, 1912, 1863, 1881, 1913, 1917, 1918, 1919, 1923,
+ 1924, 1925, 1931, 1929, 1935, 1941, 1946, 1948, 564, 552,
+ 548, 540, 534, 1952, 503, 500, 2321, 2321, 2321, 469,
+ 1954, 439, 1956, 1958, 1962, 1967, 1971, 1975, 1980, 1984,
+ 1990, 1995, 1976, 1985, 2002, 2006, 2008, 2010, 2012, 461,
+ 421, 2014, 2321, 410, 2321, 2016, 377, 2018, 2030, 2024,
+
+ 2034, 2039, 2028, 2040, 2044, 2045, 2046, 340, 324, 2321,
+ 2062, 2066, 2067, 2051, 309, 253, 2072, 2077, 216, 166,
+ 2083, 2078, 142, 95, 2092, 2096, 59, 2321, 2105, 2109,
+ 2321, 2121, 2127, 2133, 2139, 2145, 2151, 2157, 2163, 2169,
+ 2175, 2181, 2187, 2193, 2199, 2205, 2211, 48, 2217, 2223,
+ 2229, 2235
} ;
-static yyconst flex_int16_t yy_def[829] =
+static yyconst short int yy_def[953] =
{ 0,
- 805, 804, 806, 807, 808, 808, 809, 809, 810, 804,
- 811, 804, 804, 13, 812, 812, 813, 813, 804, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 814,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
- 815, 804, 816, 804, 804, 817, 816, 816, 816, 818,
- 804, 804, 818, 818, 819, 804, 804, 820, 804, 804,
- 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
- 820, 820, 820, 820, 820, 821, 820, 820, 820, 820,
- 820, 820, 820, 822, 804, 804, 804, 804, 822, 822,
-
- 822, 822, 822, 822, 822, 822, 822, 822, 822, 822,
- 822, 822, 39, 823, 822, 822, 822, 822, 822, 822,
- 822, 804, 804, 804, 824, 824, 824, 824, 824, 824,
- 824, 824, 824, 824, 824, 824, 824, 824, 824, 39,
- 824, 824, 824, 824, 824, 825, 804, 804, 804, 804,
- 826, 804, 826, 826, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 39, 814, 804, 804,
- 804, 804, 804, 814, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 816, 804, 816, 804,
-
- 816, 816, 816, 816, 818, 818, 804, 818, 818, 818,
- 819, 804, 804, 820, 820, 804, 820, 820, 820, 820,
- 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
- 820, 820, 820, 820, 820, 820, 821, 821, 820, 820,
- 820, 820, 820, 820, 820, 820, 827, 804, 804, 804,
- 804, 827, 827, 827, 827, 827, 827, 827, 827, 827,
- 827, 827, 827, 827, 827, 827, 827, 827, 827, 827,
- 827, 113, 828, 827, 827, 827, 827, 827, 827, 827,
- 827, 804, 804, 804, 804, 824, 824, 824, 824, 824,
- 824, 824, 824, 824, 824, 824, 824, 824, 824, 824,
-
- 824, 824, 824, 824, 824, 824, 140, 824, 824, 824,
- 824, 824, 824, 824, 825, 825, 804, 804, 804, 826,
- 804, 826, 804, 826, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
- 804, 816, 818, 818, 818, 804, 820, 820, 820, 820,
- 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
- 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
- 820, 820, 827, 827, 827, 827, 827, 827, 827, 827,
- 827, 827, 827, 827, 827, 827, 827, 827, 827, 827,
-
- 827, 827, 827, 827, 828, 827, 827, 827, 827, 827,
- 827, 827, 827, 824, 824, 824, 824, 824, 824, 824,
- 824, 824, 824, 824, 824, 824, 824, 824, 824, 824,
- 824, 824, 824, 824, 824, 824, 824, 824, 824, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
+ 931, 1, 932, 933, 934, 934, 935, 935, 931, 9,
+ 931, 11, 931, 13, 936, 936, 937, 937, 931, 931,
+ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ 931, 931, 938, 931, 931, 931, 931, 931, 931, 931,
+ 931, 931, 931, 939, 931, 940, 931, 931, 941, 940,
+ 940, 940, 942, 931, 931, 942, 942, 943, 931, 931,
+ 944, 931, 931, 944, 944, 944, 944, 944, 944, 944,
+ 944, 944, 944, 944, 944, 944, 944, 944, 944, 944,
+ 944, 945, 944, 944, 944, 944, 944, 944, 944, 946,
+
+ 931, 931, 931, 931, 946, 946, 946, 946, 946, 946,
+ 946, 946, 946, 946, 946, 946, 946, 946, 946, 946,
+ 946, 42, 947, 946, 946, 946, 946, 946, 946, 946,
+ 931, 931, 931, 948, 948, 948, 948, 948, 948, 948,
+ 948, 948, 948, 948, 948, 948, 948, 948, 948, 948,
+ 948, 42, 948, 948, 948, 948, 948, 949, 931, 931,
+ 931, 931, 950, 931, 950, 950, 931, 931, 931, 931,
+ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ 931, 42, 938, 931, 931, 931, 931, 931, 938, 931,
+
+ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ 931, 940, 931, 940, 931, 940, 940, 940, 940, 942,
+ 942, 931, 942, 942, 942, 943, 931, 931, 944, 944,
+ 931, 944, 944, 944, 944, 944, 944, 944, 944, 944,
+ 944, 944, 944, 944, 944, 944, 944, 944, 944, 944,
+ 944, 944, 944, 944, 945, 945, 944, 944, 944, 944,
+ 944, 944, 944, 944, 951, 931, 931, 931, 931, 951,
+ 951, 951, 951, 951, 951, 951, 951, 951, 951, 951,
+ 951, 951, 951, 951, 951, 951, 951, 951, 951, 951,
+ 951, 951, 122, 952, 951, 951, 951, 951, 951, 951,
+
+ 951, 951, 931, 931, 931, 931, 948, 948, 948, 948,
+ 948, 948, 948, 948, 948, 948, 948, 948, 948, 948,
+ 948, 948, 948, 948, 948, 948, 948, 948, 948, 948,
+ 152, 948, 948, 948, 948, 948, 948, 948, 949, 949,
+ 931, 931, 931, 950, 931, 950, 931, 950, 931, 931,
+ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ 940, 942, 942, 942, 931, 944, 944, 944, 944, 944,
+ 944, 944, 944, 944, 944, 944, 944, 944, 944, 944,
+
+ 944, 944, 944, 944, 944, 944, 944, 944, 944, 944,
+ 944, 944, 944, 944, 944, 944, 951, 951, 951, 951,
+ 951, 951, 951, 951, 951, 951, 951, 951, 951, 951,
+ 951, 951, 951, 951, 951, 951, 951, 951, 951, 951,
+ 951, 951, 951, 952, 951, 951, 951, 951, 951, 951,
+ 951, 951, 948, 948, 948, 948, 948, 948, 948, 948,
+ 948, 948, 948, 948, 948, 948, 948, 948, 948, 948,
+ 948, 948, 948, 948, 948, 948, 948, 948, 948, 948,
+ 948, 948, 948, 931, 931, 931, 931, 931, 931, 931,
+ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
804, 804, 804, 804, 804, 804, 816, 818, 804, 818,
804, 820, 820, 820, 820, 820, 820, 820, 820, 820,
820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
820, 820, 820, 820, 820, 820, 820, 827, 827, 827,
- 827, 827, 827, 827, 827, 827, 827, 827, 827, 827,
- 827, 827, 827, 827, 827, 827, 827, 827, 827, 827,
- 827, 827, 827, 824, 824, 824, 824, 824, 824, 824,
- 824, 824, 824, 824, 824, 824, 824, 824, 824, 824,
- 824, 824, 824, 824, 824, 824, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
+ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ 931, 931, 931, 931, 931, 940, 942, 931, 942, 931,
+ 944, 944, 944, 944, 944, 944, 944, 944, 944, 944,
+ 944, 944, 944, 944, 944, 944, 944, 944, 944, 944,
+ 944, 944, 944, 944, 944, 944, 944, 944, 944, 944,
+ 944, 951, 951, 951, 951, 951, 951, 951, 951, 951,
+ 951, 951, 951, 951, 951, 951, 951, 951, 951, 951,
+ 951, 951, 951, 951, 951, 951, 951, 951, 951, 951,
+ 951, 951, 948, 948, 948, 948, 948, 948, 948, 948,
+ 948, 948, 948, 948, 948, 948, 948, 948, 948, 948,
804, 816, 820, 820, 820, 820, 820, 820, 820, 820,
820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
820, 820, 820, 820, 820, 820, 820, 827, 827, 827,
- 827, 827, 827, 827, 827, 827, 827, 827, 827, 827,
- 827, 827, 827, 827, 827, 827, 827, 827, 827, 827,
- 827, 827, 824, 824, 824, 824, 824, 824, 824, 824,
- 824, 824, 824, 824, 824, 824, 824, 824, 824, 824,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 816,
- 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
- 820, 820, 820, 820, 820, 820, 820, 820, 820, 827,
- 827, 827, 827, 827, 827, 827, 827, 827, 827, 827,
- 827, 827, 827, 827, 827, 827, 827, 827, 824, 824,
-
- 824, 824, 824, 824, 824, 824, 824, 824, 824, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
- 816, 820, 820, 820, 820, 820, 820, 820, 820, 820,
- 820, 820, 827, 827, 827, 827, 827, 827, 827, 827,
- 827, 827, 827, 824, 824, 824, 824, 824, 804, 804,
- 804, 804, 804, 804, 820, 820, 820, 820, 820, 820,
- 827, 827, 827, 827, 827, 827, 824, 824, 804, 804,
- 804, 804, 820, 820, 820, 820, 827, 827, 827, 827,
- 824, 804, 804, 820, 820, 827, 827, 824, 804, 820,
- 827, 824, 804, 820, 827, 824, 804, 820, 827, 824,
-
- 804, 820, 827, 0, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 804, 804
+ 948, 948, 948, 948, 948, 948, 948, 948, 948, 948,
+ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ 940, 944, 944, 944, 944, 944, 944, 944, 944, 944,
+ 944, 944, 944, 944, 944, 944, 944, 944, 944, 944,
+ 944, 944, 944, 944, 944, 944, 944, 944, 944, 944,
+ 944, 951, 951, 951, 951, 951, 951, 951, 951, 951,
+ 951, 951, 951, 951, 951, 951, 951, 951, 951, 951,
+ 951, 951, 951, 951, 951, 951, 951, 951, 951, 951,
+
+ 951, 948, 948, 948, 948, 948, 948, 948, 948, 948,
+ 948, 948, 948, 948, 948, 948, 948, 948, 948, 948,
+ 948, 948, 948, 948, 931, 931, 931, 931, 931, 931,
+ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ 931, 931, 931, 931, 931, 931, 931, 931, 940, 944,
+ 944, 944, 944, 944, 944, 944, 944, 944, 944, 944,
+ 944, 944, 944, 944, 944, 944, 944, 944, 944, 944,
+ 944, 944, 944, 951, 951, 951, 951, 951, 951, 951,
+ 951, 951, 951, 951, 951, 951, 951, 951, 951, 951,
+ 951, 951, 951, 951, 951, 951, 951, 948, 948, 948,
+
+ 948, 948, 948, 948, 948, 948, 948, 948, 948, 948,
+ 948, 948, 931, 931, 931, 931, 931, 931, 931, 931,
+ 931, 931, 931, 931, 931, 931, 931, 940, 944, 944,
+ 944, 944, 944, 944, 944, 944, 944, 944, 944, 944,
+ 944, 944, 944, 951, 951, 951, 951, 951, 951, 951,
+ 951, 951, 951, 951, 951, 951, 951, 951, 948, 948,
+ 948, 948, 948, 948, 948, 931, 931, 931, 931, 931,
+ 931, 931, 931, 944, 944, 944, 944, 944, 944, 944,
+ 944, 951, 951, 951, 951, 951, 951, 951, 951, 948,
+ 948, 948, 931, 931, 931, 931, 931, 944, 944, 944,
+
+ 944, 944, 951, 951, 951, 951, 951, 948, 931, 931,
+ 944, 944, 951, 951, 948, 931, 944, 951, 948, 931,
+ 944, 951, 948, 931, 944, 951, 948, 931, 944, 951,
+ 0, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ 931, 931
} ;
-static yyconst flex_int16_t yy_nxt[2138] =
+static yyconst short int yy_nxt[2370] =
{ 0,
- 804, 21, 22, 23, 21, 286, 24, 804, 25, 66,
- 67, 155, 26, 27, 155, 28, 66, 67, 29, 158,
- 30, 801, 31, 32, 33, 34, 159, 35, 36, 215,
- 37, 215, 215, 38, 20, 39, 22, 23, 39, 40,
- 24, 20, 25, 41, 20, 20, 26, 27, 20, 28,
- 20, 20, 29, 20, 30, 20, 42, 32, 33, 34,
- 20, 35, 36, 20, 37, 20, 20, 38, 20, 20,
- 20, 20, 43, 20, 44, 20, 45, 20, 20, 46,
- 47, 20, 49, 50, 51, 52, 48, 54, 55, 56,
- 57, 61, 62, 61, 62, 147, 148, 149, 147, 58,
-
- 150, 147, 148, 149, 147, 166, 150, 168, 152, 153,
- 163, 172, 185, 164, 152, 153, 190, 165, 191, 167,
- 193, 195, 196, 173, 169, 188, 167, 59, 801, 203,
- 208, 63, 263, 63, 261, 209, 64, 154, 64, 21,
- 69, 70, 21, 154, 71, 189, 72, 267, 262, 264,
- 73, 74, 215, 75, 215, 215, 76, 204, 77, 268,
- 78, 79, 80, 81, 800, 82, 83, 238, 84, 238,
- 238, 85, 68, 39, 69, 70, 39, 86, 71, 68,
- 72, 87, 68, 68, 73, 74, 68, 75, 68, 68,
- 76, 68, 77, 68, 88, 79, 80, 81, 68, 82,
-
- 83, 68, 84, 68, 68, 85, 68, 68, 68, 68,
- 89, 68, 90, 68, 91, 68, 68, 92, 93, 68,
- 95, 96, 97, 95, 302, 98, 215, 99, 215, 215,
- 208, 100, 101, 217, 102, 209, 303, 103, 253, 104,
- 797, 105, 106, 107, 108, 254, 109, 110, 215, 111,
- 215, 215, 112, 94, 113, 96, 97, 113, 114, 98,
- 94, 99, 115, 94, 94, 100, 101, 94, 102, 94,
- 94, 103, 94, 104, 94, 116, 106, 107, 108, 94,
- 109, 110, 94, 111, 94, 94, 112, 94, 94, 94,
- 94, 117, 94, 118, 94, 119, 94, 94, 120, 121,
-
- 94, 20, 122, 123, 124, 122, 20, 24, 125, 126,
- 20, 125, 125, 127, 128, 125, 129, 125, 125, 130,
- 125, 131, 125, 132, 133, 134, 135, 125, 136, 137,
- 125, 138, 20, 125, 139, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 20, 20, 140,
- 796, 184, 140, 40, 184, 277, 311, 41, 194, 198,
- 200, 201, 215, 274, 215, 215, 215, 296, 215, 215,
- 141, 215, 793, 215, 215, 278, 312, 262, 218, 220,
- 215, 297, 215, 215, 298, 219, 142, 792, 143, 258,
- 144, 221, 259, 145, 47, 177, 260, 316, 177, 178,
-
- 316, 299, 215, 179, 215, 215, 215, 222, 215, 215,
- 279, 215, 280, 215, 215, 226, 223, 321, 155, 224,
- 228, 155, 215, 225, 215, 215, 346, 334, 215, 227,
- 215, 215, 180, 215, 181, 215, 215, 229, 288, 182,
- 183, 215, 308, 215, 215, 289, 322, 230, 231, 232,
- 234, 215, 789, 215, 215, 215, 297, 215, 215, 188,
- 215, 233, 215, 215, 235, 215, 203, 215, 215, 239,
- 215, 788, 215, 215, 215, 783, 215, 215, 215, 189,
- 215, 215, 215, 227, 215, 215, 434, 422, 236, 248,
- 249, 250, 248, 782, 204, 242, 250, 251, 250, 250,
-
- 272, 249, 250, 272, 282, 283, 284, 282, 240, 244,
- 241, 245, 313, 293, 314, 243, 294, 323, 781, 770,
- 295, 307, 283, 284, 307, 311, 769, 246, 317, 318,
- 319, 317, 324, 325, 343, 324, 190, 344, 191, 193,
- 195, 196, 198, 200, 201, 312, 322, 355, 356, 215,
- 355, 215, 215, 215, 768, 215, 215, 215, 247, 215,
- 215, 247, 322, 215, 217, 215, 215, 215, 767, 215,
- 215, 215, 357, 215, 215, 215, 750, 215, 215, 215,
- 749, 215, 215, 215, 360, 215, 215, 358, 215, 321,
- 215, 215, 361, 353, 721, 359, 362, 215, 754, 215,
-
- 215, 215, 751, 215, 215, 215, 750, 215, 215, 215,
- 247, 215, 215, 247, 215, 363, 215, 215, 322, 215,
- 364, 215, 215, 389, 749, 247, 365, 366, 247, 215,
- 367, 215, 215, 748, 385, 747, 369, 215, 370, 215,
- 215, 215, 368, 215, 215, 215, 247, 215, 215, 247,
- 215, 372, 215, 215, 215, 388, 215, 215, 746, 238,
- 373, 238, 238, 745, 716, 371, 238, 374, 238, 238,
- 375, 215, 744, 215, 215, 215, 714, 215, 215, 215,
- 713, 215, 215, 215, 712, 215, 215, 215, 376, 215,
- 215, 215, 380, 215, 215, 377, 365, 215, 711, 215,
-
- 215, 215, 247, 215, 215, 247, 378, 247, 242, 384,
- 247, 710, 379, 248, 249, 250, 248, 250, 249, 250,
- 250, 247, 247, 247, 247, 247, 247, 386, 243, 247,
- 721, 720, 247, 382, 381, 390, 247, 247, 719, 247,
- 247, 247, 718, 247, 247, 387, 247, 717, 247, 716,
- 391, 247, 392, 247, 247, 247, 247, 247, 247, 394,
- 715, 393, 395, 398, 247, 397, 247, 247, 714, 247,
- 401, 396, 247, 247, 400, 247, 247, 273, 713, 184,
- 273, 399, 184, 402, 247, 247, 403, 247, 247, 247,
- 247, 247, 247, 247, 247, 712, 711, 406, 393, 409,
-
- 247, 247, 431, 247, 247, 432, 404, 710, 709, 708,
- 410, 282, 283, 284, 282, 407, 316, 316, 408, 316,
- 316, 317, 318, 319, 317, 707, 324, 325, 412, 324,
- 411, 324, 325, 706, 324, 460, 461, 462, 460, 705,
- 462, 653, 413, 468, 469, 704, 468, 470, 471, 651,
- 470, 355, 356, 703, 355, 215, 322, 215, 215, 702,
- 215, 322, 215, 215, 215, 247, 215, 215, 247, 215,
- 701, 215, 215, 215, 647, 215, 215, 472, 215, 646,
- 215, 215, 463, 473, 475, 247, 645, 477, 247, 353,
- 644, 474, 384, 353, 476, 643, 215, 206, 215, 215,
-
- 215, 700, 215, 215, 215, 699, 215, 215, 215, 478,
- 215, 215, 215, 660, 215, 215, 215, 247, 215, 215,
- 247, 519, 479, 480, 519, 482, 483, 215, 247, 215,
- 215, 247, 501, 215, 481, 215, 215, 503, 659, 215,
- 484, 215, 215, 215, 485, 215, 215, 215, 247, 215,
- 215, 247, 215, 486, 215, 215, 658, 215, 657, 215,
- 215, 215, 247, 215, 215, 247, 520, 489, 490, 487,
- 498, 656, 655, 488, 492, 461, 215, 492, 493, 654,
- 215, 493, 215, 502, 215, 215, 215, 247, 215, 215,
- 247, 215, 491, 215, 215, 215, 653, 215, 215, 247,
-
- 247, 652, 247, 247, 247, 247, 247, 247, 247, 247,
- 377, 651, 247, 504, 500, 247, 650, 247, 247, 495,
- 247, 247, 499, 494, 506, 508, 505, 496, 509, 649,
- 510, 247, 507, 497, 247, 247, 247, 247, 247, 247,
- 247, 247, 511, 247, 247, 247, 247, 648, 247, 512,
- 273, 647, 184, 273, 516, 184, 515, 518, 461, 646,
- 518, 247, 513, 514, 247, 247, 247, 247, 247, 247,
- 247, 247, 645, 644, 247, 409, 517, 247, 460, 461,
- 247, 460, 462, 460, 461, 462, 460, 462, 410, 406,
- 462, 570, 468, 469, 570, 468, 470, 471, 521, 470,
-
- 215, 247, 215, 215, 247, 643, 247, 522, 411, 247,
- 215, 573, 215, 215, 642, 523, 215, 598, 215, 215,
- 215, 247, 215, 215, 247, 247, 575, 463, 247, 599,
- 641, 215, 463, 215, 215, 640, 571, 600, 206, 577,
- 247, 615, 206, 247, 574, 215, 576, 215, 215, 215,
- 639, 215, 215, 215, 247, 215, 215, 247, 215, 638,
- 215, 215, 602, 637, 636, 215, 601, 215, 215, 563,
- 579, 581, 578, 582, 215, 635, 215, 215, 215, 580,
- 215, 215, 583, 215, 634, 215, 215, 215, 247, 215,
- 215, 247, 215, 633, 215, 215, 215, 632, 215, 215,
-
- 586, 606, 631, 557, 584, 585, 587, 215, 556, 215,
- 215, 215, 630, 215, 215, 589, 215, 247, 215, 215,
- 247, 629, 215, 588, 215, 215, 628, 590, 492, 461,
- 215, 492, 493, 247, 215, 493, 247, 627, 215, 591,
- 215, 215, 215, 605, 215, 215, 215, 551, 215, 215,
- 596, 247, 215, 596, 247, 247, 247, 626, 247, 247,
- 603, 625, 624, 607, 608, 592, 247, 247, 247, 247,
- 247, 247, 604, 247, 623, 572, 247, 494, 595, 247,
- 569, 611, 247, 593, 568, 594, 567, 612, 247, 610,
- 247, 247, 609, 247, 247, 597, 614, 247, 518, 461,
-
- 519, 518, 247, 519, 566, 247, 613, 247, 247, 621,
- 247, 247, 621, 616, 570, 570, 565, 570, 570, 215,
- 564, 215, 215, 215, 563, 215, 215, 215, 562, 215,
- 215, 215, 661, 215, 215, 663, 561, 617, 560, 664,
- 620, 215, 559, 215, 215, 520, 558, 618, 662, 215,
- 619, 215, 215, 215, 622, 215, 215, 665, 557, 571,
- 571, 666, 215, 556, 215, 215, 215, 555, 215, 215,
- 667, 215, 554, 215, 215, 215, 553, 215, 215, 215,
- 552, 215, 215, 215, 551, 215, 215, 215, 550, 215,
- 215, 668, 549, 548, 215, 671, 215, 215, 547, 215,
-
- 247, 215, 215, 247, 546, 247, 669, 673, 247, 215,
- 670, 215, 215, 215, 672, 215, 215, 215, 680, 215,
- 215, 215, 545, 215, 215, 215, 434, 215, 215, 215,
- 544, 215, 215, 215, 247, 215, 215, 247, 675, 596,
- 674, 215, 596, 215, 247, 215, 215, 247, 247, 543,
- 247, 247, 682, 247, 247, 542, 683, 247, 676, 681,
- 247, 677, 684, 247, 678, 541, 247, 247, 685, 247,
- 247, 540, 539, 247, 686, 687, 247, 247, 247, 247,
- 247, 247, 247, 247, 597, 538, 247, 690, 679, 247,
- 247, 247, 247, 247, 247, 247, 247, 692, 247, 247,
-
- 537, 536, 535, 691, 688, 689, 247, 247, 534, 247,
- 247, 247, 621, 533, 247, 621, 694, 247, 693, 215,
- 247, 215, 215, 215, 532, 215, 215, 722, 531, 530,
- 529, 723, 215, 695, 215, 215, 528, 527, 215, 696,
- 215, 215, 697, 215, 526, 215, 215, 215, 525, 215,
- 215, 215, 247, 215, 215, 247, 215, 622, 215, 215,
- 733, 524, 698, 215, 724, 215, 215, 215, 467, 215,
- 215, 725, 466, 465, 215, 726, 215, 215, 215, 346,
- 215, 215, 215, 464, 215, 215, 215, 459, 215, 215,
- 215, 727, 215, 215, 728, 215, 458, 215, 215, 215,
-
- 457, 215, 215, 729, 215, 456, 215, 215, 215, 247,
- 215, 215, 247, 247, 455, 247, 247, 734, 247, 247,
- 247, 247, 247, 247, 247, 247, 247, 247, 247, 247,
- 247, 454, 731, 735, 736, 737, 247, 730, 247, 247,
- 247, 247, 247, 247, 247, 247, 732, 247, 453, 247,
- 739, 738, 247, 247, 452, 247, 247, 740, 247, 247,
- 752, 451, 247, 752, 215, 450, 215, 215, 215, 449,
- 215, 215, 215, 448, 215, 215, 215, 447, 215, 215,
- 215, 247, 215, 215, 247, 215, 742, 215, 215, 446,
- 445, 741, 215, 755, 215, 215, 215, 743, 215, 215,
-
- 215, 444, 215, 215, 756, 753, 757, 758, 443, 215,
- 758, 215, 247, 215, 215, 247, 247, 247, 247, 247,
- 247, 247, 247, 247, 247, 247, 247, 247, 247, 442,
- 761, 247, 762, 764, 763, 247, 764, 752, 247, 752,
- 752, 441, 752, 771, 760, 215, 771, 215, 215, 440,
- 318, 215, 759, 215, 215, 215, 439, 215, 215, 758,
- 438, 215, 758, 215, 437, 215, 215, 775, 766, 215,
- 775, 247, 247, 247, 247, 247, 247, 764, 765, 436,
- 764, 435, 753, 247, 753, 433, 247, 773, 772, 779,
- 771, 771, 779, 771, 771, 430, 215, 429, 215, 215,
-
- 215, 428, 215, 215, 759, 777, 427, 775, 774, 215,
- 775, 215, 776, 215, 215, 247, 247, 779, 247, 247,
- 779, 247, 765, 215, 247, 215, 215, 426, 778, 784,
- 215, 425, 215, 215, 780, 772, 772, 247, 247, 424,
- 247, 247, 215, 247, 215, 215, 247, 215, 786, 215,
- 215, 247, 776, 423, 247, 215, 785, 215, 215, 422,
- 421, 420, 780, 802, 247, 419, 787, 247, 215, 790,
- 215, 215, 803, 418, 247, 417, 791, 247, 416, 415,
- 414, 287, 798, 283, 794, 795, 799, 20, 20, 20,
- 20, 20, 20, 48, 48, 48, 48, 48, 48, 53,
-
- 53, 53, 53, 53, 53, 60, 60, 60, 60, 60,
- 60, 65, 65, 65, 65, 65, 65, 68, 68, 68,
- 68, 68, 68, 94, 94, 94, 94, 94, 94, 146,
- 146, 146, 146, 146, 146, 151, 151, 151, 151, 151,
- 151, 184, 184, 212, 184, 184, 184, 194, 194, 194,
- 194, 194, 194, 197, 354, 353, 206, 197, 197, 199,
- 199, 199, 199, 199, 199, 205, 205, 202, 352, 205,
- 205, 211, 211, 211, 198, 211, 211, 214, 214, 193,
- 214, 214, 214, 237, 237, 351, 237, 237, 237, 247,
- 247, 350, 349, 348, 247, 273, 273, 347, 273, 273,
-
- 273, 315, 315, 192, 187, 186, 315, 320, 320, 320,
- 320, 320, 320, 383, 383, 345, 342, 341, 383, 405,
- 405, 340, 405, 405, 405, 339, 338, 337, 336, 335,
- 334, 333, 332, 331, 330, 329, 328, 327, 326, 157,
- 318, 310, 309, 306, 305, 304, 301, 300, 292, 291,
- 290, 287, 285, 281, 276, 275, 271, 270, 269, 266,
- 265, 257, 256, 255, 252, 216, 213, 212, 210, 207,
- 206, 202, 198, 193, 192, 187, 186, 176, 175, 174,
- 171, 170, 162, 161, 160, 157, 156, 804, 19, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
-
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 804
+ 20, 21, 22, 23, 21, 20, 24, 20, 25, 20,
+ 20, 26, 27, 28, 20, 29, 20, 20, 30, 20,
+ 31, 32, 33, 34, 35, 36, 37, 38, 39, 20,
+ 40, 20, 20, 41, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 42, 69,
+ 70, 42, 43, 307, 64, 65, 44, 52, 53, 54,
+ 55, 51, 57, 58, 59, 60, 64, 65, 928, 45,
+ 69, 70, 164, 165, 61, 159, 160, 161, 159, 182,
+ 162, 159, 160, 161, 159, 46, 162, 47, 167, 48,
+ 171, 167, 49, 50, 66, 180, 183, 172, 187, 67,
+
+ 176, 166, 62, 177, 928, 199, 66, 178, 199, 181,
+ 188, 67, 71, 21, 72, 73, 21, 71, 74, 71,
+ 75, 71, 71, 76, 77, 78, 71, 79, 71, 71,
+ 80, 71, 81, 82, 83, 84, 85, 86, 87, 88,
+ 89, 71, 90, 71, 71, 91, 71, 71, 71, 71,
+ 71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
+ 42, 164, 165, 42, 92, 200, 203, 205, 93, 206,
+ 208, 210, 211, 209, 213, 215, 216, 223, 927, 181,
+ 281, 94, 224, 298, 295, 230, 204, 230, 230, 230,
+ 166, 230, 230, 230, 282, 230, 230, 95, 282, 96,
+
+ 232, 97, 924, 299, 98, 99, 100, 101, 102, 103,
+ 101, 100, 104, 100, 105, 100, 100, 106, 107, 108,
+ 100, 109, 100, 100, 110, 100, 111, 112, 113, 114,
+ 115, 116, 117, 118, 119, 100, 120, 100, 100, 121,
+ 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
+ 100, 100, 100, 100, 122, 218, 283, 122, 123, 923,
+ 272, 277, 124, 230, 278, 230, 230, 273, 279, 230,
+ 288, 230, 230, 284, 310, 125, 230, 233, 230, 230,
+ 319, 311, 289, 219, 230, 234, 230, 230, 300, 236,
+ 301, 126, 235, 127, 320, 128, 920, 253, 129, 130,
+
+ 20, 131, 132, 133, 131, 20, 24, 134, 135, 20,
+ 134, 136, 137, 138, 134, 139, 134, 134, 140, 134,
+ 141, 142, 143, 144, 145, 146, 147, 148, 149, 134,
+ 150, 20, 134, 151, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 134, 20, 20, 152, 919,
+ 321, 152, 43, 335, 345, 230, 44, 230, 230, 230,
+ 326, 230, 230, 230, 916, 230, 230, 322, 230, 153,
+ 230, 230, 327, 336, 915, 237, 230, 239, 230, 230,
+ 240, 332, 242, 346, 241, 154, 238, 155, 230, 156,
+ 230, 230, 157, 50, 192, 320, 248, 192, 193, 375,
+
+ 362, 230, 194, 230, 230, 337, 230, 338, 230, 230,
+ 243, 354, 347, 247, 230, 245, 230, 230, 230, 340,
+ 230, 230, 340, 910, 244, 355, 230, 167, 230, 230,
+ 167, 195, 246, 196, 250, 252, 359, 249, 197, 198,
+ 230, 346, 230, 230, 909, 256, 251, 256, 256, 230,
+ 360, 230, 230, 230, 908, 230, 230, 230, 203, 230,
+ 230, 230, 257, 230, 230, 230, 372, 230, 230, 373,
+ 893, 218, 230, 254, 230, 230, 244, 230, 204, 230,
+ 230, 266, 267, 268, 266, 895, 260, 268, 269, 268,
+ 268, 293, 267, 268, 293, 303, 304, 305, 303, 219,
+
+ 258, 259, 894, 262, 315, 263, 261, 316, 205, 893,
+ 206, 317, 331, 304, 305, 331, 341, 342, 343, 341,
+ 348, 349, 264, 348, 208, 210, 211, 213, 215, 216,
+ 223, 384, 385, 335, 384, 224, 230, 892, 230, 230,
+ 230, 891, 230, 230, 230, 265, 230, 230, 265, 869,
+ 346, 232, 230, 336, 230, 230, 230, 868, 230, 230,
+ 230, 867, 230, 230, 230, 387, 230, 230, 230, 457,
+ 230, 230, 386, 230, 345, 230, 230, 382, 478, 465,
+ 388, 392, 390, 458, 230, 890, 230, 230, 389, 230,
+ 265, 230, 230, 265, 828, 873, 391, 393, 230, 420,
+
+ 230, 230, 230, 346, 230, 230, 230, 395, 230, 230,
+ 230, 265, 230, 230, 265, 230, 394, 230, 230, 462,
+ 423, 396, 397, 230, 870, 230, 230, 230, 869, 230,
+ 230, 398, 399, 463, 424, 265, 400, 230, 265, 230,
+ 230, 868, 418, 867, 402, 230, 403, 230, 230, 866,
+ 230, 401, 230, 230, 865, 230, 404, 230, 230, 230,
+ 265, 230, 230, 265, 230, 406, 230, 230, 230, 265,
+ 230, 230, 265, 256, 407, 256, 256, 256, 405, 256,
+ 256, 408, 425, 230, 409, 230, 230, 230, 434, 230,
+ 230, 230, 864, 230, 230, 230, 265, 230, 230, 265,
+
+ 863, 862, 410, 230, 414, 230, 230, 411, 398, 230,
+ 823, 230, 230, 230, 861, 230, 230, 230, 412, 230,
+ 230, 860, 820, 427, 413, 266, 267, 268, 266, 819,
+ 260, 268, 267, 268, 268, 818, 265, 817, 265, 265,
+ 415, 265, 265, 265, 265, 265, 265, 265, 859, 265,
+ 261, 265, 265, 815, 265, 416, 419, 426, 421, 265,
+ 428, 265, 265, 430, 265, 265, 422, 265, 265, 265,
+ 265, 432, 265, 814, 429, 265, 436, 265, 265, 813,
+ 265, 828, 433, 827, 431, 439, 435, 265, 437, 265,
+ 265, 265, 265, 438, 265, 294, 265, 199, 294, 265,
+
+ 199, 265, 440, 826, 265, 265, 441, 265, 265, 442,
+ 265, 265, 265, 825, 265, 265, 448, 824, 823, 265,
+ 445, 431, 265, 265, 822, 443, 265, 303, 304, 305,
+ 303, 475, 446, 449, 476, 821, 340, 340, 447, 340,
+ 340, 341, 342, 343, 341, 820, 348, 349, 451, 348,
+ 819, 348, 349, 450, 348, 509, 510, 511, 509, 818,
+ 511, 452, 517, 518, 817, 517, 519, 520, 816, 519,
+ 384, 385, 815, 384, 814, 230, 346, 230, 230, 265,
+ 813, 346, 265, 230, 521, 230, 230, 230, 812, 230,
+ 230, 230, 265, 230, 230, 265, 230, 265, 230, 230,
+
+ 265, 230, 512, 230, 230, 522, 265, 567, 382, 265,
+ 523, 525, 382, 418, 553, 811, 221, 230, 524, 230,
+ 230, 810, 809, 230, 526, 230, 230, 230, 808, 230,
+ 230, 230, 528, 230, 230, 742, 807, 806, 527, 230,
+ 529, 230, 230, 230, 739, 230, 230, 230, 805, 230,
+ 230, 230, 532, 230, 230, 804, 230, 530, 230, 230,
+ 230, 531, 230, 230, 803, 230, 533, 230, 230, 535,
+ 536, 230, 265, 230, 230, 265, 265, 534, 537, 265,
+ 802, 230, 538, 230, 230, 230, 734, 230, 230, 230,
+ 733, 230, 230, 230, 732, 230, 230, 558, 561, 540,
+
+ 539, 230, 265, 230, 230, 265, 230, 731, 230, 230,
+ 230, 552, 230, 230, 801, 541, 543, 544, 729, 542,
+ 546, 510, 230, 546, 547, 728, 230, 547, 230, 800,
+ 230, 230, 230, 799, 230, 230, 230, 798, 230, 230,
+ 230, 545, 230, 230, 265, 265, 265, 265, 265, 265,
+ 265, 265, 749, 265, 265, 265, 411, 748, 265, 559,
+ 556, 265, 747, 265, 265, 549, 265, 554, 560, 548,
+ 746, 745, 550, 555, 557, 744, 265, 265, 551, 265,
+ 265, 265, 564, 562, 265, 563, 265, 265, 265, 265,
+ 265, 265, 265, 265, 566, 265, 265, 265, 569, 568,
+
+ 265, 265, 265, 565, 265, 265, 571, 570, 265, 743,
+ 742, 265, 294, 575, 199, 294, 574, 199, 741, 572,
+ 740, 577, 510, 573, 577, 578, 265, 265, 578, 265,
+ 265, 265, 265, 265, 265, 265, 265, 739, 265, 576,
+ 448, 265, 509, 510, 511, 509, 738, 511, 737, 509,
+ 510, 445, 509, 449, 511, 639, 736, 511, 639, 517,
+ 518, 735, 517, 580, 519, 520, 734, 519, 265, 581,
+ 579, 265, 230, 450, 230, 230, 582, 230, 733, 230,
+ 230, 230, 265, 230, 230, 265, 732, 642, 643, 512,
+ 230, 695, 230, 230, 230, 265, 230, 230, 265, 512,
+
+ 640, 230, 731, 230, 230, 221, 645, 730, 676, 644,
+ 221, 230, 729, 230, 230, 230, 728, 230, 230, 648,
+ 646, 727, 230, 674, 230, 230, 647, 230, 726, 230,
+ 230, 230, 725, 230, 230, 230, 265, 230, 230, 265,
+ 724, 265, 649, 650, 265, 230, 651, 230, 230, 723,
+ 653, 230, 675, 230, 230, 722, 672, 652, 654, 655,
+ 230, 721, 230, 230, 230, 720, 230, 230, 656, 230,
+ 632, 230, 230, 230, 719, 230, 230, 230, 718, 230,
+ 230, 230, 265, 230, 230, 265, 659, 717, 660, 265,
+ 657, 658, 265, 673, 230, 661, 230, 230, 230, 716,
+
+ 230, 230, 230, 715, 230, 230, 663, 230, 714, 230,
+ 230, 230, 265, 230, 230, 265, 679, 547, 664, 230,
+ 547, 662, 546, 510, 230, 546, 230, 683, 230, 230,
+ 665, 230, 625, 230, 230, 230, 624, 230, 230, 670,
+ 265, 230, 670, 265, 265, 265, 265, 265, 265, 265,
+ 265, 713, 678, 265, 666, 265, 265, 265, 265, 265,
+ 265, 712, 548, 711, 685, 677, 680, 669, 684, 681,
+ 265, 667, 682, 265, 668, 710, 265, 265, 686, 265,
+ 265, 709, 265, 687, 671, 265, 265, 708, 265, 265,
+ 689, 265, 265, 690, 265, 265, 265, 265, 688, 265,
+
+ 691, 617, 693, 577, 510, 707, 577, 578, 694, 265,
+ 578, 265, 265, 265, 265, 692, 265, 700, 639, 639,
+ 700, 639, 639, 230, 706, 230, 230, 230, 265, 230,
+ 230, 265, 230, 265, 230, 230, 265, 705, 704, 696,
+ 751, 775, 230, 699, 230, 230, 703, 702, 265, 750,
+ 753, 265, 579, 641, 697, 638, 698, 752, 230, 774,
+ 230, 230, 701, 640, 640, 230, 754, 230, 230, 230,
+ 637, 230, 230, 776, 636, 230, 755, 230, 230, 230,
+ 635, 230, 230, 756, 634, 633, 230, 757, 230, 230,
+ 230, 632, 230, 230, 758, 631, 630, 230, 759, 230,
+
+ 230, 230, 629, 230, 230, 230, 628, 230, 230, 230,
+ 627, 230, 230, 230, 626, 230, 230, 230, 265, 230,
+ 230, 265, 230, 760, 230, 230, 761, 625, 624, 230,
+ 764, 230, 230, 230, 265, 230, 230, 265, 623, 230,
+ 762, 230, 230, 230, 763, 230, 230, 767, 230, 622,
+ 230, 230, 765, 766, 621, 230, 620, 230, 230, 230,
+ 784, 230, 230, 230, 619, 230, 230, 230, 618, 230,
+ 230, 230, 617, 230, 230, 768, 769, 670, 616, 230,
+ 670, 230, 265, 230, 230, 265, 265, 615, 265, 265,
+ 777, 265, 265, 614, 778, 265, 770, 265, 265, 771,
+
+ 265, 265, 772, 779, 265, 780, 781, 265, 265, 613,
+ 612, 265, 782, 785, 265, 265, 783, 265, 265, 611,
+ 265, 265, 671, 265, 265, 265, 773, 265, 265, 265,
+ 265, 265, 265, 788, 265, 265, 610, 265, 265, 791,
+ 265, 265, 265, 265, 265, 265, 265, 786, 787, 790,
+ 789, 265, 700, 265, 265, 700, 265, 265, 265, 609,
+ 265, 265, 793, 230, 792, 230, 230, 230, 478, 230,
+ 230, 829, 608, 607, 230, 830, 230, 230, 230, 794,
+ 230, 230, 831, 795, 796, 230, 606, 230, 230, 230,
+ 605, 230, 230, 230, 604, 230, 230, 701, 230, 603,
+
+ 230, 230, 797, 230, 602, 230, 230, 230, 601, 230,
+ 230, 230, 832, 230, 230, 230, 600, 230, 230, 833,
+ 599, 598, 230, 834, 230, 230, 230, 597, 230, 230,
+ 835, 596, 595, 230, 836, 230, 230, 230, 594, 230,
+ 230, 230, 593, 230, 230, 230, 265, 230, 230, 265,
+ 230, 592, 230, 230, 838, 591, 590, 837, 839, 230,
+ 589, 230, 230, 230, 588, 230, 230, 230, 587, 230,
+ 230, 230, 840, 230, 230, 230, 265, 230, 230, 265,
+ 265, 586, 265, 265, 844, 265, 265, 585, 845, 265,
+ 846, 265, 265, 265, 265, 265, 265, 584, 265, 265,
+
+ 842, 265, 265, 265, 583, 841, 265, 848, 516, 847,
+ 515, 849, 265, 843, 265, 265, 265, 265, 265, 265,
+ 850, 265, 851, 265, 265, 265, 265, 265, 265, 265,
+ 514, 265, 265, 854, 265, 375, 853, 265, 852, 513,
+ 265, 265, 855, 265, 265, 871, 265, 230, 871, 230,
+ 230, 230, 508, 230, 230, 230, 507, 230, 230, 230,
+ 506, 230, 230, 230, 265, 230, 230, 265, 505, 230,
+ 857, 230, 230, 856, 230, 504, 230, 230, 230, 874,
+ 230, 230, 265, 858, 230, 265, 230, 230, 503, 502,
+ 872, 230, 875, 230, 230, 230, 501, 230, 230, 876,
+
+ 230, 500, 230, 230, 230, 499, 230, 230, 877, 879,
+ 878, 230, 879, 230, 265, 230, 230, 265, 265, 265,
+ 265, 265, 265, 265, 265, 265, 265, 265, 265, 265,
+ 265, 498, 265, 265, 883, 265, 265, 497, 882, 265,
+ 884, 496, 265, 495, 885, 265, 881, 887, 886, 265,
+ 887, 494, 265, 871, 880, 871, 871, 896, 871, 230,
+ 896, 230, 230, 230, 493, 230, 230, 898, 230, 492,
+ 230, 230, 230, 491, 230, 230, 230, 265, 230, 230,
+ 265, 879, 889, 230, 879, 230, 265, 230, 230, 265,
+ 490, 901, 888, 230, 901, 489, 265, 488, 872, 265,
+
+ 872, 487, 897, 265, 903, 486, 265, 265, 899, 887,
+ 265, 265, 887, 906, 265, 896, 906, 896, 896, 230,
+ 896, 230, 230, 485, 484, 230, 880, 230, 230, 265,
+ 900, 230, 265, 230, 230, 901, 902, 230, 901, 904,
+ 230, 265, 230, 230, 265, 265, 906, 265, 265, 906,
+ 265, 342, 265, 483, 888, 265, 905, 482, 907, 481,
+ 897, 480, 897, 230, 911, 230, 230, 230, 265, 230,
+ 230, 265, 479, 230, 913, 230, 230, 477, 265, 265,
+ 902, 265, 265, 474, 230, 912, 230, 230, 473, 472,
+ 471, 907, 914, 230, 470, 230, 230, 265, 469, 468,
+
+ 265, 929, 917, 467, 466, 930, 230, 918, 230, 230,
+ 265, 465, 464, 265, 926, 921, 461, 460, 459, 925,
+ 922, 51, 51, 51, 51, 51, 51, 56, 56, 56,
+ 56, 56, 56, 63, 63, 63, 63, 63, 63, 68,
+ 68, 68, 68, 68, 68, 158, 158, 158, 158, 158,
+ 158, 163, 163, 163, 163, 163, 163, 199, 199, 456,
+ 199, 199, 199, 209, 209, 209, 209, 209, 209, 212,
+ 455, 454, 453, 212, 212, 214, 214, 214, 214, 214,
+ 214, 220, 220, 308, 304, 220, 220, 226, 226, 226,
+ 227, 226, 226, 229, 229, 383, 229, 229, 229, 255,
+
+ 255, 382, 255, 255, 255, 265, 265, 221, 217, 381,
+ 265, 294, 294, 213, 294, 294, 294, 339, 339, 208,
+ 380, 379, 339, 344, 344, 344, 344, 344, 344, 417,
+ 417, 378, 377, 376, 417, 444, 444, 207, 444, 444,
+ 444, 202, 201, 374, 371, 370, 369, 368, 367, 366,
+ 365, 364, 363, 362, 361, 358, 357, 356, 353, 352,
+ 351, 350, 169, 342, 334, 333, 330, 329, 328, 325,
+ 324, 323, 318, 314, 313, 312, 309, 308, 306, 302,
+ 297, 296, 292, 291, 290, 287, 286, 285, 280, 276,
+ 275, 274, 271, 270, 231, 228, 227, 225, 222, 221,
+
+ 217, 213, 208, 207, 202, 201, 191, 190, 189, 186,
+ 185, 184, 179, 175, 174, 173, 170, 169, 168, 931,
+ 19, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ 931, 931, 931, 931, 931, 931, 931, 931, 931
} ;
-static yyconst flex_int16_t yy_chk[2138] =
+static yyconst short int yy_chk[2370] =
{ 0,
- 0, 1, 1, 1, 1, 824, 1, 0, 1, 7,
- 7, 21, 1, 1, 21, 1, 8, 8, 1, 26,
- 1, 800, 1, 1, 1, 1, 26, 1, 1, 68,
- 1, 68, 68, 1, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 3, 3, 3, 3, 4, 4, 4, 4,
- 4, 5, 5, 6, 6, 15, 15, 15, 15, 4,
-
- 15, 16, 16, 16, 16, 31, 16, 32, 17, 17,
- 30, 35, 42, 30, 18, 18, 46, 30, 46, 31,
- 51, 51, 51, 35, 32, 45, 42, 4, 797, 59,
- 63, 5, 106, 6, 105, 63, 5, 17, 6, 9,
- 9, 9, 9, 18, 9, 45, 9, 109, 105, 106,
- 9, 9, 71, 9, 71, 71, 9, 59, 9, 109,
- 9, 9, 9, 9, 796, 9, 9, 86, 9, 86,
- 86, 9, 10, 10, 10, 10, 10, 10, 10, 10,
- 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
- 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
-
- 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
- 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
- 11, 11, 11, 11, 136, 11, 72, 11, 72, 72,
- 208, 11, 11, 72, 11, 208, 136, 11, 100, 11,
- 793, 11, 11, 11, 11, 100, 11, 11, 87, 11,
- 87, 87, 11, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-
- 12, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 7,
+ 7, 2, 2, 948, 5, 5, 2, 3, 3, 3,
+ 3, 4, 4, 4, 4, 4, 6, 6, 927, 2,
+ 8, 8, 17, 17, 4, 15, 15, 15, 15, 34,
+ 15, 16, 16, 16, 16, 2, 16, 2, 21, 2,
+ 27, 21, 2, 2, 5, 33, 34, 27, 38, 5,
+
+ 31, 17, 4, 31, 924, 123, 6, 31, 123, 33,
+ 38, 6, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 10, 18, 18, 10, 10, 45, 48, 49, 10, 49,
+ 54, 54, 54, 59, 59, 59, 59, 66, 923, 45,
+ 113, 10, 66, 128, 125, 71, 48, 71, 71, 74,
+ 18, 74, 74, 75, 113, 75, 75, 10, 125, 10,
+
+ 75, 10, 920, 128, 10, 10, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 12, 62, 114, 12, 12, 919,
+ 107, 111, 12, 76, 111, 76, 76, 107, 111, 77,
+ 118, 77, 77, 114, 137, 12, 78, 76, 78, 78,
+ 143, 137, 118, 62, 90, 77, 90, 90, 129, 78,
+ 129, 12, 77, 12, 143, 12, 916, 90, 12, 12,
+
13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 14,
- 792, 114, 14, 14, 114, 119, 144, 14, 56, 56,
- 56, 56, 73, 116, 73, 73, 74, 132, 74, 74,
- 14, 75, 789, 75, 75, 119, 144, 116, 73, 74,
- 76, 132, 76, 76, 133, 73, 14, 788, 14, 104,
- 14, 75, 104, 14, 14, 39, 104, 146, 39, 39,
-
- 146, 133, 77, 39, 77, 77, 78, 76, 78, 78,
- 120, 79, 120, 79, 79, 78, 77, 151, 155, 77,
- 79, 155, 80, 77, 80, 80, 185, 185, 81, 78,
- 81, 81, 39, 82, 39, 82, 82, 79, 127, 39,
- 39, 83, 141, 83, 83, 127, 151, 80, 81, 82,
- 83, 84, 782, 84, 84, 85, 141, 85, 85, 189,
- 88, 82, 88, 88, 84, 89, 204, 89, 89, 88,
- 90, 781, 90, 90, 91, 772, 91, 91, 92, 189,
- 92, 92, 93, 88, 93, 93, 308, 308, 85, 95,
- 95, 95, 95, 769, 204, 91, 97, 97, 97, 97,
-
- 113, 113, 113, 113, 122, 122, 122, 122, 89, 92,
- 90, 92, 145, 131, 145, 91, 131, 153, 767, 753,
- 131, 140, 140, 140, 140, 312, 751, 93, 147, 147,
- 147, 147, 154, 154, 175, 154, 182, 175, 182, 196,
- 196, 196, 201, 201, 201, 312, 153, 210, 210, 214,
- 210, 214, 214, 215, 748, 215, 215, 217, 247, 217,
- 217, 247, 154, 218, 217, 218, 218, 219, 746, 219,
- 219, 220, 218, 220, 220, 221, 745, 221, 221, 222,
- 744, 222, 222, 223, 221, 223, 223, 219, 224, 320,
- 224, 224, 222, 210, 721, 220, 223, 225, 720, 225,
-
- 225, 226, 718, 226, 226, 227, 717, 227, 227, 228,
- 257, 228, 228, 257, 229, 224, 229, 229, 320, 230,
- 225, 230, 230, 257, 715, 253, 226, 227, 253, 231,
- 228, 231, 231, 709, 253, 708, 230, 232, 231, 232,
- 232, 233, 229, 233, 233, 234, 256, 234, 234, 256,
- 235, 233, 235, 235, 236, 256, 236, 236, 707, 237,
- 234, 237, 237, 706, 705, 232, 238, 235, 238, 238,
- 235, 239, 704, 239, 239, 240, 703, 240, 240, 241,
- 702, 241, 241, 242, 701, 242, 242, 243, 236, 243,
- 243, 245, 242, 245, 245, 239, 239, 244, 700, 244,
-
- 244, 246, 252, 246, 246, 252, 240, 254, 243, 252,
- 254, 699, 241, 248, 248, 248, 248, 250, 250, 250,
- 250, 255, 258, 259, 255, 258, 259, 254, 243, 260,
- 660, 658, 260, 245, 244, 258, 261, 262, 657, 261,
- 262, 263, 656, 264, 263, 255, 264, 655, 265, 654,
- 259, 265, 260, 267, 266, 269, 267, 266, 269, 262,
- 652, 261, 263, 266, 268, 265, 270, 268, 650, 270,
- 269, 264, 271, 274, 268, 271, 274, 273, 649, 273,
- 273, 267, 273, 270, 275, 276, 270, 275, 276, 278,
- 277, 279, 278, 277, 279, 648, 642, 274, 274, 277,
-
- 280, 281, 305, 280, 281, 305, 271, 641, 640, 639,
- 278, 282, 282, 282, 282, 275, 315, 316, 276, 315,
- 316, 317, 317, 317, 317, 638, 322, 322, 279, 322,
- 278, 324, 324, 637, 324, 346, 346, 347, 346, 636,
- 347, 635, 280, 353, 353, 634, 353, 354, 354, 633,
- 354, 355, 355, 632, 355, 357, 322, 357, 357, 631,
- 358, 324, 358, 358, 359, 383, 359, 359, 383, 360,
- 630, 360, 360, 361, 629, 361, 361, 357, 362, 628,
- 362, 362, 347, 358, 360, 384, 627, 362, 384, 353,
- 626, 359, 384, 354, 361, 625, 363, 355, 363, 363,
-
- 364, 624, 364, 364, 365, 623, 365, 365, 366, 363,
- 366, 366, 367, 572, 367, 367, 368, 388, 368, 368,
- 388, 407, 364, 365, 407, 367, 368, 369, 390, 369,
- 369, 390, 388, 370, 366, 370, 370, 390, 571, 371,
- 369, 371, 371, 372, 370, 372, 372, 373, 385, 373,
- 373, 385, 374, 371, 374, 374, 569, 375, 568, 375,
- 375, 376, 389, 376, 376, 389, 407, 374, 375, 372,
- 385, 566, 565, 373, 377, 377, 377, 377, 378, 564,
- 378, 378, 379, 389, 379, 379, 380, 387, 380, 380,
- 387, 381, 376, 381, 381, 382, 562, 382, 382, 386,
-
- 391, 561, 386, 391, 392, 393, 394, 392, 393, 394,
- 380, 560, 395, 391, 387, 395, 559, 397, 396, 379,
- 397, 396, 386, 378, 393, 395, 392, 381, 396, 558,
- 397, 398, 394, 382, 398, 399, 400, 401, 399, 400,
- 401, 402, 398, 403, 402, 404, 403, 555, 404, 399,
- 405, 554, 405, 405, 403, 405, 402, 406, 406, 553,
- 406, 408, 400, 401, 408, 409, 410, 411, 409, 410,
- 411, 412, 552, 550, 412, 410, 404, 413, 434, 434,
- 413, 434, 435, 460, 460, 435, 460, 462, 411, 409,
- 462, 466, 468, 468, 466, 468, 470, 470, 408, 470,
-
- 472, 499, 472, 472, 499, 549, 498, 412, 411, 498,
- 474, 472, 474, 474, 548, 413, 473, 498, 473, 473,
- 475, 500, 475, 475, 500, 515, 474, 435, 515, 499,
- 547, 476, 462, 476, 476, 545, 466, 500, 468, 476,
- 501, 515, 470, 501, 473, 477, 475, 477, 477, 478,
- 544, 478, 478, 479, 502, 479, 479, 502, 480, 543,
- 480, 480, 502, 542, 541, 481, 501, 481, 481, 540,
- 478, 480, 477, 481, 482, 539, 482, 482, 483, 479,
- 483, 483, 482, 484, 538, 484, 484, 485, 506, 485,
- 485, 506, 486, 537, 486, 486, 487, 536, 487, 487,
-
- 485, 506, 535, 534, 483, 484, 486, 488, 533, 488,
- 488, 489, 532, 489, 489, 488, 490, 505, 490, 490,
- 505, 531, 491, 487, 491, 491, 530, 489, 492, 492,
- 492, 492, 493, 503, 493, 493, 503, 529, 494, 490,
- 494, 494, 495, 505, 495, 495, 496, 528, 496, 496,
- 497, 504, 497, 497, 504, 507, 508, 527, 507, 508,
- 503, 526, 525, 507, 508, 491, 509, 510, 511, 509,
- 510, 511, 504, 512, 524, 467, 512, 493, 496, 513,
- 465, 511, 513, 494, 464, 495, 463, 512, 514, 510,
- 516, 514, 509, 516, 517, 497, 514, 517, 518, 518,
-
- 519, 518, 520, 519, 459, 520, 513, 521, 522, 523,
- 521, 522, 523, 516, 546, 570, 458, 546, 570, 573,
- 457, 573, 573, 574, 456, 574, 574, 575, 455, 575,
- 575, 576, 573, 576, 576, 575, 454, 517, 453, 576,
- 522, 577, 452, 577, 577, 519, 451, 520, 574, 578,
- 521, 578, 578, 579, 523, 579, 579, 578, 450, 546,
- 570, 579, 580, 449, 580, 580, 581, 448, 581, 581,
- 580, 582, 447, 582, 582, 583, 446, 583, 583, 584,
- 445, 584, 584, 585, 444, 585, 585, 586, 443, 586,
- 586, 581, 442, 441, 587, 586, 587, 587, 440, 588,
-
- 602, 588, 588, 602, 439, 598, 584, 588, 598, 589,
- 585, 589, 589, 590, 587, 590, 590, 591, 598, 591,
- 591, 592, 438, 592, 592, 593, 437, 593, 593, 594,
- 436, 594, 594, 595, 599, 595, 595, 599, 591, 596,
- 590, 596, 596, 597, 600, 597, 597, 600, 601, 433,
- 606, 601, 600, 606, 603, 432, 601, 603, 592, 599,
- 604, 594, 603, 604, 595, 431, 605, 607, 604, 605,
- 607, 430, 429, 608, 605, 606, 608, 609, 610, 611,
- 609, 610, 611, 612, 596, 428, 612, 611, 597, 613,
- 614, 615, 613, 614, 615, 616, 617, 613, 616, 617,
-
- 427, 426, 425, 612, 609, 610, 618, 619, 424, 618,
- 619, 620, 621, 423, 620, 621, 616, 622, 615, 661,
- 622, 661, 661, 662, 422, 662, 662, 661, 421, 420,
- 419, 662, 663, 617, 663, 663, 418, 417, 664, 619,
- 664, 664, 620, 665, 416, 665, 665, 666, 415, 666,
- 666, 667, 680, 667, 667, 680, 668, 621, 668, 668,
- 680, 414, 622, 669, 668, 669, 669, 670, 352, 670,
- 670, 669, 351, 350, 671, 670, 671, 671, 672, 349,
- 672, 672, 673, 348, 673, 673, 674, 345, 674, 674,
- 675, 672, 675, 675, 674, 676, 344, 676, 676, 677,
-
- 343, 677, 677, 675, 678, 342, 678, 678, 679, 681,
- 679, 679, 681, 682, 341, 683, 682, 681, 683, 684,
- 685, 686, 684, 685, 686, 687, 688, 689, 687, 688,
- 689, 340, 677, 687, 688, 689, 690, 676, 691, 690,
- 692, 691, 693, 692, 694, 693, 678, 694, 339, 695,
- 693, 691, 695, 696, 338, 697, 696, 694, 697, 698,
- 719, 337, 698, 719, 722, 336, 722, 722, 723, 335,
- 723, 723, 724, 334, 724, 724, 725, 333, 725, 725,
- 726, 733, 726, 726, 733, 727, 696, 727, 727, 332,
- 331, 695, 728, 727, 728, 728, 729, 697, 729, 729,
-
- 730, 330, 730, 730, 729, 719, 730, 731, 329, 731,
- 731, 732, 734, 732, 732, 734, 735, 736, 737, 735,
- 736, 737, 738, 739, 740, 738, 739, 740, 741, 328,
- 738, 741, 740, 742, 741, 743, 742, 747, 743, 752,
- 747, 327, 752, 754, 732, 755, 754, 755, 755, 326,
- 319, 756, 731, 756, 756, 757, 314, 757, 757, 758,
- 313, 758, 758, 759, 311, 759, 759, 760, 743, 760,
- 760, 761, 762, 763, 761, 762, 763, 764, 742, 310,
- 764, 309, 747, 765, 752, 306, 765, 757, 754, 766,
- 768, 771, 766, 768, 771, 304, 773, 303, 773, 773,
-
- 774, 302, 774, 774, 758, 763, 301, 775, 759, 775,
- 775, 776, 760, 776, 776, 777, 778, 779, 777, 778,
- 779, 780, 764, 785, 780, 785, 785, 300, 765, 773,
- 784, 299, 784, 784, 766, 768, 771, 786, 787, 298,
- 786, 787, 790, 791, 790, 790, 791, 794, 777, 794,
- 794, 795, 775, 297, 795, 798, 776, 798, 798, 296,
- 295, 294, 779, 798, 799, 293, 780, 799, 802, 784,
- 802, 802, 799, 292, 803, 291, 786, 803, 290, 289,
- 288, 287, 794, 284, 790, 791, 795, 805, 805, 805,
- 805, 805, 805, 806, 806, 806, 806, 806, 806, 807,
-
- 807, 807, 807, 807, 807, 808, 808, 808, 808, 808,
- 808, 809, 809, 809, 809, 809, 809, 810, 810, 810,
- 810, 810, 810, 811, 811, 811, 811, 811, 811, 812,
- 812, 812, 812, 812, 812, 813, 813, 813, 813, 813,
- 813, 814, 814, 211, 814, 814, 814, 815, 815, 815,
- 815, 815, 815, 816, 209, 206, 205, 816, 816, 817,
- 817, 817, 817, 817, 817, 818, 818, 203, 202, 818,
- 818, 819, 819, 819, 200, 819, 819, 820, 820, 195,
- 820, 820, 820, 821, 821, 191, 821, 821, 821, 822,
- 822, 190, 188, 187, 822, 823, 823, 186, 823, 823,
-
- 823, 825, 825, 183, 181, 180, 825, 826, 826, 826,
- 826, 826, 826, 827, 827, 176, 174, 173, 827, 828,
- 828, 172, 828, 828, 828, 171, 170, 169, 168, 167,
- 166, 165, 164, 163, 162, 161, 160, 159, 158, 157,
- 149, 143, 142, 139, 138, 137, 135, 134, 130, 129,
- 128, 126, 124, 121, 118, 117, 112, 111, 110, 108,
- 107, 103, 102, 101, 99, 70, 67, 65, 64, 62,
- 60, 58, 55, 50, 47, 44, 43, 38, 37, 36,
- 34, 33, 29, 28, 27, 25, 23, 19, 804, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
-
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 804, 804, 804, 804,
- 804, 804, 804, 804, 804, 804, 804
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 14, 915,
+ 144, 14, 14, 156, 163, 79, 14, 79, 79, 80,
+ 148, 80, 80, 81, 909, 81, 81, 144, 82, 14,
+ 82, 82, 148, 156, 908, 79, 86, 81, 86, 86,
+ 81, 153, 82, 163, 81, 14, 80, 14, 85, 14,
+ 85, 85, 14, 14, 42, 153, 86, 42, 42, 200,
+
+ 200, 83, 42, 83, 83, 157, 84, 157, 84, 84,
+ 83, 174, 165, 85, 87, 84, 87, 87, 88, 158,
+ 88, 88, 158, 897, 83, 174, 89, 167, 89, 89,
+ 167, 42, 84, 42, 88, 89, 178, 87, 42, 42,
+ 91, 165, 91, 91, 894, 92, 88, 92, 92, 93,
+ 178, 93, 93, 94, 891, 94, 94, 95, 204, 95,
+ 95, 96, 94, 96, 96, 97, 190, 97, 97, 190,
+ 890, 219, 98, 91, 98, 98, 94, 99, 204, 99,
+ 99, 101, 101, 101, 101, 872, 97, 103, 103, 103,
+ 103, 122, 122, 122, 122, 131, 131, 131, 131, 219,
+
+ 95, 96, 870, 98, 141, 98, 97, 141, 197, 866,
+ 197, 141, 152, 152, 152, 152, 159, 159, 159, 159,
+ 166, 166, 99, 166, 211, 211, 211, 216, 216, 216,
+ 223, 225, 225, 336, 225, 223, 229, 865, 229, 229,
+ 230, 863, 230, 230, 232, 265, 232, 232, 265, 862,
+ 166, 232, 233, 336, 233, 233, 234, 861, 234, 234,
+ 235, 860, 235, 235, 236, 234, 236, 236, 238, 313,
+ 238, 238, 233, 237, 344, 237, 237, 225, 332, 332,
+ 235, 238, 237, 313, 239, 859, 239, 239, 236, 240,
+ 272, 240, 240, 272, 828, 827, 237, 239, 241, 272,
+
+ 241, 241, 242, 344, 242, 242, 243, 241, 243, 243,
+ 244, 275, 244, 244, 275, 245, 240, 245, 245, 317,
+ 275, 241, 242, 246, 825, 246, 246, 247, 824, 247,
+ 247, 243, 244, 317, 275, 270, 245, 248, 270, 248,
+ 248, 822, 270, 821, 247, 249, 248, 249, 249, 816,
+ 250, 246, 250, 250, 812, 251, 249, 251, 251, 252,
+ 284, 252, 252, 284, 253, 251, 253, 253, 254, 276,
+ 254, 254, 276, 255, 252, 255, 255, 256, 250, 256,
+ 256, 253, 276, 257, 253, 257, 257, 258, 284, 258,
+ 258, 259, 811, 259, 259, 260, 278, 260, 260, 278,
+
+ 810, 809, 254, 262, 260, 262, 262, 257, 257, 261,
+ 808, 261, 261, 263, 807, 263, 263, 264, 258, 264,
+ 264, 806, 805, 278, 259, 266, 266, 266, 266, 804,
+ 261, 268, 268, 268, 268, 803, 271, 802, 273, 271,
+ 262, 273, 274, 280, 277, 274, 280, 277, 801, 282,
+ 261, 279, 282, 800, 279, 263, 271, 277, 273, 281,
+ 279, 283, 281, 280, 283, 288, 274, 286, 288, 285,
+ 286, 282, 285, 799, 279, 289, 286, 287, 289, 798,
+ 287, 749, 283, 747, 281, 289, 285, 290, 287, 291,
+ 290, 292, 291, 288, 292, 294, 295, 294, 294, 295,
+
+ 294, 296, 290, 746, 296, 297, 291, 298, 297, 291,
+ 298, 300, 299, 745, 300, 299, 298, 744, 743, 301,
+ 295, 295, 301, 302, 741, 292, 302, 303, 303, 303,
+ 303, 329, 296, 299, 329, 740, 339, 340, 297, 339,
+ 340, 341, 341, 341, 341, 738, 346, 346, 300, 346,
+ 737, 348, 348, 299, 348, 375, 375, 376, 375, 736,
+ 376, 301, 382, 382, 735, 382, 383, 383, 730, 383,
+ 384, 384, 727, 384, 726, 386, 346, 386, 386, 417,
+ 725, 348, 417, 387, 386, 387, 387, 388, 724, 388,
+ 388, 389, 420, 389, 389, 420, 390, 434, 390, 390,
+
+ 434, 391, 376, 391, 391, 387, 418, 434, 382, 418,
+ 388, 390, 383, 418, 420, 723, 384, 392, 389, 392,
+ 392, 722, 721, 393, 391, 393, 393, 394, 720, 394,
+ 394, 395, 393, 395, 395, 719, 718, 717, 392, 396,
+ 394, 396, 396, 397, 716, 397, 397, 398, 715, 398,
+ 398, 399, 397, 399, 399, 714, 400, 395, 400, 400,
+ 401, 396, 401, 401, 713, 402, 398, 402, 402, 400,
+ 401, 403, 428, 403, 403, 428, 425, 399, 402, 425,
+ 712, 404, 403, 404, 404, 405, 711, 405, 405, 406,
+ 710, 406, 406, 407, 709, 407, 407, 425, 428, 405,
+
+ 404, 408, 419, 408, 408, 419, 409, 708, 409, 409,
+ 410, 419, 410, 410, 707, 406, 408, 409, 706, 407,
+ 411, 411, 411, 411, 412, 705, 412, 412, 413, 704,
+ 413, 413, 414, 703, 414, 414, 415, 702, 415, 415,
+ 416, 410, 416, 416, 421, 423, 422, 421, 423, 422,
+ 426, 424, 641, 426, 424, 427, 414, 640, 427, 426,
+ 423, 429, 638, 431, 429, 413, 431, 421, 427, 412,
+ 637, 635, 415, 422, 424, 634, 430, 432, 416, 430,
+ 432, 433, 431, 429, 433, 430, 435, 436, 437, 435,
+ 436, 437, 438, 439, 433, 438, 439, 440, 436, 435,
+
+ 440, 441, 442, 432, 441, 442, 438, 437, 443, 633,
+ 631, 443, 444, 442, 444, 444, 441, 444, 630, 439,
+ 629, 445, 445, 440, 445, 446, 447, 448, 446, 447,
+ 448, 449, 450, 451, 449, 450, 451, 628, 452, 443,
+ 449, 452, 478, 478, 479, 478, 627, 479, 626, 509,
+ 509, 448, 509, 450, 511, 515, 623, 511, 515, 517,
+ 517, 622, 517, 447, 519, 519, 621, 519, 575, 451,
+ 446, 575, 521, 450, 521, 521, 452, 522, 620, 522,
+ 522, 523, 556, 523, 523, 556, 619, 521, 522, 479,
+ 524, 575, 524, 524, 525, 554, 525, 525, 554, 511,
+
+ 515, 526, 618, 526, 526, 517, 524, 616, 556, 523,
+ 519, 527, 615, 527, 527, 528, 614, 528, 528, 527,
+ 525, 613, 529, 554, 529, 529, 526, 530, 612, 530,
+ 530, 531, 611, 531, 531, 532, 555, 532, 532, 555,
+ 609, 552, 528, 529, 552, 533, 530, 533, 533, 608,
+ 532, 534, 555, 534, 534, 607, 552, 531, 533, 534,
+ 535, 606, 535, 535, 536, 605, 536, 536, 535, 537,
+ 604, 537, 537, 538, 603, 538, 538, 539, 602, 539,
+ 539, 540, 553, 540, 540, 553, 538, 601, 539, 559,
+ 536, 537, 559, 553, 541, 540, 541, 541, 542, 600,
+
+ 542, 542, 543, 599, 543, 543, 542, 544, 598, 544,
+ 544, 545, 563, 545, 545, 563, 559, 547, 543, 547,
+ 547, 541, 546, 546, 546, 546, 548, 563, 548, 548,
+ 544, 549, 597, 549, 549, 550, 596, 550, 550, 551,
+ 557, 551, 551, 557, 558, 560, 562, 558, 560, 562,
+ 561, 595, 558, 561, 545, 564, 565, 567, 564, 565,
+ 567, 594, 547, 593, 565, 557, 560, 550, 564, 561,
+ 566, 548, 562, 566, 549, 592, 568, 569, 566, 568,
+ 569, 591, 570, 567, 551, 570, 571, 590, 572, 571,
+ 569, 572, 574, 570, 573, 574, 576, 573, 568, 576,
+
+ 571, 589, 573, 577, 577, 588, 577, 578, 574, 579,
+ 578, 581, 579, 580, 581, 572, 580, 582, 610, 639,
+ 582, 610, 639, 642, 587, 642, 642, 643, 673, 643,
+ 643, 673, 644, 672, 644, 644, 672, 586, 585, 576,
+ 643, 673, 645, 581, 645, 645, 584, 583, 674, 642,
+ 645, 674, 578, 516, 579, 514, 580, 644, 646, 672,
+ 646, 646, 582, 610, 639, 647, 646, 647, 647, 648,
+ 513, 648, 648, 674, 512, 649, 647, 649, 649, 650,
+ 508, 650, 650, 649, 507, 506, 651, 650, 651, 651,
+ 652, 505, 652, 652, 651, 504, 503, 653, 652, 653,
+
+ 653, 654, 502, 654, 654, 655, 501, 655, 655, 656,
+ 500, 656, 656, 657, 499, 657, 657, 658, 678, 658,
+ 658, 678, 659, 653, 659, 659, 654, 498, 497, 660,
+ 659, 660, 660, 661, 683, 661, 661, 683, 496, 662,
+ 657, 662, 662, 663, 658, 663, 663, 662, 664, 495,
+ 664, 664, 660, 661, 494, 665, 493, 665, 665, 666,
+ 683, 666, 666, 667, 492, 667, 667, 668, 491, 668,
+ 668, 669, 490, 669, 669, 664, 665, 670, 489, 670,
+ 670, 671, 675, 671, 671, 675, 676, 488, 684, 676,
+ 675, 684, 677, 487, 676, 677, 666, 679, 680, 668,
+
+ 679, 680, 669, 677, 681, 679, 680, 681, 682, 486,
+ 485, 682, 681, 684, 685, 686, 682, 685, 686, 484,
+ 687, 688, 670, 687, 688, 689, 671, 690, 689, 691,
+ 690, 692, 691, 689, 692, 693, 483, 694, 693, 692,
+ 694, 695, 696, 697, 695, 696, 697, 687, 688, 691,
+ 690, 698, 700, 699, 698, 700, 699, 701, 777, 482,
+ 701, 777, 695, 750, 694, 750, 750, 751, 481, 751,
+ 751, 750, 480, 477, 752, 751, 752, 752, 753, 696,
+ 753, 753, 752, 698, 699, 754, 476, 754, 754, 755,
+ 475, 755, 755, 756, 474, 756, 756, 700, 757, 473,
+
+ 757, 757, 701, 758, 472, 758, 758, 759, 471, 759,
+ 759, 760, 755, 760, 760, 761, 470, 761, 761, 760,
+ 469, 468, 762, 761, 762, 762, 763, 467, 763, 763,
+ 762, 466, 465, 764, 763, 764, 764, 765, 464, 765,
+ 765, 766, 463, 766, 766, 767, 778, 767, 767, 778,
+ 768, 462, 768, 768, 766, 461, 460, 765, 768, 769,
+ 459, 769, 769, 770, 458, 770, 770, 771, 457, 771,
+ 771, 772, 769, 772, 772, 773, 774, 773, 773, 774,
+ 775, 456, 776, 775, 774, 776, 779, 455, 775, 779,
+ 776, 780, 781, 782, 780, 781, 782, 454, 783, 784,
+
+ 771, 783, 784, 785, 453, 770, 785, 784, 381, 779,
+ 380, 785, 786, 772, 787, 786, 788, 787, 789, 788,
+ 786, 789, 787, 790, 791, 792, 790, 791, 792, 793,
+ 379, 794, 793, 792, 794, 378, 790, 795, 789, 377,
+ 795, 796, 793, 797, 796, 826, 797, 829, 826, 829,
+ 829, 830, 374, 830, 830, 831, 373, 831, 831, 832,
+ 372, 832, 832, 833, 844, 833, 833, 844, 371, 834,
+ 795, 834, 834, 794, 835, 370, 835, 835, 836, 832,
+ 836, 836, 845, 796, 837, 845, 837, 837, 369, 368,
+ 826, 838, 837, 838, 838, 839, 367, 839, 839, 838,
+
+ 840, 366, 840, 840, 841, 365, 841, 841, 840, 842,
+ 841, 842, 842, 843, 846, 843, 843, 846, 847, 848,
+ 849, 847, 848, 849, 850, 851, 852, 850, 851, 852,
+ 854, 364, 853, 854, 852, 853, 855, 363, 847, 855,
+ 853, 362, 856, 361, 855, 856, 843, 857, 856, 858,
+ 857, 360, 858, 864, 842, 871, 864, 873, 871, 874,
+ 873, 874, 874, 875, 359, 875, 875, 874, 876, 358,
+ 876, 876, 877, 357, 877, 877, 878, 883, 878, 878,
+ 883, 879, 858, 879, 879, 880, 884, 880, 880, 884,
+ 356, 881, 857, 881, 881, 355, 882, 354, 864, 882,
+
+ 871, 353, 873, 885, 882, 352, 885, 886, 878, 887,
+ 886, 888, 887, 889, 888, 892, 889, 896, 892, 898,
+ 896, 898, 898, 351, 350, 900, 879, 900, 900, 903,
+ 880, 899, 903, 899, 899, 901, 881, 901, 901, 886,
+ 902, 904, 902, 902, 904, 905, 906, 907, 905, 906,
+ 907, 343, 914, 338, 887, 914, 888, 337, 889, 335,
+ 892, 334, 896, 911, 899, 911, 911, 912, 913, 912,
+ 912, 913, 333, 917, 904, 917, 917, 330, 918, 922,
+ 901, 918, 922, 328, 921, 902, 921, 921, 327, 326,
+ 325, 906, 907, 925, 324, 925, 925, 926, 323, 322,
+
+ 926, 925, 911, 321, 320, 926, 929, 913, 929, 929,
+ 930, 319, 318, 930, 922, 917, 316, 315, 314, 921,
+ 918, 932, 932, 932, 932, 932, 932, 933, 933, 933,
+ 933, 933, 933, 934, 934, 934, 934, 934, 934, 935,
+ 935, 935, 935, 935, 935, 936, 936, 936, 936, 936,
+ 936, 937, 937, 937, 937, 937, 937, 938, 938, 312,
+ 938, 938, 938, 939, 939, 939, 939, 939, 939, 940,
+ 311, 310, 309, 940, 940, 941, 941, 941, 941, 941,
+ 941, 942, 942, 308, 305, 942, 942, 943, 943, 943,
+ 226, 943, 943, 944, 944, 224, 944, 944, 944, 945,
+
+ 945, 221, 945, 945, 945, 946, 946, 220, 218, 217,
+ 946, 947, 947, 215, 947, 947, 947, 949, 949, 210,
+ 206, 205, 949, 950, 950, 950, 950, 950, 950, 951,
+ 951, 203, 202, 201, 951, 952, 952, 198, 952, 952,
+ 952, 196, 195, 191, 189, 188, 187, 186, 185, 184,
+ 183, 182, 181, 180, 179, 177, 176, 175, 173, 172,
+ 171, 170, 169, 161, 155, 154, 151, 150, 149, 147,
+ 146, 145, 142, 140, 139, 138, 136, 135, 133, 130,
+ 127, 126, 121, 120, 119, 117, 116, 115, 112, 110,
+ 109, 108, 106, 105, 73, 70, 68, 67, 65, 63,
+
+ 61, 58, 53, 50, 47, 46, 41, 40, 39, 37,
+ 36, 35, 32, 30, 29, 28, 26, 25, 23, 19,
+ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ 931, 931, 931, 931, 931, 931, 931, 931, 931
} ;
-/* Table of booleans, true if rule could match eol. */
-static yyconst flex_int32_t yy_rule_can_match_eol[64] =
- { 0,
-0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0,
- 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 0, 0, };
-
-static yy_state_type yy_last_accepting_state;
-static char *yy_last_accepting_cpos;
-
-extern int yy_flex_debug;
-int yy_flex_debug = 0;
-
-/* The intent behind this definition is that it'll catch
- * any uses of REJECT which flex missed.
- */
-#define REJECT reject_used_but_not_detected
+static yy_state_type yy_state_buf[YY_BUF_SIZE + 2], *yy_state_ptr;
+static char *yy_full_match;
+static int yy_lp;
+#define REJECT \
+{ \
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */ \
+yy_cp = yy_full_match; /* restore poss. backed-over text */ \
+++yy_lp; \
+goto find_rule; \
+}
#define yymore() yymore_used_but_not_detected
#define YY_MORE_ADJ 0
#define YY_RESTORE_YY_MORE_OFFSET
char *yytext;
#line 1 "levcomp.lpp"
+#define INITIAL 0
#line 2 "levcomp.lpp"
// levcomp.lpp:
@@ -1283,39 +1393,24 @@ static void settext(bool trim_right = false, int strip_trailing = 0)
yylval.text = newstring;
}
-
-
-
-
-
-
-
-
-#line 1295 "levcomp.lex.cc"
-
-#define INITIAL 0
#define MAPDEF 1
+
#define LUA 2
+
#define LUA_ONELINER 3
+
#define ARGUMENT 4
+
#define MNAME 5
+
#define KEYWORDS 6
-#define ITEM_LIST 7
-#define TOEOL 8
-#ifndef YY_NO_UNISTD_H
-/* Special case for "unistd.h", since it is non-ANSI. We include it way
- * down here because we want the user's section 1 to have been scanned first.
- * The user has a chance to override it with an option.
- */
-#include <unistd.h>
-#endif
+#define ITEM_LIST 7
-#ifndef YY_EXTRA_TYPE
-#define YY_EXTRA_TYPE void *
-#endif
+#define TOEOL 8
-static int yy_init_globals (void );
+#define YY_NEVER_INTERACTIVE 1
+#line 1403 "levcomp.lex.cc"
/* Macros after this point can all be overridden by user definitions in
* section 1.
@@ -1323,30 +1418,65 @@ static int yy_init_globals (void );
#ifndef YY_SKIP_YYWRAP
#ifdef __cplusplus
-extern "C" int yywrap (void );
+extern "C" int yywrap YY_PROTO(( void ));
#else
-extern int yywrap (void );
+extern int yywrap YY_PROTO(( void ));
#endif
#endif
- static void yyunput (int c,char *buf_ptr );
-
+#ifndef YY_NO_UNPUT
+static void yyunput YY_PROTO(( int c, char *buf_ptr ));
+#endif
+
#ifndef yytext_ptr
-static void yy_flex_strncpy (char *,yyconst char *,int );
+static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
#endif
#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * );
+static int yy_flex_strlen YY_PROTO(( yyconst char * ));
#endif
#ifndef YY_NO_INPUT
-
#ifdef __cplusplus
-static int yyinput (void );
+static int yyinput YY_PROTO(( void ));
+#else
+static int input YY_PROTO(( void ));
+#endif
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO(( int new_state ));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO(( void ));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO(( void ));
+#endif
+
#else
-static int input (void );
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
#endif
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines. This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
#endif
/* Amount of stuff to slurp up with each read. */
@@ -1355,6 +1485,7 @@ static int input (void );
#endif
/* Copy whatever the last rule matched to the standard output. */
+
#ifndef ECHO
/* This used to be an fputs(), but since the string might contain NUL's,
* we now use fwrite().
@@ -1367,10 +1498,9 @@ static int input (void );
*/
#ifndef YY_INPUT
#define YY_INPUT(buf,result,max_size) \
- if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ if ( yy_current_buffer->yy_is_interactive ) \
{ \
- int c = '*'; \
- size_t n; \
+ int c = '*', n; \
for ( n = 0; n < max_size && \
(c = getc( yyin )) != EOF && c != '\n'; ++n ) \
buf[n] = (char) c; \
@@ -1380,22 +1510,9 @@ static int input (void );
YY_FATAL_ERROR( "input in flex scanner failed" ); \
result = n; \
} \
- else \
- { \
- errno=0; \
- while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
- { \
- if( errno != EINTR) \
- { \
- YY_FATAL_ERROR( "input in flex scanner failed" ); \
- break; \
- } \
- errno=0; \
- clearerr(yyin); \
- } \
- }\
-\
-
+ else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
+ && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" );
#endif
/* No semi-colon after return; correct usage is to write "yyterminate();" -
@@ -1416,18 +1533,12 @@ static int input (void );
#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
#endif
-/* end tables serialization structures and prototypes */
-
/* Default declaration of generated scanner - a define so the user can
* easily add parameters.
*/
#ifndef YY_DECL
-#define YY_DECL_IS_OURS 1
-
-extern int yylex (void);
-
-#define YY_DECL int yylex (void)
-#endif /* !YY_DECL */
+#define YY_DECL int yylex YY_PROTO(( void ))
+#endif
/* Code executed at the beginning of each rule, after yytext and yyleng
* have been set up.
@@ -1443,33 +1554,31 @@ extern int yylex (void);
#define YY_RULE_SETUP \
if ( yyleng > 0 ) \
- YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \
+ yy_current_buffer->yy_at_bol = \
(yytext[yyleng - 1] == '\n'); \
YY_USER_ACTION
-/** The main scanner function which does all the work.
- */
YY_DECL
-{
+ {
register yy_state_type yy_current_state;
register char *yy_cp, *yy_bp;
register int yy_act;
-
+
#line 89 "levcomp.lpp"
-#line 1462 "levcomp.lex.cc"
+#line 1560 "levcomp.lex.cc"
- if ( !(yy_init) )
+ if ( yy_init )
{
- (yy_init) = 1;
+ yy_init = 0;
#ifdef YY_USER_INIT
YY_USER_INIT;
#endif
- if ( ! (yy_start) )
- (yy_start) = 1; /* first start state */
+ if ( ! yy_start )
+ yy_start = 1; /* first start state */
if ( ! yyin )
yyin = stdin;
@@ -1477,77 +1586,79 @@ YY_DECL
if ( ! yyout )
yyout = stdout;
- if ( ! YY_CURRENT_BUFFER ) {
- yyensure_buffer_stack ();
- YY_CURRENT_BUFFER_LVALUE =
- yy_create_buffer(yyin,YY_BUF_SIZE );
- }
+ if ( ! yy_current_buffer )
+ yy_current_buffer =
+ yy_create_buffer( yyin, YY_BUF_SIZE );
- yy_load_buffer_state( );
+ yy_load_buffer_state();
}
while ( 1 ) /* loops until end-of-file is reached */
{
- yy_cp = (yy_c_buf_p);
+ yy_cp = yy_c_buf_p;
/* Support of yytext. */
- *yy_cp = (yy_hold_char);
+ *yy_cp = yy_hold_char;
/* yy_bp points to the position in yy_ch_buf of the start of
* the current run.
*/
yy_bp = yy_cp;
- yy_current_state = (yy_start);
+ yy_current_state = yy_start;
yy_current_state += YY_AT_BOL();
+ yy_state_ptr = yy_state_buf;
+ *yy_state_ptr++ = yy_current_state;
yy_match:
do
{
register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
- if ( yy_accept[yy_current_state] )
- {
- (yy_last_accepting_state) = yy_current_state;
- (yy_last_accepting_cpos) = yy_cp;
- }
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 805 )
+ if ( yy_current_state >= 932 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ *yy_state_ptr++ = yy_current_state;
++yy_cp;
}
- while ( yy_current_state != 804 );
- yy_cp = (yy_last_accepting_cpos);
- yy_current_state = (yy_last_accepting_state);
+ while ( yy_base[yy_current_state] != 2321 );
yy_find_action:
- yy_act = yy_accept[yy_current_state];
+ yy_current_state = *--yy_state_ptr;
+ yy_lp = yy_accept[yy_current_state];
+find_rule: /* we branch to this label when backing up */
+ for ( ; ; ) /* until we find what rule we matched */
+ {
+ if ( yy_lp && yy_lp < yy_accept[yy_current_state + 1] )
+ {
+ yy_act = yy_acclist[yy_lp];
+ {
+ yy_full_match = yy_cp;
+ break;
+ }
+ }
+ --yy_cp;
+ yy_current_state = *--yy_state_ptr;
+ yy_lp = yy_accept[yy_current_state];
+ }
YY_DO_BEFORE_ACTION;
- if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
+ if ( yy_act != YY_END_OF_BUFFER )
{
int yyl;
for ( yyl = 0; yyl < yyleng; ++yyl )
if ( yytext[yyl] == '\n' )
-
- yylineno++;
-;
+ ++yylineno;
}
do_action: /* This label is used only to access EOF actions. */
+
switch ( yy_act )
{ /* beginning of action switch */
- case 0: /* must back up */
- /* undo the effects of YY_DO_BEFORE_ACTION */
- *yy_cp = (yy_hold_char);
- yy_cp = (yy_last_accepting_cpos);
- yy_current_state = (yy_last_accepting_state);
- goto yy_find_action;
-
case 1:
YY_RULE_SETUP
#line 91 "levcomp.lpp"
@@ -1562,7 +1673,6 @@ YY_RULE_SETUP
}
YY_BREAK
case 3:
-/* rule 3 can match eol */
YY_RULE_SETUP
#line 98 "levcomp.lpp"
return CHARACTER;
@@ -1578,22 +1688,21 @@ YY_RULE_SETUP
return CHARACTER;
YY_BREAK
case 6:
-/* rule 6 can match eol */
YY_RULE_SETUP
#line 102 "levcomp.lpp"
;
YY_BREAK
case 7:
-*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */
-(yy_c_buf_p) = yy_cp -= 1;
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp -= 1;
YY_DO_BEFORE_ACTION; /* set up yytext again */
YY_RULE_SETUP
#line 104 "levcomp.lpp"
{ BEGIN(INITIAL); }
YY_BREAK
case 8:
-*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */
-(yy_c_buf_p) = yy_cp -= 1;
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp -= 1;
YY_DO_BEFORE_ACTION; /* set up yytext again */
YY_RULE_SETUP
#line 105 "levcomp.lpp"
@@ -1612,14 +1721,13 @@ YY_RULE_SETUP
}
YY_BREAK
case 10:
-/* rule 10 can match eol */
YY_RULE_SETUP
#line 114 "levcomp.lpp"
;
YY_BREAK
case 11:
-*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */
-(yy_c_buf_p) = yy_cp -= 1;
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp -= 1;
YY_DO_BEFORE_ACTION; /* set up yytext again */
YY_RULE_SETUP
#line 116 "levcomp.lpp"
@@ -1629,7 +1737,6 @@ YY_RULE_SETUP
}
YY_BREAK
case 12:
-/* rule 12 can match eol */
YY_RULE_SETUP
#line 120 "levcomp.lpp"
{ BEGIN(INITIAL); }
@@ -1648,7 +1755,6 @@ YY_RULE_SETUP
;
YY_BREAK
case 15:
-/* rule 15 can match eol */
YY_RULE_SETUP
#line 128 "levcomp.lpp"
{ BEGIN(INITIAL); }
@@ -1680,13 +1786,11 @@ YY_RULE_SETUP
;
YY_BREAK
case 20:
-/* rule 20 can match eol */
YY_RULE_SETUP
#line 142 "levcomp.lpp"
{ BEGIN(INITIAL); }
YY_BREAK
case 21:
-/* rule 21 can match eol */
YY_RULE_SETUP
#line 144 "levcomp.lpp"
{ BEGIN(INITIAL); }
@@ -1719,14 +1823,13 @@ YY_RULE_SETUP
}
YY_BREAK
case 26:
-/* rule 26 can match eol */
YY_RULE_SETUP
#line 160 "levcomp.lpp"
{ BEGIN(INITIAL); }
YY_BREAK
case 27:
-*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */
-(yy_c_buf_p) = yy_cp -= 1;
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp -= 1;
YY_DO_BEFORE_ACTION; /* set up yytext again */
YY_RULE_SETUP
#line 162 "levcomp.lpp"
@@ -1736,8 +1839,8 @@ YY_RULE_SETUP
}
YY_BREAK
case 28:
-*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */
-(yy_c_buf_p) = yy_cp -= 1;
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp -= 1;
YY_DO_BEFORE_ACTION; /* set up yytext again */
YY_RULE_SETUP
#line 167 "levcomp.lpp"
@@ -1748,7 +1851,6 @@ YY_RULE_SETUP
}
YY_BREAK
case 29:
-/* rule 29 can match eol */
YY_RULE_SETUP
#line 172 "levcomp.lpp"
;
@@ -1759,8 +1861,8 @@ YY_RULE_SETUP
;
YY_BREAK
case 31:
-*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */
-(yy_c_buf_p) = yy_cp -= 1;
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp -= 1;
YY_DO_BEFORE_ACTION; /* set up yytext again */
YY_RULE_SETUP
#line 176 "levcomp.lpp"
@@ -1849,123 +1951,148 @@ YY_RULE_SETUP
case 48:
YY_RULE_SETUP
#line 197 "levcomp.lpp"
-{ BEGIN(ITEM_LIST); return SUBST; }
+{ BEGIN(ARGUMENT); return LFLAGS; }
YY_BREAK
case 49:
YY_RULE_SETUP
#line 198 "levcomp.lpp"
-{ BEGIN(ITEM_LIST); return NSUBST; }
+{ BEGIN(ARGUMENT); return BFLAGS; }
YY_BREAK
case 50:
YY_RULE_SETUP
#line 199 "levcomp.lpp"
-{ BEGIN(ITEM_LIST); return COLOUR; }
+{ BEGIN(ITEM_LIST); return SUBST; }
YY_BREAK
case 51:
YY_RULE_SETUP
#line 200 "levcomp.lpp"
-{ BEGIN(MNAME); return MONS; }
+{ BEGIN(ITEM_LIST); return NSUBST; }
YY_BREAK
case 52:
YY_RULE_SETUP
#line 201 "levcomp.lpp"
-{ BEGIN(ITEM_LIST); return ITEM; }
+{ BEGIN(ITEM_LIST); return COLOUR; }
YY_BREAK
case 53:
YY_RULE_SETUP
#line 202 "levcomp.lpp"
-{ BEGIN(TOEOL); return MARKER; }
+{ BEGIN(ARGUMENT); return FLOORCOL; }
YY_BREAK
case 54:
YY_RULE_SETUP
#line 203 "levcomp.lpp"
-{ BEGIN(ITEM_LIST); return SHUFFLE; }
+{ BEGIN(ARGUMENT); return ROCKCOL; }
YY_BREAK
case 55:
YY_RULE_SETUP
-#line 205 "levcomp.lpp"
-{ BEGIN(ARGUMENT); return KFEAT; }
+#line 204 "levcomp.lpp"
+{ BEGIN(MNAME); return MONS; }
YY_BREAK
case 56:
YY_RULE_SETUP
-#line 206 "levcomp.lpp"
-{ BEGIN(ARGUMENT); return KITEM; }
+#line 205 "levcomp.lpp"
+{ BEGIN(ITEM_LIST); return ITEM; }
YY_BREAK
case 57:
YY_RULE_SETUP
-#line 207 "levcomp.lpp"
-{ BEGIN(ARGUMENT); return KMONS; }
+#line 206 "levcomp.lpp"
+{ BEGIN(TOEOL); return MARKER; }
YY_BREAK
case 58:
YY_RULE_SETUP
-#line 209 "levcomp.lpp"
-return COMMA;
+#line 207 "levcomp.lpp"
+{ BEGIN(ITEM_LIST); return SHUFFLE; }
YY_BREAK
case 59:
YY_RULE_SETUP
+#line 209 "levcomp.lpp"
+{ BEGIN(ARGUMENT); return KFEAT; }
+ YY_BREAK
+case 60:
+YY_RULE_SETUP
+#line 210 "levcomp.lpp"
+{ BEGIN(ARGUMENT); return KFEAT; }
+ YY_BREAK
+case 61:
+YY_RULE_SETUP
#line 211 "levcomp.lpp"
+{ BEGIN(ARGUMENT); return KITEM; }
+ YY_BREAK
+case 62:
+YY_RULE_SETUP
+#line 212 "levcomp.lpp"
+{ BEGIN(ARGUMENT); return KMASK; }
+ YY_BREAK
+case 63:
+YY_RULE_SETUP
+#line 214 "levcomp.lpp"
+return COMMA;
+ YY_BREAK
+case 64:
+YY_RULE_SETUP
+#line 216 "levcomp.lpp"
{
clean();
yylval.i = atoi(yytext);
return INTEGER;
}
YY_BREAK
-case 60:
+case 65:
YY_RULE_SETUP
-#line 217 "levcomp.lpp"
+#line 222 "levcomp.lpp"
;
YY_BREAK
-case 61:
-/* rule 61 can match eol */
+case 66:
YY_RULE_SETUP
-#line 218 "levcomp.lpp"
+#line 223 "levcomp.lpp"
;
YY_BREAK
-case 62:
+case 67:
+/* rule 61 can match eol */
YY_RULE_SETUP
-#line 219 "levcomp.lpp"
-return CHARACTER;
+#line 224 "levcomp.lpp"
+;
YY_BREAK
-case 63:
+case 68:
YY_RULE_SETUP
-#line 221 "levcomp.lpp"
+#line 226 "levcomp.lpp"
ECHO;
YY_BREAK
-#line 1935 "levcomp.lex.cc"
-case YY_STATE_EOF(INITIAL):
-case YY_STATE_EOF(MAPDEF):
-case YY_STATE_EOF(LUA):
-case YY_STATE_EOF(LUA_ONELINER):
-case YY_STATE_EOF(ARGUMENT):
-case YY_STATE_EOF(MNAME):
-case YY_STATE_EOF(KEYWORDS):
-case YY_STATE_EOF(ITEM_LIST):
-case YY_STATE_EOF(TOEOL):
- yyterminate();
+#line 2050 "levcomp.lex.cc"
+ case YY_STATE_EOF(INITIAL):
+ case YY_STATE_EOF(MAPDEF):
+ case YY_STATE_EOF(LUA):
+ case YY_STATE_EOF(LUA_ONELINER):
+ case YY_STATE_EOF(ARGUMENT):
+ case YY_STATE_EOF(MNAME):
+ case YY_STATE_EOF(KEYWORDS):
+ case YY_STATE_EOF(ITEM_LIST):
+ case YY_STATE_EOF(TOEOL):
+ yyterminate();
case YY_END_OF_BUFFER:
{
/* Amount of text matched not including the EOB char. */
- int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+ int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
/* Undo the effects of YY_DO_BEFORE_ACTION. */
- *yy_cp = (yy_hold_char);
+ *yy_cp = yy_hold_char;
YY_RESTORE_YY_MORE_OFFSET
- if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
{
/* We're scanning a new file or input source. It's
* possible that this happened because the user
* just pointed yyin at a new source and called
* yylex(). If so, then we have to assure
- * consistency between YY_CURRENT_BUFFER and our
+ * consistency between yy_current_buffer and our
* globals. Here is the right place to do so, because
* this is the first action (other than possibly a
* back-up) that will match for the new input source.
*/
- (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
- YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
- YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yy_current_buffer->yy_input_file = yyin;
+ yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
}
/* Note that here we test for yy_c_buf_p "<=" to the position
@@ -1975,13 +2102,13 @@ case YY_STATE_EOF(TOEOL):
* end-of-buffer state). Contrast this with the test
* in input().
*/
- if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
{ /* This was really a NUL. */
yy_state_type yy_next_state;
- (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+ yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
- yy_current_state = yy_get_previous_state( );
+ yy_current_state = yy_get_previous_state();
/* Okay, we're now positioned to make the NUL
* transition. We couldn't have
@@ -1994,31 +2121,30 @@ case YY_STATE_EOF(TOEOL):
yy_next_state = yy_try_NUL_trans( yy_current_state );
- yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
if ( yy_next_state )
{
/* Consume the NUL. */
- yy_cp = ++(yy_c_buf_p);
+ yy_cp = ++yy_c_buf_p;
yy_current_state = yy_next_state;
goto yy_match;
}
else
{
- yy_cp = (yy_last_accepting_cpos);
- yy_current_state = (yy_last_accepting_state);
+ yy_cp = yy_c_buf_p;
goto yy_find_action;
}
}
- else switch ( yy_get_next_buffer( ) )
+ else switch ( yy_get_next_buffer() )
{
case EOB_ACT_END_OF_FILE:
{
- (yy_did_buffer_switch_on_eof) = 0;
+ yy_did_buffer_switch_on_eof = 0;
- if ( yywrap( ) )
+ if ( yywrap() )
{
/* Note: because we've taken care in
* yy_get_next_buffer() to have set up
@@ -2029,7 +2155,7 @@ case YY_STATE_EOF(TOEOL):
* YY_NULL, it'll still work - another
* YY_NULL will get returned.
*/
- (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+ yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
yy_act = YY_STATE_EOF(YY_START);
goto do_action;
@@ -2037,30 +2163,30 @@ case YY_STATE_EOF(TOEOL):
else
{
- if ( ! (yy_did_buffer_switch_on_eof) )
+ if ( ! yy_did_buffer_switch_on_eof )
YY_NEW_FILE;
}
break;
}
case EOB_ACT_CONTINUE_SCAN:
- (yy_c_buf_p) =
- (yytext_ptr) + yy_amount_of_matched_text;
+ yy_c_buf_p =
+ yytext_ptr + yy_amount_of_matched_text;
- yy_current_state = yy_get_previous_state( );
+ yy_current_state = yy_get_previous_state();
- yy_cp = (yy_c_buf_p);
- yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
goto yy_match;
case EOB_ACT_LAST_MATCH:
- (yy_c_buf_p) =
- &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+ yy_c_buf_p =
+ &yy_current_buffer->yy_ch_buf[yy_n_chars];
- yy_current_state = yy_get_previous_state( );
+ yy_current_state = yy_get_previous_state();
- yy_cp = (yy_c_buf_p);
- yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
goto yy_find_action;
}
break;
@@ -2071,7 +2197,8 @@ case YY_STATE_EOF(TOEOL):
"fatal flex scanner internal error--no action found" );
} /* end of action switch */
} /* end of scanning one token */
-} /* end of yylex */
+ } /* end of yylex */
+
/* yy_get_next_buffer - try to read in a new buffer
*
@@ -2080,20 +2207,21 @@ case YY_STATE_EOF(TOEOL):
* EOB_ACT_CONTINUE_SCAN - continue scanning from current position
* EOB_ACT_END_OF_FILE - end of file
*/
-static int yy_get_next_buffer (void)
-{
- register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
- register char *source = (yytext_ptr);
+
+static int yy_get_next_buffer()
+ {
+ register char *dest = yy_current_buffer->yy_ch_buf;
+ register char *source = yytext_ptr;
register int number_to_move, i;
int ret_val;
- if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+ if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
YY_FATAL_ERROR(
"fatal flex scanner internal error--end of buffer missed" );
- if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ if ( yy_current_buffer->yy_fill_buffer == 0 )
{ /* Don't try to fill the buffer, so this is an EOF. */
- if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+ if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
{
/* We matched a single character, the EOB, so
* treat this as a final EOF.
@@ -2113,30 +2241,34 @@ static int yy_get_next_buffer (void)
/* Try to read more data. */
/* First move last chars to start of buffer. */
- number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+ number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
for ( i = 0; i < number_to_move; ++i )
*(dest++) = *(source++);
- if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
/* don't do the read, it's not guaranteed to return an EOF,
* just force an EOF
*/
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+ yy_current_buffer->yy_n_chars = yy_n_chars = 0;
else
{
- int num_to_read =
- YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+ int num_to_read =
+ yy_current_buffer->yy_buf_size - number_to_move - 1;
while ( num_to_read <= 0 )
{ /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+ YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
/* just a shorter name for the current buffer */
- YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+ YY_BUFFER_STATE b = yy_current_buffer;
int yy_c_buf_p_offset =
- (int) ((yy_c_buf_p) - b->yy_ch_buf);
+ (int) (yy_c_buf_p - b->yy_ch_buf);
if ( b->yy_is_our_buffer )
{
@@ -2149,7 +2281,8 @@ static int yy_get_next_buffer (void)
b->yy_ch_buf = (char *)
/* Include room in for 2 EOB chars. */
- yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
+ yy_flex_realloc( (void *) b->yy_ch_buf,
+ b->yy_buf_size + 2 );
}
else
/* Can't grow it, we don't own it. */
@@ -2159,35 +2292,35 @@ static int yy_get_next_buffer (void)
YY_FATAL_ERROR(
"fatal error - scanner input buffer overflow" );
- (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+ yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
- num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ num_to_read = yy_current_buffer->yy_buf_size -
number_to_move - 1;
-
+#endif
}
if ( num_to_read > YY_READ_BUF_SIZE )
num_to_read = YY_READ_BUF_SIZE;
/* Read in more data. */
- YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
- (yy_n_chars), num_to_read );
+ YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+ yy_n_chars, num_to_read );
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ yy_current_buffer->yy_n_chars = yy_n_chars;
}
- if ( (yy_n_chars) == 0 )
+ if ( yy_n_chars == 0 )
{
if ( number_to_move == YY_MORE_ADJ )
{
ret_val = EOB_ACT_END_OF_FILE;
- yyrestart(yyin );
+ yyrestart( yyin );
}
else
{
ret_val = EOB_ACT_LAST_MATCH;
- YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ yy_current_buffer->yy_buffer_status =
YY_BUFFER_EOF_PENDING;
}
}
@@ -2195,142 +2328,149 @@ static int yy_get_next_buffer (void)
else
ret_val = EOB_ACT_CONTINUE_SCAN;
- (yy_n_chars) += number_to_move;
- YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
- YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+ yy_n_chars += number_to_move;
+ yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
- (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+ yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
return ret_val;
-}
+ }
+
/* yy_get_previous_state - get the state just before the EOB char was reached */
- static yy_state_type yy_get_previous_state (void)
-{
+static yy_state_type yy_get_previous_state()
+ {
register yy_state_type yy_current_state;
register char *yy_cp;
-
- yy_current_state = (yy_start);
+
+ yy_current_state = yy_start;
yy_current_state += YY_AT_BOL();
+ yy_state_ptr = yy_state_buf;
+ *yy_state_ptr++ = yy_current_state;
- for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+ for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
{
register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
- if ( yy_accept[yy_current_state] )
- {
- (yy_last_accepting_state) = yy_current_state;
- (yy_last_accepting_cpos) = yy_cp;
- }
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 805 )
+ if ( yy_current_state >= 932 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ *yy_state_ptr++ = yy_current_state;
}
return yy_current_state;
-}
+ }
+
/* yy_try_NUL_trans - try to make a transition on the NUL character
*
* synopsis
* next_state = yy_try_NUL_trans( current_state );
*/
- static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
-{
+
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
+#else
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+yy_state_type yy_current_state;
+#endif
+ {
register int yy_is_jam;
- register char *yy_cp = (yy_c_buf_p);
register YY_CHAR yy_c = 1;
- if ( yy_accept[yy_current_state] )
- {
- (yy_last_accepting_state) = yy_current_state;
- (yy_last_accepting_cpos) = yy_cp;
- }
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 805 )
+ if ( yy_current_state >= 932 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- yy_is_jam = (yy_current_state == 804);
+ yy_is_jam = (yy_current_state == 931);
+ if ( ! yy_is_jam )
+ *yy_state_ptr++ = yy_current_state;
return yy_is_jam ? 0 : yy_current_state;
-}
+ }
- static void yyunput (int c, register char * yy_bp )
-{
- register char *yy_cp;
-
- yy_cp = (yy_c_buf_p);
+
+#ifndef YY_NO_UNPUT
+#ifdef YY_USE_PROTOS
+static void yyunput( int c, register char *yy_bp )
+#else
+static void yyunput( c, yy_bp )
+int c;
+register char *yy_bp;
+#endif
+ {
+ register char *yy_cp = yy_c_buf_p;
/* undo effects of setting up yytext */
- *yy_cp = (yy_hold_char);
+ *yy_cp = yy_hold_char;
- if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
{ /* need to shift things up to make room */
/* +2 for EOB chars. */
- register int number_to_move = (yy_n_chars) + 2;
- register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
- YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+ register int number_to_move = yy_n_chars + 2;
+ register char *dest = &yy_current_buffer->yy_ch_buf[
+ yy_current_buffer->yy_buf_size + 2];
register char *source =
- &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+ &yy_current_buffer->yy_ch_buf[number_to_move];
- while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ while ( source > yy_current_buffer->yy_ch_buf )
*--dest = *--source;
yy_cp += (int) (dest - source);
yy_bp += (int) (dest - source);
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
- (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+ yy_current_buffer->yy_n_chars =
+ yy_n_chars = yy_current_buffer->yy_buf_size;
- if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
YY_FATAL_ERROR( "flex scanner push-back overflow" );
}
*--yy_cp = (char) c;
- if ( c == '\n' ){
- --yylineno;
- }
+ if ( c == '\n' )
+ --yylineno;
+
+ yytext_ptr = yy_bp;
+ yy_hold_char = *yy_cp;
+ yy_c_buf_p = yy_cp;
+ }
+#endif /* ifndef YY_NO_UNPUT */
- (yytext_ptr) = yy_bp;
- (yy_hold_char) = *yy_cp;
- (yy_c_buf_p) = yy_cp;
-}
-#ifndef YY_NO_INPUT
#ifdef __cplusplus
- static int yyinput (void)
+static int yyinput()
#else
- static int input (void)
+static int input()
#endif
-
-{
+ {
int c;
-
- *(yy_c_buf_p) = (yy_hold_char);
- if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+ *yy_c_buf_p = yy_hold_char;
+
+ if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
{
/* yy_c_buf_p now points to the character we want to return.
* If this occurs *before* the EOB characters, then it's a
* valid NUL; if not, then we've hit the end of the buffer.
*/
- if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
/* This was really a NUL. */
- *(yy_c_buf_p) = '\0';
+ *yy_c_buf_p = '\0';
else
{ /* need more input */
- int offset = (yy_c_buf_p) - (yytext_ptr);
- ++(yy_c_buf_p);
+ int offset = yy_c_buf_p - yytext_ptr;
+ ++yy_c_buf_p;
- switch ( yy_get_next_buffer( ) )
+ switch ( yy_get_next_buffer() )
{
case EOB_ACT_LAST_MATCH:
/* This happens because yy_g_n_b()
@@ -2344,16 +2484,16 @@ static int yy_get_next_buffer (void)
*/
/* Reset buffer status. */
- yyrestart(yyin );
+ yyrestart( yyin );
- /*FALLTHROUGH*/
+ /* fall through */
case EOB_ACT_END_OF_FILE:
{
- if ( yywrap( ) )
+ if ( yywrap() )
return EOF;
- if ( ! (yy_did_buffer_switch_on_eof) )
+ if ( ! yy_did_buffer_switch_on_eof )
YY_NEW_FILE;
#ifdef __cplusplus
return yyinput();
@@ -2363,98 +2503,93 @@ static int yy_get_next_buffer (void)
}
case EOB_ACT_CONTINUE_SCAN:
- (yy_c_buf_p) = (yytext_ptr) + offset;
+ yy_c_buf_p = yytext_ptr + offset;
break;
}
}
}
- c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
- *(yy_c_buf_p) = '\0'; /* preserve yytext */
- (yy_hold_char) = *++(yy_c_buf_p);
+ c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */
+ *yy_c_buf_p = '\0'; /* preserve yytext */
+ yy_hold_char = *++yy_c_buf_p;
- YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n');
- if ( YY_CURRENT_BUFFER_LVALUE->yy_at_bol )
-
- yylineno++;
-;
+ yy_current_buffer->yy_at_bol = (c == '\n');
+ if ( yy_current_buffer->yy_at_bol )
+ ++yylineno;
return c;
-}
-#endif /* ifndef YY_NO_INPUT */
+ }
-/** Immediately switch to a different input stream.
- * @param input_file A readable stream.
- *
- * @note This function does not reset the start condition to @c INITIAL .
- */
- void yyrestart (FILE * input_file )
-{
-
- if ( ! YY_CURRENT_BUFFER ){
- yyensure_buffer_stack ();
- YY_CURRENT_BUFFER_LVALUE =
- yy_create_buffer(yyin,YY_BUF_SIZE );
+
+#ifdef YY_USE_PROTOS
+void yyrestart( FILE *input_file )
+#else
+void yyrestart( input_file )
+FILE *input_file;
+#endif
+ {
+ if ( ! yy_current_buffer )
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_init_buffer( yy_current_buffer, input_file );
+ yy_load_buffer_state();
}
- yy_init_buffer(YY_CURRENT_BUFFER,input_file );
- yy_load_buffer_state( );
-}
-/** Switch to a different input buffer.
- * @param new_buffer The new input buffer.
- *
- */
- void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
-{
-
- /* TODO. We should be able to replace this entire function body
- * with
- * yypop_buffer_state();
- * yypush_buffer_state(new_buffer);
- */
- yyensure_buffer_stack ();
- if ( YY_CURRENT_BUFFER == new_buffer )
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+#else
+void yy_switch_to_buffer( new_buffer )
+YY_BUFFER_STATE new_buffer;
+#endif
+ {
+ if ( yy_current_buffer == new_buffer )
return;
- if ( YY_CURRENT_BUFFER )
+ if ( yy_current_buffer )
{
/* Flush out information for old buffer. */
- *(yy_c_buf_p) = (yy_hold_char);
- YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ *yy_c_buf_p = yy_hold_char;
+ yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+ yy_current_buffer->yy_n_chars = yy_n_chars;
}
- YY_CURRENT_BUFFER_LVALUE = new_buffer;
- yy_load_buffer_state( );
+ yy_current_buffer = new_buffer;
+ yy_load_buffer_state();
/* We don't actually know whether we did this switch during
* EOF (yywrap()) processing, but the only time this flag
* is looked at is after yywrap() is called, so it's safe
* to go ahead and always set it.
*/
- (yy_did_buffer_switch_on_eof) = 1;
-}
+ yy_did_buffer_switch_on_eof = 1;
+ }
-static void yy_load_buffer_state (void)
-{
- (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
- (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
- yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
- (yy_hold_char) = *(yy_c_buf_p);
-}
-/** Allocate and initialize an input buffer state.
- * @param file A readable stream.
- * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
- *
- * @return the allocated buffer state.
- */
- YY_BUFFER_STATE yy_create_buffer (FILE * file, int size )
-{
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state( void )
+#else
+void yy_load_buffer_state()
+#endif
+ {
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+ yyin = yy_current_buffer->yy_input_file;
+ yy_hold_char = *yy_c_buf_p;
+ }
+
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+#else
+YY_BUFFER_STATE yy_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+ {
YY_BUFFER_STATE b;
-
- b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
+
+ b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
if ( ! b )
YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
@@ -2463,71 +2598,80 @@ static void yy_load_buffer_state (void)
/* yy_ch_buf has to be 2 characters longer than the size given because
* we need to put in 2 end-of-buffer characters.
*/
- b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 );
+ b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
if ( ! b->yy_ch_buf )
YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
b->yy_is_our_buffer = 1;
- yy_init_buffer(b,file );
+ yy_init_buffer( b, file );
return b;
-}
+ }
-/** Destroy the buffer.
- * @param b a buffer created with yy_create_buffer()
- *
- */
- void yy_delete_buffer (YY_BUFFER_STATE b )
-{
-
+
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer( YY_BUFFER_STATE b )
+#else
+void yy_delete_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+ {
if ( ! b )
return;
- if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
- YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+ if ( b == yy_current_buffer )
+ yy_current_buffer = (YY_BUFFER_STATE) 0;
if ( b->yy_is_our_buffer )
- yyfree((void *) b->yy_ch_buf );
+ yy_flex_free( (void *) b->yy_ch_buf );
- yyfree((void *) b );
-}
+ yy_flex_free( (void *) b );
+ }
-/* Initializes or reinitializes a buffer.
- * This function is sometimes called more than once on the same buffer,
- * such as during a yyrestart() or at EOF.
- */
- static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file )
-{
- int oerrno = errno;
-
- yy_flush_buffer(b );
+#ifndef YY_ALWAYS_INTERACTIVE
+#ifndef YY_NEVER_INTERACTIVE
+extern int isatty YY_PROTO(( int ));
+#endif
+#endif
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
+#else
+void yy_init_buffer( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+#endif
+
+
+ {
+ yy_flush_buffer( b );
b->yy_input_file = file;
b->yy_fill_buffer = 1;
- /* If b is the current buffer, then yy_init_buffer was _probably_
- * called from yyrestart() or through yy_get_next_buffer.
- * In that case, we don't want to reset the lineno or column.
- */
- if (b != YY_CURRENT_BUFFER){
- b->yy_bs_lineno = 1;
- b->yy_bs_column = 0;
- }
+#if YY_ALWAYS_INTERACTIVE
+ b->yy_is_interactive = 1;
+#else
+#if YY_NEVER_INTERACTIVE
+ b->yy_is_interactive = 0;
+#else
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+ }
- b->yy_is_interactive = 0;
-
- errno = oerrno;
-}
-/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
- * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
- *
- */
- void yy_flush_buffer (YY_BUFFER_STATE b )
-{
- if ( ! b )
+#ifdef YY_USE_PROTOS
+void yy_flush_buffer( YY_BUFFER_STATE b )
+#else
+void yy_flush_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+
+ {
+ if ( ! b )
return;
b->yy_n_chars = 0;
@@ -2544,121 +2688,29 @@ static void yy_load_buffer_state (void)
b->yy_at_bol = 1;
b->yy_buffer_status = YY_BUFFER_NEW;
- if ( b == YY_CURRENT_BUFFER )
- yy_load_buffer_state( );
-}
-
-/** Pushes the new state onto the stack. The new state becomes
- * the current state. This function will allocate the stack
- * if necessary.
- * @param new_buffer The new state.
- *
- */
-void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
-{
- if (new_buffer == NULL)
- return;
-
- yyensure_buffer_stack();
-
- /* This block is copied from yy_switch_to_buffer. */
- if ( YY_CURRENT_BUFFER )
- {
- /* Flush out information for old buffer. */
- *(yy_c_buf_p) = (yy_hold_char);
- YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
- }
-
- /* Only push if top exists. Otherwise, replace top. */
- if (YY_CURRENT_BUFFER)
- (yy_buffer_stack_top)++;
- YY_CURRENT_BUFFER_LVALUE = new_buffer;
-
- /* copied from yy_switch_to_buffer. */
- yy_load_buffer_state( );
- (yy_did_buffer_switch_on_eof) = 1;
-}
-
-/** Removes and deletes the top of the stack, if present.
- * The next element becomes the new top.
- *
- */
-void yypop_buffer_state (void)
-{
- if (!YY_CURRENT_BUFFER)
- return;
-
- yy_delete_buffer(YY_CURRENT_BUFFER );
- YY_CURRENT_BUFFER_LVALUE = NULL;
- if ((yy_buffer_stack_top) > 0)
- --(yy_buffer_stack_top);
-
- if (YY_CURRENT_BUFFER) {
- yy_load_buffer_state( );
- (yy_did_buffer_switch_on_eof) = 1;
- }
-}
-
-/* Allocates the stack if it does not exist.
- * Guarantees space for at least one push.
- */
-static void yyensure_buffer_stack (void)
-{
- int num_to_alloc;
-
- if (!(yy_buffer_stack)) {
-
- /* First allocation is just for 2 elements, since we don't know if this
- * scanner will even need a stack. We use 2 instead of 1 to avoid an
- * immediate realloc on the next call.
- */
- num_to_alloc = 1;
- (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
- (num_to_alloc * sizeof(struct yy_buffer_state*)
- );
-
- memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
-
- (yy_buffer_stack_max) = num_to_alloc;
- (yy_buffer_stack_top) = 0;
- return;
+ if ( b == yy_current_buffer )
+ yy_load_buffer_state();
}
- if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
- /* Increase the buffer to prepare for a possible push. */
- int grow_size = 8 /* arbitrary grow size */;
-
- num_to_alloc = (yy_buffer_stack_max) + grow_size;
- (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
- ((yy_buffer_stack),
- num_to_alloc * sizeof(struct yy_buffer_state*)
- );
-
- /* zero only the new slots.*/
- memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
- (yy_buffer_stack_max) = num_to_alloc;
- }
-}
-
-/** Setup the input buffer state to scan directly from a user-specified character buffer.
- * @param base the character buffer
- * @param size the size in bytes of the character buffer
- *
- * @return the newly allocated buffer state object.
- */
-YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
-{
+#ifndef YY_NO_SCAN_BUFFER
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
+#else
+YY_BUFFER_STATE yy_scan_buffer( base, size )
+char *base;
+yy_size_t size;
+#endif
+ {
YY_BUFFER_STATE b;
-
+
if ( size < 2 ||
base[size-2] != YY_END_OF_BUFFER_CHAR ||
base[size-1] != YY_END_OF_BUFFER_CHAR )
/* They forgot to leave room for the EOB's. */
return 0;
- b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
+ b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
if ( ! b )
YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
@@ -2672,51 +2724,56 @@ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
b->yy_fill_buffer = 0;
b->yy_buffer_status = YY_BUFFER_NEW;
- yy_switch_to_buffer(b );
+ yy_switch_to_buffer( b );
return b;
-}
+ }
+#endif
-/** Setup the input buffer state to scan a string. The next call to yylex() will
- * scan from a @e copy of @a str.
- * @param yystr a NUL-terminated string to scan
- *
- * @return the newly allocated buffer state object.
- * @note If you want to scan bytes that may contain NUL values, then use
- * yy_scan_bytes() instead.
- */
-YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
-{
-
- return yy_scan_bytes(yystr,strlen(yystr) );
-}
-/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
- * scan from a @e copy of @a bytes.
- * @param bytes the byte buffer to scan
- * @param len the number of bytes in the buffer pointed to by @a bytes.
- *
- * @return the newly allocated buffer state object.
- */
-YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len )
-{
+#ifndef YY_NO_SCAN_STRING
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
+#else
+YY_BUFFER_STATE yy_scan_string( yy_str )
+yyconst char *yy_str;
+#endif
+ {
+ int len;
+ for ( len = 0; yy_str[len]; ++len )
+ ;
+
+ return yy_scan_bytes( yy_str, len );
+ }
+#endif
+
+
+#ifndef YY_NO_SCAN_BYTES
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
+#else
+YY_BUFFER_STATE yy_scan_bytes( bytes, len )
+yyconst char *bytes;
+int len;
+#endif
+ {
YY_BUFFER_STATE b;
char *buf;
yy_size_t n;
int i;
-
+
/* Get memory for full buffer, including space for trailing EOB's. */
- n = _yybytes_len + 2;
- buf = (char *) yyalloc(n );
+ n = len + 2;
+ buf = (char *) yy_flex_alloc( n );
if ( ! buf )
YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
- for ( i = 0; i < _yybytes_len; ++i )
- buf[i] = yybytes[i];
+ for ( i = 0; i < len; ++i )
+ buf[i] = bytes[i];
- buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+ buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
- b = yy_scan_buffer(buf,n );
+ b = yy_scan_buffer( buf, n );
if ( ! b )
YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
@@ -2726,199 +2783,148 @@ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len )
b->yy_is_our_buffer = 1;
return b;
-}
-
-#ifndef YY_EXIT_FAILURE
-#define YY_EXIT_FAILURE 2
+ }
#endif
-static void yy_fatal_error (yyconst char* msg )
-{
- (void) fprintf( stderr, "%s\n", msg );
- exit( YY_EXIT_FAILURE );
-}
-/* Redefine yyless() so it works in section 3 code. */
+#ifndef YY_NO_PUSH_STATE
+#ifdef YY_USE_PROTOS
+static void yy_push_state( int new_state )
+#else
+static void yy_push_state( new_state )
+int new_state;
+#endif
+ {
+ if ( yy_start_stack_ptr >= yy_start_stack_depth )
+ {
+ yy_size_t new_size;
-#undef yyless
-#define yyless(n) \
- do \
- { \
- /* Undo effects of setting up yytext. */ \
- int yyless_macro_arg = (n); \
- YY_LESS_LINENO(yyless_macro_arg);\
- yytext[yyleng] = (yy_hold_char); \
- (yy_c_buf_p) = yytext + yyless_macro_arg; \
- (yy_hold_char) = *(yy_c_buf_p); \
- *(yy_c_buf_p) = '\0'; \
- yyleng = yyless_macro_arg; \
- } \
- while ( 0 )
+ yy_start_stack_depth += YY_START_STACK_INCR;
+ new_size = yy_start_stack_depth * sizeof( int );
-/* Accessor methods (get/set functions) to struct members. */
+ if ( ! yy_start_stack )
+ yy_start_stack = (int *) yy_flex_alloc( new_size );
-/** Get the current line number.
- *
- */
-int yyget_lineno (void)
-{
-
- return yylineno;
-}
+ else
+ yy_start_stack = (int *) yy_flex_realloc(
+ (void *) yy_start_stack, new_size );
-/** Get the input stream.
- *
- */
-FILE *yyget_in (void)
-{
- return yyin;
-}
+ if ( ! yy_start_stack )
+ YY_FATAL_ERROR(
+ "out of memory expanding start-condition stack" );
+ }
-/** Get the output stream.
- *
- */
-FILE *yyget_out (void)
-{
- return yyout;
-}
+ yy_start_stack[yy_start_stack_ptr++] = YY_START;
-/** Get the length of the current token.
- *
- */
-int yyget_leng (void)
-{
- return yyleng;
-}
+ BEGIN(new_state);
+ }
+#endif
-/** Get the current token.
- *
- */
-char *yyget_text (void)
-{
- return yytext;
-}
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state()
+ {
+ if ( --yy_start_stack_ptr < 0 )
+ YY_FATAL_ERROR( "start-condition stack underflow" );
-/** Set the current line number.
- * @param line_number
- *
- */
-void yyset_lineno (int line_number )
-{
-
- yylineno = line_number;
-}
+ BEGIN(yy_start_stack[yy_start_stack_ptr]);
+ }
+#endif
-/** Set the input stream. This does not discard the current
- * input buffer.
- * @param in_str A readable stream.
- *
- * @see yy_switch_to_buffer
- */
-void yyset_in (FILE * in_str )
-{
- yyin = in_str ;
-}
-void yyset_out (FILE * out_str )
-{
- yyout = out_str ;
-}
-
-int yyget_debug (void)
-{
- return yy_flex_debug;
-}
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state()
+ {
+ return yy_start_stack[yy_start_stack_ptr - 1];
+ }
+#endif
-void yyset_debug (int bdebug )
-{
- yy_flex_debug = bdebug ;
-}
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
-static int yy_init_globals (void)
-{
- /* Initialization is the same as for the non-reentrant scanner.
- * This function is called from yylex_destroy(), so don't allocate here.
- */
-
- /* We do not touch yylineno unless the option is enabled. */
- yylineno = 1;
-
- (yy_buffer_stack) = 0;
- (yy_buffer_stack_top) = 0;
- (yy_buffer_stack_max) = 0;
- (yy_c_buf_p) = (char *) 0;
- (yy_init) = 0;
- (yy_start) = 0;
-
-/* Defined in main.c */
-#ifdef YY_STDINIT
- yyin = stdin;
- yyout = stdout;
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error( yyconst char msg[] )
#else
- yyin = (FILE *) 0;
- yyout = (FILE *) 0;
+static void yy_fatal_error( msg )
+char msg[];
#endif
+ {
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+ }
- /* For future reference: Set errno on error, since we are called by
- * yylex_init()
- */
- return 0;
-}
-/* yylex_destroy is for both reentrant and non-reentrant scanners. */
-int yylex_destroy (void)
-{
-
- /* Pop the buffer stack, destroying each element. */
- while(YY_CURRENT_BUFFER){
- yy_delete_buffer(YY_CURRENT_BUFFER );
- YY_CURRENT_BUFFER_LVALUE = NULL;
- yypop_buffer_state();
- }
- /* Destroy the stack itself. */
- yyfree((yy_buffer_stack) );
- (yy_buffer_stack) = NULL;
+/* Redefine yyless() so it works in section 3 code. */
- /* Reset the globals. This is important in a non-reentrant scanner so the next time
- * yylex() is called, initialization will occur. */
- yy_init_globals( );
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ yytext[yyleng] = yy_hold_char; \
+ yy_c_buf_p = yytext + n; \
+ yy_hold_char = *yy_c_buf_p; \
+ *yy_c_buf_p = '\0'; \
+ yyleng = n; \
+ } \
+ while ( 0 )
- return 0;
-}
-/*
- * Internal utility routines.
- */
+/* Internal utility routines. */
#ifndef yytext_ptr
-static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
-{
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+yyconst char *s2;
+int n;
+#endif
+ {
register int i;
for ( i = 0; i < n; ++i )
s1[i] = s2[i];
-}
+ }
#endif
#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * s )
-{
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen( yyconst char *s )
+#else
+static int yy_flex_strlen( s )
+yyconst char *s;
+#endif
+ {
register int n;
for ( n = 0; s[n]; ++n )
;
return n;
-}
+ }
#endif
-void *yyalloc (yy_size_t size )
-{
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( yy_size_t size )
+#else
+static void *yy_flex_alloc( size )
+yy_size_t size;
+#endif
+ {
return (void *) malloc( size );
-}
+ }
-void *yyrealloc (void * ptr, yy_size_t size )
-{
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc( void *ptr, yy_size_t size )
+#else
+static void *yy_flex_realloc( ptr, size )
+void *ptr;
+yy_size_t size;
+#endif
+ {
/* The cast to (char *) in the following accommodates both
* implementations that use char* generic pointers, and those
* that use void* generic pointers. It works with the latter
@@ -2927,17 +2933,26 @@ void *yyrealloc (void * ptr, yy_size_t size )
* as though doing an assignment.
*/
return (void *) realloc( (char *) ptr, size );
-}
-
-void yyfree (void * ptr )
-{
- free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
-}
-
-#define YYTABLES_NAME "yytables"
+ }
-#line 221 "levcomp.lpp"
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+ {
+ free( ptr );
+ }
+#if YY_MAIN
+int main()
+ {
+ yylex();
+ return 0;
+ }
+#endif
+#line 226 "levcomp.lpp"
int yywrap()
@@ -2946,4 +2961,3 @@ int yywrap()
flush_free_queue(0);
return 1;
}
-
diff --git a/crawl-ref/source/prebuilt/levcomp.tab.cc b/crawl-ref/source/prebuilt/levcomp.tab.cc
index 7eda2aff4c..1679a76a3b 100644
--- a/crawl-ref/source/prebuilt/levcomp.tab.cc
+++ b/crawl-ref/source/prebuilt/levcomp.tab.cc
@@ -1,9 +1,7 @@
-/* A Bison parser, made by GNU Bison 2.3. */
+/* A Bison parser, made by GNU Bison 2.0. */
-/* Skeleton implementation for Bison's Yacc-like parsers in C
-
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- Free Software Foundation, Inc.
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,24 +15,16 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
-
-/* As a special exception, you may create a larger work that contains
- part or all of the Bison parser skeleton and distribute that work
- under terms of your choice, so long as that work isn't itself a
- parser generator using the skeleton or a modified version thereof
- as a parser skeleton. Alternatively, if you modify or redistribute
- the parser skeleton itself, you may (at your option) remove this
- special exception, which will cause the skeleton and the resulting
- Bison output files to be licensed under the GNU General Public
- License without this special exception.
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
- This special exception was added by the Free Software Foundation in
- version 2.2 of Bison. */
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
-/* C LALR(1) parser skeleton written by Richard Stallman, by
- simplifying the original so-called "semantic" parser. */
+/* Written by Richard Stallman by simplifying the original so called
+ ``semantic'' parser. */
/* All symbols defined below should begin with yy or YY, to avoid
infringing on user name space. This should be done even for local
@@ -46,9 +36,6 @@
/* Identify Bison output. */
#define YYBISON 1
-/* Bison version. */
-#define YYBISON_VERSION "2.3"
-
/* Skeleton name. */
#define YYSKELETON_NAME "yacc.c"
@@ -73,32 +60,36 @@
KFEAT = 262,
KITEM = 263,
KMONS = 264,
- NAME = 265,
- DEPTH = 266,
- ORIENT = 267,
- PLACE = 268,
- CHANCE = 269,
- MONS = 270,
- ITEM = 271,
- MARKER = 272,
- COLOUR = 273,
- PRELUDE = 274,
- MAIN = 275,
- VALIDATE = 276,
- VETO = 277,
- NSUBST = 278,
- WELCOME = 279,
- COMMA = 280,
- INTEGER = 281,
- CHARACTER = 282,
- STRING = 283,
- MAP_LINE = 284,
- MONSTER_NAME = 285,
- ITEM_INFO = 286,
- LUA_LINE = 287
+ KMASK = 265,
+ NAME = 266,
+ DEPTH = 267,
+ ORIENT = 268,
+ PLACE = 269,
+ CHANCE = 270,
+ MONS = 271,
+ ITEM = 272,
+ MARKER = 273,
+ COLOUR = 274,
+ PRELUDE = 275,
+ MAIN = 276,
+ VALIDATE = 277,
+ VETO = 278,
+ NSUBST = 279,
+ WELCOME = 280,
+ LFLAGS = 281,
+ BFLAGS = 282,
+ FLOORCOL = 283,
+ ROCKCOL = 284,
+ COMMA = 285,
+ INTEGER = 286,
+ CHARACTER = 287,
+ STRING = 288,
+ MAP_LINE = 289,
+ MONSTER_NAME = 290,
+ ITEM_INFO = 291,
+ LUA_LINE = 292
};
#endif
-/* Tokens. */
#define DEFAULT_DEPTH 258
#define SHUFFLE 259
#define SUBST 260
@@ -106,29 +97,34 @@
#define KFEAT 262
#define KITEM 263
#define KMONS 264
-#define NAME 265
-#define DEPTH 266
-#define ORIENT 267
-#define PLACE 268
-#define CHANCE 269
-#define MONS 270
-#define ITEM 271
-#define MARKER 272
-#define COLOUR 273
-#define PRELUDE 274
-#define MAIN 275
-#define VALIDATE 276
-#define VETO 277
-#define NSUBST 278
-#define WELCOME 279
-#define COMMA 280
-#define INTEGER 281
-#define CHARACTER 282
-#define STRING 283
-#define MAP_LINE 284
-#define MONSTER_NAME 285
-#define ITEM_INFO 286
-#define LUA_LINE 287
+#define KMASK 265
+#define NAME 266
+#define DEPTH 267
+#define ORIENT 268
+#define PLACE 269
+#define CHANCE 270
+#define MONS 271
+#define ITEM 272
+#define MARKER 273
+#define COLOUR 274
+#define PRELUDE 275
+#define MAIN 276
+#define VALIDATE 277
+#define VETO 278
+#define NSUBST 279
+#define WELCOME 280
+#define LFLAGS 281
+#define BFLAGS 282
+#define FLOORCOL 283
+#define ROCKCOL 284
+#define COMMA 285
+#define INTEGER 286
+#define CHARACTER 287
+#define STRING 288
+#define MAP_LINE 289
+#define MONSTER_NAME 290
+#define ITEM_INFO 291
+#define LUA_LINE 292
@@ -192,22 +188,15 @@ level_range set_range(const char *s, int start, int end)
# define YYERROR_VERBOSE 0
#endif
-/* Enabling the token table. */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
-#endif
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
#line 46 "levcomp.ypp"
-{
+typedef union YYSTYPE {
int i;
const char *text;
raw_range range;
-}
-/* Line 193 of yacc.c. */
-#line 210 "levcomp.tab.c"
- YYSTYPE;
+} YYSTYPE;
+/* Line 185 of yacc.c. */
+#line 200 "levcomp.tab.c"
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
# define YYSTYPE_IS_TRIVIAL 1
@@ -218,94 +207,17 @@ typedef union YYSTYPE
/* Copy the second part of user declarations. */
-/* Line 216 of yacc.c. */
-#line 223 "levcomp.tab.c"
-
-#ifdef short
-# undef short
-#endif
-
-#ifdef YYTYPE_UINT8
-typedef YYTYPE_UINT8 yytype_uint8;
-#else
-typedef unsigned char yytype_uint8;
-#endif
-
-#ifdef YYTYPE_INT8
-typedef YYTYPE_INT8 yytype_int8;
-#elif (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-typedef signed char yytype_int8;
-#else
-typedef short int yytype_int8;
-#endif
-
-#ifdef YYTYPE_UINT16
-typedef YYTYPE_UINT16 yytype_uint16;
-#else
-typedef unsigned short int yytype_uint16;
-#endif
+/* Line 213 of yacc.c. */
+#line 212 "levcomp.tab.c"
-#ifdef YYTYPE_INT16
-typedef YYTYPE_INT16 yytype_int16;
-#else
-typedef short int yytype_int16;
-#endif
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
-#ifndef YYSIZE_T
-# ifdef __SIZE_TYPE__
-# define YYSIZE_T __SIZE_TYPE__
-# elif defined size_t
-# define YYSIZE_T size_t
-# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-# define YYSIZE_T size_t
-# else
-# define YYSIZE_T unsigned int
+# ifndef YYFREE
+# define YYFREE free
# endif
-#endif
-
-#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
-
-#ifndef YY_
-# if YYENABLE_NLS
-# if ENABLE_NLS
-# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-# define YY_(msgid) dgettext ("bison-runtime", msgid)
-# endif
-# endif
-# ifndef YY_
-# define YY_(msgid) msgid
+# ifndef YYMALLOC
+# define YYMALLOC malloc
# endif
-#endif
-
-/* Suppress unused-variable warnings by "using" E. */
-#if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
-#else
-# define YYUSE(e) /* empty */
-#endif
-
-/* Identity function, used to suppress warnings about constant conditions. */
-#ifndef lint
-# define YYID(n) (n)
-#else
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static int
-YYID (int i)
-#else
-static int
-YYID (i)
- int i;
-#endif
-{
- return i;
-}
-#endif
-
-#if ! defined yyoverflow || YYERROR_VERBOSE
/* The parser invokes alloca or malloc; define the necessary symbols. */
@@ -313,76 +225,34 @@ YYID (i)
# if YYSTACK_USE_ALLOCA
# ifdef __GNUC__
# define YYSTACK_ALLOC __builtin_alloca
-# elif defined __BUILTIN_VA_ARG_INCR
-# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
-# elif defined _AIX
-# define YYSTACK_ALLOC __alloca
-# elif defined _MSC_VER
-# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
-# define alloca _alloca
# else
# define YYSTACK_ALLOC alloca
-# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef _STDLIB_H
-# define _STDLIB_H 1
-# endif
-# endif
# endif
# endif
# endif
# ifdef YYSTACK_ALLOC
- /* Pacify GCC's `empty if-body' warning. */
-# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
-# ifndef YYSTACK_ALLOC_MAXIMUM
- /* The OS might guarantee only one guard page at the bottom of the stack,
- and a page size can be as small as 4096 bytes. So we cannot safely
- invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
- to allow for a few compiler-allocated temporary stack slots. */
-# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
-# endif
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
# else
-# define YYSTACK_ALLOC YYMALLOC
-# define YYSTACK_FREE YYFREE
-# ifndef YYSTACK_ALLOC_MAXIMUM
-# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
-# endif
-# if (defined __cplusplus && ! defined _STDLIB_H \
- && ! ((defined YYMALLOC || defined malloc) \
- && (defined YYFREE || defined free)))
+# if defined (__STDC__) || defined (__cplusplus)
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef _STDLIB_H
-# define _STDLIB_H 1
-# endif
-# endif
-# ifndef YYMALLOC
-# define YYMALLOC malloc
-# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
-# endif
-# endif
-# ifndef YYFREE
-# define YYFREE free
-# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-void free (void *); /* INFRINGES ON USER NAME SPACE */
-# endif
+# define YYSIZE_T size_t
# endif
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
# endif
-#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
-#if (! defined yyoverflow \
- && (! defined __cplusplus \
- || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+#if (! defined (yyoverflow) \
+ && (! defined (__cplusplus) \
+ || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL)))
/* A type that is properly aligned for any stack member. */
union yyalloc
{
- yytype_int16 yyss;
+ short int yyss;
YYSTYPE yyvs;
};
@@ -392,24 +262,24 @@ union yyalloc
/* The size of an array large to enough to hold all stacks, each with
N elements. */
# define YYSTACK_BYTES(N) \
- ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ ((N) * (sizeof (short int) + sizeof (YYSTYPE)) \
+ YYSTACK_GAP_MAXIMUM)
/* Copy COUNT objects from FROM to TO. The source and destination do
not overlap. */
# ifndef YYCOPY
-# if defined __GNUC__ && 1 < __GNUC__
+# if defined (__GNUC__) && 1 < __GNUC__
# define YYCOPY(To, From, Count) \
__builtin_memcpy (To, From, (Count) * sizeof (*(From)))
# else
# define YYCOPY(To, From, Count) \
do \
{ \
- YYSIZE_T yyi; \
+ register YYSIZE_T yyi; \
for (yyi = 0; yyi < (Count); yyi++) \
(To)[yyi] = (From)[yyi]; \
} \
- while (YYID (0))
+ while (0)
# endif
# endif
@@ -427,33 +297,39 @@ union yyalloc
yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
yyptr += yynewbytes / sizeof (*yyptr); \
} \
- while (YYID (0))
+ while (0)
#endif
-/* YYFINAL -- State number of the termination state. */
+#if defined (__STDC__) || defined (__cplusplus)
+ typedef signed char yysigned_char;
+#else
+ typedef short int yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
#define YYFINAL 3
/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 67
+#define YYLAST 75
-/* YYNTOKENS -- Number of terminals. */
-#define YYNTOKENS 33
-/* YYNNTS -- Number of nonterminals. */
-#define YYNNTS 64
-/* YYNRULES -- Number of rules. */
-#define YYNRULES 110
-/* YYNRULES -- Number of states. */
-#define YYNSTATES 126
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 38
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 69
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 123
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 141
/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
#define YYUNDEFTOK 2
-#define YYMAXUTOK 287
+#define YYMAXUTOK 292
-#define YYTRANSLATE(YYX) \
+#define YYTRANSLATE(YYX) \
((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
-static const yytype_uint8 yytranslate[] =
+static const unsigned char yytranslate[] =
{
0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
@@ -483,211 +359,225 @@ static const yytype_uint8 yytranslate[] =
2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
- 25, 26, 27, 28, 29, 30, 31, 32
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37
};
#if YYDEBUG
/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
YYRHS. */
-static const yytype_uint16 yyprhs[] =
+static const unsigned short int yyprhs[] =
{
0, 0, 3, 5, 6, 9, 11, 13, 15, 17,
19, 22, 25, 26, 29, 31, 33, 36, 38, 40,
42, 44, 46, 48, 50, 52, 54, 56, 58, 60,
- 62, 64, 66, 68, 70, 72, 74, 76, 78, 81,
- 82, 85, 87, 90, 91, 94, 96, 99, 100, 103,
- 105, 108, 109, 112, 114, 117, 118, 121, 123, 125,
- 128, 130, 133, 135, 138, 141, 143, 147, 149, 152,
- 153, 156, 158, 159, 163, 165, 166, 169, 171, 174,
- 176, 180, 182, 185, 187, 191, 193, 196, 198, 202,
- 204, 206, 209, 213, 215, 217, 219, 222, 226, 228,
- 230, 233, 235, 238, 241, 243, 246, 249, 251, 254,
- 256
+ 62, 64, 66, 68, 70, 72, 74, 76, 78, 80,
+ 82, 84, 86, 88, 91, 92, 95, 97, 100, 101,
+ 104, 106, 109, 110, 113, 115, 118, 119, 122, 124,
+ 127, 128, 131, 133, 135, 138, 140, 143, 145, 148,
+ 150, 153, 156, 158, 162, 164, 167, 168, 171, 173,
+ 176, 179, 180, 184, 186, 187, 190, 192, 195, 197,
+ 200, 202, 205, 207, 211, 213, 216, 218, 222, 224,
+ 227, 229, 233, 235, 237, 240, 244, 246, 248, 250,
+ 253, 257, 259, 261, 264, 266, 269, 272, 274, 277,
+ 280, 282, 285, 287
};
-/* YYRHS -- A `-1'-separated list of the rules' RHS. */
-static const yytype_int8 yyrhs[] =
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yysigned_char yyrhs[] =
{
- 34, 0, -1, 35, -1, -1, 35, 36, -1, 38,
- -1, 40, -1, 27, -1, 39, -1, 45, -1, 3,
- 28, -1, 43, 41, -1, -1, 41, 42, -1, 44,
- -1, 94, -1, 10, 28, -1, 89, -1, 90, -1,
- 91, -1, 92, -1, 93, -1, 86, -1, 83, -1,
- 69, -1, 80, -1, 77, -1, 74, -1, 63, -1,
- 66, -1, 60, -1, 62, -1, 61, -1, 48, -1,
- 57, -1, 51, -1, 54, -1, 37, -1, 20, 46,
- -1, -1, 46, 47, -1, 32, -1, 20, 49, -1,
- -1, 49, 50, -1, 32, -1, 21, 52, -1, -1,
- 52, 53, -1, 32, -1, 22, 55, -1, -1, 55,
- 56, -1, 32, -1, 19, 58, -1, -1, 58, 59,
- -1, 32, -1, 7, -1, 7, 28, -1, 9, -1,
- 9, 28, -1, 8, -1, 8, 28, -1, 4, 64,
- -1, 65, -1, 64, 25, 65, -1, 31, -1, 6,
- 67, -1, -1, 67, 68, -1, 28, -1, -1, 17,
- 70, 71, -1, 72, -1, -1, 72, 73, -1, 28,
- -1, 18, 75, -1, 76, -1, 75, 25, 76, -1,
- 31, -1, 23, 78, -1, 79, -1, 78, 25, 79,
- -1, 31, -1, 5, 81, -1, 82, -1, 82, 25,
- 81, -1, 31, -1, 16, -1, 16, 84, -1, 84,
- 25, 85, -1, 85, -1, 31, -1, 15, -1, 15,
- 87, -1, 88, 25, 87, -1, 88, -1, 30, -1,
- 13, 28, -1, 11, -1, 11, 28, -1, 14, 26,
- -1, 12, -1, 12, 28, -1, 24, 28, -1, 95,
- -1, 95, 96, -1, 96, -1, 29, -1
+ 39, 0, -1, 40, -1, -1, 40, 41, -1, 43,
+ -1, 45, -1, 32, -1, 44, -1, 50, -1, 3,
+ 33, -1, 48, 46, -1, -1, 46, 47, -1, 49,
+ -1, 104, -1, 11, 33, -1, 99, -1, 100, -1,
+ 101, -1, 102, -1, 103, -1, 96, -1, 93, -1,
+ 77, -1, 90, -1, 87, -1, 82, -1, 83, -1,
+ 84, -1, 69, -1, 72, -1, 75, -1, 76, -1,
+ 65, -1, 67, -1, 66, -1, 68, -1, 53, -1,
+ 62, -1, 56, -1, 59, -1, 42, -1, 21, 51,
+ -1, -1, 51, 52, -1, 37, -1, 21, 54, -1,
+ -1, 54, 55, -1, 37, -1, 22, 57, -1, -1,
+ 57, 58, -1, 37, -1, 23, 60, -1, -1, 60,
+ 61, -1, 37, -1, 20, 63, -1, -1, 63, 64,
+ -1, 37, -1, 7, -1, 7, 33, -1, 9, -1,
+ 9, 33, -1, 8, -1, 8, 33, -1, 10, -1,
+ 10, 33, -1, 4, 70, -1, 71, -1, 70, 30,
+ 71, -1, 36, -1, 6, 73, -1, -1, 73, 74,
+ -1, 33, -1, 26, 33, -1, 27, 33, -1, -1,
+ 18, 78, 79, -1, 80, -1, -1, 80, 81, -1,
+ 33, -1, 19, 85, -1, 28, -1, 28, 33, -1,
+ 29, -1, 29, 33, -1, 86, -1, 85, 30, 86,
+ -1, 36, -1, 24, 88, -1, 89, -1, 88, 30,
+ 89, -1, 36, -1, 5, 91, -1, 92, -1, 92,
+ 30, 91, -1, 36, -1, 17, -1, 17, 94, -1,
+ 94, 30, 95, -1, 95, -1, 36, -1, 16, -1,
+ 16, 97, -1, 98, 30, 97, -1, 98, -1, 35,
+ -1, 14, 33, -1, 12, -1, 12, 33, -1, 15,
+ 31, -1, 13, -1, 13, 33, -1, 25, 33, -1,
+ 105, -1, 105, 106, -1, 106, -1, 34, -1
};
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
-static const yytype_uint16 yyrline[] =
+static const unsigned short int yyrline[] =
{
- 0, 66, 66, 69, 70, 73, 74, 77, 83, 84,
- 87, 97, 119, 120, 123, 124, 127, 151, 152, 153,
- 154, 155, 156, 157, 158, 159, 160, 161, 162, 163,
- 164, 165, 166, 167, 168, 169, 170, 171, 174, 176,
- 177, 180, 185, 187, 188, 191, 196, 198, 199, 202,
- 207, 209, 210, 213, 218, 220, 221, 224, 229, 230,
- 238, 239, 247, 248, 256, 259, 260, 263, 271, 274,
- 275, 278, 288, 287, 298, 300, 301, 304, 316, 319,
- 320, 323, 332, 335, 336, 339, 348, 351, 352, 355,
- 364, 365, 368, 369, 372, 380, 381, 384, 385, 388,
- 397, 406, 407, 416, 424, 425, 434, 443, 446, 447,
- 450
+ 0, 67, 67, 70, 71, 74, 75, 78, 84, 85,
+ 88, 98, 120, 121, 124, 125, 128, 152, 153, 154,
+ 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
+ 165, 166, 167, 168, 169, 170, 171, 172, 173, 174,
+ 175, 176, 177, 180, 182, 183, 186, 191, 193, 194,
+ 197, 202, 204, 205, 208, 213, 215, 216, 219, 224,
+ 226, 227, 230, 235, 236, 244, 245, 253, 254, 262,
+ 263, 271, 274, 275, 278, 286, 289, 290, 293, 302,
+ 311, 321, 320, 331, 333, 334, 337, 349, 352, 353,
+ 361, 362, 370, 371, 374, 383, 386, 387, 390, 399,
+ 402, 403, 406, 415, 416, 419, 420, 423, 431, 432,
+ 435, 436, 439, 448, 457, 458, 467, 475, 476, 485,
+ 494, 497, 498, 501
};
#endif
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
-/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
- First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+#if YYDEBUG || YYERROR_VERBOSE
+/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
static const char *const yytname[] =
{
"$end", "error", "$undefined", "DEFAULT_DEPTH", "SHUFFLE", "SUBST",
- "TAGS", "KFEAT", "KITEM", "KMONS", "NAME", "DEPTH", "ORIENT", "PLACE",
- "CHANCE", "MONS", "ITEM", "MARKER", "COLOUR", "PRELUDE", "MAIN",
- "VALIDATE", "VETO", "NSUBST", "WELCOME", "COMMA", "INTEGER", "CHARACTER",
- "STRING", "MAP_LINE", "MONSTER_NAME", "ITEM_INFO", "LUA_LINE", "$accept",
- "file", "definitions", "definition", "error_seq", "def", "defdepth",
- "level", "map_specs", "map_spec", "name", "metaline", "global_lua",
+ "TAGS", "KFEAT", "KITEM", "KMONS", "KMASK", "NAME", "DEPTH", "ORIENT",
+ "PLACE", "CHANCE", "MONS", "ITEM", "MARKER", "COLOUR", "PRELUDE", "MAIN",
+ "VALIDATE", "VETO", "NSUBST", "WELCOME", "LFLAGS", "BFLAGS", "FLOORCOL",
+ "ROCKCOL", "COMMA", "INTEGER", "CHARACTER", "STRING", "MAP_LINE",
+ "MONSTER_NAME", "ITEM_INFO", "LUA_LINE", "$accept", "file",
+ "definitions", "definition", "error_seq", "def", "defdepth", "level",
+ "map_specs", "map_spec", "name", "metaline", "global_lua",
"global_lua_lines", "global_lua_line", "main_lua", "main_lua_lines",
"main_lua_line", "validate_lua", "validate_lua_lines",
"validate_lua_line", "veto_lua", "veto_lua_lines", "veto_lua_line",
"prelude_lua", "prelude_lua_lines", "prelude_lua_line", "kfeat", "kmons",
- "kitem", "shuffle", "shuffle_specifiers", "shuffle_spec", "tags",
- "tagstrings", "tagstring", "marker", "@1", "marker_spec",
- "mspec_segments", "mspec_segment", "colour", "colour_specifiers",
- "colour_specifier", "nsubst", "nsubst_specifiers", "nsubst_spec",
- "subst", "subst_specifiers", "subst_spec", "items", "item_specifiers",
- "item_specifier", "mons", "mnames", "mname", "place", "depth", "chance",
- "orientation", "welcome", "map_def", "map_lines", "map_line", 0
+ "kitem", "kmask", "shuffle", "shuffle_specifiers", "shuffle_spec",
+ "tags", "tagstrings", "tagstring", "lflags", "bflags", "marker", "@1",
+ "marker_spec", "mspec_segments", "mspec_segment", "colour", "floorcol",
+ "rockcol", "colour_specifiers", "colour_specifier", "nsubst",
+ "nsubst_specifiers", "nsubst_spec", "subst", "subst_specifiers",
+ "subst_spec", "items", "item_specifiers", "item_specifier", "mons",
+ "mnames", "mname", "place", "depth", "chance", "orientation", "welcome",
+ "map_def", "map_lines", "map_line", 0
};
#endif
# ifdef YYPRINT
/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
token YYLEX-NUM. */
-static const yytype_uint16 yytoknum[] =
+static const unsigned short int yytoknum[] =
{
0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
- 285, 286, 287
+ 285, 286, 287, 288, 289, 290, 291, 292
};
# endif
/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
-static const yytype_uint8 yyr1[] =
+static const unsigned char yyr1[] =
{
- 0, 33, 34, 35, 35, 36, 36, 37, 38, 38,
- 39, 40, 41, 41, 42, 42, 43, 44, 44, 44,
- 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
- 44, 44, 44, 44, 44, 44, 44, 44, 45, 46,
- 46, 47, 48, 49, 49, 50, 51, 52, 52, 53,
- 54, 55, 55, 56, 57, 58, 58, 59, 60, 60,
- 61, 61, 62, 62, 63, 64, 64, 65, 66, 67,
- 67, 68, 70, 69, 71, 72, 72, 73, 74, 75,
- 75, 76, 77, 78, 78, 79, 80, 81, 81, 82,
- 83, 83, 84, 84, 85, 86, 86, 87, 87, 88,
- 89, 90, 90, 91, 92, 92, 93, 94, 95, 95,
- 96
+ 0, 38, 39, 40, 40, 41, 41, 42, 43, 43,
+ 44, 45, 46, 46, 47, 47, 48, 49, 49, 49,
+ 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+ 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+ 49, 49, 49, 50, 51, 51, 52, 53, 54, 54,
+ 55, 56, 57, 57, 58, 59, 60, 60, 61, 62,
+ 63, 63, 64, 65, 65, 66, 66, 67, 67, 68,
+ 68, 69, 70, 70, 71, 72, 73, 73, 74, 75,
+ 76, 78, 77, 79, 80, 80, 81, 82, 83, 83,
+ 84, 84, 85, 85, 86, 87, 88, 88, 89, 90,
+ 91, 91, 92, 93, 93, 94, 94, 95, 96, 96,
+ 97, 97, 98, 99, 100, 100, 101, 102, 102, 103,
+ 104, 105, 105, 106
};
/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
-static const yytype_uint8 yyr2[] =
+static const unsigned char yyr2[] =
{
0, 2, 1, 0, 2, 1, 1, 1, 1, 1,
2, 2, 0, 2, 1, 1, 2, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 2, 0,
- 2, 1, 2, 0, 2, 1, 2, 0, 2, 1,
- 2, 0, 2, 1, 2, 0, 2, 1, 1, 2,
- 1, 2, 1, 2, 2, 1, 3, 1, 2, 0,
- 2, 1, 0, 3, 1, 0, 2, 1, 2, 1,
- 3, 1, 2, 1, 3, 1, 2, 1, 3, 1,
- 1, 2, 3, 1, 1, 1, 2, 3, 1, 1,
- 2, 1, 2, 2, 1, 2, 2, 1, 2, 1,
- 1
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 2, 0, 2, 1, 2, 0, 2,
+ 1, 2, 0, 2, 1, 2, 0, 2, 1, 2,
+ 0, 2, 1, 1, 2, 1, 2, 1, 2, 1,
+ 2, 2, 1, 3, 1, 2, 0, 2, 1, 2,
+ 2, 0, 3, 1, 0, 2, 1, 2, 1, 2,
+ 1, 2, 1, 3, 1, 2, 1, 3, 1, 2,
+ 1, 3, 1, 1, 2, 3, 1, 1, 1, 2,
+ 3, 1, 1, 2, 1, 2, 2, 1, 2, 2,
+ 1, 2, 1, 1
};
/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
STATE-NUM when YYTABLE doesn't specify something else to do. Zero
means the default is an error. */
-static const yytype_uint8 yydefact[] =
+static const unsigned char yydefact[] =
{
- 3, 0, 2, 1, 0, 0, 39, 4, 5, 8,
- 6, 12, 9, 10, 16, 38, 11, 41, 40, 0,
- 0, 69, 58, 62, 60, 101, 104, 0, 0, 95,
- 90, 72, 0, 55, 43, 47, 51, 0, 0, 7,
- 110, 37, 13, 14, 33, 35, 36, 34, 30, 32,
- 31, 28, 29, 24, 27, 26, 25, 23, 22, 17,
- 18, 19, 20, 21, 15, 107, 109, 67, 64, 65,
- 89, 86, 87, 68, 59, 63, 61, 102, 105, 100,
- 103, 99, 96, 98, 94, 91, 93, 75, 81, 78,
- 79, 54, 42, 46, 50, 85, 82, 83, 106, 108,
- 0, 0, 71, 70, 0, 0, 73, 74, 0, 57,
- 56, 45, 44, 49, 48, 53, 52, 0, 66, 88,
- 97, 92, 77, 76, 80, 84
+ 3, 0, 2, 1, 0, 0, 44, 4, 5, 8,
+ 6, 12, 9, 10, 16, 43, 11, 46, 45, 0,
+ 0, 76, 63, 67, 65, 69, 114, 117, 0, 0,
+ 108, 103, 81, 0, 60, 48, 52, 56, 0, 0,
+ 0, 0, 88, 90, 7, 123, 42, 13, 14, 38,
+ 40, 41, 39, 34, 36, 35, 37, 30, 31, 32,
+ 33, 24, 27, 28, 29, 26, 25, 23, 22, 17,
+ 18, 19, 20, 21, 15, 120, 122, 74, 71, 72,
+ 102, 99, 100, 75, 64, 68, 66, 70, 115, 118,
+ 113, 116, 112, 109, 111, 107, 104, 106, 84, 94,
+ 87, 92, 59, 47, 51, 55, 98, 95, 96, 119,
+ 79, 80, 89, 91, 121, 0, 0, 78, 77, 0,
+ 0, 82, 83, 0, 62, 61, 50, 49, 54, 53,
+ 58, 57, 0, 73, 101, 110, 105, 86, 85, 93,
+ 97
};
-/* YYDEFGOTO[NTERM-NUM]. */
-static const yytype_int8 yydefgoto[] =
+/* YYDEFGOTO[NTERM-NUM]. */
+static const short int yydefgoto[] =
{
- -1, 1, 2, 7, 41, 8, 9, 10, 16, 42,
- 11, 43, 12, 15, 18, 44, 92, 112, 45, 93,
- 114, 46, 94, 116, 47, 91, 110, 48, 49, 50,
- 51, 68, 69, 52, 73, 103, 53, 87, 106, 107,
- 123, 54, 89, 90, 55, 96, 97, 56, 71, 72,
- 57, 85, 86, 58, 82, 83, 59, 60, 61, 62,
- 63, 64, 65, 66
+ -1, 1, 2, 7, 46, 8, 9, 10, 16, 47,
+ 11, 48, 12, 15, 18, 49, 103, 127, 50, 104,
+ 129, 51, 105, 131, 52, 102, 125, 53, 54, 55,
+ 56, 57, 78, 79, 58, 83, 118, 59, 60, 61,
+ 98, 121, 122, 138, 62, 63, 64, 100, 101, 65,
+ 107, 108, 66, 81, 82, 67, 96, 97, 68, 93,
+ 94, 69, 70, 71, 72, 73, 74, 75, 76
};
/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
STATE-NUM. */
-#define YYPACT_NINF -66
-static const yytype_int8 yypact[] =
+#define YYPACT_NINF -76
+static const yysigned_char yypact[] =
{
- -66, 6, 18, -66, -6, -2, -66, -66, -66, -66,
- -66, -66, -66, -66, -66, -8, -4, -66, -66, -1,
- 0, -66, 1, 4, 5, 7, 8, 9, 13, -3,
- 3, -66, 10, -66, -66, -66, -66, 11, 12, -66,
- -66, -66, -66, -66, -66, -66, -66, -66, -66, -66,
- -66, -66, -66, -66, -66, -66, -66, -66, -66, -66,
- -66, -66, -66, -66, -66, 14, -66, -66, 19, -66,
- -66, -66, 20, 21, -66, -66, -66, -66, -66, -66,
- -66, -66, -66, 22, -66, 23, -66, -66, -66, 25,
- -66, 24, 26, 27, 28, -66, 29, -66, -66, -66,
- -1, 0, -66, -66, -3, 3, -66, 33, 10, -66,
- -66, -66, -66, -66, -66, -66, -66, 11, -66, -66,
- -66, -66, -66, -66, -66, -66
+ -76, 7, 23, -76, -6, -2, -76, -76, -76, -76,
+ -76, -76, -76, -76, -76, -8, -4, -76, -76, -3,
+ -1, -76, 3, 4, 5, 6, 8, 9, 10, 1,
+ 11, 12, -76, 13, -76, -76, -76, -76, 14, 18,
+ 19, 20, 21, 22, -76, -76, -76, -76, -76, -76,
+ -76, -76, -76, -76, -76, -76, -76, -76, -76, -76,
+ -76, -76, -76, -76, -76, -76, -76, -76, -76, -76,
+ -76, -76, -76, -76, -76, 24, -76, -76, 15, -76,
+ -76, -76, 17, 26, -76, -76, -76, -76, -76, -76,
+ -76, -76, -76, -76, 27, -76, 30, -76, -76, -76,
+ 31, -76, 25, 28, 29, 32, -76, 33, -76, -76,
+ -76, -76, -76, -76, -76, -3, -1, -76, -76, 11,
+ 12, -76, 34, 13, -76, -76, -76, -76, -76, -76,
+ -76, -76, 14, -76, -76, -76, -76, -76, -76, -76,
+ -76
};
/* YYPGOTO[NTERM-NUM]. */
-static const yytype_int8 yypgoto[] =
+static const yysigned_char yypgoto[] =
{
- -66, -66, -66, -66, -66, -66, -66, -66, -66, -66,
- -66, -66, -66, -66, -66, -66, -66, -66, -66, -66,
- -66, -66, -66, -66, -66, -66, -66, -66, -66, -66,
- -66, -66, -54, -66, -66, -66, -66, -66, -66, -66,
- -66, -66, -66, -57, -66, -66, -65, -66, -48, -66,
- -66, -66, -50, -66, -47, -66, -66, -66, -66, -66,
- -66, -66, -66, 2
+ -76, -76, -76, -76, -76, -76, -76, -76, -76, -76,
+ -76, -76, -76, -76, -76, -76, -76, -76, -76, -76,
+ -76, -76, -76, -76, -76, -76, -76, -76, -76, -76,
+ -76, -76, -76, -75, -76, -76, -76, -76, -76, -76,
+ -76, -76, -76, -76, -76, -76, -76, -76, -67, -76,
+ -76, -68, -76, -48, -76, -76, -76, -50, -76, -47,
+ -76, -76, -76, -76, -76, -76, -76, -76, 0
};
/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
@@ -695,47 +585,67 @@ static const yytype_int8 yypgoto[] =
number is the opposite. If zero, do what YYDEFACT says.
If YYTABLE_NINF, syntax error. */
#define YYTABLE_NINF -1
-static const yytype_uint8 yytable[] =
+static const unsigned char yytable[] =
{
- 19, 20, 21, 22, 23, 24, 3, 25, 26, 27,
+ 19, 20, 21, 22, 23, 24, 25, 3, 26, 27,
28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
- 38, 4, 13, 39, 17, 40, 14, 81, 5, 74,
- 67, 70, 75, 76, 84, 77, 78, 79, 6, 80,
- 98, 88, 95, 40, 100, 101, 118, 104, 105, 102,
- 108, 124, 125, 119, 117, 121, 109, 120, 111, 113,
- 115, 122, 0, 0, 0, 0, 0, 99
+ 38, 39, 40, 41, 42, 43, 4, 13, 44, 17,
+ 45, 14, 91, 77, 5, 80, 84, 85, 86, 87,
+ 133, 88, 89, 90, 6, 115, 92, 116, 95, 99,
+ 106, 109, 110, 111, 112, 113, 139, 119, 45, 117,
+ 120, 123, 124, 132, 140, 126, 128, 137, 134, 130,
+ 136, 0, 135, 0, 0, 114
};
-static const yytype_int8 yycheck[] =
+static const short int yycheck[] =
{
- 4, 5, 6, 7, 8, 9, 0, 11, 12, 13,
+ 4, 5, 6, 7, 8, 9, 10, 0, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
- 24, 3, 28, 27, 32, 29, 28, 30, 10, 28,
- 31, 31, 28, 28, 31, 28, 28, 28, 20, 26,
- 28, 31, 31, 29, 25, 25, 100, 25, 25, 28,
- 25, 108, 117, 101, 25, 105, 32, 104, 32, 32,
- 32, 28, -1, -1, -1, -1, -1, 65
+ 24, 25, 26, 27, 28, 29, 3, 33, 32, 37,
+ 34, 33, 31, 36, 11, 36, 33, 33, 33, 33,
+ 115, 33, 33, 33, 21, 30, 35, 30, 36, 36,
+ 36, 33, 33, 33, 33, 33, 123, 30, 34, 33,
+ 30, 30, 37, 30, 132, 37, 37, 33, 116, 37,
+ 120, -1, 119, -1, -1, 75
};
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
symbol of state STATE-NUM. */
-static const yytype_uint8 yystos[] =
+static const unsigned char yystos[] =
{
- 0, 34, 35, 0, 3, 10, 20, 36, 38, 39,
- 40, 43, 45, 28, 28, 46, 41, 32, 47, 4,
- 5, 6, 7, 8, 9, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 27,
- 29, 37, 42, 44, 48, 51, 54, 57, 60, 61,
- 62, 63, 66, 69, 74, 77, 80, 83, 86, 89,
- 90, 91, 92, 93, 94, 95, 96, 31, 64, 65,
- 31, 81, 82, 67, 28, 28, 28, 28, 28, 28,
- 26, 30, 87, 88, 31, 84, 85, 70, 31, 75,
- 76, 58, 49, 52, 55, 31, 78, 79, 28, 96,
- 25, 25, 28, 68, 25, 25, 71, 72, 25, 32,
- 59, 32, 50, 32, 53, 32, 56, 25, 65, 81,
- 87, 85, 28, 73, 76, 79
+ 0, 39, 40, 0, 3, 11, 21, 41, 43, 44,
+ 45, 48, 50, 33, 33, 51, 46, 37, 52, 4,
+ 5, 6, 7, 8, 9, 10, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 26, 27, 28, 29, 32, 34, 42, 47, 49, 53,
+ 56, 59, 62, 65, 66, 67, 68, 69, 72, 75,
+ 76, 77, 82, 83, 84, 87, 90, 93, 96, 99,
+ 100, 101, 102, 103, 104, 105, 106, 36, 70, 71,
+ 36, 91, 92, 73, 33, 33, 33, 33, 33, 33,
+ 33, 31, 35, 97, 98, 36, 94, 95, 78, 36,
+ 85, 86, 63, 54, 57, 60, 36, 88, 89, 33,
+ 33, 33, 33, 33, 106, 30, 30, 33, 74, 30,
+ 30, 79, 80, 30, 37, 64, 37, 55, 37, 58,
+ 37, 61, 30, 71, 91, 97, 95, 33, 81, 86,
+ 89
};
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
#define yyerrok (yyerrstatus = 0)
#define yyclearin (yychar = YYEMPTY)
#define YYEMPTY (-2)
@@ -761,15 +671,15 @@ do \
yychar = (Token); \
yylval = (Value); \
yytoken = YYTRANSLATE (yychar); \
- YYPOPSTACK (1); \
+ YYPOPSTACK; \
goto yybackup; \
} \
else \
- { \
- yyerror (YY_("syntax error: cannot back up")); \
+ { \
+ yyerror ("syntax error: cannot back up");\
YYERROR; \
} \
-while (YYID (0))
+while (0)
#define YYTERROR 1
@@ -784,7 +694,7 @@ while (YYID (0))
#ifndef YYLLOC_DEFAULT
# define YYLLOC_DEFAULT(Current, Rhs, N) \
do \
- if (YYID (N)) \
+ if (N) \
{ \
(Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
(Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
@@ -798,7 +708,7 @@ while (YYID (0))
(Current).first_column = (Current).last_column = \
YYRHSLOC (Rhs, 0).last_column; \
} \
- while (YYID (0))
+ while (0)
#endif
@@ -810,8 +720,8 @@ while (YYID (0))
# if YYLTYPE_IS_TRIVIAL
# define YY_LOCATION_PRINT(File, Loc) \
fprintf (File, "%d.%d-%d.%d", \
- (Loc).first_line, (Loc).first_column, \
- (Loc).last_line, (Loc).last_column)
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
# else
# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
# endif
@@ -838,96 +748,36 @@ while (YYID (0))
do { \
if (yydebug) \
YYFPRINTF Args; \
-} while (YYID (0))
-
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
-do { \
- if (yydebug) \
- { \
- YYFPRINTF (stderr, "%s ", Title); \
- yy_symbol_print (stderr, \
- Type, Value); \
- YYFPRINTF (stderr, "\n"); \
- } \
-} while (YYID (0))
+} while (0)
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep)
- FILE *yyoutput;
- int yytype;
- YYSTYPE const * const yyvaluep;
-#endif
-{
- if (!yyvaluep)
- return;
-# ifdef YYPRINT
- if (yytype < YYNTOKENS)
- YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# else
- YYUSE (yyoutput);
-# endif
- switch (yytype)
- {
- default:
- break;
- }
-}
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_print (yyoutput, yytype, yyvaluep)
- FILE *yyoutput;
- int yytype;
- YYSTYPE const * const yyvaluep;
-#endif
-{
- if (yytype < YYNTOKENS)
- YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
- else
- YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
-
- yy_symbol_value_print (yyoutput, yytype, yyvaluep);
- YYFPRINTF (yyoutput, ")");
-}
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yysymprint (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
/*------------------------------------------------------------------.
| yy_stack_print -- Print the state stack from its BOTTOM up to its |
| TOP (included). |
`------------------------------------------------------------------*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
+#if defined (__STDC__) || defined (__cplusplus)
static void
-yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+yy_stack_print (short int *bottom, short int *top)
#else
static void
yy_stack_print (bottom, top)
- yytype_int16 *bottom;
- yytype_int16 *top;
+ short int *bottom;
+ short int *top;
#endif
{
YYFPRINTF (stderr, "Stack now");
- for (; bottom <= top; ++bottom)
+ for (/* Nothing. */; bottom <= top; ++bottom)
YYFPRINTF (stderr, " %d", *bottom);
YYFPRINTF (stderr, "\n");
}
@@ -936,45 +786,37 @@ yy_stack_print (bottom, top)
do { \
if (yydebug) \
yy_stack_print ((Bottom), (Top)); \
-} while (YYID (0))
+} while (0)
/*------------------------------------------------.
| Report that the YYRULE is going to be reduced. |
`------------------------------------------------*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
+#if defined (__STDC__) || defined (__cplusplus)
static void
-yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+yy_reduce_print (int yyrule)
#else
static void
-yy_reduce_print (yyvsp, yyrule)
- YYSTYPE *yyvsp;
+yy_reduce_print (yyrule)
int yyrule;
#endif
{
- int yynrhs = yyr2[yyrule];
int yyi;
- unsigned long int yylno = yyrline[yyrule];
- YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
- yyrule - 1, yylno);
- /* The symbols being reduced. */
- for (yyi = 0; yyi < yynrhs; yyi++)
- {
- fprintf (stderr, " $%d = ", yyi + 1);
- yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
- &(yyvsp[(yyi + 1) - (yynrhs)])
- );
- fprintf (stderr, "\n");
- }
+ unsigned int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
+ yyrule - 1, yylno);
+ /* Print the symbols being reduced, and their result. */
+ for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+ YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
+ YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
}
# define YY_REDUCE_PRINT(Rule) \
do { \
if (yydebug) \
- yy_reduce_print (yyvsp, Rule); \
-} while (YYID (0))
+ yy_reduce_print (Rule); \
+} while (0)
/* Nonzero means print parse trace. It is left uninitialized so that
multiple parsers can coexist. */
@@ -996,7 +838,7 @@ int yydebug;
if the built-in stack extension method is used).
Do not make this value too large; the results are undefined if
- YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
evaluated with infinite-precision integer arithmetic. */
#ifndef YYMAXDEPTH
@@ -1008,47 +850,45 @@ int yydebug;
#if YYERROR_VERBOSE
# ifndef yystrlen
-# if defined __GLIBC__ && defined _STRING_H
+# if defined (__GLIBC__) && defined (_STRING_H)
# define yystrlen strlen
# else
/* Return the length of YYSTR. */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
static YYSIZE_T
+# if defined (__STDC__) || defined (__cplusplus)
yystrlen (const char *yystr)
-#else
-static YYSIZE_T
+# else
yystrlen (yystr)
- const char *yystr;
-#endif
+ const char *yystr;
+# endif
{
- YYSIZE_T yylen;
- for (yylen = 0; yystr[yylen]; yylen++)
+ register const char *yys = yystr;
+
+ while (*yys++ != '\0')
continue;
- return yylen;
+
+ return yys - yystr - 1;
}
# endif
# endif
# ifndef yystpcpy
-# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
# define yystpcpy stpcpy
# else
/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
YYDEST. */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
static char *
+# if defined (__STDC__) || defined (__cplusplus)
yystpcpy (char *yydest, const char *yysrc)
-#else
-static char *
+# else
yystpcpy (yydest, yysrc)
- char *yydest;
- const char *yysrc;
-#endif
+ char *yydest;
+ const char *yysrc;
+# endif
{
- char *yyd = yydest;
- const char *yys = yysrc;
+ register char *yyd = yydest;
+ register const char *yys = yysrc;
while ((*yyd++ = *yys++) != '\0')
continue;
@@ -1058,171 +898,53 @@ yystpcpy (yydest, yysrc)
# endif
# endif
-# ifndef yytnamerr
-/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
- quotes and backslashes, so that it's suitable for yyerror. The
- heuristic is that double-quoting is unnecessary unless the string
- contains an apostrophe, a comma, or backslash (other than
- backslash-backslash). YYSTR is taken from yytname. If YYRES is
- null, do not copy; instead, return the length of what the result
- would have been. */
-static YYSIZE_T
-yytnamerr (char *yyres, const char *yystr)
-{
- if (*yystr == '"')
- {
- YYSIZE_T yyn = 0;
- char const *yyp = yystr;
-
- for (;;)
- switch (*++yyp)
- {
- case '\'':
- case ',':
- goto do_not_strip_quotes;
-
- case '\\':
- if (*++yyp != '\\')
- goto do_not_strip_quotes;
- /* Fall through. */
- default:
- if (yyres)
- yyres[yyn] = *yyp;
- yyn++;
- break;
-
- case '"':
- if (yyres)
- yyres[yyn] = '\0';
- return yyn;
- }
- do_not_strip_quotes: ;
- }
+#endif /* !YYERROR_VERBOSE */
- if (! yyres)
- return yystrlen (yystr);
+
- return yystpcpy (yyres, yystr) - yyres;
-}
-# endif
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
-/* Copy into YYRESULT an error message about the unexpected token
- YYCHAR while in state YYSTATE. Return the number of bytes copied,
- including the terminating null byte. If YYRESULT is null, do not
- copy anything; just return the number of bytes that would be
- copied. As a special case, return 0 if an ordinary "syntax error"
- message will do. Return YYSIZE_MAXIMUM if overflow occurs during
- size calculation. */
-static YYSIZE_T
-yysyntax_error (char *yyresult, int yystate, int yychar)
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
{
- int yyn = yypact[yystate];
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
- if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
- return 0;
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
else
- {
- int yytype = YYTRANSLATE (yychar);
- YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
- YYSIZE_T yysize = yysize0;
- YYSIZE_T yysize1;
- int yysize_overflow = 0;
- enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
- char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
- int yyx;
-
-# if 0
- /* This is so xgettext sees the translatable formats that are
- constructed on the fly. */
- YY_("syntax error, unexpected %s");
- YY_("syntax error, unexpected %s, expecting %s");
- YY_("syntax error, unexpected %s, expecting %s or %s");
- YY_("syntax error, unexpected %s, expecting %s or %s or %s");
- YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
# endif
- char *yyfmt;
- char const *yyf;
- static char const yyunexpected[] = "syntax error, unexpected %s";
- static char const yyexpecting[] = ", expecting %s";
- static char const yyor[] = " or %s";
- char yyformat[sizeof yyunexpected
- + sizeof yyexpecting - 1
- + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
- * (sizeof yyor - 1))];
- char const *yyprefix = yyexpecting;
-
- /* Start YYX at -YYN if negative to avoid negative indexes in
- YYCHECK. */
- int yyxbegin = yyn < 0 ? -yyn : 0;
-
- /* Stay within bounds of both yycheck and yytname. */
- int yychecklim = YYLAST - yyn + 1;
- int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
- int yycount = 1;
-
- yyarg[0] = yytname[yytype];
- yyfmt = yystpcpy (yyformat, yyunexpected);
-
- for (yyx = yyxbegin; yyx < yyxend; ++yyx)
- if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
- {
- if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
- {
- yycount = 1;
- yysize = yysize0;
- yyformat[sizeof yyunexpected - 1] = '\0';
- break;
- }
- yyarg[yycount++] = yytname[yyx];
- yysize1 = yysize + yytnamerr (0, yytname[yyx]);
- yysize_overflow |= (yysize1 < yysize);
- yysize = yysize1;
- yyfmt = yystpcpy (yyfmt, yyprefix);
- yyprefix = yyor;
- }
-
- yyf = YY_(yyformat);
- yysize1 = yysize + yystrlen (yyf);
- yysize_overflow |= (yysize1 < yysize);
- yysize = yysize1;
-
- if (yysize_overflow)
- return YYSIZE_MAXIMUM;
-
- if (yyresult)
- {
- /* Avoid sprintf, as that infringes on the user's name space.
- Don't have undefined behavior even if the translation
- produced a string with the wrong number of "%s"s. */
- char *yyp = yyresult;
- int yyi = 0;
- while ((*yyp = *yyf) != '\0')
- {
- if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
- {
- yyp += yytnamerr (yyp, yyarg[yyi++]);
- yyf += 2;
- }
- else
- {
- yyp++;
- yyf++;
- }
- }
- }
- return yysize;
+ switch (yytype)
+ {
+ default:
+ break;
}
+ YYFPRINTF (yyoutput, ")");
}
-#endif /* YYERROR_VERBOSE */
-
+#endif /* ! YYDEBUG */
/*-----------------------------------------------.
| Release the memory associated to this symbol. |
`-----------------------------------------------*/
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
+#if defined (__STDC__) || defined (__cplusplus)
static void
yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
#else
@@ -1233,7 +955,8 @@ yydestruct (yymsg, yytype, yyvaluep)
YYSTYPE *yyvaluep;
#endif
{
- YYUSE (yyvaluep);
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
if (!yymsg)
yymsg = "Deleting";
@@ -1243,7 +966,7 @@ yydestruct (yymsg, yytype, yyvaluep)
{
default:
- break;
+ break;
}
}
@@ -1251,13 +974,13 @@ yydestruct (yymsg, yytype, yyvaluep)
/* Prevent warnings from -Wmissing-prototypes. */
#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
+# if defined (__STDC__) || defined (__cplusplus)
int yyparse (void *YYPARSE_PARAM);
-#else
+# else
int yyparse ();
-#endif
+# endif
#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
+#if defined (__STDC__) || defined (__cplusplus)
int yyparse (void);
#else
int yyparse ();
@@ -1282,18 +1005,14 @@ int yynerrs;
`----------*/
#ifdef YYPARSE_PARAM
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void *YYPARSE_PARAM)
-#else
-int
-yyparse (YYPARSE_PARAM)
- void *YYPARSE_PARAM;
-#endif
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+# endif
#else /* ! YYPARSE_PARAM */
-#if (defined __STDC__ || defined __C99__FUNC__ \
- || defined __cplusplus || defined _MSC_VER)
+#if defined (__STDC__) || defined (__cplusplus)
int
yyparse (void)
#else
@@ -1304,19 +1023,13 @@ yyparse ()
#endif
{
- int yystate;
- int yyn;
+ register int yystate;
+ register int yyn;
int yyresult;
/* Number of tokens to shift before error messages enabled. */
int yyerrstatus;
/* Look-ahead token as an internal (translated) token number. */
int yytoken = 0;
-#if YYERROR_VERBOSE
- /* Buffer for error messages, and its allocated size. */
- char yymsgbuf[128];
- char *yymsg = yymsgbuf;
- YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
-#endif
/* Three stacks and their tools:
`yyss': related to states,
@@ -1327,18 +1040,18 @@ yyparse ()
to reallocate them elsewhere. */
/* The state stack. */
- yytype_int16 yyssa[YYINITDEPTH];
- yytype_int16 *yyss = yyssa;
- yytype_int16 *yyssp;
+ short int yyssa[YYINITDEPTH];
+ short int *yyss = yyssa;
+ register short int *yyssp;
/* The semantic value stack. */
YYSTYPE yyvsa[YYINITDEPTH];
YYSTYPE *yyvs = yyvsa;
- YYSTYPE *yyvsp;
+ register YYSTYPE *yyvsp;
-#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+#define YYPOPSTACK (yyvsp--, yyssp--)
YYSIZE_T yystacksize = YYINITDEPTH;
@@ -1347,9 +1060,9 @@ yyparse ()
YYSTYPE yyval;
- /* The number of symbols on the RHS of the reduced rule.
- Keep to zero when no symbol should be popped. */
- int yylen = 0;
+ /* When reducing, the number of symbols on the RHS of the reduced
+ rule. */
+ int yylen;
YYDPRINTF ((stderr, "Starting parse\n"));
@@ -1366,6 +1079,9 @@ yyparse ()
yyssp = yyss;
yyvsp = yyvs;
+
+ yyvsp[0] = yylval;
+
goto yysetstate;
/*------------------------------------------------------------.
@@ -1373,7 +1089,8 @@ yyparse ()
`------------------------------------------------------------*/
yynewstate:
/* In all cases, when you get here, the value and location stacks
- have just been pushed. So pushing a state here evens the stacks. */
+ have just been pushed. so pushing a state here evens the stacks.
+ */
yyssp++;
yysetstate:
@@ -1386,18 +1103,18 @@ yyparse ()
#ifdef yyoverflow
{
- /* Give user a chance to reallocate the stack. Use copies of
+ /* Give user a chance to reallocate the stack. Use copies of
these so that the &'s don't force the real ones into
memory. */
YYSTYPE *yyvs1 = yyvs;
- yytype_int16 *yyss1 = yyss;
+ short int *yyss1 = yyss;
/* Each stack pointer address is followed by the size of the
data in use in that stack, in bytes. This used to be a
conditional around just the two extra args, but that might
be undefined if yyoverflow is a macro. */
- yyoverflow (YY_("memory exhausted"),
+ yyoverflow ("parser stack overflow",
&yyss1, yysize * sizeof (*yyssp),
&yyvs1, yysize * sizeof (*yyvsp),
@@ -1408,21 +1125,21 @@ yyparse ()
}
#else /* no yyoverflow */
# ifndef YYSTACK_RELOCATE
- goto yyexhaustedlab;
+ goto yyoverflowlab;
# else
/* Extend the stack our own way. */
if (YYMAXDEPTH <= yystacksize)
- goto yyexhaustedlab;
+ goto yyoverflowlab;
yystacksize *= 2;
if (YYMAXDEPTH < yystacksize)
yystacksize = YYMAXDEPTH;
{
- yytype_int16 *yyss1 = yyss;
+ short int *yyss1 = yyss;
union yyalloc *yyptr =
(union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
if (! yyptr)
- goto yyexhaustedlab;
+ goto yyoverflowlab;
YYSTACK_RELOCATE (yyss);
YYSTACK_RELOCATE (yyvs);
@@ -1453,10 +1170,12 @@ yyparse ()
`-----------*/
yybackup:
- /* Do appropriate processing given the current state. Read a
- look-ahead token if we need one and don't already have one. */
+/* Do appropriate processing given the current state. */
+/* Read a look-ahead token if we need one and don't already have one. */
+/* yyresume: */
/* First try to decide what to do without reference to look-ahead token. */
+
yyn = yypact[yystate];
if (yyn == YYPACT_NINF)
goto yydefault;
@@ -1498,21 +1217,22 @@ yybackup:
if (yyn == YYFINAL)
YYACCEPT;
- /* Count tokens shifted since error; after three, turn off error
- status. */
- if (yyerrstatus)
- yyerrstatus--;
-
/* Shift the look-ahead token. */
YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
- /* Discard the shifted token unless it is eof. */
+ /* Discard the token being shifted unless it is eof. */
if (yychar != YYEOF)
yychar = YYEMPTY;
- yystate = yyn;
*++yyvsp = yylval;
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ yystate = yyn;
goto yynewstate;
@@ -1548,60 +1268,60 @@ yyreduce:
switch (yyn)
{
case 2:
-#line 66 "levcomp.ypp"
+#line 67 "levcomp.ypp"
{ }
break;
case 3:
-#line 69 "levcomp.ypp"
+#line 70 "levcomp.ypp"
{}
break;
case 4:
-#line 70 "levcomp.ypp"
+#line 71 "levcomp.ypp"
{}
break;
case 5:
-#line 73 "levcomp.ypp"
+#line 74 "levcomp.ypp"
{}
break;
case 6:
-#line 74 "levcomp.ypp"
+#line 75 "levcomp.ypp"
{}
break;
case 7:
-#line 78 "levcomp.ypp"
+#line 79 "levcomp.ypp"
{
yyerror("Unexpected character sequence.");
}
break;
case 8:
-#line 83 "levcomp.ypp"
+#line 84 "levcomp.ypp"
{}
break;
case 9:
-#line 84 "levcomp.ypp"
+#line 85 "levcomp.ypp"
{}
break;
case 10:
-#line 88 "levcomp.ypp"
+#line 89 "levcomp.ypp"
{
dgn_reset_default_depth();
- std::string err = dgn_set_default_depth((yyvsp[(2) - (2)].text));
+ std::string err = dgn_set_default_depth((yyvsp[0].text));
if (!err.empty())
yyerror(make_stringf("Bad default-depth: %s (%s)",
- (yyvsp[(2) - (2)].text), err.c_str()).c_str());
+ (yyvsp[0].text), err.c_str()).c_str());
}
break;
case 11:
-#line 98 "levcomp.ypp"
+#line 99 "levcomp.ypp"
{
lc_map.set_file(lc_desfile);
@@ -1624,285 +1344,315 @@ yyreduce:
break;
case 12:
-#line 119 "levcomp.ypp"
+#line 120 "levcomp.ypp"
{ }
break;
case 13:
-#line 120 "levcomp.ypp"
+#line 121 "levcomp.ypp"
{ }
break;
case 14:
-#line 123 "levcomp.ypp"
+#line 124 "levcomp.ypp"
{ }
break;
case 15:
-#line 124 "levcomp.ypp"
+#line 125 "levcomp.ypp"
{ }
break;
case 16:
-#line 128 "levcomp.ypp"
+#line 129 "levcomp.ypp"
{
lc_map.init();
- lc_map.name = (yyvsp[(2) - (2)].text);
+ lc_map.name = (yyvsp[0].text);
map_load_info_t::const_iterator i =
- lc_loaded_maps.find((yyvsp[(2) - (2)].text));
+ lc_loaded_maps.find((yyvsp[0].text));
if (i != lc_loaded_maps.end())
{
yyerror(
make_stringf(
"Map named '%s' already loaded at %s:%d",
- (yyvsp[(2) - (2)].text),
+ (yyvsp[0].text),
i->second.filename.c_str(),
i->second.lineno).c_str() );
}
lc_map.place_loaded_from =
map_file_place(lc_desfile, yylineno);
- lc_loaded_maps[(yyvsp[(2) - (2)].text)] = lc_map.place_loaded_from;
+ lc_loaded_maps[(yyvsp[0].text)] = lc_map.place_loaded_from;
}
break;
- case 37:
-#line 171 "levcomp.ypp"
+ case 42:
+#line 177 "levcomp.ypp"
{}
break;
- case 38:
-#line 174 "levcomp.ypp"
+ case 43:
+#line 180 "levcomp.ypp"
{ }
break;
- case 39:
-#line 176 "levcomp.ypp"
+ case 44:
+#line 182 "levcomp.ypp"
{ }
break;
- case 40:
-#line 177 "levcomp.ypp"
+ case 45:
+#line 183 "levcomp.ypp"
{ }
break;
- case 41:
-#line 181 "levcomp.ypp"
+ case 46:
+#line 187 "levcomp.ypp"
{
- lc_global_prelude.add(yylineno, (yyvsp[(1) - (1)].text));
+ lc_global_prelude.add(yylineno, (yyvsp[0].text));
}
break;
- case 42:
-#line 185 "levcomp.ypp"
+ case 47:
+#line 191 "levcomp.ypp"
{ }
break;
- case 43:
-#line 187 "levcomp.ypp"
+ case 48:
+#line 193 "levcomp.ypp"
{ }
break;
- case 44:
-#line 188 "levcomp.ypp"
+ case 49:
+#line 194 "levcomp.ypp"
{ }
break;
- case 45:
-#line 192 "levcomp.ypp"
+ case 50:
+#line 198 "levcomp.ypp"
{
- lc_map.main.add(yylineno, (yyvsp[(1) - (1)].text));
+ lc_map.main.add(yylineno, (yyvsp[0].text));
}
break;
- case 46:
-#line 196 "levcomp.ypp"
+ case 51:
+#line 202 "levcomp.ypp"
{ }
break;
- case 47:
-#line 198 "levcomp.ypp"
+ case 52:
+#line 204 "levcomp.ypp"
{ }
break;
- case 48:
-#line 199 "levcomp.ypp"
+ case 53:
+#line 205 "levcomp.ypp"
{ }
break;
- case 49:
-#line 203 "levcomp.ypp"
+ case 54:
+#line 209 "levcomp.ypp"
{
- lc_map.validate.add(yylineno, (yyvsp[(1) - (1)].text));
+ lc_map.validate.add(yylineno, (yyvsp[0].text));
}
break;
- case 50:
-#line 207 "levcomp.ypp"
+ case 55:
+#line 213 "levcomp.ypp"
{ }
break;
- case 51:
-#line 209 "levcomp.ypp"
+ case 56:
+#line 215 "levcomp.ypp"
{ }
break;
- case 52:
-#line 210 "levcomp.ypp"
+ case 57:
+#line 216 "levcomp.ypp"
{ }
break;
- case 53:
-#line 214 "levcomp.ypp"
+ case 58:
+#line 220 "levcomp.ypp"
{
- lc_map.veto.add(yylineno, (yyvsp[(1) - (1)].text));
+ lc_map.veto.add(yylineno, (yyvsp[0].text));
}
break;
- case 54:
-#line 218 "levcomp.ypp"
+ case 59:
+#line 224 "levcomp.ypp"
{ }
break;
- case 55:
-#line 220 "levcomp.ypp"
+ case 60:
+#line 226 "levcomp.ypp"
{ }
break;
- case 56:
-#line 221 "levcomp.ypp"
+ case 61:
+#line 227 "levcomp.ypp"
{ }
break;
- case 57:
-#line 225 "levcomp.ypp"
+ case 62:
+#line 231 "levcomp.ypp"
{
- lc_map.prelude.add(yylineno, (yyvsp[(1) - (1)].text));
+ lc_map.prelude.add(yylineno, (yyvsp[0].text));
}
break;
- case 58:
-#line 229 "levcomp.ypp"
+ case 63:
+#line 235 "levcomp.ypp"
{ }
break;
- case 59:
-#line 231 "levcomp.ypp"
+ case 64:
+#line 237 "levcomp.ypp"
{
lc_map.main.add(
yylineno,
make_stringf("kfeat(\"%s\")",
- quote_lua_string((yyvsp[(2) - (2)].text)).c_str()));
+ quote_lua_string((yyvsp[0].text)).c_str()));
}
break;
- case 60:
-#line 238 "levcomp.ypp"
+ case 65:
+#line 244 "levcomp.ypp"
{ }
break;
- case 61:
-#line 240 "levcomp.ypp"
+ case 66:
+#line 246 "levcomp.ypp"
{
lc_map.main.add(
yylineno,
make_stringf("kmons(\"%s\")",
- quote_lua_string((yyvsp[(2) - (2)].text)).c_str()));
+ quote_lua_string((yyvsp[0].text)).c_str()));
}
break;
- case 62:
-#line 247 "levcomp.ypp"
+ case 67:
+#line 253 "levcomp.ypp"
{ }
break;
- case 63:
-#line 249 "levcomp.ypp"
+ case 68:
+#line 255 "levcomp.ypp"
{
lc_map.main.add(
yylineno,
make_stringf("kitem(\"%s\")",
- quote_lua_string((yyvsp[(2) - (2)].text)).c_str()));
+ quote_lua_string((yyvsp[0].text)).c_str()));
}
break;
- case 64:
-#line 256 "levcomp.ypp"
- {}
+ case 69:
+#line 262 "levcomp.ypp"
+ { }
break;
- case 67:
+ case 70:
#line 264 "levcomp.ypp"
{
lc_map.main.add(
yylineno,
- make_stringf("shuffle(\"%s\")",
- quote_lua_string((yyvsp[(1) - (1)].text)).c_str()));
+ make_stringf("kmask(\"%s\")",
+ quote_lua_string((yyvsp[0].text)).c_str()));
}
break;
- case 68:
+ case 71:
#line 271 "levcomp.ypp"
{}
break;
- case 71:
+ case 74:
#line 279 "levcomp.ypp"
{
lc_map.main.add(
yylineno,
+ make_stringf("shuffle(\"%s\")",
+ quote_lua_string((yyvsp[0].text)).c_str()));
+ }
+ break;
+
+ case 75:
+#line 286 "levcomp.ypp"
+ {}
+ break;
+
+ case 78:
+#line 294 "levcomp.ypp"
+ {
+ lc_map.main.add(
+ yylineno,
make_stringf("tags(\"%s\")",
- quote_lua_string((yyvsp[(1) - (1)].text)).c_str()));
+ quote_lua_string((yyvsp[0].text)).c_str()));
}
break;
- case 72:
-#line 288 "levcomp.ypp"
+ case 79:
+#line 303 "levcomp.ypp"
+ {
+ lc_map.main.add(
+ yylineno,
+ make_stringf("lflags(\"%s\")",
+ quote_lua_string((yyvsp[0].text)).c_str()));
+ }
+ break;
+
+ case 80:
+#line 312 "levcomp.ypp"
+ {
+ lc_map.main.add(
+ yylineno,
+ make_stringf("bflags(\"%s\")",
+ quote_lua_string((yyvsp[0].text)).c_str()));
+ }
+ break;
+
+ case 81:
+#line 321 "levcomp.ypp"
{
lc_map.main.add(yylineno, "marker(");
start_marker_segment = true;
}
break;
- case 73:
-#line 293 "levcomp.ypp"
+ case 82:
+#line 326 "levcomp.ypp"
{
lc_map.main.add(yylineno, ")");
}
break;
- case 77:
-#line 305 "levcomp.ypp"
+ case 86:
+#line 338 "levcomp.ypp"
{
lc_map.main.add(
yylineno,
make_stringf(
"%s\"%s\"",
start_marker_segment? "" : " .. ",
- quote_lua_string((yyvsp[(1) - (1)].text)).c_str()));
+ quote_lua_string((yyvsp[0].text)).c_str()));
start_marker_segment = false;
}
break;
- case 78:
-#line 316 "levcomp.ypp"
+ case 87:
+#line 349 "levcomp.ypp"
{ }
break;
- case 79:
-#line 319 "levcomp.ypp"
+ case 88:
+#line 352 "levcomp.ypp"
{ }
break;
- case 80:
-#line 320 "levcomp.ypp"
- { }
- break;
-
- case 81:
-#line 324 "levcomp.ypp"
+ case 89:
+#line 354 "levcomp.ypp"
{
lc_map.main.add(
yylineno,
@@ -1930,145 +1680,206 @@ yyreduce:
#line 340 "levcomp.ypp"
{
lc_map.main.add(
+ yylineno,
+ make_stringf("floor_colour(\"%s\")",
+ quote_lua_string((yyvsp[0].text)).c_str()));
+ }
+ break;
+
+ case 90:
+#line 361 "levcomp.ypp"
+ { }
+ break;
+
+ case 91:
+#line 363 "levcomp.ypp"
+ {
+ lc_map.main.add(
+ yylineno,
+ make_stringf("rock_colour(\"%s\")",
+ quote_lua_string((yyvsp[0].text)).c_str()));
+ }
+ break;
+
+ case 92:
+#line 370 "levcomp.ypp"
+ { }
+ break;
+
+ case 93:
+#line 371 "levcomp.ypp"
+ { }
+ break;
+
+ case 94:
+#line 375 "levcomp.ypp"
+ {
+ lc_map.main.add(
+ yylineno,
+ make_stringf("colour(\"%s\")",
+ quote_lua_string((yyvsp[0].text)).c_str()));
+ }
+ break;
+
+ case 95:
+#line 383 "levcomp.ypp"
+ { }
+ break;
+
+ case 96:
+#line 386 "levcomp.ypp"
+ { }
+ break;
+
+ case 97:
+#line 387 "levcomp.ypp"
+ { }
+ break;
+
+ case 98:
+#line 391 "levcomp.ypp"
+ {
+ lc_map.main.add(
yylineno,
make_stringf("nsubst(\"%s\")",
- quote_lua_string((yyvsp[(1) - (1)].text)).c_str()));
+ quote_lua_string((yyvsp[0].text)).c_str()));
}
break;
- case 86:
-#line 348 "levcomp.ypp"
+ case 99:
+#line 399 "levcomp.ypp"
{ }
break;
- case 89:
-#line 356 "levcomp.ypp"
+ case 102:
+#line 407 "levcomp.ypp"
{
lc_map.main.add(
yylineno,
make_stringf("subst(\"%s\")",
- quote_lua_string((yyvsp[(1) - (1)].text)).c_str()));
+ quote_lua_string((yyvsp[0].text)).c_str()));
}
break;
- case 90:
-#line 364 "levcomp.ypp"
+ case 103:
+#line 415 "levcomp.ypp"
{}
break;
- case 91:
-#line 365 "levcomp.ypp"
+ case 104:
+#line 416 "levcomp.ypp"
{}
break;
- case 94:
-#line 373 "levcomp.ypp"
+ case 107:
+#line 424 "levcomp.ypp"
{
lc_map.main.add(
yylineno,
make_stringf("item(\"%s\")",
- quote_lua_string((yyvsp[(1) - (1)].text)).c_str()));
+ quote_lua_string((yyvsp[0].text)).c_str()));
}
break;
- case 95:
-#line 380 "levcomp.ypp"
+ case 108:
+#line 431 "levcomp.ypp"
{}
break;
- case 96:
-#line 381 "levcomp.ypp"
+ case 109:
+#line 432 "levcomp.ypp"
{}
break;
- case 99:
-#line 389 "levcomp.ypp"
+ case 112:
+#line 440 "levcomp.ypp"
{
lc_map.main.add(
yylineno,
make_stringf("mons(\"%s\")",
- quote_lua_string((yyvsp[(1) - (1)].text)).c_str()));
+ quote_lua_string((yyvsp[0].text)).c_str()));
}
break;
- case 100:
-#line 398 "levcomp.ypp"
+ case 113:
+#line 449 "levcomp.ypp"
{
lc_map.main.add(
yylineno,
make_stringf("place(\"%s\")",
- quote_lua_string((yyvsp[(2) - (2)].text)).c_str()));
+ quote_lua_string((yyvsp[0].text)).c_str()));
}
break;
- case 101:
-#line 406 "levcomp.ypp"
+ case 114:
+#line 457 "levcomp.ypp"
{}
break;
- case 102:
-#line 408 "levcomp.ypp"
+ case 115:
+#line 459 "levcomp.ypp"
{
lc_map.main.add(
yylineno,
make_stringf("depth(\"%s\")",
- quote_lua_string((yyvsp[(2) - (2)].text)).c_str()));
+ quote_lua_string((yyvsp[0].text)).c_str()));
}
break;
- case 103:
-#line 417 "levcomp.ypp"
+ case 116:
+#line 468 "levcomp.ypp"
{
lc_map.main.add(
yylineno,
- make_stringf("chance(\"%d\")", (yyvsp[(2) - (2)].i)));
+ make_stringf("chance(\"%d\")", (yyvsp[0].i)));
}
break;
- case 104:
-#line 424 "levcomp.ypp"
+ case 117:
+#line 475 "levcomp.ypp"
{}
break;
- case 105:
-#line 426 "levcomp.ypp"
+ case 118:
+#line 477 "levcomp.ypp"
{
lc_map.main.add(
yylineno,
make_stringf("orient(\"%s\")",
- quote_lua_string((yyvsp[(2) - (2)].text)).c_str()));
+ quote_lua_string((yyvsp[0].text)).c_str()));
}
break;
- case 106:
-#line 435 "levcomp.ypp"
+ case 119:
+#line 486 "levcomp.ypp"
{
lc_map.main.add(
yylineno,
make_stringf("welcome(\"%s\")",
- quote_lua_string((yyvsp[(2) - (2)].text)).c_str()));
+ quote_lua_string((yyvsp[0].text)).c_str()));
}
break;
- case 110:
-#line 451 "levcomp.ypp"
+ case 123:
+#line 502 "levcomp.ypp"
{
lc_map.main.add(
yylineno,
make_stringf("map(\"%s\")",
- quote_lua_string((yyvsp[(1) - (1)].text)).c_str()));
+ quote_lua_string((yyvsp[0].text)).c_str()));
}
break;
-/* Line 1267 of yacc.c. */
-#line 2066 "levcomp.tab.c"
- default: break;
}
- YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
- YYPOPSTACK (yylen);
- yylen = 0;
+/* Line 1037 of yacc.c. */
+#line 1853 "levcomp.tab.c"
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+
+
YY_STACK_PRINT (yyss, yyssp);
*++yyvsp = yyval;
@@ -2097,41 +1908,66 @@ yyerrlab:
if (!yyerrstatus)
{
++yynerrs;
-#if ! YYERROR_VERBOSE
- yyerror (YY_("syntax error"));
-#else
- {
- YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
- if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
- {
- YYSIZE_T yyalloc = 2 * yysize;
- if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
- yyalloc = YYSTACK_ALLOC_MAXIMUM;
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
- yymsg = (char *) YYSTACK_ALLOC (yyalloc);
- if (yymsg)
- yymsg_alloc = yyalloc;
- else
+#if YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (YYPACT_NINF < yyn && yyn < YYLAST)
+ {
+ YYSIZE_T yysize = 0;
+ int yytype = YYTRANSLATE (yychar);
+ const char* yyprefix;
+ char *yymsg;
+ int yyx;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 0;
+
+ yyprefix = ", expecting ";
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
{
- yymsg = yymsgbuf;
- yymsg_alloc = sizeof yymsgbuf;
+ yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]);
+ yycount += 1;
+ if (yycount == 5)
+ {
+ yysize = 0;
+ break;
+ }
}
- }
-
- if (0 < yysize && yysize <= yymsg_alloc)
- {
- (void) yysyntax_error (yymsg, yystate, yychar);
- yyerror (yymsg);
- }
- else
- {
- yyerror (YY_("syntax error"));
- if (yysize != 0)
- goto yyexhaustedlab;
- }
- }
-#endif
+ yysize += (sizeof ("syntax error, unexpected ")
+ + yystrlen (yytname[yytype]));
+ yymsg = (char *) YYSTACK_ALLOC (yysize);
+ if (yymsg != 0)
+ {
+ char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
+ yyp = yystpcpy (yyp, yytname[yytype]);
+
+ if (yycount < 5)
+ {
+ yyprefix = ", expecting ";
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ yyp = yystpcpy (yyp, yyprefix);
+ yyp = yystpcpy (yyp, yytname[yyx]);
+ yyprefix = " or ";
+ }
+ }
+ yyerror (yymsg);
+ YYSTACK_FREE (yymsg);
+ }
+ else
+ yyerror ("syntax error; also virtual memory exhausted");
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror ("syntax error");
}
@@ -2142,15 +1978,23 @@ yyerrlab:
error, discard it. */
if (yychar <= YYEOF)
- {
- /* Return failure if at end of input. */
+ {
+ /* If at end of input, pop the error token,
+ then the rest of the stack, then return failure. */
if (yychar == YYEOF)
- YYABORT;
- }
+ for (;;)
+ {
+
+ YYPOPSTACK;
+ if (yyssp == yyss)
+ YYABORT;
+ yydestruct ("Error: popping",
+ yystos[*yyssp], yyvsp);
+ }
+ }
else
{
- yydestruct ("Error: discarding",
- yytoken, &yylval);
+ yydestruct ("Error: discarding", yytoken, &yylval);
yychar = YYEMPTY;
}
}
@@ -2165,17 +2009,15 @@ yyerrlab:
`---------------------------------------------------*/
yyerrorlab:
- /* Pacify compilers like GCC when the user code never invokes
- YYERROR and the label yyerrorlab therefore never appears in user
- code. */
- if (/*CONSTCOND*/ 0)
+#ifdef __GNUC__
+ /* Pacify GCC when the user code never invokes YYERROR and the label
+ yyerrorlab therefore never appears in user code. */
+ if (0)
goto yyerrorlab;
+#endif
- /* Do not reclaim the symbols of the rule which action triggered
- this YYERROR. */
- YYPOPSTACK (yylen);
- yylen = 0;
- YY_STACK_PRINT (yyss, yyssp);
+yyvsp -= yylen;
+ yyssp -= yylen;
yystate = *yyssp;
goto yyerrlab1;
@@ -2205,9 +2047,8 @@ yyerrlab1:
YYABORT;
- yydestruct ("Error: popping",
- yystos[yystate], yyvsp);
- YYPOPSTACK (1);
+ yydestruct ("Error: popping", yystos[yystate], yyvsp);
+ YYPOPSTACK;
yystate = *yyssp;
YY_STACK_PRINT (yyss, yyssp);
}
@@ -2218,7 +2059,7 @@ yyerrlab1:
*++yyvsp = yylval;
- /* Shift the error token. */
+ /* Shift the error token. */
YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
yystate = yyn;
@@ -2236,46 +2077,31 @@ yyacceptlab:
| yyabortlab -- YYABORT comes here. |
`-----------------------------------*/
yyabortlab:
+ yydestruct ("Error: discarding lookahead",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
yyresult = 1;
goto yyreturn;
#ifndef yyoverflow
-/*-------------------------------------------------.
-| yyexhaustedlab -- memory exhaustion comes here. |
-`-------------------------------------------------*/
-yyexhaustedlab:
- yyerror (YY_("memory exhausted"));
+/*----------------------------------------------.
+| yyoverflowlab -- parser overflow comes here. |
+`----------------------------------------------*/
+yyoverflowlab:
+ yyerror ("parser stack overflow");
yyresult = 2;
/* Fall through. */
#endif
yyreturn:
- if (yychar != YYEOF && yychar != YYEMPTY)
- yydestruct ("Cleanup: discarding lookahead",
- yytoken, &yylval);
- /* Do not reclaim the symbols of the rule which action triggered
- this YYABORT or YYACCEPT. */
- YYPOPSTACK (yylen);
- YY_STACK_PRINT (yyss, yyssp);
- while (yyssp != yyss)
- {
- yydestruct ("Cleanup: popping",
- yystos[*yyssp], yyvsp);
- YYPOPSTACK (1);
- }
#ifndef yyoverflow
if (yyss != yyssa)
YYSTACK_FREE (yyss);
#endif
-#if YYERROR_VERBOSE
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
-#endif
- /* Make sure YYID is used. */
- return YYID (yyresult);
+ return yyresult;
}
-#line 459 "levcomp.ypp"
+#line 510 "levcomp.ypp"
diff --git a/crawl-ref/source/prebuilt/levcomp.tab.h b/crawl-ref/source/prebuilt/levcomp.tab.h
index 4eb150880f..4d3e2e81e2 100644
--- a/crawl-ref/source/prebuilt/levcomp.tab.h
+++ b/crawl-ref/source/prebuilt/levcomp.tab.h
@@ -1,9 +1,7 @@
-/* A Bison parser, made by GNU Bison 2.3. */
+/* A Bison parser, made by GNU Bison 2.0. */
-/* Skeleton interface for Bison's Yacc-like parsers in C
-
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- Free Software Foundation, Inc.
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,21 +15,13 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
-
-/* As a special exception, you may create a larger work that contains
- part or all of the Bison parser skeleton and distribute that work
- under terms of your choice, so long as that work isn't itself a
- parser generator using the skeleton or a modified version thereof
- as a parser skeleton. Alternatively, if you modify or redistribute
- the parser skeleton itself, you may (at your option) remove this
- special exception, which will cause the skeleton and the resulting
- Bison output files to be licensed under the GNU General Public
- License without this special exception.
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
- This special exception was added by the Free Software Foundation in
- version 2.2 of Bison. */
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
/* Tokens. */
#ifndef YYTOKENTYPE
@@ -46,32 +36,36 @@
KFEAT = 262,
KITEM = 263,
KMONS = 264,
- NAME = 265,
- DEPTH = 266,
- ORIENT = 267,
- PLACE = 268,
- CHANCE = 269,
- MONS = 270,
- ITEM = 271,
- MARKER = 272,
- COLOUR = 273,
- PRELUDE = 274,
- MAIN = 275,
- VALIDATE = 276,
- VETO = 277,
- NSUBST = 278,
- WELCOME = 279,
- COMMA = 280,
- INTEGER = 281,
- CHARACTER = 282,
- STRING = 283,
- MAP_LINE = 284,
- MONSTER_NAME = 285,
- ITEM_INFO = 286,
- LUA_LINE = 287
+ KMASK = 265,
+ NAME = 266,
+ DEPTH = 267,
+ ORIENT = 268,
+ PLACE = 269,
+ CHANCE = 270,
+ MONS = 271,
+ ITEM = 272,
+ MARKER = 273,
+ COLOUR = 274,
+ PRELUDE = 275,
+ MAIN = 276,
+ VALIDATE = 277,
+ VETO = 278,
+ NSUBST = 279,
+ WELCOME = 280,
+ LFLAGS = 281,
+ BFLAGS = 282,
+ FLOORCOL = 283,
+ ROCKCOL = 284,
+ COMMA = 285,
+ INTEGER = 286,
+ CHARACTER = 287,
+ STRING = 288,
+ MAP_LINE = 289,
+ MONSTER_NAME = 290,
+ ITEM_INFO = 291,
+ LUA_LINE = 292
};
#endif
-/* Tokens. */
#define DEFAULT_DEPTH 258
#define SHUFFLE 259
#define SUBST 260
@@ -79,44 +73,47 @@
#define KFEAT 262
#define KITEM 263
#define KMONS 264
-#define NAME 265
-#define DEPTH 266
-#define ORIENT 267
-#define PLACE 268
-#define CHANCE 269
-#define MONS 270
-#define ITEM 271
-#define MARKER 272
-#define COLOUR 273
-#define PRELUDE 274
-#define MAIN 275
-#define VALIDATE 276
-#define VETO 277
-#define NSUBST 278
-#define WELCOME 279
-#define COMMA 280
-#define INTEGER 281
-#define CHARACTER 282
-#define STRING 283
-#define MAP_LINE 284
-#define MONSTER_NAME 285
-#define ITEM_INFO 286
-#define LUA_LINE 287
+#define KMASK 265
+#define NAME 266
+#define DEPTH 267
+#define ORIENT 268
+#define PLACE 269
+#define CHANCE 270
+#define MONS 271
+#define ITEM 272
+#define MARKER 273
+#define COLOUR 274
+#define PRELUDE 275
+#define MAIN 276
+#define VALIDATE 277
+#define VETO 278
+#define NSUBST 279
+#define WELCOME 280
+#define LFLAGS 281
+#define BFLAGS 282
+#define FLOORCOL 283
+#define ROCKCOL 284
+#define COMMA 285
+#define INTEGER 286
+#define CHARACTER 287
+#define STRING 288
+#define MAP_LINE 289
+#define MONSTER_NAME 290
+#define ITEM_INFO 291
+#define LUA_LINE 292
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
#line 46 "levcomp.ypp"
-{
+typedef union YYSTYPE {
int i;
const char *text;
raw_range range;
-}
-/* Line 1529 of yacc.c. */
+} YYSTYPE;
+/* Line 1274 of yacc.c. */
#line 119 "levcomp.tab.h"
- YYSTYPE;
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
# define YYSTYPE_IS_TRIVIAL 1
@@ -124,3 +121,5 @@ typedef union YYSTYPE
extern YYSTYPE yylval;
+
+
diff --git a/crawl-ref/source/randart.cc b/crawl-ref/source/randart.cc
index 8e9308fa6d..3e54be6752 100644
--- a/crawl-ref/source/randart.cc
+++ b/crawl-ref/source/randart.cc
@@ -27,6 +27,8 @@
#include "itemprop.h"
#include "stuff.h"
+#define KNOWN_PROPS_KEY "randart_known_props"
+
/*
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
@@ -832,7 +834,8 @@ bool is_fixed_artefact( const item_def &item )
return (false);
}
-unique_item_status_type get_unique_item_status( int base_type, int art )
+unique_item_status_type get_unique_item_status( object_class_type base_type,
+ int art )
{
// Note: for weapons "art" is in item.special,
// for orbs it's the sub_type.
@@ -853,7 +856,7 @@ unique_item_status_type get_unique_item_status( int base_type, int art )
return (UNIQ_NOT_EXISTS);
}
-void set_unique_item_status( int base_type, int art,
+void set_unique_item_status( object_class_type base_type, int art,
unique_item_status_type status )
{
// Note: for weapons "art" is in item.special,
@@ -878,6 +881,49 @@ static long calc_seed( const item_def &item )
return (item.special & RANDART_SEED_MASK);
}
+void randart_desc_properties( const item_def &item,
+ randart_properties_t &proprt,
+ randart_known_props_t &known )
+{
+ randart_wpn_properties( item, proprt, known);
+
+ if ( item_ident( item, ISFLAG_KNOW_PROPERTIES ) )
+ return;
+
+ if (item.base_type != OBJ_JEWELLERY)
+ return;
+
+ randart_prop_type fake_rap = RAP_NUM_PROPERTIES;
+ int fake_plus = 1;
+
+ switch (item.sub_type)
+ {
+ case RING_INVISIBILITY:
+ fake_rap = RAP_INVISIBLE;
+ break;
+
+ case RING_TELEPORTATION:
+ fake_rap = RAP_CAUSE_TELEPORTATION;
+ break;
+
+ case RING_MAGICAL_POWER:
+ fake_rap = RAP_MAGICAL_POWER;
+ fake_plus = 9;
+ break;
+
+ case RING_LEVITATION:
+ fake_rap = RAP_LEVITATE;
+ break;
+
+ case AMU_RAGE:
+ fake_rap = RAP_BERSERK;
+ break;
+ }
+
+ if (fake_rap != RAP_NUM_PROPERTIES)
+ proprt[fake_rap] += fake_plus;
+}
+
static int randart_add_one_property( const item_def &item,
randart_properties_t &proprt )
{
@@ -959,9 +1005,28 @@ static int randart_add_one_property( const item_def &item,
}
void randart_wpn_properties( const item_def &item,
- randart_properties_t &proprt )
+ randart_properties_t &proprt,
+ randart_known_props_t &known)
{
ASSERT( is_random_artefact( item ) );
+ ASSERT( item.props.exists( KNOWN_PROPS_KEY ) );
+ const CrawlStoreValue &_val = item.props[KNOWN_PROPS_KEY];
+ ASSERT( _val.get_type() == SV_VEC );
+ const CrawlVector &known_vec = _val.get_vector();
+ ASSERT( known_vec.get_type() == SV_BOOL );
+ ASSERT( known_vec.size() == RA_PROPERTIES);
+ ASSERT( known_vec.get_max_size() == RA_PROPERTIES);
+
+ if ( item_ident( item, ISFLAG_KNOW_PROPERTIES ) )
+ {
+ for (vec_size i = 0; i < RA_PROPERTIES; i++)
+ known[i] = (bool) true;
+ }
+ else
+ {
+ for (vec_size i = 0; i < RA_PROPERTIES; i++)
+ known[i] = known_vec[i];
+ }
const object_class_type aclass = item.base_type;
const int atype = item.sub_type;
@@ -970,7 +1035,7 @@ void randart_wpn_properties( const item_def &item,
if (is_unrandom_artefact( item ))
{
- struct unrandart_entry *unrand = seekunrandart( item );
+ const unrandart_entry *unrand = seekunrandart( item );
for (int i = 0; i < RA_PROPERTIES; i++)
proprt[i] = unrand->prpty[i];
@@ -1430,15 +1495,48 @@ void randart_wpn_properties( const item_def &item,
proprt[RAP_CURSED] = 1;
}
-int randart_wpn_property( const item_def &item, int prop )
+void randart_wpn_properties( const item_def &item,
+ randart_properties_t &proprt )
{
- randart_properties_t proprt;
+ randart_known_props_t known;
- randart_wpn_properties( item, proprt );
+ randart_wpn_properties(item, proprt, known);
+}
+
+int randart_wpn_property( const item_def &item, randart_prop_type prop,
+ bool &_known )
+{
+ randart_properties_t proprt;
+ randart_known_props_t known;
+
+ randart_wpn_properties( item, proprt, known );
+
+ _known = known[prop];
+
+ return ( proprt[prop] );
+}
+
+int randart_wpn_property( const item_def &item, randart_prop_type prop )
+{
+ bool known;
+
+ return randart_wpn_property( item, prop, known );
+}
+
+int randart_known_wpn_property( const item_def &item, randart_prop_type prop )
+{
+ randart_properties_t proprt;
+ randart_known_props_t known;
+
+ randart_wpn_properties( item, proprt, known );
- return (proprt[prop]);
+ if (known[prop])
+ return ( proprt[prop] );
+ else
+ return (0);
}
+
int randart_wpn_num_props( const item_def &item )
{
randart_properties_t proprt;
@@ -1458,6 +1556,30 @@ int randart_wpn_num_props( const randart_properties_t &proprt )
return num;
}
+void randart_wpn_learn_prop( item_def &item, randart_prop_type prop )
+{
+ ASSERT( is_random_artefact( item ) );
+ ASSERT( item.props.exists( KNOWN_PROPS_KEY ) );
+ CrawlStoreValue &_val = item.props[KNOWN_PROPS_KEY];
+ ASSERT( _val.get_type() == SV_VEC );
+ CrawlVector &known_vec = _val.get_vector();
+ ASSERT( known_vec.get_type() == SV_BOOL );
+ ASSERT( known_vec.size() == RA_PROPERTIES);
+ ASSERT( known_vec.get_max_size() == RA_PROPERTIES);
+
+ if ( item_ident( item, ISFLAG_KNOW_PROPERTIES ) )
+ return;
+ else
+ known_vec[prop] = (bool) true;
+}
+
+bool randart_wpn_known_prop( const item_def &item, randart_prop_type prop )
+{
+ bool known;
+ randart_wpn_property( item, prop, known );
+ return known;
+}
+
std::string randart_name( const item_def &item )
{
ASSERT( item.base_type == OBJ_WEAPONS );
@@ -1676,19 +1798,23 @@ int find_okay_unrandart(unsigned char aclass, unsigned char atype)
// 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
+ 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
+ do {
+ which = SPWPN_SINGING_SWORD +
+ random2(SPWPN_STAFF_OF_WUCAD_MU - SPWPN_SINGING_SWORD + 1);
+ } while ( which == SPWPN_SWORD_OF_CEREBOV ||
+ which == SPWPN_STAFF_OF_DISPATER ||
+ which == SPWPN_SCEPTRE_OF_ASMODEUS );
}
- int status = get_unique_item_status( OBJ_WEAPONS, which );
+ const unique_item_status_type status =
+ get_unique_item_status( OBJ_WEAPONS, which );
if ((status == UNIQ_EXISTS
|| (in_abyss && status == UNIQ_NOT_EXISTS)
@@ -1836,14 +1962,6 @@ static bool randart_is_redundant( const item_def &item,
switch (item.sub_type)
{
- case RING_SUSTAIN_ABILITIES:
- case RING_SUSTENANCE:
- case RING_REGENERATION:
- case RING_TELEPORT_CONTROL:
- case RING_WIZARDRY:
- case RING_MAGICAL_POWER:
- break;
-
case RING_PROTECTION:
provides = RAP_AC;
break;
@@ -1900,6 +2018,10 @@ static bool randart_is_redundant( const item_def &item,
provides = RAP_INTELLIGENCE;
break;
+ case RING_MAGICAL_POWER:
+ provides = RAP_MAGICAL_POWER;
+ break;
+
case RING_LEVITATION:
provides = RAP_LEVITATE;
break;
@@ -1919,16 +2041,6 @@ static bool randart_is_redundant( const item_def &item,
case AMU_INACCURACY:
provides = RAP_ACCURACY;
break;
-
- case AMU_RESIST_SLOW:
- case AMU_CLARITY:
- case AMU_WARDING:
- case AMU_RESIST_CORROSION:
- case AMU_THE_GOURMAND:
- case AMU_CONSERVATION:
- case AMU_CONTROLLED_FLIGHT:
- case AMU_RESIST_MUTATION:
- break;
}
if (provides == RAP_NUM_PROPERTIES)
@@ -1956,25 +2068,6 @@ static bool randart_is_conflicting( const item_def &item,
switch (item.sub_type)
{
- case RING_REGENERATION:
- case RING_PROTECTION:
- case RING_PROTECTION_FROM_FIRE:
- case RING_POISON_RESISTANCE:
- case RING_PROTECTION_FROM_COLD:
- case RING_STRENGTH:
- case RING_SLAYING:
- case RING_SEE_INVISIBLE:
- case RING_INVISIBILITY:
- case RING_HUNGER:
- case RING_EVASION:
- case RING_SUSTAIN_ABILITIES:
- case RING_DEXTERITY:
- case RING_INTELLIGENCE:
- case RING_LEVITATION:
- case RING_LIFE_PROTECTION:
- case RING_PROTECTION_FROM_MAGIC:
- break;
-
case RING_SUSTENANCE:
conflicts = RAP_METABOLISM;
break;
@@ -1998,16 +2091,6 @@ static bool randart_is_conflicting( const item_def &item,
case AMU_RAGE:
conflicts = RAP_STEALTH;
break;
-
- case AMU_RESIST_SLOW:
- case AMU_CLARITY:
- case AMU_WARDING:
- case AMU_RESIST_CORROSION:
- case AMU_THE_GOURMAND:
- case AMU_CONSERVATION:
- case AMU_CONTROLLED_FLIGHT:
- case AMU_INACCURACY:
- break;
}
if (conflicts == RAP_NUM_PROPERTIES)
@@ -2040,6 +2123,19 @@ bool make_item_randart( item_def &item )
return (false);
}
+ if (item.flags & ISFLAG_RANDART)
+ return (true);
+
+ if (item.flags & ISFLAG_UNRANDART)
+ return (false);
+
+ ASSERT(!item.props.exists( KNOWN_PROPS_KEY ));
+ item.props[KNOWN_PROPS_KEY].new_vector(SV_BOOL).resize(RA_PROPERTIES);
+ CrawlVector &known = item.props[KNOWN_PROPS_KEY];
+ known.set_max_size(RA_PROPERTIES);
+ for (vec_size i = 0; i < RA_PROPERTIES; i++)
+ known[i] = (bool) false;
+
item.flags |= ISFLAG_RANDART;
do
{
@@ -2049,9 +2145,17 @@ bool make_item_randart( item_def &item )
return (true);
}
-// void make_item_unrandart( int x, int ura_item )
bool make_item_unrandart( item_def &item, int unrand_index )
{
+ if (!item.props.exists( KNOWN_PROPS_KEY ))
+ {
+ item.props[KNOWN_PROPS_KEY].new_vector(SV_BOOL).resize(RA_PROPERTIES);
+ CrawlVector &known = item.props[KNOWN_PROPS_KEY];
+ known.set_max_size(RA_PROPERTIES);
+ for (vec_size i = 0; i < RA_PROPERTIES; i++)
+ known[i] = (bool) false;
+ }
+
item.base_type = unranddata[unrand_index].ura_cl;
item.sub_type = unranddata[unrand_index].ura_ty;
item.plus = unranddata[unrand_index].ura_pl;
@@ -2069,14 +2173,13 @@ bool make_item_unrandart( item_def &item, int unrand_index )
return (true);
} // end make_item_unrandart()
-const char *unrandart_descrip( char which_descrip, const item_def &item )
+const char *unrandart_descrip( int which_descrip, const item_def &item )
{
/* Eventually it would be great to have randomly generated descriptions for
randarts. */
- struct unrandart_entry *unrand = seekunrandart( item );
+ const 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()
+}
diff --git a/crawl-ref/source/randart.h b/crawl-ref/source/randart.h
index 5508b59b5c..74d7905aed 100644
--- a/crawl-ref/source/randart.h
+++ b/crawl-ref/source/randart.h
@@ -12,47 +12,11 @@
#ifndef RANDART_H
#define RANDART_H
-#include "enum.h"
#include "externs.h"
-enum randart_prop_type
-{
- 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,
- RAP_NUM_PROPERTIES
-};
-
// used in files.cc, newgame.cc, randart.cc {dlb}
#define NO_UNRANDARTS 53
-#define RA_PROPERTIES 30
+#define RA_PROPERTIES RAP_NUM_PROPERTIES
// Reserving the upper bits for later expansion/versioning.
#define RANDART_SEED_MASK 0x00ffffff
@@ -63,8 +27,9 @@ bool is_random_artefact( const item_def &item );
bool is_unrandom_artefact( const item_def &item );
bool is_fixed_artefact( const item_def &item );
-unique_item_status_type get_unique_item_status( int base_type, int type );
-void set_unique_item_status( int base_type, int type,
+unique_item_status_type get_unique_item_status( object_class_type base_type,
+ int type );
+void set_unique_item_status( object_class_type base_type, int type,
unique_item_status_type status );
/* ***********************************************************************
@@ -85,7 +50,7 @@ std::string randart_jewellery_name( const item_def &item );
/* ***********************************************************************
* called from: describe
* *********************************************************************** */
-const char *unrandart_descrip( char which_descrip, const item_def &item );
+const char *unrandart_descrip( int which_descrip, const item_def &item );
bool does_unrandart_exist(int whun);
@@ -94,19 +59,36 @@ bool does_unrandart_exist(int whun);
* *********************************************************************** */
int find_okay_unrandart(unsigned char aclass, unsigned char atype = OBJ_RANDOM);
-typedef FixedVector< int, RA_PROPERTIES > randart_properties_t;
+typedef FixedVector< int, RA_PROPERTIES > randart_properties_t;
+typedef FixedVector< bool, RA_PROPERTIES > randart_known_props_t;
/* ***********************************************************************
* called from: describe - fight - it_use2 - item_use - player
* *********************************************************************** */
+void randart_desc_properties( const item_def &item,
+ randart_properties_t &proprt,
+ randart_known_props_t &known );
+
+void randart_wpn_properties( const item_def &item,
+ randart_properties_t &proprt,
+ randart_known_props_t &known );
+
void randart_wpn_properties( const item_def &item,
randart_properties_t &proprt );
-int randart_wpn_property( const item_def &item, int prop );
+int randart_wpn_property( const item_def &item, randart_prop_type prop,
+ bool &known );
+
+int randart_wpn_property( const item_def &item, randart_prop_type prop );
+
+int randart_known_wpn_property( const item_def &item, randart_prop_type prop );
int randart_wpn_num_props( const item_def &item );
int randart_wpn_num_props( const randart_properties_t &proprt );
+void randart_wpn_learn_prop( item_def &item, randart_prop_type prop );
+bool randart_wpn_known_prop( item_def &item, randart_prop_type prop );
+
/* ***********************************************************************
* called from: dungeon
* *********************************************************************** */
diff --git a/crawl-ref/source/religion.cc b/crawl-ref/source/religion.cc
index 37e25dee7f..ca4453b50e 100644
--- a/crawl-ref/source/religion.cc
+++ b/crawl-ref/source/religion.cc
@@ -74,87 +74,111 @@
#include "terrain.h"
#include "tutorial.h"
#include "view.h"
+#include "xom.h"
+
+#if DEBUG_RELIGION
+# define DEBUG_DIAGNOSTICS 1
+# define DEBUG_GIFTS 1
+# define DEBUG_SACRIFICE 1
+# define DEBUG_PIETY 1
+#endif
// Item offer messages for the gods:
// & is replaced by "is" or "are" as appropriate for the item.
// % is replaced by "s" or "" as appropriate.
-// First message is if there's no piety gain, second is if there is.
-const char *sacrifice[NUM_GODS][2] =
+// First message is if there's no piety gain, second is if piety gain
+// is one, third message is for piety gain > 1 (currently unused).
+const char *sacrifice[NUM_GODS][3] =
{
// No god
{
" & eaten by a bored swarm of bugs.",
+ " & eaten by a swarm of bugs.",
" & eaten by a ravening swarm of bugs."
},
// Zin
{
- " faintly glow% silver and disappear%.",
- " glow% silver and disappear%.",
+ " barely glow% and disappear%.",
+ " glow% silver and disappear%.",
+ " glow% blindingly silver and disappear%.",
},
// TSO
{
- " glow% a golden colour and disappear%.",
- " glow% a brilliant golden colour and disappear%.",
+ " faintly glow% and disappear%.",
+ " glow% a golden colour and disappear%.",
+ " glow% a brilliant golden colour and disappear%.",
},
// Kikubaaqudgha
{
- " slowly rot% away.",
- " rot% away in an instant.",
+ " slowly rot% away.",
+ " rot% away.",
+ " rot% away in an instant.",
},
// Yredelemnul
{
" slowly crumble% to dust.",
" crumble% to dust.",
+ " turn% to dust in an instant.",
},
// Xom (no sacrifices)
{
" & eaten by a bored bug.",
" & eaten by a bug.",
+ " & eaten by a greedy bug.",
},
// Vehumet
{
- " burn% into nothingness.",
- " explode% into nothingness.",
+ " fade% into nothingness.",
+ " burn% into nothingness.",
+ " explode% into nothingness.",
},
// Okawaru
{
- " & consumed by flame.",
- " & consumed in a burst of flame.",
+ " slowly burn% to ash.",
+ " & consumed by flame.",
+ " & consumed in a burst of flame.",
},
// Makhleb
{
- " flare% red and disappear%.",
- " flare% blood-red and disappear%.",
+ " disappear% without a sign.",
+ " flare% red and disappear%.",
+ " flare% blood-red and disappear%.",
},
// Sif Muna
{
- " glow% very faintly for a moment, and & gone.",
- " glow% faintly for a moment, and & gone.",
+ " & gone without a glow.",
+ " glow% faintly for a moment, and & gone.",
+ " glow% for a moment, and & gone.",
},
// Trog
{
- " & consumed in a column of flame.",
- " & consumed in a roaring column of flame.",
+ " & slowly consumed by flames.",
+ " & consumed in a column of flame.",
+ " & consumed in a roaring column of flame.",
},
// Nemelex
{
- " glow% slightly and disappear%.",
- " glow% with a rainbow of weird colours and disappear%.",
+ " disappear% without a glow.",
+ " glow% slightly and disappear%.",
+ " glow% with a rainbow of weird colours and disappear%.",
},
// Elyvilon
{
- " slowly evaporate%.",
- " evaporate%.",
+ " slowly evaporate%.",
+ " evaporate%.",
+ " glow% and evaporate%.",
},
// Lugonu
{
- " & disappears into the void.",
- " & consumed by the void.",
+ " & disappears into the void.",
+ " & consumed by the void.",
+ " & voraciously consumed by the void.",
},
// Beogh
{
- " slowly crumble% into the ground.",
- " crumble% into the ground.",
+ " slowly crumble% into the ground.",
+ " crumble% into the ground.",
+ " disintegrate% into the ground.",
}
};
@@ -218,10 +242,10 @@ const char* god_gain_power_messages[NUM_GODS][MAX_GOD_ABILITIES] =
"call in reinforcement",
"" },
// Nemelex
- { "peek at the first card of a deck",
+ { "peek at three random cards from a deck",
"draw cards from decks in your inventory",
"choose one out of three cards",
- "",
+ "mark decks",
"order the the top five cards of a deck, forfeiting the rest" },
// Elyvilon
{ "call upon Elyvilon for minor healing",
@@ -304,10 +328,10 @@ const char* god_lose_power_messages[NUM_GODS][MAX_GOD_ABILITIES] =
"call in reinforcement",
"" },
// Nemelex
- { "peek at the first card of a deck",
+ { "peek at three random cards from a deck",
"draw cards from decks in your inventory",
"choose one out of three cards",
- "",
+ "mark decks",
"order decks" },
// Elyvilon
{ "call upon Elyvilon for minor healing",
@@ -336,7 +360,7 @@ void inc_penance(int god, int val);
void inc_penance(int val);
static bool followers_abandon_you(void); // Beogh
-static bool is_evil_god(god_type god)
+bool is_evil_god(god_type god)
{
return
god == GOD_KIKUBAAQUDGHA ||
@@ -347,7 +371,7 @@ static bool is_evil_god(god_type god)
god == GOD_LUGONU;
}
-static bool is_good_god(god_type god)
+bool is_good_god(god_type god)
{
return
god == GOD_SHINING_ONE ||
@@ -372,6 +396,9 @@ void dec_penance(god_type god, int val)
{
if (you.penance[god] > 0)
{
+#if DEBUG_PIETY
+ mprf(MSGCH_DIAGNOSTICS, "Decreasing penance by %d", val);
+#endif
if (you.penance[god] <= val)
{
simple_god_message(" seems mollified.", god);
@@ -422,20 +449,45 @@ static void inc_gift_timeout(int val)
you.gift_timeout += val;
} // end inc_gift_timeout()
-static monster_type random_undead_servant(int religion /* unused */)
+// Only Yredelemnul and Okawaru use this for now
+static monster_type random_servant(god_type god)
{
// error trapping {dlb}
monster_type thing_called = MONS_PROGRAM_BUG;
int 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%
+
+ switch (god)
+ {
+ case GOD_YREDELEMNUL:
+ // undead
+ 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%
+ break;
+ case GOD_OKAWARU:
+ // warriors
+ thing_called = ((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);
+
+ break;
+ default:
+ break;
+ }
+
return (thing_called);
}
@@ -487,11 +539,193 @@ static bool need_missile_gift()
&& ammo_count(launcher) < 20 + random2(35));
}
+static void get_pure_deck_weights(int weights[])
+{
+ weights[0] = you.sacrifice_value[OBJ_ARMOUR] + 1;
+ weights[1] = you.sacrifice_value[OBJ_WEAPONS] +
+ you.sacrifice_value[OBJ_STAVES] +
+ you.sacrifice_value[OBJ_MISSILES] + 1;
+ weights[2] = you.sacrifice_value[OBJ_MISCELLANY] +
+ you.sacrifice_value[OBJ_JEWELLERY] +
+ you.sacrifice_value[OBJ_BOOKS] +
+ you.sacrifice_value[OBJ_GOLD];
+ weights[3] = you.sacrifice_value[OBJ_CORPSES] / 2;
+ weights[4] = you.sacrifice_value[OBJ_POTIONS] +
+ you.sacrifice_value[OBJ_SCROLLS] +
+ you.sacrifice_value[OBJ_WANDS] +
+ you.sacrifice_value[OBJ_FOOD];
+}
+
+static void update_sacrifice_weights(int which)
+{
+ switch ( which )
+ {
+ case 0:
+ you.sacrifice_value[OBJ_ARMOUR] /= 5;
+ you.sacrifice_value[OBJ_ARMOUR] *= 4;
+ break;
+ case 1:
+ you.sacrifice_value[OBJ_WEAPONS] /= 5;
+ you.sacrifice_value[OBJ_STAVES] /= 5;
+ you.sacrifice_value[OBJ_MISSILES] /= 5;
+ you.sacrifice_value[OBJ_WEAPONS] *= 4;
+ you.sacrifice_value[OBJ_STAVES] *= 4;
+ you.sacrifice_value[OBJ_MISSILES] *= 4;
+ break;
+ case 2:
+ you.sacrifice_value[OBJ_MISCELLANY] /= 5;
+ you.sacrifice_value[OBJ_JEWELLERY] /= 5;
+ you.sacrifice_value[OBJ_BOOKS] /= 5;
+ you.sacrifice_value[OBJ_GOLD] /= 5;
+ you.sacrifice_value[OBJ_MISCELLANY] *= 4;
+ you.sacrifice_value[OBJ_JEWELLERY] *= 4;
+ you.sacrifice_value[OBJ_BOOKS] *= 4;
+ you.sacrifice_value[OBJ_GOLD] *= 4;
+ case 3:
+ you.sacrifice_value[OBJ_CORPSES] /= 5;
+ you.sacrifice_value[OBJ_CORPSES] *= 4;
+ break;
+ case 4:
+ you.sacrifice_value[OBJ_POTIONS] /= 5;
+ you.sacrifice_value[OBJ_SCROLLS] /= 5;
+ you.sacrifice_value[OBJ_WANDS] /= 5;
+ you.sacrifice_value[OBJ_FOOD] /= 5;
+ you.sacrifice_value[OBJ_POTIONS] *= 4;
+ you.sacrifice_value[OBJ_SCROLLS] *= 4;
+ you.sacrifice_value[OBJ_WANDS] *= 4;
+ you.sacrifice_value[OBJ_FOOD] *= 4;
+ break;
+ }
+}
+
+#if DEBUG_GIFTS || DEBUG_CARDS
+static void show_pure_deck_chances()
+{
+ int weights[5];
+
+ get_pure_deck_weights(weights);
+
+ float total = (float) (weights[0] + weights[1] + weights[2] + weights[3] +
+ weights[4]);
+
+ mprf(MSGCH_DIAGNOSTICS, "Pure cards chances: "
+ "escape %0.2f%%, destruction %0.2f%%, dungeons %0.2f%%,"
+ "summoning %0.2f%%, wonders %0.2f%%",
+ (float)weights[0] / total * 100.0,
+ (float)weights[1] / total * 100.0,
+ (float)weights[2] / total * 100.0,
+ (float)weights[3] / total * 100.0,
+ (float)weights[4] / total * 100.0);
+}
+#endif
+
+static void give_nemelex_gift()
+{
+ if ( grid_destroys_items(grd[you.x_pos][you.y_pos]) )
+ return;
+
+ // Nemelex will give at least one gift early.
+ if ((you.num_gifts[GOD_NEMELEX_XOBEH] == 0
+ && random2(piety_breakpoint(1)) < you.piety) ||
+ (random2(MAX_PIETY) <= you.piety
+ && one_chance_in(3)
+ && !you.attribute[ATTR_CARD_COUNTDOWN]))
+ {
+ misc_item_type gift_type;
+ if ( random2(MAX_PIETY) <= you.piety )
+ {
+ // make a pure deck
+ const misc_item_type pure_decks[] = {
+ MISC_DECK_OF_ESCAPE,
+ MISC_DECK_OF_DESTRUCTION,
+ MISC_DECK_OF_DUNGEONS,
+ MISC_DECK_OF_SUMMONING,
+ MISC_DECK_OF_WONDERS
+ };
+ int weights[5];
+ get_pure_deck_weights(weights);
+ const int choice = choose_random_weighted(weights, weights+5);
+ gift_type = pure_decks[choice];
+#if DEBUG_GIFTS || DEBUG_CARDS
+ show_pure_deck_chances();
+#endif
+ update_sacrifice_weights(choice);
+ }
+ else
+ {
+ // make a mixed deck
+ const misc_item_type mixed_decks[] = {
+ MISC_DECK_OF_WAR,
+ MISC_DECK_OF_CHANGES,
+ MISC_DECK_OF_DEFENSE
+ };
+ gift_type = RANDOM_ELEMENT(mixed_decks);
+ }
+
+ int thing_created = items( 1, OBJ_MISCELLANY, gift_type,
+ true, 1, MAKE_ITEM_RANDOM_RACE );
+
+ if (thing_created != NON_ITEM)
+ {
+ // Piety|Common | Rare |Legendary
+ // --------------------------------
+ // 0: 95.00%, 5.00%, 0.00%
+ // 20: 86.00%, 10.50%, 3.50%
+ // 40: 77.00%, 16.00%, 7.00%
+ // 60: 68.00%, 21.50%, 10.50%
+ // 80: 59.00%, 27.00%, 14.00%
+ // 100: 50.00%, 32.50%, 17.50%
+ // 120: 41.00%, 38.00%, 21.00%
+ // 140: 32.00%, 43.50%, 24.50%
+ // 160: 23.00%, 49.00%, 28.00%
+ // 180: 14.00%, 54.50%, 31.50%
+ // 200: 5.00%, 60.00%, 35.00%
+ int common_weight = 95 - (90 * you.piety / MAX_PIETY);
+ int rare_weight = 5 + (55 * you.piety / MAX_PIETY);
+ int legend_weight = 0 + (35 * you.piety / MAX_PIETY);
+
+ deck_rarity_type rarity = static_cast<deck_rarity_type>(
+ random_choose_weighted(common_weight,
+ DECK_RARITY_COMMON,
+ rare_weight,
+ DECK_RARITY_RARE,
+ legend_weight,
+ DECK_RARITY_LEGENDARY,
+ 0));
+
+ item_def &deck(mitm[thing_created]);
+
+ deck.special = rarity;
+ deck.colour = deck_rarity_to_color(rarity);
+
+ move_item_to_grid( &thing_created, you.x_pos, you.y_pos );
+ origin_acquired(deck, you.religion);
+
+ 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));
+ you.num_gifts[you.religion]++;
+ take_note(Note(NOTE_GOD_GIFT, you.religion));
+ }
+ }
+}
+
static void do_god_gift(bool prayed_for)
{
+ ASSERT(you.religion != GOD_NO_GOD);
+
// Zin worshippers are the only ones that can pray to ask Zin for stuff.
if (prayed_for != (you.religion == GOD_ZIN))
return;
+
+ god_acting gdact;
+
+#if DEBUG_DIAGNOSTICS || DEBUG_GIFTS
+ int old_gifts = you.num_gifts[ you.religion ];
+#endif
// Consider a gift if we don't have a timeout and weren't
// already praying when we prayed.
@@ -519,66 +753,7 @@ static void do_god_gift(bool prayed_for)
break;
case GOD_NEMELEX_XOBEH:
- if (random2(200) <= you.piety
- && one_chance_in(3)
- && !you.attribute[ATTR_CARD_COUNTDOWN]
- && !grid_destroys_items(grd[you.x_pos][you.y_pos]))
- {
- misc_item_type gift_type;
- if ( random2(200) <= you.piety )
- {
- // make a pure deck
- const misc_item_type pure_decks[] = {
- MISC_DECK_OF_ESCAPE,
- MISC_DECK_OF_DESTRUCTION,
- MISC_DECK_OF_DUNGEONS,
- MISC_DECK_OF_SUMMONING,
- MISC_DECK_OF_WONDERS
- };
- int weights[5];
- // FIXME do something with OBJ_FOOD,
- // OBJ_WANDS, OBJ_JEWELLERY, OBJ_BOOKS
- // (and maybe OBJ_ORBS...)
- weights[0] = you.sacrifice_value[OBJ_SCROLLS] +
- you.sacrifice_value[OBJ_ARMOUR] + 1;
- weights[1] = you.sacrifice_value[OBJ_WEAPONS] +
- you.sacrifice_value[OBJ_STAVES] +
- you.sacrifice_value[OBJ_MISSILES] + 1;
- weights[2] = you.sacrifice_value[OBJ_MISCELLANY];
- weights[3] = you.sacrifice_value[OBJ_CORPSES] * 100;
- weights[4] = you.sacrifice_value[OBJ_POTIONS];
- gift_type = pure_decks[choose_random_weighted(weights,
- weights+5)];
- }
- else
- {
- // make a mixed deck
- const misc_item_type mixed_decks[] = {
- MISC_DECK_OF_WAR,
- MISC_DECK_OF_CHANGES,
- MISC_DECK_OF_DEFENSE
- };
- gift_type = RANDOM_ELEMENT(mixed_decks);
- }
-
- int thing_created = items( 1, OBJ_MISCELLANY, gift_type,
- true, 1, MAKE_ITEM_RANDOM_RACE );
-
- if (thing_created != NON_ITEM)
- {
- move_item_to_grid( &thing_created, you.x_pos, you.y_pos );
- origin_acquired(mitm[thing_created], you.religion);
-
- 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));
- you.num_gifts[you.religion]++;
- take_note(Note(NOTE_GOD_GIFT, you.religion));
- }
- }
+ give_nemelex_gift();
break;
case GOD_OKAWARU:
@@ -632,13 +807,12 @@ static void do_god_gift(bool prayed_for)
case GOD_YREDELEMNUL:
if (random2(you.piety) > 80 && one_chance_in(5))
{
- monster_type thing_called =
- random_undead_servant(GOD_YREDELEMNUL);
+ monster_type thing_called =
+ random_servant(GOD_YREDELEMNUL);
- if (create_monster( thing_called, 0, BEH_FRIENDLY,
- you.x_pos, you.y_pos,
- you.pet_target, MAKE_ITEM_RANDOM_RACE )
- != -1)
+ if (create_monster(thing_called, 0, BEH_FRIENDLY,
+ you.x_pos, you.y_pos, you.pet_target,
+ MAKE_ITEM_RANDOM_RACE) != -1)
{
simple_god_message(" grants you an undead servant!");
more();
@@ -737,6 +911,12 @@ static void do_god_gift(bool prayed_for)
break;
}
} // end of gift giving
+
+#if DEBUG_DIAGNOSTICS || DEBUG_GIFTS
+ if (old_gifts < you.num_gifts[ you.religion ])
+ mprf(MSGCH_DIAGNOSTICS, "Total number of gifts from this god: %d",
+ you.num_gifts[ you.religion ] );
+#endif
}
static bool is_risky_sacrifice(const item_def& item)
@@ -1054,7 +1234,8 @@ void god_speaks( god_type god, const char *mesg )
// This function is the merger of done_good() and naughty().
// Returns true if god was interested (good or bad) in conduct.
-bool did_god_conduct( conduct_type thing_done, int level, const actor *victim )
+bool did_god_conduct( conduct_type thing_done, int level, bool known,
+ const actor *victim )
{
bool ret = false;
int piety_change = 0;
@@ -1063,15 +1244,28 @@ bool did_god_conduct( conduct_type thing_done, int level, const actor *victim )
if (you.religion == GOD_NO_GOD || you.religion == GOD_XOM)
return (false);
+ god_acting gdact;
+
switch (thing_done)
{
case DID_DRINK_BLOOD:
switch (you.religion)
{
- case GOD_ZIN:
case GOD_SHINING_ONE:
+ if (!known)
+ {
+ simple_god_message(" did not appreciate that!");
+ break;
+ }
+ penance = level;
+ // deliberate fall-through
+ case GOD_ZIN:
case GOD_ELYVILON:
- // no penance as this can happen accidentally
+ if (!known)
+ {
+ simple_god_message(" did not appreciate that!");
+ break;
+ }
piety_change = -2*level;
ret = true;
break;
@@ -1080,7 +1274,22 @@ bool did_god_conduct( conduct_type thing_done, int level, const actor *victim )
}
break;
- // If you make some god like these acts, modify did_god_conduct call
+ case DID_CANNIBALISM:
+ switch (you.religion)
+ {
+ case GOD_ZIN:
+ case GOD_SHINING_ONE:
+ case GOD_ELYVILON:
+ piety_change = -level;
+ penance = level;
+ ret = true;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ // If you make some god like these acts, modify did_god_conduct call
// in beam.cc with god_likes_necromancy check or something similar
case DID_NECROMANCY:
case DID_UNHOLY:
@@ -1090,8 +1299,14 @@ bool did_god_conduct( conduct_type thing_done, int level, const actor *victim )
case GOD_ZIN:
case GOD_SHINING_ONE:
case GOD_ELYVILON:
+ if (!known && thing_done != DID_ATTACK_HOLY)
+ {
+ simple_god_message(" did not appreciate that!");
+ break;
+ }
piety_change = -level;
- penance = level * ((you.religion == GOD_ZIN) ? 2 : 1);
+ if (known)
+ penance = level * ((you.religion == GOD_SHINING_ONE) ? 2 : 1);
ret = true;
break;
default:
@@ -1122,7 +1337,8 @@ bool did_god_conduct( conduct_type thing_done, int level, const actor *victim )
(victim && mons_species(victim->id()) == MONS_ORC))
{
piety_change = -level;
- penance = level * 3;
+ if (known)
+ penance = level * 3;
ret = true;
}
break;
@@ -1427,6 +1643,31 @@ bool did_god_conduct( conduct_type thing_done, int level, const actor *victim )
{
piety_change = level;
ret = true;
+
+ // For a stacked deck, 0% chance of card countdown decrement
+ // drawing a card which doesn't use up the deck, and 40%
+ // on a card which does. For a non-stacked deck, an
+ // average 50% of decrement for drawing a card which doesn't
+ // use up the deck, and 80% on a card which does use up the
+ // deck.
+ int chance = 0;
+ switch(level)
+ {
+ case 0: chance = 0; break;
+ case 1: chance = 40; break;
+ case 2: chance = 70; break;
+ default:
+ case 3: chance = 100; break;
+ }
+
+ if (random2(100) < chance && you.attribute[ATTR_CARD_COUNTDOWN])
+ {
+ you.attribute[ATTR_CARD_COUNTDOWN]--;
+#if DEBUG_DIAGNOSTICS || DEBUG_CARDS || DEBUG_GIFTS
+ mprf(MSGCH_DIAGNOSTICS, "Countdown down to %d",
+ you.attribute[ATTR_CARD_COUNTDOWN]);
+#endif
+ }
}
break;
@@ -1478,13 +1719,12 @@ bool did_god_conduct( conduct_type thing_done, int level, const actor *victim )
"Necromancy", "Unholy", "Attack Holy", "Attack Friend",
"Friend Died", "Stab", "Poison", "Field Sacrifice",
"Kill Living", "Kill Undead", "Kill Demon", "Kill Natural Evil",
- "Kill Wizard",
- "Kill Priest", "Kill Angel", "Undead Slave Kill Living",
- "Servant Kill Living", "Servant Kill Undead",
- "Servant Kill Demon", "Servant Kill Natural Evil",
- "Servant Kill Angel",
+ "Kill Wizard", "Kill Priest", "Kill Angel", "Undead Slave Kill Living",
+ "Servant Kill Living", "Servant Kill Undead", "Servant Kill Demon",
+ "Servant Kill Natural Evil", "Servant Kill Angel",
"Spell Memorise", "Spell Cast", "Spell Practise", "Spell Nonutility",
- "Cards", "Stimulants", "Drink Blood", "Eat Meat", "Create Life"
+ "Cards", "Stimulants", "Drink Blood", "Cannibalism", "Eat Meat",
+ "Create Life"
};
ASSERT(ARRAYSIZE(conducts) == NUM_CONDUCTS);
@@ -1502,7 +1742,7 @@ bool did_god_conduct( conduct_type thing_done, int level, const actor *victim )
void gain_piety(int pgn)
{
// Xom uses piety differently...
- if (you.religion == GOD_XOM)
+ if (you.religion == GOD_XOM || you.religion == GOD_NO_GOD)
return;
// check to see if we owe anything first
@@ -1521,13 +1761,22 @@ void gain_piety(int pgn)
// Slow down piety gain to account for the fact that gifts
// no longer have a piety cost for getting them
if (!one_chance_in(4))
+ {
+#if DEBUG_PIETY
+ mprf(MSGCH_DIAGNOSTICS, "Piety slowdown due to gift timeout.");
+#endif
return;
+ }
}
+#if DEBUG_PIETY
+ mprf(MSGCH_DIAGNOSTICS, "Piety increasing by %d", pgn);
+#endif
+
// slow down gain at upper levels of piety
if (you.religion != GOD_SIF_MUNA)
{
- if (you.piety > 199
+ if (you.piety >= MAX_PIETY
|| (you.piety > 150 && one_chance_in(3))
|| (you.piety > 100 && one_chance_in(3)))
{
@@ -1539,7 +1788,7 @@ void gain_piety(int pgn)
{
// Sif Muna has a gentler taper off because training becomes
// naturally slower as the player gains in spell skills.
- if ((you.piety > 199) ||
+ if ((you.piety >= MAX_PIETY) ||
(you.piety > 150 && one_chance_in(5)))
{
do_god_gift(false);
@@ -1550,6 +1799,8 @@ void gain_piety(int pgn)
int old_piety = you.piety;
you.piety += pgn;
+ if (you.piety > MAX_PIETY)
+ you.piety = MAX_PIETY;
for ( int i = 0; i < MAX_GOD_ABILITIES; ++i )
{
@@ -1602,11 +1853,24 @@ static bool need_water_walking()
grd[you.x_pos][you.y_pos] == DNGN_DEEP_WATER;
}
+static bool is_evil_weapon(item_def weap)
+{
+ if (weap.base_type != OBJ_WEAPONS)
+ return false;
+
+ return (is_demonic(weap)
+ || weap.special == SPWPN_VAMPIRICISM
+ || weap.special == SPWPN_PAIN
+ || weap.special == SPWPN_DRAINING);
+}
+
bool ely_destroy_weapons()
{
if (you.religion != GOD_ELYVILON)
return false;
-
+
+ god_acting gdact;
+
bool success = false;
int i = igrd[you.x_pos][you.y_pos];
while (i != NON_ITEM)
@@ -1627,7 +1891,8 @@ bool ely_destroy_weapons()
#endif
bool pgain = false;
- if (random2(value) >= random2(250) // artefacts (incl. most randarts)
+ if (is_evil_weapon(mitm[i])
+ || random2(value) >= random2(250) // artefacts (incl. most randarts)
|| random2(value) >= random2(100) && one_chance_in(1 + you.piety/50)
|| (mitm[i].base_type == OBJ_WEAPONS
&& (you.piety < 30 || player_under_penance())))
@@ -1635,7 +1900,18 @@ bool ely_destroy_weapons()
pgain = true;
gain_piety(1);
}
-
+
+ std::ostream& strm = msg::streams(MSGCH_GOD);
+ strm << mitm[i].name(DESC_CAP_THE);
+
+ if (!pgain)
+ strm << " barely";
+
+ if ( mitm[i].quantity == 1 )
+ strm << " shimmers and breaks into pieces." << std::endl;
+ else
+ strm << " shimmer and break into pieces." << std::endl;
+
std::ostream& strm = msg::streams(MSGCH_GOD);
strm << mitm[i].name(DESC_CAP_THE);
@@ -1656,7 +1932,6 @@ bool ely_destroy_weapons()
{
mpr("There are no weapons here to destroy!");
}
-
return success;
}
@@ -1666,6 +1941,8 @@ bool trog_burn_books()
if (you.religion != GOD_TROG)
return (false);
+ god_acting gdact;
+
int i = igrd[you.x_pos][you.y_pos];
while (i != NON_ITEM)
{
@@ -1770,7 +2047,6 @@ bool trog_burn_books()
simple_god_message(" is delighted!", GOD_TROG);
gain_piety(totalpiety);
}
-
return (true);
}
@@ -1778,6 +2054,10 @@ void lose_piety(int pgn)
{
const int old_piety = you.piety;
+#if DEBUG_PIETY
+ mprf(MSGCH_DIAGNOSTICS, "Piety decreasing by %d", pgn);
+#endif
+
if (you.piety - pgn < 0)
you.piety = 0;
else
@@ -1885,9 +2165,10 @@ static bool zin_retribution()
if (!is_evil_god(you.religion))
return false;
+ bool success = false;
+
if (random2(you.experience_level) > 7 && !one_chance_in(5))
{
- bool success = false;
const int how_many = 1 + (you.experience_level / 10) + random2(3);
for (int i = 0; i < how_many; i++)
@@ -1904,8 +2185,11 @@ static bool zin_retribution()
else
{
// god_gift == false gives unfriendly
- summon_swarm( you.experience_level * 20, true, false );
- simple_god_message(" sends a plague down upon you!", god);
+ success = summon_swarm( you.experience_level * 20, true, false );
+ simple_god_message(success ?
+ " sends a plague down upon you!" :
+ "'s plague fails to arrive.",
+ god);
}
return false;
@@ -1989,13 +2273,11 @@ static bool yredelemnul_retribution()
for (int i = 0; i < how_many; i++)
{
- monster_type punisher =
- random_undead_servant(GOD_YREDELEMNUL);
+ monster_type punisher = random_servant(GOD_YREDELEMNUL);
- if (create_monster( punisher, 0, BEH_HOSTILE,
- you.x_pos, you.y_pos, MHITYOU, 250 ) != -1)
+ if (create_monster(punisher, 0, BEH_HOSTILE,
+ you.x_pos, you.y_pos, MHITYOU, 250) != -1)
count++;
-
}
simple_god_message(count > 1? " sends servants to punish you." :
@@ -2021,7 +2303,7 @@ static bool trog_retribution()
{
// Would be better if berserking monsters were available,
// we just send some big bruisers for now.
- bool success = false;
+ int count = 0;
int points = 3 + you.experience_level * 3;
while (points > 0)
@@ -2051,13 +2333,12 @@ static bool trog_retribution()
if (create_monster(punisher, 0, BEH_HOSTILE, you.x_pos,
you.y_pos, MHITYOU, 250) != -1)
- success = true;
+ count++;
}
-
- simple_god_message(success ?
- " sends monsters to punish you." :
- " has no time to punish you...now.",
- god);
+
+ simple_god_message(count > 1 ? " sends monsters to punish you." :
+ count > 0 ? " sends a monster to punish you." :
+ " has no time to punish you...now.", god);
}
else if ( !one_chance_in(3) )
{
@@ -2075,7 +2356,8 @@ static bool trog_retribution()
case 1:
case 2:
- lose_stat(STAT_STRENGTH, 1 + random2(you.strength / 5), true);
+ lose_stat(STAT_STRENGTH, 1 + random2(you.strength / 5), true,
+ "divine retribution from Trog");
break;
case 3:
@@ -2244,18 +2526,7 @@ static bool okawaru_retribution()
for (int i = 0; i < how_many; i++)
{
- const int temp_rand = random2(100);
-
- monster_type 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);
+ monster_type punisher = random_servant(GOD_OKAWARU);
if (create_monster(punisher, 0, BEH_HOSTILE,
you.x_pos, you.y_pos, MHITYOU, 250) != -1)
@@ -2282,7 +2553,8 @@ static bool sif_muna_retribution()
{
case 0:
case 1:
- lose_stat(STAT_INTELLIGENCE, 1 + random2( you.intel / 5 ), true);
+ lose_stat(STAT_INTELLIGENCE, 1 + random2( you.intel / 5 ), true,
+ "divine retribution from Sif Muna");
break;
case 2:
@@ -2408,6 +2680,8 @@ void divine_retribution( god_type god )
if (god == you.religion && is_good_god(god) )
return;
+ god_acting gdact(god, true);
+
bool do_more = true;
switch (god)
{
@@ -2477,7 +2751,7 @@ bool followers_abandon_you()
{
for ( int x = xstart; x < xend; ++x )
{
- const unsigned char targ_monst = mgrd[x][y];
+ const unsigned short targ_monst = mgrd[x][y];
if ( targ_monst != NON_MONSTER )
{
monsters *monster = &menv[targ_monst];
@@ -2547,6 +2821,8 @@ bool followers_abandon_you()
// Destroying orcish idols (a.k.a. idols of Beogh) may anger Beogh
void beogh_idol_revenge()
{
+ god_acting gdact(GOD_BEOGH, true);
+
// Beogh watches his charges closely, but for others doesn't always notice
if (you.religion == GOD_BEOGH
|| (you.species == SP_HILL_ORC && coinflip())
@@ -2705,6 +2981,7 @@ void beogh_convert_orc(monsters *orc, bool emergency)
void excommunication(void)
{
const god_type old_god = you.religion;
+ god_acting gdact(old_god, true);
take_note(Note(NOTE_LOSE_GOD, old_god));
@@ -2860,6 +3137,8 @@ void altar_prayer(void)
if (you.religion == GOD_XOM)
return;
+ god_acting gdact;
+
// TSO blesses long swords with holy wrath
if (you.religion == GOD_SHINING_ONE
&& !you.num_gifts[GOD_SHINING_ONE]
@@ -2958,7 +3237,10 @@ void offer_items()
if (you.religion == GOD_NO_GOD || !god_likes_items(you.religion))
return;
- int i = igrd[you.x_pos][you.y_pos];
+ god_acting gdact;
+
+ int num_sacced = 0;
+ int i = igrd[you.x_pos][you.y_pos];
while (i != NON_ITEM)
{
item_def &item(mitm[i]);
@@ -2966,7 +3248,7 @@ void offer_items()
const int value = item_value( item, true );
- if (item_is_stationary(item) || !god_likes_item(you.religion, mitm[i]))
+ if (item_is_stationary(item) || !god_likes_item(you.religion, item))
{
i = next;
continue;
@@ -2974,7 +3256,7 @@ void offer_items()
bool gained_piety = false;
-#ifdef DEBUG_DIAGNOSTICS
+#if DEBUG_DIAGNOSTICS || DEBUG_SACRIFICE
mprf(MSGCH_DIAGNOSTICS, "Sacrifice item value: %d", value);
#endif
@@ -2995,22 +3277,49 @@ void offer_items()
}
}
- you.sacrifice_value[mitm[i].base_type] += value;
if (you.attribute[ATTR_CARD_COUNTDOWN] && random2(800) < value)
{
you.attribute[ATTR_CARD_COUNTDOWN]--;
-#ifdef DEBUG_DIAGNOSTICS
+#if DEBUG_DIAGNOSTICS || DEBUG_CARDS || DEBUG_SACRIFICE
mprf(MSGCH_DIAGNOSTICS, "Countdown down to %d",
you.attribute[ATTR_CARD_COUNTDOWN]);
#endif
}
- if ((mitm[i].base_type == OBJ_CORPSES && coinflip())
- // Nemelex piety gain is fairly fast.
- || random2(value) >= random2(60))
+ // Aproximate piety gain chance.
+ // Value: %
+ // ---------
+ // 10: 9.0%
+ // 20: 17.5%
+ // 30: 25.5%
+ // 40: 34.0%
+ // 50: 42.5%
+ // 60: 50.0%
+ // 70: 58.0%
+ // 80: 63.0%
+ if ((item.base_type == OBJ_CORPSES &&
+ one_chance_in(2+you.piety/50))
+ // Nemelex piety gain is fairly fast...at least
+ // when you have low piety.
+ || value/2 >= random2(30 + you.piety/2))
{
gain_piety(1);
gained_piety = true;
}
+
+ if (item.base_type == OBJ_FOOD && item.sub_type == FOOD_CHUNK)
+ // No sacrifice value for chunks of flesh, since food
+ // value goes towards decks of wonder.
+ ;
+ else if (item.base_type == OBJ_CORPSES)
+ {
+#if DEBUG_GIFTS || DEBUG_CARDS || DEBUG_SACRIFICE
+ mprf(MSGCH_DIAGNOSTICS, "Corpse mass is %d",
+ item_mass(item));
+#endif
+ you.sacrifice_value[item.base_type] += item_mass(item);
+ }
+ else
+ you.sacrifice_value[item.base_type] += value;
break;
case GOD_ZIN:
@@ -3047,9 +3356,16 @@ void offer_items()
<< sacrifice_message(you.religion, mitm[i],
gained_piety)
<< std::endl;
+ item_was_destroyed(mitm[i]);
destroy_item(i);
i = next;
+ num_sacced++;
}
+
+#if DEBUG_GIFTS || DEBUG_CARDS || DEBUG_SACRIFICE
+ if (num_sacced > 0 && you.religion == GOD_NEMELEX_XOBEH)
+ show_pure_deck_chances();
+#endif
}
void god_pitch(god_type which_god)
@@ -3076,6 +3392,7 @@ void god_pitch(god_type which_god)
if (which_god == GOD_LUGONU && you.penance[GOD_LUGONU])
{
simple_god_message(" is most displeased with you!", which_god);
+ god_acting gdact(GOD_LUGONU, true);
lugonu_retribution();
return;
}
@@ -3174,6 +3491,12 @@ bool god_hates_butchery(god_type god)
return (god == GOD_ELYVILON);
}
+bool god_protects_from_harm(god_type god)
+{
+ return (god == GOD_ZIN || god == GOD_SHINING_ONE ||
+ god == GOD_ELYVILON || god == GOD_YREDELEMNUL);
+}
+
void offer_corpse(int corpse)
{
// We always give the "good" (piety-gain) message when doing
diff --git a/crawl-ref/source/religion.h b/crawl-ref/source/religion.h
index 7b2d8e7b03..e7117ca90b 100644
--- a/crawl-ref/source/religion.h
+++ b/crawl-ref/source/religion.h
@@ -16,6 +16,8 @@
#include "enum.h"
+#define MAX_PIETY 200
+
class actor;
class monsters;
@@ -25,7 +27,7 @@ int piety_breakpoint(int i);
const char *god_name(god_type which_god, bool long_name = false); //mv
void dec_penance(int val);
void dec_penance(god_type god, int val);
-bool did_god_conduct(conduct_type thing_done, int pgain,
+bool did_god_conduct(conduct_type thing_done, int pgain, bool known = true,
const actor *victim = NULL);
void excommunication(void);
void gain_piety(int pgn);
@@ -41,13 +43,9 @@ int piety_rank(int piety = -1);
void offer_items();
bool god_likes_butchery(god_type god);
bool god_hates_butchery(god_type god);
+bool god_protects_from_harm(god_type god);
void divine_retribution(god_type god);
-bool xom_is_nice();
-void xom_is_stimulated(int maxinterestingness);
-void xom_acts(bool niceness, int sever);
-const char *describe_xom_favour();
-
bool beogh_water_walk();
void beogh_idol_revenge();
void beogh_convert_orc(monsters *orc, bool emergency);
@@ -55,10 +53,7 @@ bool ely_destroy_weapons();
bool trog_burn_books();
bool tso_stab_safe_monster(const actor *act);
-
-inline void xom_acts(int sever)
-{
- xom_acts(xom_is_nice(), sever);
-}
+bool is_evil_god(god_type god);
+bool is_good_god(god_type god);
#endif
diff --git a/crawl-ref/source/shopping.cc b/crawl-ref/source/shopping.cc
index 8b7f000c5e..1576fa420b 100644
--- a/crawl-ref/source/shopping.cc
+++ b/crawl-ref/source/shopping.cc
@@ -766,7 +766,7 @@ unsigned int item_value( item_def item, bool ident )
valued += 20;
}
- if (item_cursed( item ))
+ if (item_known_cursed(item))
{
valued *= 6;
valued /= 10;
@@ -1018,7 +1018,7 @@ unsigned int item_value( item_def item, bool ident )
valued += 20;
}
- if (item_cursed( item ))
+ if (item_known_cursed(item))
{
valued *= 6;
valued /= 10;
@@ -1254,13 +1254,15 @@ unsigned int item_value( item_def item, bool ident )
case SCR_IDENTIFY:
valued += 20;
break;
+ case SCR_FOG:
+ valued += 10;
+ 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++;
@@ -1270,7 +1272,7 @@ unsigned int item_value( item_def item, bool ident )
break;
case OBJ_JEWELLERY:
- if (item_cursed( item ))
+ if (item_known_cursed(item))
valued -= 10;
if ( !item_type_known(item) )
diff --git a/crawl-ref/source/skills2.cc b/crawl-ref/source/skills2.cc
index 62f5b2023c..6b83e96772 100644
--- a/crawl-ref/source/skills2.cc
+++ b/crawl-ref/source/skills2.cc
@@ -36,7 +36,6 @@
#include "menu.h"
#include "player.h"
#include "randart.h"
-#include "religion.h"
#include "stuff.h"
#include "transfor.h"
#include "view.h"
@@ -1879,10 +1878,7 @@ static void display_skill_table(bool show_aptitudes)
if ( !show_aptitudes )
{
textcolor(CYAN);
- if ( !Options.increasing_skill_progress )
- cprintf( " (%d)", (100 - percent_done) / 10 );
- else
- cprintf( " (%2d%%)", (percent_done / 5) * 5 );
+ cprintf( " (%2d%%)", (percent_done / 5) * 5 );
}
else
{
@@ -2249,6 +2245,10 @@ int calc_mp(bool real_mp)
if (!real_mp)
you.max_magic_points += player_magical_power();
+ // analogous to ROBUST/FRAIL
+ you.max_magic_points *= (10 + you.mutation[MUT_HIGH_MAGIC] - you.mutation[MUT_LOW_MAGIC]);
+ you.max_magic_points /= 10;
+
if (you.max_magic_points > 50)
you.max_magic_points = 50 + ((you.max_magic_points - 50) / 2);
diff --git a/crawl-ref/source/spells1.cc b/crawl-ref/source/spells1.cc
index 2901aa805b..247e12f8d6 100644
--- a/crawl-ref/source/spells1.cc
+++ b/crawl-ref/source/spells1.cc
@@ -1,6 +1,7 @@
/*
* File: spells1.cc
* Summary: Implementations of some additional spells.
+ * Mostly Translocations.
* Written by: Linley Henzell
*
* Modified for Crawl Reference by $Author$ on $Date$
@@ -45,6 +46,7 @@
#include "spells3.h"
#include "spells4.h"
#include "spl-util.h"
+#include "state.h"
#include "stuff.h"
#include "terrain.h"
#include "transfor.h"
@@ -61,19 +63,33 @@ static bool abyss_blocks_teleport(bool cblink)
return (cblink? one_chance_in(3) : !one_chance_in(3));
}
-int blink(int pow, bool high_level_controlled_blink)
+// If wizard_blink is set, all restriction are ignored (except for
+// a monster being at the target spot), and the player gains no
+// contamination.
+int blink(int pow, bool high_level_controlled_blink, bool wizard_blink)
{
dist beam;
+ if (crawl_state.is_repeating_cmd())
+ {
+ crawl_state.cant_cmd_repeat("You can't repeat controlled blinks.");
+ crawl_state.cancel_cmd_again();
+ crawl_state.cancel_cmd_repeat();
+ return(1);
+ }
+
// yes, there is a logic to this ordering {dlb}:
- if (scan_randarts(RAP_PREVENT_TELEPORTATION))
+ if (scan_randarts(RAP_PREVENT_TELEPORTATION) && !wizard_blink)
mpr("You feel a weird sense of stasis.");
else if (you.level_type == LEVEL_ABYSS
- && abyss_blocks_teleport(high_level_controlled_blink))
+ && abyss_blocks_teleport(high_level_controlled_blink)
+ && !wizard_blink)
+ {
mpr("The power of the Abyss keeps you in your place!");
- else if (you.duration[DUR_CONF])
+ }
+ else if (you.duration[DUR_CONF] && !wizard_blink)
random_blink(false);
- else if (!allow_control_teleport(true))
+ else if (!allow_control_teleport(true) && !wizard_blink)
{
mpr("A powerful magic interferes with your control of the blink.");
if (high_level_controlled_blink)
@@ -85,11 +101,13 @@ int blink(int pow, bool high_level_controlled_blink)
// query for location {dlb}:
for (;;)
{
- direction(beam, DIR_TARGET, TARG_ANY, false, false, "Blink to where?");
+ direction(beam, DIR_TARGET, TARG_ANY, false, false,
+ "Blink to where?");
if (!beam.isValid || coord_def(beam.tx, beam.ty) == you.pos())
{
- if (!yesno("Are you sure you want to cancel this blink?",
+ if (!wizard_blink &&
+ !yesno("Are you sure you want to cancel this blink?",
false, 'n'))
{
mesclr();
@@ -99,22 +117,37 @@ int blink(int pow, bool high_level_controlled_blink)
return (-1); // early return {dlb}
}
- if (see_grid(beam.tx, beam.ty))
+ // Wizard blink can move past translucent walls.
+ if (see_grid_no_trans(beam.tx, beam.ty))
break;
+ else if (trans_wall_blocking( beam.tx, beam.ty ))
+ {
+ // Wizard blink can move past translucent walls.
+ if (wizard_blink)
+ break;
+
+ mesclr();
+ mpr("You can't blink through translucent walls.");
+ }
else
{
mesclr();
- mpr("You can't blink there!");
+ mpr("You can only blink to visible locations.");
}
}
+ // Allow wizard blink to send player into walls, in case
+ // the user wants to alter that grid to something else.
+ if (grid_is_solid(grd[beam.tx][beam.ty]) && wizard_blink)
+ grd[beam.tx][beam.ty] = DNGN_FLOOR;
+
if (grid_is_solid(grd[beam.tx][beam.ty])
|| mgrd[beam.tx][beam.ty] != NON_MONSTER)
{
mpr("Oops! Maybe something was there already.");
random_blink(false);
}
- else if (you.level_type == LEVEL_ABYSS)
+ else if (you.level_type == LEVEL_ABYSS && !wizard_blink)
{
abyss_teleport( false );
you.pet_target = MHITNOT;
@@ -127,16 +160,20 @@ int blink(int pow, bool high_level_controlled_blink)
move_player_to_grid(beam.tx, beam.ty, false, true, true);
// controlling teleport contaminates the player -- bwr
- contaminate_player( 1 );
+ if (!wizard_blink)
+ contaminate_player( 1 );
}
- if (you.duration[DUR_CONDENSATION_SHIELD] > 0)
+ if (you.duration[DUR_CONDENSATION_SHIELD] > 0 && !wizard_blink)
{
you.duration[DUR_CONDENSATION_SHIELD] = 0;
you.redraw_armour_class = 1;
}
}
+ crawl_state.cancel_cmd_again();
+ crawl_state.cancel_cmd_repeat();
+
return (1);
} // end blink()
@@ -152,7 +189,10 @@ void random_blink(bool allow_partial_control, bool override_abyss)
{
mpr("The power of the Abyss keeps you in your place!");
}
- else if (!random_near_space(you.x_pos, you.y_pos, tx, ty))
+ // First try to find a random square not adjacent to the player,
+ // then one adjacent if that fails.
+ else if (!random_near_space(you.x_pos, you.y_pos, tx, ty)
+ && !random_near_space(you.x_pos, you.y_pos, tx, ty, true))
{
mpr("You feel jittery for a moment.");
}
@@ -353,7 +393,7 @@ void cast_chain_lightning( int powc )
else if (!see_source && see_targ)
mpr( "The lightning arc suddenly appears!" );
- if (!see_targ)
+ if (!see_grid_no_trans( tx, ty ))
{
// It's no longer in the caster's LOS and influence.
powc = powc / 2 + 1;
@@ -452,7 +492,12 @@ bool conjure_flame(int pow)
return false;
}
- if (!see_grid(spelld.tx, spelld.ty))
+ if (trans_wall_blocking(spelld.tx, spelld.ty))
+ {
+ mpr("A translucent wall is in the way.");
+ return false;
+ }
+ else if (!see_grid(spelld.tx, spelld.ty))
{
mpr("You can't see that place!");
continue;
@@ -525,10 +570,10 @@ int cast_big_c(int pow, cloud_type cty, kill_category whose, bolt &beam)
} // end cast_big_c()
void big_cloud(cloud_type cl_type, kill_category whose,
- int cl_x, int cl_y, int pow, int size)
+ int cl_x, int cl_y, int pow, int size, int spread_rate)
{
apply_area_cloud(make_a_normal_cloud, cl_x, cl_y, pow, size,
- cl_type, whose);
+ cl_type, whose, spread_rate);
} // end big_cloud()
static int healing_spell( int healed )
@@ -692,19 +737,16 @@ void cast_deaths_door(int pow)
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!");
// Scale power into something comparable to summon lifetime.
const int abjdur = pow * 12;
- for (int ab = 0; ab < MAX_MONSTERS; ab++)
+ for (int i = 0; i < MAX_MONSTERS; ++i)
{
- monster = &menv[ab];
+ monsters* const monster = &menv[i];
if (monster->type == -1 || !mons_near(monster))
continue;
diff --git a/crawl-ref/source/spells1.h b/crawl-ref/source/spells1.h
index b9146d8ffd..5764bdef73 100644
--- a/crawl-ref/source/spells1.h
+++ b/crawl-ref/source/spells1.h
@@ -58,14 +58,15 @@ int cast_healing(int power);
* called from: beam - it_use3 - spells - spells1
* *********************************************************************** */
void big_cloud(cloud_type cl_type, kill_category whose, int cl_x, int cl_y,
- int pow, int size);
+ int pow, int size, int spread_rate = -1);
// last updated 24may2000 {dlb}
/* ***********************************************************************
* called from: acr (WIZARD only) - item_use - spell
* *********************************************************************** */
-int blink(int pow, bool high_level_controlled_blink);
+int blink(int pow, bool high_level_controlled_blink,
+ bool wizard_blink = false);
/* ***********************************************************************
diff --git a/crawl-ref/source/spells2.cc b/crawl-ref/source/spells2.cc
index d9cd928d61..ba189cf2ad 100644
--- a/crawl-ref/source/spells2.cc
+++ b/crawl-ref/source/spells2.cc
@@ -1,6 +1,7 @@
/*
* File: spells2.cc
* Summary: Implementations of some additional spells.
+ * Mostly Necromancy and Summoning.
* Written by: Linley Henzell
*
* Modified for Crawl Reference by $Author$ on $Date$
@@ -50,6 +51,7 @@
#include "terrain.h"
#include "traps.h"
#include "view.h"
+#include "xom.h"
static int raise_corpse( int corps, int corx, int cory, beh_type corps_beh,
int corps_hit, int actual );
@@ -154,7 +156,8 @@ static void mark_detected_creature(int gridx, int gridy, const monsters *mon,
gx = gridx + random2(fuzz_diam) - fuzz_radius;
gy = gridy + random2(fuzz_diam) - fuzz_radius;
- if (map_bounds(gx, gy) && !grid_is_solid(grd[gx][gy]))
+ if (map_bounds(gx, gy)
+ && mon->can_pass_through(grd[gx][gy]))
{
found_good = true;
break;
@@ -248,7 +251,7 @@ int corpse_rot(int power)
{
for (ady = miny; ady != maxy; ady += yinc)
{
- if (see_grid(adx, ady))
+ if (see_grid_no_trans(adx, ady))
{
if (igrd[adx][ady] == NON_ITEM
|| env.cgrid[adx][ady] != EMPTY_CLOUD)
@@ -328,7 +331,7 @@ int animate_dead( int power, beh_type corps_beh, int corps_hit, int actual )
{
for (ady = miny; ady != maxy; ady += yinc)
{
- if (see_grid(adx, ady))
+ if (see_grid_no_trans(adx, ady))
{
if (igrd[adx][ady] != NON_ITEM)
{
@@ -379,9 +382,16 @@ int animate_a_corpse( int axps, int ayps, beh_type corps_beh, int corps_hit,
if (is_animatable_corpse(item) &&
(class_allowed == CORPSE_BODY || item.sub_type == CORPSE_SKELETON))
{
+ bool was_butchering = is_being_butchered(item);
+
rc = raise_corpse(objl, axps, ayps, corps_beh, corps_hit, 1);
if ( rc )
+ {
mpr("The dead are walking!");
+
+ if (was_butchering)
+ xom_is_stimulated(255);
+ }
break;
}
objl = item.link;
@@ -525,7 +535,7 @@ void cast_twisted(int power, beh_type corps_beh, int corps_hit)
}
} // end cast_twisted()
-bool brand_weapon(int which_brand, int power)
+bool brand_weapon(brand_type which_brand, int power)
{
int temp_rand; // probability determination {dlb}
int duration_affected = 0; //jmf: NB: now HOW LONG, not WHICH BRAND.
@@ -611,7 +621,7 @@ bool brand_weapon(int which_brand, int power)
// with removing the miscast effect. We may need to revise the spell
// to level 8 or 9. XXX.
// miscast_effect(SPTYP_TRANSLOCATION,
- // 9, 90, 100, "a distortion effect");
+ // 9, 90, 100, "distortion branding");
break;
case SPWPN_PAIN:
@@ -630,6 +640,8 @@ bool brand_weapon(int which_brand, int power)
msg += " glows silver and feels heavier.";
duration_affected = 7;
break;
+ default:
+ break;
}
set_item_ego_type( you.inv[wpn], OBJ_WEAPONS, which_brand );
@@ -777,10 +789,11 @@ void holy_word(int pow, bool silent)
continue;
if (mons_holiness(monster) == MH_UNDEAD
- || mons_holiness(monster) == MH_DEMONIC)
+ || mons_holiness(monster) == MH_DEMONIC)
{
simple_monster_message(monster, " convulses!");
+ behaviour_event( monster, ME_ANNOY, MHITYOU );
hurt_monster( monster, roll_dice( 2, 15 ) + (random2(pow) / 3) );
if (monster->hit_points < 1)
@@ -1095,6 +1108,12 @@ char burn_freeze(int pow, char flavour)
mpr("There isn't anything close enough!");
return 0;
}
+
+ if (trans_wall_blocking( bmove.tx, bmove.ty ))
+ {
+ mpr("A translucent wall is in the way.");
+ return 0;
+ }
}
monster = &menv[mgr];
@@ -1120,7 +1139,7 @@ char burn_freeze(int pow, char flavour)
{
if (mons_friendly( monster ))
{
- did_god_conduct( DID_ATTACK_FRIEND, 5, monster );
+ did_god_conduct( DID_ATTACK_FRIEND, 5, true, monster );
}
if (mons_holiness( monster ) == MH_HOLY)
@@ -1169,7 +1188,7 @@ int summon_elemental(int pow, int restricted_type,
unsigned char unfriendly)
{
int type_summoned = MONS_PROGRAM_BUG; // error trapping {dlb}
- char summ_success = 0;
+ int summ_success = 0;
struct dist smove;
int dir_x;
@@ -1212,7 +1231,8 @@ int summon_elemental(int pow, int restricted_type,
break;
}
- if (grd[ targ_x ][ targ_y ] == DNGN_ROCK_WALL
+ if ((grd[ targ_x ][ targ_y ] == DNGN_ROCK_WALL
+ || grd[ targ_x ][ targ_y ] == DNGN_CLEAR_ROCK_WALL)
&& (restricted_type == 0 || restricted_type == MONS_EARTH_ELEMENTAL))
{
type_summoned = MONS_EARTH_ELEMENTAL;
@@ -1276,7 +1296,8 @@ int summon_elemental(int pow, int restricted_type,
|| random2(100) < unfriendly)
{
summ_success = create_monster( type_summoned, numsc, BEH_HOSTILE,
- targ_x, targ_y, MHITYOU, 250 );
+ targ_x, targ_y, MHITYOU, 250,
+ false, false, false, true);
if (summ_success >= 0)
mpr( "The elemental doesn't seem to appreciate being summoned." );
@@ -1284,7 +1305,8 @@ int summon_elemental(int pow, int restricted_type,
else
{
summ_success = create_monster( type_summoned, numsc, BEH_FRIENDLY,
- targ_x, targ_y, you.pet_target, 250 );
+ targ_x, targ_y, you.pet_target, 250,
+ false, false, false, true);
}
return (summ_success >= 0);
@@ -1332,7 +1354,8 @@ void summon_small_mammals(int pow)
}
create_monster( thing_called, 3, BEH_FRIENDLY,
- you.x_pos, you.y_pos, you.pet_target, 250 );
+ you.x_pos, you.y_pos, you.pet_target, 250,
+ false, false, false, true);
}
} // end summon_small_mammals()
@@ -1372,10 +1395,12 @@ void summon_animals(int pow)
if ( random2(pow) < 5 ) // unfriendly
create_monster( mon_chosen, 4, BEH_HOSTILE,
- you.x_pos, you.y_pos, MHITYOU, 250 );
+ you.x_pos, you.y_pos, MHITYOU, 250,
+ false, false, false, true);
else
create_monster( mon_chosen, 4, BEH_FRIENDLY,
- you.x_pos, you.y_pos, you.pet_target, 250 );
+ you.x_pos, you.y_pos, you.pet_target, 250,
+ false, false, false, true);
}
}
@@ -1389,17 +1414,19 @@ void summon_scorpions(int pow)
{
if (random2(pow) <= 3)
{
- if (create_monster( MONS_SCORPION, 3, BEH_HOSTILE,
- you.x_pos, you.y_pos, MHITYOU, 250 ) != -1)
- {
+ const int mindex =
+ create_monster( MONS_SCORPION, 3, BEH_HOSTILE,
+ you.x_pos, you.y_pos, MHITYOU, 250,
+ false, false, false, true);
+ if (mindex != -1)
mpr("A scorpion appears. It doesn't look very happy.");
- }
}
else
{
if (create_monster( MONS_SCORPION, 3, BEH_FRIENDLY,
you.x_pos, you.y_pos,
- you.pet_target, 250 ) != -1)
+ you.pet_target, 250,
+ false, false, false, true) != -1)
{
mpr("A scorpion appears.");
}
@@ -1449,16 +1476,17 @@ void summon_ice_beast_etc(int pow, int ibc, bool divine_gift)
}
- create_monster( ibc, numsc, beha, you.x_pos, you.y_pos, MHITYOU, 250 );
+ create_monster( ibc, numsc, beha, you.x_pos, you.y_pos, MHITYOU, 250,
+ false, false, false, true);
} // end summon_ice_beast_etc()
-// Trog sends some fighting buddies for his followers
-void summon_berserker()
+// Trog sends some fighting buddies for his followers (or enemies if
+// god_gift is false)
+bool summon_berserker(int pow, bool god_gift)
{
- beh_type beha = BEH_GOD_GIFT;
- // randomize a bit to make things more interesting
- int pow = you.piety + random2(30) - random2(30);
+ beh_type beha = (god_gift) ? BEH_GOD_GIFT : BEH_HOSTILE;
int numsc = std::min(2 + (random2(pow) / 4), 6);
+ bool success = false;
monster_type mon = MONS_TROLL;
@@ -1513,6 +1541,8 @@ void summon_berserker()
if (mons != -1)
{
+ success = true;
+
monsters *summon = &menv[mons];
summon->go_berserk(false);
mon_enchant berserk = summon->get_ench(ENCH_BERSERK);
@@ -1526,6 +1556,8 @@ void summon_berserker()
summon->update_ench(berserk);
summon->update_ench(abj);
}
+
+ return success;
} // end summon_berserker()
bool summon_swarm( int pow, bool unfriendly, bool god_gift )
@@ -1596,7 +1628,8 @@ bool summon_swarm( int pow, bool unfriendly, bool god_gift )
behaviour = BEH_FRIENDLY;
if (create_monster( thing_called, 3, behaviour,
- you.x_pos, you.y_pos, MHITYOU, 250 ))
+ you.x_pos, you.y_pos, MHITYOU, 250,
+ false, false, false, true))
{
summoned = true;
}
@@ -1626,7 +1659,8 @@ void summon_undead(int pow)
if (random2(pow) < 6)
{
if (create_monster( thing_called, 5, BEH_HOSTILE,
- you.x_pos, you.y_pos, MHITYOU, 250 ) != -1)
+ you.x_pos, you.y_pos, MHITYOU, 250,
+ false, false, false, true ) != -1)
{
mpr("You sense a hostile presence.");
}
@@ -1634,7 +1668,8 @@ void summon_undead(int pow)
else
{
if (create_monster( thing_called, 5, BEH_FRIENDLY,
- you.x_pos, you.y_pos, you.pet_target, 250 ) != -1)
+ you.x_pos, you.y_pos, you.pet_target, 250,
+ false, false, false, true ) != -1)
{
mpr("An insubstantial figure forms in the air.");
}
@@ -1658,8 +1693,12 @@ void summon_things( int pow )
int numsc = 2 + (random2(pow) / 10) + (random2(pow) / 10);
- if (one_chance_in(3) && !lose_stat( STAT_INTELLIGENCE, 1, true ))
+ if (one_chance_in(3)
+ && !lose_stat( STAT_INTELLIGENCE, 1, true,
+ "summoning horrible things" ))
+ {
mpr("Your call goes unanswered.");
+ }
else
{
numsc = stepdown_value( numsc, 2, 2, 6, -1 );
@@ -1681,14 +1720,16 @@ void summon_things( int pow )
{
create_monster( MONS_TENTACLED_MONSTROSITY, 6,
BEH_FRIENDLY,
- you.x_pos, you.y_pos, you.pet_target, 250 );
+ you.x_pos, you.y_pos, you.pet_target, 250,
+ false, false, false, true );
big_things--;
}
while (numsc > 0)
{
create_monster( MONS_ABOMINATION_LARGE, 6, BEH_FRIENDLY,
- you.x_pos, you.y_pos, you.pet_target, 250 );
+ you.x_pos, you.y_pos, you.pet_target, 250,
+ false, false, false, true );
numsc--;
}
diff --git a/crawl-ref/source/spells2.h b/crawl-ref/source/spells2.h
index a19c83a76f..57de63e987 100644
--- a/crawl-ref/source/spells2.h
+++ b/crawl-ref/source/spells2.h
@@ -14,6 +14,7 @@
#define SPELLS2_H
#include "enum.h"
+#include "itemprop.h" // from brand_type
struct dist;
@@ -21,7 +22,7 @@ struct dist;
/* ***********************************************************************
* called from: spell
* *********************************************************************** */
-bool brand_weapon(int which_brand, int power);
+bool brand_weapon(brand_type which_brand, int power);
// last updated 24may2000 {dlb}
@@ -154,7 +155,7 @@ void summon_animals(int pow);
* *********************************************************************** */
void summon_small_mammals(int pow);
-void summon_berserker();
+bool summon_berserker(int pow, bool god_gift);
// last updated 24may2000 {dlb}
/* ***********************************************************************
diff --git a/crawl-ref/source/spells3.cc b/crawl-ref/source/spells3.cc
index 032f3bb2a7..200c0cfa83 100644
--- a/crawl-ref/source/spells3.cc
+++ b/crawl-ref/source/spells3.cc
@@ -43,7 +43,6 @@
#include "place.h"
#include "player.h"
#include "randart.h"
-#include "religion.h"
#include "spells1.h"
#include "spells4.h"
#include "spl-cast.h"
@@ -51,8 +50,7 @@
#include "stuff.h"
#include "traps.h"
#include "view.h"
-
-static bool monster_on_level(int monster);
+#include "xom.h"
bool cast_selective_amnesia(bool force)
{
@@ -489,31 +487,6 @@ void dancing_weapon(int pow, bool force_hostile)
burden_change();
} // 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()
-
-// XXX: Relies on RUNE_xxx == BRANCH_xxx. See rune_type in enum.h.
-static bool player_has_rune(branch_type branch)
-{
- 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)
- {
- return (true);
- }
- return (false);
-}
-
//
// This function returns true if the player can use controlled
// teleport here.
@@ -522,58 +495,10 @@ bool allow_control_teleport( bool silent )
{
bool ret = true;
- if (you.level_type == LEVEL_ABYSS || you.level_type == LEVEL_LABYRINTH)
- ret = false;
- else
+ if (testbits(env.level_flags, LFLAG_NO_TELE_CONTROL)
+ || testbits(get_branch_flags(), BFLAG_NO_TELE_CONTROL))
{
- switch (you.where_are_you)
- {
- case BRANCH_TOMB:
- ret = player_has_rune(you.where_are_you);
- break;
-
- case BRANCH_COCYTUS:
- case BRANCH_DIS:
- case BRANCH_TARTARUS:
- case BRANCH_GEHENNA:
- if (player_branch_depth() == branches[you.where_are_you].depth)
- ret = player_has_rune(you.where_are_you);
- 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 (player_branch_depth() == branches[BRANCH_ELVEN_HALLS].depth)
- {
- 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 (player_branch_depth() == branches[BRANCH_HALL_OF_ZOT].depth
- && you.char_direction != GDT_ASCENDING)
- {
- ret = false;
- }
- break;
-
- default:
- break;
- }
+ ret = false;
}
// Tell the player why if they have teleport control.
@@ -637,10 +562,7 @@ static bool teleport_player( bool allow_control, bool new_abyss_area )
return true;
}
- FixedVector < int, 2 > plox;
-
- plox[0] = 1;
- plox[1] = 0;
+ coord_def pos(1, 0);
if (is_controlled)
{
@@ -648,25 +570,24 @@ static bool teleport_player( bool allow_control, bool new_abyss_area )
mpr("Expect minor deviation.");
more();
- show_map(plox, false);
+ show_map(pos, false);
redraw_screen();
#if DEBUG_DIAGNOSTICS
- mprf(MSGCH_DIAGNOSTICS, "Target square (%d,%d)", plox[0], plox[1] );
+ mprf(MSGCH_DIAGNOSTICS, "Target square (%d,%d)", pos.x, pos.y );
#endif
- plox[0] += random2(3) - 1;
- plox[1] += random2(3) - 1;
+ pos.x += random2(3) - 1;
+ pos.y += random2(3) - 1;
if (one_chance_in(4))
{
- plox[0] += random2(3) - 1;
- plox[1] += random2(3) - 1;
+ pos.x += random2(3) - 1;
+ pos.y += random2(3) - 1;
}
- if (plox[0] < 6 || plox[1] < 6 || plox[0] > (GXM - 5)
- || plox[1] > (GYM - 5))
+ if (!in_bounds(pos))
{
mpr("Nearby solid objects disrupt your rematerialisation!");
is_controlled = false;
@@ -674,16 +595,16 @@ static bool teleport_player( bool allow_control, bool new_abyss_area )
#if DEBUG_DIAGNOSTICS
mprf(MSGCH_DIAGNOSTICS,
- "Scattered target square (%d,%d)", plox[0], plox[1] );
+ "Scattered target square (%d,%d)", pos.x, pos.y );
#endif
if (is_controlled)
{
// no longer held in net
- if (plox[0] != you.x_pos || plox[1] != you.y_pos)
+ if (pos.x != you.x_pos || pos.y != you.y_pos)
clear_trapping_net();
- you.moveto(plox[0], plox[1]);
+ you.moveto(pos.x, pos.y);
if ((grd[you.x_pos][you.y_pos] != DNGN_FLOOR
&& grd[you.x_pos][you.y_pos] != DNGN_SHALLOW_WATER)
@@ -706,8 +627,8 @@ static bool teleport_player( bool allow_control, bool new_abyss_area )
do
{
- newx = 5 + random2( GXM - 10 );
- newy = 5 + random2( GYM - 10 );
+ newx = random_range(X_BOUND_1 + 1, X_BOUND_2 - 1);
+ newy = random_range(Y_BOUND_1 + 1, Y_BOUND_2 - 1);
}
while ((grd[newx][newy] != DNGN_FLOOR
&& grd[newx][newy] != DNGN_SHALLOW_WATER)
@@ -738,28 +659,34 @@ static bool teleport_player( bool allow_control, bool new_abyss_area )
void you_teleport_now( bool allow_control, bool new_abyss_area )
{
const bool randtele = teleport_player(allow_control, new_abyss_area);
+
// Xom is amused by uncontrolled teleports that land you in a
- // dangerous place.
- if (randtele && player_in_a_dangerous_place())
+ // dangerous place, unless the player is in the Abyss and
+ // teleported to escape from all the monsters chasing him/her,
+ // since in that case the new dangerous area is almost certainly
+ // *less* dangerous than the old dangerous area.
+ if (randtele && player_in_a_dangerous_place()
+ && you.level_type != LEVEL_ABYSS)
+ {
xom_is_stimulated(255);
+ }
}
bool entomb(int powc)
{
+ // power guidelines:
+ // powc is roughly 50 at Evoc 10 with no godly assistance, ranging
+ // up to 300 or so with godly assistance or end-level, and 1200
+ // as more or less the theoretical maximum.
int number_built = 0;
const dungeon_feature_type safe_to_overwrite[] = {
DNGN_FLOOR, DNGN_SHALLOW_WATER, DNGN_OPEN_DOOR,
- DNGN_TRAP_MECHANICAL, DNGN_TRAP_MAGICAL, DNGN_TRAP_III,
+ DNGN_TRAP_MECHANICAL, DNGN_TRAP_MAGICAL, DNGN_TRAP_NATURAL,
DNGN_UNDISCOVERED_TRAP,
DNGN_FLOOR_SPECIAL
};
- if ( powc > 95 )
- powc = 95;
- if ( powc < 25 )
- powc = 25;
-
for (int srx = you.x_pos - 1; srx < you.x_pos + 2; srx++)
{
for (int sry = you.y_pos - 1; sry < you.y_pos + 2; sry++)
@@ -771,7 +698,7 @@ bool entomb(int powc)
continue;
}
- if ( random2(100) > powc )
+ if ( one_chance_in(powc/5) )
continue;
bool proceed = false;
@@ -842,7 +769,29 @@ bool entomb(int powc)
}
if (number_built > 0)
+ {
mpr("Walls emerge from the floor!");
+
+ for (int i = you.beheld_by.size() - 1; i >= 0; i--)
+ {
+ const monsters* mon = &menv[you.beheld_by[i]];
+ const coord_def pos = mon->pos();
+ int walls = num_feats_between(you.x_pos, you.y_pos,
+ pos.x, pos.y, DNGN_UNSEEN,
+ DNGN_MAXWALL);
+
+ if (walls > 0)
+ {
+ update_beholders(mon, true);
+ if (you.beheld_by.empty())
+ {
+ you.duration[DUR_BEHELD] = 0;
+ break;
+ }
+ continue;
+ }
+ }
+ }
else
canned_msg(MSG_NOTHING_HAPPENS);
@@ -879,29 +828,24 @@ void cast_poison_ammo(void)
bool project_noise(void)
{
bool success = false;
- FixedVector < int, 2 > plox;
- plox[0] = 1;
- plox[1] = 0;
+ coord_def pos(1, 0);
mpr( "Choose the noise's source (press '.' or delete to select)." );
more();
- show_map(plox, false);
+ show_map(pos, false);
redraw_screen();
#if DEBUG_DIAGNOSTICS
- mprf(MSGCH_DIAGNOSTICS, "Target square (%d,%d)", plox[0], plox[1] );
+ mprf(MSGCH_DIAGNOSTICS, "Target square (%d,%d)", pos.x, pos.y );
#endif
- if (!silenced( plox[0], plox[1] ))
+ if (!silenced( pos.x, pos.y ))
{
- // 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)
- && !grid_is_solid(grd[ plox[0] ][ plox[1] ]))
+ if (in_bounds(pos) && !grid_is_solid(grd(pos)))
{
- noisy( 30, plox[0], plox[1] );
+ noisy( 30, pos.x, pos.y );
success = true;
}
@@ -909,7 +853,7 @@ bool project_noise(void)
{
if (success)
mprf(MSGCH_SOUND, "You hear a %svoice call your name.",
- (see_grid( plox[0], plox[1] ) ? "distant " : "") );
+ (!see_grid( pos.x, pos.y ) ? "distant " : "") );
else
mprf(MSGCH_SOUND, "You hear a dull thud.");
}
@@ -1002,13 +946,10 @@ bool recall(char type_recalled)
return (success);
} // end recall()
-int portal(void)
+// Restricted to main dungeon for historical reasons, probably for
+// balance: otherwise you have an instant teleport from anywhere.
+int portal()
{
- 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.");
@@ -1019,84 +960,70 @@ int portal(void)
mpr("You must find a clear area in which to cast this spell.");
return (-1);
}
- else
+ else if (you.char_direction == GDT_ASCENDING)
{
- // the first query {dlb}:
- mpr("Which direction ('<' for up, '>' for down, 'x' to quit)?", MSGCH_PROMPT);
+ // be evil if you've got the Orb
+ mpr("An empty arch forms before you, then disappears.");
+ return 1;
+ }
- for (;;)
+ mpr("Which direction ('<' for up, '>' for down, 'x' to quit)?",
+ MSGCH_PROMPT);
+
+ int dir_sign = 0;
+ while (dir_sign == 0)
+ {
+ const int keyin = getch();
+ switch ( keyin )
{
- keyi = get_ch();
+ case '<':
+ 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 == 0)
- mpr("You can't go any further upwards with this spell.");
- else
- {
- dir_sign = -1;
- break;
- }
- }
+ case '>':
+ if (you.your_level + 1 == your_branch().depth)
+ mpr("You can't go any further downwards 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;
- }
- }
+ case 'x':
+ canned_msg(MSG_OK);
+ return (-1);
- if (keyi == 'x')
- {
- canned_msg(MSG_OK);
- return (-1); // an early return {dlb}
- }
+ default:
+ break;
}
+ }
- // the second query {dlb}:
- mpr("How many levels (1 - 9, 'x' to quit)?", MSGCH_PROMPT);
-
- for (;;)
- {
- keyi = get_ch();
-
- if (keyi == 'x')
- {
- canned_msg(MSG_OK);
- return (-1); // another early return {dlb}
- }
+ mpr("How many levels (1 - 9, 'x' to quit)?", MSGCH_PROMPT);
- 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 ))
+ int amount = 0;
+ while (amount == 0)
+ {
+ const int keyin = getch();
+ if ( isdigit(keyin) )
+ amount = (keyin - '0') * dir_sign;
+ else if (keyin == 'x')
{
- if (target_level < 0)
- target_level = 0;
- else if (target_level > 26)
- target_level = 26;
+ canned_msg(MSG_OK);
+ return (-1);
}
+ }
- mpr( "You fall through a mystic portal, and materialise at the "
- "foot of a staircase." );
- more();
-
- you.your_level = target_level - 1;
+ mpr( "You fall through a mystic portal, and materialise at the "
+ "foot of a staircase." );
+ more();
- down_stairs( old_level, DNGN_STONE_STAIRS_DOWN_I );
- }
+ const int old_level = you.your_level;
+ you.your_level = std::max(0, std::min(26, you.your_level + amount)) - 1;
+ down_stairs( old_level, DNGN_STONE_STAIRS_DOWN_I );
return (1);
-} // end portal()
+}
bool cast_death_channel(int power)
{
diff --git a/crawl-ref/source/spells4.cc b/crawl-ref/source/spells4.cc
index c76a02a8a1..947a2274aa 100644
--- a/crawl-ref/source/spells4.cc
+++ b/crawl-ref/source/spells4.cc
@@ -44,7 +44,6 @@
#include "ouch.h"
#include "player.h"
#include "randart.h"
-#include "religion.h"
#include "skills.h"
#include "spells1.h"
#include "spells4.h"
@@ -66,13 +65,9 @@ enum DEBRIS // jmf: add for shatter, dig, and Giants to throw
NUM_DEBRIS
}; // jmf: ...and I'll actually implement the items Real Soon Now...
-// 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, cloud_type 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?)
@@ -118,43 +113,6 @@ std::string your_hand( bool plural )
return result;
}
-// 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)
@@ -323,8 +281,7 @@ static int shatter_walls(int x, int y, int pow, int garbage)
{
UNUSED( garbage );
- int chance = 0;
- int stuff = 0;
+ int chance = 0;
// if not in-bounds then we can't really shatter it -- bwr
if (x <= 5 || x >= GXM - 5 || y <= 5 || y >= GYM - 5)
@@ -336,7 +293,6 @@ static int shatter_walls(int x, int y, int pow, int garbage)
if (see_grid(x, y))
mpr("A secret door shatters!");
grd[x][y] = DNGN_FLOOR;
- stuff = DEBRIS_WOOD;
chance = 100;
break;
@@ -345,47 +301,42 @@ static int shatter_walls(int x, int y, int pow, int garbage)
if (see_grid(x, y))
mpr("A door shatters!");
grd[x][y] = DNGN_FLOOR;
- stuff = DEBRIS_WOOD;
chance = 100;
break;
case DNGN_METAL_WALL:
- stuff = DEBRIS_METAL;
chance = pow / 10;
break;
case DNGN_ORCISH_IDOL:
case DNGN_GRANITE_STATUE:
chance = 50;
- stuff = DEBRIS_STONE;
break;
+ case DNGN_CLEAR_STONE_WALL:
case DNGN_STONE_WALL:
chance = pow / 6;
- stuff = DEBRIS_STONE;
break;
+ case DNGN_CLEAR_ROCK_WALL:
case DNGN_ROCK_WALL:
chance = pow / 4;
- stuff = DEBRIS_ROCK;
break;
case DNGN_GREEN_CRYSTAL_WALL:
chance = 50;
- stuff = DEBRIS_CRYSTAL;
break;
default:
break;
}
- if (stuff && random2(100) < chance)
+ if (random2(100) < chance)
{
if (!silenced( x, y ))
noisy( 30, x, y );
grd[x][y] = DNGN_FLOOR;
- place_debris(x, y, stuff);
return (1);
}
@@ -450,14 +401,16 @@ void cast_forescry(int pow)
{
if (!you.duration[DUR_FORESCRY])
mpr("You begin to receive glimpses of the immediate future...");
+ else
+ mpr("Your vision of the future intensifies.");
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()
+ you.redraw_evasion = true;
+}
void cast_see_invisible(int pow)
{
@@ -471,113 +424,7 @@ void cast_see_invisible(int pow)
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, TARG_ANY, true );
-
- 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_artefact(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
@@ -622,7 +469,8 @@ void cast_summon_butterflies(int pow)
for (int scount = 1; scount < num; scount++)
{
create_monster( MONS_BUTTERFLY, 3, BEH_FRIENDLY,
- you.x_pos, you.y_pos, MHITYOU, 250 );
+ you.x_pos, you.y_pos, MHITYOU, 250,
+ false, false, false, true );
}
}
@@ -660,7 +508,8 @@ void cast_summon_large_mammal(int pow)
}
create_monster( mon, 3, BEH_FRIENDLY, you.x_pos, you.y_pos,
- you.pet_target, 250 );
+ you.pet_target, 250,
+ false, false, false, true );
}
void cast_sticks_to_snakes(int pow)
@@ -701,7 +550,8 @@ void cast_sticks_to_snakes(int pow)
}
if (create_monster( mon, dur, behaviour, you.x_pos, you.y_pos,
- MHITYOU, 250 ) != -1)
+ MHITYOU, 250,
+ false, false, false, true ) != -1)
{
how_many++;
}
@@ -746,19 +596,10 @@ void cast_sticks_to_snakes(int pow)
if (pow > 20 && one_chance_in(3))
mon = MONS_BROWN_SNAKE;
- create_monster(mon, dur, behaviour, you.x_pos, you.y_pos, MHITYOU, 250);
+ create_monster(mon, dur, behaviour, you.x_pos, you.y_pos, MHITYOU, 250,
+ false, false, false, true);
}
-#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;
@@ -789,7 +630,8 @@ void cast_summon_dragon(int pow)
if (create_monster( MONS_DRAGON, 3,
(happy ? BEH_FRIENDLY : BEH_HOSTILE),
- you.x_pos, you.y_pos, MHITYOU, 250 ) != -1)
+ you.x_pos, you.y_pos, MHITYOU, 250,
+ false, false, false, true) != -1)
{
mprf("A dragon appears.%s",
happy ? "" : " It doesn't look very happy.");
@@ -861,12 +703,12 @@ static int sleep_monsters(int x, int y, int pow, int garbage)
// if (mons_friendly( &menv[mnstr] )) return 0;
//jmf: now that sleep == hibernation:
- if (mons_res_cold( &menv[mnstr] ) > 0 && coinflip()) return 0;
- if (menv[mnstr].has_ench(ENCH_SLEEP_WARY)) return 0;
+ if (mons_res_cold( &menv[mnstr] ) > 0 && coinflip())
+ return 0;
+ if (menv[mnstr].has_ench(ENCH_SLEEP_WARY))
+ return 0;
- menv[mnstr].behaviour = BEH_SLEEP;
- menv[mnstr].add_ench(ENCH_SLEEPY);
- menv[mnstr].add_ench(ENCH_SLEEP_WARY);
+ menv[mnstr].put_to_sleep();
if (mons_class_flag( menv[mnstr].type, M_COLD_BLOOD ) && coinflip())
menv[mnstr].add_ench(ENCH_SLOW);
@@ -1231,28 +1073,15 @@ void cast_silence(int pow)
if (you.duration[DUR_SILENCE] > 100)
you.duration[DUR_SILENCE] = 100;
+
+ if (you.duration[DUR_BEHELD])
+ {
+ mpr("You break out of your daze!", MSGCH_RECOVERY);
+ you.duration[DUR_BEHELD] = 0;
+ you.beheld_by.clear();
+ }
} // 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 );
@@ -1358,12 +1187,12 @@ static int distortion_monsters(int x, int y, int pow, int message)
if (you.skills[SK_TRANSLOCATIONS] < random2(8))
{
miscast_effect( SPTYP_TRANSLOCATION, pow / 9 + 1, pow, 100,
- "a distortion effect" );
+ "cast bend on self" );
}
else
{
miscast_effect( SPTYP_TRANSLOCATION, 1, 1, 100,
- "a distortion effect" );
+ "cast bend on self" );
}
return 1;
@@ -1555,63 +1384,16 @@ static int make_a_rot_cloud(int x, int y, int pow, cloud_type ctype)
return 0;
} // end make_a_rot_cloud()
-int make_a_normal_cloud(int x, int y, int pow, cloud_type ctype,
- kill_category whose)
+int make_a_normal_cloud(int x, int y, int pow, int spread_rate,
+ cloud_type ctype, kill_category whose)
{
place_cloud( ctype, x, y,
(3 + random2(pow / 4) + random2(pow / 4) + random2(pow / 4)),
- whose );
+ whose, spread_rate );
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 );
@@ -1622,7 +1404,7 @@ static int passwall(int x, int y, int pow, int garbage)
int shallow = 1 + (you.skills[SK_EARTH_MAGIC] / 8);
// allow statues as entry points?
- if (grd[x][y] != DNGN_ROCK_WALL)
+ if (grd[x][y] != DNGN_ROCK_WALL && grd[x][y] != DNGN_CLEAR_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
@@ -1651,6 +1433,7 @@ static int passwall(int x, int y, int pow, int garbage)
done = true;
break;
case DNGN_ROCK_WALL:
+ case DNGN_CLEAR_ROCK_WALL:
case DNGN_ORCISH_IDOL:
case DNGN_GRANITE_STATUE:
case DNGN_SECRET_DOOR:
@@ -1722,8 +1505,12 @@ 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) ))
+ if (one_chance_in(20)
+ && lose_stat( STAT_INTELLIGENCE, 1 + random2(3), false,
+ "casting intoxication"))
+ {
mpr("Your head spins!");
+ }
apply_area_visible(intoxicate_monsters, pow);
} // end cast_intoxicate()
@@ -2185,7 +1972,8 @@ void cast_fulsome_distillation( int powc )
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 );
+ BEH_HOSTILE, x, y, MHITNOT, 250,
+ false, false, false, true );
if (mon != -1)
{
@@ -2515,9 +2303,11 @@ void cast_fragmentation(int pow) // jmf: ripped idea from airstrike
// Stone and rock terrain
//
case DNGN_ROCK_WALL:
+ case DNGN_CLEAR_ROCK_WALL:
case DNGN_SECRET_DOOR:
blast.colour = env.rock_colour;
// fall-through
+ case DNGN_CLEAR_STONE_WALL:
case DNGN_STONE_WALL:
what = "wall";
if (player_in_branch( BRANCH_HALL_OF_ZOT ))
@@ -2544,7 +2334,11 @@ void cast_fragmentation(int pow) // jmf: ripped idea from airstrike
&& (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))))
+ || (pow >= 40 && grid == DNGN_CLEAR_ROCK_WALL
+ && one_chance_in(3))
+ || (pow >= 60 && grid == DNGN_STONE_WALL && one_chance_in(10))
+ || (pow >= 60 && grid == DNGN_CLEAR_STONE_WALL &&
+ one_chance_in(10)) ))
{
// terrain blew up real good:
blast.ex_size = 2;
@@ -2654,7 +2448,6 @@ void cast_fragmentation(int pow) // jmf: ripped idea from airstrike
: "The dungeon floor");
break;
- case DNGN_TRAP_III: // What are these? Should they explode? -- bwr
default:
// FIXME: cute message for water?
break;
@@ -2673,9 +2466,6 @@ void cast_fragmentation(int pow) // jmf: ripped idea from airstrike
// 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)
@@ -2720,7 +2510,7 @@ void cast_twist(int pow)
return;
} // end cast_twist()
-bool cast_portaled_projectile(int pow, bolt& beam)
+bool cast_portal_projectile(int pow, bolt& beam)
{
if ( pow > 50 )
pow = 50;
@@ -2731,6 +2521,12 @@ bool cast_portaled_projectile(int pow, bolt& beam)
return false;
}
+ if (trans_wall_blocking( beam.target_x, beam.target_y ))
+ {
+ mpr("A translucent wall is in the way.");
+ return 0;
+ }
+
const int idx = get_fire_item_index();
if ( idx == ENDOFPACK )
{
@@ -2759,8 +2555,8 @@ bool cast_portaled_projectile(int pow, bolt& beam)
void cast_far_strike(int pow)
{
- struct dist targ;
- struct bolt tmp; // used, but ignored
+ dist targ;
+ bolt tmp; // used, but ignored
// Get target, using DIR_TARGET for targetting only,
// since we don't use fire_beam() for this spell.
@@ -2768,37 +2564,39 @@ void cast_far_strike(int pow)
return;
// Get the target monster...
- if (mgrd[targ.tx][targ.ty] == NON_MONSTER
- || targ.isMe)
+ if (mgrd[targ.tx][targ.ty] == NON_MONSTER || targ.isMe)
{
mpr("There is no monster there!");
return;
}
+ if (trans_wall_blocking( targ.tx, targ.ty ))
+ {
+ mpr("A translucent wall is in the way.");
+ 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
+ if (you.weapon()) // if not unarmed
{
+ const item_def& wpn(*you.weapon());
// look up the damage base
- if (you.inv[ weapon ].base_type == OBJ_WEAPONS)
+ if (wpn.base_type == OBJ_WEAPONS)
{
- damage = property( you.inv[ weapon ], PWPN_DAMAGE );
- speed = property( you.inv[ weapon ], PWPN_SPEED );
+ damage = property( wpn, PWPN_DAMAGE );
+ speed = property( wpn, PWPN_SPEED );
- if (get_weapon_brand( you.inv[ weapon ] ) == SPWPN_SPEED)
- {
- speed *= 5;
- speed /= 10;
- }
+ if (get_weapon_brand(wpn) == SPWPN_SPEED)
+ speed /= 2;
}
- else if (item_is_staff( you.inv[ weapon ] ))
+ else if (item_is_staff(wpn))
{
- damage = property( you.inv[ weapon ], PWPN_DAMAGE );
- speed = property( you.inv[ weapon ], PWPN_SPEED );
+ damage = property(wpn, PWPN_DAMAGE );
+ speed = property(wpn, PWPN_SPEED );
}
}
@@ -2839,21 +2637,12 @@ void cast_far_strike(int pow)
damage *= dammod;
damage /= 78;
- struct monsters *monster = &menv[ mgrd[targ.tx][targ.ty] ];
+ monsters *monster = &menv[ mgrd[targ.tx][targ.ty] ];
// apply monster's AC
if (monster->ac > 0)
damage -= random2( 1 + monster->ac );
-#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 );
@@ -2878,7 +2667,7 @@ void cast_far_strike(int pow)
int cast_apportation(int pow)
{
- struct dist beam;
+ dist beam;
mpr("Pull items from where?");
@@ -2897,6 +2686,12 @@ int cast_apportation(int pow)
return (-1);
}
+ if (trans_wall_blocking( beam.tx, beam.ty ))
+ {
+ mpr("A translucent wall is in the way.");
+ return (0);
+ }
+
// Protect the player from destroying the item
const dungeon_feature_type grid = grd[ you.x_pos ][ you.y_pos ];
@@ -2984,7 +2779,7 @@ int cast_apportation(int pow)
&& mitm[item].sub_type == MI_THROWING_NET
&& item_is_stationary(mitm[item]))
{
- int mon = mgrd[ beam.tx ][ beam.ty ];
+ const int mon = mgrd[ beam.tx ][ beam.ty ];
remove_item_stationary(mitm[item]);
if (mon != NON_MONSTER)
@@ -2999,37 +2794,24 @@ int cast_apportation(int pow)
void cast_sandblast(int pow, bolt &beam)
{
- bool big = true;
-
- // 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;
+ bool big = false;
- big = false;
-
- if (you.equip[EQ_WEAPON] != -1)
+ if (you.weapon())
{
- 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;
+ const item_def& wpn(*you.weapon());
+ big = (wpn.base_type == OBJ_MISSILES)
+ && (wpn.sub_type == MI_STONE || wpn.sub_type == MI_LARGE_ROCK);
}
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()
+
+ zapping(big ? ZAP_SANDBLAST : ZAP_SMALL_SANDBLAST, pow, beam);
+}
void cast_condensation_shield(int pow)
{
- if (you.equip[EQ_SHIELD] != -1 || you.duration[DUR_FIRE_SHIELD])
+ if (you.shield() || you.duration[DUR_FIRE_SHIELD])
canned_msg(MSG_SPELL_FIZZLES);
else
{
@@ -3041,7 +2823,7 @@ void cast_condensation_shield(int pow)
else
{
mpr("A crackling disc of dense vapour forms in the air!");
- you.redraw_armour_class = 1;
+ you.redraw_armour_class = true;
you.duration[DUR_CONDENSATION_SHIELD] = 10 + roll_dice(2, pow / 5);
}
@@ -3073,20 +2855,35 @@ static int quadrant_blink(int x, int y, int pow, int garbage)
const int dist = random2(6) + 2; // 2-7
const int ox = you.x_pos + (x - you.x_pos) * dist;
const int oy = you.y_pos + (y - you.y_pos) * dist;
-
+
+ // This can take a while if pow is high and there's lots of translucent
+ // walls nearby.
int tx, ty;
+ bool found = false;
for ( int i = 0; i < (pow*pow) / 500 + 1; ++i )
{
- // find a space near our target...
- if ( !random_near_space(ox, oy, tx, ty) )
+ // find a space near our target... First try to find a random
+ // square not adjacent to the player, then one adjacent if
+ // that fails.
+ if ( !random_near_space(ox, oy, tx, ty) &&
+ !random_near_space(ox, oy, tx, ty, true))
return 0;
-
+
// which is close enough, and also far enough from us
- if ( distance(ox, oy, tx, ty) <= 10 &&
- distance(you.x_pos, you.y_pos, tx, ty) >= 8 )
- break;
+ if ( distance(ox, oy, tx, ty) > 10 &&
+ distance(you.x_pos, you.y_pos, tx, ty) < 8 )
+ continue;
+
+ if (!see_grid_no_trans(tx, ty))
+ continue;
+
+ found = true;
+ break;
}
+ if (!found)
+ return(0);
+
you.moveto(tx, ty);
return 1;
}
diff --git a/crawl-ref/source/spells4.h b/crawl-ref/source/spells4.h
index 515c8cc5a6..55535bf37a 100644
--- a/crawl-ref/source/spells4.h
+++ b/crawl-ref/source/spells4.h
@@ -20,8 +20,8 @@ struct bolt;
std::string 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, cloud_type ctype,
- kill_category);
+int make_a_normal_cloud(int x, int y, int pow, int spread_rate,
+ cloud_type ctype, kill_category);
int disperse_monsters(int x, int y, int pow, int message);
void cast_bend(int pow);
@@ -62,6 +62,6 @@ void cast_shuggoth_seed(int powc);
void make_shuggoth(int x, int y, int hp);
int cast_semi_controlled_blink(int pow);
-bool cast_portaled_projectile(int pow, bolt& beam);
+bool cast_portal_projectile(int pow, bolt& beam);
#endif
diff --git a/crawl-ref/source/spl-book.cc b/crawl-ref/source/spl-book.cc
index 9b4535d3dc..33206f31c5 100644
--- a/crawl-ref/source/spl-book.cc
+++ b/crawl-ref/source/spl-book.cc
@@ -40,6 +40,7 @@
#include "religion.h"
#include "spl-cast.h"
#include "spl-util.h"
+#include "state.h"
#include "stuff.h"
#define SPELLBOOK_SIZE 8
@@ -160,7 +161,7 @@ static spell_type spellbook_template_array[NUMBER_SPELLBOOKS][SPELLBOOK_SIZE] =
},
// 11 - Book of Spatial Translocations
{SPELL_APPORTATION,
- SPELL_PORTALED_PROJECTILE,
+ SPELL_PORTAL_PROJECTILE,
SPELL_BLINK,
SPELL_RECALL,
SPELL_TELEPORT_OTHER,
@@ -1485,12 +1486,14 @@ int staff_spell( int staff )
if (food && (you.hunger_state <= HS_STARVING || you.hunger <= food))
{
mpr("You don't have the energy to cast that spell.");
+ crawl_state.zero_turns_taken();
return (-1);
}
if (istaff.plus < mana)
{
mpr("The rod doesn't have enough magic points.");
+ crawl_state.zero_turns_taken();
// Don't lose a turn for trying to evoke without enough MP - that's
// needlessly cruel for an honest error.
return (-1);
@@ -1499,6 +1502,7 @@ int staff_spell( int staff )
if (you.experience_level < diff)
{
mprf("You need to be at least level %d to use that.", diff);
+ crawl_state.zero_turns_taken();
return (-1);
}
@@ -1511,7 +1515,10 @@ int staff_spell( int staff )
}
// All checks passed, we can cast the spell
else if (your_spells(spell, powc, false) == SPRET_ABORT)
+ {
+ crawl_state.zero_turns_taken();
return (-1);
+ }
make_hungry( food, true );
istaff.plus -= mana;
diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc
index 2480ba424c..3685534fe2 100644
--- a/crawl-ref/source/spl-cast.cc
+++ b/crawl-ref/source/spl-cast.cc
@@ -51,9 +51,11 @@
#include "spells4.h"
#include "spl-book.h"
#include "spl-util.h"
+#include "state.h"
#include "stuff.h"
#include "transfor.h"
#include "view.h"
+#include "xom.h"
#ifdef DOS
#include <conio.h>
@@ -200,6 +202,7 @@ int list_spells()
spell_menu.set_highlighter(NULL);
spell_menu.set_more(formatted_string("Press '!' to toggle spell view."));
spell_menu.add_toggle_key('!');
+ spell_menu.set_tag("spell");
for ( int i = 0; i < 52; ++i )
{
@@ -584,6 +587,7 @@ bool cast_a_spell()
if (!you.spell_no)
{
mpr("You don't know any spells.");
+ crawl_state.zero_turns_taken();
return (false);
}
@@ -596,6 +600,7 @@ bool cast_a_spell()
if (silenced(you.x_pos, you.y_pos))
{
mpr("You cannot cast spells when silenced!");
+ crawl_state.zero_turns_taken();
more();
return (false);
}
@@ -628,11 +633,15 @@ bool cast_a_spell()
}
if (keyin == ESCAPE)
+ {
+ canned_msg( MSG_OK );
return (false);
+ }
if (!isalpha(keyin))
{
mpr("You don't know that spell.");
+ crawl_state.zero_turns_taken();
return (false);
}
@@ -641,6 +650,7 @@ bool cast_a_spell()
if (spell == SPELL_NO_SPELL)
{
mpr("You don't know that spell.");
+ crawl_state.zero_turns_taken();
return (false);
}
@@ -665,7 +675,10 @@ bool cast_a_spell()
{
const spret_type cast_result = your_spells( spell );
if (cast_result == SPRET_ABORT)
+ {
+ crawl_state.zero_turns_taken();
return (false);
+ }
exercise_spell( spell, true, cast_result == SPRET_SUCCESS );
did_god_conduct( DID_SPELL_CASTING, 1 + random2(5) );
@@ -780,15 +793,19 @@ void spellcasting_side_effects(spell_type spell, bool idonly = false)
if (!spell_is_utility_spell(spell))
did_god_conduct( DID_SPELL_NONUTILITY, 10 + spell_difficulty(spell) );
- if (spell_is_unholy( spell ))
- did_god_conduct( DID_UNHOLY, 10 + spell_difficulty(spell) );
+ // Self-banishment gets a special exemption - you're there to spread light
+ if (spell_is_unholy(spell) &&
+ (spell != SPELL_BANISHMENT || !you.banished))
+ {
+ did_god_conduct( DID_UNHOLY, 10 + spell_difficulty(spell) );
+ }
// 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 (spell_typematch(spell, SPTYP_FIRE))
expose_player_to_element(BEAM_FIRE, 0);
- if (spell_typematch( spell, SPTYP_NECROMANCY ))
+ if (spell_typematch(spell, SPTYP_NECROMANCY))
{
did_god_conduct( DID_NECROMANCY, 10 + spell_difficulty(spell) );
@@ -862,7 +879,7 @@ spret_type your_spells( spell_type spell, int powc, bool allow_fail )
testbits( flags, SPFLAG_DIR ) ? DIR_DIR : DIR_NONE);
const char *prompt = get_spell_target_prompt(spell);
- if (spell == SPELL_PORTALED_PROJECTILE)
+ if (spell == SPELL_PORTAL_PROJECTILE)
{
const int idx = get_fire_item_index();
if ( idx == ENDOFPACK )
@@ -876,7 +893,7 @@ spret_type your_spells( spell_type spell, int powc, bool allow_fail )
else if (dir == DIR_DIR)
mpr(prompt? prompt : "Which direction? ", MSGCH_PROMPT);
- bool needs_path =
+ const bool needs_path =
!(testbits(flags, SPFLAG_GRID) || testbits(flags, SPFLAG_TARGET));
if ( !spell_direction( spd, beam, dir, targ, needs_path, prompt ) )
@@ -1016,6 +1033,7 @@ spret_type your_spells( spell_type spell, int powc, bool allow_fail )
break;
case SPELL_DELAYED_FIREBALL:
+ crawl_state.cant_cmd_repeat("You can't repeat delayed fireball.");
// This spell has two main advantages over Fireball:
//
// (1) The release is instantaneous, so monsters will not
@@ -1188,6 +1206,8 @@ spret_type your_spells( spell_type spell, int powc, bool allow_fail )
break;
case SPELL_SELECTIVE_AMNESIA:
+ crawl_state.cant_cmd_repeat("You can't repeat selective amnesia.");
+
if (!cast_selective_amnesia(false))
return (SPRET_ABORT);
break; // Sif Muna power calls with true
@@ -1433,6 +1453,7 @@ spret_type your_spells( spell_type spell, int powc, bool allow_fail )
break;
case SPELL_TUKIMAS_DANCE:
+ crawl_state.cant_cmd_repeat("You can't repeat dancing weapon.");
dancing_weapon(powc, false);
break;
@@ -1572,6 +1593,7 @@ spret_type your_spells( spell_type spell, int powc, bool allow_fail )
break;
case SPELL_ALTER_SELF:
+ crawl_state.cant_cmd_repeat("You can't repeat alter self.");
if (!enough_hp( you.hp_max / 2, true ))
{
mpr( "Your body is in too poor a condition "
@@ -1597,6 +1619,7 @@ spret_type your_spells( spell_type spell, int powc, bool allow_fail )
break;
case SPELL_PORTAL:
+ crawl_state.cant_cmd_repeat("You can't repeat create portal.");
if (portal() == -1)
return (SPRET_ABORT);
break;
@@ -1846,6 +1869,7 @@ spret_type your_spells( spell_type spell, int powc, bool allow_fail )
break;
case SPELL_SWAP:
+ crawl_state.cant_cmd_repeat("You can't swap.");
cast_swap(powc);
break;
@@ -1854,8 +1878,8 @@ spret_type your_spells( spell_type spell, int powc, bool allow_fail )
return (SPRET_ABORT);
break;
- case SPELL_PORTALED_PROJECTILE:
- if ( !cast_portaled_projectile(powc, beam) )
+ case SPELL_PORTAL_PROJECTILE:
+ if ( !cast_portal_projectile(powc, beam) )
return SPRET_ABORT;
break;
@@ -2542,7 +2566,8 @@ static void miscast_divination(int severity, const char* cause)
case 0:
if (you.is_undead)
mpr("You suddenly recall your previous life!");
- else if (lose_stat(STAT_INTELLIGENCE, 1 + random2(3)))
+ else if (lose_stat(STAT_INTELLIGENCE, 1 + random2(3),
+ false, cause))
mpr("You have damaged your brain!");
else
mpr("You have a terrible headache.");
@@ -2570,7 +2595,8 @@ static void miscast_divination(int severity, const char* cause)
case 2:
if (you.is_undead)
mpr("You suddenly recall your previous life.");
- else if (lose_stat(STAT_INTELLIGENCE, 3 + random2(3)))
+ else if (lose_stat(STAT_INTELLIGENCE, 3 + random2(3),
+ false, cause))
mpr("You have damaged your brain!");
else
mpr("You have a terrible headache.");
@@ -2725,7 +2751,7 @@ static void miscast_necromancy(int severity, const char* cause)
} // otherwise it just flows through...
case 2:
- lose_stat(STAT_RANDOM, 1 + random2avg(7, 2));
+ lose_stat(STAT_RANDOM, 1 + random2avg(7, 2), false, cause);
break;
case 3:
@@ -3420,7 +3446,7 @@ static void miscast_poison(int severity, const char* cause)
if (player_res_poison())
canned_msg(MSG_NOTHING_HAPPENS);
else
- lose_stat(STAT_RANDOM, 1);
+ lose_stat(STAT_RANDOM, 1, false, cause);
break;
}
break;
@@ -3447,7 +3473,7 @@ static void miscast_poison(int severity, const char* cause)
if (player_res_poison())
canned_msg(MSG_NOTHING_HAPPENS);
else
- lose_stat(STAT_RANDOM, 1 + random2avg(5, 2));
+ lose_stat(STAT_RANDOM, 1 + random2avg(5, 2), false, cause);
break;
}
break;
@@ -3474,6 +3500,9 @@ void miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail,
return;
}
+ if (cause == NULL || strlen(cause) == 0)
+ cause = "spell miscasting";
+
sever /= 100;
#if DEBUG_DIAGNOSTICS
diff --git a/crawl-ref/source/spl-data.h b/crawl-ref/source/spl-data.h
index c50c5e40da..99b5ed5d7e 100644
--- a/crawl-ref/source/spl-data.h
+++ b/crawl-ref/source/spl-data.h
@@ -2160,14 +2160,14 @@
},
{
- SPELL_PORTALED_PROJECTILE, "Portaled Projectile",
- SPTYP_TRANSLOCATION,
- SPFLAG_TARGET,
- 2,
- 50,
- NULL,
- false,
- false
+ SPELL_PORTAL_PROJECTILE, "Portal Projectile",
+ SPTYP_TRANSLOCATION,
+ SPFLAG_TARGET,
+ 2,
+ 50,
+ NULL,
+ false,
+ false
},
{
diff --git a/crawl-ref/source/spl-util.cc b/crawl-ref/source/spl-util.cc
index 3f9bcffad7..9cbaace2df 100644
--- a/crawl-ref/source/spl-util.cc
+++ b/crawl-ref/source/spl-util.cc
@@ -54,9 +54,10 @@ static int spell_list[NUM_SPELLS];
#define SPELLDATASIZE (sizeof(spelldata)/sizeof(struct spell_desc))
static struct spell_desc *seekspell(spell_type spellid);
-static bool cloud_helper(int (*func)(int, int, int, cloud_type, kill_category),
- int x, int y,
- int pow, cloud_type ctype, kill_category );
+static bool cloud_helper(int (*func)(int, int, int, int, cloud_type,
+ kill_category),
+ int x, int y, int pow, int spread_rate,
+ cloud_type ctype, kill_category );
/*
* BEGIN PUBLIC FUNCTIONS
@@ -286,7 +287,8 @@ const char *spell_title(spell_type spell)
// 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 apply_area_visible( int (*func) (int, int, int, int), int power,
+ bool pass_through_trans)
{
int x, y;
int rv = 0;
@@ -296,7 +298,8 @@ int apply_area_visible( int (*func) (int, int, int, int), int power )
{
for (y = you.y_pos - 8; y <= you.y_pos + 8; y++)
{
- if (see_grid(x, y))
+ if ((pass_through_trans && see_grid(x, y))
+ || (!pass_through_trans && see_grid_no_trans(x, y)))
rv += func(x, y, power, 0);
}
}
@@ -543,17 +546,19 @@ int apply_area_within_radius( int (*func) (int, int, int, int),
// 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, cloud_type, kill_category),
+void apply_area_cloud( int (*func) (int, int, int, int, cloud_type,
+ kill_category),
int x, int y,
int pow, int number, cloud_type ctype,
- kill_category whose )
+ kill_category whose, int spread_rate )
{
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, whose))
+ if (clouds_left && cloud_helper(func, x, y, pow, spread_rate,
+ ctype, whose))
clouds_left--;
if (!clouds_left)
@@ -568,28 +573,32 @@ void apply_area_cloud( int (*func) (int, int, int, cloud_type, kill_category),
if (x_first)
{
- if (clouds_left && cloud_helper(func, x + dx, y, pow, ctype, whose))
+ if (clouds_left && cloud_helper(func, x + dx, y, pow, spread_rate,
+ ctype, whose))
{
clouds_left--;
good_squares++;
neighbours[0]++;
}
- if (clouds_left && cloud_helper(func, x - dx, y, pow, ctype, whose))
+ if (clouds_left && cloud_helper(func, x - dx, y, pow, spread_rate,
+ ctype, whose))
{
clouds_left--;
good_squares++;
neighbours[1]++;
}
- if (clouds_left && cloud_helper(func, x, y + dy, pow, ctype, whose))
+ if (clouds_left && cloud_helper(func, x, y + dy, pow, spread_rate,
+ ctype, whose))
{
clouds_left--;
good_squares++;
neighbours[2]++;
}
- if (clouds_left && cloud_helper(func, x, y - dy, pow, ctype, whose))
+ if (clouds_left && cloud_helper(func, x, y - dy, pow, spread_rate,
+ ctype, whose))
{
clouds_left--;
good_squares++;
@@ -598,28 +607,32 @@ void apply_area_cloud( int (*func) (int, int, int, cloud_type, kill_category),
}
else
{
- if (clouds_left && cloud_helper(func, x, y + dy, pow, ctype, whose))
+ if (clouds_left && cloud_helper(func, x, y + dy, pow, spread_rate,
+ ctype, whose))
{
clouds_left--;
good_squares++;
neighbours[2]++;
}
- if (clouds_left && cloud_helper(func, x, y - dy, pow, ctype, whose))
+ if (clouds_left && cloud_helper(func, x, y - dy, pow, spread_rate,
+ ctype, whose))
{
clouds_left--;
good_squares++;
neighbours[3]++;
}
- if (clouds_left && cloud_helper(func, x + dx, y, pow, ctype, whose))
+ if (clouds_left && cloud_helper(func, x + dx, y, pow, spread_rate,
+ ctype, whose))
{
clouds_left--;
good_squares++;
neighbours[0]++;
}
- if (clouds_left && cloud_helper(func, x - dx, y, pow, ctype, whose))
+ if (clouds_left && cloud_helper(func, x - dx, y, pow, spread_rate,
+ ctype, whose))
{
clouds_left--;
good_squares++;
@@ -628,28 +641,32 @@ void apply_area_cloud( int (*func) (int, int, int, cloud_type, kill_category),
}
// now diagonals; we could randomize dx & dy again here
- if (clouds_left && cloud_helper(func, x + dx, y + dy, pow, ctype, whose))
+ if (clouds_left && cloud_helper(func, x + dx, y + dy, pow, spread_rate,
+ ctype, whose))
{
clouds_left--;
good_squares++;
neighbours[4]++;
}
- if (clouds_left && cloud_helper(func, x - dx, y + dy, pow, ctype, whose))
+ if (clouds_left && cloud_helper(func, x - dx, y + dy, pow, spread_rate,
+ ctype, whose))
{
clouds_left--;
good_squares++;
neighbours[5]++;
}
- if (clouds_left && cloud_helper(func, x + dx, y - dy, pow, ctype, whose))
+ if (clouds_left && cloud_helper(func, x + dx, y - dy, pow, spread_rate,
+ ctype, whose))
{
clouds_left--;
good_squares++;
neighbours[6]++;
}
- if (clouds_left && cloud_helper(func, x - dx, y - dy, pow, ctype, whose))
+ if (clouds_left && cloud_helper(func, x - dx, y - dy, pow, spread_rate,
+ ctype, whose))
{
clouds_left--;
good_squares++;
@@ -671,28 +688,36 @@ void apply_area_cloud( int (*func) (int, int, int, cloud_type, kill_category),
switch (i)
{
case 0:
- apply_area_cloud(func, x + dx, y, pow, spread, ctype, whose);
+ apply_area_cloud(func, x + dx, y, pow, spread, ctype, whose,
+ spread_rate);
break;
case 1:
- apply_area_cloud(func, x - dx, y, pow, spread, ctype, whose);
+ apply_area_cloud(func, x - dx, y, pow, spread, ctype, whose,
+ spread_rate);
break;
case 2:
- apply_area_cloud(func, x, y + dy, pow, spread, ctype, whose);
+ apply_area_cloud(func, x, y + dy, pow, spread, ctype, whose,
+ spread_rate);
break;
case 3:
- apply_area_cloud(func, x, y - dy, pow, spread, ctype, whose);
+ apply_area_cloud(func, x, y - dy, pow, spread, ctype, whose,
+ spread_rate);
break;
case 4:
- apply_area_cloud(func, x + dx, y + dy, pow, spread, ctype, whose);
+ apply_area_cloud(func, x + dx, y + dy, pow, spread, ctype, whose,
+ spread_rate);
break;
case 5:
- apply_area_cloud(func, x - dx, y + dy, pow, spread, ctype, whose);
+ apply_area_cloud(func, x - dx, y + dy, pow, spread, ctype, whose,
+ spread_rate);
break;
case 6:
- apply_area_cloud(func, x + dx, y - dy, pow, spread, ctype, whose);
+ apply_area_cloud(func, x + dx, y - dy, pow, spread, ctype, whose,
+ spread_rate);
break;
case 7:
- apply_area_cloud(func, x - dx, y - dy, pow, spread, ctype, whose);
+ apply_area_cloud(func, x - dx, y - dy, pow, spread, ctype, whose,
+ spread_rate);
break;
}
}
@@ -835,13 +860,14 @@ static spell_desc *seekspell(spell_type spell)
return (index != -1? &spelldata[index] : NULL);
}
-static bool cloud_helper(int (*func)(int, int, int, cloud_type, kill_category),
- int x, int y,
- int pow, cloud_type ctype, kill_category whose )
+static bool cloud_helper(int (*func)(int, int, int, int, cloud_type,
+ kill_category),
+ int x, int y, int pow, int spread_rate,
+ cloud_type ctype, kill_category whose )
{
if (!grid_is_solid(grd[x][y]) && env.cgrid[x][y] == EMPTY_CLOUD)
{
- func(x, y, pow, ctype, whose);
+ func(x, y, pow, spread_rate, ctype, whose);
return true;
}
diff --git a/crawl-ref/source/spl-util.h b/crawl-ref/source/spl-util.h
index 4b393ec514..1f3ce8219e 100644
--- a/crawl-ref/source/spl-util.h
+++ b/crawl-ref/source/spl-util.h
@@ -103,7 +103,8 @@ const char* spelltype_short_name( int which_spelltype );
//int spell_restriction(int which_spell, int which_restriction);
-int apply_area_visible(int (*func) (int, int, int, int), int power);
+int apply_area_visible(int (*func) (int, int, int, int), int power,
+ bool pass_through_trans = false);
int apply_area_square(int (*func) (int, int, int, int),
int cx, int cy, int power);
@@ -127,9 +128,10 @@ bool spell_direction( dist &spelld, bolt &pbolt,
bool needs_path = true,
const char *prompt = NULL );
-void apply_area_cloud(int (*func) (int, int, int, cloud_type, kill_category),
+void apply_area_cloud(int (*func) (int, int, int, int, cloud_type,
+ kill_category),
int x, int y, int pow, int number, cloud_type ctype,
- kill_category);
+ kill_category kc, int spread_rate = -1);
const char *spelltype_name(unsigned int which_spelltype);
diff --git a/crawl-ref/source/sqldbm.cc b/crawl-ref/source/sqldbm.cc
index 7a6956f08c..db6c1f0606 100644
--- a/crawl-ref/source/sqldbm.cc
+++ b/crawl-ref/source/sqldbm.cc
@@ -3,7 +3,7 @@
* Summary: dbm wrapper for SQLite
* Written by: Darshan Shaligram
*
- * Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-06-26T17:43:23.491102Z $
+ * Modified for Crawl Reference by $Author$ on $Date$
*/
#include "AppHdr.h"
@@ -15,7 +15,7 @@
SQL_DBM::SQL_DBM(const std::string &dbname, bool do_open)
: error(), errc(SQLITE_OK), db(NULL), s_insert(NULL),
- s_query(NULL), dbfile(dbname)
+ s_query(NULL), s_iterator(NULL), dbfile(dbname)
{
if (do_open && !dbfile.empty())
open();
@@ -95,6 +95,7 @@ void SQL_DBM::close()
sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL);
finalise_query(&s_insert);
finalise_query(&s_query);
+ finalise_query(&s_iterator);
sqlite3_close(db);
db = NULL;
}
@@ -145,12 +146,45 @@ std::string SQL_DBM::query(const std::string &key)
return (res);
}
+std::auto_ptr<std::string> SQL_DBM::firstkey()
+{
+ if (init_iterator() != SQLITE_OK)
+ {
+ std::auto_ptr<std::string> result;
+ return (result);
+ }
+
+ return nextkey();
+}
+
+std::auto_ptr<std::string> SQL_DBM::nextkey()
+{
+ std::auto_ptr<std::string> result;
+ if (s_iterator)
+ {
+ int err = SQLITE_OK;
+ if ((err = ec(sqlite3_step(s_iterator))) == SQLITE_ROW)
+ result.reset(
+ new std::string(
+ (const char *) sqlite3_column_text(s_iterator, 0) ));
+ else
+ sqlite3_reset(s_iterator);
+ }
+ return (result);
+}
+
int SQL_DBM::init_query()
{
return s_query? SQLITE_OK :
prepare_query(&s_query, "SELECT value FROM dbm WHERE key = ?");
}
+int SQL_DBM::init_iterator()
+{
+ return s_iterator? SQLITE_OK :
+ prepare_query(&s_iterator, "SELECT key FROM dbm");
+}
+
int SQL_DBM::finalise_query(sqlite3_stmt **q)
{
if (!*q)
@@ -179,7 +213,7 @@ sql_datum::sql_datum() : dptr(NULL), dsize(0), need_free(false)
}
sql_datum::sql_datum(const std::string &s) : dptr(NULL), dsize(s.length()),
- need_free(false)
+ need_free(false)
{
if ((dptr = new char [dsize]))
{
@@ -269,6 +303,30 @@ sql_datum dbm_fetch(SQL_DBM *db, const sql_datum &key)
return sql_datum(ans);
}
+static sql_datum dbm_key(
+ SQL_DBM *db,
+ std::auto_ptr<std::string> (SQL_DBM::*key)())
+{
+ std::auto_ptr<std::string> res = (db->*key)();
+ if (res.get())
+ return sql_datum(*res.get());
+ else
+ {
+ sql_datum dummy;
+ return dummy;
+ }
+}
+
+sql_datum dbm_firstkey(SQL_DBM *db)
+{
+ return dbm_key(db, &SQL_DBM::firstkey);
+}
+
+sql_datum dbm_nextkey(SQL_DBM *db)
+{
+ return dbm_key(db, &SQL_DBM::nextkey);
+}
+
int dbm_store(SQL_DBM *db, const sql_datum &key, const sql_datum &value, int)
{
int err = db->insert(key.to_str(), value.to_str());
diff --git a/crawl-ref/source/sqldbm.h b/crawl-ref/source/sqldbm.h
index 7cf8faac8a..8a4130cd8c 100644
--- a/crawl-ref/source/sqldbm.h
+++ b/crawl-ref/source/sqldbm.h
@@ -6,6 +6,7 @@
#ifdef USE_SQLITE_DBM
#include <sys/types.h>
+#include <memory>
#if defined(DOS) || defined(WIN32CONSOLE)
#define SQLITE_INT64_TYPE int
@@ -55,6 +56,10 @@ public:
int open(const std::string &db = "");
void close();
+
+ std::auto_ptr<std::string> firstkey();
+ std::auto_ptr<std::string> nextkey();
+
std::string query(const std::string &key);
int insert(const std::string &key, const std::string &value);
@@ -66,6 +71,7 @@ private:
int finalise_query(sqlite3_stmt **query);
int prepare_query(sqlite3_stmt **query, const char *sql);
int init_query();
+ int init_iterator();
int init_insert();
int init_schema();
int ec(int err);
@@ -74,6 +80,7 @@ private:
sqlite3 *db;
sqlite3_stmt *s_insert;
sqlite3_stmt *s_query;
+ sqlite3_stmt *s_iterator;
std::string dbfile;
};
@@ -81,6 +88,8 @@ SQL_DBM *dbm_open(const char *filename, int open_mode, int permissions);
int dbm_close(SQL_DBM *db);
sql_datum dbm_fetch(SQL_DBM *db, const sql_datum &key);
+sql_datum dbm_firstkey(SQL_DBM *db);
+sql_datum dbm_nextkey(SQL_DBM *db);
int dbm_store(SQL_DBM *db, const sql_datum &key,
const sql_datum &value, int overwrite);
diff --git a/crawl-ref/source/stash.cc b/crawl-ref/source/stash.cc
index 962883da9d..b0555abe6a 100644
--- a/crawl-ref/source/stash.cc
+++ b/crawl-ref/source/stash.cc
@@ -24,6 +24,7 @@
#include "menu.h"
#include "message.h"
#include "misc.h"
+#include "notes.h"
#include "overmap.h"
#include "place.h"
#include "shopping.h"
@@ -393,6 +394,7 @@ public:
StashMenu() : InvMenu(MF_SINGLESELECT), can_travel(false)
{
set_type(MT_PICKUP);
+ set_tag("stash"); // override "inventory" tag
}
unsigned char getkey() const;
public:
@@ -563,6 +565,7 @@ void Stash::write(std::ostream &os,
bool identify)
const
{
+ activate_notes(false);
if (!enabled || (items.size() == 0 && verified)) return;
os << "(" << ((int) x - refx) << ", " << ((int) y - refy)
<< (place.length()? ", " + place : "")
@@ -616,6 +619,7 @@ void Stash::write(std::ostream &os,
if (items.size() <= 1 && !verified)
os << " (unseen)" << std::endl;
+ activate_notes(true);
}
void Stash::save(FILE *file) const
@@ -871,6 +875,7 @@ bool ShopInfo::matches_search(const std::string &prefix,
void ShopInfo::write(std::ostream &os, bool identify) const
{
+ activate_notes(false);
os << "[Shop] " << name << std::endl;
if (items.size() > 0)
{
@@ -891,6 +896,7 @@ void ShopInfo::write(std::ostream &os, bool identify) const
os << " (Shop is empty)" << std::endl;
else
os << " (Shop contents are unknown)" << std::endl;
+ activate_notes(true);
}
void ShopInfo::save(FILE *file) const
@@ -1536,6 +1542,7 @@ void StashTracker::display_search_results(
bool travelable = can_travel_interlevel();
StashSearchMenu stashmenu;
+ stashmenu.set_tag("stash");
stashmenu.can_travel = travelable;
std::string title = "match";
diff --git a/crawl-ref/source/state.cc b/crawl-ref/source/state.cc
new file mode 100644
index 0000000000..1d86dc1862
--- /dev/null
+++ b/crawl-ref/source/state.cc
@@ -0,0 +1,367 @@
+/*
+ * File: state.cc
+ * Summary: Game state functions.
+ * Written by: Matthew Cline
+ *
+ * Modified for Crawl Reference by $Author$ on $Date$
+ *
+ * Change History (most recent first):
+ *
+ * <1> 09/18/07 MPC Created
+ */
+
+#include "AppHdr.h"
+#include "externs.h"
+
+#include "delay.h"
+#include "direct.h"
+#include "macro.h"
+#include "menu.h" // For print_formatted_paragraph()
+#include "message.h"
+#include "mon-util.h"
+#include "player.h"
+#include "state.h"
+#include "tutorial.h"
+#include "view.h"
+
+game_state::game_state()
+ : mouse_enabled(false), waiting_for_command(false),
+ terminal_resized(false), io_inited(false), need_save(false),
+ saving_game(false), updating_scores(false), seen_hups(0),
+ map_stat_gen(false), unicode_ok(false), glyph2strfn(NULL),
+ multibyte_strlen(NULL), terminal_resize_handler(NULL),
+ terminal_resize_check(NULL), doing_prev_cmd_again(false),
+ prev_cmd(CMD_NO_CMD), repeat_cmd(CMD_NO_CMD), cmd_repeat_count(0),
+ cmd_repeat_goal(0), prev_repetition_turn(0),
+ cmd_repeat_started_unsafe(false), input_line_curr(0),
+ level_annotation_shown(false)
+{
+ reset_cmd_repeat();
+ reset_cmd_again();
+}
+
+void game_state::add_startup_error(const std::string &err)
+{
+ startup_errors.push_back(err);
+}
+
+void game_state::show_startup_errors()
+{
+ formatted_scroller error_menu;
+ error_menu.set_flags(MF_NOSELECT | MF_ALWAYS_SHOW_MORE | MF_NOWRAP
+ | MF_EASY_EXIT);
+ error_menu.set_more(
+ formatted_string::parse_string(
+ "<cyan>[ + : Page down. - : Page up."
+ " Esc or Enter to continue.]"));
+ error_menu.set_title(
+ new MenuEntry("Warning: Crawl encountered errors during startup:",
+ MEL_TITLE));
+ for (int i = 0, size = startup_errors.size(); i < size; ++i)
+ error_menu.add_entry(new MenuEntry(startup_errors[i]));
+ error_menu.show();
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Repeating commands and doing the previous command over again.
+
+bool game_state::is_replaying_keys() const
+{
+ return (crawl_state.doing_prev_cmd_again
+ || (crawl_state.is_repeating_cmd()
+ && !crawl_state.cmd_repeat_start));
+}
+
+bool game_state::is_repeating_cmd() const
+{
+ ASSERT((cmd_repeat_goal == 0 && cmd_repeat_count == 0
+ && repeat_cmd == CMD_NO_CMD && !cmd_repeat_start)
+ || (cmd_repeat_goal > 0 && cmd_repeat_count <= cmd_repeat_goal
+ && repeat_cmd != CMD_NO_CMD));
+
+ return (repeat_cmd != CMD_NO_CMD);
+}
+
+void game_state::cancel_cmd_repeat(std::string reason)
+{
+ if (!is_repeating_cmd())
+ return;
+
+ if (is_replaying_keys() || cmd_repeat_start)
+ flush_input_buffer(FLUSH_KEY_REPLAY_CANCEL);
+
+ if (is_processing_macro())
+ flush_input_buffer(FLUSH_ABORT_MACRO);
+
+ reset_cmd_repeat();
+
+ if (reason != "")
+ mpr(reason.c_str());
+}
+
+void game_state::cancel_cmd_again(std::string reason)
+{
+ if (!doing_prev_cmd_again)
+ return;
+
+ flush_input_buffer(FLUSH_KEY_REPLAY_CANCEL);
+
+ if (is_processing_macro())
+ flush_input_buffer(FLUSH_ABORT_MACRO);
+
+ reset_cmd_again();
+
+ if (reason != "")
+ mpr(reason.c_str());
+}
+
+void game_state::cant_cmd_repeat(std::string reason)
+{
+ if (reason == "")
+ reason = "Can't repeat that command.";
+
+ cancel_cmd_repeat(reason);
+}
+
+void game_state::cant_cmd_again(std::string reason)
+{
+ if (reason == "")
+ reason = "Can't redo that command.";
+
+ cancel_cmd_again(reason);
+}
+
+// The method is called to prevent the "no repeating zero turns
+// commands" message that input() generates (in the absence of
+// cancelling the repeition) for a repeated command that took no
+// turns. A wrapper around cancel_cmd_repeat(), its only purpose it
+// to make it clear why cancel_cmd_repeat() is being called.
+void game_state::zero_turns_taken()
+{
+ ASSERT(!you.turn_is_over);
+ cancel_cmd_repeat();
+}
+
+bool interrupt_cmd_repeat( activity_interrupt_type ai,
+ const activity_interrupt_data &at )
+{
+ if (crawl_state.cmd_repeat_start)
+ return false;
+
+ if (crawl_state.repeat_cmd == CMD_WIZARD)
+ return false;
+
+ switch (ai)
+ {
+ case AI_STATUE:
+ case AI_HUNGRY:
+ case AI_TELEPORT:
+ case AI_FORCE_INTERRUPT:
+ case AI_HP_LOSS:
+ case AI_MONSTER_ATTACKS:
+ crawl_state.cancel_cmd_repeat("Command repetition interrupted.");
+ return true;
+
+ default:
+ break;
+ }
+
+ if (ai == AI_SEE_MONSTER)
+ {
+ const monsters* mon = static_cast<const monsters*>(at.data);
+ if (!mon->visible())
+ return false;
+
+ if (crawl_state.cmd_repeat_started_unsafe
+ && at.context != "newly seen")
+ {
+ return false;
+ }
+
+ crawl_state.cancel_cmd_repeat();
+
+#ifndef DEBUG_DIAGNOSTICS
+ if (at.context == "newly seen")
+ {
+ std::string text = get_monster_desc(mon, false);
+ text += " comes into view.";
+ print_formatted_paragraph(text, get_number_of_cols(), MSGCH_WARN);
+ }
+
+ if (Options.tutorial_left)
+ {
+ // enforce that this message comes first
+ tutorial_first_monster(*mon);
+ if (get_mons_colour(mon) != mon->colour)
+ learned_something_new(TUT_MONSTER_BRAND);
+ }
+#else
+ formatted_string fs( channel_to_colour(MSGCH_WARN) );
+ fs.cprintf("%s (", mon->name(DESC_PLAIN, true).c_str());
+ fs.add_glyph( mon );
+ fs.cprintf(") in view: (%d,%d), see_grid: %s",
+ mon->x, mon->y,
+ see_grid(mon->x, mon->y)? "yes" : "no");
+ formatted_mpr(fs, MSGCH_WARN);
+#endif
+
+ return true;
+ }
+
+ // If command repitition is being used to immitate the rest command,
+ // then everything interrupts it.
+ if (crawl_state.repeat_cmd == CMD_MOVE_NOWHERE
+ || crawl_state.repeat_cmd == CMD_SEARCH)
+ {
+ if (ai == AI_FULL_MP)
+ crawl_state.cancel_cmd_repeat("Magic restored.");
+ else if (ai == AI_FULL_HP)
+ crawl_state.cancel_cmd_repeat("HP restored.");
+ else
+ crawl_state.cancel_cmd_repeat("Command repetition interrupted.");
+ return true;
+ }
+
+ if (crawl_state.cmd_repeat_started_unsafe)
+ return false;
+
+ if (ai == AI_HIT_MONSTER)
+ {
+ // This check is for when command repetition is used to
+ // whack away at a 0xp monster, since the player feels safe
+ // when the only monsters around are 0xp.
+ const monsters* mon = static_cast<const monsters*>(at.data);
+
+ if (mons_class_flag(mon->type, M_NO_EXP_GAIN)
+ && player_monster_visible(mon))
+ {
+ return false;
+ }
+
+ crawl_state.cancel_cmd_repeat("Command repetition interrupted.");
+ return true;
+ }
+
+ return false;
+}
+
+void game_state::reset_cmd_repeat()
+{
+ repeat_cmd = CMD_NO_CMD;
+ cmd_repeat_count = 0;
+ cmd_repeat_goal = 0;
+ cmd_repeat_start = false;
+ prev_repetition_turn = 0;
+
+ repeat_cmd_keys.clear();
+}
+
+void game_state::reset_cmd_again()
+{
+ doing_prev_cmd_again = false;
+ prev_cmd = CMD_NO_CMD;
+
+ prev_cmd_keys.clear();
+}
+
+///////////////////////////////////////////////////////////
+// Keeping track of which god is currently doing something
+///////////////////////////////////////////////////////////
+
+god_act_state::god_act_state()
+{
+ reset();
+}
+
+void god_act_state::reset()
+{
+ which_god = GOD_NO_GOD;
+ retribution = false;
+ depth = 0;
+}
+
+bool game_state::is_god_acting() const
+{
+ ASSERT(god_act.depth >= 0);
+ ASSERT(!(god_act.depth > 0 && god_act.which_god == GOD_NO_GOD));
+ ASSERT(!(god_act.depth == 0 && god_act.which_god != GOD_NO_GOD));
+ ASSERT(!(god_act.depth == 0 && god_act_stack.size() > 0));
+
+ return (god_act.depth > 0);
+}
+
+bool game_state::is_god_retribution() const
+{
+ ASSERT(is_god_acting());
+
+ return (god_act.retribution);
+}
+
+god_type game_state::which_god_acting() const
+{
+ return god_act.which_god;
+}
+
+void game_state::inc_god_acting(bool is_retribution)
+{
+ inc_god_acting(you.religion, is_retribution);
+}
+
+void game_state::inc_god_acting(god_type which_god, bool is_retribution)
+{
+ ASSERT(which_god != GOD_NO_GOD);
+
+ if (god_act.which_god != GOD_NO_GOD &&
+ god_act.which_god != which_god)
+ {
+ ASSERT(god_act.depth >= 1);
+
+ god_act_stack.push_back(god_act);
+ god_act.reset();
+ }
+
+ god_act.which_god = which_god;
+ god_act.retribution = is_retribution || god_act.retribution;
+ god_act.depth++;
+}
+
+void game_state::dec_god_acting()
+{
+ dec_god_acting(you.religion);
+}
+
+void game_state::dec_god_acting(god_type which_god)
+{
+ ASSERT(which_god != GOD_NO_GOD);
+ ASSERT(god_act.depth > 0);
+ ASSERT(god_act.which_god == which_god);
+
+ god_act.depth--;
+
+ if (god_act.depth == 0)
+ {
+ god_act.reset();
+ if (god_act_stack.size() > 0)
+ {
+ god_act = god_act_stack[god_act_stack.size() - 1];
+ god_act_stack.pop_back();
+ ASSERT(god_act.depth >= 1);
+ ASSERT(god_act.which_god != GOD_NO_GOD);
+ ASSERT(god_act.which_god != which_god);
+ }
+ }
+}
+
+void game_state::clear_god_acting()
+{
+ ASSERT(!is_god_acting());
+ ASSERT(god_act_stack.size() == 0);
+
+ god_act.reset();
+}
+
+std::vector<god_act_state> game_state::other_gods_acting() const
+{
+ ASSERT(is_god_acting());
+ return god_act_stack;
+}
diff --git a/crawl-ref/source/state.h b/crawl-ref/source/state.h
index 2be86b8a76..cd572ed865 100644
--- a/crawl-ref/source/state.h
+++ b/crawl-ref/source/state.h
@@ -13,6 +13,21 @@
#ifndef STATE_H
#define STATE_H
+#include "enum.h"
+#include <vector>
+
+struct god_act_state
+{
+public:
+
+ god_act_state();
+ void reset();
+
+ god_type which_god;
+ bool retribution;
+ int depth;
+};
+
// Track various aspects of Crawl game state.
struct game_state
{
@@ -38,21 +53,90 @@ struct game_state
void (*terminal_resize_handler)();
void (*terminal_resize_check)();
- game_state() : mouse_enabled(false), waiting_for_command(false),
- terminal_resized(false), io_inited(false), need_save(false),
- saving_game(false), updating_scores(false),
- seen_hups(0), map_stat_gen(false), unicode_ok(false),
- glyph2strfn(NULL), multibyte_strlen(NULL),
- terminal_resize_handler(NULL), terminal_resize_check(NULL)
- {
- }
+ bool doing_prev_cmd_again;
+ command_type prev_cmd;
+ std::deque<int> prev_cmd_keys;
+
+ command_type repeat_cmd;
+ std::deque<int> repeat_cmd_keys;
+ bool cmd_repeat_start;
+ int cmd_repeat_count;
+ int cmd_repeat_goal;
+ int prev_cmd_repeat_goal;
+ int prev_repetition_turn;
+ bool cmd_repeat_started_unsafe;
+
+ std::vector<std::string> startup_errors;
+
+ std::vector<std::string> input_line_strs;
+ unsigned int input_line_curr;
+
+ bool level_annotation_shown;
+
+protected:
+ void reset_cmd_repeat();
+ void reset_cmd_again();
+
+ god_act_state god_act;
+ std::vector<god_act_state> god_act_stack;
+
+public:
+ game_state();
+
+ void add_startup_error(const std::string &error);
+ void show_startup_errors();
+
+ bool is_replaying_keys() const;
+
+ bool is_repeating_cmd() const;
+
+ void cancel_cmd_repeat(std::string reason = "");
+ void cancel_cmd_again(std::string reason = "");
+
+ void cant_cmd_repeat(std::string reason = "");
+ void cant_cmd_again(std::string reason = "");
+
+ void zero_turns_taken();
void check_term_size() const
{
if (terminal_resize_check)
(*terminal_resize_check)();
}
+
+ bool is_god_acting() const;
+ bool is_god_retribution() const;
+ god_type which_god_acting() const;
+ void inc_god_acting(bool is_retribution = false);
+ void inc_god_acting(god_type which_god, bool is_retribution = false);
+ void dec_god_acting();
+ void dec_god_acting(god_type which_god);
+ void clear_god_acting();
+
+ std::vector<god_act_state> other_gods_acting() const;
};
+
extern game_state crawl_state;
+class god_acting
+{
+public:
+ god_acting(bool is_retribution = false)
+ : god(you.religion)
+ {
+ crawl_state.inc_god_acting(god, is_retribution);
+ }
+ god_acting(god_type who, bool is_retribution = false)
+ : god(who)
+ {
+ crawl_state.inc_god_acting(god, is_retribution);
+ }
+ ~god_acting()
+ {
+ crawl_state.dec_god_acting(god);
+ }
+private:
+ god_type god;
+};
+
#endif
diff --git a/crawl-ref/source/store.cc b/crawl-ref/source/store.cc
new file mode 100644
index 0000000000..0ffa96e194
--- /dev/null
+++ b/crawl-ref/source/store.cc
@@ -0,0 +1,1624 @@
+/*
+ * File: store.cc
+ * Summary: Saveable hash-table and vector capable of storing
+ * multiple types of data.
+ * Written by: Matthew Cline
+ *
+ * Modified for Crawl Reference by $Author$ on $Date$
+ *
+ * Change History (most recent first):
+
+ * <1> 10/5/07 MPC Created
+ */
+
+#include "AppHdr.h"
+#include "store.h"
+
+#include "externs.h"
+#include "tags.h"
+
+CrawlStoreValue::CrawlStoreValue()
+ : type(SV_NONE), flags(SFLAG_UNSET)
+{
+ val.ptr = NULL;
+}
+
+CrawlStoreValue::CrawlStoreValue(const CrawlStoreValue &other)
+{
+ ASSERT(other.type >= SV_NONE && other.type < NUM_STORE_VAL_TYPES);
+
+ type = other.type;
+ flags = other.flags;
+
+ if (flags & SFLAG_UNSET)
+ {
+ val = other.val;
+ return;
+ }
+
+ switch (type)
+ {
+ case SV_NONE:
+ case SV_BOOL:
+ case SV_BYTE:
+ case SV_SHORT:
+ case SV_LONG:
+ case SV_FLOAT:
+ val = other.val;
+ break;
+
+ case SV_STR:
+ {
+ std::string* str;
+ str = new std::string(*static_cast<std::string*>(other.val.ptr));
+ val.ptr = static_cast<void*>(str);
+ break;
+ }
+
+ case SV_COORD:
+ {
+ coord_def* coord;
+ coord = new coord_def(*static_cast<coord_def*>(other.val.ptr));
+ val.ptr = static_cast<void*>(coord);
+ break;
+ }
+
+ case SV_ITEM:
+ {
+ item_def* item;
+ item = new item_def(*static_cast<item_def*>(other.val.ptr));
+ val.ptr = static_cast<void*>(item);
+ break;
+ }
+
+ case SV_HASH:
+ {
+ CrawlHashTable* hash;
+ CrawlHashTable* tmp = static_cast<CrawlHashTable*>(other.val.ptr);
+ hash = new CrawlHashTable(*tmp);
+ val.ptr = static_cast<void*>(hash);
+ break;
+ }
+
+ case SV_VEC:
+ {
+ CrawlVector* vec;
+ CrawlVector* tmp = static_cast<CrawlVector*>(other.val.ptr);
+ vec = new CrawlVector(*tmp);
+ val.ptr = static_cast<void*>(vec);
+ break;
+ }
+
+ case NUM_STORE_VAL_TYPES:
+ ASSERT(false);
+ }
+}
+
+CrawlStoreValue::CrawlStoreValue(const store_flags _flags,
+ const store_val_type _type)
+ : type(_type), flags(_flags)
+{
+ ASSERT(type >= SV_NONE && type < NUM_STORE_VAL_TYPES);
+ ASSERT(!(flags & SFLAG_UNSET));
+
+ flags |= SFLAG_UNSET;
+ val.ptr = NULL;
+}
+
+// Conversion constructors
+CrawlStoreValue::CrawlStoreValue(const bool _val)
+ : type(SV_BOOL), flags(0)
+{
+ get_bool() = _val;
+}
+
+CrawlStoreValue::CrawlStoreValue(const char &_val)
+ : type(SV_BYTE), flags(0)
+{
+ get_byte() = _val;
+}
+
+CrawlStoreValue::CrawlStoreValue(const short &_val)
+ : type(SV_SHORT), flags(0)
+{
+ get_short() = _val;
+}
+
+CrawlStoreValue::CrawlStoreValue(const long &_val)
+ : type(SV_LONG), flags(0)
+{
+ get_long() = _val;
+}
+
+CrawlStoreValue::CrawlStoreValue(const float &_val)
+ : type(SV_FLOAT), flags(0)
+{
+ get_float() = _val;
+}
+
+CrawlStoreValue::CrawlStoreValue(const std::string &_val)
+ : type(SV_STR), flags(0)
+{
+ get_string() = _val;
+}
+
+CrawlStoreValue::CrawlStoreValue(const char* _val)
+ : type(SV_STR), flags(0)
+{
+ get_string() = _val;
+}
+
+CrawlStoreValue::CrawlStoreValue(const coord_def &_val)
+ : type(SV_COORD), flags(0)
+{
+ get_coord() = _val;
+}
+
+CrawlStoreValue::CrawlStoreValue(const item_def &_val)
+ : type(SV_ITEM), flags(0)
+{
+ get_item() = _val;
+}
+
+CrawlStoreValue::CrawlStoreValue(const CrawlHashTable &_val)
+ : type(SV_HASH), flags(0)
+{
+ get_table() = _val;
+}
+
+CrawlStoreValue::CrawlStoreValue(const CrawlVector &_val)
+ : type(SV_VEC), flags(0)
+{
+ get_vector() = _val;
+}
+
+CrawlStoreValue::~CrawlStoreValue()
+{
+ unset(true);
+}
+
+void CrawlStoreValue::unset(bool force)
+{
+ if (flags & SFLAG_UNSET)
+ return;
+
+ if (force)
+ flags &= ~SFLAG_NO_ERASE;
+
+ ASSERT(!(flags & SFLAG_NO_ERASE));
+
+ switch (type)
+ {
+ case SV_BOOL:
+ val.boolean = false;
+ break;
+
+ case SV_BYTE:
+ val.byte = 0;
+ break;
+
+ case SV_SHORT:
+ val._short = 0;
+ break;
+
+ case SV_LONG:
+ val._long = 0;
+ break;
+
+ case SV_FLOAT:
+ val._float = 0.0;
+ break;
+
+ case SV_STR:
+ {
+ std::string* str = static_cast<std::string*>(val.ptr);
+ delete str;
+ val.ptr = NULL;
+ break;
+ }
+
+ case SV_COORD:
+ {
+ coord_def* coord = static_cast<coord_def*>(val.ptr);
+ delete coord;
+ val.ptr = NULL;
+ break;
+ }
+
+ case SV_ITEM:
+ {
+ item_def* item = static_cast<item_def*>(val.ptr);
+ delete item;
+ val.ptr = NULL;
+ break;
+ }
+
+ case SV_HASH:
+ {
+ CrawlHashTable* hash = static_cast<CrawlHashTable*>(val.ptr);
+ delete hash;
+ val.ptr = NULL;
+ break;
+ }
+
+ case SV_VEC:
+ {
+ CrawlVector* vec = static_cast<CrawlVector*>(val.ptr);
+ delete vec;
+ val.ptr = NULL;
+ break;
+ }
+
+ case SV_NONE:
+ ASSERT(false);
+
+ case NUM_STORE_VAL_TYPES:
+ ASSERT(false);
+ }
+
+ flags |= SFLAG_UNSET;
+}
+
+// Only needed to do some assertion checking.
+CrawlStoreValue &CrawlStoreValue::operator = (const CrawlStoreValue &other)
+{
+ ASSERT(other.type >= SV_NONE && other.type < NUM_STORE_VAL_TYPES);
+ ASSERT(other.type != SV_NONE || type == SV_NONE);
+
+ // NOTE: We don't bother checking SFLAG_CONST_VAL, since the
+ // asignment operator is used when swapping two elements.
+
+ if (!(flags & SFLAG_UNSET))
+ {
+ if (flags & SFLAG_CONST_TYPE)
+ ASSERT(type == SV_NONE || type == other.type);
+ }
+
+ type = other.type;
+ flags = other.flags;
+ val = other.val;
+
+ return (*this);
+}
+
+///////////////////////////////////
+// Meta-data accessors and changers
+store_flags CrawlStoreValue::get_flags() const
+{
+ return flags;
+}
+
+store_flags CrawlStoreValue::set_flags(store_flags _flags)
+{
+ flags |= _flags;
+ return flags;
+}
+
+store_flags CrawlStoreValue::unset_flags(store_flags _flags)
+{
+ flags &= ~_flags;
+ return flags;
+}
+
+store_val_type CrawlStoreValue::get_type() const
+{
+ return type;
+}
+
+//////////////////////////////
+// Read/write from/to savefile
+void CrawlStoreValue::write(tagHeader &th) const
+{
+ ASSERT(!(flags & SFLAG_UNSET));
+
+ marshallByte(th, (char) type);
+ marshallByte(th, (char) flags);
+
+ switch (type)
+ {
+ case SV_BOOL:
+ marshallBoolean(th, val.boolean);
+ break;
+
+ case SV_BYTE:
+ marshallByte(th, val.byte);
+ break;
+
+ case SV_SHORT:
+ marshallShort(th, val._short);
+ break;
+
+ case SV_LONG:
+ marshallLong(th, val._long);
+ break;
+
+ case SV_FLOAT:
+ marshallFloat(th, val._float);
+ break;
+
+ case SV_STR:
+ {
+ std::string* str = static_cast<std::string*>(val.ptr);
+ marshallString(th, *str);
+ break;
+ }
+
+ case SV_COORD:
+ {
+ coord_def* coord = static_cast<coord_def*>(val.ptr);
+ marshallCoord(th, *coord);
+ break;
+ }
+
+ case SV_ITEM:
+ {
+ item_def* item = static_cast<item_def*>(val.ptr);
+ marshallItem(th, *item);
+ break;
+ }
+
+ case SV_HASH:
+ {
+ CrawlHashTable* hash = static_cast<CrawlHashTable*>(val.ptr);
+ hash->write(th);
+ break;
+ }
+
+ case SV_VEC:
+ {
+ CrawlVector* vec = static_cast<CrawlVector*>(val.ptr);
+ vec->write(th);
+ break;
+ }
+
+ case SV_NONE:
+ ASSERT(false);
+
+ case NUM_STORE_VAL_TYPES:
+ ASSERT(false);
+ }
+}
+
+void CrawlStoreValue::read(tagHeader &th)
+{
+ type = static_cast<store_val_type>(unmarshallByte(th));
+ flags = (store_flags) unmarshallByte(th);
+
+ ASSERT(!(flags & SFLAG_UNSET));
+
+ switch (type)
+ {
+ case SV_BOOL:
+ val.boolean = unmarshallBoolean(th);
+ break;
+
+ case SV_BYTE:
+ val.byte = unmarshallByte(th);
+ break;
+
+ case SV_SHORT:
+ val._short = unmarshallShort(th);
+ break;
+
+ case SV_LONG:
+ val._long = unmarshallLong(th);
+ break;
+
+ case SV_FLOAT:
+ val._float = unmarshallFloat(th);
+ break;
+
+ case SV_STR:
+ {
+ std::string str = unmarshallString(th);
+ val.ptr = (void*) new std::string(str);
+ break;
+ }
+
+ case SV_COORD:
+ {
+ coord_def coord;
+ unmarshallCoord(th, coord);
+ val.ptr = (void*) new coord_def(coord);
+
+ break;
+ }
+
+ case SV_ITEM:
+ {
+ item_def item;
+ unmarshallItem(th, item);
+ val.ptr = (void*) new item_def(item);
+
+ break;
+ }
+
+ case SV_HASH:
+ {
+ CrawlHashTable* hash = new CrawlHashTable();
+ hash->read(th);
+ val.ptr = (void*) hash;
+
+ break;
+ }
+
+ case SV_VEC:
+ {
+ CrawlVector* vec = new CrawlVector();
+ vec->read(th);
+ val.ptr = (void*) vec;
+
+ break;
+ }
+
+ case SV_NONE:
+ ASSERT(false);
+
+ case NUM_STORE_VAL_TYPES:
+ ASSERT(false);
+ }
+}
+
+////////////////////////////////////////////////////////////////
+// Setup a new table with the given flags and/or type; assert if
+// a table already exists.
+CrawlHashTable &CrawlStoreValue::new_table(store_flags _flags)
+{
+ return new_table(SV_NONE, flags);
+}
+
+CrawlHashTable &CrawlStoreValue::new_table(store_val_type _type,
+ store_flags _flags)
+{
+#if DEBUG
+ CrawlHashTable* old_table = static_cast<CrawlHashTable*>(val.ptr);
+
+ ASSERT(flags & SFLAG_UNSET);
+ ASSERT(type == SV_NONE
+ || (type == SV_HASH
+ && old_table->size() == 0
+ && old_table->get_type() == SV_NONE
+ && old_table->get_default_flags() == 0));
+#endif
+
+ CrawlHashTable &table = get_table();
+
+ table.default_flags = _flags;
+ table.type = _type;
+
+ type = SV_HASH;
+ flags &= ~SFLAG_UNSET;
+
+ return table;
+}
+
+////////////////////////////////////////////////////////////////
+// Setup a new vector with the given flags and/or type; assert if
+// a vector already exists.
+CrawlVector &CrawlStoreValue::new_vector(store_flags _flags,
+ vec_size max_size)
+{
+ return new_vector(SV_NONE, flags, max_size);
+}
+
+CrawlVector &CrawlStoreValue::new_vector(store_val_type _type,
+ store_flags _flags,
+ vec_size _max_size)
+{
+#if DEBUG
+ CrawlVector* old_vector = static_cast<CrawlVector*>(val.ptr);
+
+ ASSERT(flags & SFLAG_UNSET);
+ ASSERT(type == SV_NONE
+ || (type == SV_VEC
+ && old_vector->size() == 0
+ && old_vector->get_type() == SV_NONE
+ && old_vector->get_default_flags() == 0
+ && old_vector->get_max_size() == VEC_MAX_SIZE));
+#endif
+
+ CrawlVector &vector = get_vector();
+
+ vector.default_flags = _flags;
+ vector.type = _type;
+
+ type = SV_VEC;
+ flags &= ~SFLAG_UNSET;
+
+ return vector;
+}
+
+///////////////////////////////////////////
+// Dynamic type-checking accessor functions
+#define GET_VAL(x, _type, field, value) \
+ ASSERT((flags & SFLAG_UNSET) || !(flags & SFLAG_CONST_VAL)); \
+ if (type != (x)) \
+ { \
+ if (type == SV_NONE) \
+ { \
+ type = (x); \
+ field = (value); \
+ } \
+ else \
+ { \
+ ASSERT(!(flags & SFLAG_CONST_TYPE)); \
+ switch(type) \
+ { \
+ case SV_BOOL: \
+ field = (_type) val.boolean; \
+ break; \
+ case SV_BYTE: \
+ field = (_type) val.byte; \
+ break; \
+ case SV_SHORT: \
+ field = (_type) val._short; \
+ break; \
+ case SV_LONG: \
+ field = (_type) val._long; \
+ break; \
+ case SV_FLOAT: \
+ field = (_type) val._float; \
+ break; \
+ default: \
+ ASSERT(false); \
+ } \
+ type = (x); \
+ } \
+ } \
+ flags &= ~SFLAG_UNSET; \
+ return field;
+
+#define GET_VAL_PTR(x, _type, value) \
+ ASSERT((flags & SFLAG_UNSET) || !(flags & SFLAG_CONST_VAL)); \
+ if (type != (x)) \
+ { \
+ if (type == SV_NONE) \
+ { \
+ type = (x); \
+ val.ptr = (value); \
+ } \
+ else \
+ { \
+ unset(); \
+ val.ptr = (value); \
+ type = (x); \
+ } \
+ } \
+ flags &= ~SFLAG_UNSET; \
+ return *((_type) val.ptr);
+
+bool &CrawlStoreValue::get_bool()
+{
+ GET_VAL(SV_BOOL, bool, val.boolean, false);
+}
+
+char &CrawlStoreValue::get_byte()
+{
+ GET_VAL(SV_BYTE, char, val.byte, 0);
+}
+
+short &CrawlStoreValue::get_short()
+{
+ GET_VAL(SV_SHORT, short, val._short, 0);
+}
+
+long &CrawlStoreValue::get_long()
+{
+ GET_VAL(SV_LONG, long, val._long, 0);
+}
+
+float &CrawlStoreValue::get_float()
+{
+ GET_VAL(SV_FLOAT, float, val._float, 0.0);
+}
+
+std::string &CrawlStoreValue::get_string()
+{
+ GET_VAL_PTR(SV_STR, std::string*, new std::string(""));
+}
+
+coord_def &CrawlStoreValue::get_coord()
+{
+ GET_VAL_PTR(SV_COORD, coord_def*, new coord_def());
+}
+
+item_def &CrawlStoreValue::get_item()
+{
+ GET_VAL_PTR(SV_ITEM, item_def*, new item_def());
+}
+
+CrawlHashTable &CrawlStoreValue::get_table()
+{
+ GET_VAL_PTR(SV_HASH, CrawlHashTable*, new CrawlHashTable());
+}
+
+CrawlVector &CrawlStoreValue::get_vector()
+{
+ GET_VAL_PTR(SV_VEC, CrawlVector*, new CrawlVector());
+}
+
+CrawlStoreValue &CrawlStoreValue::operator [] (const std::string &key)
+{
+ return get_table()[key];
+}
+
+CrawlStoreValue &CrawlStoreValue::operator [] (const vec_size &index)
+{
+ return get_vector()[index];
+}
+
+///////////////////////////
+// Const accessor functions
+#define GET_CONST_SETUP(x) \
+ ASSERT(!(flags & SFLAG_UNSET)); \
+ ASSERT(type == (x));
+
+bool CrawlStoreValue::get_bool() const
+{
+ GET_CONST_SETUP(SV_BOOL);
+ return val.boolean;
+}
+
+char CrawlStoreValue::get_byte() const
+{
+ GET_CONST_SETUP(SV_BYTE);
+ return val.byte;
+}
+
+short CrawlStoreValue::get_short() const
+{
+ GET_CONST_SETUP(SV_SHORT);
+ return val._short;
+}
+
+long CrawlStoreValue::get_long() const
+{
+ GET_CONST_SETUP(SV_LONG);
+ return val._long;
+}
+
+float CrawlStoreValue::get_float() const
+{
+ GET_CONST_SETUP(SV_FLOAT);
+ return val._float;
+}
+
+std::string CrawlStoreValue::get_string() const
+{
+ GET_CONST_SETUP(SV_STR);
+ return *((std::string*)val.ptr);
+}
+
+coord_def CrawlStoreValue::get_coord() const
+{
+ GET_CONST_SETUP(SV_COORD);
+ return *((coord_def*)val.ptr);
+}
+
+const item_def& CrawlStoreValue::get_item() const
+{
+ GET_CONST_SETUP(SV_ITEM);
+ return *((item_def*)val.ptr);
+}
+
+const CrawlHashTable& CrawlStoreValue::get_table() const
+{
+ GET_CONST_SETUP(SV_HASH);
+ return *((CrawlHashTable*)val.ptr);
+}
+
+const CrawlVector& CrawlStoreValue::get_vector() const
+{
+ GET_CONST_SETUP(SV_VEC);
+ return *((CrawlVector*)val.ptr);
+}
+
+const CrawlStoreValue &CrawlStoreValue::operator
+ [] (const std::string &key) const
+{
+ return get_table()[key];
+}
+
+const CrawlStoreValue &CrawlStoreValue::operator
+ [](const vec_size &index) const
+{
+ return get_vector()[index];
+}
+
+/////////////////////
+// Typecast operators
+&CrawlStoreValue::operator bool()
+{
+ return get_bool();
+}
+
+&CrawlStoreValue::operator char()
+{
+ return get_byte();
+}
+
+&CrawlStoreValue::operator short()
+{
+ return get_short();
+}
+
+&CrawlStoreValue::operator float()
+{
+ return get_float();
+}
+
+&CrawlStoreValue::operator long()
+{
+ return get_long();
+}
+
+&CrawlStoreValue::operator std::string()
+{
+ return get_string();
+}
+
+&CrawlStoreValue::operator coord_def()
+{
+ return get_coord();
+}
+
+&CrawlStoreValue::operator CrawlHashTable()
+{
+ return get_table();
+}
+
+&CrawlStoreValue::operator CrawlVector()
+{
+ return get_vector();
+}
+
+&CrawlStoreValue::operator item_def()
+{
+ return get_item();
+}
+
+///////////////////////////
+// Const typecast operators
+CrawlStoreValue::operator bool() const
+{
+ return get_bool();
+}
+
+#define CONST_INT_CAST() \
+ switch(type) \
+ { \
+ case SV_BYTE: \
+ return get_byte(); \
+ case SV_SHORT: \
+ return get_short(); \
+ case SV_LONG: \
+ return get_long(); \
+ default: \
+ ASSERT(false); \
+ return 0; \
+ }
+
+CrawlStoreValue::operator char() const
+{
+ CONST_INT_CAST();
+}
+
+CrawlStoreValue::operator short() const
+{
+ CONST_INT_CAST();
+}
+
+CrawlStoreValue::operator long() const
+{
+ CONST_INT_CAST();
+}
+
+CrawlStoreValue::operator float() const
+{
+ return get_float();
+}
+
+CrawlStoreValue::operator std::string() const
+{
+ return get_string();
+}
+
+CrawlStoreValue::operator coord_def() const
+{
+ return get_coord();
+}
+
+///////////////////////
+// Assignment operators
+CrawlStoreValue &CrawlStoreValue::operator = (const bool &_val)
+{
+ get_bool() = _val;
+ return (*this);
+}
+
+CrawlStoreValue &CrawlStoreValue::operator = (const char &_val)
+{
+ get_byte() = _val;
+ return (*this);
+}
+
+CrawlStoreValue &CrawlStoreValue::operator = (const short &_val)
+{
+ get_short() = _val;
+ return (*this);
+}
+
+CrawlStoreValue &CrawlStoreValue::operator = (const long &_val)
+{
+ get_long() = _val;
+ return (*this);
+}
+
+CrawlStoreValue &CrawlStoreValue::operator = (const float &_val)
+{
+ get_float() = _val;
+ return (*this);
+}
+
+CrawlStoreValue &CrawlStoreValue::operator = (const std::string &_val)
+{
+ get_string() = _val;
+ return (*this);
+}
+
+CrawlStoreValue &CrawlStoreValue::operator = (const char* _val)
+{
+ get_string() = _val;
+ return (*this);
+}
+
+CrawlStoreValue &CrawlStoreValue::operator = (const coord_def &_val)
+{
+ get_coord() = _val;
+ return (*this);
+}
+
+CrawlStoreValue &CrawlStoreValue::operator = (const CrawlHashTable &_val)
+{
+ get_table() = _val;
+ return (*this);
+}
+
+CrawlStoreValue &CrawlStoreValue::operator = (const CrawlVector &_val)
+{
+ get_vector() = _val;
+ return (*this);
+}
+
+CrawlStoreValue &CrawlStoreValue::operator = (const item_def &_val)
+{
+ get_item() = _val;
+ return (*this);
+}
+
+///////////////////////////////////////////////////
+// Non-assignment operators which affect the lvalue
+#define INT_OPERATOR_UNARY(op) \
+ switch(type) \
+ { \
+ case SV_BYTE: \
+ { \
+ char &temp = get_byte(); \
+ temp op; \
+ return temp; \
+ } \
+ \
+ case SV_SHORT: \
+ { \
+ short &temp = get_short(); \
+ temp op; \
+ return temp; \
+ } \
+ case SV_LONG: \
+ { \
+ long &temp = get_long(); \
+ temp op; \
+ return temp; \
+ } \
+ \
+ default: \
+ ASSERT(false); \
+ return 0; \
+ }
+
+// Prefix
+long CrawlStoreValue::operator ++ ()
+{
+ INT_OPERATOR_UNARY(++);
+}
+
+long CrawlStoreValue::operator -- ()
+{
+ INT_OPERATOR_UNARY(--);
+}
+
+// Postfix
+long CrawlStoreValue::operator ++ (int)
+{
+ INT_OPERATOR_UNARY(++);
+}
+
+long CrawlStoreValue::operator -- (int)
+{
+ INT_OPERATOR_UNARY(--);
+}
+
+std::string &CrawlStoreValue::operator += (const std::string &_val)
+{
+ return (get_string() += _val);
+}
+
+////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////
+
+CrawlHashTable::CrawlHashTable()
+ : type(SV_NONE), default_flags(0)
+{
+}
+
+CrawlHashTable::CrawlHashTable(store_flags flags)
+ : type(SV_NONE), default_flags(flags)
+{
+ ASSERT(!(default_flags & SFLAG_UNSET));
+}
+
+CrawlHashTable::CrawlHashTable(store_val_type _type, store_flags flags)
+ : type(_type), default_flags(flags)
+{
+ ASSERT(type >= SV_NONE && type < NUM_STORE_VAL_TYPES);
+ ASSERT(!(default_flags & SFLAG_UNSET));
+}
+
+CrawlHashTable::~CrawlHashTable()
+{
+ assert_validity();
+}
+
+//////////////////////////////
+// Read/write from/to savefile
+void CrawlHashTable::write(tagHeader &th) const
+{
+ assert_validity();
+ if (empty())
+ {
+ marshallByte(th, 0);
+ return;
+ }
+
+ marshallByte(th, size());
+ marshallByte(th, static_cast<char>(type));
+ marshallByte(th, (char) default_flags);
+
+ CrawlHashTable::hash_map_type::const_iterator i = hash_map.begin();
+
+ for (; i != hash_map.end(); i++)
+ {
+ marshallString(th, i->first);
+ i->second.write(th);
+ }
+
+ assert_validity();
+}
+
+void CrawlHashTable::read(tagHeader &th)
+{
+ assert_validity();
+
+ ASSERT(empty());
+ ASSERT(type == SV_NONE);
+ ASSERT(default_flags == 0);
+
+ hash_size _size = (hash_size) unmarshallByte(th);
+
+ if (_size == 0)
+ return;
+
+ type = static_cast<store_val_type>(unmarshallByte(th));
+ default_flags = (store_flags) unmarshallByte(th);
+
+ for (hash_size i = 0; i < _size; i++)
+ {
+ std::string key = unmarshallString(th);
+ CrawlStoreValue &val = (*this)[key];
+
+ val.read(th);
+ }
+
+ assert_validity();
+}
+
+
+//////////////////
+// Misc functions
+
+store_flags CrawlHashTable::get_default_flags() const
+{
+ assert_validity();
+ return default_flags;
+}
+
+store_flags CrawlHashTable::set_default_flags(store_flags flags)
+{
+ assert_validity();
+ ASSERT(!(flags & SFLAG_UNSET));
+ default_flags |= flags;
+
+ return default_flags;
+}
+
+store_flags CrawlHashTable::unset_default_flags(store_flags flags)
+{
+ assert_validity();
+ ASSERT(!(flags & SFLAG_UNSET));
+ default_flags &= ~flags;
+
+ return default_flags;
+}
+
+store_val_type CrawlHashTable::get_type() const
+{
+ assert_validity();
+ return type;
+}
+
+bool CrawlHashTable::exists(const std::string key) const
+{
+ assert_validity();
+ hash_map_type::const_iterator i = hash_map.find(key);
+
+ return (i != hash_map.end());
+}
+
+void CrawlHashTable::assert_validity() const
+{
+#if DEBUG
+ ASSERT(!(default_flags & SFLAG_UNSET));
+
+ hash_map_type::const_iterator i = hash_map.begin();
+
+ unsigned long actual_size = 0;
+
+ for (; i != hash_map.end(); i++)
+ {
+ actual_size++;
+
+ const std::string &key = i->first;
+ const CrawlStoreValue &val = i->second;
+
+ ASSERT(key != "");
+ std::string trimmed = trimmed_string(key);
+ ASSERT(key == trimmed);
+
+ ASSERT(val.type != SV_NONE);
+ ASSERT(!(val.flags & SFLAG_UNSET));
+
+ switch(val.type)
+ {
+ case SV_STR:
+ case SV_COORD:
+ case SV_ITEM:
+ ASSERT(val.val.ptr != NULL);
+ break;
+
+ case SV_HASH:
+ {
+ ASSERT(val.val.ptr != NULL);
+
+ CrawlHashTable* nested;
+ nested = static_cast<CrawlHashTable*>(val.val.ptr);
+
+ nested->assert_validity();
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+
+ ASSERT(size() == actual_size);
+#endif
+}
+
+////////////////////////////////
+// Accessors to contained values
+
+CrawlStoreValue& CrawlHashTable::get_value(const std::string &key)
+{
+ assert_validity();
+ iterator i = hash_map.find(key);
+
+ if (i == hash_map.end())
+ {
+ hash_map[key] = CrawlStoreValue(default_flags);
+ CrawlStoreValue &val = hash_map[key];
+
+ if (type != SV_NONE)
+ {
+ val.type = type;
+ val.flags |= SFLAG_CONST_TYPE;
+ }
+
+ return (val);
+ }
+
+ return (i->second);
+}
+
+const CrawlStoreValue& CrawlHashTable::get_value(const std::string &key) const
+{
+ assert_validity();
+ hash_map_type::const_iterator i = hash_map.find(key);
+
+ ASSERT(i != hash_map.end());
+ ASSERT(i->second.type != SV_NONE);
+ ASSERT(!(i->second.flags & SFLAG_UNSET));
+
+ return (i->second);
+}
+
+CrawlStoreValue& CrawlHashTable::operator[] (const std::string &key)
+{
+ return get_value(key);
+}
+
+const CrawlStoreValue& CrawlHashTable::operator[] (const std::string &key)
+ const
+{
+ return get_value(key);
+}
+
+///////////////////////////
+// std::map style interface
+hash_size CrawlHashTable::size() const
+{
+ return hash_map.size();
+}
+
+bool CrawlHashTable::empty() const
+{
+ return hash_map.empty();
+}
+
+void CrawlHashTable::erase(const std::string key)
+{
+ assert_validity();
+ iterator i = hash_map.find(key);
+
+ if (i != hash_map.end())
+ {
+#if DEBUG
+ CrawlStoreValue &val = i->second;
+ ASSERT(!(val.flags & SFLAG_NO_ERASE));
+#endif
+
+ hash_map.erase(i);
+ }
+}
+
+void CrawlHashTable::clear()
+{
+ assert_validity();
+ ASSERT(!(default_flags & SFLAG_NO_ERASE));
+
+ iterator i = hash_map.begin();
+ for (; i != hash_map.end(); i++)
+ ASSERT(!(i->second.flags & SFLAG_NO_ERASE));
+
+ hash_map.clear();
+ default_flags = 0;
+ type = SV_NONE;
+}
+
+CrawlHashTable::iterator CrawlHashTable::begin()
+{
+ assert_validity();
+ return hash_map.begin();
+}
+
+CrawlHashTable::iterator CrawlHashTable::end()
+{
+ assert_validity();
+ return hash_map.end();
+}
+
+CrawlHashTable::const_iterator CrawlHashTable::begin() const
+{
+ assert_validity();
+ return hash_map.begin();
+}
+
+CrawlHashTable::const_iterator CrawlHashTable::end() const
+{
+ assert_validity();
+ return hash_map.end();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+CrawlVector::CrawlVector()
+ : type(SV_NONE), default_flags(0), max_size(VEC_MAX_SIZE)
+{
+}
+
+CrawlVector::CrawlVector(store_flags flags, vec_size _max_size)
+ : type(SV_NONE), default_flags(flags), max_size(_max_size)
+{
+ ASSERT(!(default_flags & SFLAG_UNSET));
+ ASSERT(max_size > 0);
+}
+
+CrawlVector::CrawlVector(store_val_type _type, store_flags flags,
+ vec_size _max_size)
+ : type(_type), default_flags(flags), max_size(_max_size)
+{
+ ASSERT(type >= SV_NONE && type < NUM_STORE_VAL_TYPES);
+ ASSERT(!(default_flags & SFLAG_UNSET));
+ ASSERT(max_size > 0);
+}
+
+CrawlVector::~CrawlVector()
+{
+ assert_validity();
+}
+
+//////////////////////////////
+// Read/write from/to savefile
+void CrawlVector::write(tagHeader &th) const
+{
+ assert_validity();
+ if (empty())
+ {
+ marshallByte(th, 0);
+ return;
+ }
+
+ marshallByte(th, (char) size());
+ marshallByte(th, (char) max_size);
+ marshallByte(th, static_cast<char>(type));
+ marshallByte(th, (char) default_flags);
+
+ for (vec_size i = 0; i < size(); i++)
+ {
+ CrawlStoreValue val = vector[i];
+ ASSERT(val.type != SV_NONE);
+ ASSERT(!(val.flags & SFLAG_UNSET));
+ val.write(th);
+ }
+
+ assert_validity();
+}
+
+void CrawlVector::read(tagHeader &th)
+{
+ assert_validity();
+
+ ASSERT(empty());
+ ASSERT(type == SV_NONE);
+ ASSERT(default_flags == 0);
+ ASSERT(max_size == VEC_MAX_SIZE);
+
+ vec_size _size = (vec_size) unmarshallByte(th);
+
+ if (_size == 0)
+ return;
+
+ max_size = static_cast<vec_size>(unmarshallByte(th));
+ type = static_cast<store_val_type>(unmarshallByte(th));
+ default_flags = static_cast<store_flags>(unmarshallByte(th));
+
+ ASSERT(_size <= max_size);
+
+ vector.resize(_size);
+
+ for (vec_size i = 0; i < _size; i++)
+ vector[i].read(th);
+
+ assert_validity();
+}
+
+
+//////////////////
+// Misc functions
+
+store_flags CrawlVector::get_default_flags() const
+{
+ assert_validity();
+ return default_flags;
+}
+
+store_flags CrawlVector::set_default_flags(store_flags flags)
+{
+ assert_validity();
+ ASSERT(!(flags & SFLAG_UNSET));
+ default_flags |= flags;
+
+ return default_flags;
+}
+
+store_flags CrawlVector::unset_default_flags(store_flags flags)
+{
+ assert_validity();
+ ASSERT(!(flags & SFLAG_UNSET));
+ default_flags &= ~flags;
+
+ return default_flags;
+}
+
+store_val_type CrawlVector::get_type() const
+{
+ assert_validity();
+ return type;
+}
+
+void CrawlVector::assert_validity() const
+{
+#if DEBUG
+ ASSERT(!(default_flags & SFLAG_UNSET));
+ ASSERT(max_size > 0);
+ ASSERT(max_size >= size());
+
+ for (vec_size i = 0, _size = size(); i < _size; i++)
+ {
+ const CrawlStoreValue &val = vector[i];
+
+ // A vector might be resize()'d and filled up with unset
+ // values, which are then set one by one, so we can't
+ // assert over that here.
+ if (val.type == SV_NONE || (val.flags & SFLAG_UNSET))
+ continue;
+
+ switch(val.type)
+ {
+ case SV_STR:
+ case SV_COORD:
+ case SV_ITEM:
+ ASSERT(val.val.ptr != NULL);
+ break;
+
+ case SV_HASH:
+ {
+ ASSERT(val.val.ptr != NULL);
+
+ CrawlVector* nested;
+ nested = static_cast<CrawlVector*>(val.val.ptr);
+
+ nested->assert_validity();
+ break;
+ }
+
+ case SV_VEC:
+ {
+ ASSERT(val.val.ptr != NULL);
+
+ CrawlVector* nested;
+ nested = static_cast<CrawlVector*>(val.val.ptr);
+
+ nested->assert_validity();
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+#endif
+}
+
+void CrawlVector::set_max_size(vec_size _size)
+{
+ ASSERT(_size > 0);
+ ASSERT(max_size == VEC_MAX_SIZE);
+ max_size = _size;
+
+ vector.reserve(max_size);
+}
+
+vec_size CrawlVector::get_max_size() const
+{
+ return max_size;
+}
+
+
+////////////////////////////////
+// Accessors to contained values
+
+CrawlStoreValue& CrawlVector::get_value(const vec_size &index)
+{
+ assert_validity();
+
+ ASSERT(index <= max_size);
+ ASSERT(index <= vector.size());
+
+ return vector[index];
+}
+
+const CrawlStoreValue& CrawlVector::get_value(const vec_size &index) const
+{
+ assert_validity();
+
+ ASSERT(index <= max_size);
+ ASSERT(index <= vector.size());
+
+ return vector[index];
+}
+
+CrawlStoreValue& CrawlVector::operator[] (const vec_size &index)
+{
+ return get_value(index);
+}
+
+const CrawlStoreValue& CrawlVector::operator[] (const vec_size &index) const
+{
+ return get_value(index);
+}
+
+///////////////////////////
+// std::vector style interface
+vec_size CrawlVector::size() const
+{
+ return vector.size();
+}
+
+bool CrawlVector::empty() const
+{
+ return vector.empty();
+}
+
+CrawlStoreValue& CrawlVector::pop_back()
+{
+ assert_validity();
+ ASSERT(vector.size() > 0);
+
+ CrawlStoreValue& val = vector[vector.size() - 1];
+ vector.pop_back();
+ return val;
+}
+
+void CrawlVector::push_back(CrawlStoreValue val)
+{
+ assert_validity();
+ ASSERT(vector.size() < max_size);
+ ASSERT(type == SV_NONE
+ || (val.type == SV_NONE && (val.flags & SFLAG_UNSET))
+ || (val.type == type));
+ val.flags |= default_flags;
+ if (type != SV_NONE)
+ {
+ val.type = type;
+ val.flags |= SFLAG_CONST_TYPE;
+ }
+ vector.push_back(val);
+}
+
+void CrawlVector::insert(const vec_size index, CrawlStoreValue val)
+{
+ assert_validity();
+ ASSERT(vector.size() < max_size);
+ ASSERT(type == SV_NONE
+ || (val.type == SV_NONE && (val.flags & SFLAG_UNSET))
+ || (val.type == type));
+ val.flags |= default_flags;
+ if (type != SV_NONE)
+ {
+ val.type = type;
+ val.flags |= SFLAG_CONST_TYPE;
+ }
+ vector.insert(vector.begin() + index, val);
+}
+
+void CrawlVector::resize(const vec_size _size)
+{
+ assert_validity();
+ ASSERT(max_size == VEC_MAX_SIZE);
+ ASSERT(_size < max_size);
+
+ vec_size old_size = size();
+ vector.resize(_size);
+
+ for (vec_size i = old_size; i < _size; i++)
+ {
+ vector[i].flags = SFLAG_UNSET | default_flags;
+ vector[i].type = SV_NONE;
+ }
+}
+
+void CrawlVector::erase(const vec_size index)
+{
+ assert_validity();
+ ASSERT(index <= max_size);
+ ASSERT(index <= vector.size());
+
+ vector.erase(vector.begin() + index);
+}
+
+void CrawlVector::clear()
+{
+ assert_validity();
+ ASSERT(!(default_flags & SFLAG_NO_ERASE));
+
+ for (vec_size i = 0, _size = size(); i < _size; i++)
+ ASSERT(!(vector[i].flags & SFLAG_NO_ERASE));
+
+ vector.clear();
+ default_flags = 0;
+ type = SV_NONE;
+}
+
+CrawlVector::iterator CrawlVector::begin()
+{
+ assert_validity();
+ return vector.begin();
+}
+
+CrawlVector::iterator CrawlVector::end()
+{
+ assert_validity();
+ return vector.end();
+}
+
+CrawlVector::const_iterator CrawlVector::begin() const
+{
+ assert_validity();
+ return vector.begin();
+}
+
+CrawlVector::const_iterator CrawlVector::end() const
+{
+ assert_validity();
+ return vector.end();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+template <typename T, store_val_type TYPE>
+CrawlTableWrapper<T, TYPE>::CrawlTableWrapper()
+{
+ table = NULL;
+}
+
+template <typename T, store_val_type TYPE>
+CrawlTableWrapper<T, TYPE>::CrawlTableWrapper(CrawlHashTable& _table)
+{
+ wrap(_table);
+}
+
+template <typename T, store_val_type TYPE>
+CrawlTableWrapper<T, TYPE>::CrawlTableWrapper(CrawlHashTable* _table)
+{
+ wrap(_table);
+}
+
+template <typename T, store_val_type TYPE>
+void CrawlTableWrapper<T, TYPE>::wrap(CrawlHashTable& _table)
+{
+ wrap(&_table);
+}
+
+template <typename T, store_val_type TYPE>
+void CrawlTableWrapper<T, TYPE>::wrap(CrawlHashTable* _table)
+{
+ ASSERT(_table != NULL);
+ ASSERT(_table->get_type() == TYPE);
+
+ table = _table;
+}
+
+template <typename T, store_val_type TYPE>
+T& CrawlTableWrapper<T, TYPE>::operator[] (const std::string &key)
+{
+ return (T&) (*table)[key];
+}
+
+template <typename T, store_val_type TYPE>
+const T CrawlTableWrapper<T, TYPE>::operator[] (const std::string &key) const
+{
+ return (T) (*table)[key];
+}
diff --git a/crawl-ref/source/store.h b/crawl-ref/source/store.h
new file mode 100644
index 0000000000..434c0cd74d
--- /dev/null
+++ b/crawl-ref/source/store.h
@@ -0,0 +1,402 @@
+/*
+ * File: store.cc
+ * Summary: Saveable hash-table and vector capable of storing
+ * multiple types of data.
+ * Written by: Matthew Cline
+ *
+ * Modified for Crawl Reference by $Author$ on $Date$
+ *
+ * Change History (most recent first):
+
+ * <1> 10/5/07 MPC Created
+ */
+
+#ifndef STORE_H
+#define STORE_H
+
+#include <limits.h>
+#include <map>
+#include <string>
+#include <vector>
+
+struct tagHeader;
+class CrawlHashTable;
+class CrawlVector;
+class item_def;
+class coord_def;
+
+typedef unsigned char hash_size;
+typedef unsigned char vec_size;
+typedef unsigned char store_flags;
+
+#define VEC_MAX_SIZE 255
+#define HASH_MAX_SIZE 255
+
+// NOTE: Changing the ordering of these enums will break savefile
+// compatibility.
+enum store_val_type
+{
+ SV_NONE = 0,
+ SV_BOOL,
+ SV_BYTE,
+ SV_SHORT,
+ SV_LONG,
+ SV_FLOAT,
+ SV_STR,
+ SV_COORD,
+ SV_ITEM,
+ SV_HASH,
+ SV_VEC,
+ NUM_STORE_VAL_TYPES
+};
+
+enum store_flag_type
+{
+ SFLAG_UNSET = (1 << 0),
+ SFLAG_CONST_VAL = (1 << 1),
+ SFLAG_CONST_TYPE = (1 << 2),
+ SFLAG_NO_ERASE = (1 << 3)
+};
+
+
+// Can't just cast everything into a void pointer, since a float might
+// not fit into a pointer on all systems.
+typedef union StoreUnion StoreUnion;
+union StoreUnion
+{
+ bool boolean;
+ char byte;
+ short _short;
+ long _long;
+ float _float;
+ void* ptr;
+};
+
+
+class CrawlStoreValue
+{
+public:
+ CrawlStoreValue();
+ CrawlStoreValue(const CrawlStoreValue &other);
+
+ ~CrawlStoreValue();
+
+ // Conversion constructors
+ CrawlStoreValue(const bool val);
+ CrawlStoreValue(const char &val);
+ CrawlStoreValue(const short &val);
+ CrawlStoreValue(const long &val);
+ CrawlStoreValue(const float &val);
+ CrawlStoreValue(const std::string &val);
+ CrawlStoreValue(const char* val);
+ CrawlStoreValue(const coord_def &val);
+ CrawlStoreValue(const item_def &val);
+ CrawlStoreValue(const CrawlHashTable &val);
+ CrawlStoreValue(const CrawlVector &val);
+
+ // Only needed for doing some assertion checking.
+ CrawlStoreValue &operator = (const CrawlStoreValue &other);
+
+protected:
+ store_val_type type;
+ store_flags flags;
+ StoreUnion val;
+
+public:
+ store_flags get_flags() const;
+ store_flags set_flags(store_flags flags);
+ store_flags unset_flags(store_flags flags);
+ store_val_type get_type() const;
+
+ CrawlHashTable &new_table(store_flags flags);
+ CrawlHashTable &new_table(store_val_type type, store_flags flags = 0);
+
+ CrawlVector &new_vector(store_flags flags,
+ vec_size max_size = VEC_MAX_SIZE);
+ CrawlVector &new_vector(store_val_type type, store_flags flags = 0,
+ vec_size max_size = VEC_MAX_SIZE);
+
+ bool &get_bool();
+ char &get_byte();
+ short &get_short();
+ long &get_long();
+ float &get_float();
+ std::string &get_string();
+ coord_def &get_coord();
+ CrawlHashTable &get_table();
+ CrawlVector &get_vector();
+ item_def &get_item();
+
+ bool get_bool() const;
+ char get_byte() const;
+ short get_short() const;
+ long get_long() const;
+ float get_float() const;
+ std::string get_string() const;
+ coord_def get_coord() const;
+
+ const CrawlHashTable& get_table() const;
+ const CrawlVector& get_vector() const;
+ const item_def& get_item() const;
+
+ void set_bool(const bool val);
+ void set_byte(const char val);
+ void set_short(const short val);
+ void set_long(const long val);
+ void set_float(const float val);
+ void set_string(const std::string &val);
+ void set_coord(const coord_def &val);
+ void set_table(const CrawlHashTable &val);
+ void set_vector(const CrawlVector &val);
+ void set_item(const item_def &val);
+
+public:
+ // NOTE: All operators will assert if the value is of the wrong
+ // type for the operation. If the value has no type yet, the
+ // operation will set it to the appropriate type. If the value
+ // has no type yet and the operation modifies the existing value
+ // rather than replacing it (e.g., ++) the value will be set to a
+ // default before the operation is done.
+
+ // If the value is a hash table or vector, the container's values
+ // can be accessed with the [] operator with the approriate key
+ // type (strings for hashes, longs for vectors).
+ CrawlStoreValue &operator [] (const std::string &key);
+ CrawlStoreValue &operator [] (const vec_size &index);
+
+ const CrawlStoreValue &operator [] (const std::string &key) const;
+ const CrawlStoreValue &operator [] (const vec_size &index) const;
+
+ // Typecast operators
+ &operator bool();
+ &operator char();
+ &operator short();
+ &operator long();
+ &operator float();
+ &operator std::string();
+ &operator coord_def();
+ &operator CrawlHashTable();
+ &operator CrawlVector();
+ &operator item_def();
+
+ operator bool() const;
+ operator char() const;
+ operator short() const;
+ operator long() const;
+ operator float() const;
+ operator std::string() const;
+ operator coord_def() const;
+
+ // Assignment operators
+ CrawlStoreValue &operator = (const bool &val);
+ CrawlStoreValue &operator = (const char &val);
+ CrawlStoreValue &operator = (const short &val);
+ CrawlStoreValue &operator = (const long &val);
+ CrawlStoreValue &operator = (const float &val);
+ CrawlStoreValue &operator = (const std::string &val);
+ CrawlStoreValue &operator = (const char* val);
+ CrawlStoreValue &operator = (const coord_def &val);
+ CrawlStoreValue &operator = (const CrawlHashTable &val);
+ CrawlStoreValue &operator = (const CrawlVector &val);
+ CrawlStoreValue &operator = (const item_def &val);
+
+ // Misc operators
+ std::string &operator += (const std::string &val);
+
+ // Prefix
+ long operator ++ ();
+ long operator -- ();
+
+ // Postfix
+ long operator ++ (int);
+ long operator -- (int);
+
+protected:
+ CrawlStoreValue(const store_flags flags,
+ const store_val_type type = SV_NONE);
+
+ void write(tagHeader &th) const;
+ void read(tagHeader &th);
+
+ void unset(bool force = false);
+
+ friend class CrawlHashTable;
+ friend class CrawlVector;
+};
+
+
+// A hash table can have a maximum of 255 key/value pairs. If you
+// want more than that you can use nested hash tables.
+//
+// By default a hash table's value data types are heterogeneous. To
+// make it homogeneous (which causes dynamic type checking) you have
+// to give a type to the hash table constructor; once it's been
+// created its type (or lack of type) is immutable.
+//
+// An empty hash table will take up only 1 byte in the savefile. A
+// non-empty hash table will have an overhead of 3 bytes for the hash
+// table overall and 2 bytes per key/value pair, over and above the
+// number of bytes needed to store the keys and values themselves.
+class CrawlHashTable
+{
+public:
+ CrawlHashTable();
+ CrawlHashTable(store_flags flags);
+ CrawlHashTable(store_val_type type, store_flags flags = 0);
+
+ ~CrawlHashTable();
+
+ typedef std::map<std::string, CrawlStoreValue> hash_map_type;
+ typedef hash_map_type::iterator iterator;
+ typedef hash_map_type::const_iterator const_iterator;
+
+protected:
+ store_val_type type;
+ store_flags default_flags;
+ hash_map_type hash_map;
+
+ friend class CrawlStoreValue;
+
+public:
+ void write(tagHeader &th) const;
+ void read(tagHeader &th);
+
+ store_flags get_default_flags() const;
+ store_flags set_default_flags(store_flags flags);
+ store_flags unset_default_flags(store_flags flags);
+ store_val_type get_type() const;
+ bool exists(const std::string key) const;
+ void assert_validity() const;
+
+ // NOTE: If the const versions of get_value() or [] are given a
+ // key which doesn't exist, they will assert.
+ const CrawlStoreValue& get_value(const std::string &key) const;
+ const CrawlStoreValue& operator[] (const std::string &key) const;
+
+ // NOTE: If get_value() or [] is given a key which doesn't exist
+ // in the table, an unset/empty CrawlStoreValue will be created
+ // with that key and returned. If it is not then given a value
+ // then the next call to assert_validity() will fail. If the
+ // hash table has a type (rather than being heterogeneous)
+ // then trying to assign a different type to the CrawlStoreValue
+ // will assert.
+ CrawlStoreValue& get_value(const std::string &key);
+ CrawlStoreValue& operator[] (const std::string &key);
+
+ // std::map style interface
+ hash_size size() const;
+ bool empty() const;
+
+ void erase(const std::string key);
+ void clear();
+
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ iterator begin();
+ iterator end();
+};
+
+// A CrawlVector is the vector version of CrawlHashTable, except that
+// a non-empty CrawlVector has one more byte of savefile overhead that
+// a hash table, and that can specify a maximum size to make it act
+// similarly to a FixedVec.
+class CrawlVector
+{
+public:
+ CrawlVector();
+ CrawlVector(store_flags flags, vec_size max_size = VEC_MAX_SIZE);
+ CrawlVector(store_val_type type, store_flags flags = 0,
+ vec_size max_size = VEC_MAX_SIZE);
+
+ ~CrawlVector();
+
+ typedef std::vector<CrawlStoreValue> vector_type;
+ typedef vector_type::iterator iterator;
+ typedef vector_type::const_iterator const_iterator;
+
+protected:
+ store_val_type type;
+ store_flags default_flags;
+ vec_size max_size;
+ vector_type vector;
+
+ friend class CrawlStoreValue;
+
+public:
+ void write(tagHeader &th) const;
+ void read(tagHeader &th);
+
+ store_flags get_default_flags() const;
+ store_flags set_default_flags(store_flags flags);
+ store_flags unset_default_flags(store_flags flags);
+ store_val_type get_type() const;
+ void assert_validity() const;
+ void set_max_size(vec_size size);
+ vec_size get_max_size() const;
+
+ // NOTE: If the const versions of get_value() or [] are given a
+ // index which doesn't exist, they will assert.
+ const CrawlStoreValue& get_value(const vec_size &index) const;
+ const CrawlStoreValue& operator[] (const vec_size &index) const;
+
+ CrawlStoreValue& get_value(const vec_size &index);
+ CrawlStoreValue& operator[] (const vec_size &index);
+
+ // std::vector style interface
+ vec_size size() const;
+ bool empty() const;
+
+ // NOTE: push_back() and insert() have val passed by value rather
+ // than by reference so that conversion constructors will work.
+ CrawlStoreValue& pop_back();
+ void push_back(CrawlStoreValue val);
+ void insert(const vec_size index, CrawlStoreValue val);
+
+ // resize() will assert if the maximum size has been set.
+ void resize(const vec_size size);
+ void erase(const vec_size index);
+ void clear();
+
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ iterator begin();
+ iterator end();
+};
+
+// A wrapper for non-heterogeneous hash tables, so that the values can
+// be accessed without using get_foo(). T needs to have both normal
+// and const type-cast operators defined by CrawlStoreValue for this
+// template to work.
+template <typename T, store_val_type TYPE>
+class CrawlTableWrapper
+{
+public:
+ CrawlTableWrapper();
+ CrawlTableWrapper(CrawlHashTable& table);
+ CrawlTableWrapper(CrawlHashTable* table);
+
+protected:
+ CrawlHashTable* table;
+
+public:
+ void wrap(CrawlHashTable& table);
+ void wrap(CrawlHashTable* table);
+
+ const CrawlHashTable* get_table() const;
+ const T operator[] (const std::string &key) const;
+
+ CrawlHashTable* get_table();
+ T& operator[] (const std::string &key);
+};
+
+typedef CrawlTableWrapper<bool, SV_BOOL> CrawlBoolTable;
+typedef CrawlTableWrapper<char, SV_BYTE> CrawlByteTable;
+typedef CrawlTableWrapper<short, SV_SHORT> CrawlShortTable;
+typedef CrawlTableWrapper<long, SV_LONG> CrawlLongTable;
+typedef CrawlTableWrapper<float, SV_FLOAT> CrawlFloatTable;
+typedef CrawlTableWrapper<std::string, SV_STR> CrawlStringTable;
+typedef CrawlTableWrapper<coord_def, SV_COORD> CrawlCoordTable;
+
+#endif
diff --git a/crawl-ref/source/stuff.cc b/crawl-ref/source/stuff.cc
index 0a67d233f2..9e7f2a0b3e 100644
--- a/crawl-ref/source/stuff.cc
+++ b/crawl-ref/source/stuff.cc
@@ -14,6 +14,7 @@
*/
#include "AppHdr.h"
+#include "cio.h"
#include "database.h"
#include "direct.h"
#include "message.h"
@@ -443,9 +444,11 @@ void cio_init()
crawl_view.init_geometry();
if (Options.char_set == CSET_UNICODE && !crawl_state.unicode_ok)
- end(1, false,
- "Unicode glyphs are not available, please change your "
- "char_set option");
+ {
+ crawl_state.add_startup_error(
+ "Unicode glyphs are not available, falling back to ASCII.");
+ Options.char_set = CSET_ASCII;
+ }
}
void cio_cleanup()
@@ -685,27 +688,34 @@ void canned_msg(canned_message_type which_message)
break;
case MSG_TOO_BERSERK:
mpr("You are too berserk!");
+ crawl_state.cancel_cmd_repeat();
break;
case MSG_PRESENT_FORM:
mpr("You can't do that in your present form.");
+ crawl_state.cancel_cmd_repeat();
break;
case MSG_NOTHING_CARRIED:
mpr("You aren't carrying anything.");
+ crawl_state.cancel_cmd_repeat();
break;
case MSG_CANNOT_DO_YET:
mpr("You can't do that yet.");
+ crawl_state.cancel_cmd_repeat();
break;
case MSG_OK:
mpr("Okay, then.");
+ crawl_state.cancel_cmd_repeat();
break;
case MSG_UNTHINKING_ACT:
mpr("Why would you want to do that?");
+ crawl_state.cancel_cmd_repeat();
break;
case MSG_SPELL_FIZZLES:
mpr("The spell fizzles.");
break;
case MSG_HUH:
mpr("Huh?");
+ crawl_state.cancel_cmd_repeat();
break;
case MSG_EMPTY_HANDED:
mpr("You are now empty-handed.");
@@ -718,10 +728,12 @@ void canned_msg(canned_message_type which_message)
// jmf: general helper (should be used all over in code)
// -- idea borrowed from Nethack
bool yesno( const char *str, bool safe, int safeanswer, bool clear_after,
- bool interrupt_delays, bool noprompt )
+ bool interrupt_delays, bool noprompt,
+ const explicit_keymap *map )
{
- if (interrupt_delays)
+ if (interrupt_delays && !crawl_state.is_repeating_cmd())
interrupt_activity( AI_FORCE_INTERRUPT );
+
for (;;)
{
if ( !noprompt )
@@ -729,6 +741,9 @@ bool yesno( const char *str, bool safe, int safeanswer, bool clear_after,
int tmp = getchm(KC_CONFIRM);
+ if (map && map->find(tmp) != map->end())
+ tmp = map->find(tmp)->second;
+
if ((tmp == ' ' || tmp == 27 || tmp == '\r' || tmp == '\n')
&& safeanswer)
tmp = safeanswer;
@@ -755,14 +770,16 @@ bool yesno( const char *str, bool safe, int safeanswer, bool clear_after,
// like yesno(), but returns 0 for no, 1 for yes, and -1 for quit
int yesnoquit( const char* str, bool safe, int safeanswer, bool clear_after )
{
- interrupt_activity( AI_FORCE_INTERRUPT );
+ if (!crawl_state.is_repeating_cmd())
+ interrupt_activity( AI_FORCE_INTERRUPT );
+
while (1)
{
mpr(str, MSGCH_PROMPT);
int tmp = getchm(KC_CONFIRM);
- if ( tmp == ESCAPE || tmp == 'q' || tmp == 'Q' )
+ if ( tmp == CK_ESCAPE || tmp == 'q' || tmp == 'Q' )
return -1;
if ((tmp == ' ' || tmp == '\r' || tmp == '\n') && safeanswer)
@@ -783,7 +800,7 @@ int yesnoquit( const char* str, bool safe, int safeanswer, bool clear_after )
else if (tmp == 'Y')
return 1;
else
- mpr("[Y]es or [N]o only, please.");
+ mpr("[Y]es, [N]o or [Q]uit only, please.");
}
}
@@ -994,7 +1011,7 @@ int element_colour( int element, bool no_random )
break;
case EC_DARK:
- ret = DARKGREY;
+ ret = (tmp_rand < 80) ? DARKGREY : LIGHTGREY;
break;
case EC_HOLY:
@@ -1087,6 +1104,28 @@ int element_colour( int element, bool no_random )
ret = random_choose_weighted(80, BLUE, 20, LIGHTBLUE, 5, CYAN, 0);
break;
+ case EC_DECAY:
+ ret = (tmp_rand < 60) ? BROWN : GREEN;
+ break;
+
+ case EC_SILVER:
+ ret = (tmp_rand < 90) ? LIGHTGREY : WHITE;
+ break;
+
+ case EC_GOLD:
+ ret = (tmp_rand < 60) ? YELLOW : BROWN;
+ break;
+
+ case EC_IRON:
+ ret = (tmp_rand < 40) ? CYAN :
+ (tmp_rand < 80) ? LIGHTGREY :
+ DARKGREY;
+ break;
+
+ case EC_BONE:
+ ret = (tmp_rand < 90) ? WHITE : LIGHTGREY;
+ break;
+
case EC_RANDOM:
ret = 1 + random2(15); // always random
break;
diff --git a/crawl-ref/source/stuff.h b/crawl-ref/source/stuff.h
index 1cb39492d1..de773bcd54 100644
--- a/crawl-ref/source/stuff.h
+++ b/crawl-ref/source/stuff.h
@@ -17,6 +17,7 @@
#define STUFF_H
#include "externs.h"
+#include <map>
std::string make_time_string(time_t abs_time, bool terse = false);
void set_redraw_status( unsigned long flags );
@@ -67,9 +68,11 @@ void redraw_screen();
void canned_msg(canned_message_type which_message);
+typedef std::map<int, int> explicit_keymap;
bool yesno( const char * str, bool safe = true, int safeanswer = 0,
bool clear_after = true, bool interrupt_delays = true,
- bool noprompt = false );
+ bool noprompt = false,
+ const explicit_keymap *map = NULL );
int yesnoquit( const char* str, bool safe = true,
int safeanswer = 0, bool clear_after = true );
diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc
index d30ea7ba4c..9a057ec579 100644
--- a/crawl-ref/source/tags.cc
+++ b/crawl-ref/source/tags.cc
@@ -98,6 +98,7 @@ extern std::map<branch_type, level_id> stair_level;
extern std::map<level_pos, shop_type> shops_present;
extern std::map<level_pos, god_type> altars_present;
extern std::map<level_pos, portal_type> portals_present;
+extern std::map<level_id, std::string> level_annotations;
// temp file pairs used for file level cleanup
FixedArray < bool, MAX_LEVELS, NUM_BRANCHES > tmp_file_pairs;
@@ -129,8 +130,6 @@ static void marshallGhost(tagHeader &th, const ghost_demon &ghost);
static ghost_demon unmarshallGhost( tagHeader &th );
static void marshall_monster(tagHeader &th, const monsters &m);
static void unmarshall_monster(tagHeader &th, monsters &m);
-static void marshall_item(tagHeader &th, const item_def &item);
-static void unmarshall_item(tagHeader &th, item_def &item);
template<typename T, typename T_iter, typename T_marshal>
static void marshall_iterator(struct tagHeader &th, T_iter beg, T_iter end,
@@ -425,6 +424,12 @@ void marshallString(struct tagHeader &th, const std::string &data, int maxSize)
th.offset += len;
}
+// To pass to marsahllMap
+static void marshall_string(struct tagHeader &th, const std::string &data)
+{
+ marshallString(th, data);
+}
+
// string -- unmarshall length & string data
int unmarshallCString(struct tagHeader &th, char *data, int maxSize)
{
@@ -458,6 +463,12 @@ std::string unmarshallString(tagHeader &th, int maxSize)
return (res);
}
+// To pass to unmarshallMap
+static std::string unmarshall_string(struct tagHeader &th)
+{
+ return unmarshallString(th);
+}
+
// boolean (to avoid system-dependant bool implementations)
void marshallBoolean(struct tagHeader &th, bool data)
{
@@ -768,7 +779,7 @@ static void tag_construct_you(struct tagHeader &th)
marshallByte(th,you.rotting);
marshallByte(th,you.symbol);
marshallByte(th,you.colour);
- marshallByte(th,you.pet_target);
+ marshallShort(th,you.pet_target);
marshallByte(th,you.max_level);
marshallByte(th,you.where_are_you);
@@ -779,6 +790,8 @@ static void tag_construct_you(struct tagHeader &th)
marshallByte(th,you.berserk_penalty);
marshallByte(th,you.level_type);
marshallString(th, you.level_type_name);
+ marshallByte(th,you.entry_cause);
+ marshallByte(th,you.entry_cause_god);
marshallByte(th,you.synch_time);
marshallByte(th,you.disease);
marshallByte(th,you.species);
@@ -917,6 +930,11 @@ static void tag_construct_you(struct tagHeader &th)
marshallShort(th, you.transit_stair);
marshallByte(th, you.entering_level);
+
+ // list of currently beholding monsters (usually empty)
+ marshallByte(th, you.beheld_by.size());
+ for (unsigned int k = 0; k < you.beheld_by.size(); k++)
+ marshallByte(th, you.beheld_by[k]);
}
static void tag_construct_you_items(struct tagHeader &th)
@@ -926,19 +944,7 @@ static void tag_construct_you_items(struct tagHeader &th)
// 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);
- marshallShort(th, you.inv[i].orig_place);
- marshallShort(th, you.inv[i].orig_monnum);
- marshallString(th, you.inv[i].inscription.c_str(), 80);
- }
+ marshallItem(th, you.inv[i]);
marshallByte(th, you.quiver);
@@ -1021,7 +1027,10 @@ static void tag_construct_you_dungeon(struct tagHeader &th)
// how many branches?
marshallByte(th, NUM_BRANCHES);
for (j = 0; j < NUM_BRANCHES; ++j)
+ {
marshallLong(th, branches[j].startdepth);
+ marshallLong(th, branches[j].branch_flags);
+ }
marshallShort(th, MAX_LEVELS);
for (i = 0; i < MAX_LEVELS; ++i)
@@ -1036,6 +1045,8 @@ static void tag_construct_you_dungeon(struct tagHeader &th)
marshall_level_pos, marshall_as_long<god_type>);
marshallMap(th, portals_present,
marshall_level_pos, marshall_as_long<portal_type>);
+ marshallMap(th, level_annotations,
+ marshall_level_id, marshall_string);
marshallPlaceInfo(th, you.global_info);
std::vector<PlaceInfo> list = you.get_all_place_info();
@@ -1055,14 +1066,14 @@ static void marshall_follower(tagHeader &th, const follower &f)
{
marshall_monster(th, f.mons);
for (int i = 0; i < NUM_MONSTER_SLOTS; ++i)
- marshall_item(th, f.items[i]);
+ marshallItem(th, f.items[i]);
}
static void unmarshall_follower(tagHeader &th, follower &f)
{
unmarshall_monster(th, f.mons);
for (int i = 0; i < NUM_MONSTER_SLOTS; ++i)
- unmarshall_item(th, f.items[i]);
+ unmarshallItem(th, f.items[i]);
}
static void marshall_follower_list(tagHeader &th, const m_transit_list &mlist)
@@ -1112,7 +1123,7 @@ static void tag_read_you(struct tagHeader &th, char minorVersion)
you.rotting = unmarshallByte(th);
you.symbol = unmarshallByte(th);
you.colour = unmarshallByte(th);
- you.pet_target = unmarshallByte(th);
+ you.pet_target = unmarshallShort(th);
you.max_level = unmarshallByte(th);
you.where_are_you = static_cast<branch_type>( unmarshallByte(th) );
@@ -1123,6 +1134,8 @@ static void tag_read_you(struct tagHeader &th, char minorVersion)
you.berserk_penalty = unmarshallByte(th);
you.level_type = static_cast<level_area_type>( unmarshallByte(th) );
you.level_type_name = unmarshallString(th);
+ you.entry_cause = static_cast<entry_cause_type>( unmarshallByte(th) );
+ you.entry_cause_god = static_cast<god_type>( unmarshallByte(th) );
you.synch_time = unmarshallByte(th);
you.disease = unmarshallByte(th);
you.species = static_cast<species_type>(unmarshallByte(th));
@@ -1257,6 +1270,11 @@ static void tag_read_you(struct tagHeader &th, char minorVersion)
you.transit_stair = static_cast<dungeon_feature_type>(unmarshallShort(th));
you.entering_level = unmarshallByte(th);
+
+ // list of currently beholding monsters (usually empty)
+ count_c = unmarshallByte(th);
+ for (i = 0; i < count_c; i++)
+ you.beheld_by.push_back(unmarshallByte(th));
}
static void tag_read_you_items(struct tagHeader &th, char minorVersion)
@@ -1268,26 +1286,7 @@ static void tag_read_you_items(struct tagHeader &th, char minorVersion)
// how many inventory slots?
count_c = unmarshallByte(th);
for (i = 0; i < count_c; ++i)
- {
- you.inv[i].base_type =
- static_cast<object_class_type>(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);
- you.inv[i].orig_place = unmarshallShort(th);
- you.inv[i].orig_monnum = unmarshallShort(th);
- you.inv[i].inscription = unmarshallString(th, 80);
-
- // 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;
- you.inv[i].slot = index_to_letter(i);
- }
+ unmarshallItem(th, you.inv[i]);
you.quiver = unmarshallByte(th);
@@ -1409,7 +1408,10 @@ static void tag_read_you_dungeon(struct tagHeader &th)
// how many branches?
count_c = unmarshallByte(th);
for (j = 0; j < count_c; ++j)
- branches[j].startdepth = unmarshallLong(th);
+ {
+ branches[j].startdepth = unmarshallLong(th);
+ branches[j].branch_flags = (unsigned long) unmarshallLong(th);
+ }
count_s = unmarshallShort(th);
for (i = 0; i < count_s; ++i)
@@ -1427,6 +1429,8 @@ static void tag_read_you_dungeon(struct tagHeader &th)
unmarshall_level_pos, unmarshall_long_as<god_type>);
unmarshallMap(th, portals_present,
unmarshall_level_pos, unmarshall_long_as<portal_type>);
+ unmarshallMap(th, level_annotations,
+ unmarshall_level_id, unmarshall_string);
PlaceInfo place_info = unmarshallPlaceInfo(th);
ASSERT(place_info.is_global());
@@ -1471,6 +1475,11 @@ static void tag_read_lost_monsters(tagHeader &th, int minorVersion)
static void tag_construct_level(struct tagHeader &th)
{
+ marshallByte(th, env.floor_colour);
+ marshallByte(th, env.rock_colour);
+
+ marshallLong(th, env.level_flags);
+
marshallFloat(th, (float)you.elapsed_time);
// map grids
@@ -1489,7 +1498,7 @@ static void tag_construct_level(struct tagHeader &th)
marshallShort(th, env.map[count_x][count_y].object);
marshallShort(th, env.map[count_x][count_y].colour);
marshallShort(th, env.map[count_x][count_y].flags);
- marshallByte(th, env.cgrid[count_x][count_y]);
+ marshallShort(th, env.cgrid[count_x][count_y]);
}
}
@@ -1505,6 +1514,7 @@ static void tag_construct_level(struct tagHeader &th)
marshallByte(th, env.cloud[i].y);
marshallByte(th, env.cloud[i].type);
marshallShort(th, env.cloud[i].decay);
+ marshallByte(th, (char) env.cloud[i].spread_rate);
marshallShort(th, env.cloud[i].whose);
}
@@ -1525,7 +1535,7 @@ static void tag_construct_level(struct tagHeader &th)
env.markers.write(th);
}
-static void marshall_item(tagHeader &th, const item_def &item)
+void marshallItem(tagHeader &th, const item_def &item)
{
marshallByte(th, item.base_type);
marshallByte(th, item.sub_type);
@@ -1540,16 +1550,21 @@ static void marshall_item(tagHeader &th, const item_def &item)
marshallLong(th, item.flags);
marshallShort(th, item.link); // unused
- marshallShort(th, igrd[item.x][item.y]); // unused
+ if (item.x == -1 && item.y == -1)
+ marshallShort(th, -1); // unused
+ else
+ marshallShort(th, igrd[item.x][item.y]); // unused
marshallByte(th, item.slot);
marshallShort(th, item.orig_place);
marshallShort(th, item.orig_monnum);
marshallString(th, item.inscription.c_str(), 80);
+
+ item.props.write(th);
}
-static void unmarshall_item(tagHeader &th, item_def &item)
+void unmarshallItem(tagHeader &th, item_def &item)
{
item.base_type = static_cast<object_class_type>(unmarshallByte(th));
item.sub_type = (unsigned char) unmarshallByte(th);
@@ -1575,6 +1590,9 @@ static void unmarshall_item(tagHeader &th, item_def &item)
item.orig_place = unmarshallShort(th);
item.orig_monnum = unmarshallShort(th);
item.inscription = unmarshallString(th, 80);
+
+ item.props.clear();
+ item.props.read(th);
}
static void tag_construct_level_items(struct tagHeader &th)
@@ -1591,7 +1609,7 @@ static void tag_construct_level_items(struct tagHeader &th)
// how many items?
marshallShort(th, MAX_ITEMS);
for (int i = 0; i < MAX_ITEMS; ++i)
- marshall_item(th, mitm[i]);
+ marshallItem(th, mitm[i]);
}
static void marshall_mon_enchant(tagHeader &th, const mon_enchant &me)
@@ -1635,6 +1653,7 @@ static void marshall_monster(tagHeader &th, const monsters &m)
{
marshall_mon_enchant(th, i->second);
}
+ marshallByte(th, m.ench_countdown);
marshallShort(th, m.type);
marshallShort(th, m.hit_points);
@@ -1691,6 +1710,11 @@ void tag_construct_level_attitude(struct tagHeader &th)
static void tag_read_level( struct tagHeader &th, char minorVersion )
{
+ env.floor_colour = unmarshallByte(th);
+ env.rock_colour = unmarshallByte(th);
+
+ env.level_flags = (unsigned long) unmarshallLong(th);
+
env.elapsed_time = unmarshallFloat(th);
// map grids
// how many X?
@@ -1713,7 +1737,7 @@ static void tag_read_level( struct tagHeader &th, char minorVersion )
env.map[i][j].flags = unmarshallShort(th);
mgrd[i][j] = NON_MONSTER;
- env.cgrid[i][j] = (unsigned char) unmarshallByte(th);
+ env.cgrid[i][j] = (unsigned short) unmarshallShort(th);
}
}
@@ -1730,6 +1754,7 @@ static void tag_read_level( struct tagHeader &th, char minorVersion )
env.cloud[i].y = unmarshallByte(th);
env.cloud[i].type = static_cast<cloud_type>(unmarshallByte(th));
env.cloud[i].decay = unmarshallShort(th);
+ env.cloud[i].spread_rate = (unsigned char) unmarshallByte(th);
env.cloud[i].whose = static_cast<kill_category>(unmarshallShort(th));
}
@@ -1767,7 +1792,7 @@ static void tag_read_level_items(struct tagHeader &th, char minorVersion)
// how many items?
const int item_count = unmarshallShort(th);
for (int i = 0; i < item_count; ++i)
- unmarshall_item(th, mitm[i]);
+ unmarshallItem(th, mitm[i]);
}
static void unmarshall_monster(tagHeader &th, monsters &m)
@@ -1784,6 +1809,7 @@ static void unmarshall_monster(tagHeader &th, monsters &m)
m.target_x = unmarshallByte(th);
m.target_y = unmarshallByte(th);
m.flags = unmarshallLong(th);
+ m.experience = static_cast<unsigned long>(unmarshallLong(th));
if (tag_minor_version >= 2)
m.experience = static_cast<unsigned long>(unmarshallLong(th));
@@ -1797,6 +1823,7 @@ static void unmarshall_monster(tagHeader &th, monsters &m)
mon_enchant me = unmarshall_mon_enchant(th);
m.enchantments[me.ench] = me;
}
+ m.ench_countdown = unmarshallByte(th);
m.type = unmarshallShort(th);
m.hit_points = unmarshallShort(th);
diff --git a/crawl-ref/source/tags.h b/crawl-ref/source/tags.h
index 40244224e9..df4c3d754b 100644
--- a/crawl-ref/source/tags.h
+++ b/crawl-ref/source/tags.h
@@ -72,6 +72,7 @@ void marshallBoolean(struct tagHeader &th, bool data);
void marshallString(struct tagHeader &th, const std::string &data,
int maxSize = 0);
void marshallCoord(tagHeader &th, const coord_def &c);
+void marshallItem(tagHeader &th, const item_def &item);
// last updated 22jan2001 {gdl}
/* ***********************************************************************
@@ -85,6 +86,7 @@ bool unmarshallBoolean(struct tagHeader &th);
int unmarshallCString(struct tagHeader &th, char *data, int maxSize);
std::string unmarshallString(tagHeader &th, int maxSize = 1000);
void unmarshallCoord(tagHeader &th, coord_def &c);
+void unmarshallItem(tagHeader &th, item_def &item);
std::string make_date_string( time_t in_date );
time_t parse_date_string( char[20] );
diff --git a/crawl-ref/source/terrain.cc b/crawl-ref/source/terrain.cc
index 87a453285a..8c9e122944 100644
--- a/crawl-ref/source/terrain.cc
+++ b/crawl-ref/source/terrain.cc
@@ -34,12 +34,7 @@
bool grid_is_wall( dungeon_feature_type grid )
{
- return (grid == DNGN_ROCK_WALL
- || grid == DNGN_STONE_WALL
- || grid == DNGN_METAL_WALL
- || grid == DNGN_GREEN_CRYSTAL_WALL
- || grid == DNGN_WAX_WALL
- || grid == DNGN_PERMAROCK_WALL);
+ return (grid >= DNGN_MINWALL && grid <= DNGN_MAXWALL);
}
bool grid_is_stone_stair(dungeon_feature_type grid)
@@ -162,7 +157,7 @@ command_type grid_stair_direction(dungeon_feature_type grid)
bool grid_is_opaque( dungeon_feature_type grid )
{
- return (grid < DNGN_MINSEE && grid != DNGN_ORCISH_IDOL);
+ return (grid < DNGN_MINSEE);
}
bool grid_is_solid( dungeon_feature_type grid )
@@ -180,10 +175,19 @@ bool grid_is_solid(const coord_def &c)
return (grid_is_solid(grd(c)));
}
+bool grid_is_rock( dungeon_feature_type grid )
+{
+ return (grid == DNGN_ORCISH_IDOL
+ || grid == DNGN_GRANITE_STATUE
+ || grid == DNGN_SECRET_DOOR
+ || (grid >= DNGN_ROCK_WALL
+ && grid <= DNGN_CLEAR_PERMAROCK_WALL));
+}
+
bool grid_is_trap(dungeon_feature_type grid)
{
return (grid == DNGN_TRAP_MECHANICAL || grid == DNGN_TRAP_MAGICAL
- || grid == DNGN_TRAP_III);
+ || grid == DNGN_TRAP_NATURAL);
}
bool grid_is_water( dungeon_feature_type grid )
@@ -383,6 +387,7 @@ static void dgn_check_terrain_items(const coord_def &pos, bool preserve_items)
dgn_shift_item(pos, mitm[curr]);
else
{
+ item_was_destroyed(mitm[curr]);
destroy_item(curr);
did_destroy = true;
}
@@ -403,6 +408,8 @@ static void dgn_check_terrain_monsters(const coord_def &pos)
else
mons_check_pool(mons, KILL_MISC, -1);
}
+
+ set_terrain_changed(pos.x, pos.y);
}
void dungeon_terrain_changed(const coord_def &pos,
diff --git a/crawl-ref/source/terrain.h b/crawl-ref/source/terrain.h
index 5839d4d02e..51caa559d6 100644
--- a/crawl-ref/source/terrain.h
+++ b/crawl-ref/source/terrain.h
@@ -28,10 +28,11 @@ bool fall_into_a_pool( int entry_x, int entry_y, bool allow_shift,
bool grid_is_wall(dungeon_feature_type grid);
bool grid_is_opaque(dungeon_feature_type grid);
bool grid_is_solid(dungeon_feature_type grid);
-bool grid_is_stone_stair(dungeon_feature_type grid);
-bool grid_is_rock_stair(dungeon_feature_type grid);
bool grid_is_solid(int x, int y);
bool grid_is_solid(const coord_def &c);
+bool grid_is_rock(dungeon_feature_type grid);
+bool grid_is_stone_stair(dungeon_feature_type grid);
+bool grid_is_rock_stair(dungeon_feature_type grid);
bool grid_is_trap(dungeon_feature_type grid);
command_type grid_stair_direction(dungeon_feature_type grid);
bool grid_sealable_portal(dungeon_feature_type grid);
diff --git a/crawl-ref/source/transfor.cc b/crawl-ref/source/transfor.cc
index b49013bacf..3dc1d8e6a9 100644
--- a/crawl-ref/source/transfor.cc
+++ b/crawl-ref/source/transfor.cc
@@ -205,7 +205,8 @@ bool transform(int pow, transformation_type which_trans)
if (you.duration[DUR_TRANSFORMATION] > 60)
you.duration[DUR_TRANSFORMATION] = 60;
- modify_stat( STAT_DEXTERITY, 5, true );
+ modify_stat( STAT_DEXTERITY, 5, true,
+ "gaining the spider transformation");
you.symbol = 's';
you.colour = BROWN;
@@ -227,8 +228,10 @@ bool transform(int pow, transformation_type which_trans)
if (you.duration[DUR_TRANSFORMATION] > 100)
you.duration[DUR_TRANSFORMATION] = 100;
- modify_stat( STAT_DEXTERITY, 5, true );
- modify_stat( STAT_STRENGTH, -5, true );
+ modify_stat( STAT_DEXTERITY, 5, true,
+ "gaining the bat transformation");
+ modify_stat( STAT_STRENGTH, -5, true,
+ "gaining the bat transformation" );
you.symbol = 'b';
you.colour = DARKGREY;
@@ -303,8 +306,10 @@ bool transform(int pow, transformation_type which_trans)
if (you.duration[ DUR_TRANSFORMATION ] > 100)
you.duration[ DUR_TRANSFORMATION ] = 100;
- modify_stat( STAT_DEXTERITY, -2, true );
- modify_stat( STAT_STRENGTH, 2, true );
+ modify_stat( STAT_DEXTERITY, -2, true,
+ "gaining the statue transformation" );
+ modify_stat( STAT_STRENGTH, 2, true,
+ "gaining the statue transformation");
extra_hp(15); // must occur after attribute set
if (you.duration[DUR_STONEMAIL] || you.duration[DUR_STONESKIN])
@@ -332,7 +337,8 @@ bool transform(int pow, transformation_type which_trans)
if (you.duration[ DUR_TRANSFORMATION ] > 100)
you.duration[ DUR_TRANSFORMATION ] = 100;
- modify_stat( STAT_STRENGTH, 10, true );
+ modify_stat( STAT_STRENGTH, 10, true,
+ "gaining the dragon transformation" );
extra_hp(16); // must occur after attribute set
you.symbol = 'D';
@@ -378,7 +384,8 @@ bool transform(int pow, transformation_type which_trans)
if (you.duration[ DUR_TRANSFORMATION ] > 100)
you.duration[ DUR_TRANSFORMATION ] = 100;
- modify_stat( STAT_STRENGTH, 3, true );
+ modify_stat( STAT_STRENGTH, 3, true,
+ "gaining the lich transformation" );
you.symbol = 'L';
you.colour = LIGHTGREY;
you.is_undead = US_UNDEAD;
@@ -408,7 +415,8 @@ bool transform(int pow, transformation_type which_trans)
if (you.duration[ DUR_TRANSFORMATION ] > 150)
you.duration[ DUR_TRANSFORMATION ] = 150;
- modify_stat( STAT_DEXTERITY, 8, true );
+ modify_stat( STAT_DEXTERITY, 8, true,
+ "gaining the air transformation" );
you.symbol = '#';
you.colour = DARKGREY;
@@ -437,7 +445,8 @@ bool transform(int pow, transformation_type which_trans)
if (you.duration[ DUR_TRANSFORMATION ] > 120)
you.duration[ DUR_TRANSFORMATION ] = 120;
- modify_stat( STAT_STRENGTH, 13, true );
+ modify_stat( STAT_STRENGTH, 13, true,
+ "gaining the Serpent of Hell transformation");
extra_hp(17); // must occur after attribute set
you.symbol = 'S';
@@ -479,13 +488,16 @@ void untransform(void)
{
case TRAN_SPIDER:
mpr("Your transformation has ended.", MSGCH_DURATION);
- modify_stat( STAT_DEXTERITY, -5, true );
+ modify_stat( STAT_DEXTERITY, -5, true,
+ "losing the spider transformation" );
break;
case TRAN_BAT:
mpr("Your transformation has ended.", MSGCH_DURATION);
- modify_stat( STAT_DEXTERITY, -5, true );
- modify_stat( STAT_STRENGTH, 5, true );
+ modify_stat( STAT_DEXTERITY, -5, true,
+ "losing the bat transformation" );
+ modify_stat( STAT_STRENGTH, 5, true,
+ "losing the bat transformation" );
break;
case TRAN_BLADE_HANDS:
@@ -495,8 +507,10 @@ void untransform(void)
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 );
+ modify_stat( STAT_DEXTERITY, 2, true,
+ "losing the statue transformation" );
+ modify_stat( STAT_STRENGTH, -2, true,
+ "losing the statue transformation");
// Note: if the core goes down, the combined effect soon disappears,
// but the reverse isn't true. -- bwr
@@ -524,7 +538,8 @@ void untransform(void)
case TRAN_DRAGON:
mpr( "Your transformation has ended.", MSGCH_DURATION );
- modify_stat(STAT_STRENGTH, -10, true);
+ modify_stat(STAT_STRENGTH, -10, true,
+ "losing the dragon transformation" );
// re-check terrain now that be may no longer be flying.
move_player_to_grid( you.x_pos, you.y_pos, false, true, true );
@@ -535,18 +550,21 @@ void untransform(void)
case TRAN_LICH:
mpr( "You feel yourself come back to life.", MSGCH_DURATION );
- modify_stat(STAT_STRENGTH, -3, true);
+ modify_stat(STAT_STRENGTH, -3, true,
+ "losing the lich transformation" );
you.is_undead = US_ALIVE;
break;
case TRAN_AIR:
mpr( "Your body solidifies.", MSGCH_DURATION );
- modify_stat(STAT_DEXTERITY, -8, true);
+ modify_stat(STAT_DEXTERITY, -8, true,
+ "losing the air transformation");
break;
case TRAN_SERPENT_OF_HELL:
mpr( "Your transformation has ended.", MSGCH_DURATION );
- modify_stat(STAT_STRENGTH, -13, true);
+ modify_stat(STAT_STRENGTH, -13, true,
+ "losing the Serpent of Hell transformation");
hp_downscale = 17;
break;
@@ -587,19 +605,7 @@ bool can_equip( equipment_type use_which, bool ignore_temporary )
if (ignore_temporary || !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)
+ if (use_which == EQ_HELMET)
{
switch (you.species)
{
@@ -614,10 +620,10 @@ bool can_equip( equipment_type use_which, bool ignore_temporary )
if (use_which == EQ_HELMET && you.mutation[MUT_HORNS])
return (false);
- if (use_which == EQ_BOOTS && you.mutation[MUT_HOOVES])
+ if (use_which == EQ_BOOTS && !player_has_feet())
return (false);
- if (use_which == EQ_GLOVES && you.mutation[MUT_CLAWS] >= 3)
+ if (use_which == EQ_GLOVES && you.has_claws(false) >= 3)
return (false);
if (!ignore_temporary)
diff --git a/crawl-ref/source/traps.cc b/crawl-ref/source/traps.cc
index d8e1043695..db6d7b1f49 100644
--- a/crawl-ref/source/traps.cc
+++ b/crawl-ref/source/traps.cc
@@ -16,6 +16,7 @@
#include "traps.h"
#include "beam.h"
+#include "branch.h"
#include "direct.h"
#include "it_use2.h"
#include "items.h"
@@ -25,6 +26,7 @@
#include "mon-util.h"
#include "monstuff.h"
#include "ouch.h"
+#include "place.h"
#include "player.h"
#include "randart.h"
#include "skills.h"
@@ -285,44 +287,64 @@ void itrap( struct bolt &pbolt, int trapped )
return;
} // end itrap()
-void handle_traps(char trt, int i, bool trap_known)
+void handle_traps(trap_type trt, int i, bool trap_known)
{
struct bolt beam;
+
+ bool branchtype = false;
+ if (trap_category(trt) == DNGN_TRAP_MECHANICAL && trt != TRAP_NET
+ && trt != TRAP_BLADE)
+ {
+ if (you.where_are_you == BRANCH_ORCISH_MINES)
+ {
+ beam.name = "n orcish";
+ branchtype = true;
+ }
+ else if (you.where_are_you == BRANCH_ELVEN_HALLS)
+ {
+ beam.name = "n elven";
+ branchtype = true;
+ }
+ else
+ beam.name = "";
+ }
switch (trt)
{
case TRAP_DART:
- beam.name = " dart";
+ beam.name += " dart";
beam.damage = dice_def( 1, 4 + (you.your_level / 2) );
dart_trap(trap_known, i, beam, false);
break;
case TRAP_NEEDLE:
- beam.name = " needle";
+ beam.name += " needle";
beam.damage = dice_def( 1, 0 );
dart_trap(trap_known, i, beam, true);
break;
case TRAP_ARROW:
- beam.name = "n arrow";
+ beam.name += (branchtype? "" : "n");
+ beam.name += " arrow";
beam.damage = dice_def( 1, 7 + you.your_level );
dart_trap(trap_known, i, beam, false);
break;
case TRAP_BOLT:
- beam.name = " bolt";
+ beam.name += " bolt";
beam.damage = dice_def( 1, 13 + you.your_level );
dart_trap(trap_known, i, beam, false);
break;
case TRAP_SPEAR:
- beam.name = " spear";
+ beam.name += " spear";
beam.damage = dice_def( 1, 10 + you.your_level );
dart_trap(trap_known, i, beam, false);
break;
case TRAP_AXE:
- beam.name = "n axe";
+ beam.name += (branchtype? "" : "n");
+ beam.name += " axe";
beam.damage = dice_def( 1, 15 + you.your_level );
dart_trap(trap_known, i, beam, false);
break;
@@ -336,10 +358,18 @@ void handle_traps(char trt, int i, bool trap_known)
you_teleport_now( true );
break;
- case TRAP_AMNESIA:
- mpr("You feel momentarily disoriented.");
- if (!wearing_amulet(AMU_CLARITY))
- forget_map(random2avg(100, 2));
+ case TRAP_ALARM:
+ if (silenced(you.x_pos, you.y_pos))
+ {
+ if (trap_known)
+ mpr("The alarm is silenced.");
+ else
+ grd[you.x_pos][you.y_pos] = DNGN_UNDISCOVERED_TRAP;
+ return;
+ }
+
+ noisy(12, you.x_pos, you.y_pos, "An alarm trap emits a blaring wail!");
+
break;
case TRAP_BLADE:
@@ -359,7 +389,6 @@ void handle_traps(char trt, int i, bool trap_known)
break;
case TRAP_NET:
-
if (trap_known && one_chance_in(3))
mpr("A net swings high above you.");
else
@@ -383,6 +412,42 @@ void handle_traps(char trt, int i, bool trap_known)
env.trap[i].type = TRAP_UNASSIGNED;
}
break;
+
+ // If we don't trigger the shaft, and the player doesn't
+ // already know about it, don't let him/her notice it.
+ case TRAP_SHAFT:
+ {
+ // Paranoia
+ if (!is_valid_shaft_level())
+ {
+ if (trap_known)
+ mpr("The shaft disappears in a puff of logic!");
+
+ grd[env.trap[i].x][env.trap[i].y] = DNGN_FLOOR;
+ env.trap[i].type = TRAP_UNASSIGNED;
+ return;
+ }
+
+ if (!you.will_trigger_shaft())
+ {
+ if (trap_known && !you.airborne())
+ mpr("You don't fall through the shaft..");
+
+ if (!trap_known)
+ grd[you.x_pos][you.y_pos] = DNGN_UNDISCOVERED_TRAP;
+
+ return;
+ }
+
+ if (!you.do_shaft())
+ if (!trap_known)
+ {
+ grd[you.x_pos][you.y_pos] = DNGN_UNDISCOVERED_TRAP;
+ return;
+ }
+
+ break;
+ }
case TRAP_ZOT:
default:
@@ -579,12 +644,11 @@ static int damage_or_escape_net(int hold)
damage += 2;
else if (you.has_usable_claws())
{
- if (you.species == SP_TROLL || you.species == SP_GHOUL)
- damage += 2;
- else if (you.mutation[MUT_CLAWS] == 1)
+ int level = you.has_claws();
+ if (level == 1)
damage += coinflip();
else
- damage += you.mutation[MUT_CLAWS] - 1;
+ damage += level - 1;
}
// Berserkers get a fighting bonus
@@ -759,7 +823,6 @@ bool trap_item(object_class_type 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;
@@ -801,6 +864,15 @@ bool trap_item(object_class_type base_type, char sub_type,
}
} // end of if igrd != NON_ITEM
+ // give appropriate racial flag for Orcish Mines and Elven Halls
+ // should we ever allow properties of dungeon features, we could use that
+ if ( item.sub_type != MI_THROWING_NET )
+ {
+ if (you.where_are_you == BRANCH_ORCISH_MINES)
+ set_equip_race( item, ISFLAG_ORCISH );
+ else if (you.where_are_you == BRANCH_ELVEN_HALLS)
+ set_equip_race( item, ISFLAG_ELVEN );
+ }
return (!copy_item_to_grid( item, beam_x, beam_y, 1 ));
} // end trap_item()
@@ -809,8 +881,11 @@ dungeon_feature_type trap_category(trap_type type)
{
switch (type)
{
+ case TRAP_SHAFT:
+ return (DNGN_TRAP_NATURAL);
+
case TRAP_TELEPORT:
- case TRAP_AMNESIA:
+ case TRAP_ALARM:
case TRAP_ZOT:
return (DNGN_TRAP_MAGICAL);
@@ -851,3 +926,202 @@ trap_type trap_type_at_xy(int x, int y)
return (idx == -1? NUM_TRAPS : env.trap[idx].type);
}
+bool is_valid_shaft_level(const level_id &place)
+{
+ if (place.level_type != LEVEL_DUNGEON)
+ return (false);
+
+ // disallow shafts on the first two levels
+ if (place.branch == BRANCH_MAIN_DUNGEON
+ && you.your_level < 2)
+ {
+ return (false);
+ }
+
+ // Don't generate shafts in branches where teleport control
+ // is prevented. Prevents player from going down levels without
+ // reaching stairs, and also keeps player from getting stuck
+ // on lower levels with the innability to use teleport control to
+ // get back up.
+ if (testbits(get_branch_flags(place.branch), LFLAG_NO_TELE_CONTROL))
+ {
+ return (false);
+ }
+
+ const Branch &branch = branches[place.branch];
+
+ // When generating levels, don't place a shaft on the level
+ // immediately above the bottom of a branch if that branch is
+ // significantly more dangerous than normal.
+ int min_delta = 1;
+ if (env.turns_on_level == -1 && branch.dangerous_bottom_level)
+ min_delta = 2;
+
+ return ((branch.depth - place.depth) >= min_delta);
+}
+
+static int num_traps_default(int level_number, const level_id &place)
+{
+ return random2avg(9, 2);
+}
+
+int num_traps_for_place(int level_number, const level_id &place)
+{
+ if (level_number == -1)
+ {
+ switch(place.level_type)
+ {
+ case LEVEL_DUNGEON:
+ level_number = absdungeon_depth(place.branch, place.depth);
+ break;
+ case LEVEL_ABYSS:
+ level_number = 51;
+ break;
+ case LEVEL_PANDEMONIUM:
+ level_number = 52;
+ break;
+ default:
+ level_number = you.your_level;
+ }
+ }
+
+ switch(place.level_type)
+ {
+ case LEVEL_DUNGEON:
+ if (branches[place.branch].num_traps_function != NULL)
+ return branches[place.branch].num_traps_function(level_number);
+ else
+ return num_traps_default(level_number, place);
+ case LEVEL_ABYSS:
+ return traps_abyss_number(level_number);
+ case LEVEL_PANDEMONIUM:
+ return traps_pan_number(level_number);
+ case LEVEL_LABYRINTH:
+ case LEVEL_PORTAL_VAULT:
+ ASSERT(false);
+ break;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static trap_type random_trap_default(int level_number, const level_id &place)
+{
+ trap_type type = TRAP_DART;
+
+ if ((random2(1 + level_number) > 1) && one_chance_in(4))
+ type = TRAP_NEEDLE;
+ if (random2(1 + level_number) > 3)
+ type = TRAP_SPEAR;
+ if (random2(1 + level_number) > 5)
+ type = TRAP_AXE;
+
+ // Note we're boosting arrow trap numbers by moving it
+ // down the list, and making spear and axe traps rarer.
+ if (type == TRAP_DART?
+ random2(1 + level_number) > 2
+ : one_chance_in(7))
+ type = TRAP_ARROW;
+
+ if ((type == TRAP_DART || type == TRAP_ARROW) && one_chance_in(15))
+ type = TRAP_NET;
+
+ if (random2(1 + level_number) > 7)
+ type = TRAP_BOLT;
+ if (random2(1 + level_number) > 11)
+ type = TRAP_BLADE;
+
+ if ((random2(1 + level_number) > 14 && one_chance_in(3))
+ || (place.branch == BRANCH_HALL_OF_ZOT &&
+ place.level_type == LEVEL_DUNGEON && coinflip()))
+ {
+ type = TRAP_ZOT;
+ }
+
+ if (one_chance_in(50) && is_valid_shaft_level(place))
+ type = TRAP_SHAFT;
+ if (one_chance_in(20))
+ type = TRAP_TELEPORT;
+ if (one_chance_in(40))
+ type = TRAP_ALARM;
+
+ return (type);
+}
+
+trap_type random_trap_for_place(int level_number, const level_id &place)
+{
+ if (level_number == -1)
+ {
+ switch(place.level_type)
+ {
+ case LEVEL_DUNGEON:
+ level_number = absdungeon_depth(place.branch, place.depth);
+ break;
+ case LEVEL_ABYSS:
+ level_number = 51;
+ break;
+ case LEVEL_PANDEMONIUM:
+ level_number = 52;
+ break;
+ default:
+ level_number = you.your_level;
+ }
+ }
+
+ switch(place.level_type)
+ {
+ case LEVEL_DUNGEON:
+ if (branches[place.branch].rand_trap_function != NULL)
+ return branches[place.branch].rand_trap_function(level_number);
+ else
+ return random_trap_default(level_number, place);
+ case LEVEL_ABYSS:
+ return traps_abyss_type(level_number);
+ case LEVEL_PANDEMONIUM:
+ return traps_pan_type(level_number);
+ case LEVEL_LABYRINTH:
+ case LEVEL_PORTAL_VAULT:
+ ASSERT(false);
+ break;
+ default:
+ return random_trap_default(level_number, place);
+ }
+ return NUM_TRAPS;
+}
+
+int traps_zero_number(int level_number)
+{
+ return 0;
+}
+
+int traps_pan_number(int level_number)
+{
+ return num_traps_default(level_number, level_id(LEVEL_PANDEMONIUM));
+}
+
+trap_type traps_pan_type(int level_number)
+{
+ return random_trap_default(level_number, level_id(LEVEL_PANDEMONIUM));
+}
+
+int traps_abyss_number(int level_number)
+{
+ return num_traps_default(level_number, level_id(LEVEL_ABYSS));
+}
+
+trap_type traps_abyss_type(int level_number)
+{
+ return random_trap_default(level_number, level_id(LEVEL_ABYSS));
+}
+
+int traps_lab_number(int level_number)
+{
+ return num_traps_default(level_number, level_id(LEVEL_LABYRINTH));
+}
+
+trap_type traps_lab_type(int level_number)
+{
+ return random_trap_default(level_number, level_id(LEVEL_LABYRINTH));
+}
diff --git a/crawl-ref/source/traps.h b/crawl-ref/source/traps.h
index f8cbec2629..1853cf5313 100644
--- a/crawl-ref/source/traps.h
+++ b/crawl-ref/source/traps.h
@@ -14,6 +14,7 @@
#define TRAPS_H
#include "enum.h"
+#include "travel.h"
struct dist;
struct bolt;
@@ -34,7 +35,7 @@ void free_self_from_net(void);
/* ***********************************************************************
* called from: acr - misc
* *********************************************************************** */
-void handle_traps(char trt, int i, bool trap_known);
+void handle_traps(trap_type trt, int i, bool trap_known);
int get_trapping_net(int x, int y, bool trapped = true);
void mark_net_trapping(int x, int y);
void monster_caught_in_net(monsters *mon, bolt &pbolt);
@@ -63,4 +64,22 @@ dungeon_feature_type trap_category(trap_type type);
int trap_at_xy(int x, int y);
trap_type trap_type_at_xy(int x, int y);
+bool is_valid_shaft_level(const level_id &place = level_id::current());
+
+int num_traps_for_place(int level_number = -1,
+ const level_id &place = level_id::current());
+trap_type random_trap_for_place(int level_number = -1,
+ const level_id &place = level_id::current());
+
+int traps_zero_number(int level_number = -1);
+
+int traps_pan_number(int level_number = -1);
+trap_type traps_pan_type(int level_number = -1);
+
+int traps_abyss_number(int level_number = -1);
+trap_type traps_abyss_type(int level_number = -1);
+
+int traps_lab_number(int level_number = -1);
+trap_type traps_lab_type(int level_number = -1);
+
#endif
diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc
index 3295f550a3..c6b3ccbb53 100644
--- a/crawl-ref/source/travel.cc
+++ b/crawl-ref/source/travel.cc
@@ -931,7 +931,10 @@ void explore_pickup_event(int did_pickup, int tried_pickup)
"Could not pick up %s here, shall I ignore %s? ",
tried_pickup == 1? "an item" : "some items",
tried_pickup == 1? "it" : "them");
- if (yesno(prompt.c_str(), true, 'y', true, false))
+ // Make Escape => 'n' and stop run.
+ explicit_keymap map;
+ map[ESCAPE] = 'n';
+ if (yesno(prompt.c_str(), true, 'y', true, false, false, &map))
{
mark_items_non_pickup_at(you.pos());
// Don't stop explore.
@@ -3896,7 +3899,7 @@ void explore_discoveries::found_item(const coord_def &pos, const item_def &i)
es_flags |= ES_ITEM;
}
-// Expensive O(n2) duplicate search, but we can live with that.
+// Expensive O(n^2) duplicate search, but we can live with that.
template <class citer> bool explore_discoveries::has_duplicates(
citer begin, citer end) const
{
diff --git a/crawl-ref/source/tutorial.cc b/crawl-ref/source/tutorial.cc
index c83906e634..60cbe65b79 100644
--- a/crawl-ref/source/tutorial.cc
+++ b/crawl-ref/source/tutorial.cc
@@ -1953,6 +1953,7 @@ bool tutorial_feat_interesting(dungeon_feature_type feat)
case DNGN_GRANITE_STATUE:
case DNGN_TRAP_MAGICAL:
case DNGN_TRAP_MECHANICAL:
+ case DNGN_TRAP_NATURAL:
case DNGN_STONE_STAIRS_DOWN_I:
case DNGN_STONE_STAIRS_DOWN_II:
case DNGN_STONE_STAIRS_DOWN_III:
@@ -1997,6 +1998,12 @@ void tutorial_describe_feature(dungeon_feature_type feat)
Options.tutorial_events[TUT_SEEN_TRAP] = 0;
break;
+ case DNGN_TRAP_NATURAL: // only shafts for now
+ ostr << "The dungeon contains a number of natural obstacles such "
+ "as shafts, which lead one or two levels down.";
+ Options.tutorial_events[TUT_SEEN_TRAP] = 0;
+ break;
+
case DNGN_STONE_STAIRS_DOWN_I:
case DNGN_STONE_STAIRS_DOWN_II:
case DNGN_STONE_STAIRS_DOWN_III:
diff --git a/crawl-ref/source/unrand.h b/crawl-ref/source/unrand.h
index 57c2b0f0fc..375d2a128f 100644
--- a/crawl-ref/source/unrand.h
+++ b/crawl-ref/source/unrand.h
@@ -1114,7 +1114,7 @@
"blowgun of the Assassin", "tiny blowgun",
OBJ_WEAPONS, WPN_BLOWGUN, +6, +6, WHITE,
{
- SPWPN_VENOM, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 1, 0, 0, 0, 0, // turn invisible
0, 0, 0, 0, 0,
diff --git a/crawl-ref/source/util/levcomp.lpp b/crawl-ref/source/util/levcomp.lpp
index 74bf14732a..4d7e0278bd 100644
--- a/crawl-ref/source/util/levcomp.lpp
+++ b/crawl-ref/source/util/levcomp.lpp
@@ -194,9 +194,13 @@ CHANCE: return CHANCE;
WEIGHT: return CHANCE;
FLAGS: { BEGIN(KEYWORDS); return TAGS; }
TAGS: { BEGIN(KEYWORDS); return TAGS; }
+LFLAGS: { BEGIN(ARGUMENT); return LFLAGS; }
+BFLAGS: { BEGIN(ARGUMENT); return BFLAGS; }
SUBST: { BEGIN(ITEM_LIST); return SUBST; }
NSUBST: { BEGIN(ITEM_LIST); return NSUBST; }
COLOUR: { BEGIN(ITEM_LIST); return COLOUR; }
+FLOORCOL: { BEGIN(ARGUMENT); return FLOORCOL; }
+ROCKCOL: { BEGIN(ARGUMENT); return ROCKCOL; }
MONS: { BEGIN(MNAME); return MONS; }
ITEM: { BEGIN(ITEM_LIST); return ITEM; }
MARKER: { BEGIN(TOEOL); return MARKER; }
@@ -205,6 +209,7 @@ SHUFFLE: { BEGIN(ITEM_LIST); return SHUFFLE; }
KFEAT: { BEGIN(ARGUMENT); return KFEAT; }
KITEM: { BEGIN(ARGUMENT); return KITEM; }
KMONS: { BEGIN(ARGUMENT); return KMONS; }
+KMASK: { BEGIN(ARGUMENT); return KMASK; }
, return COMMA;
diff --git a/crawl-ref/source/util/levcomp.ypp b/crawl-ref/source/util/levcomp.ypp
index 199fb9e31b..614a357bbc 100644
--- a/crawl-ref/source/util/levcomp.ypp
+++ b/crawl-ref/source/util/levcomp.ypp
@@ -52,9 +52,10 @@ level_range set_range(const char *s, int start, int end)
/* Two harmless shift/reduce conflicts */
%expect 2
-%token <i> DEFAULT_DEPTH SHUFFLE SUBST TAGS KFEAT KITEM KMONS
+%token <i> DEFAULT_DEPTH SHUFFLE SUBST TAGS KFEAT KITEM KMONS KMASK
%token <i> NAME DEPTH ORIENT PLACE CHANCE MONS ITEM MARKER COLOUR
-%token <i> PRELUDE MAIN VALIDATE VETO NSUBST WELCOME
+%token <i> PRELUDE MAIN VALIDATE VETO NSUBST WELCOME LFLAGS BFLAGS
+%token <i> FLOORCOL ROCKCOL
%token <i> COMMA INTEGER CHARACTER
@@ -159,11 +160,16 @@ metaline : place
| subst
| nsubst
| colour
+ | floorcol
+ | rockcol
| shuffle
| tags
+ | lflags
+ | bflags
| kfeat
| kitem
| kmons
+ | kmask
| main_lua
| prelude_lua
| validate_lua
@@ -253,6 +259,15 @@ kitem : KITEM { }
quote_lua_string($2).c_str()));
}
+kmask : KMASK { }
+ | KMASK STRING
+ {
+ lc_map.main.add(
+ yylineno,
+ make_stringf("kmask(\"%s\")",
+ quote_lua_string($2).c_str()));
+ }
+
shuffle : SHUFFLE shuffle_specifiers {}
;
@@ -284,6 +299,24 @@ tagstring : STRING
}
;
+lflags : LFLAGS STRING
+ {
+ lc_map.main.add(
+ yylineno,
+ make_stringf("lflags(\"%s\")",
+ quote_lua_string($2).c_str()));
+ }
+ ;
+
+bflags : BFLAGS STRING
+ {
+ lc_map.main.add(
+ yylineno,
+ make_stringf("bflags(\"%s\")",
+ quote_lua_string($2).c_str()));
+ }
+ ;
+
marker : MARKER
{
lc_map.main.add(yylineno, "marker(");
@@ -316,6 +349,24 @@ mspec_segment : STRING
colour : COLOUR colour_specifiers { }
;
+floorcol : FLOORCOL { }
+ | FLOORCOL STRING
+ {
+ lc_map.main.add(
+ yylineno,
+ make_stringf("floor_colour(\"%s\")",
+ quote_lua_string($2).c_str()));
+ }
+
+rockcol : ROCKCOL { }
+ | ROCKCOL STRING
+ {
+ lc_map.main.add(
+ yylineno,
+ make_stringf("rock_colour(\"%s\")",
+ quote_lua_string($2).c_str()));
+ }
+
colour_specifiers : colour_specifier { }
| colour_specifiers COMMA colour_specifier { }
;
diff --git a/crawl-ref/source/version.h b/crawl-ref/source/version.h
index c99e6ac1b0..78e8536ca9 100644
--- a/crawl-ref/source/version.h
+++ b/crawl-ref/source/version.h
@@ -37,8 +37,8 @@
#define CRAWL "Dungeon Crawl Stone Soup"
-#define VER_NUM "0.3.2"
-#define VER_QUAL ""
+#define VER_NUM "0.4"
+#define VER_QUAL "-svn"
// last updated 07august2001 {mv}
/* ***********************************************************************
@@ -58,6 +58,6 @@
#define VERSION_DETAIL BUILD_DATE
#endif
-#define SAVE_MAJOR_VERSION 3
+#define SAVE_MAJOR_VERSION 4
#endif
diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc
index 2cf125566c..121d9ca833 100644
--- a/crawl-ref/source/view.cc
+++ b/crawl-ref/source/view.cc
@@ -36,6 +36,7 @@
#include "externs.h"
+#include "branch.h"
#include "command.h"
#include "cio.h"
#include "cloud.h"
@@ -43,6 +44,7 @@
#include "database.h"
#include "debug.h"
#include "delay.h"
+#include "dgnevent.h"
#include "direct.h"
#include "dungeon.h"
#include "format.h"
@@ -65,6 +67,7 @@
#include "terrain.h"
#include "travel.h"
#include "tutorial.h"
+#include "xom.h"
// These are hidden from the rest of the world... use the functions
// below to get information about the map grid.
@@ -218,6 +221,8 @@ bool is_terrain_changed( int x, int y )
void set_terrain_changed( int x, int y )
{
env.map[x][y].flags |= MAP_CHANGED_FLAG;
+
+ dungeon_events.fire_position_event(DET_FEAT_CHANGE, coord_def(x, y));
}
void set_terrain_mapped( int x, int y )
@@ -621,12 +626,18 @@ int get_mons_colour(const monsters *mons)
{
col |= COLFLAG_MAYSTAB;
}
- else if (Options.heap_brand != CHATTR_NORMAL
- && mons_is_stationary(mons)
- && in_bounds(mons->x, mons->y)
- && igrd[mons->x][mons->y] != NON_ITEM)
+ else if (mons_is_stationary(mons))
{
- col |= COLFLAG_ITEM_HEAP;
+ if (Options.stair_item_brand != CHATTR_NORMAL
+ && grid_stair_direction(grd(mons->pos())) != CMD_NO_CMD)
+ {
+ col |= COLFLAG_STAIR_ITEM;
+ }
+ else if (Options.heap_brand != CHATTR_NORMAL
+ && igrd(mons->pos()) != NON_ITEM)
+ {
+ col |= COLFLAG_ITEM_HEAP;
+ }
}
// Backlit monsters are fuzzy and override brands.
@@ -682,7 +693,7 @@ void beogh_follower_convert(monsters *monster, bool orc_hit)
return;
}
beogh_convert_orc(monster, orc_hit);
- stop_running();
+ stop_running();
}
}
else if (is_orc
@@ -709,6 +720,28 @@ void beogh_follower_convert(monsters *monster, bool orc_hit)
}
}
+static void handle_seen_interrupt(monsters* monster)
+{
+ activity_interrupt_data aid(monster);
+ if (monster->seen_context != "")
+ aid.context = monster->seen_context;
+ else if (testbits(monster->flags, MF_WAS_IN_VIEW))
+ aid.context = "already seen";
+ else
+ aid.context = "newly seen";
+
+ if (!mons_is_safe( static_cast<const monsters*>(monster) )
+ && !mons_class_flag( monster->type, M_NO_EXP_GAIN )
+ && !mons_is_mimic( monster->type ))
+ {
+ interrupt_activity( AI_SEE_MONSTER, aid );
+ }
+ seen_monster( monster );
+
+ // Monster was viewed this turn
+ monster->flags |= MF_WAS_IN_VIEW;
+}
+
void handle_monster_shouts(monsters* monster, bool force)
{
if (!force
@@ -876,6 +909,19 @@ void handle_monster_shouts(monsters* monster, bool force)
else if (param == "SOUND")
channel = MSGCH_SOUND;
+ // Monster must come up from being submerged if it wants to
+ // shout.
+ if (mons_is_submerged(monster))
+ {
+ monster->del_ench(ENCH_SUBMERGED);
+ if (you.can_see(monster))
+ {
+ monster->seen_context = "bursts forth shouting";
+ // Give interrupt message before shout message.
+ handle_seen_interrupt(monster);
+ }
+ }
+
msg::streams(channel) << msg << std::endl;
}
@@ -956,6 +1002,8 @@ void monster_grid(bool do_updates)
void fire_monster_alerts()
{
+ int num_hostile = 0;
+
for (int s = 0; s < MAX_MONSTERS; s++)
{
monsters *monster = &menv[s];
@@ -966,22 +1014,10 @@ void fire_monster_alerts()
|| mons_was_seen_this_turn(monster))
&& !mons_is_submerged( monster ))
{
- activity_interrupt_data aid(monster);
- if (testbits(monster->flags, MF_WAS_IN_VIEW))
- aid.context = "already seen";
- else
- aid.context = "newly seen";
-
- if (!mons_is_safe( static_cast<const monsters*>(monster) )
- && !mons_class_flag( monster->type, M_NO_EXP_GAIN )
- && !mons_is_mimic( monster->type ))
- {
- interrupt_activity( AI_SEE_MONSTER, aid );
- }
- seen_monster( monster );
+ handle_seen_interrupt(monster);
- // Monster was viewed this turn
- monster->flags |= MF_WAS_IN_VIEW;
+ if (mons_attitude(monster) == ATT_HOSTILE)
+ num_hostile++;
}
else
{
@@ -994,6 +1030,22 @@ void fire_monster_alerts()
// Monster was not viewed this turn
monster->flags &= ~MF_WAS_IN_VIEW;
}
+ monster->seen_context = "";
+ }
+
+ // Xom thinks it's hilarious the way the player picks up an ever
+ // growing entourage of monsters while running through the Abyss.
+ // To approximate this, if the number of hostile monsters in view
+ // is greater than it ever was for this particular trip to the
+ // Abyss, Xom is stimulated in proprotion to the number of
+ // hostile monsters. Thus if the entourage doesn't grow, then
+ // Xom becomes bored.
+ if (you.level_type == LEVEL_ABYSS
+ && you.attribute[ATTR_ABYSS_ENTOURAGE] < num_hostile)
+ {
+ you.attribute[ATTR_ABYSS_ENTOURAGE] = num_hostile;
+
+ xom_is_stimulated(16 * num_hostile);
}
monsters_seen_this_turn.clear();
@@ -1267,13 +1319,25 @@ bool noisy( int loudness, int nois_x, int nois_y, const char *msg )
const int dist = loudness * loudness;
+ const int player_distance =
+ distance( you.x_pos, you.y_pos, nois_x, nois_y );
// message the player
- if (distance( you.x_pos, you.y_pos, nois_x, nois_y ) <= dist
- && player_can_hear( nois_x, nois_y ))
+ if (player_distance <= dist && player_can_hear( nois_x, nois_y ))
{
if (msg)
mpr( msg, MSGCH_SOUND );
+ you.check_awaken(dist - player_distance);
+
+ if (loudness >= 20 && you.duration[DUR_BEHELD])
+ {
+ mprf("For a moment, you cannot hear the mermaid%s!",
+ you.beheld_by.size() == 1? "" : "s");
+ mpr("You break out of your daze!", MSGCH_DURATION);
+ you.duration[DUR_BEHELD] = 0;
+ you.beheld_by.clear();
+ }
+
ret = true;
}
@@ -1962,7 +2026,7 @@ static bool superior_ray(int shortest, int imbalance,
bool find_ray( int sourcex, int sourcey, int targetx, int targety,
bool allow_fallback, ray_def& ray, int cycle_dir,
- bool find_shortest )
+ bool find_shortest, bool ignore_solid )
{
int cellray, inray;
const int signx = ((targetx - sourcex >= 0) ? 1 : -1);
@@ -2004,7 +2068,7 @@ bool find_ray( int sourcex, int sourcey, int targetx, int targety,
{
const int xi = signx * ray_coord_x[inray + cur_offset];
const int yi = signy * ray_coord_y[inray + cur_offset];
- if (inray < cellray
+ if (inray < cellray && !ignore_solid
&& grid_is_solid(grd[sourcex + xi][sourcey + yi]))
{
blocked = true;
@@ -2122,6 +2186,48 @@ bool find_ray( int sourcex, int sourcey, int targetx, int targety,
return false;
}
+// Count the number of matching features between two points along
+// a beam-like path; the path will pass through solid features.
+// By default, it exludes enpoints from the count.
+int num_feats_between(int sourcex, int sourcey, int targetx, int targety,
+ dungeon_feature_type min_feat,
+ dungeon_feature_type max_feat,
+ bool exclude_endpoints)
+{
+ ray_def ray;
+ int count = 0;
+ int max_dist = grid_distance(sourcex, sourcey, targetx, targety);
+
+ ray.fullray_idx = -1; // to quiet valgrind
+ find_ray( sourcex, sourcey, targetx, targety, true, ray, 0, true, true );
+
+ if (exclude_endpoints && ray.x() == sourcex && ray.y() == sourcey)
+ {
+ ray.advance(true);
+ max_dist--;
+ }
+
+ int dist = 0;
+ while (dist++ <= max_dist)
+ {
+ dungeon_feature_type feat = grd[ray.x()][ray.y()];
+
+ if (feat >= min_feat && feat <= max_feat)
+ count++;
+
+ if (ray.x() == targetx && ray.y() == targety)
+ {
+ if (exclude_endpoints && feat >= min_feat && feat <= max_feat)
+ count--;
+
+ break;
+ }
+ ray.advance(true);
+ }
+
+ return count;
+}
+
// The rule behind LOS is:
// Two cells can see each other if there is any line from some point
// of the first to some point of the second ("generous" LOS.)
@@ -2160,7 +2266,8 @@ bool find_ray( int sourcex, int sourcey, int targetx, int targety,
// Smoke will now only block LOS after two cells of smoke. This is
// done by updating with a second array.
void losight(FixedArray < unsigned int, 19, 19 > &sh,
- FixedArray < dungeon_feature_type, 80, 70 > &gr, int x_p, int y_p)
+ FixedArray < dungeon_feature_type, 80, 70 > &gr, int x_p, int y_p,
+ bool clear_walls_block)
{
raycast();
// go quadrant by quadrant
@@ -2197,7 +2304,8 @@ void losight(FixedArray < unsigned int, 19, 19 > &sh,
continue;
// if this cell is opaque...
- if ( grid_is_opaque(gr[realx][realy]) )
+ if ( grid_is_opaque(gr[realx][realy])
+ || (clear_walls_block && grid_is_wall(gr[realx][realy])))
{
// then block the appropriate rays
for ( unsigned int i = 0; i < num_words; ++i )
@@ -2404,7 +2512,7 @@ bool is_feature(int feature, int x, int y)
{
case DNGN_TRAP_MECHANICAL:
case DNGN_TRAP_MAGICAL:
- case DNGN_TRAP_III:
+ case DNGN_TRAP_NATURAL:
return true;
default:
return false;
@@ -2572,13 +2680,13 @@ static void draw_level_map(int start_x, int start_y, bool travel_mode)
for (int screen_y = 0; screen_y < num_lines; screen_y++)
{
- for (int screen_x = 0; screen_x < num_cols - 1; screen_x++)
+ for (int screen_x = 0; screen_x < num_cols; screen_x++)
{
screen_buffer_t colour = DARKGREY;
coord_def c(start_x + screen_x, start_y + screen_y);
- if (!in_bounds(c))
+ if (!map_bounds(c))
{
buffer2[bufcount2 + 1] = DARKGREY;
buffer2[bufcount2] = 0;
@@ -2618,7 +2726,7 @@ static void draw_level_map(int start_x, int start_y, bool travel_mode)
bufcount2 += 2;
}
}
- puttext(1, top, num_cols - 1, top + num_lines - 1, buffer2);
+ puttext(1, top, num_cols, top + num_lines - 1, buffer2);
}
static void reset_travel_colours(std::vector<coord_def> &features)
@@ -2634,7 +2742,7 @@ static void reset_travel_colours(std::vector<coord_def> &features)
// 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, bool travel_mode )
+void show_map( coord_def &spec_place, bool travel_mode )
{
cursor_control ccon(!Options.use_fake_cursor);
int i, j;
@@ -2743,6 +2851,9 @@ void show_map( FixedVector<int, 2> &spec_place, bool travel_mode )
break;
case CONTROL('F'):
+ forget_map(100, true);
+ break;
+
case CONTROL('W'):
travel_cache.add_waypoint(start_x + curs_x - 1,
start_y + curs_y - 1);
@@ -2939,8 +3050,7 @@ void show_map( FixedVector<int, 2> &spec_place, bool travel_mode )
if (cme.left_clicked() && in_bounds(grdp))
{
- spec_place[0] = grdp.x;
- spec_place[1] = grdp.y;
+ spec_place = grdp;
map_alive = false;
}
else if (cme.scroll_up())
@@ -2974,12 +3084,23 @@ void show_map( FixedVector<int, 2> &spec_place, bool travel_mode )
}
else
{
- spec_place[0] = x;
- spec_place[1] = y;
+ spec_place = coord_def(x, y);
map_alive = false;
break;
}
}
+
+#ifdef WIZARD
+ case 'T':
+ {
+ if (!you.wizard)
+ break;
+ you.moveto(start_x + curs_x - 1, start_y + curs_y - 1);
+ map_alive = false;
+ break;
+ }
+#endif
+
default:
move_x = 0;
move_y = 0;
@@ -3054,8 +3175,8 @@ bool magic_mapping(int map_radius, int proportion, bool suppress_msg,
bool force)
{
if (!force &&
- ((you.level_type == LEVEL_ABYSS) ||
- (you.level_type == LEVEL_LABYRINTH && you.species != SP_MINOTAUR)))
+ (testbits(env.level_flags, LFLAG_NO_MAGIC_MAP)
+ || testbits(get_branch_flags(), BFLAG_NO_MAGIC_MAP)))
{
if (!suppress_msg)
mpr("You feel momentarily disoriented.");
@@ -3201,6 +3322,33 @@ bool see_grid( int grx, int gry )
return (false);
} // end see_grid()
+// answers the question: "Would a grid be within character's line of sight,
+// even if all translucent/clear walls were made opaque?"
+bool see_grid_no_trans( int grx, int gry )
+{
+ // rare case: can player see self? (of course!)
+ if (grx == you.x_pos && gry == you.y_pos)
+ return (true);
+
+ // check no_trans_show array
+ if (grid_distance( grx, gry, you.x_pos, you.y_pos ) < 9)
+ {
+ const int ex = grx - you.x_pos + 9;
+ const int ey = gry - you.y_pos + 9;
+
+ if (env.no_trans_show[ex][ey])
+ return (true);
+ }
+
+ return (false);
+}
+
+// Is the grid visible, but a translucent wall is in the way?
+bool trans_wall_blocking( int grx, int gry )
+{
+ return see_grid(grx, gry) && !see_grid_no_trans(grx, gry);
+}
+
static const unsigned table[ NUM_CSET ][ NUM_DCHAR_TYPES ] =
{
// CSET_ASCII
@@ -3325,6 +3473,15 @@ void init_feature_table( void )
Feature[i].magic_symbol = Options.char_table[ DCHAR_WALL_MAGIC ];
break;
+ case DNGN_CLEAR_ROCK_WALL:
+ case DNGN_CLEAR_STONE_WALL:
+ case DNGN_CLEAR_PERMAROCK_WALL:
+ Feature[i].dchar = DCHAR_WALL;
+ Feature[i].magic_symbol = Options.char_table[ DCHAR_WALL_MAGIC ];
+ Feature[i].colour = LIGHTCYAN;
+ break;
+
+
case DNGN_OPEN_DOOR:
Feature[i].dchar = DCHAR_DOOR_OPEN;
Feature[i].colour = LIGHTGREY;
@@ -3424,10 +3581,10 @@ void init_feature_table( void )
Feature[i].map_colour = MAGENTA;
break;
- case DNGN_TRAP_III:
- Feature[i].colour = LIGHTGREY;
+ case DNGN_TRAP_NATURAL:
+ Feature[i].colour = BROWN;
Feature[i].dchar = DCHAR_TRAP;
- Feature[i].map_colour = LIGHTGREY;
+ Feature[i].map_colour = BROWN;
break;
case DNGN_UNDISCOVERED_TRAP:
@@ -4080,6 +4237,10 @@ void viewwindow(bool draw_it, bool do_updates)
losight( env.show, grd, you.x_pos, you.y_pos ); // must be done first
+ // What would be visible, if all of the translucent walls were
+ // made opaque.
+ losight( env.no_trans_show, grd, you.x_pos, you.y_pos, true );
+
env.show_col.init(LIGHTGREY);
Show_Backup.init(0);
@@ -4092,7 +4253,8 @@ void viewwindow(bool draw_it, bool do_updates)
cursor_control cs(false);
const bool map = player_in_mappable_area();
- const bool draw = !you.running || Options.travel_delay > -1;
+ const bool draw =
+ (!you.running || Options.travel_delay > -1) && !you.asleep();
int bufcount = 0;
int flash_colour = you.flash_colour;
diff --git a/crawl-ref/source/view.h b/crawl-ref/source/view.h
index 3d13f5b7be..f51d6fcd7b 100644
--- a/crawl-ref/source/view.h
+++ b/crawl-ref/source/view.h
@@ -56,6 +56,11 @@ enum element_type
EC_STONE, // colour of the area's stone
EC_MIST, // colour of mist
EC_SHIMMER_BLUE, // shimmering colours of blue.
+ EC_DECAY, // colour of decay/swamp
+ EC_SILVER, // colour of silver
+ EC_GOLD, // colour of gold
+ EC_IRON, // colour of iron
+ EC_BONE, // colour of bone
EC_RANDOM // any colour (except BLACK)
};
@@ -63,6 +68,7 @@ enum element_type
void init_char_table(char_set_type set);
void init_feature_table();
+void init_monsters_seens();
/* called from: beam - fight */
void beogh_follower_convert(monsters *monster, bool orc_hit = false);
@@ -96,7 +102,7 @@ void find_features(const std::vector<coord_def>& features,
* *********************************************************************** */
void losight(FixedArray<unsigned int, ENV_SHOW_DIAMETER, ENV_SHOW_DIAMETER>& sh,
FixedArray<dungeon_feature_type, GXM, GYM>& gr,
- int x_p, int y_p);
+ int x_p, int y_p, bool clear_walls_block = false);
bool magic_mapping(int map_radius, int proportion, bool suppress_msg,
@@ -115,7 +121,7 @@ void handle_monster_shouts(monsters* monster, bool force = false);
/* ***********************************************************************
* called from: acr - spells3
* *********************************************************************** */
-void show_map( FixedVector<int, 2>& spec_place, bool travel_mode );
+void show_map( coord_def &spec_place, bool travel_mode );
// last updated 19jun2000 (gdl)
/* ***********************************************************************
@@ -187,6 +193,14 @@ void add_cset_override(char_set_type set, const std::string &overrides);
bool see_grid( int grx, int gry );
inline bool see_grid(const coord_def &p) { return see_grid(p.x, p.y); }
+bool see_grid_no_trans( int grx, int gry );
+inline bool see_grid_no_trans(const coord_def &p)
+{
+ return see_grid_no_trans(p.x, p.y);
+}
+
+bool trans_wall_blocking( int grx, int gry );
+
std::string screenshot(bool fullscreen = false);
dungeon_char_type get_feature_dchar( dungeon_feature_type feat );
@@ -201,7 +215,12 @@ void fire_monster_alerts();
struct ray_def;
bool find_ray( int sourcex, int sourcey, int targetx, int targety,
bool allow_fallback, ray_def& ray, int cycle_dir = 0,
- bool find_shortest = false );
+ bool find_shortest = false, bool ignore_solid = false );
+
+int num_feats_between(int sourcex, int sourcey, int targetx, int targety,
+ dungeon_feature_type min_feat,
+ dungeon_feature_type max_feat,
+ bool exclude_endpoints = true);
dungeon_char_type dchar_by_name(const std::string &name);
diff --git a/crawl-ref/source/xom.cc b/crawl-ref/source/xom.cc
index f35711419e..60b81fe58a 100644
--- a/crawl-ref/source/xom.cc
+++ b/crawl-ref/source/xom.cc
@@ -3,12 +3,13 @@
* Summary: All things Xomly
* Written by: Zooko
*
- * Modified for Crawl Reference by $Author: haranp $ on $Date: 2007-05-15T17:02:30.826843Z $
+ * Modified for Crawl Reference by $Author$ on $Date$
*/
#include "AppHdr.h"
#include "beam.h"
+#include "branch.h"
#include "effects.h"
#include "it_use2.h"
#include "items.h"
@@ -21,12 +22,26 @@
#include "mutation.h"
#include "ouch.h"
#include "player.h"
+#include "randart.h"
#include "religion.h"
#include "spells3.h"
#include "spl-cast.h"
#include "spl-util.h"
+#include "state.h"
#include "stuff.h"
#include "view.h"
+#include "xom.h"
+
+#if DEBUG_RELIGION
+# define DEBUG_DIAGNOSTICS 1
+# define DEBUG_GIFTS 1
+#endif
+
+#if DEBUG_XOM
+# define DEBUG_DIAGNOSTICS 1
+# define DEBUG_RELIGION 1
+# define DEBUG_GIFTS 1
+#endif
// Which spell? First I copied all spells from you_spells(), then I
// filtered some out (especially conjurations). Then I sorted them in
@@ -111,32 +126,92 @@ bool xom_is_nice()
return (you.gift_timeout > 0 && you.piety > 100) || coinflip();
}
-void xom_is_stimulated(int maxinterestingness)
+static const char* xom_message_arrays[NUM_XOM_MESSAGE_TYPES][6] =
+{
+ // XM_NORMAL
+ {
+ "Xom roars with laughter!",
+ "Xom thinks this is hilarious!",
+ "Xom is highly amused!",
+ "Xom is amused.",
+ "Xom is mildly amused.",
+ "Xom is interested."
+ },
+
+ // XM_INTRIGUED
+ {
+ "Xom is fascinated!",
+ "Xom is very intrigued!",
+ "Xom is intrigued!",
+ "Xom is extremely interested.",
+ "Xom is very interested.",
+ "Xom is interested."
+ }
+};
+
+static void _xom_is_stimulated(int maxinterestingness,
+ const char* message_array[],
+ bool force_message)
{
- if (you.religion != GOD_XOM)
+ if (you.religion != GOD_XOM || maxinterestingness <= 0)
return;
- int interestingness = random2(maxinterestingness);
- if (interestingness < 12)
+
+ // Xom is not stimulated by his own acts, at least not directly.
+ if (crawl_state.which_god_acting() == GOD_XOM)
return;
+
+ int interestingness = random2(maxinterestingness);
+
+#if DEBUG_RELIGION || DEBUG_GIFTS || DEBUG_XOM
+ mprf(MSGCH_DIAGNOSTICS,
+ "Xom: maxinterestingness = %d, interestingness = %d",
+ maxinterestingness, interestingness);
+#endif
+
if (interestingness > 255)
interestingness = 255;
- if (interestingness > you.gift_timeout)
+
+ bool was_stimulated = false;
+ if (interestingness > you.gift_timeout && interestingness >= 12)
{
you.gift_timeout = interestingness;
- god_speaks(GOD_XOM,
- ((interestingness > 200) ? "Xom roars with laughter!" :
- (interestingness > 100) ? "Xom thinks this is hilarious!" :
- (interestingness > 75) ? "Xom is highly amused!" :
- (interestingness > 50) ? "Xom is amused." :
- (interestingness > 25) ? "Xom is mildly amused." :
- "Xom is interested."));
+ was_stimulated = true;
}
+
+ if (was_stimulated || force_message)
+ god_speaks(GOD_XOM,
+ ((interestingness > 200) ? message_array[5] :
+ (interestingness > 100) ? message_array[4] :
+ (interestingness > 75) ? message_array[3] :
+ (interestingness > 50) ? message_array[2] :
+ (interestingness > 25) ? message_array[1] :
+ message_array[0]));
+}
+
+void xom_is_stimulated(int maxinterestingness, xom_message_type message_type,
+ bool force_message)
+{
+ _xom_is_stimulated(maxinterestingness, xom_message_arrays[message_type],
+ force_message);
+}
+
+void xom_is_stimulated(int maxinterestingness, const std::string& message,
+ bool force_message)
+{
+ const char* message_array[6];
+
+ for (int i = 0; i < 6; i++)
+ message_array[i] = message.c_str();
+
+ _xom_is_stimulated(maxinterestingness, message_array, force_message);
}
void xom_makes_you_cast_random_spell(int sever)
{
int spellenum = sever;
+ god_acting gdact(GOD_XOM);
+
const int nxomspells = ARRAYSIZE(xom_spells);
if (spellenum >= nxomspells)
spellenum = nxomspells - 1;
@@ -145,7 +220,7 @@ void xom_makes_you_cast_random_spell(int sever)
god_speaks(GOD_XOM, "Xom's power flows through you!");
-#if DEBUG_DIAGNOSTICS
+#if DEBUG_DIAGNOSTICS || DEBUG_RELIGION || DEBUG_XOM
mprf(MSGCH_DIAGNOSTICS,
"Xom_acts();spell: %d, spellenum: %d", spell, spellenum);
#endif
@@ -167,6 +242,8 @@ static void xom_make_item(object_class_type base,
return;
}
+ god_acting gdact(GOD_XOM);
+
move_item_to_grid( &thing_created, you.x_pos, you.y_pos );
canned_msg(MSG_SOMETHING_APPEARS);
stop_running();
@@ -199,11 +276,14 @@ static object_class_type get_unrelated_wield_class(object_class_type ref)
(temp_rand == 1) ? OBJ_STAVES :
OBJ_MISCELLANY;
}
+
return (objtype);
}
static bool xom_annoyance_gift(int power)
{
+ god_acting gdact(GOD_XOM);
+
if (coinflip() && player_in_a_dangerous_place())
{
const item_def *weapon = you.weapon();
@@ -271,6 +351,7 @@ static bool xom_annoyance_gift(int power)
return (true);
}
}
+
return (false);
}
@@ -278,7 +359,7 @@ bool xom_gives_item(int power)
{
if (xom_annoyance_gift(power))
return (true);
-
+
const item_def *cloak = you.slot_item(EQ_CLOAK);
if (coinflip() && cloak && cloak->cursed())
{
@@ -312,6 +393,8 @@ bool xom_gives_item(int power)
(r == 5) ? OBJ_FOOD :
(r == 6) ? OBJ_MISCELLANY :
OBJ_GOLD;
+
+ god_acting gdact(GOD_XOM);
acquirement(objtype, GOD_XOM);
}
else
@@ -412,6 +495,7 @@ static bool xom_is_good(int sever)
// Okay, now for the nicer stuff (note: these things are not
// necessarily nice):
+ god_acting gdact(GOD_XOM);
if (random2(sever) <= 1)
{
temp_rand = random2(4);
@@ -531,7 +615,7 @@ static bool xom_is_good(int sever)
(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.");
+ : "You hear Xom's maniacal cackling.");
mpr("Your body is suffused with distortional energy.");
set_hp(1 + random2(you.hp), false);
@@ -604,7 +688,9 @@ static bool xom_is_bad(int sever)
bool done = false;
bolt beam;
-
+
+ god_acting gdact(GOD_XOM);
+
// begin "Bad Things"
while (!done)
{
@@ -647,7 +733,8 @@ static bool xom_is_bad(int sever)
(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);
+ lose_stat(STAT_RANDOM, 1 + random2(3), true,
+ "the capriciousness of Xom" );
done = true;
}
@@ -801,14 +888,37 @@ static bool xom_is_bad(int sever)
void xom_acts(bool niceness, int sever)
{
-#if DEBUG_DIAGNOSTICS
+#if DEBUG_DIAGNOSTICS || DEBUG_RELIGION || DEBUG_XOM
mprf(MSGCH_DIAGNOSTICS, "Xom_acts(%u, %d); piety: %u, interest: %u\n",
niceness, sever, you.piety, you.gift_timeout);
#endif
+ entry_cause_type old_entry_cause = you.entry_cause;
+
if (sever < 1)
sever = 1;
-
+
+ // Nemelex's deck of punishment drawing the Xom card
+ if (crawl_state.is_god_acting()
+ && crawl_state.which_god_acting() != GOD_XOM)
+ {
+ god_type which_god = crawl_state.which_god_acting();
+
+ if (crawl_state.is_god_retribution())
+ {
+ niceness = false;
+ mprf(MSGCH_GOD, which_god,
+ "%s asks Xom for help in punishing you, and Xom happily "
+ "agrees.", god_name(which_god));
+ }
+ else
+ {
+ niceness = true;
+ mprf(MSGCH_GOD, which_god,
+ "%s calls in a favour from Xom.", god_name(which_god));
+ }
+ }
+
if (niceness && !one_chance_in(5))
{
// Good stuff.
@@ -821,7 +931,107 @@ void xom_acts(bool niceness, int sever)
while (!xom_is_bad(sever))
;
}
+
+ // Nemelex's deck of punishment drawing the Xom card
+ if (crawl_state.is_god_acting()
+ && crawl_state.which_god_acting() != GOD_XOM)
+ {
+ if (old_entry_cause != you.entry_cause
+ && you.entry_cause_god == GOD_XOM)
+ {
+ you.entry_cause_god = crawl_state.which_god_acting();
+ }
+ }
if (you.religion == GOD_XOM && coinflip())
you.piety = 200 - you.piety;
}
+
+static void xom_check_less_runes(int runes_gones)
+{
+ if (player_in_branch(BRANCH_HALL_OF_ZOT) ||
+ !(branches[BRANCH_HALL_OF_ZOT].branch_flags & BFLAG_HAS_ORB))
+ {
+ return;
+ }
+
+ int runes_avail = you.attribute[ATTR_UNIQUE_RUNES]
+ + you.attribute[ATTR_DEMONIC_RUNES]
+ + you.attribute[ATTR_ABYSSAL_RUNES]
+ - you.attribute[ATTR_RUNES_IN_ZOT];
+ int was_avail = runes_avail + runes_gones;
+
+ // No longer enough available runes to get into Zot
+ if (was_avail >= NUMBER_OF_RUNES_NEEDED &&
+ runes_avail < NUMBER_OF_RUNES_NEEDED)
+ {
+ xom_is_stimulated(128, "Xom snickers.", true);
+ }
+}
+
+void xom_check_lost_item(const item_def& item)
+{
+ if (item.base_type == OBJ_ORBS)
+ xom_is_stimulated(255, "Xom laughs nastily.", true);
+ else if (is_fixed_artefact(item))
+ xom_is_stimulated(128, "Xom snickers.", true);
+ else if (is_rune(item))
+ {
+ // If you'd dropped it, check if that means you'd dropped your
+ // third rune and now don't have enough to get into Zot.
+ if (item.flags & ISFLAG_BEEN_IN_INV)
+ xom_check_less_runes(item.quantity);
+
+ if (is_unique_rune(item))
+ xom_is_stimulated(255, "Xom snickers loudly.", true);
+ else if (you.entry_cause == EC_SELF_EXPLICIT &&
+ !(item.flags & ISFLAG_BEEN_IN_INV))
+ {
+ // Player voluntarily entered Pan or the Abyss looking for
+ // runes, yet never found it.
+ if (item.plus == RUNE_ABYSSAL &&
+ you.attribute[ATTR_ABYSSAL_RUNES] == 0)
+ {
+ // Ignore Abyss area shifts.
+ if (you.level_type != LEVEL_ABYSS)
+ // Abyssal runes are a lot more trouble to find
+ // than demonic runes, so it gets twice the
+ // stimulation.
+ xom_is_stimulated(128, "Xom snickers.", true);
+ }
+ else if (item.plus == RUNE_DEMONIC &&
+ you.attribute[ATTR_DEMONIC_RUNES] == 0)
+ {
+ xom_is_stimulated(64, "Xom snickers softly.", true);
+ }
+ }
+ }
+}
+
+void xom_check_destroyed_item(const item_def& item, int cause)
+{
+ int amusement = 0;
+
+ if (item.base_type == OBJ_ORBS)
+ {
+ xom_is_stimulated(255, "Xom laughs nastily.", true);
+ return;
+ }
+ else if (is_fixed_artefact(item))
+ xom_is_stimulated(128, "Xom snickers.", true);
+ else if (is_rune(item))
+ {
+ xom_check_less_runes(item.quantity);
+
+ if (is_unique_rune(item) || item.plus == RUNE_ABYSSAL)
+ amusement = 255;
+ else
+ amusement = 64 * item.quantity;
+ }
+
+ xom_is_stimulated(amusement,
+ amusement > 128 ? "Xom snickers loudly." :
+ amusement > 64 ? "Xom snickers." :
+ "Xom snickers softly.",
+ true);
+}
diff --git a/crawl-ref/source/xom.h b/crawl-ref/source/xom.h
new file mode 100644
index 0000000000..ec8878c9b1
--- /dev/null
+++ b/crawl-ref/source/xom.h
@@ -0,0 +1,43 @@
+/*
+ * File: xom.h
+ * Summary: Misc Xom related functions.
+ * Written by: Linley Henzell
+ *
+ * Modified for Crawl Reference by $Author$ on $Date$
+ *
+ * Change History (most recent first):
+ *
+ * <1> 09/28/07 MPC Split from religion.h
+ */
+
+#ifndef XOM_H
+#define XOM_H
+
+class item_def;
+
+enum xom_message_type
+{
+ XM_NORMAL,
+ XM_INTRIGUED,
+ NUM_XOM_MESSAGE_TYPES
+};
+
+void xom_is_stimulated(int maxinterestingness,
+ xom_message_type message_type = XM_NORMAL,
+ bool force_message = false);
+void xom_is_stimulated(int maxinterestingness, const std::string& message,
+ bool force_message = false);
+bool xom_is_nice();
+void xom_acts(bool niceness, int sever);
+const char *describe_xom_favour();
+
+inline void xom_acts(int sever)
+{
+ xom_acts(xom_is_nice(), sever);
+}
+
+void xom_check_lost_item(const item_def& item);
+void xom_check_destroyed_item(const item_def& item, int cause = -1);
+bool there_are_monsters_nearby();
+
+#endif