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 againif (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_DIAGNOSTICSint mons_total = 0;
mprf(MSGCH_DIAGNOSTICS, "turns: %d", turns );#endifupdate_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_DIAGNOSTICSmons_total++;#endif// following monsters don't get movementif (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 aroundif (monster_habitat( mon->type ) != DNGN_FLOOR|| mons_is_stationary( mon )){continue;}// Let sleeping monsters lieif (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_DIAGNOSTICSmprf(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 );#endifif (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 itmon->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. -- bwrif (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 workif (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 differentmon->target_x = you.x_pos;mon->target_y = you.y_pos;}else{// randomize the target so we have a direction to fleemon->target_x += (random2(3) - 1);mon->target_y += (random2(3) - 1);}}#if DEBUG_DIAGNOSTICSmpr( "backing off...", MSGCH_DIAGNOSTICS );#endif}else{shift_monster( mon, mon->x, mon->y );#if DEBUG_DIAGNOSTICSmprf(MSGCH_DIAGNOSTICS, "shifted to (%d,%d)", mon->x, mon->y);#endifcontinue;}}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_DIAGNOSTICSmprf(MSGCH_DIAGNOSTICS, "moved to (%d,%d)", mon->x, mon->y );#endif}#if DEBUG_DIAGNOSTICSmprf(MSGCH_DIAGNOSTICS, "total monsters on level = %d", mons_total );#endiffor (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);elsewhich_miscast = SPTYP_EARTH;break;case BRANCH_GEHENNA:if (summon_instead)which_beastie = MONS_FIEND;elsewhich_miscast = SPTYP_FIRE;break;case BRANCH_COCYTUS:if (summon_instead)which_beastie = MONS_ICE_FIEND;elsewhich_miscast = SPTYP_ICE;break;case BRANCH_TARTARUS:if (summon_instead)which_beastie = MONS_SHADOW_FIEND;elsewhich_miscast = SPTYP_NECROMANCY;break;default: // this is to silence gcc compiler warnings {dlb}if (summon_instead)which_beastie = MONS_FIEND;elsewhich_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 destroyedif (!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 rottenif (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 touchycase 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 itcase 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 mutationif (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. -- GDLif (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 turnif (!you.duration[DUR_INVIS] && !you.duration[DUR_HASTE] && coinflip())added_contamination -= 1;contaminate_player( added_contamination );// only check for badness once every other turnif (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 boomif (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);elsegive_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. -- GDLcontaminate_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];elsetotal_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];elsetotal_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];elsetotal_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];elsetotal_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.cchandle_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 floorupdate_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 -- bwrossexercise(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);elsewhich_miscast = SPTYP_EARTH;break;case BRANCH_GEHENNA:if (summon_instead)which_beastie = MONS_FIEND;elsewhich_miscast = SPTYP_FIRE;break;case BRANCH_COCYTUS:if (summon_instead)which_beastie = MONS_ICE_FIEND;elsewhich_miscast = SPTYP_ICE;break;case BRANCH_TARTARUS:if (summon_instead)which_beastie = MONS_SHADOW_FIEND;elsewhich_miscast = SPTYP_NECROMANCY;break;default: // this is to silence gcc compiler warnings {dlb}if (summon_instead)which_beastie = MONS_FIEND;elsewhich_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 destroyedif (!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 rottenif (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 touchycase 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 itcase 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 mutationif (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. -- GDLif (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 turnif (!you.duration[DUR_INVIS] && !you.duration[DUR_HASTE] && coinflip())added_contamination -= 1;contaminate_player( added_contamination );// only check for badness once every other turnif (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 boomif (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);elsegive_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. -- GDLcontaminate_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];elsetotal_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];elsetotal_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];elsetotal_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];elsetotal_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.cchandle_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 floorupdate_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 -- bwrossexercise(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_DIAGNOSTICSint mons_total = 0;mprf(MSGCH_DIAGNOSTICS, "turns: %d", turns );#endifupdate_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_DIAGNOSTICSmons_total++;#endif// following monsters don't get movementif (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 aroundif (monster_habitat( mon->type ) != DNGN_FLOOR|| mons_is_stationary( mon )){continue;}// Let sleeping monsters lieif (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_DIAGNOSTICSmprf(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 );#endifif (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 itmon->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. -- bwrif (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 workif (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 differentmon->target_x = you.x_pos;mon->target_y = you.y_pos;}else{// randomize the target so we have a direction to fleemon->target_x += (random2(3) - 1);mon->target_y += (random2(3) - 1);}}#if DEBUG_DIAGNOSTICSmpr( "backing off...", MSGCH_DIAGNOSTICS );#endif}else{shift_monster( mon, mon->x, mon->y );#if DEBUG_DIAGNOSTICSmprf(MSGCH_DIAGNOSTICS, "shifted to (%d,%d)", mon->x, mon->y);#endifcontinue;}}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_DIAGNOSTICSmprf(MSGCH_DIAGNOSTICS, "moved to (%d,%d)", mon->x, mon->y );#endif}#if DEBUG_DIAGNOSTICSmprf(MSGCH_DIAGNOSTICS, "total monsters on level = %d", mons_total );#endiffor (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 againif (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);}}}}}}}