diff options
author | j-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573> | 2009-03-28 19:59:33 +0000 |
---|---|---|
committer | j-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573> | 2009-03-28 19:59:33 +0000 |
commit | b51dc9e9720a5cdb08d240da53948d34bb8a6c5a (patch) | |
tree | 907ba1c3a10ce86c5a2b7b06c1a1cacc0da3657f /crawl-ref | |
parent | f7eda5bc39c5971efb204d29b2bf155eda36ce26 (diff) | |
download | crawl-ref-b51dc9e9720a5cdb08d240da53948d34bb8a6c5a.tar.gz crawl-ref-b51dc9e9720a5cdb08d240da53948d34bb8a6c5a.zip |
Xom again:
* tweak values for tension and amusement
* Xom only laughs about "funny" deaths
* gift_timeout rerolling after a bad act depends on its severity
* replace the blink effect with position swapping
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@9561 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref')
-rw-r--r-- | crawl-ref/source/beam.cc | 4 | ||||
-rw-r--r-- | crawl-ref/source/decks.cc | 69 | ||||
-rw-r--r-- | crawl-ref/source/delay.cc | 31 | ||||
-rw-r--r-- | crawl-ref/source/delay.h | 11 | ||||
-rw-r--r-- | crawl-ref/source/describe.cc | 18 | ||||
-rw-r--r-- | crawl-ref/source/effects.cc | 5 | ||||
-rw-r--r-- | crawl-ref/source/hiscores.cc | 10 | ||||
-rw-r--r-- | crawl-ref/source/item_use.cc | 54 | ||||
-rw-r--r-- | crawl-ref/source/misc.cc | 66 | ||||
-rw-r--r-- | crawl-ref/source/misc.h | 2 | ||||
-rw-r--r-- | crawl-ref/source/mon-util.cc | 2 | ||||
-rw-r--r-- | crawl-ref/source/newgame.cc | 2 | ||||
-rw-r--r-- | crawl-ref/source/ouch.cc | 4 | ||||
-rw-r--r-- | crawl-ref/source/xom.cc | 266 | ||||
-rw-r--r-- | crawl-ref/source/xom.h | 2 |
15 files changed, 373 insertions, 173 deletions
diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc index 68977eecb5..605c07b749 100644 --- a/crawl-ref/source/beam.cc +++ b/crawl-ref/source/beam.cc @@ -4827,7 +4827,7 @@ mon_resist_type bolt::apply_enchantment_to_monster(monsters* mon) return (MON_UNAFFECTED); case BEAM_SLOW: - // try to remove haste, if monster is hasted + // Try to remove haste, if monster is hasted. if (mon->del_ench(ENCH_HASTE, true)) { if (simple_monster_message(mon, " is no longer moving quickly.")) @@ -4835,7 +4835,7 @@ mon_resist_type bolt::apply_enchantment_to_monster(monsters* mon) return (MON_AFFECTED); } - // not hasted, slow it + // Not hasted, slow it. if (!mon->has_ench(ENCH_SLOW) && !mons_is_stationary(mon) && mon->add_ench(mon_enchant(ENCH_SLOW, 0, whose_kill()))) diff --git a/crawl-ref/source/decks.cc b/crawl-ref/source/decks.cc index 2e5364414c..659c986278 100644 --- a/crawl-ref/source/decks.cc +++ b/crawl-ref/source/decks.cc @@ -941,7 +941,13 @@ static void _describe_cards(std::vector<card_type> cards) desc = "No description found."; name = uppercase_first(name); - data << "<w>" << name << "</w>" << EOL << desc << EOL; + data << "<w>" << name << "</w>\n" + << get_linebreak_string(desc, get_number_of_cols()) +#ifdef USE_TILE + // For some reason we need another linebreak here, for the tiles version. + << EOL +#endif + << EOL; } formatted_string fs = formatted_string::parse_string(data.str()); clrscr(); @@ -1422,66 +1428,7 @@ static void _swap_monster_card(int power, deck_rarity_type rarity) if (!mon_to_swap) mpr("You spin around."); else - { - monsters& mon(*mon_to_swap); - const coord_def newpos = mon.pos(); - - // Be nice: no swapping into uninhabitable environments. - if (!you.is_habitable(newpos) || !mon.is_habitable(you.pos())) - { - mpr("You spin around."); - return; - } - - const bool mon_caught = mons_is_caught(&mon); - const bool you_caught = you.attribute[ATTR_HELD]; - - // If it was submerged, it surfaces first. - mon.del_ench(ENCH_SUBMERGED); - - // Pick the monster up. - mgrd(newpos) = NON_MONSTER; - mon.moveto(you.pos()); - - // Plunk it down. - mgrd(mon.pos()) = mon_to_swap->mindex(); - - if (you_caught) - { - check_net_will_hold_monster(&mon); - if (!mon_caught) - you.attribute[ATTR_HELD] = 0; - } - - // Move you to its previous location. - move_player_to_grid(newpos, false, true, true, false); - - if (mon_caught) - { - if (you.body_size(PSIZE_BODY) >= SIZE_GIANT) - { - mpr("The net rips apart!"); - you.attribute[ATTR_HELD] = 0; - int net = get_trapping_net(you.pos()); - if (net != NON_ITEM) - destroy_item(net); - } - else - { - you.attribute[ATTR_HELD] = 10; - mpr("You become entangled in the net!"); - - // Xom thinks this is hilarious if you trap yourself this way. - if (you_caught) - xom_is_stimulated(16); - else - xom_is_stimulated(255); - } - - if (!you_caught) - mon.del_ench(ENCH_HELD, true); - } - } + swap_with_monster(mon_to_swap); } static void _velocity_card(int power, deck_rarity_type rarity) diff --git a/crawl-ref/source/delay.cc b/crawl-ref/source/delay.cc index d1f9f04bc1..7b1f8f0e85 100644 --- a/crawl-ref/source/delay.cc +++ b/crawl-ref/source/delay.cc @@ -676,6 +676,16 @@ bool is_vampire_feeding() return (delay.type == DELAY_FEED_VAMPIRE); } +bool player_stair_delay() +{ + if (!you_are_delayed()) + return (false); + + const delay_queue_item &delay = you.delay_queue.front(); + return (delay.type == DELAY_ASCENDING_STAIRS + || delay.type == DELAY_DESCENDING_STAIRS); +} + // Check whether there are monsters who might be influenced by Recite. // Returns 0, if no monsters found // Returns 1, if eligible audience found @@ -1539,10 +1549,22 @@ void armour_wear_effects(const int item_slot) mpr("Oops, that feels deathly cold."); learned_something_new(TUT_YOU_CURSED); + int amusement = 32; + // Cursed cloaks prevent you from removing body armour. - const int cloak_mult = (get_armour_slot(arm) == EQ_CLOAK) ? 2 : 1; + if (get_armour_slot(arm) == EQ_CLOAK) + amusement *= 2; + + if (!known_cursed) + { + amusement *= 2; - xom_is_stimulated(32 * cloak_mult * (!known_cursed ? 2 : 1)); + god_type god; + if (origin_is_god_gift(arm, &god) && god == GOD_XOM) + amusement *= 2; + } + + xom_is_stimulated(amusement); } if (eq_slot == EQ_SHIELD) @@ -1757,11 +1779,8 @@ static bool _should_stop_activity(const delay_queue_item &item, delay_type curr = current_delay_action(); - if (ai == AI_SEE_MONSTER && (curr == DELAY_ASCENDING_STAIRS - || curr == DELAY_DESCENDING_STAIRS)) - { + if (ai == AI_SEE_MONSTER && player_stair_delay()) return (false); - } if (ai == AI_FULL_HP || ai == AI_FULL_MP) { diff --git a/crawl-ref/source/delay.h b/crawl-ref/source/delay.h index 81a81b1f26..d5b9363679 100644 --- a/crawl-ref/source/delay.h +++ b/crawl-ref/source/delay.h @@ -68,14 +68,15 @@ struct ait_hp_loss void start_delay( delay_type type, int turns, int parm1 = 0, int parm2 = 0 ); void stop_delay( bool stop_stair_travel = false ); -bool you_are_delayed( void ); -delay_type current_delay_action( void ); -int check_recital_audience( void ); -void handle_delay( void ); +bool you_are_delayed(); +delay_type current_delay_action(); +int check_recital_audience(); +void handle_delay(); bool is_run_delay(int delay); bool is_being_butchered(const item_def &item, bool just_first = true); -bool is_vampire_feeding( void ); +bool is_vampire_feeding(); +bool player_stair_delay(); void stop_butcher_delay(); void handle_interrupted_swap(bool swap_if_safe = false, bool force_unsafe = false, diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc index dfb4517cf3..80d45c124e 100644 --- a/crawl-ref/source/describe.cc +++ b/crawl-ref/source/describe.cc @@ -81,18 +81,18 @@ static void _append_value( std::string & description, int valu, bool plussed ) int count_desc_lines(const std::string _desc, const int width) { - std::string desc = get_linebreak_string(_desc, width); + std::string desc = get_linebreak_string(_desc, width); - int count = 0; - for (int i = 0, size = desc.size(); i < size; i++) - { - const char ch = desc[i]; + int count = 0; + for (int i = 0, size = desc.size(); i < size; i++) + { + const char ch = desc[i]; - if (ch == '\n' || ch == '$') - count++; - } + if (ch == '\n' || ch == '$') + count++; + } - return count; + return count; } //--------------------------------------------------------------- diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc index ed5b3e8341..76477d6331 100644 --- a/crawl-ref/source/effects.cc +++ b/crawl-ref/source/effects.cc @@ -2270,7 +2270,7 @@ bool vitrify_area(int radius) // This hinges on clear wall types having the same order as non-clear ones! const int clear_plus = DNGN_CLEAR_ROCK_WALL - DNGN_ROCK_WALL; bool something_happened = false; - for ( radius_iterator ri(you.pos(), radius, false, false); ri; ++ri ) + for (radius_iterator ri(you.pos(), radius, false, false); ri; ++ri) { const dungeon_feature_type grid = grd(*ri); @@ -2278,8 +2278,7 @@ bool vitrify_area(int radius) || grid == DNGN_STONE_WALL || grid == DNGN_PERMAROCK_WALL ) { - grd(*ri) - = static_cast<dungeon_feature_type>(grid + clear_plus); + grd(*ri) = static_cast<dungeon_feature_type>(grid + clear_plus); set_terrain_changed(ri->x, ri->y); something_happened = true; } diff --git a/crawl-ref/source/hiscores.cc b/crawl-ref/source/hiscores.cc index 1b5eb95249..5132af79e5 100644 --- a/crawl-ref/source/hiscores.cc +++ b/crawl-ref/source/hiscores.cc @@ -761,9 +761,9 @@ void scorefile_entry::init_death_cause(int dam, int dsrc, // for death by monster if ((death_type == KILLED_BY_MONSTER - || death_type == KILLED_BY_BEAM - || death_type == KILLED_BY_SPORE - || death_type == KILLED_BY_REFLECTION) + || death_type == KILLED_BY_BEAM + || death_type == KILLED_BY_SPORE + || death_type == KILLED_BY_REFLECTION) && !invalid_monster_index(death_source) && menv[death_source].type != -1) { @@ -1110,8 +1110,8 @@ const char *scorefile_entry::damage_verb() const // bwr: changed "blasted" since this is for melee return (final_hp > -6) ? "Slain" : (final_hp > -14) ? "Mangled" : - (final_hp > -22) ? "Demolished" : - "Annihilated"; + (final_hp > -22) ? "Demolished" + : "Annihilated"; } std::string scorefile_entry::death_source_desc() const diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc index 1ef169b56b..97c0a958a0 100644 --- a/crawl-ref/source/item_use.cc +++ b/crawl-ref/source/item_use.cc @@ -725,7 +725,15 @@ void wield_effects(int item_wield_2, bool showMsgs) mpr("Space warps around you for a moment!"); if (!was_known) - xom_is_stimulated(32); + { + // Xom loves when you ID a distortion weapon this way, + // and even more so if he gifted the weapon himself. + god_type god; + if (origin_is_god_gift(item, &god) && god == GOD_XOM) + xom_is_stimulated(255); + else + xom_is_stimulated(128); + } break; case SPWPN_SCYTHE_OF_CURSES: @@ -748,10 +756,20 @@ void wield_effects(int item_wield_2, bool showMsgs) if (item_cursed(item)) { mpr("It sticks to your hand!"); - if (known_cursed || was_known && special == SPWPN_SCYTHE_OF_CURSES) - xom_is_stimulated(32); - else - xom_is_stimulated(64); + int amusement = 16; + if (!known_cursed + && !(was_known && special == SPWPN_SCYTHE_OF_CURSES)) + { + amusement *= 2; + god_type god; + if (origin_is_god_gift(item, &god) && god == GOD_XOM) + amusement *= 2; + } + const int wpn_skill = weapon_skill(item.base_type, item.sub_type); + if (wpn_skill != SK_FIGHTING && you.skills[wpn_skill] == 0) + amusement *= 2; + + xom_is_stimulated(amusement); } break; @@ -3300,10 +3318,16 @@ void jewellery_wear_effects(item_def &item) jewellery_is_amulet(item)? "amulet" : "ring"); learned_something_new(TUT_YOU_CURSED); - if (known_cursed || known_bad) - xom_is_stimulated(64); - else - xom_is_stimulated(128); + int amusement = 32; + if (!known_cursed && !known_bad) + { + amusement *= 2; + + god_type god; + if (origin_is_god_gift(item, &god) && god == GOD_XOM) + amusement *= 2; + } + xom_is_stimulated(amusement); } // Cursed or not, we know that since we've put the ring on. @@ -4825,6 +4849,7 @@ void read_scroll(int slot) bool id_the_scroll = true; // to prevent unnecessary repetition bool tried_on_item = false; // used to modify item (?EA, ?RC, ?ID) + bool bad_effect = false; // for Xom: result is bad (or at least dangerous) switch (which_scroll) { case SCR_PAPER: @@ -4918,6 +4943,7 @@ void read_scroll(int slot) // This is only naughty if you know you're doing it. did_god_conduct(DID_UNHOLY, 10, item_type_known(scroll)); + bad_effect = true; break; case SCR_IMMOLATION: @@ -4928,6 +4954,7 @@ void read_scroll(int slot) dec_inv_item_quantity(item_slot, 1); immolation(10, IMMOLATION_SCROLL, you.pos(), alreadyknown, &you); + bad_effect = true; break; } @@ -4944,6 +4971,7 @@ void read_scroll(int slot) // Also sets wield_change. do_curse_item( *you.weapon(), false ); learned_something_new(TUT_YOU_CURSED); + bad_effect = true; } break; @@ -5068,6 +5096,7 @@ void read_scroll(int slot) // Make the name before we curse it. do_curse_item( you.inv[you.equip[affected]], false ); learned_something_new(TUT_YOU_CURSED); + bad_effect = true; break; } @@ -5123,8 +5152,9 @@ void read_scroll(int slot) if (!alreadyknown && dangerous) { // Xom loves it when you read an unknown scroll and there is a - // dangerous monster nearby... - xom_is_stimulated(255); + // dangerous monster nearby... (though not as much as potions + // since there are no *really* bad scrolls, merely useless ones). + xom_is_stimulated(bad_effect ? 128 : 64); } } @@ -5257,7 +5287,7 @@ void use_randart(item_def &item, bool unmeld) { // Xom loves it when you use an unknown random artefact and // there is a dangerous monster nearby... - xom_is_stimulated(255); + xom_is_stimulated(128); } #undef unknown_proprt } diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc index 36d1bd7b08..7713fd7ca3 100644 --- a/crawl-ref/source/misc.cc +++ b/crawl-ref/source/misc.cc @@ -3110,3 +3110,69 @@ bool is_dragonkind(const actor *act) return (false); } + +// Make the player swap positions with a given monster. +void swap_with_monster(monsters *mon_to_swap) +{ + monsters& mon(*mon_to_swap); + ASSERT(mon.alive()); + const coord_def newpos = mon.pos(); + + // Be nice: no swapping into uninhabitable environments. + if (!you.is_habitable(newpos) || !mon.is_habitable(you.pos())) + { + mpr("You spin around."); + return; + } + + const bool mon_caught = mons_is_caught(&mon); + const bool you_caught = you.attribute[ATTR_HELD]; + + // If it was submerged, it surfaces first. + mon.del_ench(ENCH_SUBMERGED); + + mprf("You swap places with %s.", mon.name(DESC_NOCAP_THE).c_str()); + + // Pick the monster up. + mgrd(newpos) = NON_MONSTER; + mon.moveto(you.pos()); + + // Plunk it down. + mgrd(mon.pos()) = mon_to_swap->mindex(); + + if (you_caught) + { + check_net_will_hold_monster(&mon); + if (!mon_caught) + you.attribute[ATTR_HELD] = 0; + } + + // Move you to its previous location. + move_player_to_grid(newpos, false, true, true, false); + + if (mon_caught) + { + if (you.body_size(PSIZE_BODY) >= SIZE_GIANT) + { + mpr("The net rips apart!"); + you.attribute[ATTR_HELD] = 0; + int net = get_trapping_net(you.pos()); + if (net != NON_ITEM) + destroy_item(net); + } + else + { + you.attribute[ATTR_HELD] = 10; + mpr("You become entangled in the net!"); + + // Xom thinks this is hilarious if you trap yourself this way. + if (you_caught) + xom_is_stimulated(16); + else + xom_is_stimulated(255); + } + + if (!you_caught) + mon.del_ench(ENCH_HELD, true); + } +} diff --git a/crawl-ref/source/misc.h b/crawl-ref/source/misc.h index ec3804ea30..400007aad5 100644 --- a/crawl-ref/source/misc.h +++ b/crawl-ref/source/misc.h @@ -116,5 +116,5 @@ bool stop_attack_prompt(const monsters *mon, bool beam_attack, bool is_orckind(const actor *act); bool is_dragonkind(const actor *act); - +void swap_with_monster(monsters *mon_to_swap); #endif diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc index 3738e09ac0..1bd90804d2 100644 --- a/crawl-ref/source/mon-util.cc +++ b/crawl-ref/source/mon-util.cc @@ -5718,7 +5718,7 @@ void monsters::expose_to_element(beam_type flavour, int strength) { case BEAM_COLD: if (mons_class_flag(this->type, M_COLD_BLOOD) && coinflip()) - add_ench(ENCH_SLOW); + slow_down(this, strength); break; default: break; diff --git a/crawl-ref/source/newgame.cc b/crawl-ref/source/newgame.cc index 826fceb758..4f02c1060a 100644 --- a/crawl-ref/source/newgame.cc +++ b/crawl-ref/source/newgame.cc @@ -5020,7 +5020,7 @@ bool _give_items_skills() // The new Xom also uses gift_timeout in his own special way... // (Namely, a countdown to becoming bored.) - you.gift_timeout = random2(40) + random2(40); + you.gift_timeout = std::max(5, random2(40) + random2(40)); } else // Makhleb or Lugonu { diff --git a/crawl-ref/source/ouch.cc b/crawl-ref/source/ouch.cc index 718f0c7a7a..d955dfdfdd 100644 --- a/crawl-ref/source/ouch.cc +++ b/crawl-ref/source/ouch.cc @@ -1079,9 +1079,7 @@ void end_game( scorefile_entry &se ) for (int i = 0; i < ENDOFPACK; i++) { if (you.inv[i].base_type != 0) - { set_ident_type( you.inv[i], ID_KNOWN_TYPE ); - } } if (!dump_char( morgue_name(se.death_time), !dead, true, &se )) @@ -1147,7 +1145,7 @@ void end_game( scorefile_entry &se ) if (dead) { mpr("You die..."); // insert player name here? {dlb} - xom_death_message(); + xom_death_message((kill_method_type) se.death_type); flush_prev_message(); viewwindow(true, false); // don't do for leaving/winning characters diff --git a/crawl-ref/source/xom.cc b/crawl-ref/source/xom.cc index 20da3b29b1..a080df0d70 100644 --- a/crawl-ref/source/xom.cc +++ b/crawl-ref/source/xom.cc @@ -14,6 +14,7 @@ REVISION("$Rev$"); #include "beam.h" #include "branch.h" #include "database.h" +#include "delay.h" #include "effects.h" #include "it_use2.h" #include "items.h" @@ -38,6 +39,7 @@ REVISION("$Rev$"); #include "state.h" #include "stuff.h" #include "transfor.h" +#include "traps.h" #include "view.h" #include "xom.h" @@ -175,7 +177,7 @@ static void _xom_is_stimulated(int maxinterestingness, interestingness = std::min(255, interestingness); -#if DEBUG_RELIGION || DEBUG_GIFTS || DEBUG_XOM +#if defined(DEBUG_RELIGION) || defined(DEBUG_GIFTS) || defined(DEBUG_XOM) mprf(MSGCH_DIAGNOSTICS, "Xom: gift_timeout: %d, maxinterestingness = %d, interestingness = %d", you.gift_timeout, maxinterestingness, interestingness); @@ -240,20 +242,26 @@ void xom_tick() if (one_chance_in(3)) { - if (_xom_is_bored()) - xom_acts(abs(you.piety - MAX_PIETY/2)); - else + const int tension = get_tension(GOD_XOM); + const int chance = (tension == 0 ? 1 : + tension <= 5 ? 2 : + tension <= 10 ? 3 : + tension <= 20 ? 4 + : 5); + + // During tension, Xom may briefly forget about being bored. + if (_xom_is_bored() && x_chance_in_y(chance-1, 4)) { - const int tension = get_tension(GOD_XOM); - const int chance = (tension == 0 ? 1 : - tension <= 5 ? 2 : - tension <= 10 ? 3 : - tension <= 20 ? 4 - : 5); - - if (x_chance_in_y(chance, 5)) - xom_acts(abs(you.piety - MAX_PIETY/2), tension); + you.gift_timeout += random2(chance*20); +#if defined(DEBUG_RELIGION) || defined(DEBUG_XOM) + mprf(MSGCH_DIAGNOSTICS, + "tension %d (chance: %d) -> increase interest to %d", + tension, chance, you.gift_timeout); +#endif } + + if (x_chance_in_y(chance, 5)) + xom_acts(abs(you.piety - MAX_PIETY/2), tension); } } @@ -293,7 +301,7 @@ static void _xom_makes_you_cast_random_spell(int sever, int tension) god_speaks(GOD_XOM, _get_xom_speech("spell effect").c_str()); -#if DEBUG_DIAGNOSTICS || DEBUG_RELIGION || DEBUG_XOM +#if defined(DEBUG_DIAGNOSTICS) || defined(DEBUG_RELIGION) || defined(DEBUG_XOM) mprf(MSGCH_DIAGNOSTICS, "_xom_makes_you_cast_random_spell(); spell: %d, spellenum: %d", spell, spellenum); @@ -999,50 +1007,125 @@ static bool _xom_polymorph_nearby_monster(bool helpful) return (rc); } -// Blink every monster on this level and the player. -static bool _xom_rearrange_pieces(int sever) +static void _confuse_monster(monsters mons, int sever) { - bool rc = false; +// monsters& mons(*mon); - // Every now and then, Xom also confuses them all. - const bool confusem = one_chance_in(10); + if (!mons_class_is_confusable(mons.type)) + return; - // Not just every monster in sight - oh no. Every monster on this - // level! + const bool was_confused = mons.confused(); + if (mons.add_ench(mon_enchant(ENCH_CONFUSION, 0, KC_FRIENDLY, + random2(sever)))) + { + if (was_confused) + simple_monster_message(&mons, " looks rather more confused."); + else + simple_monster_message(&mons, " looks rather confused."); + } +} + +static bool _swap_monsters(monsters *m1, monsters *m2) +{ + monsters& mon1(*m1); + monsters& mon2(*m2); + + const bool mon1_caught = mons_is_caught(&mon1); + const bool mon2_caught = mons_is_caught(&mon2); + + const coord_def mon1_pos = mon1.pos(); + const coord_def mon2_pos = mon2.pos(); + + if (!mon2.is_habitable(mon1_pos) || !mon1.is_habitable(mon2_pos)) + return (false); + + // Make submerged monsters unsubmerge. + mon1.del_ench(ENCH_SUBMERGED); + mon2.del_ench(ENCH_SUBMERGED); + + mgrd(mon1_pos) = mon2.mindex(); + mon1.moveto(mon2_pos); + mgrd(mon2_pos) = mon1.mindex(); + mon2.moveto(mon1_pos); + + if (mon1_caught && !mon2_caught) + { + check_net_will_hold_monster(&mon2); + mon1.del_ench(ENCH_HELD, true); + + } + else if (mon2_caught && !mon1_caught) + { + check_net_will_hold_monster(&mon1); + mon2.del_ench(ENCH_HELD, true); + } + + return (true); +} + +// Swap places with a random monster and, depending on severity, also +// between monsters. This can be pretty bad if there are a lot of hostile +// monsters around. +static bool _xom_rearrange_pieces(int sever) +{ + if (player_stair_delay()) + return (false); + + std::vector<monsters *> mons; for (unsigned i = 0; i < MAX_MONSTERS; ++i) { - monsters* monster = &menv[i]; + monsters* m = &menv[i]; - if (!monster->alive()) + if (!m->alive()) continue; - if (monster_blink(monster)) + if (!see_grid(m->pos())) + continue; + + mons.push_back(m); + } + if (mons.empty()) + return (false); + + god_speaks(GOD_XOM, _get_xom_speech("rearrange the pieces").c_str()); + + const int num_mons = mons.size(); + + // Swap places with a random monster. + monsters *mon = mons[random2(num_mons)]; + swap_with_monster(mon); + + // Occasionally confuse said monster. + if (one_chance_in(5)) + _confuse_monster(*mon, sever); + + if (num_mons > 1 && x_chance_in_y(sever,70)) + { + bool did_message = false; + const int max_repeats = std::min(num_mons/2, 8); + const int repeats = std::min(random2(sever/10)+1, max_repeats); + for (int i = 0; i < repeats; ++i) { - // Only give a message once. - if (!rc) - god_speaks(GOD_XOM, - _get_xom_speech("rearrange the pieces").c_str()); + const int mon1 = random2(num_mons); + int mon2 = mon1; + while (mon1 == mon2) + mon2 = random2(num_mons); - if (confusem) + if (_swap_monsters(mons[mon1], mons[mon2])) { - if (mons_class_is_confusable(monster->type) - && monster->add_ench(mon_enchant(ENCH_CONFUSION, 0, - KC_FRIENDLY, - random2(sever)))) + if (!did_message) { - simple_monster_message(monster, " looks rather confused."); + mpr("Some monsters swap places."); + did_message = true; } + if (one_chance_in(5)) + _confuse_monster(*mons[mon1], sever); + if (one_chance_in(5)) + _confuse_monster(*mons[mon2], sever); } - rc = true; } } - - // If Xom blinked at least one monster, blink the player, too, and - // then consider this act done. - if (rc) - random_blink(false); - - return (rc); + return (true); } static bool _xom_give_mutations(bool good) @@ -1077,6 +1160,7 @@ static bool _xom_give_mutations(bool good) return (rc); } +// Summons a permanent ally. static bool _xom_send_major_ally(int sever) { bool rc = false; @@ -1176,6 +1260,8 @@ static bool _xom_is_good(int sever, int tension) done = _xom_do_potion(); else if (x_chance_in_y(3, sever)) { + // There are a lot less non-tension spells than tension ones, + // so use them more rarely. if (tension > 0 || one_chance_in(3)) { _xom_makes_you_cast_random_spell(sever, tension); @@ -1197,13 +1283,13 @@ static bool _xom_is_good(int sever, int tension) done = _xom_send_allies(sever); else if (x_chance_in_y(8, sever)) done = _xom_polymorph_nearby_monster(true); - else if (random2(tension) < 15 && x_chance_in_y(9, sever)) + else if (tension > 0 && x_chance_in_y(9, sever)) + done = _xom_rearrange_pieces(sever); + else if (random2(tension) < 15 && x_chance_in_y(10, sever)) { _xom_give_item(sever); done = true; } - else if (x_chance_in_y(10, sever) && (you.level_type != LEVEL_ABYSS)) - done = _xom_rearrange_pieces(sever); else if (x_chance_in_y(11, sever) && (you.level_type != LEVEL_ABYSS)) { // The Xom teleportation train takes you on instant teleportation @@ -1223,7 +1309,7 @@ static bool _xom_is_good(int sever, int tension) else if (random2(tension) < 5 && x_chance_in_y(12, sever)) { // This can fail with radius 1, or in open areas. - if (vitrify_area(random2avg(sever / 2, 3) + 1)) + if (vitrify_area(random2avg(sever/4,2) + 1)) { god_speaks(GOD_XOM, _get_xom_speech("vitrification").c_str()); done = true; @@ -1305,8 +1391,10 @@ static void _xom_zero_miscast() } if (in_view[DNGN_DEEP_WATER]) + { messages.push_back("From the corner of your eye you spot something " "lurking in the deep water."); + } if (in_view[DNGN_ORCISH_IDOL]) { @@ -1846,6 +1934,9 @@ static bool _xom_is_bad(int sever, int tension) god_acting gdact(GOD_XOM); + // Rough estimate of how bad a Xom effect hits the player, + // scaled between 1 (harmless) and 5 (disastrous). + int badness = 1; while (!done) { // Did Xom kill the player? @@ -1863,10 +1954,14 @@ static bool _xom_is_bad(int sever, int tension) done = true; } else if (x_chance_in_y(5, sever)) + { done = _xom_lose_stats(); + badness = 2; + } else if (x_chance_in_y(6, sever)) { _xom_miscast(2, nasty); + badness = 2; done = true; } else if ((!nasty || coinflip()) @@ -1883,37 +1978,66 @@ static bool _xom_is_bad(int sever, int tension) more(); } while (x_chance_in_y(3, 4) && !player_in_a_dangerous_place()); + badness = player_in_a_dangerous_place() ? 3 : 1; done = true; } else if (x_chance_in_y(8, sever)) + { done = _xom_chaos_upgrade_nearby_monster(); + badness = 2 + coinflip(); + } else if (random2(tension) < 10 && x_chance_in_y(9, sever)) + { done = _xom_give_mutations(false); + badness = 3; + } else if (x_chance_in_y(10, sever)) + { done = _xom_polymorph_nearby_monster(false); + badness = 3; + } // It's pointless to confuse player if there's no danger nearby. else if (tension > 0 && x_chance_in_y(11, sever)) + { done = _xom_player_confusion_effect(sever); + badness = (random2(tension) > 5 ? 2 : 1); + } else if (x_chance_in_y(12, sever)) + { done = _xom_draining_torment_effect(sever); + badness = (random2(tension) > 5 ? 3 : 2); + } else if (x_chance_in_y(13, sever)) + { done = _xom_summon_hostiles(sever); + badness = 3 + coinflip(); + } else if (x_chance_in_y(14, sever)) { _xom_miscast(3, nasty); + badness = 4 + coinflip(); done = true; } - else if (one_chance_in(sever)) + else if (one_chance_in(sever) && you.level_type != LEVEL_ABYSS) { - if (you.level_type != LEVEL_ABYSS) - { - god_speaks(GOD_XOM, _get_xom_speech("banishment").c_str()); - banished(DNGN_ENTER_ABYSS, "Xom"); - done = true; - } + god_speaks(GOD_XOM, _get_xom_speech("banishment").c_str()); + banished(DNGN_ENTER_ABYSS, "Xom"); + badness = 5; + done = true; } } + // If we got here because Xom was bored, reset gift timeout according + // to the badness of the effect. + if (done && _xom_is_bored()) + { + const int interest = random2avg(badness*60, 2); + you.gift_timeout = std::min(interest, 255); +#if defined(DEBUG_RELIGION) || defined(DEBUG_XOM) + mprf(MSGCH_DIAGNOSTICS, "badness: %d, new interest: %d", + badness, you.gift_timeout); +#endif + } return (done); } @@ -2046,9 +2170,9 @@ static void _handle_accidental_death(const int orig_hp, void xom_acts(bool niceness, int sever, int tension) { -#if DEBUG_DIAGNOSTICS || DEBUG_RELIGION || DEBUG_XOM - mprf(MSGCH_DIAGNOSTICS, "xom_acts(%u, %d); piety: %u, interest: %u\n", - niceness, sever, you.piety, you.gift_timeout); +#if defined(DEBUG_DIAGNOSTICS) || defined(DEBUG_RELIGION) || defined(DEBUG_XOM) + mprf(MSGCH_DIAGNOSTICS, "xom_acts(%u, %d, %d); piety: %u, interest: %u\n", + niceness, sever, tension, you.piety, you.gift_timeout); #endif #ifdef WIZARD @@ -2101,7 +2225,7 @@ void xom_acts(bool niceness, int sever, int tension) if (tension == -1) tension = get_tension(which_god); -#if DEBUG_RELIGION || DEBUG_XOM || DEBUG_TENSION +#if defined(DEBUG_RELIGION) || defined(DEBUG_XOM) || defined(DEBUG_TENSION) mprf(MSGCH_DIAGNOSTICS, "Xom tension: %d", tension); #endif @@ -2123,10 +2247,6 @@ void xom_acts(bool niceness, int sever, int tension) // Bad mojo. while (!_xom_is_bad(sever, tension)) ; - - // If we got here because Xom was bored, reset gift timeout. - if (_xom_is_bored()) - you.gift_timeout = random2(40) + random2(40); } _handle_accidental_death(orig_hp, orig_stats, orig_mutation); @@ -2245,10 +2365,30 @@ void xom_check_destroyed_item(const item_def& item, int cause) true); } -void xom_death_message() +static bool _death_is_funny(const kill_method_type killed_by) +{ + switch (killed_by) + { + // The less original deaths are boring. + case KILLED_BY_MONSTER: + case KILLED_BY_BEAM: + case KILLED_BY_CLOUD: + case KILLED_BY_FREEZING: + case KILLED_BY_BURNING: + case KILLED_BY_SELF_AIMED: + case KILLED_BY_SOMETHING: + return (false); + default: + // All others are fun (says Xom). + return (true); + } +} + +void xom_death_message(const kill_method_type killed_by) { if (you.religion != GOD_XOM && (!you.worshipped[GOD_XOM] || coinflip())) return; - god_speaks(GOD_XOM, _get_xom_speech("laughter").c_str()); + if (_death_is_funny(killed_by) || you.hp < -1 * random2(10)) + god_speaks(GOD_XOM, _get_xom_speech("laughter").c_str()); } diff --git a/crawl-ref/source/xom.h b/crawl-ref/source/xom.h index 843a94bbbd..7b54f17ffa 100644 --- a/crawl-ref/source/xom.h +++ b/crawl-ref/source/xom.h @@ -35,5 +35,5 @@ inline void xom_acts(int sever, int tension = -1) void xom_check_lost_item(const item_def& item); void xom_check_destroyed_item(const item_def& item, int cause = -1); -void xom_death_message(); +void xom_death_message(const kill_method_type killed_by); #endif |