summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/effects.cc
diff options
context:
space:
mode:
authordshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2007-12-30 13:37:01 +0000
committerdshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2007-12-30 13:37:01 +0000
commite07b2622e22fa66566f3e18427e2bb2f9012682e (patch)
treecfd6490ec619d26cc968f09f64cdf204fb11363e /crawl-ref/source/effects.cc
parent5468ad7e219db69ad3b32c129a008986e038a1b7 (diff)
downloadcrawl-ref-e07b2622e22fa66566f3e18427e2bb2f9012682e.tar.gz
crawl-ref-e07b2622e22fa66566f3e18427e2bb2f9012682e.zip
Moved handle_time and friends to effects.cc.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@3157 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source/effects.cc')
-rw-r--r--crawl-ref/source/effects.cc808
1 files changed, 808 insertions, 0 deletions
diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc
index 4159e7e0ee..0aa101bf09 100644
--- a/crawl-ref/source/effects.cc
+++ b/crawl-ref/source/effects.cc
@@ -20,8 +20,11 @@
#include "externs.h"
#include "beam.h"
+#include "cloud.h"
#include "decks.h"
+#include "delay.h"
#include "direct.h"
+#include "dgnevent.h"
#include "food.h"
#include "hiscores.h"
#include "it_use2.h"
@@ -41,15 +44,19 @@
#include "ouch.h"
#include "player.h"
#include "randart.h"
+#include "religion.h"
+#include "skills.h"
#include "skills2.h"
#include "spells3.h"
#include "spells4.h"
#include "spl-book.h"
+#include "spl-cast.h"
#include "spl-util.h"
#include "state.h"
#include "stuff.h"
#include "terrain.h"
#include "traps.h"
+#include "tutorial.h"
#include "view.h"
#include "xom.h"
@@ -1870,3 +1877,804 @@ bool forget_inventory(bool quiet)
return (items_forgotten > 0);
}
+
+///////////////////////////////////////////////////////////////////////
+
+static void hell_effects()
+{
+ int temp_rand = random2(17);
+ spschool_flag_type which_miscast = SPTYP_RANDOM;
+ bool summon_instead = false;
+ monster_type which_beastie = MONS_PROGRAM_BUG;
+
+ mpr((temp_rand == 0) ? "\"You will not leave this place.\"" :
+ (temp_rand == 1) ? "\"Die, mortal!\"" :
+ (temp_rand == 2) ? "\"We do not forgive those who trespass against us!\"" :
+ (temp_rand == 3) ? "\"Trespassers are not welcome here!\"" :
+ (temp_rand == 4) ? "\"You do not belong in this place!\"" :
+ (temp_rand == 5) ? "\"Leave now, before it is too late!\"" :
+ (temp_rand == 6) ? "\"We have you now!\"" :
+ // plain messages
+ (temp_rand == 7) ? (player_can_smell()) ? "You smell brimstone." :
+ "Brimstone rains from above." :
+ (temp_rand == 8) ? "You feel lost and a long, long way from home..." :
+ (temp_rand == 9) ? "You shiver with fear." :
+ // warning
+ (temp_rand == 10) ? "You feel a terrible foreboding..." :
+ (temp_rand == 11) ? "Something frightening happens." :
+ (temp_rand == 12) ? "You sense an ancient evil watching you..." :
+ (temp_rand == 13) ? "You suddenly feel all small and vulnerable." :
+ (temp_rand == 14) ? "You sense a hostile presence." :
+ // sounds
+ (temp_rand == 15) ? "A gut-wrenching scream fills the air!" :
+ (temp_rand == 16) ? "You hear words spoken in a strange and terrible language..."
+ : "You hear diabolical laughter!",
+ (temp_rand < 7 ? MSGCH_TALK :
+ temp_rand < 10 ? MSGCH_PLAIN :
+ temp_rand < 15 ? MSGCH_WARN
+ : MSGCH_SOUND) );
+
+ temp_rand = random2(27);
+
+ if (temp_rand > 17) // 9 in 27 odds {dlb}
+ {
+ temp_rand = random2(8);
+
+ if (temp_rand > 3) // 4 in 8 odds {dlb}
+ which_miscast = SPTYP_NECROMANCY;
+ else if (temp_rand > 1) // 2 in 8 odds {dlb}
+ which_miscast = SPTYP_SUMMONING;
+ else if (temp_rand > 0) // 1 in 8 odds {dlb}
+ which_miscast = SPTYP_CONJURATION;
+ else // 1 in 8 odds {dlb}
+ which_miscast = SPTYP_ENCHANTMENT;
+
+ miscast_effect( which_miscast, 4 + random2(6), random2avg(97, 3),
+ 100, "the effects of Hell" );
+ }
+ else if (temp_rand > 7) // 10 in 27 odds {dlb}
+ {
+ // 60:40 miscast:summon split {dlb}
+ summon_instead = (random2(5) > 2);
+
+ switch (you.where_are_you)
+ {
+ case BRANCH_DIS:
+ if (summon_instead)
+ which_beastie = summon_any_demon(DEMON_GREATER);
+ else
+ which_miscast = SPTYP_EARTH;
+ break;
+ case BRANCH_GEHENNA:
+ if (summon_instead)
+ which_beastie = MONS_FIEND;
+ else
+ which_miscast = SPTYP_FIRE;
+ break;
+ case BRANCH_COCYTUS:
+ if (summon_instead)
+ which_beastie = MONS_ICE_FIEND;
+ else
+ which_miscast = SPTYP_ICE;
+ break;
+ case BRANCH_TARTARUS:
+ if (summon_instead)
+ which_beastie = MONS_SHADOW_FIEND;
+ else
+ which_miscast = SPTYP_NECROMANCY;
+ break;
+ default: // this is to silence gcc compiler warnings {dlb}
+ if (summon_instead)
+ which_beastie = MONS_FIEND;
+ else
+ which_miscast = SPTYP_NECROMANCY;
+ break;
+ }
+
+ if (summon_instead)
+ {
+ create_monster( which_beastie, 0, BEH_HOSTILE, you.x_pos,
+ you.y_pos, MHITYOU, 250 );
+ }
+ else
+ {
+ miscast_effect( which_miscast, 4 + random2(6),
+ random2avg(97, 3), 100, "the effects of Hell" );
+ }
+ }
+
+ // NB: no "else" - 8 in 27 odds that nothing happens through
+ // first chain {dlb}
+ // also note that the following is distinct from and in
+ // addition to the above chain:
+
+ // try to summon at least one and up to five random monsters {dlb}
+ if (one_chance_in(3))
+ {
+ create_monster( RANDOM_MONSTER, 0, BEH_HOSTILE,
+ you.x_pos, you.y_pos, MHITYOU, 250 );
+
+ for (int i = 0; i < 4; i++)
+ {
+ if (one_chance_in(3))
+ {
+ create_monster( RANDOM_MONSTER, 0, BEH_HOSTILE,
+ you.x_pos, you.y_pos, MHITYOU, 250 );
+ }
+ }
+ }
+}
+
+static void rot_inventory_food(long time_delta)
+{
+ // Update all of the corpses and food chunks in the player's
+ // inventory {should be moved elsewhere - dlb}
+
+ bool burden_changed_by_rot = false;
+ bool new_rotting_item = false;
+ for (int i = 0; i < ENDOFPACK; i++)
+ {
+ if (you.inv[i].quantity < 1)
+ continue;
+
+ if (you.inv[i].base_type != OBJ_CORPSES && you.inv[i].base_type != OBJ_FOOD)
+ continue;
+
+ if (you.inv[i].base_type == OBJ_CORPSES
+ && you.inv[i].sub_type > CORPSE_SKELETON)
+ {
+ continue;
+ }
+
+ if (you.inv[i].base_type == OBJ_FOOD && you.inv[i].sub_type != FOOD_CHUNK)
+ continue;
+
+ if ((time_delta / 20) >= you.inv[i].special)
+ {
+ if (you.inv[i].base_type == OBJ_FOOD)
+ {
+ if (you.equip[EQ_WEAPON] == i)
+ unwield_item();
+
+ destroy_item(you.inv[i]);
+ burden_changed_by_rot = true;
+ continue;
+ }
+
+ if (you.inv[i].sub_type == CORPSE_SKELETON)
+ continue; // carried skeletons are not destroyed
+
+ if (!mons_skeleton( you.inv[i].plus ))
+ {
+ if (you.equip[EQ_WEAPON] == i)
+ unwield_item();
+
+ destroy_item(you.inv[i]);
+ burden_changed_by_rot = true;
+ continue;
+ }
+
+ you.inv[i].sub_type = CORPSE_SKELETON;
+ you.inv[i].special = 0;
+ you.inv[i].colour = LIGHTGREY;
+ you.wield_change = true;
+ burden_changed_by_rot = true;
+ continue;
+ }
+
+ you.inv[i].special -= (time_delta / 20);
+
+ if (you.inv[i].special < 100 && (you.inv[i].special + (time_delta / 20)>=100))
+ {
+ new_rotting_item = true;
+ }
+ }
+
+ //mv: messages when chunks/corpses become rotten
+ if (new_rotting_item)
+ {
+ // XXX: should probably still notice?
+ // Races that can't smell don't care, and trolls are stupid and
+ // don't care.
+ if (player_can_smell() && you.species != SP_TROLL)
+ {
+ int temp_rand = 0; // Grr.
+ switch (you.mutation[MUT_SAPROVOROUS])
+ {
+ // level 1 and level 2 saprovores aren't so touchy
+ case 1:
+ case 2:
+ temp_rand = random2(8);
+ mpr( ((temp_rand < 5) ? "You smell something rotten." :
+ (temp_rand == 5) ? "You smell rotting flesh." :
+ (temp_rand == 6) ? "You smell decay."
+ : "There is something rotten in your inventory."),
+ MSGCH_ROTTEN_MEAT );
+ break;
+
+ // level 3 saprovores like it
+ case 3:
+ temp_rand = random2(8);
+ mpr( ((temp_rand < 5) ? "You smell something rotten." :
+ (temp_rand == 5) ? "The smell of rotting flesh makes you hungry." :
+ (temp_rand == 6) ? "You smell decay. Yum-yum."
+ : "Wow! There is something tasty in your inventory."),
+ MSGCH_ROTTEN_MEAT );
+ break;
+
+ default:
+ temp_rand = random2(8);
+ mpr( ((temp_rand < 5) ? "You smell something rotten." :
+ (temp_rand == 5) ? "The smell of rotting flesh makes you sick." :
+ (temp_rand == 6) ? "You smell decay. Yuck!"
+ : "Ugh! There is something really disgusting in your inventory."),
+ MSGCH_ROTTEN_MEAT );
+ break;
+ }
+ }
+ learned_something_new(TUT_ROTTEN_FOOD);
+ }
+ if (burden_changed_by_rot)
+ {
+ mpr("Your equipment suddenly weighs less.", MSGCH_ROTTEN_MEAT);
+ burden_change();
+ }
+}
+
+//---------------------------------------------------------------
+//
+// handle_time
+//
+// Do various time related actions...
+// This function is called about every 20 turns.
+//
+//---------------------------------------------------------------
+void handle_time( long time_delta )
+{
+ // BEGIN - Nasty things happen to people who spend too long in Hell:
+ if (player_in_hell() && coinflip())
+ hell_effects();
+
+ // Adjust the player's stats if s/he's diseased (or recovering).
+ if (!you.disease)
+ {
+ if (you.strength < you.max_strength && one_chance_in(100))
+ {
+ mpr("You feel your strength returning.", MSGCH_RECOVERY);
+ you.strength++;
+ you.redraw_strength = 1;
+ }
+
+ if (you.dex < you.max_dex && one_chance_in(100))
+ {
+ mpr("You feel your dexterity returning.", MSGCH_RECOVERY);
+ you.dex++;
+ you.redraw_dexterity = 1;
+ }
+
+ if (you.intel < you.max_intel && one_chance_in(100))
+ {
+ mpr("You feel your intelligence returning.", MSGCH_RECOVERY);
+ you.intel++;
+ you.redraw_intelligence = 1;
+ }
+ }
+ else
+ {
+ if (one_chance_in(30))
+ {
+ mpr("Your disease is taking its toll.", MSGCH_WARN);
+ lose_stat(STAT_RANDOM, 1, false, "disease");
+ }
+ }
+
+ // Adjust the player's stats if s/he has the deterioration mutation
+ if (you.mutation[MUT_DETERIORATION]
+ && random2(200) <= you.mutation[MUT_DETERIORATION] * 5 - 2)
+ {
+ lose_stat(STAT_RANDOM, 1, false, "deterioration mutation");
+ }
+
+ int added_contamination = 0;
+
+ // Account for mutagenic radiation. Invis and haste will give the
+ // player about .1 points per turn, mutagenic randarts will give
+ // about 1.5 points on average, so they can corrupt the player
+ // quite quickly. Wielding one for a short battle is OK, which is
+ // as things should be. -- GDL
+ if (you.duration[DUR_INVIS] && random2(10) < 6)
+ added_contamination++;
+
+ if (you.duration[DUR_HASTE] && !you.duration[DUR_BERSERKER]
+ && random2(10) < 6)
+ {
+ added_contamination++;
+ }
+
+ if (const int randart_glow = scan_randarts(RAP_MUTAGENIC))
+ {
+ // Reduced randart glow. Note that one randart will contribute
+ // 2 - 5 units of glow to randart_glow. A randart with a mutagen
+ // index of 2 does about 0.58 points of contamination per turn.
+ // A randart with a mutagen index of 5 does about 0.7 points of
+ // contamination per turn.
+
+ const int mean_glow = 500 + randart_glow * 40;
+ const int actual_glow = mean_glow / 2 + random2(mean_glow);
+ added_contamination += div_rand_round(actual_glow, 1000);
+ }
+
+ // we take off about .5 points per turn
+ if (!you.duration[DUR_INVIS] && !you.duration[DUR_HASTE] && coinflip())
+ added_contamination -= 1;
+
+ contaminate_player( added_contamination );
+
+ // only check for badness once every other turn
+ if (coinflip())
+ {
+ // [ds] Be less harsh with glow mutation; Brent and Mark Mackey note
+ // that the commented out random2(X) <= MC check was a bug. I've
+ // uncommented it but dropped the roll sharply from 150. (Brent used
+ // the original roll of 150 for 4.1.2, but I think players are
+ // sufficiently used to beta 26's unkindness that we can use a lower
+ // roll.)
+ if (you.magic_contamination >= 5
+ && random2(25) <= you.magic_contamination)
+ {
+ mpr("Your body shudders with the violent release of wild energies!", MSGCH_WARN);
+
+ // for particularly violent releases, make a little boom
+ if (you.magic_contamination >= 10 && coinflip())
+ {
+ struct bolt boom;
+ boom.type = dchar_glyph(DCHAR_FIRED_BURST);
+ boom.colour = BLACK;
+ boom.flavour = BEAM_RANDOM;
+ boom.target_x = you.x_pos;
+ boom.target_y = you.y_pos;
+ // Undead enjoy extra contamination explosion damage because
+ // the magical contamination has a harder time dissipating
+ // through non-living flesh. :-)
+ boom.damage =
+ dice_def( 3,
+ you.magic_contamination
+ * (you.is_undead? 4 : 2)
+ / 4 );
+ boom.thrower = KILL_MISC;
+ boom.aux_source = "a magical explosion";
+ boom.beam_source = NON_MONSTER;
+ boom.is_beam = false;
+ boom.is_tracer = false;
+ boom.is_explosion = true;
+ boom.name = "magical storm";
+
+ boom.ench_power = (you.magic_contamination * 5);
+ boom.ex_size = (you.magic_contamination / 15);
+ if (boom.ex_size > 9)
+ boom.ex_size = 9;
+
+ explosion(boom);
+ }
+
+ // we want to warp the player, not do good stuff!
+ if (one_chance_in(5))
+ mutate(RANDOM_MUTATION);
+ else
+ give_bad_mutation(coinflip());
+
+ // we're meaner now, what with explosions and whatnot, but
+ // we dial down the contamination a little faster if its actually
+ // mutating you. -- GDL
+ contaminate_player( -(random2(you.magic_contamination / 4) + 1) );
+ }
+ }
+
+ // Random chance to identify staff in hand based off of Spellcasting
+ // and an appropriate other spell skill... is 1/20 too fast?
+ if (you.equip[EQ_WEAPON] != -1
+ && you.inv[you.equip[EQ_WEAPON]].base_type == OBJ_STAVES
+ && !item_type_known( you.inv[you.equip[EQ_WEAPON]] )
+ && one_chance_in(20))
+ {
+ int total_skill = you.skills[SK_SPELLCASTING];
+
+ switch (you.inv[you.equip[EQ_WEAPON]].sub_type)
+ {
+ case STAFF_WIZARDRY:
+ case STAFF_ENERGY:
+ total_skill += you.skills[SK_SPELLCASTING];
+ break;
+ case STAFF_FIRE:
+ if (you.skills[SK_FIRE_MAGIC] > you.skills[SK_ICE_MAGIC])
+ total_skill += you.skills[SK_FIRE_MAGIC];
+ else
+ total_skill += you.skills[SK_ICE_MAGIC];
+ break;
+ case STAFF_COLD:
+ if (you.skills[SK_ICE_MAGIC] > you.skills[SK_FIRE_MAGIC])
+ total_skill += you.skills[SK_ICE_MAGIC];
+ else
+ total_skill += you.skills[SK_FIRE_MAGIC];
+ break;
+ case STAFF_AIR:
+ if (you.skills[SK_AIR_MAGIC] > you.skills[SK_EARTH_MAGIC])
+ total_skill += you.skills[SK_AIR_MAGIC];
+ else
+ total_skill += you.skills[SK_EARTH_MAGIC];
+ break;
+ case STAFF_EARTH:
+ if (you.skills[SK_EARTH_MAGIC] > you.skills[SK_AIR_MAGIC])
+ total_skill += you.skills[SK_EARTH_MAGIC];
+ else
+ total_skill += you.skills[SK_AIR_MAGIC];
+ break;
+ case STAFF_POISON:
+ total_skill += you.skills[SK_POISON_MAGIC];
+ break;
+ case STAFF_DEATH:
+ total_skill += you.skills[SK_NECROMANCY];
+ break;
+ case STAFF_CONJURATION:
+ total_skill += you.skills[SK_CONJURATIONS];
+ break;
+ case STAFF_ENCHANTMENT:
+ total_skill += you.skills[SK_ENCHANTMENTS];
+ break;
+ case STAFF_SUMMONING:
+ total_skill += you.skills[SK_SUMMONINGS];
+ break;
+ }
+
+ if (random2(100) < total_skill)
+ {
+ item_def& item = you.inv[you.equip[EQ_WEAPON]];
+ set_ident_flags( item, ISFLAG_IDENT_MASK );
+
+ mprf("You are wielding %s.", item.name(DESC_NOCAP_A).c_str());
+ more();
+
+ you.wield_change = true;
+ }
+ }
+
+ // Check to see if an upset god wants to do something to the player
+ // jmf: moved huge thing to religion.cc
+ handle_god_time();
+
+ if (you.mutation[MUT_SCREAM]
+ && (random2(100) <= 2 + you.mutation[MUT_SCREAM] * 3) )
+ {
+ yell(true);
+ }
+ else if (you.mutation[MUT_SLEEPINESS]
+ && random2(100) < you.mutation[MUT_SLEEPINESS] * 5)
+ {
+ you.put_to_sleep();
+ }
+
+ // Update all of the corpses and food chunks on the floor
+ update_corpses(time_delta);
+
+ rot_inventory_food(time_delta);
+
+ // exercise armour *xor* stealth skill: {dlb}
+ if (!player_light_armour(true))
+ {
+ if (random2(1000) <= item_mass( you.inv[you.equip[EQ_BODY_ARMOUR]] ))
+ return;
+
+ if (one_chance_in(6)) // lowered random roll from 7 to 6 -- bwross
+ exercise(SK_ARMOUR, 1);
+ }
+ else // exercise stealth skill:
+ {
+ if (you.burden_state != BS_UNENCUMBERED || you.duration[DUR_BERSERKER])
+ return;
+
+ if (you.special_wield == SPWLD_SHADOW)
+ return;
+
+ if (you.equip[EQ_BODY_ARMOUR] != -1
+ && random2( item_mass( you.inv[you.equip[EQ_BODY_ARMOUR]] )) >= 100)
+ {
+ return;
+ }
+
+ if (one_chance_in(18))
+ exercise(SK_STEALTH, 1);
+ }
+}
+
+//---------------------------------------------------------------
+//
+// update_level
+//
+// Update the level when the player returns to it.
+//
+//---------------------------------------------------------------
+void update_level( double elapsedTime )
+{
+ int m, i;
+ const int turns = static_cast<int>(elapsedTime / 10.0);
+
+#if DEBUG_DIAGNOSTICS
+ int mons_total = 0;
+
+ mprf(MSGCH_DIAGNOSTICS, "turns: %d", turns );
+#endif
+
+ update_corpses( elapsedTime );
+
+ dungeon_events.fire_event(
+ dgn_event(DET_TURN_ELAPSED, coord_def(0, 0), turns * 10));
+
+ for (m = 0; m < MAX_MONSTERS; m++)
+ {
+ struct monsters *mon = &menv[m];
+
+ if (mon->type == -1)
+ continue;
+
+#if DEBUG_DIAGNOSTICS
+ mons_total++;
+#endif
+
+ // following monsters don't get movement
+ if (mon->flags & MF_JUST_SUMMONED)
+ continue;
+
+ // XXX: Allow some spellcasting (like Healing and Teleport)? -- bwr
+ // const bool healthy = (mon->hit_points * 2 > mon->max_hit_points);
+
+ // This is the monster healing code, moved here from tag.cc:
+ if (monster_descriptor( mon->type, MDSC_REGENERATES )
+ || mon->type == MONS_PLAYER_GHOST)
+ {
+ heal_monster( mon, turns, false );
+ }
+ else
+ {
+ heal_monster( mon, (turns / 10), false );
+ }
+
+ if (turns >= 10)
+ mon->timeout_enchantments( turns / 10 );
+
+ // Don't move water, lava, or stationary monsters around
+ if (monster_habitat( mon->type ) != DNGN_FLOOR
+ || mons_is_stationary( mon ))
+ {
+ continue;
+ }
+
+ // Let sleeping monsters lie
+ if (mon->behaviour == BEH_SLEEP || mons_is_paralysed(mon))
+ continue;
+
+ const int range = (turns * mon->speed) / 10;
+ const int moves = (range > 50) ? 50 : range;
+
+ // const bool short_time = (range >= 5 + random2(10));
+ const bool long_time = (range >= (500 + roll_dice( 2, 500 )));
+
+ const bool ranged_attack = (mons_has_ranged_spell( mon )
+ || mons_has_ranged_attack( mon ));
+
+#if DEBUG_DIAGNOSTICS
+ // probably too annoying even for DEBUG_DIAGNOSTICS
+ mprf(MSGCH_DIAGNOSTICS,
+ "mon #%d: range %d; long %d; "
+ "pos (%d,%d); targ %d(%d,%d); flags %ld",
+ m, range, long_time, mon->x, mon->y,
+ mon->foe, mon->target_x, mon->target_y, mon->flags );
+#endif
+
+ if (range <= 0)
+ continue;
+
+ if (long_time
+ && (mon->behaviour == BEH_FLEE
+ || mon->behaviour == BEH_CORNERED
+ || testbits( mon->flags, MF_BATTY )
+ || ranged_attack
+ || coinflip()))
+ {
+ if (mon->behaviour != BEH_WANDER)
+ {
+ mon->behaviour = BEH_WANDER;
+ mon->foe = MHITNOT;
+ mon->target_x = 10 + random2( GXM - 10 );
+ mon->target_y = 10 + random2( GYM - 10 );
+ }
+ else
+ {
+ // monster will be sleeping after we move it
+ mon->behaviour = BEH_SLEEP;
+ }
+ }
+ else if (ranged_attack)
+ {
+ // if we're doing short time movement and the monster has a
+ // ranged attack (missile or spell), then the monster will
+ // flee to gain distance if its "too close", else it will
+ // just shift its position rather than charge the player. -- bwr
+ if (grid_distance(mon->x, mon->y, mon->target_x, mon->target_y) < 3)
+ {
+ mon->behaviour = BEH_FLEE;
+
+ // if the monster is on the target square, fleeing won't work
+ if (mon->x == mon->target_x && mon->y == mon->target_y)
+ {
+ if (you.x_pos != mon->x || you.y_pos != mon->y)
+ {
+ // flee from player's position if different
+ mon->target_x = you.x_pos;
+ mon->target_y = you.y_pos;
+ }
+ else
+ {
+ // randomize the target so we have a direction to flee
+ mon->target_x += (random2(3) - 1);
+ mon->target_y += (random2(3) - 1);
+ }
+ }
+
+#if DEBUG_DIAGNOSTICS
+ mpr( "backing off...", MSGCH_DIAGNOSTICS );
+#endif
+ }
+ else
+ {
+ shift_monster( mon, mon->x, mon->y );
+
+#if DEBUG_DIAGNOSTICS
+ mprf(MSGCH_DIAGNOSTICS, "shifted to (%d,%d)", mon->x, mon->y);
+#endif
+ continue;
+ }
+ }
+
+ coord_def pos(mon->pos());
+ // dirt simple movement:
+ for (i = 0; i < moves; i++)
+ {
+ coord_def inc(mon->target_pos() - pos);
+ inc = coord_def(sgn(inc.x), sgn(inc.y));
+
+ if (mon->behaviour == BEH_FLEE)
+ inc *= -1;
+
+ if (pos.x + inc.x < 0 || pos.x + inc.x >= GXM)
+ inc.x = 0;
+
+ if (pos.y + inc.y < 0 || pos.y + inc.y >= GYM)
+ inc.y = 0;
+
+ if (inc.origin())
+ break;
+
+ const coord_def next(pos + inc);
+ const dungeon_feature_type feat = grd(next);
+ if (grid_is_solid(feat)
+ || mgrd(next) != NON_MONSTER
+ || !monster_habitable_grid(mon, feat))
+ break;
+
+ pos = next;
+ }
+
+ if (!shift_monster( mon, pos.x, pos.y ))
+ shift_monster( mon, mon->x, mon->y );
+
+#if DEBUG_DIAGNOSTICS
+ mprf(MSGCH_DIAGNOSTICS, "moved to (%d,%d)", mon->x, mon->y );
+#endif
+ }
+
+#if DEBUG_DIAGNOSTICS
+ mprf(MSGCH_DIAGNOSTICS, "total monsters on level = %d", mons_total );
+#endif
+
+ for (i = 0; i < MAX_CLOUDS; i++)
+ delete_cloud( i );
+}
+
+//---------------------------------------------------------------
+//
+// update_corpses
+//
+// Update all of the corpses and food chunks on the floor. (The
+// elapsed time is a double because this is called when we re-
+// enter a level and a *long* time may have elapsed).
+//
+//---------------------------------------------------------------
+void update_corpses(double elapsedTime)
+{
+ int cx, cy;
+
+ if (elapsedTime <= 0.0)
+ return;
+
+ const long rot_time = static_cast<long>(elapsedTime / 20.0);
+
+ for (int c = 0; c < MAX_ITEMS; c++)
+ {
+ item_def &it = mitm[c];
+
+ if (!is_valid_item(it))
+ continue;
+
+ if (it.base_type != OBJ_CORPSES && it.base_type != OBJ_FOOD)
+ {
+ continue;
+ }
+
+ if (it.base_type == OBJ_CORPSES
+ && it.sub_type > CORPSE_SKELETON)
+ {
+ continue;
+ }
+
+ if (it.base_type == OBJ_FOOD && it.sub_type != FOOD_CHUNK)
+ {
+ continue;
+ }
+
+ if (rot_time >= it.special && !is_being_butchered(it))
+ {
+ if (it.base_type == OBJ_FOOD)
+ {
+ destroy_item(c);
+ }
+ else
+ {
+ if (it.sub_type == CORPSE_SKELETON
+ || !mons_skeleton( it.plus ))
+ {
+ destroy_item(c);
+ }
+ else
+ {
+ it.sub_type = CORPSE_SKELETON;
+ it.special = 200;
+ it.colour = LIGHTGREY;
+ }
+ }
+ }
+ else
+ {
+ ASSERT(rot_time < 256);
+ it.special -= rot_time;
+ }
+ }
+
+ int fountain_checks = static_cast<int>(elapsedTime / 1000.0);
+ if (random2(1000) < static_cast<int>(elapsedTime) % 1000)
+ fountain_checks += 1;
+
+ // dry fountains may start flowing again
+ if (fountain_checks > 0)
+ {
+ for (cx=0; cx<GXM; cx++)
+ {
+ for (cy=0; cy<GYM; cy++)
+ {
+ if (grd[cx][cy] > DNGN_SPARKLING_FOUNTAIN
+ && grd[cx][cy] < DNGN_PERMADRY_FOUNTAIN)
+ {
+ for (int i=0; i<fountain_checks; i++)
+ {
+ if (one_chance_in(100))
+ {
+ if (grd[cx][cy] > DNGN_SPARKLING_FOUNTAIN)
+ grd[cx][cy] =
+ static_cast<dungeon_feature_type>(
+ grd[cx][cy] - 1);
+ }
+ }
+ }
+ }
+ }
+ }
+}