git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@3157 c06c8d41-db1a-0410-9941-cceddc491573
HIRKGUMNJPWKSVTR6TVBPD3MWNA63CEHCLCIPWEMGDFHVB3NPLDQC
XXBZEIEB6JTDFJC6V2VSDAV2KHDXZYQ245EMQBKOX3I7HTU2DMIAC
UB67ZWGT7FOPKZ7SO5PAO3V4PUBPWPWXKQIQIUABNB533XP4JUMQC
EMZKIUVF6DACSA7C24CHXRQ56JGLSB3MHTCDZSRBXPMOTZNLHTQQC
CIAIASCBKKV7VMYBL2CIFAYGFQTB6GIME4FSQGZNQGXO7FXQTA5AC
2ZZV4SDJQ7WW4W5GRR4OPQ7SEHELWIEKIB2RVJFGEJSNWD6VEGTAC
UZ5623MOLKBTGBSRBJ4OBOEI4IEZSPV3NCV2DRMUZ3CHHJQVHIIAC
GNF4E3QZL4L24PB5KIRO5JJAZYIAIQLGH6PEJB3ONWMIIYDKTY6AC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
TAHSTXR7ROOMDFUSBUU4ZAIEWQLAS5CIRCTARLD4Q2BGNLSL7E5QC
GQL5SIGBHLU3FMCE54XVGLRY5AZHRM6DUEB722REA2DPLGJSN6EQC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
QKGDOYIYKE6B36ION5O2DRW65DWWPZMYNWJVH7LJJ7FPGGM2MYAQC
T5XERKCC6UL2UI2HKE34BTKNINTOXOSDCBYGC3A3JY7XMKIQW4GQC
SYTQFVPZKDRTGKBV7SQFULQKY4V7NBBCEBQF2KF5LZEP2VVYNUFQC
ILOED4VB4I6VPAUTR75ZWX6MXDYXB5DO2EDK2UH67O3HNKWV23RQC
YCL3W2PFE6ILTGBFODCSXNPDIA46KVSZP2TI7HDMYAOEJT65RIEAC
X5WLJCJVW55SXZVP7IKP7ADCJIGNKN4PKAXFECVR6TNK7XSMZR7QC
F7Q5PX44SLPANIZXCY67TG2W5JTRVJMHGQW54VJLGB4XRH7R6JBQC
H2GLADU4H3H3WGWK74KCQD6U447Z723DXMX43OUCFD2JQGRDTUWAC
BFZZ7DFLZM4WNHQOKWDJENZOLMXH3UPHZ437BMISYJ3VSO2Y57WQC
CLIEHAE2PP7ZIGLLIMYCWM4FC54KBOAN5AILOLAZJ5S26GTJM4RQC
I2B33Z7NZGC33AMDSSK446AZZYWKPHWLAGULVHKKZU4MVB4BNJOAC
CMNLYUECIMEZSOYG4KOSINOPER5OM7PPCGIHCM7LQVWEO77XFUYQC
QVVC7AYGVA6U64PTNA7L27422NLMO327P22BQKXEVIMPZHIHO7MQC
CIPVRZGLOZHCERK6YPOBV3P2E4IAB4H6D5EHLRQE2O5E4P4VCBUAC
ZCRK2DJ5VKECRQXZTWT4NUDL2VT5ZHUK7NT6NQPLRJ56TDX5PJSAC
Z63Q4DA5J5TZAC5LN55UD4CLADUMU5Z73TGEVE2YUXCHIST2Y4QAC
FBK5ECMQ6HJSQSN7C3DICKJIRJ3CSO3CHCQ3ONPBKLLSHDGPBQ7QC
5VFJGYI4MCPASCLFBHHNHXRREYPQURKXZTBMXUM72KPYONCQNQFAC
TPSCOEB3X6LNZ7F5UBMHDZ4IUE4H3RLX6IGNW65VSJBDMNNZ3FMAC
SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC
OONYLF4DAPLIYLBNNRW74IVT5BBTWI4XHQBXSNSPVRX3FTKJBTRAC
* called from: files - items
* *********************************************************************** */
void update_corpses(double elapsedTime);
void update_level(double elapsedTime);
// last updated: 08jun2000 {dlb}
/* ***********************************************************************
* called from: acr
* *********************************************************************** */
void handle_time( long time_delta );
// last updated: 08jun2000 {dlb}
/* ***********************************************************************
}
//---------------------------------------------------------------
//
// 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);
}
}
}
}
}
}
//---------------------------------------------------------------
//
// 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 );
}
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);
}
return;
} // end handle_time()
}
///////////////////////////////////////////////////////////////////////
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);
}
}
}
}
}
}
}