summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2007-10-25 18:23:34 +0000
committerdshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2007-10-25 18:23:34 +0000
commitc74d8c41878cff22751311e0c631d22114f1417b (patch)
treefc3c97c8017bfd68ec64397633abcd1d242a704b
parentf6e4e9e9c96bc7801daaf0ce7339200c0e572aed (diff)
downloadcrawl-ref-c74d8c41878cff22751311e0c631d22114f1417b.tar.gz
crawl-ref-c74d8c41878cff22751311e0c631d22114f1417b.zip
Trunk->0.3 merge, revisions 2531-2536, 2540-2543, 2545, 2547-2553, 2555-2556, 2563, 2568, 2570, 2572-2573, 2576: Lugonu invoc, orc battle cry, hunter changes, idle time clamp, Olgreb spam fix, Lab fixes, greedy explore item ignore, Makhleb/Vehumet power gain w/o prayer, spell power changes, doc fixes, shift-run secret door fix, Lua file-not-found error message fix, poisoned sling bullet fix, temple fix, colour overlay fixes.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/branches/stone_soup-0.3@2577 c06c8d41-db1a-0410-9941-cceddc491573
-rw-r--r--crawl-ref/docs/crawl_options.txt32
-rw-r--r--crawl-ref/dolinks.sh5
-rw-r--r--crawl-ref/domake.sh6
-rw-r--r--crawl-ref/source/AppHdr.h5
-rw-r--r--crawl-ref/source/abl-show.cc10
-rw-r--r--crawl-ref/source/acr.cc11
-rw-r--r--crawl-ref/source/beam.cc31
-rw-r--r--crawl-ref/source/beam.h4
-rw-r--r--crawl-ref/source/clua.cc8
-rw-r--r--crawl-ref/source/dat/temple.des38
-rw-r--r--crawl-ref/source/debug.cc2
-rw-r--r--crawl-ref/source/dungeon.cc86
-rw-r--r--crawl-ref/source/dungeon.h1
-rw-r--r--crawl-ref/source/externs.h2
-rw-r--r--crawl-ref/source/initfile.cc5
-rw-r--r--crawl-ref/source/it_use3.cc7
-rw-r--r--crawl-ref/source/item_use.cc13
-rw-r--r--crawl-ref/source/itemprop.cc4
-rw-r--r--crawl-ref/source/items.cc78
-rw-r--r--crawl-ref/source/items.h1
-rw-r--r--crawl-ref/source/libutil.cc105
-rw-r--r--crawl-ref/source/libutil.h29
-rw-r--r--crawl-ref/source/makeitem.cc7
-rw-r--r--crawl-ref/source/mapdef.cc2
-rw-r--r--crawl-ref/source/misc.cc2
-rw-r--r--crawl-ref/source/mon-util.cc6
-rw-r--r--crawl-ref/source/monstuff.cc7
-rw-r--r--crawl-ref/source/mstuff2.cc15
-rw-r--r--crawl-ref/source/newgame.cc31
-rw-r--r--crawl-ref/source/player.cc11
-rw-r--r--crawl-ref/source/spells1.cc2
-rw-r--r--crawl-ref/source/spells2.cc26
-rw-r--r--crawl-ref/source/spl-book.cc13
-rw-r--r--crawl-ref/source/spl-cast.cc17
-rw-r--r--crawl-ref/source/spl-cast.h3
-rw-r--r--crawl-ref/source/spl-data.h8
-rw-r--r--crawl-ref/source/spl-util.cc14
-rw-r--r--crawl-ref/source/spl-util.h2
-rw-r--r--crawl-ref/source/traps.cc3
-rw-r--r--crawl-ref/source/travel.cc63
-rw-r--r--crawl-ref/source/travel.h1
41 files changed, 545 insertions, 171 deletions
diff --git a/crawl-ref/docs/crawl_options.txt b/crawl-ref/docs/crawl_options.txt
index 1d6fabeaf1..2072654cfa 100644
--- a/crawl-ref/docs/crawl_options.txt
+++ b/crawl-ref/docs/crawl_options.txt
@@ -307,7 +307,7 @@ autopickup_exceptions = <pickup-regex, >don't-pickup-regex, ...
autopickup_exceptions = noise, torment
default_autopickup = true
- When set false, the game starts with autopickup turned off. You can
+ When set to false, the game starts with autopickup turned off. You can
still toggle autopickup in-game with Ctrl-A.
safe_autopickup = true
@@ -622,8 +622,7 @@ travel_stop_message = <list of regexes>
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've an amulet of the gourmand,
- and are hankering after rotten meat, or you're playing a ghoul:
+ 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:
@@ -668,7 +667,7 @@ runrest_ignore_monster = <string>:<distance>
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_ingore_monster = fish:3
+ 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.
@@ -690,8 +689,8 @@ tc_dangerous = cyan
tc_excluded = lightmagenta
tc_exclude_circle = red
The above four settle the colouring of the level map ('X'). They are
- reachable: all squares reachable without problems (perhaps via stairs)
- dangerous: squares which are only connected to your place via traps
+ reachable: all squares safely reachable (without leaving the level)
+ dangerous: squares which are only connected to you via traps, etc.
excluded: the colour for the centre of travel exclusions (Ctrl-X)
excluded_circle: the colour for travel exclusions apart from centre
@@ -727,25 +726,25 @@ stash_tracking = (all | explicit | dropped)
-----------------------------
auto_list = true
- Change to true if you want to automatically list appropriate inventory
- items 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.
+ 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.
-easy_open = false
+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 uncursed short blade for butchery. For such
- tools any special messages are ignored. If false, you have to wield the
- tool manually.
+ 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.
easy_unequip = true
Allows auto removal of armour and jewellery when dropping it.
@@ -772,9 +771,6 @@ easy_exit_menu = 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.
- Letting Crawl pray throughout and automatically can be useful for gods
- like Trog and Makhleb, who constantly demand kills from their
- followers.
Automatic prayers take a turn like manual prayers and happen only if
- there is no hostile monster in sight
diff --git a/crawl-ref/dolinks.sh b/crawl-ref/dolinks.sh
index 46815055b0..ed4fd2cb6f 100644
--- a/crawl-ref/dolinks.sh
+++ b/crawl-ref/dolinks.sh
@@ -3,6 +3,7 @@
mkdir -p NORMAL
mkdir -p WIZARD
-pushd NORMAL ; ln -s ../source/*.h ../source/*.cc ../source/makefile* . ; popd
-pushd WIZARD ; ln -s ../source/*.h ../source/*.cc ../source/makefile* . ; popd
+pushd NORMAL ; ln -s ../source/util . ; ln -s ../source/*.h ../source/*.cc ../source/makefile* . ; popd
+pushd WIZARD ; ln -s ../source/util . ; ln -s ../source/*.h ../source/*.cc ../source/makefile* . ; popd
+ln -s source/dat dat
diff --git a/crawl-ref/domake.sh b/crawl-ref/domake.sh
index a523e0b3b6..31e5a26938 100644
--- a/crawl-ref/domake.sh
+++ b/crawl-ref/domake.sh
@@ -10,3 +10,9 @@ fi
if [ -f WIZARD/crawl ]; then
ln -sf WIZARD/crawl wcrawl
fi
+
+if [ -d dat/lua ]; then
+ true
+else
+ cp -r source/lua dat/lua
+fi
diff --git a/crawl-ref/source/AppHdr.h b/crawl-ref/source/AppHdr.h
index b354185fa0..5c5253ce9c 100644
--- a/crawl-ref/source/AppHdr.h
+++ b/crawl-ref/source/AppHdr.h
@@ -224,7 +224,9 @@
#endif
// Increase the size of the topscores file for public servers.
+ #ifndef SCORE_FILE_ENTRIES
#define SCORE_FILE_ENTRIES 1000
+ #endif
// If defined, the hiscores code dumps preformatted verbose and terse
// death message strings in the logfile for the convenience of logfile
@@ -322,6 +324,9 @@
// number of back messages saved during play (currently none saved into files)
#define NUM_STORED_MESSAGES 1000
+// clamp time between command inputs at 5 minutes when reporting play time.
+#define IDLE_TIME_CLAMP (5 * 60)
+
// Uncomment this if you find the labyrinth to be buggy and want to
// remove it from the game.
// #define SHUT_LABYRINTH
diff --git a/crawl-ref/source/abl-show.cc b/crawl-ref/source/abl-show.cc
index 90aa4b25c0..65bdb47e6b 100644
--- a/crawl-ref/source/abl-show.cc
+++ b/crawl-ref/source/abl-show.cc
@@ -640,6 +640,7 @@ static talent get_talent(ability_type ability, bool check_confused)
case ABIL_BEOGH_RECALL_ORCISH_FOLLOWERS:
case ABIL_OKAWARU_MIGHT:
case ABIL_ELYVILON_LESSER_HEALING:
+ case ABIL_LUGONU_ABYSS_EXIT:
invoc = true;
failure = 30 - (you.piety / 20) - (6 * you.skills[SK_INVOCATIONS]);
break;
@@ -685,6 +686,7 @@ static talent get_talent(ability_type ability, bool check_confused)
case ABIL_YRED_ANIMATE_DEAD:
case ABIL_MAKHLEB_LESSER_SERVANT_OF_MAKHLEB:
case ABIL_ELYVILON_HEALING:
+ case ABIL_LUGONU_BEND_SPACE:
invoc = true;
failure = 40 - (you.piety / 20) - (5 * you.skills[SK_INVOCATIONS]);
break;
@@ -701,6 +703,7 @@ static talent get_talent(ability_type ability, bool check_confused)
case ABIL_ZIN_PESTILENCE:
case ABIL_TSO_ANNIHILATE_UNDEAD:
+ case ABIL_LUGONU_BANISH:
invoc = true;
failure = 60 - (you.piety / 20) - (5 * you.skills[SK_INVOCATIONS]);
break;
@@ -717,6 +720,7 @@ static talent get_talent(ability_type ability, bool check_confused)
case ABIL_YRED_CONTROL_UNDEAD:
case ABIL_OKAWARU_HASTE:
case ABIL_MAKHLEB_GREATER_SERVANT_OF_MAKHLEB:
+ case ABIL_LUGONU_CORRUPT:
invoc = true;
failure = 70 - (you.piety / 25) - (you.skills[SK_INVOCATIONS] * 4);
break;
@@ -725,6 +729,7 @@ static talent get_talent(ability_type ability, bool check_confused)
case ABIL_TSO_SUMMON_DAEVA:
case ABIL_KIKU_INVOKE_DEATH:
case ABIL_ELYVILON_GREATER_HEALING:
+ case ABIL_LUGONU_ABYSS_ENTER:
invoc = true;
failure = 80 - (you.piety / 25) - (you.skills[SK_INVOCATIONS] * 4);
break;
@@ -1007,8 +1012,9 @@ static bool do_ability(const ability_def& abil)
case ABIL_EVOKE_MAPPING: // randarts
case ABIL_MAPPING: // Gnome + sense surrounds mut
- if (abil.ability == ABIL_MAPPING && you.mutation[MUT_MAPPING] < 3 &&
- you.level_type == LEVEL_PANDEMONIUM)
+ if (abil.ability == ABIL_MAPPING && you.mutation[MUT_MAPPING] < 3
+ && (you.level_type == LEVEL_PANDEMONIUM
+ || you.level_type == LEVEL_LABYRINTH))
{
mpr("You feel momentarily disoriented.");
return (false);
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc
index 71dffbff5d..83dfcf9d6f 100644
--- a/crawl-ref/source/acr.cc
+++ b/crawl-ref/source/acr.cc
@@ -2651,7 +2651,18 @@ static command_type get_next_cmd()
#if DEBUG_ITEM_SCAN
debug_item_scan();
#endif
+
+ const time_t before = time(NULL);
keycode_type keyin = get_next_keycode();
+
+ const time_t after = time(NULL);
+
+ // Clamp idle time so that play time is more meaningful.
+ if (after - before > IDLE_TIME_CLAMP)
+ {
+ you.real_time += (before - you.start_time) + IDLE_TIME_CLAMP;
+ you.start_time = after;
+ }
if (is_userfunction(keyin))
{
diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc
index 01e3620354..f78c61b174 100644
--- a/crawl-ref/source/beam.cc
+++ b/crawl-ref/source/beam.cc
@@ -685,10 +685,10 @@ static void zappy( zap_type z_type, int power, bolt &pbolt )
pbolt.name = "stone arrow";
pbolt.colour = LIGHTGREY;
pbolt.range = 8 + random2(5);
- pbolt.damage = dice_def( 2, 4 + power / 8 ); // 25: 2d7 50: 2d10
- pbolt.hit = 5 + power / 10; // 25: 6 50: 7
+ pbolt.damage = dice_def( 2, 5 + power / 7 ); // 25: 2d8 50: 2d12
+ pbolt.hit = 8 + power / 10; // 25: 10 50: 13
pbolt.type = SYM_MISSILE;
- pbolt.flavour = BEAM_MMISSILE; // unresistable
+ pbolt.flavour = BEAM_MMISSILE; // irresistible
pbolt.obvious_effect = true;
break;
@@ -753,7 +753,7 @@ static void zappy( zap_type z_type, int power, bolt &pbolt )
pbolt.name = "bolt of fire";
pbolt.colour = RED;
pbolt.range = 7 + random2(10);
- pbolt.damage = calc_dice( 6, 20 + (power * 3) / 4 );
+ pbolt.damage = calc_dice( 6, 18 + power * 2 / 3 );
pbolt.hit = 10 + power / 25; // 50: 12 100: 14
pbolt.type = SYM_ZAP;
pbolt.flavour = BEAM_FIRE;
@@ -766,7 +766,7 @@ static void zappy( zap_type z_type, int power, bolt &pbolt )
pbolt.name = "bolt of cold";
pbolt.colour = WHITE;
pbolt.range = 7 + random2(10);
- pbolt.damage = calc_dice( 6, 20 + (power * 3) / 4 );
+ pbolt.damage = calc_dice( 6, 18 + power * 2 / 3 );
pbolt.hit = 10 + power / 25; // 50: 12 100: 14
pbolt.type = SYM_ZAP;
pbolt.flavour = BEAM_COLD;
@@ -897,8 +897,8 @@ static void zappy( zap_type z_type, int power, bolt &pbolt )
case ZAP_CRYSTAL_SPEAR: // cap 200
pbolt.name = "crystal spear";
pbolt.colour = WHITE;
- pbolt.range = 7 + random2(10);
- pbolt.damage = calc_dice( 12, 30 + (power * 4) / 3 );
+ pbolt.range = 6 + random2(4);
+ pbolt.damage = calc_dice( 10, 23 + power );
pbolt.hit = 10 + power / 15; // 50: 13 100: 16
pbolt.type = SYM_MISSILE;
pbolt.flavour = BEAM_MMISSILE; // unresistable
@@ -923,7 +923,7 @@ static void zappy( zap_type z_type, int power, bolt &pbolt )
pbolt.name = "great blast of cold";
pbolt.colour = BLUE;
pbolt.range = 9 + random2(5);
- pbolt.damage = calc_dice( 6, 15 + power );
+ pbolt.damage = calc_dice( 10, 18 + power );
pbolt.damage.num = 0; // only does explosion damage
pbolt.hit = 20 + power / 10; // 50: 25 100: 30
pbolt.ench_power = power; // used for radius
@@ -2111,16 +2111,17 @@ bool curare_hits_monster( const bolt &beam,
}
// actually poisons a monster (w/ message)
-void poison_monster( monsters *monster,
+bool poison_monster( monsters *monster,
kill_category from_whom,
int levels,
- bool force )
+ bool force,
+ bool verbose)
{
if (!monster->alive())
- return;
+ return (false);
if (!force && mons_res_poison(monster) > 0)
- return;
+ return (false);
const mon_enchant old_pois = monster->get_ench(ENCH_POISON);
monster->add_ench( mon_enchant(ENCH_POISON, levels, from_whom) );
@@ -2128,7 +2129,7 @@ void poison_monster( monsters *monster,
// actually do the poisoning
// note: order important here
- if (new_pois.degree > old_pois.degree)
+ if (new_pois.degree > old_pois.degree && verbose)
{
simple_monster_message( monster,
!old_pois.degree? " is poisoned."
@@ -2138,7 +2139,9 @@ void poison_monster( monsters *monster,
// finally, take care of deity preferences
if (from_whom == KC_YOU)
did_god_conduct( DID_POISON, 5 + random2(3) );
-} // end poison_monster()
+
+ return (new_pois.degree > old_pois.degree);
+}
// actually napalms a monster (w/ message)
void sticky_flame_monster( int mn, kill_category who, int levels )
diff --git a/crawl-ref/source/beam.h b/crawl-ref/source/beam.h
index d1ff65df04..35c09d23b8 100644
--- a/crawl-ref/source/beam.h
+++ b/crawl-ref/source/beam.h
@@ -235,8 +235,8 @@ int mons_ench_f2( struct monsters *monster, struct bolt &pbolt );
/* ***********************************************************************
* called from: fight - monstuff - spells2
* *********************************************************************** */
-void poison_monster( struct monsters *monster, kill_category who,
- int levels = 1, bool force = false );
+bool poison_monster( monsters *monster, kill_category who,
+ int levels = 1, bool force = false, bool verbose = true );
/* ***********************************************************************
diff --git a/crawl-ref/source/clua.cc b/crawl-ref/source/clua.cc
index 5455b857f1..7fb5f104eb 100644
--- a/crawl-ref/source/clua.cc
+++ b/crawl-ref/source/clua.cc
@@ -47,7 +47,7 @@
#define BUGGY_SCRIPT_ERROR "666: Killing badly-behaved Lua script."
#define CL_RESETSTACK_RETURN(ls, oldtop, retval) \
- if (true) \
+ do \
{\
if (oldtop != lua_gettop(ls)) \
{ \
@@ -55,7 +55,7 @@
} \
return (retval); \
} \
- else
+ while (false)
static int clua_panic(lua_State *);
static void clua_throttle_hook(lua_State *, lua_Debug *);
@@ -255,7 +255,9 @@ int CLua::loadfile(lua_State *ls, const char *filename, bool trusted,
return (-1);
}
- const std::string file = datafile_path(filename, die_on_fail);
+ std::string file = datafile_path(filename, die_on_fail);
+ if (file.empty())
+ file = filename;
return (luaL_loadfile(ls, file.c_str()));
}
diff --git a/crawl-ref/source/dat/temple.des b/crawl-ref/source/dat/temple.des
index 57410e1522..119efe9fc6 100644
--- a/crawl-ref/source/dat/temple.des
+++ b/crawl-ref/source/dat/temple.des
@@ -34,29 +34,27 @@ c@..@..@c
ENDMAP
NAME: temple_hall_b
-TAGS: temple_entry
+TAGS: temple_entry no_pool_fixup no_monster_gen
CHANCE: 1
ORIENT: float
-SUBST: ? : c:20 x v b G:5
-SHUFFLE: defghij
-SUBST: d==, e=c, f=c, g=c, h=c, i=c, j=c
+SUBST: ? : v b G:5
MAP
-ccccccccc
-c...O...c
-cdefghijc
-c...G...c
-c.......c
-c.?...?.c
-c.......c
-c.......c
-c.?...?.c
-c.......c
-c.......c
-c.?...?.c
-c.......c
-c.......c
-c.?...?.c
-c.......c
+ ccc
+ cOc
+cccc+cccc
+cwwG.Gwwc
+cwww.wwwc
+cw?w.w?wc
+cwww.wwwc
+cwww.wwwc
+cw?w.w?wc
+cwww.wwwc
+cwww.wwwc
+cw?w.w?wc
+cwww.wwwc
+cwww.wwwc
+cw?w.w?wc
+cwww.wwwc
c@..@..@c
ENDMAP
diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc
index c6a4e3c740..babc50a38c 100644
--- a/crawl-ref/source/debug.cc
+++ b/crawl-ref/source/debug.cc
@@ -347,7 +347,7 @@ void cast_spec_spell_name(void)
mpr( "Cast which spell by name? ", MSGCH_PROMPT );
get_input_line( specs, sizeof( specs ) );
- spell_type type = spell_by_name(specs);
+ 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."
diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc
index 90e495fdd9..01a4046de0 100644
--- a/crawl-ref/source/dungeon.cc
+++ b/crawl-ref/source/dungeon.cc
@@ -223,6 +223,8 @@ static int vault_grid( vault_placement &,
int &num_runes, int rune_subst = -1, bool foll = false);
static int dgn_random_map_for_place(bool wantmini);
+static void dgn_load_colour_grid();
+static void dgn_map_colour_fixup();
// ALTAR FUNCTIONS
static dungeon_feature_type pick_an_altar();
@@ -245,6 +247,34 @@ static bool use_random_maps = true;
static bool dgn_check_connectivity = false;
static int dgn_zones = 0;
+struct coloured_feature
+{
+ dungeon_feature_type feature;
+ int colour;
+
+ coloured_feature() : feature(DNGN_UNSEEN), colour(BLACK) { }
+ coloured_feature(dungeon_feature_type f, int c)
+ : feature(f), colour(c)
+ {
+ }
+};
+
+struct dgn_colour_override_manager
+{
+ dgn_colour_override_manager()
+ {
+ dgn_load_colour_grid();
+ }
+
+ ~dgn_colour_override_manager()
+ {
+ dgn_map_colour_fixup();
+ }
+};
+
+typedef FixedArray< coloured_feature, GXM, GYM > dungeon_colour_grid;
+static std::auto_ptr<dungeon_colour_grid> dgn_colour_grid;
+
/**********************************************************************
* builder() - kickoff for the dungeon generator.
*********************************************************************/
@@ -278,7 +308,10 @@ bool builder(int level_number, int level_type)
#endif
if (!dgn_level_vetoed && valid_dungeon_level(level_number, level_type))
+ {
+ dgn_map_colour_fixup();
return (true);
+ }
you.uniq_map_tags = uniq_tags;
you.uniq_map_names = uniq_names;
@@ -311,6 +344,46 @@ void level_clear_vault_memory()
dgn_map_mask.init(0);
}
+static void dgn_load_colour_grid()
+{
+ dgn_colour_grid.reset(new dungeon_colour_grid);
+ dungeon_colour_grid &dcgrid(*dgn_colour_grid);
+ for (int y = Y_BOUND_1; y <= Y_BOUND_2; ++y)
+ for (int x = X_BOUND_1; x <= X_BOUND_2; ++x)
+ if (env.grid_colours[x][y] != BLACK)
+ dcgrid[x][y] =
+ coloured_feature(grd[x][y], env.grid_colours[x][y]);
+}
+
+static void dgn_map_colour_fixup()
+{
+ if (!dgn_colour_grid.get())
+ return;
+
+ // If the original coloured feature has been changed, reset the colour.
+ const dungeon_colour_grid &dcgrid(*dgn_colour_grid);
+ for (int y = Y_BOUND_1; y <= Y_BOUND_2; ++y)
+ for (int x = X_BOUND_1; x <= X_BOUND_2; ++x)
+ if (dcgrid[x][y].colour != BLACK
+ && grd[x][y] != dcgrid[x][y].feature)
+ {
+ env.grid_colours[x][y] = BLACK;
+ }
+
+ dgn_colour_grid.reset(NULL);
+}
+
+void dgn_set_grid_colour_at(const coord_def &c, int colour)
+{
+ if (colour != BLACK)
+ {
+ env.grid_colours(c) = colour;
+ if (!dgn_colour_grid.get())
+ dgn_colour_grid.reset( new dungeon_colour_grid );
+ (*dgn_colour_grid)(c) = coloured_feature(grd(c), colour);
+ }
+}
+
static void dgn_register_vault(const map_def &map)
{
if (!map.has_tag("allow_dup"))
@@ -517,6 +590,8 @@ static bool valid_dungeon_level(int level_number, int level_type)
static void reset_level()
{
level_clear_vault_memory();
+ dgn_colour_grid.reset(NULL);
+
vault_chance = 9;
minivault_chance = 3;
use_random_maps = true;
@@ -3561,6 +3636,8 @@ static dungeon_feature_type dgn_find_rune_subst_tags(const std::string &tags)
// teleported).
bool dgn_place_map(int map, bool generating_level, bool clobber)
{
+ const dgn_colour_override_manager colour_man;
+
const map_def *mdef = map_by_index(map);
bool did_map = false;
bool fixup = false;
@@ -5840,15 +5917,16 @@ static void labyrinth_place_entry_point(const dgn_region &region,
{
const coord_def p = labyrinth_find_entry_point(region, pos);
if (in_bounds(p))
- env.markers.add(new map_feature_marker(pos, DNGN_ENTER_LABYRINTH));
+ env.markers.add(new map_feature_marker(p, DNGN_ENTER_LABYRINTH));
}
static void labyrinth_level(int level_number)
{
dgn_region lab =
- dgn_region::absolute( MAPGEN_BORDER * 5 / 2, MAPGEN_BORDER * 5 / 2,
- GXM - MAPGEN_BORDER * 5 / 2 - 1,
- GYM - MAPGEN_BORDER * 5 / 2 - 1 );
+ dgn_region::absolute( MAPGEN_BORDER * 2,
+ MAPGEN_BORDER * 2,
+ GXM - MAPGEN_BORDER * 2 - 1,
+ GYM - MAPGEN_BORDER * 2 - 1 );
// First decide if we're going to use a Lab minivault.
int vault = random_map_for_tag("minotaur", true, false);
diff --git a/crawl-ref/source/dungeon.h b/crawl-ref/source/dungeon.h
index b7fc8bca02..5b507af77f 100644
--- a/crawl-ref/source/dungeon.h
+++ b/crawl-ref/source/dungeon.h
@@ -299,6 +299,7 @@ int bazaar_floor_colour(int curr_level);
// 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);
bool dgn_place_map(int map, bool generating_level, bool clobber);
void level_clear_vault_memory();
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index 7c6a19c529..1deec33d25 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -778,6 +778,8 @@ public:
bool caught() const;
bool backlit() const;
+ bool can_throw_rocks() const;
+
int armour_class() const;
int melee_evasion(const actor *attacker) const;
diff --git a/crawl-ref/source/initfile.cc b/crawl-ref/source/initfile.cc
index 5c363802ed..aed876f778 100644
--- a/crawl-ref/source/initfile.cc
+++ b/crawl-ref/source/initfile.cc
@@ -260,6 +260,8 @@ static fire_type str_to_fire_types( const std::string &str )
return (FIRE_DART);
else if (str == "stone")
return (FIRE_STONE);
+ else if (str == "rock")
+ return (FIRE_ROCK);
else if (str == "dagger")
return (FIRE_DAGGER);
else if (str == "spear")
@@ -705,7 +707,8 @@ void game_options::reset_options()
fire_items_start = 2; // start at slot 'c'
// Clear fire_order and set up the defaults.
- set_fire_order("launcher, javelin / dart / stone / spear");
+ set_fire_order("launcher, "
+ "javelin / dart / stone / rock / spear / net / handaxe");
item_stack_summary_minimum = 5;
diff --git a/crawl-ref/source/it_use3.cc b/crawl-ref/source/it_use3.cc
index 0ae2f6524b..e3d33d45d8 100644
--- a/crawl-ref/source/it_use3.cc
+++ b/crawl-ref/source/it_use3.cc
@@ -714,7 +714,8 @@ static bool ball_of_seeing(void)
mpr("You gaze into the crystal ball.");
- use = ((!you.duration[DUR_CONF]) ? random2(you.skills[SK_EVOCATIONS] * 6) : random2(5));
+ use = ((!you.duration[DUR_CONF]) ?
+ random2(you.skills[SK_EVOCATIONS] * 6) : random2(5));
if (use < 2)
{
@@ -725,8 +726,10 @@ static bool ball_of_seeing(void)
mpr("You feel power drain from you!");
set_mp(0, false);
}
- else if (use < 10)
+ else if (use < 10 || you.level_type == LEVEL_LABYRINTH)
{
+ if (you.level_type == LEVEL_LABYRINTH)
+ mpr("You see a maze of twisty little passages, all alike.");
confuse_player( 10 + random2(10), false );
}
else if (use < 15 || coinflip())
diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc
index 382b22f549..659c06f119 100644
--- a/crawl-ref/source/item_use.cc
+++ b/crawl-ref/source/item_use.cc
@@ -1996,7 +1996,7 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus,
// all weapons that use 'throwing' go here..
if (wepClass == OBJ_WEAPONS
|| (wepClass == OBJ_MISSILES
- && (wepType == MI_STONE || wepType == MI_SLING_BULLET)))
+ && (wepType == MI_STONE || wepType == MI_LARGE_ROCK)))
{
// elves with elven weapons
if (get_equip_race(item) == ISFLAG_ELVEN
@@ -2040,6 +2040,10 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus,
{
switch (wepType)
{
+ case MI_LARGE_ROCK:
+ if (you.can_throw_rocks())
+ baseHit = 1;
+ break;
case MI_DART:
// give an appropriate 'tohit' & damage
baseHit = 2;
@@ -2057,7 +2061,7 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus,
// Javelins use throwing skill.
baseHit = -1;
baseDam = property( item, PWPN_DAMAGE );
- exHitBonus += (skill_bump(SK_THROWING) * 7 / 2);
+ exHitBonus += skill_bump(SK_THROWING) * 3 / 2;
exDamBonus += you.skills[SK_THROWING] * 3 / 5;
// Adjust for strength and dex.
@@ -2093,8 +2097,7 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus,
// for launchers. Hand-thrown stones and darts do only half
// base damage. Yet another evil 4.0ism.
if (wepClass == OBJ_MISSILES
- && (wepType == MI_DART || wepType == MI_STONE
- || wepType == MI_SLING_BULLET))
+ && (wepType == MI_DART || wepType == MI_STONE))
baseDam = div_rand_round(baseDam, 2);
// exercise skill
@@ -2118,6 +2121,8 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus,
if (wepType == MI_LARGE_ROCK)
{
pbolt.range = 1 + random2( you.strength / 5 );
+ if (you.can_throw_rocks())
+ pbolt.range += random_range(4, 7);
if (pbolt.range > 12)
pbolt.range = 12;
diff --git a/crawl-ref/source/itemprop.cc b/crawl-ref/source/itemprop.cc
index cd77235da0..0f8f52be49 100644
--- a/crawl-ref/source/itemprop.cc
+++ b/crawl-ref/source/itemprop.cc
@@ -350,9 +350,9 @@ static missile_def Missile_prop[NUM_MISSILES] =
{ MI_DART, "dart", 5, 3, true },
{ MI_ARROW, "arrow", 7, 5, false },
{ MI_BOLT, "bolt", 9, 5, false },
- { MI_LARGE_ROCK, "large rock", 20, 1000, true },
+ { MI_LARGE_ROCK, "large rock", 20, 800, true },
{ MI_SLING_BULLET, "sling bullet", 6, 4, false },
- { MI_JAVELIN, "javelin", 10, 40, true },
+ { MI_JAVELIN, "javelin", 10, 90, true },
{ MI_THROWING_NET, "throwing net", 0, 30, true },
};
diff --git a/crawl-ref/source/items.cc b/crawl-ref/source/items.cc
index ea3045437f..fda39d9c5d 100644
--- a/crawl-ref/source/items.cc
+++ b/crawl-ref/source/items.cc
@@ -959,25 +959,6 @@ bool origin_describable(const item_def &item)
std::string article_it(const item_def &item)
{
- /*
- bool them = false;
- if (item.quantity > 1)
- them = true;
- else if (item.base_type == OBJ_ARMOUR &&
- item.sub_type == ARM_BOOTS)
- {
- if (item.plus2 != TBOOT_NAGA_BARDING &&
- item.plus2 != TBOOT_CENTAUR_BARDING)
- them = true;
- }
- else if (item.base_type == OBJ_ARMOUR &&
- item.sub_type == ARM_GLOVES)
- {
- them = true;
- }
-
- return them? "them" : "it";
- */
// "it" is always correct, since gloves and boots also come in pairs.
return "it";
}
@@ -1338,7 +1319,8 @@ int find_free_slot(const item_def &i)
int move_item_to_player( int obj, int quant_got, bool quiet )
{
if (you.attribute[ATTR_HELD] && mitm[obj].base_type == OBJ_MISSILES
- && mitm[obj].sub_type == MI_THROWING_NET && item_is_stationary(mitm[obj]))
+ && mitm[obj].sub_type == MI_THROWING_NET
+ && item_is_stationary(mitm[obj]))
{
mpr("You cannot pick up the net that holds you!");
return (1);
@@ -1477,6 +1459,16 @@ int move_item_to_player( int obj, int quant_got, bool quiet )
return (retval);
} // end move_item_to_player()
+void mark_items_non_pickup_at(const coord_def &pos)
+{
+ int item = igrd(pos);
+ while (item != NON_ITEM)
+ {
+ mitm[item].flags |= ISFLAG_DROPPED;
+ mitm[item].flags &= ~ISFLAG_THROWN;
+ item = mitm[item].link;
+ }
+}
// Moves mitm[obj] to (x,y)... will modify the value of obj to
// be the index of the final object (possibly different).
@@ -2825,8 +2817,8 @@ static void do_autopickup()
{
//David Loewenstern 6/99
int result, o, next;
- bool did_pickup = false;
- bool tried_pickup = false;
+ int n_did_pickup = 0;
+ int n_tried_pickup = 0;
will_autopickup = false;
@@ -2841,7 +2833,6 @@ static void do_autopickup()
if (item_needs_autopickup(mitm[o]))
{
-
int num_to_take = mitm[o].quantity;
if ( Options.autopickup_no_burden && item_mass(mitm[o]) != 0)
{
@@ -2851,10 +2842,10 @@ static void do_autopickup()
if ( num_can_take < num_to_take )
{
- if (!tried_pickup)
+ if (!n_tried_pickup)
mpr("You can't pick everything up without burdening "
"yourself.");
- tried_pickup = true;
+ n_tried_pickup++;
num_to_take = num_can_take;
}
@@ -2865,49 +2856,40 @@ static void do_autopickup()
}
}
+ const unsigned long iflags(mitm[o].flags);
mitm[o].flags &= ~(ISFLAG_THROWN | ISFLAG_DROPPED);
result = move_item_to_player(o, num_to_take);
- if (result == 0)
+ if (result == 0 || result == -1)
{
- tried_pickup = true;
- mpr("You can't carry any more.");
- break;
- }
- else if (result == -1)
- {
- tried_pickup = true;
- mpr("Your pack is full.");
+ n_tried_pickup++;
+ if (result == 0)
+ mpr("You can't carry any more.");
+ else
+ mpr("Your pack is full.");
+ mitm[o].flags = iflags;
break;
}
- did_pickup = true;
+ n_did_pickup++;
}
o = next;
}
- if (did_pickup)
- {
+ if (n_did_pickup)
you.turn_is_over = true;
- const int estop =
- you.running == RMODE_EXPLORE_GREEDY?
- ES_GREEDY_PICKUP : ES_PICKUP;
- if ((Options.explore_stop & estop) && prompt_stop_explore(estop))
- stop_delay();
- }
- // Greedy explore has no good way to deal with an item that we can't
- // pick up, so the only thing to do is to stop.
- else if (tried_pickup && you.running == RMODE_EXPLORE_GREEDY)
- stop_delay();
+
+ item_check(false);
+
+ explore_pickup_event(n_did_pickup, n_tried_pickup);
}
void autopickup()
{
autoinscribe_floor_items();
do_autopickup();
- item_check(false);
}
int inv_count(void)
diff --git a/crawl-ref/source/items.h b/crawl-ref/source/items.h
index 57669b42cd..8dfcff9a20 100644
--- a/crawl-ref/source/items.h
+++ b/crawl-ref/source/items.h
@@ -40,6 +40,7 @@ void inc_mitm_item_quantity( int obj, int amount );
bool move_item_to_grid( int *const obj, int x, int y );
void move_item_stack_to_grid( int x, int y, int targ_x, int targ_y );
int move_item_to_player( int obj, int quant_got, bool quiet = false );
+void mark_items_non_pickup_at(const coord_def &pos);
bool is_stackable_item( const item_def &item );
bool items_stack( const item_def &item1, const item_def &item2,
bool force = false );
diff --git a/crawl-ref/source/libutil.cc b/crawl-ref/source/libutil.cc
index 586de1db77..ed0b640680 100644
--- a/crawl-ref/source/libutil.cc
+++ b/crawl-ref/source/libutil.cc
@@ -18,6 +18,7 @@
#include "externs.h"
#include "macro.h"
#include "stuff.h"
+#include <sstream>
#include <stdio.h>
#include <ctype.h>
#include <stdarg.h>
@@ -75,6 +76,39 @@ description_level_type description_type_by_name(const char *desc)
return DESC_PLAIN;
}
+std::string number_to_string(unsigned number, bool in_words)
+{
+ return (in_words? number_in_words(number) : make_stringf("%u", number));
+}
+
+std::string apply_description(description_level_type desc,
+ const std::string &name,
+ int quantity, bool in_words)
+{
+ switch (desc)
+ {
+ case DESC_CAP_THE:
+ return ("The " + name);
+ case DESC_NOCAP_THE:
+ return ("the " + name);
+ case DESC_CAP_A:
+ return (quantity > 1?
+ number_to_string(quantity, in_words) + name
+ : article_a(name, false));
+ case DESC_NOCAP_A:
+ return (quantity > 1?
+ number_to_string(quantity, in_words) + name
+ : article_a(name, true));
+ case DESC_CAP_YOUR:
+ return ("Your " + name);
+ case DESC_NOCAP_YOUR:
+ return ("your " + name);
+ case DESC_PLAIN:
+ default:
+ return (name);
+ }
+}
+
// Should return true if the filename contains nothing that
// the shell can do damage with.
bool shell_safe(const char *file)
@@ -527,6 +561,77 @@ int snprintf( char *str, size_t size, const char *format, ... )
#endif
+//////////////////////////////////////////////////////////////////////////
+// named_thing_collection
+
+named_thing_collection::named_thing_collection()
+ : names(), nnames(0u)
+{
+}
+
+void named_thing_collection::add_thing(const std::string &name)
+{
+ names[name]++;
+ nnames++;
+}
+
+size_t named_thing_collection::size() const
+{
+ return (nnames);
+}
+
+bool named_thing_collection::empty() const
+{
+ return (!nnames);
+}
+
+std::string named_thing_collection::describe(
+ description_level_type desc,
+ const char **plural_qualifiers,
+ const char **no_qualifier_suffixes) const
+{
+ if (empty())
+ return ("");
+
+ std::ostringstream out;
+ for (name_count_map::const_iterator i = names.begin();
+ i != names.end(); )
+ {
+ const std::pair<std::string, int> &curr(*i);
+ if (i != names.begin())
+ {
+ ++i;
+ out << (i == names.end()? " and " : ", ");
+ }
+ else
+ ++i;
+
+ const std::string name =
+ curr.second > 1? pluralise(curr.first, plural_qualifiers,
+ no_qualifier_suffixes)
+ : curr.first;
+ out << apply_description(desc, name, curr.second);
+
+ switch (desc)
+ {
+ case DESC_CAP_A:
+ desc = DESC_NOCAP_A;
+ break;
+ case DESC_CAP_THE:
+ desc = DESC_NOCAP_THE;
+ break;
+ case DESC_CAP_YOUR: case DESC_NOCAP_YOUR:
+ desc = DESC_PLAIN;
+ break;
+ default:
+ break;
+ }
+ }
+ return (out.str());
+}
+
+/////////////////////////////////////////////////////////////////////////
+
///////////////////////////////////////////////////////////////////////
// Pattern matching
diff --git a/crawl-ref/source/libutil.h b/crawl-ref/source/libutil.h
index e68863bd57..6ae7bedec4 100644
--- a/crawl-ref/source/libutil.h
+++ b/crawl-ref/source/libutil.h
@@ -19,9 +19,37 @@
#include <cctype>
#include <string>
#include <vector>
+#include <map>
+
+// A collection of named things that can be stacked. The collection merges
+// things that should be merged (by name) and outputs a comma-separated list
+// with the preferred description type.
+class named_thing_collection
+{
+public:
+ named_thing_collection();
+ void add_thing(const std::string &name);
+ std::string describe(description_level_type desc,
+ const char **plural_qualifiers = NULL,
+ const char **no_qualifier_suffix = NULL) const;
+ size_t size() const;
+ bool empty() const;
+private:
+ typedef std::map<std::string, int> name_count_map;
+ name_count_map names;
+ size_t nnames;
+};
extern const char *standard_plural_qualifiers[];
+// Applies a description type to a name, but does not pluralise! You
+// must pluralise the name if needed. The quantity is used to prefix the
+// name with a quantity if appropriate.
+std::string apply_description(description_level_type desc,
+ const std::string &name,
+ int quantity = 1,
+ bool num_in_words = false);
+
description_level_type description_type_by_name(const char *desc);
std::string lowercase_string(std::string s);
@@ -42,6 +70,7 @@ std::string pluralise(
const char *no_of[] = NULL);
std::string number_in_words(unsigned number, int pow = 0);
+std::string number_to_string(unsigned number, bool in_words = false);
bool shell_safe(const char *file);
diff --git a/crawl-ref/source/makeitem.cc b/crawl-ref/source/makeitem.cc
index 7cbaf63fe2..5bed8798aa 100644
--- a/crawl-ref/source/makeitem.cc
+++ b/crawl-ref/source/makeitem.cc
@@ -1815,6 +1815,13 @@ int items( int allow_uniques, // not just true-false,
if (get_equip_race(mitm[p]) == ISFLAG_ORCISH && one_chance_in(3))
set_item_ego_type( mitm[p], OBJ_MISSILES, SPMSL_POISONED );
+ // Un-poison sling bullets.
+ if (mitm[p].sub_type == MI_SLING_BULLET
+ && get_ammo_brand( mitm[p] ) == SPMSL_POISONED)
+ {
+ set_item_ego_type( mitm[p], OBJ_MISSILES, SPMSL_NORMAL );
+ }
+
// reduced quantity if special
if (mitm[p].sub_type == MI_JAVELIN
|| get_ammo_brand( mitm[p] ) == SPMSL_CURARE)
diff --git a/crawl-ref/source/mapdef.cc b/crawl-ref/source/mapdef.cc
index 0cdca251b0..7d88ff9834 100644
--- a/crawl-ref/source/mapdef.cc
+++ b/crawl-ref/source/mapdef.cc
@@ -411,7 +411,7 @@ void map_lines::apply_colours(const coord_def &c)
{
const int colour = overlay(x, y);
if (colour)
- env.grid_colours(c + coord_def(x, y)) = colour;
+ dgn_set_grid_colour_at(c + coord_def(x, y), colour);
}
}
diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc
index fc7239567b..6039265869 100644
--- a/crawl-ref/source/misc.cc
+++ b/crawl-ref/source/misc.cc
@@ -890,7 +890,7 @@ void down_stairs( int old_level, dungeon_feature_type force_stair )
dungeon_feature_type stair_taken = stair_find;
- if (you.level_type == LEVEL_LABYRINTH || you.level_type == LEVEL_ABYSS)
+ if (you.level_type == LEVEL_ABYSS)
stair_taken = DNGN_FLOOR;
if (you.level_type == LEVEL_PANDEMONIUM)
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 5f73bc91df..40bf299303 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -2457,8 +2457,8 @@ item_def *monsters::weapon(int which_attack)
bool monsters::can_throw_rocks() const
{
- return (type == MONS_STONE_GIANT || type == MONS_CYCLOPS ||
- type == MONS_POLYPHEMUS);
+ return (type == MONS_STONE_GIANT || type == MONS_CYCLOPS
+ || type == MONS_OGRE || type == MONS_POLYPHEMUS);
}
bool monsters::has_spell_of_type(unsigned disciplines) const
@@ -4680,7 +4680,7 @@ void monsters::apply_location_effects()
if (alive())
mons_check_pool(this);
}
-
+
/////////////////////////////////////////////////////////////////////////
// mon_enchant
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index ffe027e0fc..e1696cb44d 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -578,9 +578,9 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent)
// Divine health and mp restoration doesn't happen when killing
// born-friendly monsters. The mutation still applies, however.
if (you.mutation[MUT_DEATH_STRENGTH]
- || (!created_friendly &&
- you.religion == GOD_MAKHLEB && you.duration[DUR_PRAYER] &&
- (!player_under_penance() && random2(you.piety) >= 30)))
+ || (!created_friendly
+ && you.religion == GOD_MAKHLEB
+ && (!player_under_penance() && random2(you.piety) >= 30)))
{
if (you.hp < you.hp_max)
{
@@ -592,7 +592,6 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent)
if (!created_friendly
&& (you.religion == GOD_MAKHLEB || you.religion == GOD_VEHUMET)
- && you.duration[DUR_PRAYER]
&& (!player_under_penance() && random2(you.piety) >= 30))
{
if (you.magic_points < you.max_magic_points)
diff --git a/crawl-ref/source/mstuff2.cc b/crawl-ref/source/mstuff2.cc
index 7b7822af94..e479659526 100644
--- a/crawl-ref/source/mstuff2.cc
+++ b/crawl-ref/source/mstuff2.cc
@@ -2152,6 +2152,9 @@ bool orc_battle_cry(monsters *chief)
&& mons_species(mons->type) == MONS_ORC
&& mons_aligned(boss_index, i)
&& mons->hit_dice < chief->hit_dice
+ && !mons->has_ench(ENCH_BERSERK)
+ && !mons->paralysed()
+ && !mons->confused()
&& chief->can_see(mons))
{
mon_enchant ench = mons->get_ench(ENCH_BATTLE_FRENZY);
@@ -2159,7 +2162,7 @@ bool orc_battle_cry(monsters *chief)
{
const int dur =
random_range(9, 15) * speed_to_duration(mons->speed);
-
+
if (ench.ench != ENCH_NONE)
{
ench.degree = level;
@@ -2174,6 +2177,10 @@ bool orc_battle_cry(monsters *chief)
dur));
}
affected.push_back(mons);
+
+ if (mons->asleep())
+ behaviour_event( mons, ME_DISTURB, MHITNOT,
+ chief->x, chief->y );
}
}
}
@@ -2181,11 +2188,11 @@ bool orc_battle_cry(monsters *chief)
if (!affected.empty())
{
if (you.can_see(chief) && player_can_hear(chief->x, chief->y))
- {
mprf(MSGCH_SOUND, "%s roars a battle-cry!",
chief->name(DESC_CAP_THE).c_str());
- noisy(15, chief->x, chief->y);
- }
+
+ // The yell happens whether you happen to see it or not.
+ noisy(15, chief->x, chief->y);
// Disabling detailed frenzy announcement because it's so spammy.
#ifdef ANNOUNCE_BATTLE_FRENZY
diff --git a/crawl-ref/source/newgame.cc b/crawl-ref/source/newgame.cc
index 0726a9ea73..221187b679 100644
--- a/crawl-ref/source/newgame.cc
+++ b/crawl-ref/source/newgame.cc
@@ -2510,6 +2510,19 @@ static void newgame_make_item(int slot, equipment_type eqslot,
int sub_type, int qty = 1,
int plus = 0, int plus2 = 0)
{
+ if (slot == -1)
+ {
+ for (int i = 0; i < ENDOFPACK; ++i)
+ {
+ if (!is_valid_item(you.inv[i]))
+ {
+ slot = i;
+ break;
+ }
+ }
+ ASSERT(slot != -1);
+ }
+
item_def &item(you.inv[slot]);
item.base_type = base;
item.sub_type = sub_type;
@@ -3843,9 +3856,9 @@ bool give_items_skills()
}
if (you.species == SP_MERFOLK)
- // Merfolk are spear hunters -- clobber bow, give six javelins
- // possibly allow choice between javelin and net
{
+ // Merfolk are spear hunters -- clobber bow, give six javelins
+ // possibly allow choice between javelin and net
you.inv[1] = you.inv[2];
you.equip[EQ_BODY_ARMOUR] = 1;
newgame_make_item(2, EQ_NONE, OBJ_MISSILES, MI_JAVELIN, 6);
@@ -3862,9 +3875,18 @@ bool give_items_skills()
switch (you.species)
{
+ case SP_OGRE:
+ // Ogres chop up their food without finesse.
+ you.inv[0].sub_type = WPN_HAND_AXE;
+ you.inv[1].quantity = 0;
+
+ // And they get to throw rocks.
+ you.inv[3].sub_type = MI_LARGE_ROCK;
+ you.inv[3].quantity = 3;
+ break;
+
case SP_HALFLING:
case SP_GNOME:
- case SP_OGRE:
you.inv[3].quantity += random2avg(15, 2);
you.inv[3].sub_type = MI_SLING_BULLET;
you.inv[1].sub_type = WPN_SLING;
@@ -3900,6 +3922,9 @@ bool give_items_skills()
you.skills[SK_POLEARMS] = 2;
you.skills[SK_DODGING] = 2;
you.skills[SK_THROWING] += 3;
+
+ // And a hunting knife.
+ newgame_make_item(-1, EQ_NONE, OBJ_WEAPONS, WPN_KNIFE);
break;
default:
diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc
index d40d691bb6..ae2b6f621e 100644
--- a/crawl-ref/source/player.cc
+++ b/crawl-ref/source/player.cc
@@ -916,8 +916,9 @@ int player_hunger_rate(void)
hunger += 2 * player_equip_ego_type( EQ_WEAPON, SPWPN_VAMPIRES_TOOTH );
}
- // troll leather armour
- hunger += player_equip( EQ_BODY_ARMOUR, ARM_TROLL_LEATHER_ARMOUR );
+ // troll leather armour
+ if (you.species != SP_TROLL)
+ hunger += player_equip( EQ_BODY_ARMOUR, ARM_TROLL_LEATHER_ARMOUR );
// randarts
hunger += scan_randarts(RAP_METABOLISM);
@@ -5850,6 +5851,12 @@ void player::moveto(const coord_def &c)
dungeon_events.fire_position_event(DET_PLAYER_MOVED, c);
}
+bool player::can_throw_rocks() const
+{
+ return (species == SP_OGRE || species == SP_TROLL
+ || species == SP_OGRE_MAGE);
+}
+
////////////////////////////////////////////////////////////////////////////
PlaceInfo::PlaceInfo()
diff --git a/crawl-ref/source/spells1.cc b/crawl-ref/source/spells1.cc
index 7b71d46c16..69f75555a1 100644
--- a/crawl-ref/source/spells1.cc
+++ b/crawl-ref/source/spells1.cc
@@ -228,7 +228,7 @@ int cast_fire_storm(int powc, bolt &beam)
beam.ench_power = powc; // used for radius
beam.name = "great blast of fire";
beam.hit = 20 + powc / 10;
- beam.damage = calc_dice( 6, 15 + powc );
+ beam.damage = calc_dice( 9, 20 + powc );
explosion( beam );
mpr("A raging storm of fire appears!");
diff --git a/crawl-ref/source/spells2.cc b/crawl-ref/source/spells2.cc
index cfa0b9f76a..8ca8b6cecc 100644
--- a/crawl-ref/source/spells2.cc
+++ b/crawl-ref/source/spells2.cc
@@ -822,6 +822,7 @@ void cast_toxic_radiance(void)
poison_player(2);
}
+ named_thing_collection affected_monsters;
// determine which monsters are hit by the radiance: {dlb}
for (int toxy = 0; toxy < MAX_MONSTERS; toxy++)
{
@@ -834,11 +835,14 @@ void cast_toxic_radiance(void)
// this check should not be !monster->invisible().
if (!monster->has_ench(ENCH_INVIS))
{
- poison_monster(monster, KC_YOU);
+ bool affected =
+ poison_monster(monster, KC_YOU, 1, false, false);
- if (coinflip()) // 50-50 chance for a "double hit" {dlb}
- poison_monster(monster, KC_YOU);
+ if (coinflip() && poison_monster(monster, KC_YOU, false, false))
+ affected = true;
+ if (affected)
+ affected_monsters.add_thing(monster->name(DESC_PLAIN));
}
else if (player_see_invis())
{
@@ -848,7 +852,21 @@ void cast_toxic_radiance(void)
}
}
}
-} // end cast_toxic_radiance()
+
+ if (!affected_monsters.empty())
+ {
+ const std::string message =
+ make_stringf("%s %s poisoned.",
+ affected_monsters.describe(DESC_CAP_THE).c_str(),
+ affected_monsters.size() == 1? "is" : "are");
+ if (static_cast<int>(message.length()) < get_number_of_cols() - 2)
+ mpr(message.c_str());
+ else
+ // Exclamation mark to suggest that a lot of creatures were
+ // affected.
+ mpr("The monsters around you are poisoned!");
+ }
+}
void cast_refrigeration(int pow)
{
diff --git a/crawl-ref/source/spl-book.cc b/crawl-ref/source/spl-book.cc
index 99fcc53130..8c8d671160 100644
--- a/crawl-ref/source/spl-book.cc
+++ b/crawl-ref/source/spl-book.cc
@@ -1495,14 +1495,19 @@ int staff_spell( int staff )
return (-1);
}
- // All checks passed, we can cast the spell
- if (your_spells(spell, powc, false) == SPRET_ABORT)
+ const int flags = get_spell_flags(spell);
+ // Labyrinths block divinations.
+ if (you.level_type == LEVEL_LABYRINTH
+ && testbits(flags, SPFLAG_MAPPING))
+ {
+ mpr("Something interferes with your magic!");
+ }
+ // All checks passed, we can cast the spell
+ else if (your_spells(spell, powc, false) == SPRET_ABORT)
return (-1);
make_hungry( food, true );
-
istaff.plus -= mana;
-
you.wield_change = true;
you.turn_is_over = true;
diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc
index ffe21b064e..88629617eb 100644
--- a/crawl-ref/source/spl-cast.cc
+++ b/crawl-ref/source/spl-cast.cc
@@ -927,7 +927,18 @@ spret_type your_spells( spell_type spell, int powc, bool allow_fail )
dec_penance(GOD_SIF_MUNA, 1);
}
- if (spfl < spell_fail(spell))
+ const int spfail_chance = spell_fail(spell);
+ // Divination mappings backfire in Labyrinths.
+ if (you.level_type == LEVEL_LABYRINTH
+ && testbits(flags, SPFLAG_MAPPING))
+ {
+ mprf(MSGCH_WARN,
+ "The warped magic of this place twists your "
+ "spell in on itself!");
+ spfl = spfail_chance / 2 - 1;
+ }
+
+ if (spfl < spfail_chance)
{
spellcasting_side_effects(spell, true);
@@ -955,14 +966,14 @@ spret_type your_spells( spell_type spell, int powc, bool allow_fail )
// spells can be quite nasty: 9 * 9 * 90 / 500 = 15
// points of contamination!
int nastiness = spell_mana(spell) * spell_mana(spell)
- * (spell_fail(spell) - spfl) + 250;
+ * (spfail_chance - spfl) + 250;
const int cont_points = div_rand_round(nastiness, 500);
contaminate_player( cont_points );
miscast_effect( sptype, spell_mana(spell),
- spell_fail(spell) - spfl, 100 );
+ spfail_chance - spfl, 100 );
return (SPRET_FAIL);
}
diff --git a/crawl-ref/source/spl-cast.h b/crawl-ref/source/spl-cast.h
index 350a07d6da..75f50d82ae 100644
--- a/crawl-ref/source/spl-cast.h
+++ b/crawl-ref/source/spl-cast.h
@@ -26,7 +26,8 @@ enum spflag_type
SPFLAG_TARGETING_MASK = 0x000f, // used to test for targeting
SPFLAG_HELPFUL = 0x0010, // TARG_FRIENDS used
SPFLAG_NOT_SELF = 0x0020, // aborts on isMe
- SPFLAG_UNHOLY = 0x0040 // counts at "unholy"
+ SPFLAG_UNHOLY = 0x0040, // counts at "unholy"
+ SPFLAG_MAPPING = 0x0080 // a mapping spell of some kind
};
enum spret_type
diff --git a/crawl-ref/source/spl-data.h b/crawl-ref/source/spl-data.h
index 812ba85aae..c50c5e40da 100644
--- a/crawl-ref/source/spl-data.h
+++ b/crawl-ref/source/spl-data.h
@@ -715,7 +715,7 @@
{
SPELL_DETECT_TRAPS, "Detect Traps",
SPTYP_DIVINATION,
- SPFLAG_NONE,
+ SPFLAG_MAPPING,
2,
50,
NULL,
@@ -782,7 +782,7 @@
{
SPELL_MAGIC_MAPPING, "Magic Mapping",
SPTYP_DIVINATION | SPTYP_EARTH,
- SPFLAG_NONE,
+ SPFLAG_MAPPING,
4,
45,
NULL,
@@ -879,7 +879,7 @@
{
SPELL_DETECT_ITEMS, "Detect Items",
SPTYP_DIVINATION,
- SPFLAG_NONE,
+ SPFLAG_MAPPING,
2,
50,
NULL,
@@ -1385,7 +1385,7 @@
{
SPELL_DETECT_CREATURES, "Detect Creatures",
SPTYP_DIVINATION,
- SPFLAG_NONE,
+ SPFLAG_MAPPING,
2,
60, // not 50, note the fuzz
NULL,
diff --git a/crawl-ref/source/spl-util.cc b/crawl-ref/source/spl-util.cc
index 71b773ac83..3f9bcffad7 100644
--- a/crawl-ref/source/spl-util.cc
+++ b/crawl-ref/source/spl-util.cc
@@ -75,13 +75,14 @@ void init_spell_descs(void)
spell_list[spelldata[i].id] = i;
} // end init_spell_descs()
-spell_type spell_by_name(std::string name)
+spell_type spell_by_name(std::string name, bool partial_match)
{
if (name.empty())
return (SPELL_NO_SPELL);
lowercase(name);
-
+
+ int spellmatch = -1;
for (int i = 0; i < NUM_SPELLS; i++)
{
spell_type type = static_cast<spell_type>(i);
@@ -89,11 +90,16 @@ spell_type spell_by_name(std::string name)
if (!sptitle)
continue;
- if (name == lowercase_string(sptitle))
+ const std::string spell_name = lowercase_string(sptitle);
+ if (name == spell_name)
return (type);
+
+ if (partial_match && spell_name.find(name) != std::string::npos)
+ spellmatch = i;
}
- return (SPELL_NO_SPELL);
+ return (spellmatch != -1? static_cast<spell_type>(spellmatch)
+ : SPELL_NO_SPELL);
}
int get_spell_slot_by_letter( char letter )
diff --git a/crawl-ref/source/spl-util.h b/crawl-ref/source/spl-util.h
index 10428fbc3e..4b393ec514 100644
--- a/crawl-ref/source/spl-util.h
+++ b/crawl-ref/source/spl-util.h
@@ -64,7 +64,7 @@ struct spell_desc
//* * called from: acr
void init_spell_descs(void);
-spell_type spell_by_name(std::string name);
+spell_type spell_by_name(std::string name, bool partial_match = false);
int get_spell_slot_by_letter( char letter );
spell_type get_spell_by_letter( char letter );
diff --git a/crawl-ref/source/traps.cc b/crawl-ref/source/traps.cc
index f8b77fd996..7f9b41e7c9 100644
--- a/crawl-ref/source/traps.cc
+++ b/crawl-ref/source/traps.cc
@@ -755,7 +755,8 @@ bool trap_item(object_class_type base_type, char sub_type,
// don't want to go overboard here. Will only generate up to three
// separate trap items, or less if there are other items present.
if (mitm[ igrd[beam_x][beam_y] ].link != NON_ITEM
- && (item.base_type != OBJ_MISSILES || item.sub_type != MI_THROWING_NET))
+ && (item.base_type != OBJ_MISSILES
+ || item.sub_type != MI_THROWING_NET))
{
if (mitm[ mitm[ igrd[beam_x][beam_y] ].link ].link != NON_ITEM)
return (false);
diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc
index b2e12e140b..d8102554bd 100644
--- a/crawl-ref/source/travel.cc
+++ b/crawl-ref/source/travel.cc
@@ -85,6 +85,9 @@ static level_id last_stair;
// Where travel wants to get to.
static travel_target level_target;
+// Remember the last place explore stopped because autopickup failed.
+static coord_def explore_stopped_pos;
+
// The place in the Vestibule of Hell where all portals to Hell land.
static level_pos travel_hell_entry;
@@ -512,10 +515,12 @@ void travel_init_new_level()
// Zero out last travel coords
you.travel_x = you.travel_y = 0;
- traps_inited = false;
+ traps_inited = false;
curr_excludes.clear();
travel_cache.set_level_excludes();
travel_cache.update_waypoints();
+
+ explore_stopped_pos.reset();
}
/*
@@ -896,6 +901,47 @@ static void explore_find_target_square()
}
}
+void explore_pickup_event(int did_pickup, int tried_pickup)
+{
+ if (!did_pickup && !tried_pickup)
+ return;
+
+ if (!you.running.is_explore())
+ return;
+
+ if (did_pickup)
+ {
+ const int estop =
+ you.running == RMODE_EXPLORE_GREEDY?
+ ES_GREEDY_PICKUP : ES_PICKUP;
+ if ((Options.explore_stop & estop) && prompt_stop_explore(estop))
+ stop_delay();
+ }
+
+ // Greedy explore has no good way to deal with an item that we can't
+ // pick up, so the only thing to do is to stop.
+ if (tried_pickup && you.running == RMODE_EXPLORE_GREEDY)
+ {
+ if (explore_stopped_pos == you.pos()
+ && !Options.pickup_dropped)
+ {
+ const std::string prompt =
+ make_stringf(
+ "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))
+ {
+ mark_items_non_pickup_at(you.pos());
+ // Don't stop explore.
+ return;
+ }
+ }
+ explore_stopped_pos = you.pos();
+ stop_delay();
+ }
+}
+
/*
* Top-level travel control (called from input() in acr.cc).
*
@@ -1006,7 +1052,10 @@ command_type travel()
{
if ((Options.explore_stop & ES_ITEM)
&& prompt_stop_explore(ES_ITEM))
+ {
+ explore_stopped_pos = coord_def(new_x, new_y);
stop_running();
+ }
return direction_to_command( *move_x, *move_y );
}
}
@@ -2292,7 +2341,6 @@ void start_translevel_travel(bool prompt_for_destination)
level_target = target;
}
-
if (level_id::current() == level_target.p.id
&& (level_target.p.pos.x == -1 || level_target.p.pos == you.pos()))
{
@@ -2630,10 +2678,11 @@ static bool find_transtravel_square(const level_pos &target, bool verbose)
if (verbose)
{
- if (target.id != current || target.pos.x != -1 && target.pos != you.pos())
+ if (target.id != current
+ || target.pos.x != -1 && target.pos != you.pos())
+ {
mpr("Sorry, I don't know how to get there.");
- if (target.id == current && target.pos.x != -1 && target.pos == you.pos())
- mpr("You're already here!");
+ }
}
return (false);
@@ -3612,8 +3661,8 @@ static dungeon_feature_type base_grid_type( dungeon_feature_type grid )
if (grid == DNGN_FLOOR_SPECIAL)
return (DNGN_FLOOR);
- // Or secret doors (which currently always look like rock walls):
- if (grid_is_wall(grid))
+ // Merge walls and secret doors.
+ if (grid_is_wall(grid) || grid == DNGN_SECRET_DOOR)
return (DNGN_ROCK_WALL);
return (grid);
diff --git a/crawl-ref/source/travel.h b/crawl-ref/source/travel.h
index 592c9f08f1..3f50591b5f 100644
--- a/crawl-ref/source/travel.h
+++ b/crawl-ref/source/travel.h
@@ -71,6 +71,7 @@ command_type direction_to_command( char x, char y );
bool is_resting( void );
bool can_travel_interlevel();
bool is_traversable(dungeon_feature_type grid);
+void explore_pickup_event(int did_pickup, int tried_pickup);
void find_travel_pos(int you_x, int you_y, char *move_x, char *move_y,
std::vector<coord_def>* coords = NULL);