diff options
author | dshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573> | 2007-10-25 18:23:34 +0000 |
---|---|---|
committer | dshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573> | 2007-10-25 18:23:34 +0000 |
commit | c74d8c41878cff22751311e0c631d22114f1417b (patch) | |
tree | fc3c97c8017bfd68ec64397633abcd1d242a704b | |
parent | f6e4e9e9c96bc7801daaf0ce7339200c0e572aed (diff) | |
download | crawl-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
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 ®ion, { 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); |