diff options
author | reaver <address.auto@gmail.com> | 2014-04-12 23:41:56 -0400 |
---|---|---|
committer | Steve Melenchuk <smelenchuk@gmail.com> | 2014-04-14 22:25:16 -0600 |
commit | 6d8a42cd9ae10e2f4931a80236c1b3e001368953 (patch) | |
tree | e9af4cd9aac560a89258a907e08a0ec048532303 | |
parent | 961a08fe896de355d603cf447009c4dac0f8a2ec (diff) | |
download | crawl-ref-6d8a42cd9ae10e2f4931a80236c1b3e001368953.tar.gz crawl-ref-6d8a42cd9ae10e2f4931a80236c1b3e001368953.zip |
Move some main.cc functions to a new file
Specifically player_reacts, decrement_durations, and various helper
functions.
[Committer's note: updated the xcode and MSVC project files too; I don't
guarantee that they work.]
Signed-off-by: Steve Melenchuk <smelenchuk@gmail.com>
-rw-r--r-- | crawl-ref/source/Crawl.xcodeproj/project.pbxproj | 7 | ||||
-rw-r--r-- | crawl-ref/source/MSVC/crawl.vcxproj | 2 | ||||
-rw-r--r-- | crawl-ref/source/MSVC/crawl.vcxproj.filters | 2 | ||||
-rw-r--r-- | crawl-ref/source/Makefile.obj | 1 | ||||
-rw-r--r-- | crawl-ref/source/initfile.cc | 2 | ||||
-rw-r--r-- | crawl-ref/source/main.cc | 1186 | ||||
-rw-r--r-- | crawl-ref/source/player-reacts.cc | 1349 | ||||
-rw-r--r-- | crawl-ref/source/player-reacts.h | 9 |
8 files changed, 1377 insertions, 1181 deletions
diff --git a/crawl-ref/source/Crawl.xcodeproj/project.pbxproj b/crawl-ref/source/Crawl.xcodeproj/project.pbxproj index eee3dd642f..5d92bb6a65 100644 --- a/crawl-ref/source/Crawl.xcodeproj/project.pbxproj +++ b/crawl-ref/source/Crawl.xcodeproj/project.pbxproj @@ -376,11 +376,13 @@ 7B5165AE11859D5A005B23ED /* ng-wanderer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7B5165A611859D5A005B23ED /* ng-wanderer.cc */; }; 7B5165AF11859D5A005B23ED /* place-info.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7B5165A811859D5A005B23ED /* place-info.cc */; }; 7B5165B011859D5A005B23ED /* player-act.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7B5165AA11859D5A005B23ED /* player-act.cc */; }; + 7B5165BA11859D5A005B23ED /* player-reacts.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7B5165B711859D5A005B23ED /* player-reacts.cc */; }; 7B5165B111859D5A005B23ED /* player-stats.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7B5165AB11859D5A005B23ED /* player-stats.cc */; }; 7B5165B211859D5A005B23ED /* ng-setup.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7B5165A411859D5A005B23ED /* ng-setup.cc */; }; 7B5165B311859D5A005B23ED /* ng-wanderer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7B5165A611859D5A005B23ED /* ng-wanderer.cc */; }; 7B5165B411859D5A005B23ED /* place-info.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7B5165A811859D5A005B23ED /* place-info.cc */; }; 7B5165B511859D5A005B23ED /* player-act.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7B5165AA11859D5A005B23ED /* player-act.cc */; }; + 7B5165B911859D5A005B23ED /* player-reacts.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7B5165B711859D5A005B23ED /* player-reacts.cc */; }; 7B5165B611859D5A005B23ED /* player-stats.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7B5165AB11859D5A005B23ED /* player-stats.cc */; }; 7B5165C611859D82005B23ED /* random-var.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7B5165B711859D82005B23ED /* random-var.cc */; }; 7B5165C711859D82005B23ED /* spl-zap.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7B5165BA11859D82005B23ED /* spl-zap.cc */; }; @@ -1167,6 +1169,8 @@ 7B5165A811859D5A005B23ED /* place-info.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "place-info.cc"; sourceTree = "<group>"; }; 7B5165A911859D5A005B23ED /* place-info.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "place-info.h"; sourceTree = "<group>"; }; 7B5165AA11859D5A005B23ED /* player-act.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "player-act.cc"; sourceTree = "<group>"; }; + 7B5165B711859D5A005B23ED /* player-reacts.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "player-reacts.cc"; sourceTree = "<group>"; }; + 7B5165B811859D5A005B23ED /* player-reacts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "player-reacts.h"; sourceTree = "<group>"; }; 7B5165AB11859D5A005B23ED /* player-stats.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "player-stats.cc"; sourceTree = "<group>"; }; 7B5165AC11859D5A005B23ED /* player-stats.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "player-stats.h"; sourceTree = "<group>"; }; 7B5165B711859D82005B23ED /* random-var.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "random-var.cc"; sourceTree = "<group>"; }; @@ -2099,6 +2103,8 @@ 7B5165AA11859D5A005B23ED /* player-act.cc */, 7BDE8442116D247D00974D63 /* player-equip.cc */, 7BDE8443116D247D00974D63 /* player-equip.h */, + 7B5165B711859D5A005B23ED /* player-reacts.cc */, + 7B5165B811859D5A005B23ED /* player-reacts.h */, 7B5165AB11859D5A005B23ED /* player-stats.cc */, 7B5165AC11859D5A005B23ED /* player-stats.h */, E5D6406210BD494500A99626 /* player.cc */, @@ -3088,6 +3094,7 @@ 7B09F5F01133D6AB004F149D /* place.cc in Sources */, 7B5165B511859D5A005B23ED /* player-act.cc in Sources */, 7BDE8444116D247D00974D63 /* player-equip.cc in Sources */, + 7B5165B911859D5A005B23ED /* player-reacts.cc in Sources */, 7B5165B611859D5A005B23ED /* player-stats.cc in Sources */, 7B09F5F11133D6AB004F149D /* player.cc in Sources */, 1F909C4D148B47AA00084E83 /* potion.cc in Sources */, diff --git a/crawl-ref/source/MSVC/crawl.vcxproj b/crawl-ref/source/MSVC/crawl.vcxproj index cba00e02ff..e892721591 100644 --- a/crawl-ref/source/MSVC/crawl.vcxproj +++ b/crawl-ref/source/MSVC/crawl.vcxproj @@ -366,6 +366,7 @@ perl.exe "util/gen-cflg.pl" compflag.h "<UNKNOWN>" "<UNKNOWN>" <ClCompile Include="..\place-info.cc" />
<ClCompile Include="..\player-act.cc" />
<ClCompile Include="..\player-equip.cc" />
+ <ClCompile Include="..\player-reacts.cc" />
<ClCompile Include="..\player-stats.cc" />
<ClCompile Include="..\potion.cc" />
<ClCompile Include="..\prebuilt\levcomp.lex.cc">
@@ -734,6 +735,7 @@ perl.exe "util/gen-cflg.pl" compflag.h "<UNKNOWN>" "<UNKNOWN>" <ClInclude Include="..\place-info.h" />
<ClInclude Include="..\platform.h" />
<ClInclude Include="..\player-equip.h" />
+ <ClInclude Include="..\player-reacts.h" />
<ClInclude Include="..\player-stats.h" />
<ClInclude Include="..\potion.h" />
<ClInclude Include="..\prebuilt\levcomp.tab.h" />
diff --git a/crawl-ref/source/MSVC/crawl.vcxproj.filters b/crawl-ref/source/MSVC/crawl.vcxproj.filters index 0de0e20f66..e84b27e33b 100644 --- a/crawl-ref/source/MSVC/crawl.vcxproj.filters +++ b/crawl-ref/source/MSVC/crawl.vcxproj.filters @@ -130,6 +130,7 @@ <ClCompile Include="..\place-info.cc" />
<ClCompile Include="..\player-act.cc" />
<ClCompile Include="..\player-equip.cc" />
+ <ClCompile Include="..\player-reacts.cc" /> <ClCompile Include="..\player-stats.cc" />
<ClCompile Include="..\potion.cc" />
<ClCompile Include="..\prebuilt\levcomp.lex.cc" />
@@ -430,6 +431,7 @@ <ClInclude Include="..\place-info.h" />
<ClInclude Include="..\platform.h" />
<ClInclude Include="..\player-equip.h" />
+ <ClInclude Include="..\player-reacts.h" /> <ClInclude Include="..\player-stats.h" />
<ClInclude Include="..\potion.h" />
<ClInclude Include="..\prebuilt\levcomp.tab.h" />
diff --git a/crawl-ref/source/Makefile.obj b/crawl-ref/source/Makefile.obj index 7906a54dde..6d30983bc4 100644 --- a/crawl-ref/source/Makefile.obj +++ b/crawl-ref/source/Makefile.obj @@ -171,6 +171,7 @@ place-info.o \ place.o \ player-act.o \ player-equip.o \ +player-reacts.o \ player-stats.o \ player.o \ potion.o \ diff --git a/crawl-ref/source/initfile.cc b/crawl-ref/source/initfile.cc index 7db2a01b2a..92b60f6cc6 100644 --- a/crawl-ref/source/initfile.cc +++ b/crawl-ref/source/initfile.cc @@ -2493,9 +2493,7 @@ void game_options::read_option_line(const string &str, bool runscript) #endif } else if (key == "terp_file" && runscript) - { terp_files.push_back(field); - } else if (key == "colour" || key == "color") { const int orig_col = str_to_colour(subkey); diff --git a/crawl-ref/source/main.cc b/crawl-ref/source/main.cc index f8991e3cf3..d6f314ab50 100644 --- a/crawl-ref/source/main.cc +++ b/crawl-ref/source/main.cc @@ -103,6 +103,7 @@ #include "output.h" #include "player.h" #include "player-equip.h" +#include "player-reacts.h" #include "player-stats.h" #include "quiver.h" #include "random.h" @@ -181,7 +182,7 @@ string init_file_error; // externed in newgame.cc char info[ INFO_SIZE ]; // messaging queue extern'd everywhere {dlb} -int stealth; // externed in view.cc +int stealth; // externed in shout.cc and player_reacts.cc void world_reacts(); @@ -201,7 +202,6 @@ NORETURN static void _launch_game(); static void _do_berserk_no_combat_penalty(void); static void _do_searing_ray(void); -static void _extract_manticore_spikes(void); static void _input(void); static void _move_player(int move_x, int move_y); static void _move_player(coord_def move); @@ -1964,7 +1964,8 @@ void process_command(command_type cmd) case CMD_WAIT: you.check_clinging(false); you.turn_is_over = true; - _extract_manticore_spikes(); + extract_manticore_spikes("You carefully extract the manticore spikes " + "from your body."); break; case CMD_PICKUP: @@ -2205,901 +2206,6 @@ static void _prep_input() } } -/** - * Decrement a duration by the given delay. - - * The midloss value should be either 0 or a number of turns where the delay - * from those turns at normal speed is less than the duration's midpoint. The - * use of midloss prevents the player from knowing the exact remaining duration - * when the midpoint message is displayed. - * - * @param dur The duration type to be decremented. - * @param delay The delay aut amount by which to decrement the duration. - * @param endmsg The message to be displayed when the duration ends. - * @param midloss A number of normal-speed turns by which to further decrement - * the duration if we cross the duration's midpoint. - * @param endmsg The message to be displayed when the duration is decremented - * to a value under its midpoint. - * @param chan The channel where the endmsg will be printed if the duration - * ends. - * - * @returns True if the duration ended, false otherwise. - */ -static bool _decrement_a_duration(duration_type dur, int delay, - const char* endmsg = nullptr, - int midloss = 0, - const char* midmsg = nullptr, - msg_channel_type chan = MSGCH_DURATION) -{ - ASSERT(you.duration[dur] >= 0); - if (you.duration[dur] == 0) - return false; - - ASSERT(!midloss || midmsg != nullptr); - const int midpoint = get_expiration_threshold(dur); - ASSERTM(!midloss || midloss * BASELINE_DELAY < midpoint, - "midpoint delay loss %d not less than duration midpoint %d", - midloss * BASELINE_DELAY, midpoint); - - int old_dur = you.duration[dur]; - you.duration[dur] -= delay; - - // If we cross the midpoint, handle midloss and print the midpoint message. - if (you.duration[dur] <= midpoint && old_dur > midpoint) - { - you.duration[dur] -= midloss * BASELINE_DELAY; - if (midmsg) - { - // Make sure the player has a turn to react to the midpoint - // message. - if (you.duration[dur] <= 0) - you.duration[dur] = 1; - if (need_expiration_warning(dur)) - mprf(MSGCH_DANGER, "Careful! %s", midmsg); - else - mprf(chan, "%s", midmsg); - } - } - - if (you.duration[dur] <= 0) - { - you.duration[dur] = 0; - if (endmsg) - mprf(chan, "%s", endmsg); - return true; - } - - return false; -} - -static void _decrement_paralysis(int delay) -{ - _decrement_a_duration(DUR_PARALYSIS_IMMUNITY, delay); - - if (you.duration[DUR_PARALYSIS]) - { - _decrement_a_duration(DUR_PARALYSIS, delay); - - if (!you.duration[DUR_PARALYSIS] && !you.petrified()) - { - mprf(MSGCH_DURATION, "You can move again."); - you.redraw_evasion = true; - you.duration[DUR_PARALYSIS_IMMUNITY] = roll_dice(1, 3) - * BASELINE_DELAY; - if (you.props.exists("paralysed_by")) - you.props.erase("paralysed_by"); - } - } -} - -static void _decrement_petrification(int delay) -{ - if (_decrement_a_duration(DUR_PETRIFIED, delay) && !you.paralysed()) - { - you.redraw_evasion = true; - mprf(MSGCH_DURATION, "You turn to %s and can move again.", - you.form == TRAN_LICH ? "bone" : - you.form == TRAN_ICE_BEAST ? "ice" : - "flesh"); - } - - if (you.duration[DUR_PETRIFYING]) - { - int &dur = you.duration[DUR_PETRIFYING]; - int old_dur = dur; - if ((dur -= delay) <= 0) - { - dur = 0; - // If we'd kill the player when active flight stops, this will - // need to pass the killer. Unlike monsters, almost all flight is - // magical, inluding tengu, as there's no flapping of wings. Should - // we be nasty to dragon and bat forms? For now, let's not instakill - // them even if it's inconsistent. - you.fully_petrify(NULL); - } - else if (dur < 15 && old_dur >= 15) - mpr("Your limbs are stiffening."); - } -} - -static int _zin_recite_to_monsters(coord_def where, int prayertype, int, actor *) -{ - ASSERT_RANGE(prayertype, 0, NUM_RECITE_TYPES); - return zin_recite_to_single_monster(where, (recite_type)prayertype); -} - -static bool _check_recite() -{ - if (you.hp*2 < you.attribute[ATTR_RECITE_HP] - || silenced(you.pos()) - || you.paralysed() - || you.confused() - || you.asleep() - || you.petrified() - || you.berserk()) - { - zin_recite_interrupt(); - return false; - } - return true; -} - -static void _handle_recitation(int step) -{ - mprf("\"%s\"", - zin_recite_text(you.attribute[ATTR_RECITE_SEED], - you.attribute[ATTR_RECITE_TYPE], step).c_str()); - - if (apply_area_visible(_zin_recite_to_monsters, - you.attribute[ATTR_RECITE_TYPE], &you)) - viewwindow(); - - // Recite trains more than once per use, because it has a - // long timer in between uses and actually takes up multiple - // turns. - practise(EX_USED_ABIL, ABIL_ZIN_RECITE); - - noisy(you.shout_volume(), you.pos()); - - if (step == 0) - { - string speech = zin_recite_text(you.attribute[ATTR_RECITE_SEED], - you.attribute[ATTR_RECITE_TYPE], -1); - speech += "."; - if (one_chance_in(9)) - { - const string closure = getSpeakString("recite_closure"); - if (!closure.empty() && one_chance_in(3)) - { - speech += " "; - speech += closure; - } - } - mprf(MSGCH_DURATION, "You finish reciting %s", speech.c_str()); - mpr("You feel short of breath."); - you.increase_duration(DUR_BREATH_WEAPON, random2(10) + random2(30)); - } -} - -// Perhaps we should write functions like: update_liquid_flames(), etc. -// Even better, we could have a vector of callback functions (or -// objects) which get installed at some point. - -/** - * Decrement player durations based on how long the player's turn lasted in aut. - */ -static void _decrement_durations() -{ - int delay = you.time_taken; - - if (you.gourmand()) - { - // Innate gourmand is always fully active. - if (player_mutation_level(MUT_GOURMAND) > 0) - you.duration[DUR_GOURMAND] = GOURMAND_MAX; - else if (you.duration[DUR_GOURMAND] < GOURMAND_MAX && coinflip()) - you.duration[DUR_GOURMAND] += delay; - } - else - you.duration[DUR_GOURMAND] = 0; - - if (you.duration[DUR_ICEMAIL_DEPLETED] > 0) - { - if (delay > you.duration[DUR_ICEMAIL_DEPLETED]) - you.duration[DUR_ICEMAIL_DEPLETED] = 0; - else - you.duration[DUR_ICEMAIL_DEPLETED] -= delay; - - if (!you.duration[DUR_ICEMAIL_DEPLETED]) - mprf(MSGCH_DURATION, "Your icy envelope is restored."); - - you.redraw_armour_class = true; - } - - if (you.duration[DUR_DEMONIC_GUARDIAN] > 0) - { - if (delay > you.duration[DUR_DEMONIC_GUARDIAN]) - you.duration[DUR_DEMONIC_GUARDIAN] = 0; - else - you.duration[DUR_DEMONIC_GUARDIAN] -= delay; - } - - // Must come before berserk. - if (_decrement_a_duration(DUR_BUILDING_RAGE, delay)) - go_berserk(false); - - if (you.duration[DUR_LIQUID_FLAMES]) - dec_napalm_player(delay); - - const bool melted = you.props.exists(MELT_ARMOUR_KEY); - if (_decrement_a_duration(DUR_ICY_ARMOUR, delay, - "Your icy armour evaporates.", - melted ? 0 : coinflip(), - melted ? nullptr - : "Your icy armour starts to melt.")) - { - you.redraw_armour_class = true; - } - - // Possible reduction of silence radius. - if (you.duration[DUR_SILENCE]) - invalidate_agrid(); - // and liquefying radius. - if (you.duration[DUR_LIQUEFYING]) - invalidate_agrid(); - - _decrement_a_duration(DUR_SILENCE, delay, "Your hearing returns."); - - if (_decrement_a_duration(DUR_TROGS_HAND, delay, - NULL, coinflip(), - "You feel the effects of Trog's Hand fading.")) - { - trog_remove_trogs_hand(); - } - - _decrement_a_duration(DUR_REGENERATION, delay, - "Your skin stops crawling.", - coinflip(), - "Your skin is crawling a little less now."); - - _decrement_a_duration(DUR_VEHUMET_GIFT, delay); - - _decrement_a_duration(DUR_JELLY_PRAYER, delay, "Your prayer is over."); - - if (you.duration[DUR_DIVINE_SHIELD] > 0) - { - if (you.duration[DUR_DIVINE_SHIELD] > 1) - { - you.duration[DUR_DIVINE_SHIELD] -= delay; - if (you.duration[DUR_DIVINE_SHIELD] <= 1) - { - you.duration[DUR_DIVINE_SHIELD] = 1; - mprf(MSGCH_DURATION, "Your divine shield starts to fade."); - } - } - - if (you.duration[DUR_DIVINE_SHIELD] == 1 && !one_chance_in(3)) - { - you.redraw_armour_class = true; - if (--you.attribute[ATTR_DIVINE_SHIELD] == 0) - { - you.duration[DUR_DIVINE_SHIELD] = 0; - mprf(MSGCH_DURATION, "Your divine shield fades away."); - } - } - } - - //jmf: More flexible weapon branding code. - int last_value = you.duration[DUR_WEAPON_BRAND]; - - if (last_value > 0) - { - you.duration[DUR_WEAPON_BRAND] -= delay; - - if (you.duration[DUR_WEAPON_BRAND] <= 0) - { - you.duration[DUR_WEAPON_BRAND] = 0; - item_def& weapon = *you.weapon(); - const int temp_effect = get_weapon_brand(weapon); - - set_item_ego_type(weapon, OBJ_WEAPONS, SPWPN_NORMAL); - const char *msg = nullptr; - - switch (temp_effect) - { - case SPWPN_VORPAL: - if (get_vorpal_type(weapon) == DVORP_SLICING) - msg = " seems blunter."; - else - msg = " feels lighter."; - break; - case SPWPN_FLAME: - case SPWPN_FLAMING: - msg = " goes out."; - break; - case SPWPN_FREEZING: - msg = " stops glowing."; - break; - case SPWPN_FROST: - msg = "'s frost melts away."; - break; - case SPWPN_VENOM: - msg = " stops dripping with poison."; - break; - case SPWPN_DRAINING: - msg = " stops crackling."; - break; - case SPWPN_DISTORTION: - msg = " seems straighter."; - break; - case SPWPN_PAIN: - msg = " seems less pained."; - break; - case SPWPN_CHAOS: - msg = " seems more stable."; - break; - case SPWPN_ELECTROCUTION: - msg = " stops emitting sparks."; - break; - case SPWPN_HOLY_WRATH: - msg = "'s light goes out."; - break; - case SPWPN_ANTIMAGIC: - msg = " stops repelling magic."; - calc_mp(); - break; - default: - msg = " seems inexplicably less special."; - break; - } - - mprf(MSGCH_DURATION, "%s%s", weapon.name(DESC_YOUR).c_str(), msg); - you.wield_change = true; - } - } - - // FIXME: [ds] Remove this once we've ensured durations can never go < 0? - if (you.duration[DUR_TRANSFORMATION] <= 0 - && you.form != TRAN_NONE) - { - you.duration[DUR_TRANSFORMATION] = 1; - } - - // Vampire bat transformations are permanent (until ended). - if (you.species != SP_VAMPIRE || you.form != TRAN_BAT - || you.duration[DUR_TRANSFORMATION] <= 5 * BASELINE_DELAY) - { - if (_decrement_a_duration(DUR_TRANSFORMATION, delay, NULL, random2(3), - "Your transformation is almost over.")) - { - untransform(); - } - } - - // Must come after transformation duration. - _decrement_a_duration(DUR_BREATH_WEAPON, delay, - "You have got your breath back.", 0, NULL, - MSGCH_RECOVERY); - - if (you.attribute[ATTR_SWIFTNESS] >= 0) - { - if (_decrement_a_duration(DUR_SWIFTNESS, delay, - "You feel sluggish.", coinflip(), - "You start to feel a little slower.")) - { - // Start anti-swiftness. - you.duration[DUR_SWIFTNESS] = you.attribute[ATTR_SWIFTNESS]; - you.attribute[ATTR_SWIFTNESS] = -1; - } - } - else - { - if (_decrement_a_duration(DUR_SWIFTNESS, delay, - "You no longer feel sluggish.", coinflip(), - "You start to feel a little faster.")) - { - you.attribute[ATTR_SWIFTNESS] = 0; - } - } - - _decrement_a_duration(DUR_RESISTANCE, delay, - "Your resistance to elements expires.", coinflip(), - "You start to feel less resistant."); - - if (_decrement_a_duration(DUR_PHASE_SHIFT, delay, - "You are firmly grounded in the material plane once more.", - coinflip(), - "You feel closer to the material plane.")) - { - you.redraw_evasion = true; - } - - _decrement_a_duration(DUR_POWERED_BY_DEATH, delay, - "You feel less regenerative."); - - _decrement_a_duration(DUR_TELEPATHY, delay, "You feel less empathic."); - - if (_decrement_a_duration(DUR_CONDENSATION_SHIELD, delay, - "Your icy shield evaporates.", - coinflip(), - "Your icy shield starts to melt.")) - { - you.redraw_armour_class = true; - } - - if (_decrement_a_duration(DUR_MAGIC_SHIELD, delay, - "Your magical shield disappears.")) - { - you.redraw_armour_class = true; - } - - if (_decrement_a_duration(DUR_STONESKIN, delay, "Your skin feels tender.")) - you.redraw_armour_class = true; - - if (_decrement_a_duration(DUR_TELEPORT, delay)) - { - you_teleport_now(true); - untag_followers(); - } - - _decrement_a_duration(DUR_CONTROL_TELEPORT, delay, - "You feel uncertain.", coinflip(), - "You start to feel a little uncertain."); - - if (_decrement_a_duration(DUR_DEATH_CHANNEL, delay, - "Your unholy channel expires.", coinflip(), - "Your unholy channel is weakening.")) - { - you.attribute[ATTR_DIVINE_DEATH_CHANNEL] = 0; - } - - _decrement_a_duration(DUR_STEALTH, delay, "You feel less stealthy."); - - if (_decrement_a_duration(DUR_INVIS, delay, NULL, - coinflip(), "You flicker for a moment.")) - { - if (you.invisible()) - mprf(MSGCH_DURATION, "You feel more conspicuous."); - else - mprf(MSGCH_DURATION, "You flicker back into view."); - you.attribute[ATTR_INVIS_UNCANCELLABLE] = 0; - } - - _decrement_a_duration(DUR_CONF, delay, "You feel less confused."); - _decrement_a_duration(DUR_LOWERED_MR, delay, "You feel less vulnerable to hostile enchantments."); - _decrement_a_duration(DUR_SLIMIFY, delay, "You feel less slimy.", - coinflip(), "Your slime is starting to congeal."); - if (_decrement_a_duration(DUR_QUAD_DAMAGE, delay, NULL, 0, - "Quad Damage is wearing off.")) - { - invalidate_agrid(true); - } - _decrement_a_duration(DUR_MIRROR_DAMAGE, delay, - "Your dark mirror aura disappears."); - if (_decrement_a_duration(DUR_HEROISM, delay, - "You feel like a meek peon again.")) - { - you.redraw_evasion = true; - you.redraw_armour_class = true; - } - _decrement_a_duration(DUR_FINESSE, delay, "Your hands slow down."); - - _decrement_a_duration(DUR_CONFUSING_TOUCH, delay, - ((string("Your ") + you.hand_name(true)) + - " stop glowing.").c_str()); - - _decrement_a_duration(DUR_SURE_BLADE, delay, - "The bond with your blade fades away."); - - _decrement_a_duration(DUR_FORESTED, delay, - "Space becomes stable."); - - if (_decrement_a_duration(DUR_MESMERISED, delay, - "You break out of your daze.", - 0, NULL, MSGCH_RECOVERY)) - { - you.clear_beholders(); - } - - _decrement_a_duration(DUR_MESMERISE_IMMUNE, delay); - - if (_decrement_a_duration(DUR_AFRAID, delay, - "Your fear fades away.", - 0, NULL, MSGCH_RECOVERY)) - { - you.clear_fearmongers(); - } - - _decrement_a_duration(DUR_FROZEN, delay, - "The ice encasing you melts away.", - 0, NULL, MSGCH_RECOVERY); - - dec_slow_player(delay); - dec_exhaust_player(delay); - dec_haste_player(delay); - - if (you.duration[DUR_LIQUEFYING] && !you.stand_on_solid_ground()) - you.duration[DUR_LIQUEFYING] = 1; - - if (_decrement_a_duration(DUR_LIQUEFYING, delay, - "The ground is no longer liquid beneath you.")) - { - invalidate_agrid(); - } - - if (_decrement_a_duration(DUR_MIGHT, delay, - "You feel a little less mighty now.")) - { - notify_stat_change(STAT_STR, -5, true, "might running out"); - } - - if (_decrement_a_duration(DUR_AGILITY, delay, - "You feel a little less agile now.")) - { - notify_stat_change(STAT_DEX, -5, true, "agility running out"); - } - - if (_decrement_a_duration(DUR_BRILLIANCE, delay, - "You feel a little less clever now.")) - { - notify_stat_change(STAT_INT, -5, true, "brilliance running out"); - } - - if (you.duration[DUR_BERSERK] - && (_decrement_a_duration(DUR_BERSERK, delay) - || you.hunger + 100 <= HUNGER_STARVING + BERSERK_NUTRITION)) - { - mpr("You are no longer berserk."); - you.duration[DUR_BERSERK] = 0; - - // Sometimes berserk leaves us physically drained. - // - // Chance of passing out: - // - mutation gives a large plus in order to try and - // avoid the mutation being a "death sentence" to - // certain characters. - - if (you.berserk_penalty != NO_BERSERK_PENALTY - && one_chance_in(10 + player_mutation_level(MUT_BERSERK) * 25)) - { - // Note the beauty of Trog! They get an extra save that's at - // the very least 20% and goes up to 100%. - if (you_worship(GOD_TROG) - && !player_under_penance() - && x_chance_in_y(you.piety, piety_breakpoint(5))) - { - mpr("Trog's vigour flows through your veins."); - } - else - { - mprf(MSGCH_WARN, "You pass out from exhaustion."); - you.increase_duration(DUR_PARALYSIS, roll_dice(1,4)); - you.stop_constricting_all(); - } - } - - if (!you.duration[DUR_PARALYSIS] && !you.petrified()) - mprf(MSGCH_WARN, "You are exhausted."); - - if (you.species == SP_LAVA_ORC) - mpr("You feel less hot-headed."); - - // This resets from an actual penalty or from NO_BERSERK_PENALTY. - you.berserk_penalty = 0; - - int dur = 12 + roll_dice(2, 12); - // For consistency with slow give exhaustion 2 times the nominal - // duration. - you.increase_duration(DUR_EXHAUSTED, dur * 2); - - notify_stat_change(STAT_STR, -5, true, "berserk running out"); - - // Don't trigger too many hints mode messages. - const bool hints_slow = Hints.hints_events[HINT_YOU_ENCHANTED]; - Hints.hints_events[HINT_YOU_ENCHANTED] = false; - - slow_player(dur); - - make_hungry(BERSERK_NUTRITION, true); - you.hunger = max(HUNGER_STARVING - 100, you.hunger); - - // 1KB: No berserk healing. - set_hp((you.hp + 1) * 2 / 3); - calc_hp(); - - learned_something_new(HINT_POSTBERSERK); - Hints.hints_events[HINT_YOU_ENCHANTED] = hints_slow; - you.redraw_quiver = true; // Can throw again. - } - - if (_decrement_a_duration(DUR_CORONA, delay) && !you.backlit()) - mprf(MSGCH_DURATION, "You are no longer glowing."); - - // Leak piety from the piety pool into actual piety. - // Note that changes of religious status without corresponding actions - // (killing monsters, offering items, ...) might be confusing for characters - // of other religions. - // For now, though, keep information about what happened hidden. - if (you.piety < MAX_PIETY && you.duration[DUR_PIETY_POOL] > 0 - && one_chance_in(5)) - { - you.duration[DUR_PIETY_POOL]--; - gain_piety(1, 1, true); - -#if defined(DEBUG_DIAGNOSTICS) || defined(DEBUG_SACRIFICE) || defined(DEBUG_PIETY) - mprf(MSGCH_DIAGNOSTICS, "Piety increases by 1 due to piety pool."); - - if (you.duration[DUR_PIETY_POOL] == 0) - mprf(MSGCH_DIAGNOSTICS, "Piety pool is now empty."); -#endif - } - - if (you.duration[DUR_DISJUNCTION]) - { - disjunction(); - _decrement_a_duration(DUR_DISJUNCTION, delay, - "The translocation energy dissipates."); - if (!you.duration[DUR_DISJUNCTION]) - invalidate_agrid(true); - } - - if (_decrement_a_duration(DUR_TORNADO_COOLDOWN, delay, - "The winds around you calm down.")) - { - remove_tornado_clouds(MID_PLAYER); - } - // Should expire before flight. - if (you.duration[DUR_TORNADO]) - { - tornado_damage(&you, min(delay, you.duration[DUR_TORNADO])); - _decrement_a_duration(DUR_TORNADO, delay, - "The winds around you start to calm down."); - if (!you.duration[DUR_TORNADO]) - you.duration[DUR_TORNADO_COOLDOWN] = random_range(25, 35); - } - - if (you.duration[DUR_FLIGHT]) - { - if (!you.permanent_flight()) - { - if (_decrement_a_duration(DUR_FLIGHT, delay, nullptr, random2(6), - "You are starting to lose your buoyancy.")) - { - land_player(); - } - } - else if ((you.duration[DUR_FLIGHT] -= delay) <= 0) - { - // Just time out potions/spells/miscasts. - you.attribute[ATTR_FLIGHT_UNCANCELLABLE] = 0; - you.duration[DUR_FLIGHT] = 0; - } - } - - if (you.rotting > 0) - { - // XXX: Mummies have an ability (albeit an expensive one) that - // can fix rotted HPs now... it's probably impossible for them - // to even start rotting right now, but that could be changed. - bwr - // It's not normal biology, so Cheibriados won't help. - if (you.species == SP_MUMMY) - you.rotting = 0; - else if (x_chance_in_y(you.rotting, 20) - && !you.duration[DUR_DEATHS_DOOR]) - { - mprf(MSGCH_WARN, "You feel your flesh rotting away."); - rot_hp(1); - you.rotting--; - } - } - - // ghoul rotting is special, but will deduct from you.rotting - // if it happens to be positive - because this is placed after - // the "normal" rotting check, rotting attacks can be somewhat - // more painful on ghouls - reversing order would make rotting - // attacks somewhat less painful, but that seems wrong-headed {dlb}: - if (you.species == SP_GHOUL) - { - int resilience = 400; - - if (you_worship(GOD_CHEIBRIADOS) && you.piety >= piety_breakpoint(0)) - resilience = resilience * 3 / 2; - - // Faster rotting when hungry. - if (you.hunger_state < HS_SATIATED) - resilience >>= HS_SATIATED - you.hunger_state; - - if (one_chance_in(resilience)) - { - dprf("rot rate: 1/%d", resilience); - mprf(MSGCH_WARN, "You feel your flesh rotting away."); - rot_hp(1); - if (you.rotting > 0) - you.rotting--; - } - } - - if (you.duration[DUR_DEATHS_DOOR]) - { - if (you.hp > allowed_deaths_door_hp()) - { - set_hp(allowed_deaths_door_hp()); - you.redraw_hit_points = true; - } - - if (_decrement_a_duration(DUR_DEATHS_DOOR, delay, - "Your life is in your own hands again!", - random2(6), - "Your time is quickly running out!")) - { - you.increase_duration(DUR_EXHAUSTED, roll_dice(1,3)); - } - } - - if (_decrement_a_duration(DUR_DIVINE_STAMINA, delay)) - zin_remove_divine_stamina(); - - if (_decrement_a_duration(DUR_DIVINE_VIGOUR, delay)) - elyvilon_remove_divine_vigour(); - - _decrement_a_duration(DUR_REPEL_STAIRS_MOVE, delay); - _decrement_a_duration(DUR_REPEL_STAIRS_CLIMB, delay); - - _decrement_a_duration(DUR_COLOUR_SMOKE_TRAIL, 1); - - if (_decrement_a_duration(DUR_SCRYING, delay, - "Your astral sight fades away.")) - { - you.xray_vision = false; - } - - _decrement_a_duration(DUR_LIFESAVING, delay, - "Your divine protection fades away."); - - if (_decrement_a_duration(DUR_DARKNESS, delay, - "The ambient light returns to normal.") - || (you.duration[DUR_DARKNESS] && you.haloed())) - { - if (you.duration[DUR_DARKNESS]) - { - you.duration[DUR_DARKNESS] = 0; - mpr("The divine light dispels your darkness!"); - } - update_vision_range(); - } - - _decrement_a_duration(DUR_SHROUD_OF_GOLUBRIA, delay, - "Your shroud unravels.", - 0, - "Your shroud begins to fray at the edges."); - - _decrement_a_duration(DUR_INFUSION, delay, - "Your attacks are no longer magically infused.", - 0, - "You are feeling less magically infused."); - - _decrement_a_duration(DUR_SONG_OF_SLAYING, delay, - "Your song has ended.", - 0, - "Your song is almost over."); - - _decrement_a_duration(DUR_SENTINEL_MARK, delay, - "The sentinel's mark upon you fades away."); - - _decrement_a_duration(DUR_WEAK, delay, - "Your attacks no longer feel as feeble."); - - _decrement_a_duration(DUR_DIMENSION_ANCHOR, delay, - "You are no longer firmly anchored in space."); - - _decrement_a_duration(DUR_SICKENING, delay); - - _decrement_a_duration(DUR_SAP_MAGIC, delay, - "Your magic seems less tainted."); - - if (!you.duration[DUR_SAP_MAGIC]) - { - _decrement_a_duration(DUR_MAGIC_SAPPED, delay, - "You feel more in control of your magic."); - } - - _decrement_a_duration(DUR_ANTIMAGIC, delay, - "You regain control over your magic."); - - _decrement_a_duration(DUR_WATER_HOLD_IMMUNITY, delay); - if (you.duration[DUR_WATER_HOLD]) - handle_player_drowning(delay); - - if (you.duration[DUR_FLAYED]) - { - bool near_ghost = false; - for (monster_iterator mi; mi; ++mi) - { - if (mi->type == MONS_FLAYED_GHOST && !mi->wont_attack() - && you.see_cell(mi->pos())) - { - near_ghost = true; - break; - } - } - if (!near_ghost) - { - if (_decrement_a_duration(DUR_FLAYED, delay)) - heal_flayed_effect(&you); - } - else if (you.duration[DUR_FLAYED] < 80) - you.duration[DUR_FLAYED] += div_rand_round(50, delay); - } - - _decrement_a_duration(DUR_RETCHING, delay, "Your fit of retching subsides."); - - if (you.duration[DUR_TOXIC_RADIANCE]) - { - int ticks = (you.duration[DUR_TOXIC_RADIANCE] / 10) - - ((you.duration[DUR_TOXIC_RADIANCE] - delay) / 10); - toxic_radiance_effect(&you, ticks); - _decrement_a_duration(DUR_TOXIC_RADIANCE, delay, - "Your toxic aura wanes."); - } - - if (you.duration[DUR_RECITE] && _check_recite()) - { - const int old_recite = - (you.duration[DUR_RECITE] + BASELINE_DELAY - 1) / BASELINE_DELAY; - _decrement_a_duration(DUR_RECITE, delay); - const int new_recite = - (you.duration[DUR_RECITE] + BASELINE_DELAY - 1) / BASELINE_DELAY; - if (old_recite != new_recite) - _handle_recitation(new_recite); - } - - if (you.duration[DUR_GRASPING_ROOTS]) - check_grasping_roots(&you); - - if (you.attribute[ATTR_NEXT_RECALL_INDEX] > 0) - do_recall(delay); - - _decrement_a_duration(DUR_SLEEP_IMMUNITY, delay); - - _decrement_a_duration(DUR_FIRE_VULN, delay, - "You feel less vulnerable to fire."); - - _decrement_a_duration(DUR_POISON_VULN, delay, - "You feel less vulnerable to poison."); - - if (_decrement_a_duration(DUR_PORTAL_PROJECTILE, delay, - "You are no longer teleporting projectiles to their destination.")) - { - you.attribute[ATTR_PORTAL_PROJECTILE] = 0; - } - - _decrement_a_duration(DUR_DRAGON_CALL_COOLDOWN, delay, - "You can once more reach out to the dragon horde."); - - if (you.duration[DUR_DRAGON_CALL]) - { - do_dragon_call(delay); - if (_decrement_a_duration(DUR_DRAGON_CALL, delay, - "The roar of the dragon horde subsides.")) - { - you.duration[DUR_DRAGON_CALL_COOLDOWN] = random_range(150, 250); - } - - } - - if (you.duration[DUR_ABJURATION_AURA]) - { - do_aura_of_abjuration(delay); - _decrement_a_duration(DUR_ABJURATION_AURA, delay, - "Your aura of abjuration expires."); - } - - dec_elixir_player(delay); - - if (!env.sunlight.empty()) - process_sunlights(); -} - static void _check_banished() { if (you.banished) @@ -3141,70 +2247,6 @@ static void _check_sanctuary() decrease_sanctuary_radius(); } -// cjo: Handles player hp and mp regeneration. If the counter you.hit_points_regeneration -// is over 100, a loop restores 1 hp and decreases the counter by 100 (so you can regen -// more than 1 hp per turn). If the counter is below 100, it is increased by a variable -// calculated from delay, BASELINE_DELAY, and your regeneration rate. MP regeneration happens -// similarly, but the countup depends on delay, BASELINE_DELAY, and you.max_magic_points -static void _regenerate_hp_and_mp(int delay) -{ - if (crawl_state.disables[DIS_PLAYER_REGEN]) - return; - - // XXX: using an int tmp to fix the fact that hit_points_regeneration - // is only an unsigned char and is thus likely to overflow. -- bwr - int tmp = you.hit_points_regeneration; - - if (you.hp < you.hp_max && !you.duration[DUR_DEATHS_DOOR]) - { - const int base_val = player_regen(); - tmp += div_rand_round(base_val * delay, BASELINE_DELAY); - } - - while (tmp >= 100) - { - // at low mp, "mana link" restores mp in place of hp - if (you.mutation[MUT_MANA_LINK] - && !x_chance_in_y(you.magic_points, you.max_magic_points)) - { - inc_mp(1); - } - else // standard hp regeneration - inc_hp(1); - tmp -= 100; - } - - ASSERT_RANGE(tmp, 0, 100); - you.hit_points_regeneration = tmp; - - // XXX: Don't let DD use guardian spirit for free HP, since their - // damage shaving is enough. (due, dpeg) - if (you.spirit_shield() && you.species == SP_DEEP_DWARF) - return; - - // XXX: Doing the same as the above, although overflow isn't an - // issue with magic point regeneration, yet. -- bwr - tmp = you.magic_points_regeneration; - - if (you.magic_points < you.max_magic_points) - { - const int base_val = 7 + you.max_magic_points / 2; - int mp_regen_countup = div_rand_round(base_val * delay, BASELINE_DELAY); - if (you.mutation[MUT_MANA_REGENERATION]) - mp_regen_countup *= 2; - tmp += mp_regen_countup; - } - - while (tmp >= 100) - { - inc_mp(1); - tmp -= 100; - } - - ASSERT_RANGE(tmp, 0, 100); - you.magic_points_regeneration = tmp; -} - static void _update_mold_state(const coord_def & pos) { if (coinflip()) @@ -3252,208 +2294,6 @@ static void _update_mold() } } -// For worn items; weapons do this on melee attacks. -static void _check_equipment_conducts() -{ - if (you_worship(GOD_DITHMENOS) && one_chance_in(10)) - { - bool illuminating = false, fiery = false; - const item_def* item; - for (int i = EQ_MIN_ARMOUR; i < NUM_EQUIP; i++) - { - item = you.slot_item(static_cast<equipment_type>(i)); - if (!item) - continue; - if (is_illuminating_item(*item)) - illuminating = true; - else if (is_fiery_item(*item)) - fiery = true; - if (illuminating && fiery) - break; - } - if (illuminating) - did_god_conduct(DID_ILLUMINATE, 1, true); - else if (fiery) - did_god_conduct(DID_FIRE, 1, true); - } -} - -static void _player_reacts() -{ - search_around(); - - stealth = check_stealth(); - -#ifdef DEBUG_STEALTH - // Too annoying for regular diagnostics. - mprf(MSGCH_DIAGNOSTICS, "stealth: %d", stealth); -#endif - - if (you.attribute[ATTR_SHADOWS]) - shadow_lantern_effect(); - - if (you.species == SP_LAVA_ORC) - temperature_check(); - - if (player_mutation_level(MUT_DEMONIC_GUARDIAN)) - check_demonic_guardian(); - - _check_equipment_conducts(); - - if (you.unrand_reacts != 0) - unrand_reacts(); - - // Handle sound-dependent effects that are silenced - if (silenced(you.pos())) - { - if (you.duration[DUR_SONG_OF_SLAYING]) - { - mpr("The silence causes your song to end."); - _decrement_a_duration(DUR_SONG_OF_SLAYING, you.duration[DUR_SONG_OF_SLAYING]); - } - } - - // Singing makes a continuous noise - if (you.duration[DUR_SONG_OF_SLAYING]) - noisy(8, you.pos()); - - if (one_chance_in(10)) - { - const int teleportitis_level = player_teleport(); - // this is instantaneous - if (teleportitis_level > 0 && one_chance_in(100 / teleportitis_level)) - { - if (teleportitis_level >= 8) - you_teleport_now(true); - else - you_teleport_now(true, false, teleportitis_level * 5); - } - else if (player_in_branch(BRANCH_ABYSS) && one_chance_in(80) - && (!map_masked(you.pos(), MMT_VAULT) || one_chance_in(3))) - { - mprf(MSGCH_BANISHMENT, "You are suddenly pulled into a different region of the Abyss!"); - you_teleport_now(false); // to new area of the Abyss - - // It's effectively a new level, make a checkpoint save so eventual - // crashes lose less of the player's progress (and fresh new bad - // mutations). - if (!crawl_state.disables[DIS_SAVE_CHECKPOINTS]) - save_game(false); - } - else if (you.form == TRAN_WISP && !you.stasis()) - random_blink(false); - } - - actor_apply_cloud(&you); - - if (env.level_state & LSTATE_SLIMY_WALL) - slime_wall_damage(&you, you.time_taken); - - // Icy shield and armour melt over lava. - if (grd(you.pos()) == DNGN_LAVA) - expose_player_to_element(BEAM_LAVA); - - you.update_beholders(); - you.update_fearmongers(); - - _decrement_durations(); - you.handle_constriction(); - - // increment constriction durations - you.accum_has_constricted(); - - int capped_time = you.time_taken; - if (you.walking && capped_time > BASELINE_DELAY) - capped_time = BASELINE_DELAY; - - int food_use = player_hunger_rate(); - food_use = div_rand_round(food_use * capped_time, BASELINE_DELAY); - - if (food_use > 0 && you.hunger > 0) - { - make_hungry(food_use, true); - if (you.duration[DUR_AMBROSIA]) - { - if (food_use > you.duration[DUR_AMBROSIA]) - food_use = you.duration[DUR_AMBROSIA]; - you.duration[DUR_AMBROSIA] -= food_use; - inc_mp(food_use); - } - } - - _regenerate_hp_and_mp(capped_time); - dec_disease_player(capped_time); - if (you.duration[DUR_POISONING]) - handle_player_poison(capped_time); - recharge_rods(you.time_taken, false); - - // Reveal adjacent mimics. - for (adjacent_iterator ai(you.pos(), false); ai; ++ai) - discover_mimic(*ai); - - // Player stealth check. - seen_monsters_react(); - - update_stat_zero(); - - // XOM now ticks from here, to increase his reaction time to tension. - if (you_worship(GOD_XOM)) - xom_tick(); -} - - -/** - * Player reactions after monster and cloud activities in the turn are finished. - */ -static void _player_reacts_to_monsters() -{ - // In case Maurice managed to steal a needed item for example. - if (!you_are_delayed()) - update_can_train(); - - if (you.duration[DUR_FIRE_SHIELD] > 0) - manage_fire_shield(you.time_taken); - - check_monster_detect(); - - if ((you_worship(GOD_ASHENZARI) && !player_under_penance()) - || you.mutation[MUT_JELLY_GROWTH]) - { - detect_items(-1); - } - - if (you.duration[DUR_TELEPATHY]) - detect_creatures(1 + you.duration[DUR_TELEPATHY] / - (2 * BASELINE_DELAY), true); - - // We have to do the messaging here, because a simple wand of flame will - // call _maybe_melt_player_enchantments twice. It also avoid duplicate - // messages when melting because of several heating sources. - string what; - if (you.props.exists(MELT_ARMOUR_KEY)) - { - what = "armour"; - you.props.erase(MELT_ARMOUR_KEY); - } - - if (you.props.exists("melt_shield")) - { - if (what != "") - what += " and "; - what += "shield"; - you.props.erase("melt_shield"); - } - - if (what != "") - mprf(MSGCH_DURATION, "The heat melts your icy %s.", what.c_str()); - - handle_starvation(); - _decrement_paralysis(you.time_taken); - _decrement_petrification(you.time_taken); - if (_decrement_a_duration(DUR_SLEEP, you.time_taken)) - you.awake(); -} - static void _update_golubria_traps() { vector<coord_def> traps = find_golubria_on_level(); @@ -3518,7 +2358,7 @@ void world_reacts() run_environment_effects(); if (!crawl_state.game_is_arena()) - _player_reacts(); + player_reacts(); abyss_morph(you.time_taken); apply_noises(); @@ -3577,7 +2417,7 @@ void world_reacts() } } if (!crawl_state.game_is_arena()) - _player_reacts_to_monsters(); + player_reacts_to_monsters(); viewwindow(); @@ -4397,15 +3237,6 @@ static void _do_searing_ray() end_searing_ray(); } -static void _extract_manticore_spikes() -{ - if (_decrement_a_duration(DUR_BARBS, you.time_taken, - "You carefully extract the manticore spikes from your body.")) - { - you.attribute[ATTR_BARBS_POW] = 0; - } -} - // Called when the player moves by walking/running. Also calls attack // function etc when necessary. static void _move_player(int move_x, int move_y) @@ -4767,10 +3598,7 @@ static void _move_player(coord_def move) // Sometimes decrease duration even when we move. if (one_chance_in(3)) - { - _decrement_a_duration(DUR_BARBS, you.time_taken, - "The manticore spikes snap loose."); - } + extract_manticore_spikes("The manticore spikes snap loose."); } if (delay_is_run(current_delay_action())) diff --git a/crawl-ref/source/player-reacts.cc b/crawl-ref/source/player-reacts.cc new file mode 100644 index 0000000000..4cb25f623d --- /dev/null +++ b/crawl-ref/source/player-reacts.cc @@ -0,0 +1,1349 @@ +/** + * @file player_reacts.cc + * @brief Player functions called every turn, mostly handling enchantment durations/expirations. + **/ + +#include "AppHdr.h" + +#include "player-reacts.h" + +// Later #includes are copy-pasted from main.cc +// since I didn't have an automated include- +// what-you-use program when I wrote this. -reaverb + +#include <string> +#include <algorithm> + +#include <errno.h> +#ifndef TARGET_OS_WINDOWS +# ifndef __ANDROID__ +# include <langinfo.h> +# endif +#endif +#include <time.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <stdio.h> +#include <list> +#include <sstream> +#include <iostream> + +#ifdef USE_UNIX_SIGNALS +#include <signal.h> +#endif + +#include "ability.h" +#include "abyss.h" +#include "acquire.h" +#include "act-iter.h" +#include "areas.h" +#include "art-enum.h" +#include "artefact.h" +#include "arena.h" +#include "beam.h" +#include "branch.h" +#include "chardump.h" +#include "cio.h" +#include "cloud.h" +#include "clua.h" +#include "colour.h" +#include "command.h" +#include "coord.h" +#include "coordit.h" +#include "crash.h" +#include "dactions.h" +#include "database.h" +#include "dbg-scan.h" +#include "dbg-util.h" +#include "delay.h" +#include "describe.h" +#include "dgn-overview.h" +#include "dgn-shoals.h" +#include "dlua.h" +#include "dungeon.h" +#include "effects.h" +#include "env.h" +#include "errors.h" +#include "exercise.h" +#include "externs.h" +#include "goditem.h" +#include "map_knowledge.h" +#include "fprop.h" +#include "fight.h" +#include "files.h" +#include "fineff.h" +#include "food.h" +#include "godabil.h" +#include "godcompanions.h" +#include "godpassive.h" +#include "godprayer.h" +#include "hiscores.h" +#include "initfile.h" +#include "invent.h" +#include "item_use.h" +#include "evoke.h" +#include "itemname.h" +#include "itemprop.h" +#include "items.h" +#include "libutil.h" +#include "luaterp.h" +#include "macro.h" +#include "makeitem.h" +#include "mapmark.h" +#include "maps.h" +#include "melee_attack.h" +#include "message.h" +#include "misc.h" +#include "mon-act.h" +#include "mon-abil.h" +#include "mon-cast.h" +#include "mon-stuff.h" +#include "mon-transit.h" +#include "mon-util.h" +#include "mutation.h" +#include "notes.h" +#include "options.h" +#include "ouch.h" +#include "output.h" +#include "player.h" +#include "player-equip.h" +#include "player-stats.h" +#include "quiver.h" +#include "random.h" +#include "religion.h" +#include "godconduct.h" +#include "shopping.h" +#include "skills.h" +#include "skills2.h" +#include "species.h" +#include "spl-book.h" +#include "spl-cast.h" +#include "spl-clouds.h" +#include "spl-damage.h" +#include "spl-goditem.h" +#include "spl-other.h" +#include "spl-selfench.h" +#include "spl-summoning.h" +#include "spl-transloc.h" +#include "spl-util.h" +#include "stairs.h" +#include "stash.h" +#include "state.h" +#include "stuff.h" +#include "startup.h" +#include "tags.h" +#include "target.h" +#include "terrain.h" +#include "throw.h" +#include "transform.h" +#include "traps.h" +#include "travel.h" +#include "hints.h" +#include "shout.h" +#include "stash.h" +#include "uncancel.h" +#include "version.h" +#include "view.h" +#include "viewchar.h" +#include "viewgeom.h" +#include "viewmap.h" +#include "wiz-dgn.h" +#include "wiz-fsim.h" +#include "wiz-item.h" +#include "wiz-mon.h" +#include "wiz-you.h" +#include "xom.h" +#include "zotdef.h" + +#ifdef USE_TILE +#include "tiledef-dngn.h" +#include "tilepick.h" +#endif + +#ifdef DGL_SIMPLE_MESSAGING +#include "dgl-message.h" +#endif + +/** + * Decrement a duration by the given delay. + + * The midloss value should be either 0 or a number of turns where the delay + * from those turns at normal speed is less than the duration's midpoint. The + * use of midloss prevents the player from knowing the exact remaining duration + * when the midpoint message is displayed. + * + * @param dur The duration type to be decremented. + * @param delay The delay aut amount by which to decrement the duration. + * @param endmsg The message to be displayed when the duration ends. + * @param midloss A number of normal-speed turns by which to further decrement + * the duration if we cross the duration's midpoint. + * @param endmsg The message to be displayed when the duration is decremented + * to a value under its midpoint. + * @param chan The channel where the endmsg will be printed if the duration + * ends. + * + * @returns True if the duration ended, false otherwise. + */ + +static bool _decrement_a_duration(duration_type dur, int delay, + const char* endmsg = nullptr, + int midloss = 0, + const char* midmsg = nullptr, + msg_channel_type chan = MSGCH_DURATION) +{ + ASSERT(you.duration[dur] >= 0); + if (you.duration[dur] == 0) + return false; + + ASSERT(!midloss || midmsg != nullptr); + const int midpoint = get_expiration_threshold(dur); + ASSERTM(!midloss || midloss * BASELINE_DELAY < midpoint, + "midpoint delay loss %d not less than duration midpoint %d", + midloss * BASELINE_DELAY, midpoint); + + int old_dur = you.duration[dur]; + you.duration[dur] -= delay; + + // If we cross the midpoint, handle midloss and print the midpoint message. + if (you.duration[dur] <= midpoint && old_dur > midpoint) + { + you.duration[dur] -= midloss * BASELINE_DELAY; + if (midmsg) + { + // Make sure the player has a turn to react to the midpoint + // message. + if (you.duration[dur] <= 0) + you.duration[dur] = 1; + if (need_expiration_warning(dur)) + mprf(MSGCH_DANGER, "Careful! %s", midmsg); + else + mprf(chan, "%s", midmsg); + } + } + + if (you.duration[dur] <= 0) + { + you.duration[dur] = 0; + if (endmsg) + mprf(chan, "%s", endmsg); + return true; + } + + return false; +} + + +static void _decrement_petrification(int delay) +{ + if (_decrement_a_duration(DUR_PETRIFIED, delay) && !you.paralysed()) + { + you.redraw_evasion = true; + mprf(MSGCH_DURATION, "You turn to %s and can move again.", + you.form == TRAN_LICH ? "bone" : + you.form == TRAN_ICE_BEAST ? "ice" : + "flesh"); + } + + if (you.duration[DUR_PETRIFYING]) + { + int &dur = you.duration[DUR_PETRIFYING]; + int old_dur = dur; + if ((dur -= delay) <= 0) + { + dur = 0; + // If we'd kill the player when active flight stops, this will + // need to pass the killer. Unlike monsters, almost all flight is + // magical, inluding tengu, as there's no flapping of wings. Should + // we be nasty to dragon and bat forms? For now, let's not instakill + // them even if it's inconsistent. + you.fully_petrify(NULL); + } + else if (dur < 15 && old_dur >= 15) + mpr("Your limbs are stiffening."); + } +} + +static void _decrement_paralysis(int delay) +{ + _decrement_a_duration(DUR_PARALYSIS_IMMUNITY, delay); + + if (you.duration[DUR_PARALYSIS]) + { + _decrement_a_duration(DUR_PARALYSIS, delay); + + if (!you.duration[DUR_PARALYSIS] && !you.petrified()) + { + mprf(MSGCH_DURATION, "You can move again."); + you.redraw_evasion = true; + you.duration[DUR_PARALYSIS_IMMUNITY] = roll_dice(1, 3) + * BASELINE_DELAY; + if (you.props.exists("paralysed_by")) + you.props.erase("paralysed_by"); + } + } +} + +/** + * Player reactions after monster and cloud activities in the turn are finished. + */ +void player_reacts_to_monsters() +{ + // In case Maurice managed to steal a needed item for example. + if (!you_are_delayed()) + update_can_train(); + + if (you.duration[DUR_FIRE_SHIELD] > 0) + manage_fire_shield(you.time_taken); + + check_monster_detect(); + + if ((you_worship(GOD_ASHENZARI) && !player_under_penance()) + || you.mutation[MUT_JELLY_GROWTH]) + { + detect_items(-1); + } + + if (you.duration[DUR_TELEPATHY]) + detect_creatures(1 + you.duration[DUR_TELEPATHY] / + (2 * BASELINE_DELAY), true); + + // We have to do the messaging here, because a simple wand of flame will + // call _maybe_melt_player_enchantments twice. It also avoid duplicate + // messages when melting because of several heating sources. + string what; + if (you.props.exists(MELT_ARMOUR_KEY)) + { + what = "armour"; + you.props.erase(MELT_ARMOUR_KEY); + } + + if (you.props.exists("melt_shield")) + { + if (what != "") + what += " and "; + what += "shield"; + you.props.erase("melt_shield"); + } + + if (what != "") + mprf(MSGCH_DURATION, "The heat melts your icy %s.", what.c_str()); + + handle_starvation(); + _decrement_paralysis(you.time_taken); + _decrement_petrification(you.time_taken); + if (_decrement_a_duration(DUR_SLEEP, you.time_taken)) + you.awake(); +} + +static bool _check_recite() +{ + if (you.hp*2 < you.attribute[ATTR_RECITE_HP] + || silenced(you.pos()) + || you.paralysed() + || you.confused() + || you.asleep() + || you.petrified() + || you.berserk()) + { + zin_recite_interrupt(); + return false; + } + return true; +} + + +static int _zin_recite_to_monsters(coord_def where, int prayertype, int, actor *) +{ + ASSERT_RANGE(prayertype, 0, NUM_RECITE_TYPES); + return zin_recite_to_single_monster(where, (recite_type)prayertype); +} + + +static void _handle_recitation(int step) +{ + mprf("\"%s\"", + zin_recite_text(you.attribute[ATTR_RECITE_SEED], + you.attribute[ATTR_RECITE_TYPE], step).c_str()); + + if (apply_area_visible(_zin_recite_to_monsters, + you.attribute[ATTR_RECITE_TYPE], &you)) + viewwindow(); + + // Recite trains more than once per use, because it has a + // long timer in between uses and actually takes up multiple + // turns. + practise(EX_USED_ABIL, ABIL_ZIN_RECITE); + + noisy(you.shout_volume(), you.pos()); + + if (step == 0) + { + string speech = zin_recite_text(you.attribute[ATTR_RECITE_SEED], + you.attribute[ATTR_RECITE_TYPE], -1); + speech += "."; + if (one_chance_in(9)) + { + const string closure = getSpeakString("recite_closure"); + if (!closure.empty() && one_chance_in(3)) + { + speech += " "; + speech += closure; + } + } + mprf(MSGCH_DURATION, "You finish reciting %s", speech.c_str()); + mpr("You feel short of breath."); + you.increase_duration(DUR_BREATH_WEAPON, random2(10) + random2(30)); + } +} + + +// Perhaps we should write functions like: update_liquid_flames(), etc. +// Even better, we could have a vector of callback functions (or +// objects) which get installed at some point. + +/** + * Decrement player durations based on how long the player's turn lasted in aut. + */ +static void _decrement_durations() +{ + int delay = you.time_taken; + + if (you.gourmand()) + { + // Innate gourmand is always fully active. + if (player_mutation_level(MUT_GOURMAND) > 0) + you.duration[DUR_GOURMAND] = GOURMAND_MAX; + else if (you.duration[DUR_GOURMAND] < GOURMAND_MAX && coinflip()) + you.duration[DUR_GOURMAND] += delay; + } + else + you.duration[DUR_GOURMAND] = 0; + + if (you.duration[DUR_ICEMAIL_DEPLETED] > 0) + { + if (delay > you.duration[DUR_ICEMAIL_DEPLETED]) + you.duration[DUR_ICEMAIL_DEPLETED] = 0; + else + you.duration[DUR_ICEMAIL_DEPLETED] -= delay; + + if (!you.duration[DUR_ICEMAIL_DEPLETED]) + mprf(MSGCH_DURATION, "Your icy envelope is restored."); + + you.redraw_armour_class = true; + } + + if (you.duration[DUR_DEMONIC_GUARDIAN] > 0) + { + if (delay > you.duration[DUR_DEMONIC_GUARDIAN]) + you.duration[DUR_DEMONIC_GUARDIAN] = 0; + else + you.duration[DUR_DEMONIC_GUARDIAN] -= delay; + } + + // Must come before berserk. + if (_decrement_a_duration(DUR_BUILDING_RAGE, delay)) + go_berserk(false); + + if (you.duration[DUR_LIQUID_FLAMES]) + dec_napalm_player(delay); + + const bool melted = you.props.exists(MELT_ARMOUR_KEY); + if (_decrement_a_duration(DUR_ICY_ARMOUR, delay, + "Your icy armour evaporates.", + melted ? 0 : coinflip(), + melted ? nullptr + : "Your icy armour starts to melt.")) + { + you.redraw_armour_class = true; + } + + // Possible reduction of silence radius. + if (you.duration[DUR_SILENCE]) + invalidate_agrid(); + // and liquefying radius. + if (you.duration[DUR_LIQUEFYING]) + invalidate_agrid(); + + _decrement_a_duration(DUR_SILENCE, delay, "Your hearing returns."); + + if (_decrement_a_duration(DUR_TROGS_HAND, delay, + NULL, coinflip(), + "You feel the effects of Trog's Hand fading.")) + { + trog_remove_trogs_hand(); + } + + _decrement_a_duration(DUR_REGENERATION, delay, + "Your skin stops crawling.", + coinflip(), + "Your skin is crawling a little less now."); + + _decrement_a_duration(DUR_VEHUMET_GIFT, delay); + + _decrement_a_duration(DUR_JELLY_PRAYER, delay, "Your prayer is over."); + + if (you.duration[DUR_DIVINE_SHIELD] > 0) + { + if (you.duration[DUR_DIVINE_SHIELD] > 1) + { + you.duration[DUR_DIVINE_SHIELD] -= delay; + if (you.duration[DUR_DIVINE_SHIELD] <= 1) + { + you.duration[DUR_DIVINE_SHIELD] = 1; + mprf(MSGCH_DURATION, "Your divine shield starts to fade."); + } + } + + if (you.duration[DUR_DIVINE_SHIELD] == 1 && !one_chance_in(3)) + { + you.redraw_armour_class = true; + if (--you.attribute[ATTR_DIVINE_SHIELD] == 0) + { + you.duration[DUR_DIVINE_SHIELD] = 0; + mprf(MSGCH_DURATION, "Your divine shield fades away."); + } + } + } + + //jmf: More flexible weapon branding code. + int last_value = you.duration[DUR_WEAPON_BRAND]; + + if (last_value > 0) + { + you.duration[DUR_WEAPON_BRAND] -= delay; + + if (you.duration[DUR_WEAPON_BRAND] <= 0) + { + you.duration[DUR_WEAPON_BRAND] = 0; + item_def& weapon = *you.weapon(); + const int temp_effect = get_weapon_brand(weapon); + + set_item_ego_type(weapon, OBJ_WEAPONS, SPWPN_NORMAL); + const char *msg = nullptr; + + switch (temp_effect) + { + case SPWPN_VORPAL: + if (get_vorpal_type(weapon) == DVORP_SLICING) + msg = " seems blunter."; + else + msg = " feels lighter."; + break; + case SPWPN_FLAME: + case SPWPN_FLAMING: + msg = " goes out."; + break; + case SPWPN_FREEZING: + msg = " stops glowing."; + break; + case SPWPN_FROST: + msg = "'s frost melts away."; + break; + case SPWPN_VENOM: + msg = " stops dripping with poison."; + break; + case SPWPN_DRAINING: + msg = " stops crackling."; + break; + case SPWPN_DISTORTION: + msg = " seems straighter."; + break; + case SPWPN_PAIN: + msg = " seems less pained."; + break; + case SPWPN_CHAOS: + msg = " seems more stable."; + break; + case SPWPN_ELECTROCUTION: + msg = " stops emitting sparks."; + break; + case SPWPN_HOLY_WRATH: + msg = "'s light goes out."; + break; + case SPWPN_ANTIMAGIC: + msg = " stops repelling magic."; + calc_mp(); + break; + default: + msg = " seems inexplicably less special."; + break; + } + + mprf(MSGCH_DURATION, "%s%s", weapon.name(DESC_YOUR).c_str(), msg); + you.wield_change = true; + } + } + + // FIXME: [ds] Remove this once we've ensured durations can never go < 0? + if (you.duration[DUR_TRANSFORMATION] <= 0 + && you.form != TRAN_NONE) + { + you.duration[DUR_TRANSFORMATION] = 1; + } + + // Vampire bat transformations are permanent (until ended). + if (you.species != SP_VAMPIRE || you.form != TRAN_BAT + || you.duration[DUR_TRANSFORMATION] <= 5 * BASELINE_DELAY) + { + if (_decrement_a_duration(DUR_TRANSFORMATION, delay, NULL, random2(3), + "Your transformation is almost over.")) + { + untransform(); + } + } + + // Must come after transformation duration. + _decrement_a_duration(DUR_BREATH_WEAPON, delay, + "You have got your breath back.", 0, NULL, + MSGCH_RECOVERY); + + if (you.attribute[ATTR_SWIFTNESS] >= 0) + { + if (_decrement_a_duration(DUR_SWIFTNESS, delay, + "You feel sluggish.", coinflip(), + "You start to feel a little slower.")) + { + // Start anti-swiftness. + you.duration[DUR_SWIFTNESS] = you.attribute[ATTR_SWIFTNESS]; + you.attribute[ATTR_SWIFTNESS] = -1; + } + } + else + { + if (_decrement_a_duration(DUR_SWIFTNESS, delay, + "You no longer feel sluggish.", coinflip(), + "You start to feel a little faster.")) + { + you.attribute[ATTR_SWIFTNESS] = 0; + } + } + + _decrement_a_duration(DUR_RESISTANCE, delay, + "Your resistance to elements expires.", coinflip(), + "You start to feel less resistant."); + + if (_decrement_a_duration(DUR_PHASE_SHIFT, delay, + "You are firmly grounded in the material plane once more.", + coinflip(), + "You feel closer to the material plane.")) + { + you.redraw_evasion = true; + } + + _decrement_a_duration(DUR_POWERED_BY_DEATH, delay, + "You feel less regenerative."); + + _decrement_a_duration(DUR_TELEPATHY, delay, "You feel less empathic."); + + if (_decrement_a_duration(DUR_CONDENSATION_SHIELD, delay, + "Your icy shield evaporates.", + coinflip(), + "Your icy shield starts to melt.")) + { + you.redraw_armour_class = true; + } + + if (_decrement_a_duration(DUR_MAGIC_SHIELD, delay, + "Your magical shield disappears.")) + { + you.redraw_armour_class = true; + } + + if (_decrement_a_duration(DUR_STONESKIN, delay, "Your skin feels tender.")) + you.redraw_armour_class = true; + + if (_decrement_a_duration(DUR_TELEPORT, delay)) + { + you_teleport_now(true); + untag_followers(); + } + + _decrement_a_duration(DUR_CONTROL_TELEPORT, delay, + "You feel uncertain.", coinflip(), + "You start to feel a little uncertain."); + + if (_decrement_a_duration(DUR_DEATH_CHANNEL, delay, + "Your unholy channel expires.", coinflip(), + "Your unholy channel is weakening.")) + { + you.attribute[ATTR_DIVINE_DEATH_CHANNEL] = 0; + } + + _decrement_a_duration(DUR_STEALTH, delay, "You feel less stealthy."); + + if (_decrement_a_duration(DUR_INVIS, delay, NULL, + coinflip(), "You flicker for a moment.")) + { + if (you.invisible()) + mprf(MSGCH_DURATION, "You feel more conspicuous."); + else + mprf(MSGCH_DURATION, "You flicker back into view."); + you.attribute[ATTR_INVIS_UNCANCELLABLE] = 0; + } + + _decrement_a_duration(DUR_CONF, delay, "You feel less confused."); + _decrement_a_duration(DUR_LOWERED_MR, delay, "You feel less vulnerable to hostile enchantments."); + _decrement_a_duration(DUR_SLIMIFY, delay, "You feel less slimy.", + coinflip(), "Your slime is starting to congeal."); + if (_decrement_a_duration(DUR_QUAD_DAMAGE, delay, NULL, 0, + "Quad Damage is wearing off.")) + { + invalidate_agrid(true); + } + _decrement_a_duration(DUR_MIRROR_DAMAGE, delay, + "Your dark mirror aura disappears."); + if (_decrement_a_duration(DUR_HEROISM, delay, + "You feel like a meek peon again.")) + { + you.redraw_evasion = true; + you.redraw_armour_class = true; + } + _decrement_a_duration(DUR_FINESSE, delay, "Your hands slow down."); + + _decrement_a_duration(DUR_CONFUSING_TOUCH, delay, + ((string("Your ") + you.hand_name(true)) + + " stop glowing.").c_str()); + + _decrement_a_duration(DUR_SURE_BLADE, delay, + "The bond with your blade fades away."); + + _decrement_a_duration(DUR_FORESTED, delay, + "Space becomes stable."); + + if (_decrement_a_duration(DUR_MESMERISED, delay, + "You break out of your daze.", + 0, NULL, MSGCH_RECOVERY)) + { + you.clear_beholders(); + } + + _decrement_a_duration(DUR_MESMERISE_IMMUNE, delay); + + if (_decrement_a_duration(DUR_AFRAID, delay, + "Your fear fades away.", + 0, NULL, MSGCH_RECOVERY)) + { + you.clear_fearmongers(); + } + + _decrement_a_duration(DUR_FROZEN, delay, + "The ice encasing you melts away.", + 0, NULL, MSGCH_RECOVERY); + + dec_slow_player(delay); + dec_exhaust_player(delay); + dec_haste_player(delay); + + if (you.duration[DUR_LIQUEFYING] && !you.stand_on_solid_ground()) + you.duration[DUR_LIQUEFYING] = 1; + + if (_decrement_a_duration(DUR_LIQUEFYING, delay, + "The ground is no longer liquid beneath you.")) + { + invalidate_agrid(); + } + + if (_decrement_a_duration(DUR_MIGHT, delay, + "You feel a little less mighty now.")) + { + notify_stat_change(STAT_STR, -5, true, "might running out"); + } + + if (_decrement_a_duration(DUR_AGILITY, delay, + "You feel a little less agile now.")) + { + notify_stat_change(STAT_DEX, -5, true, "agility running out"); + } + + if (_decrement_a_duration(DUR_BRILLIANCE, delay, + "You feel a little less clever now.")) + { + notify_stat_change(STAT_INT, -5, true, "brilliance running out"); + } + + if (you.duration[DUR_BERSERK] + && (_decrement_a_duration(DUR_BERSERK, delay) + || you.hunger + 100 <= HUNGER_STARVING + BERSERK_NUTRITION)) + { + mpr("You are no longer berserk."); + you.duration[DUR_BERSERK] = 0; + + // Sometimes berserk leaves us physically drained. + // + // Chance of passing out: + // - mutation gives a large plus in order to try and + // avoid the mutation being a "death sentence" to + // certain characters. + + if (you.berserk_penalty != NO_BERSERK_PENALTY + && one_chance_in(10 + player_mutation_level(MUT_BERSERK) * 25)) + { + // Note the beauty of Trog! They get an extra save that's at + // the very least 20% and goes up to 100%. + if (you_worship(GOD_TROG) + && !player_under_penance() + && x_chance_in_y(you.piety, piety_breakpoint(5))) + { + mpr("Trog's vigour flows through your veins."); + } + else + { + mprf(MSGCH_WARN, "You pass out from exhaustion."); + you.increase_duration(DUR_PARALYSIS, roll_dice(1,4)); + you.stop_constricting_all(); + } + } + + if (!you.duration[DUR_PARALYSIS] && !you.petrified()) + mprf(MSGCH_WARN, "You are exhausted."); + + if (you.species == SP_LAVA_ORC) + mpr("You feel less hot-headed."); + + // This resets from an actual penalty or from NO_BERSERK_PENALTY. + you.berserk_penalty = 0; + + int dur = 12 + roll_dice(2, 12); + // For consistency with slow give exhaustion 2 times the nominal + // duration. + you.increase_duration(DUR_EXHAUSTED, dur * 2); + + notify_stat_change(STAT_STR, -5, true, "berserk running out"); + + // Don't trigger too many hints mode messages. + const bool hints_slow = Hints.hints_events[HINT_YOU_ENCHANTED]; + Hints.hints_events[HINT_YOU_ENCHANTED] = false; + + slow_player(dur); + + make_hungry(BERSERK_NUTRITION, true); + you.hunger = max(HUNGER_STARVING - 100, you.hunger); + + // 1KB: No berserk healing. + set_hp((you.hp + 1) * 2 / 3); + calc_hp(); + + learned_something_new(HINT_POSTBERSERK); + Hints.hints_events[HINT_YOU_ENCHANTED] = hints_slow; + you.redraw_quiver = true; // Can throw again. + } + + if (_decrement_a_duration(DUR_CORONA, delay) && !you.backlit()) + mprf(MSGCH_DURATION, "You are no longer glowing."); + + // Leak piety from the piety pool into actual piety. + // Note that changes of religious status without corresponding actions + // (killing monsters, offering items, ...) might be confusing for characters + // of other religions. + // For now, though, keep information about what happened hidden. + if (you.piety < MAX_PIETY && you.duration[DUR_PIETY_POOL] > 0 + && one_chance_in(5)) + { + you.duration[DUR_PIETY_POOL]--; + gain_piety(1, 1, true); + +#if defined(DEBUG_DIAGNOSTICS) || defined(DEBUG_SACRIFICE) || defined(DEBUG_PIETY) + mprf(MSGCH_DIAGNOSTICS, "Piety increases by 1 due to piety pool."); + + if (you.duration[DUR_PIETY_POOL] == 0) + mprf(MSGCH_DIAGNOSTICS, "Piety pool is now empty."); +#endif + } + + if (you.duration[DUR_DISJUNCTION]) + { + disjunction(); + _decrement_a_duration(DUR_DISJUNCTION, delay, + "The translocation energy dissipates."); + if (!you.duration[DUR_DISJUNCTION]) + invalidate_agrid(true); + } + + if (_decrement_a_duration(DUR_TORNADO_COOLDOWN, delay, + "The winds around you calm down.")) + { + remove_tornado_clouds(MID_PLAYER); + } + // Should expire before flight. + if (you.duration[DUR_TORNADO]) + { + tornado_damage(&you, min(delay, you.duration[DUR_TORNADO])); + _decrement_a_duration(DUR_TORNADO, delay, + "The winds around you start to calm down."); + if (!you.duration[DUR_TORNADO]) + you.duration[DUR_TORNADO_COOLDOWN] = random_range(25, 35); + } + + if (you.duration[DUR_FLIGHT]) + { + if (!you.permanent_flight()) + { + if (_decrement_a_duration(DUR_FLIGHT, delay, nullptr, random2(6), + "You are starting to lose your buoyancy.")) + { + land_player(); + } + } + else if ((you.duration[DUR_FLIGHT] -= delay) <= 0) + { + // Just time out potions/spells/miscasts. + you.attribute[ATTR_FLIGHT_UNCANCELLABLE] = 0; + you.duration[DUR_FLIGHT] = 0; + } + } + + if (you.rotting > 0) + { + // XXX: Mummies have an ability (albeit an expensive one) that + // can fix rotted HPs now... it's probably impossible for them + // to even start rotting right now, but that could be changed. - bwr + // It's not normal biology, so Cheibriados won't help. + if (you.species == SP_MUMMY) + you.rotting = 0; + else if (x_chance_in_y(you.rotting, 20) + && !you.duration[DUR_DEATHS_DOOR]) + { + mprf(MSGCH_WARN, "You feel your flesh rotting away."); + rot_hp(1); + you.rotting--; + } + } + + // ghoul rotting is special, but will deduct from you.rotting + // if it happens to be positive - because this is placed after + // the "normal" rotting check, rotting attacks can be somewhat + // more painful on ghouls - reversing order would make rotting + // attacks somewhat less painful, but that seems wrong-headed {dlb}: + if (you.species == SP_GHOUL) + { + int resilience = 400; + + if (you_worship(GOD_CHEIBRIADOS) && you.piety >= piety_breakpoint(0)) + resilience = resilience * 3 / 2; + + // Faster rotting when hungry. + if (you.hunger_state < HS_SATIATED) + resilience >>= HS_SATIATED - you.hunger_state; + + if (one_chance_in(resilience)) + { + dprf("rot rate: 1/%d", resilience); + mprf(MSGCH_WARN, "You feel your flesh rotting away."); + rot_hp(1); + if (you.rotting > 0) + you.rotting--; + } + } + + if (you.duration[DUR_DEATHS_DOOR]) + { + if (you.hp > allowed_deaths_door_hp()) + { + set_hp(allowed_deaths_door_hp()); + you.redraw_hit_points = true; + } + + if (_decrement_a_duration(DUR_DEATHS_DOOR, delay, + "Your life is in your own hands again!", + random2(6), + "Your time is quickly running out!")) + { + you.increase_duration(DUR_EXHAUSTED, roll_dice(1,3)); + } + } + + if (_decrement_a_duration(DUR_DIVINE_STAMINA, delay)) + zin_remove_divine_stamina(); + + if (_decrement_a_duration(DUR_DIVINE_VIGOUR, delay)) + elyvilon_remove_divine_vigour(); + + _decrement_a_duration(DUR_REPEL_STAIRS_MOVE, delay); + _decrement_a_duration(DUR_REPEL_STAIRS_CLIMB, delay); + + _decrement_a_duration(DUR_COLOUR_SMOKE_TRAIL, 1); + + if (_decrement_a_duration(DUR_SCRYING, delay, + "Your astral sight fades away.")) + { + you.xray_vision = false; + } + + _decrement_a_duration(DUR_LIFESAVING, delay, + "Your divine protection fades away."); + + if (_decrement_a_duration(DUR_DARKNESS, delay, + "The ambient light returns to normal.") + || (you.duration[DUR_DARKNESS] && you.haloed())) + { + if (you.duration[DUR_DARKNESS]) + { + you.duration[DUR_DARKNESS] = 0; + mpr("The divine light dispels your darkness!"); + } + update_vision_range(); + } + + _decrement_a_duration(DUR_SHROUD_OF_GOLUBRIA, delay, + "Your shroud unravels.", + 0, + "Your shroud begins to fray at the edges."); + + _decrement_a_duration(DUR_INFUSION, delay, + "Your attacks are no longer magically infused.", + 0, + "You are feeling less magically infused."); + + _decrement_a_duration(DUR_SONG_OF_SLAYING, delay, + "Your song has ended.", + 0, + "Your song is almost over."); + + _decrement_a_duration(DUR_SENTINEL_MARK, delay, + "The sentinel's mark upon you fades away."); + + _decrement_a_duration(DUR_WEAK, delay, + "Your attacks no longer feel as feeble."); + + _decrement_a_duration(DUR_DIMENSION_ANCHOR, delay, + "You are no longer firmly anchored in space."); + + _decrement_a_duration(DUR_SICKENING, delay); + + _decrement_a_duration(DUR_SAP_MAGIC, delay, + "Your magic seems less tainted."); + + if (!you.duration[DUR_SAP_MAGIC]) + { + _decrement_a_duration(DUR_MAGIC_SAPPED, delay, + "You feel more in control of your magic."); + } + + _decrement_a_duration(DUR_ANTIMAGIC, delay, + "You regain control over your magic."); + + _decrement_a_duration(DUR_WATER_HOLD_IMMUNITY, delay); + if (you.duration[DUR_WATER_HOLD]) + handle_player_drowning(delay); + + if (you.duration[DUR_FLAYED]) + { + bool near_ghost = false; + for (monster_iterator mi; mi; ++mi) + { + if (mi->type == MONS_FLAYED_GHOST && !mi->wont_attack() + && you.see_cell(mi->pos())) + { + near_ghost = true; + break; + } + } + if (!near_ghost) + { + if (_decrement_a_duration(DUR_FLAYED, delay)) + heal_flayed_effect(&you); + } + else if (you.duration[DUR_FLAYED] < 80) + you.duration[DUR_FLAYED] += div_rand_round(50, delay); + } + + _decrement_a_duration(DUR_RETCHING, delay, "Your fit of retching subsides."); + + if (you.duration[DUR_TOXIC_RADIANCE]) + { + int ticks = (you.duration[DUR_TOXIC_RADIANCE] / 10) + - ((you.duration[DUR_TOXIC_RADIANCE] - delay) / 10); + toxic_radiance_effect(&you, ticks); + _decrement_a_duration(DUR_TOXIC_RADIANCE, delay, + "Your toxic aura wanes."); + } + + if (you.duration[DUR_RECITE] && _check_recite()) + { + const int old_recite = + (you.duration[DUR_RECITE] + BASELINE_DELAY - 1) / BASELINE_DELAY; + _decrement_a_duration(DUR_RECITE, delay); + const int new_recite = + (you.duration[DUR_RECITE] + BASELINE_DELAY - 1) / BASELINE_DELAY; + if (old_recite != new_recite) + _handle_recitation(new_recite); + } + + if (you.duration[DUR_GRASPING_ROOTS]) + check_grasping_roots(&you); + + if (you.attribute[ATTR_NEXT_RECALL_INDEX] > 0) + do_recall(delay); + + _decrement_a_duration(DUR_SLEEP_IMMUNITY, delay); + + _decrement_a_duration(DUR_FIRE_VULN, delay, + "You feel less vulnerable to fire."); + + _decrement_a_duration(DUR_POISON_VULN, delay, + "You feel less vulnerable to poison."); + + if (_decrement_a_duration(DUR_PORTAL_PROJECTILE, delay, + "You are no longer teleporting projectiles to their destination.")) + { + you.attribute[ATTR_PORTAL_PROJECTILE] = 0; + } + + _decrement_a_duration(DUR_DRAGON_CALL_COOLDOWN, delay, + "You can once more reach out to the dragon horde."); + + if (you.duration[DUR_DRAGON_CALL]) + { + do_dragon_call(delay); + if (_decrement_a_duration(DUR_DRAGON_CALL, delay, + "The roar of the dragon horde subsides.")) + { + you.duration[DUR_DRAGON_CALL_COOLDOWN] = random_range(150, 250); + } + + } + + if (you.duration[DUR_ABJURATION_AURA]) + { + do_aura_of_abjuration(delay); + _decrement_a_duration(DUR_ABJURATION_AURA, delay, + "Your aura of abjuration expires."); + } + + dec_elixir_player(delay); + + if (!env.sunlight.empty()) + process_sunlights(); +} + + +// For worn items; weapons do this on melee attacks. +static void _check_equipment_conducts() +{ + if (you_worship(GOD_DITHMENOS) && one_chance_in(10)) + { + bool illuminating = false, fiery = false; + const item_def* item; + for (int i = EQ_MIN_ARMOUR; i < NUM_EQUIP; i++) + { + item = you.slot_item(static_cast<equipment_type>(i)); + if (!item) + continue; + if (is_illuminating_item(*item)) + illuminating = true; + else if (is_fiery_item(*item)) + fiery = true; + if (illuminating && fiery) + break; + } + if (illuminating) + did_god_conduct(DID_ILLUMINATE, 1, true); + else if (fiery) + did_god_conduct(DID_FIRE, 1, true); + } +} + + +// cjo: Handles player hp and mp regeneration. If the counter you.hit_points_regeneration +// is over 100, a loop restores 1 hp and decreases the counter by 100 (so you can regen +// more than 1 hp per turn). If the counter is below 100, it is increased by a variable +// calculated from delay, BASELINE_DELAY, and your regeneration rate. MP regeneration happens +// similarly, but the countup depends on delay, BASELINE_DELAY, and you.max_magic_points +static void _regenerate_hp_and_mp(int delay) +{ + if (crawl_state.disables[DIS_PLAYER_REGEN]) + return; + + // XXX: using an int tmp to fix the fact that hit_points_regeneration + // is only an unsigned char and is thus likely to overflow. -- bwr + int tmp = you.hit_points_regeneration; + + if (you.hp < you.hp_max && !you.duration[DUR_DEATHS_DOOR]) + { + const int base_val = player_regen(); + tmp += div_rand_round(base_val * delay, BASELINE_DELAY); + } + + while (tmp >= 100) + { + // at low mp, "mana link" restores mp in place of hp + if (you.mutation[MUT_MANA_LINK] + && !x_chance_in_y(you.magic_points, you.max_magic_points)) + { + inc_mp(1); + } + else // standard hp regeneration + inc_hp(1); + tmp -= 100; + } + + ASSERT_RANGE(tmp, 0, 100); + you.hit_points_regeneration = tmp; + + // XXX: Don't let DD use guardian spirit for free HP, since their + // damage shaving is enough. (due, dpeg) + if (you.spirit_shield() && you.species == SP_DEEP_DWARF) + return; + + // XXX: Doing the same as the above, although overflow isn't an + // issue with magic point regeneration, yet. -- bwr + tmp = you.magic_points_regeneration; + + if (you.magic_points < you.max_magic_points) + { + const int base_val = 7 + you.max_magic_points / 2; + int mp_regen_countup = div_rand_round(base_val * delay, BASELINE_DELAY); + if (you.mutation[MUT_MANA_REGENERATION]) + mp_regen_countup *= 2; + tmp += mp_regen_countup; + } + + while (tmp >= 100) + { + inc_mp(1); + tmp -= 100; + } + + ASSERT_RANGE(tmp, 0, 100); + you.magic_points_regeneration = tmp; +} + +void player_reacts() +{ + extern int stealth; // defined in main.cc + + search_around(); + + stealth = check_stealth(); + +#ifdef DEBUG_STEALTH + // Too annoying for regular diagnostics. + mprf(MSGCH_DIAGNOSTICS, "stealth: %d", stealth); +#endif + + if (you.attribute[ATTR_SHADOWS]) + shadow_lantern_effect(); + + if (you.species == SP_LAVA_ORC) + temperature_check(); + + if (player_mutation_level(MUT_DEMONIC_GUARDIAN)) + check_demonic_guardian(); + + _check_equipment_conducts(); + + if (you.unrand_reacts != 0) + unrand_reacts(); + + // Handle sound-dependent effects that are silenced + if (silenced(you.pos())) + { + if (you.duration[DUR_SONG_OF_SLAYING]) + { + mpr("The silence causes your song to end."); + _decrement_a_duration(DUR_SONG_OF_SLAYING, you.duration[DUR_SONG_OF_SLAYING]); + } + } + + // Singing makes a continuous noise + if (you.duration[DUR_SONG_OF_SLAYING]) + noisy(8, you.pos()); + + if (one_chance_in(10)) + { + const int teleportitis_level = player_teleport(); + // this is instantaneous + if (teleportitis_level > 0 && one_chance_in(100 / teleportitis_level)) + { + if (teleportitis_level >= 8) + you_teleport_now(true); + else + you_teleport_now(true, false, teleportitis_level * 5); + } + else if (player_in_branch(BRANCH_ABYSS) && one_chance_in(80) + && (!map_masked(you.pos(), MMT_VAULT) || one_chance_in(3))) + { + mprf(MSGCH_BANISHMENT, "You are suddenly pulled into a different region of the Abyss!"); + you_teleport_now(false); // to new area of the Abyss + + // It's effectively a new level, make a checkpoint save so eventual + // crashes lose less of the player's progress (and fresh new bad + // mutations). + if (!crawl_state.disables[DIS_SAVE_CHECKPOINTS]) + save_game(false); + } + else if (you.form == TRAN_WISP && !you.stasis()) + random_blink(false); + } + + actor_apply_cloud(&you); + + if (env.level_state & LSTATE_SLIMY_WALL) + slime_wall_damage(&you, you.time_taken); + + // Icy shield and armour melt over lava. + if (grd(you.pos()) == DNGN_LAVA) + expose_player_to_element(BEAM_LAVA); + + you.update_beholders(); + you.update_fearmongers(); + + _decrement_durations(); + you.handle_constriction(); + + // increment constriction durations + you.accum_has_constricted(); + + int capped_time = you.time_taken; + if (you.walking && capped_time > BASELINE_DELAY) + capped_time = BASELINE_DELAY; + + int food_use = player_hunger_rate(); + food_use = div_rand_round(food_use * capped_time, BASELINE_DELAY); + + if (food_use > 0 && you.hunger > 0) + { + make_hungry(food_use, true); + if (you.duration[DUR_AMBROSIA]) + { + if (food_use > you.duration[DUR_AMBROSIA]) + food_use = you.duration[DUR_AMBROSIA]; + you.duration[DUR_AMBROSIA] -= food_use; + inc_mp(food_use); + } + } + + _regenerate_hp_and_mp(capped_time); + + dec_disease_player(capped_time); + if (you.duration[DUR_POISONING]) + handle_player_poison(capped_time); + + recharge_rods(you.time_taken, false); + + // Reveal adjacent mimics. + for (adjacent_iterator ai(you.pos(), false); ai; ++ai) + discover_mimic(*ai); + + // Player stealth check. + seen_monsters_react(); + + update_stat_zero(); + + // XOM now ticks from here, to increase his reaction time to tension. + if (you_worship(GOD_XOM)) + xom_tick(); +} + +void extract_manticore_spikes(const char* endmsg) +{ + if (_decrement_a_duration(DUR_BARBS, you.time_taken, endmsg)) + { + // Note: When this is called in _move player(), ATTR_BARBS_POW + // has already been used to calculated damage for the player. + // Otherwise, this prevents the damage. + + you.attribute[ATTR_BARBS_POW] = 0; + } +} diff --git a/crawl-ref/source/player-reacts.h b/crawl-ref/source/player-reacts.h new file mode 100644 index 0000000000..def989ca60 --- /dev/null +++ b/crawl-ref/source/player-reacts.h @@ -0,0 +1,9 @@ +#ifndef PLAYER_REACTS_H +#define PLAYER_REACTS_H +// Used only in world_reacts() +void player_reacts(); +void player_reacts_to_monsters(); + +// Only function other than decrement_duratons() which uses decrement_a_duration() +void extract_manticore_spikes(const char* endmsg); +#endif |