diff options
32 files changed, 1111 insertions, 1354 deletions
diff --git a/crawl-ref/source/Kills.cc b/crawl-ref/source/Kills.cc index b146a89cd5..8a85e04921 100644 --- a/crawl-ref/source/Kills.cc +++ b/crawl-ref/source/Kills.cc @@ -671,8 +671,8 @@ kill_monster_desc::kill_monster_desc(const monsters *mon) } if (modifier != M_NORMAL) monnum = mon->number; - if (mons_has_ench(mon, ENCH_SHAPESHIFTER) || - mons_has_ench(mon, ENCH_GLOWING_SHAPESHIFTER)) + if (mon->has_ench(ENCH_SHAPESHIFTER) || + mon->has_ench(ENCH_GLOWING_SHAPESHIFTER)) modifier = M_SHAPESHIFTER; // XXX: Ugly hack - merge all mimics into one mimic record. diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc index e31ec340c2..5b75740269 100644 --- a/crawl-ref/source/acr.cc +++ b/crawl-ref/source/acr.cc @@ -2698,23 +2698,7 @@ static bool initialise(void) strcpy(info, ""); for (i = 0; i < MAX_MONSTERS; i++) - { - menv[i].type = -1; - menv[i].speed_increment = 10; - menv[i].flags = 0; - menv[i].behaviour = BEH_SLEEP; - - menv[i].foe = NON_MONSTER; - menv[i].attitude = ATT_HOSTILE; - - for (j = 0; j < NUM_MON_ENCHANTS; j++) - menv[i].enchantment[j] = ENCH_NONE; - - for (j = 0; j < NUM_MONSTER_SLOTS; j++) - menv[i].inv[j] = NON_ITEM; - - menv[i].number = 0; - } + menv[i].reset(); for (i = 0; i < GXM; i++) { diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc index 593f6c3cc3..38cca50cd3 100644 --- a/crawl-ref/source/beam.cc +++ b/crawl-ref/source/beam.cc @@ -68,7 +68,7 @@ static FixedArray < bool, 19, 19 > explode_map; // helper functions (some of these, esp. affect(), should probably // be public): -static void sticky_flame_monster( int mn, bool source, int hurt_final ); +static void sticky_flame_monster( int mn, kill_category who, int hurt_final ); static bool affectsWall(const bolt &beam, int wall_feature); static bool isBouncy(struct bolt &beam, unsigned char gridtype); static void beam_drop_object( struct bolt &beam, item_def *item, int x, int y ); @@ -126,6 +126,22 @@ static void monster_die(monsters *mons, const bolt &beam) monster_die(mons, beam.killer(), beam.beam_source); } +static kill_category whose_kill(const bolt &beam) +{ + if (YOU_KILL(beam.thrower)) + return (KC_YOU); + else if (MON_KILL(beam.thrower)) + { + if (beam.beam_source >= 0 && beam.beam_source < MAX_MONSTERS) + { + const monsters &mons = menv[beam.beam_source]; + if (mons.attitude == ATT_FRIENDLY) + return (KC_FRIENDLY); + } + } + return (KC_OTHER); +} + // simple animated flash from Rupert Smith (and expanded to be more generic): void zap_animation( int colour, const monsters *mon, bool force ) { @@ -1565,7 +1581,7 @@ int mons_adjust_flavoured( struct monsters *monster, struct bolt &pbolt, } else if (doFlavouredEffects && !one_chance_in(3)) { - poison_monster( monster, YOU_KILL(pbolt.thrower) ); + poison_monster( monster, whose_kill(pbolt) ); } break; @@ -1579,14 +1595,14 @@ int mons_adjust_flavoured( struct monsters *monster, struct bolt &pbolt, // Poison arrow can poison any living thing regardless of // poison resistance. -- bwr if (mons_has_lifeforce(monster)) - poison_monster( monster, YOU_KILL(pbolt.thrower), 2, true ); + poison_monster( monster, whose_kill(pbolt), 2, true ); } hurted /= 2; } else if (doFlavouredEffects) { - poison_monster( monster, YOU_KILL(pbolt.thrower), 4 ); + poison_monster( monster, whose_kill(pbolt), 4 ); } break; @@ -1638,7 +1654,7 @@ int mons_adjust_flavoured( struct monsters *monster, struct bolt &pbolt, return (hurted); if (mons_res_poison( monster ) <= 0) - poison_monster( monster, YOU_KILL(pbolt.thrower) ); + poison_monster( monster, whose_kill(pbolt) ); if (one_chance_in( 3 + 2 * mons_res_negative_energy(monster) )) { @@ -1806,10 +1822,10 @@ bool mass_enchantment( int wh_enchant, int pow, int origin ) continue; } - if (mons_has_ench(monster, wh_enchant)) + if (monster->has_ench(static_cast<enchant_type>(wh_enchant))) continue; - if (mons_add_ench(monster, wh_enchant)) + if (monster->add_ench(static_cast<enchant_type>(wh_enchant))) { if (player_monster_visible( monster )) { @@ -1860,7 +1876,7 @@ int mons_ench_f2(struct monsters *monster, struct bolt &pbolt) { case BEAM_SLOW: /* 0 = slow monster */ // try to remove haste, if monster is hasted - if (mons_del_ench(monster, ENCH_HASTE)) + if (monster->del_ench(ENCH_HASTE)) { if (simple_monster_message(monster, " is no longer moving quickly.")) pbolt.obvious_effect = true; @@ -1869,9 +1885,9 @@ int mons_ench_f2(struct monsters *monster, struct bolt &pbolt) } // not hasted, slow it - if (!mons_has_ench(monster, ENCH_SLOW) + if (!monster->has_ench(ENCH_SLOW) && !mons_is_stationary(monster) - && mons_add_ench(monster, ENCH_SLOW)) + && monster->add_ench(ENCH_SLOW)) { if (!mons_is_paralysed(monster) && simple_monster_message(monster, " seems to slow down.")) @@ -1882,7 +1898,7 @@ int mons_ench_f2(struct monsters *monster, struct bolt &pbolt) return (MON_AFFECTED); case BEAM_HASTE: // 1 = haste - if (mons_del_ench(monster, ENCH_SLOW)) + if (monster->del_ench(ENCH_SLOW)) { if (simple_monster_message(monster, " is no longer moving slowly.")) pbolt.obvious_effect = true; @@ -1891,9 +1907,9 @@ int mons_ench_f2(struct monsters *monster, struct bolt &pbolt) } // not slowed, haste it - if (!mons_has_ench(monster, ENCH_HASTE) + if (!monster->has_ench(ENCH_HASTE) && !mons_is_stationary(monster) - && mons_add_ench(monster, ENCH_HASTE)) + && monster->add_ench(ENCH_HASTE)) { if (!mons_is_paralysed(monster) && simple_monster_message(monster, " seems to speed up.")) @@ -1925,7 +1941,7 @@ int mons_ench_f2(struct monsters *monster, struct bolt &pbolt) return (MON_AFFECTED); case BEAM_CONFUSION: /* 4 = confusion */ - if (mons_add_ench(monster, ENCH_CONFUSION)) + if (monster->add_ench(ENCH_CONFUSION)) { // put in an exception for fungi, plants and other things you won't // notice becoming confused. @@ -1939,8 +1955,8 @@ int mons_ench_f2(struct monsters *monster, struct bolt &pbolt) { const std::string monster_name = ptr_monam(monster, DESC_CAP_THE); - if (!mons_has_ench(monster, ENCH_INVIS) - && mons_add_ench(monster, ENCH_INVIS)) + if (!monster->has_ench(ENCH_INVIS) + && monster->add_ench(ENCH_INVIS)) { // Can't use simple_monster_message here, since it checks // for visibility of the monster (and its now invisible) -- bwr @@ -1957,7 +1973,7 @@ int mons_ench_f2(struct monsters *monster, struct bolt &pbolt) return (MON_AFFECTED); } case BEAM_CHARM: /* 9 = charm */ - if (mons_add_ench(monster, ENCH_CHARM)) + if (monster->add_ench(ENCH_CHARM)) { // break fleeing and suchlike monster->behaviour = BEH_SEEK; @@ -1986,8 +2002,8 @@ static void slow_monster(monsters *mon, int /* degree */) static void beam_paralyses_monster(bolt &pbolt, monsters *monster) { - if (!mons_has_ench(monster, ENCH_PARALYSIS) - && mons_add_ench(monster, ENCH_PARALYSIS)) + if (!monster->has_ench(ENCH_PARALYSIS) + && monster->add_ench(ENCH_PARALYSIS)) { if (simple_monster_message(monster, " suddenly stops moving!")) pbolt.obvious_effect = true; @@ -1998,14 +2014,14 @@ static void beam_paralyses_monster(bolt &pbolt, monsters *monster) // Returns true if the curare killed the monster. bool curare_hits_monster( const bolt &beam, - monsters *monster, - bool fromPlayer, + monsters *monster, + kill_category who, int levels ) { const bool res_poison = mons_res_poison(monster); bool mondied = false; - poison_monster(monster, fromPlayer, levels, false); + poison_monster(monster, who, levels, false); if (!mons_res_asphyx(monster)) { @@ -2030,134 +2046,55 @@ bool curare_hits_monster( const bolt &beam, } // Deities take notice. - if (fromPlayer) + if (who == KC_YOU) did_god_conduct( DID_POISON, 5 + random2(3) ); return (mondied); } // actually poisons a monster (w/ message) -void poison_monster( struct monsters *monster, bool fromPlayer, int levels, +void poison_monster( monsters *monster, + kill_category from_whom, + int levels, bool force ) { - bool yourPoison = false; - int ench = ENCH_NONE; - int old_strength = 0; - - if (monster->type == -1) + if (!monster->alive()) return; if (!force && mons_res_poison(monster) > 0) return; - // who gets the credit if monster dies of poison? - ench = mons_has_ench( monster, ENCH_POISON_I, ENCH_POISON_IV ); - if (ench != ENCH_NONE) - { - old_strength = ench - ENCH_POISON_I; - } - else - { - ench = mons_has_ench(monster, ENCH_YOUR_POISON_I, ENCH_YOUR_POISON_IV); - if (ench != ENCH_NONE) - { - old_strength = ench - ENCH_YOUR_POISON_I; - yourPoison = true; - } - } - - // delete old poison - mons_del_ench( monster, ENCH_POISON_I, ENCH_POISON_IV, true ); - mons_del_ench( monster, ENCH_YOUR_POISON_I, ENCH_YOUR_POISON_IV, true ); - - // Calculate new strength: - int new_strength = old_strength + levels; - if (new_strength > 3) - new_strength = 3; - - // now, if player poisons the monster at ANY TIME, they should - // get credit for the kill if the monster dies from poison. This - // really isn't that abusable -- GDL. - if (fromPlayer || yourPoison) - ench = ENCH_YOUR_POISON_I + new_strength; - else - ench = ENCH_POISON_I + new_strength; + const mon_enchant old_pois = monster->get_ench(ENCH_POISON); + monster->add_ench( mon_enchant(ENCH_POISON, levels, from_whom) ); + const mon_enchant new_pois = monster->get_ench(ENCH_POISON); // actually do the poisoning // note: order important here - if (mons_add_ench( monster, ench ) && new_strength > old_strength) + if (new_pois.degree > old_pois.degree) { simple_monster_message( monster, - (old_strength == 0) ? " looks ill." - : " looks even sicker." ); + !old_pois.degree? " looks ill." + : " looks even sicker." ); } // finally, take care of deity preferences - if (fromPlayer) + if (from_whom == KC_YOU) did_god_conduct( DID_POISON, 5 + random2(3) ); } // end poison_monster() // actually napalms a monster (w/ message) -void sticky_flame_monster( int mn, bool fromPlayer, int levels ) +void sticky_flame_monster( int mn, kill_category who, int levels ) { - bool yourFlame = fromPlayer; - int currentFlame; - int currentStrength = 0; + monsters *monster = &menv[mn]; - struct monsters *monster = &menv[mn]; - - if (monster->type == -1) + if (!monster->alive()) return; if (mons_res_fire(monster) > 0) return; - // who gets the credit if monster dies of napalm? - currentFlame = mons_has_ench( monster, ENCH_STICKY_FLAME_I, - ENCH_STICKY_FLAME_IV ); - - if (currentFlame != ENCH_NONE) - { - currentStrength = currentFlame - ENCH_STICKY_FLAME_I; - yourFlame = false; - } - else - { - currentFlame = mons_has_ench( monster, ENCH_YOUR_STICKY_FLAME_I, - ENCH_YOUR_STICKY_FLAME_IV ); - - if (currentFlame != ENCH_NONE) - { - currentStrength = currentFlame - ENCH_YOUR_STICKY_FLAME_I; - yourFlame = true; - } - else - currentStrength = -1; // no flame yet! - } - - // delete old flame - mons_del_ench( monster, ENCH_STICKY_FLAME_I, ENCH_STICKY_FLAME_IV, true ); - mons_del_ench( monster, ENCH_YOUR_STICKY_FLAME_I, ENCH_YOUR_STICKY_FLAME_IV, - true ); - - // increase sticky flame strength, cap at 3 (level is 0..3) - currentStrength += levels; - - if (currentStrength > 3) - currentStrength = 3; - - // now, if player flames the monster at ANY TIME, they should - // get credit for the kill if the monster dies from napalm. This - // really isn't that abusable -- GDL. - if (fromPlayer || yourFlame) - currentStrength += ENCH_YOUR_STICKY_FLAME_I; - else - currentStrength += ENCH_STICKY_FLAME_I; - - // actually do flame - if (mons_add_ench( monster, currentStrength )) + if (monster->add_ench(mon_enchant(ENCH_STICKY_FLAME, levels, who))) simple_monster_message(monster, " is covered in liquid fire!"); - } // end sticky_flame_monster /* @@ -2229,7 +2166,7 @@ bool check_line_of_sight( int sx, int sy, int tx, int ty ) */ void mimic_alert(monsters *mimic) { - if (mons_has_ench( mimic, ENCH_TP_I, ENCH_TP_IV )) + if (mimic->has_ench(ENCH_TP)) return; monster_teleport( mimic, !one_chance_in(3) ); @@ -2492,7 +2429,7 @@ int affect(struct bolt &beam, int x, int y) // if there is a monster at this location, affect it // submerged monsters aren't really there -- bwr int mid = mgrd[x][y]; - if (mid != NON_MONSTER && !mons_has_ench( &menv[mid], ENCH_SUBMERGED )) + if (mid != NON_MONSTER && !menv[mid].has_ench( ENCH_SUBMERGED )) { if (!beam.is_big_cloud && (!beam.is_explosion || beam.in_explosion_phase)) @@ -3381,7 +3318,7 @@ static int affect_monster(struct bolt &beam, struct monsters *mon) if (beam.is_tracer) { // check can see other monster - if (!beam.can_see_invis && mons_has_ench(&menv[tid], ENCH_INVIS)) + if (!beam.can_see_invis && menv[tid].has_ench(ENCH_INVIS)) { // can't see this monster, ignore it return 0; @@ -3482,7 +3419,7 @@ static int affect_monster(struct bolt &beam, struct monsters *mon) // BEGIN non-enchantment (could still be tracer) - if (mons_has_ench( mon, ENCH_SUBMERGED ) && !beam.aimed_at_feet) + if (mon->has_ench(ENCH_SUBMERGED) && !beam.aimed_at_feet) return (0); // missed me! // we need to know how much the monster _would_ be hurt by this, before @@ -3638,7 +3575,7 @@ static int affect_monster(struct bolt &beam, struct monsters *mon) if (levels > 4) levels = 4; - sticky_flame_monster( tid, YOU_KILL(beam.thrower), levels ); + sticky_flame_monster( tid, whose_kill(beam), levels ); } @@ -3652,18 +3589,18 @@ static int affect_monster(struct bolt &beam, struct monsters *mon) if (beam.ench_power == AUTOMATIC_HIT && random2(100) < 90 - (3 * mon->ac)) { - poison_monster( mon, YOU_KILL(beam.thrower), 2 ); + poison_monster( mon, whose_kill(beam), 2 ); } else if (random2(hurt_final) - random2(mon->ac) > 0) { - poison_monster( mon, YOU_KILL(beam.thrower) ); + poison_monster( mon, whose_kill(beam) ); } } bool wake_mimic = true; if (beam.name.find("curare") != std::string::npos) { - if (curare_hits_monster( beam, mon, YOU_KILL(beam.thrower), 2 )) + if (curare_hits_monster( beam, mon, whose_kill(beam), 2 )) wake_mimic = false; } @@ -3863,7 +3800,7 @@ static int affect_monster_enchantment(struct bolt &beam, struct monsters *mon) if (beam.flavour == BEAM_SLEEP) { - if (mons_has_ench( mon, ENCH_SLEEP_WARY )) // slept recently + if (mon->has_ench(ENCH_SLEEP_WARY)) // slept recently return (MON_RESIST); if (mons_holiness(mon) != MH_NATURAL) // no unnatural @@ -3873,7 +3810,7 @@ static int affect_monster_enchantment(struct bolt &beam, struct monsters *mon) beam.obvious_effect = true; mon->behaviour = BEH_SLEEP; - mons_add_ench( mon, ENCH_SLEEP_WARY ); + mon->add_ench(ENCH_SLEEP_WARY); return (MON_AFFECTED); } diff --git a/crawl-ref/source/beam.h b/crawl-ref/source/beam.h index f95477fb29..87930575de 100644 --- a/crawl-ref/source/beam.h +++ b/crawl-ref/source/beam.h @@ -66,8 +66,8 @@ int mons_ench_f2( struct monsters *monster, struct bolt &pbolt ); /* *********************************************************************** * called from: fight - monstuff - spells2 * *********************************************************************** */ -void poison_monster( struct monsters *monster, bool fromPlayer, int levels = 1, - bool force = false ); +void poison_monster( struct monsters *monster, kill_category who, + int levels = 1, bool force = false ); /* *********************************************************************** diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc index 80da858529..34e4f13530 100644 --- a/crawl-ref/source/debug.cc +++ b/crawl-ref/source/debug.cc @@ -878,34 +878,11 @@ void tweak_object(void) //--------------------------------------------------------------- #if DEBUG_DIAGNOSTICS -static const char *enchant_names[] = -{ - "None", - "Slow", "Haste", "*BUG-3*", "Fear", "Conf", "Invis", - "YPois-1", "YPois-2", "YPois-3", "YPois-4", - "YShug-1", "YShug-2", "YShug-3", "YShug-4", - "YRot-1", "YRot-2", "YRot-3", "YRot-4", - "Summon", "Abj-1", "Abj-2", "Abj-3", "Abj-4", "Abj-5", "Abj-6", - "Corona-1", "Corona-2", "Corona-3", "Corona-4", - "Charm", "YSticky-1", "YSticky-2", "YSticky-3", "YSticky-4", - "*BUG-35*", "*BUG-36*", "*BUG-37*", - "GlowShapeshifter", "Shapeshifter", - "Tele-1", "Tele-2", "Tele-3", "Tele-4", - "*BUG-44*", "*BUG-45*", "*BUG-46*", "*BUG-47*", "*BUG-48*", "*BUG-49*", - "*BUG-50*", "*BUG-51*", "*BUG-52*", "*BUG-53*", "*BUG-54*", "*BUG-55*", - "*BUG-56*", - "Pois-1", "Pois-2", "Pois-3", "Pois-4", - "Sticky-1", "Sticky-2", "Sticky-3", "Sticky-4", - "OldAbj-1", "OldAbj-2", "OldAbj-3", "OldAbj-4", "OldAbj-5", "OldAbj-6", - "OldCreatedFriendly", "SleepWary", "Submerged", "Short Lived", - "*BUG-too big*" -}; - void stethoscope(int mwh) { struct dist stth; int steth_x, steth_y; - int i, j; + int i; if (mwh != RANDOM_MONSTER) i = mwh; @@ -1012,25 +989,10 @@ void stethoscope(int mwh) mpr( info, MSGCH_DIAGNOSTICS ); - // print enchantments - strncpy( info, "ench: ", INFO_SIZE ); - for (j = 0; j < 6; j++) - { - if (menv[i].enchantment[j] >= NUM_ENCHANTMENTS) - strncat( info, enchant_names[ NUM_ENCHANTMENTS ], INFO_SIZE ); - else - strncat( info, enchant_names[ menv[i].enchantment[j] ], INFO_SIZE ); - - if (strlen( info ) <= 70) - strncat( info, " ", INFO_SIZE ); - else if (j < 5) - { - mpr( info, MSGCH_DIAGNOSTICS ); - strncpy( info, "ench: ", INFO_SIZE ); - } - } - - mpr( info, MSGCH_DIAGNOSTICS ); + mprf(MSGCH_DIAGNOSTICS, "ench: %s", + comma_separated_line(menv[i].enchantments.begin(), + menv[i].enchantments.end(), + ", ").c_str()); if (menv[i].type == MONS_PLAYER_GHOST || menv[i].type == MONS_PANDEMONIUM_DEMON) diff --git a/crawl-ref/source/decks.cc b/crawl-ref/source/decks.cc index a76835a0f4..deb8b1629c 100644 --- a/crawl-ref/source/decks.cc +++ b/crawl-ref/source/decks.cc @@ -323,9 +323,9 @@ static void cards(unsigned char which_card) case CARD_BUTTERFLY: mpr("You have drawn the Butterfly."); - summ_dur = ENCH_ABJ_I + random2(3) + you.skills[SK_EVOCATIONS] / 2; - if (summ_dur > ENCH_ABJ_VI) - summ_dur = ENCH_ABJ_VI; + summ_dur = 1 + random2(3) + you.skills[SK_EVOCATIONS] / 2; + if (summ_dur > 6) + summ_dur = 6; if (create_monster( MONS_BUTTERFLY, summ_dur, BEH_FRIENDLY, you.x_pos, you.y_pos, MHITYOU, 250 ) != -1) @@ -545,9 +545,7 @@ static void cards(unsigned char which_card) case CARD_DEMON_LESSER: mpr("On the card is a picture of a little demon."); - summ_dur = ENCH_ABJ_I + random2(3) + you.skills[SK_EVOCATIONS] / 3; - if (summ_dur > ENCH_ABJ_VI) - summ_dur = ENCH_ABJ_VI; + summ_dur = cap_int(1 + random2(3) + you.skills[SK_EVOCATIONS] / 3, 6); if (create_monster( summon_any_demon( DEMON_LESSER ), summ_dur, BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target, @@ -560,9 +558,7 @@ static void cards(unsigned char which_card) case CARD_DEMON_COMMON: mpr("On the card is a picture of a demon."); - summ_dur = ENCH_ABJ_I + random2(3) + you.skills[SK_EVOCATIONS] / 4; - if (summ_dur > ENCH_ABJ_VI) - summ_dur = ENCH_ABJ_VI; + summ_dur = cap_int(1 + random2(3) + you.skills[SK_EVOCATIONS] / 4, 6); if (create_monster( summon_any_demon( DEMON_COMMON ), summ_dur, BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target, @@ -581,7 +577,7 @@ static void cards(unsigned char which_card) if (summ_beh == BEH_CHARMED) mpr( "You don't feel so good about this..." ); - if (create_monster( summon_any_demon( DEMON_GREATER ), ENCH_ABJ_V, + if (create_monster( summon_any_demon( DEMON_GREATER ), 5, summ_beh, you.x_pos, you.y_pos, you.pet_target, 250 ) != -1) { @@ -598,7 +594,7 @@ static void cards(unsigned char which_card) for (loopy = 0; loopy < summ_num; loopy++) { - if (create_monster( summon_any_demon( DEMON_LESSER ), ENCH_ABJ_VI, + if (create_monster( summon_any_demon( DEMON_LESSER ), 6, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250 ) != -1) { @@ -613,10 +609,7 @@ static void cards(unsigned char which_card) case CARD_YAK: mpr("On the card is a picture of a huge shaggy yak."); - summ_dur = ENCH_ABJ_II + you.skills[SK_EVOCATIONS] / 2; - if (summ_dur > ENCH_ABJ_VI) - summ_dur = ENCH_ABJ_VI; - + summ_dur = cap_int(2 + you.skills[SK_EVOCATIONS] / 2, 6); if (create_monster( MONS_DEATH_YAK, summ_dur, BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target, 250 ) != -1) { @@ -627,10 +620,7 @@ static void cards(unsigned char which_card) case CARD_FIEND: mpr("On the card is a picture of a huge scaly devil."); - summ_dur = ENCH_ABJ_II + you.skills[SK_EVOCATIONS] / 6; - if (summ_dur > ENCH_ABJ_VI) - summ_dur = ENCH_ABJ_VI; - + summ_dur = cap_int(2 + you.skills[SK_EVOCATIONS] / 6, 6); if (create_monster( MONS_FIEND, summ_dur, BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target, 250 ) != -1) { @@ -641,10 +631,7 @@ static void cards(unsigned char which_card) case CARD_DRAGON: mpr("On the card is a picture of a huge scaly dragon."); - summ_dur = ENCH_ABJ_III + you.skills[SK_EVOCATIONS] / 6; - if (summ_dur > ENCH_ABJ_VI) - summ_dur = ENCH_ABJ_VI; - + summ_dur = cap_int(3 + you.skills[SK_EVOCATIONS] / 6, 6); if (create_monster( (coinflip() ? MONS_DRAGON : MONS_ICE_DRAGON), summ_dur, BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target, 250 ) != -1) @@ -656,10 +643,7 @@ static void cards(unsigned char which_card) case CARD_GOLEM: mpr("On the card is a picture of a statue."); - summ_dur = ENCH_ABJ_II + you.skills[SK_EVOCATIONS] / 4; - if (summ_dur > ENCH_ABJ_VI) - summ_dur = ENCH_ABJ_VI; - + summ_dur = cap_int(2 + you.skills[SK_EVOCATIONS] / 4, 6); if (create_monster( MONS_CLAY_GOLEM + random2(6), summ_dur, BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target, 250 ) != -1) @@ -671,10 +655,7 @@ static void cards(unsigned char which_card) case CARD_THING_FUGLY: mpr("On the card is a picture of a very ugly thing."); - summ_dur = ENCH_ABJ_II + you.skills[SK_EVOCATIONS] / 4; - if (summ_dur > ENCH_ABJ_VI) - summ_dur = ENCH_ABJ_VI; - + summ_dur = cap_int(2 + you.skills[SK_EVOCATIONS] / 4, 6); if (create_monster( MONS_VERY_UGLY_THING, summ_dur, BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target, 250 ) != -1) { @@ -699,10 +680,7 @@ static void cards(unsigned char which_card) else mpr("On the card is a picture of a hideous abomination."); - summ_dur = ENCH_ABJ_II + you.skills[SK_EVOCATIONS] / 4; - if (summ_dur > ENCH_ABJ_VI) - summ_dur = ENCH_ABJ_VI; - + summ_dur = cap_int(2 + you.skills[SK_EVOCATIONS] / 4, 6); if (create_monster( MONS_UNSEEN_HORROR, summ_dur, BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target, 250 ) != -1) { diff --git a/crawl-ref/source/defines.h b/crawl-ref/source/defines.h index 9f1a642503..2a9c8d5aca 100644 --- a/crawl-ref/source/defines.h +++ b/crawl-ref/source/defines.h @@ -140,6 +140,9 @@ // lowest grid value which can be seen through #define MINSEE 11 +// Can be passed to monster_die to indicate that a friendly did the killing. +#define ANON_FRIENDLY_MONSTER -1 + // This value is used to make test_hit checks always succeed #define AUTOMATIC_HIT 1500 diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc index fe451caea1..bff0ca3e99 100644 --- a/crawl-ref/source/describe.cc +++ b/crawl-ref/source/describe.cc @@ -6072,7 +6072,7 @@ void describe_monsters(int class_described, unsigned char which_mons) break; case MONS_PSYCHE: - description += "A fair-haired magess."; + description += "A fair-haired mage."; break; case MONS_DONALD: @@ -6160,7 +6160,7 @@ void describe_monsters(int class_described, unsigned char which_mons) break; case MONS_EROLCHA: - description += "An especially cunning ogre magess."; + description += "An especially cunning ogre mage."; break; case MONS_URUG: diff --git a/crawl-ref/source/direct.cc b/crawl-ref/source/direct.cc index 299260289b..6cbc6a4120 100644 --- a/crawl-ref/source/direct.cc +++ b/crawl-ref/source/direct.cc @@ -1382,6 +1382,54 @@ std::string feature_description(int mx, int my) return (desc); } +static void describe_mons_enchantment(const monsters &mons, + const mon_enchant &ench, + bool paralysed) +{ + // Suppress silly-looking combinations, even if they're + // internally valid. + if (paralysed && (ench.ench == ENCH_SLOW || ench.ench == ENCH_HASTE)) + return; + + strcpy(info, mons_pronoun(mons.type, PRONOUN_CAP)); + + switch (ench.ench) + { + case ENCH_POISON: + strcat(info, " is poisoned."); + break; + case ENCH_ROT: + strcat(info, " is rotting away."); //jmf: "covered in sores"? + break; + case ENCH_BACKLIGHT: + strcat(info, " is softly glowing."); + break; + case ENCH_SLOW: + strcat(info, " is moving slowly."); + break; + case ENCH_HASTE: + strcat(info, " is moving very quickly."); + break; + case ENCH_CONFUSION: + strcat(info, " appears to be bewildered and confused."); + break; + case ENCH_INVIS: + strcat(info, " is slightly transparent."); + break; + case ENCH_CHARM: + strcat(info, " is in your thrall."); + break; + case ENCH_STICKY_FLAME: + strcat(info, " is covered in liquid flames."); + break; + default: + info[0] = 0; + break; + } // end switch + if (info[0]) + mpr(info); +} + static void describe_cell(int mx, int my) { char str_pass[ ITEMNAME_SIZE ]; @@ -1484,62 +1532,10 @@ static void describe_cell(int mx, int my) if (paralysed) mprf("%s is paralysed.", mons_pronoun(menv[i].type, PRONOUN_CAP)); - for (int p = 0; p < NUM_MON_ENCHANTS; p++) + for (mon_enchant_list::const_iterator e = menv[i].enchantments.begin(); + e != menv[i].enchantments.end(); ++e) { - const unsigned ench = menv[i].enchantment[p]; - - // Suppress silly-looking combinations, even if they're - // internally valid. - if (paralysed && (ench == ENCH_SLOW || ench == ENCH_HASTE)) - continue; - - strcpy(info, mons_pronoun(menv[i].type, PRONOUN_CAP)); - - switch (ench) - { - case ENCH_YOUR_ROT_I: - case ENCH_YOUR_ROT_II: - case ENCH_YOUR_ROT_III: - case ENCH_YOUR_ROT_IV: - strcat(info, " is rotting away."); //jmf: "covered in sores"? - break; - case ENCH_BACKLIGHT_I: - case ENCH_BACKLIGHT_II: - case ENCH_BACKLIGHT_III: - case ENCH_BACKLIGHT_IV: - strcat(info, " is softly glowing."); - break; - case ENCH_SLOW: - strcat(info, " is moving slowly."); - break; - case ENCH_HASTE: - strcat(info, " is moving very quickly."); - break; - case ENCH_CONFUSION: - strcat(info, " appears to be bewildered and confused."); - break; - case ENCH_INVIS: - strcat(info, " is slightly transparent."); - break; - case ENCH_CHARM: - strcat(info, " is in your thrall."); - break; - case ENCH_YOUR_STICKY_FLAME_I: - case ENCH_YOUR_STICKY_FLAME_II: - case ENCH_YOUR_STICKY_FLAME_III: - case ENCH_YOUR_STICKY_FLAME_IV: - case ENCH_STICKY_FLAME_I: - case ENCH_STICKY_FLAME_II: - case ENCH_STICKY_FLAME_III: - case ENCH_STICKY_FLAME_IV: - strcat(info, " is covered in liquid flames."); - break; - default: - info[0] = 0; - break; - } // end switch - if (info[0]) - mpr(info); + describe_mons_enchantment(menv[i], *e, paralysed); } #if DEBUG_DIAGNOSTICS diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h index d85a07b8ef..38c65184d6 100644 --- a/crawl-ref/source/enum.h +++ b/crawl-ref/source/enum.h @@ -1174,64 +1174,25 @@ enum enchant_type { ENCH_NONE = 0, // 0 ENCH_SLOW, - ENCH_HASTE, // 2 - ENCH_FEAR = 4, // 4 - ENCH_CONFUSION, // 5 - ENCH_INVIS, - ENCH_YOUR_POISON_I, - ENCH_YOUR_POISON_II, - ENCH_YOUR_POISON_III, - ENCH_YOUR_POISON_IV, // 10 - ENCH_BERSERK_I, - ENCH_BERSERK_II, - ENCH_BERSERK_III, - ENCH_BERSERK_IV, - ENCH_YOUR_ROT_I, // 15 //jmf: rotting effect for monsters - ENCH_YOUR_ROT_II, - ENCH_YOUR_ROT_III, - ENCH_YOUR_ROT_IV, - ENCH_SUMMON = 19, // 19 - ENCH_ABJ_I, // 20 - ENCH_ABJ_II, - ENCH_ABJ_III, - ENCH_ABJ_IV, - ENCH_ABJ_V, - ENCH_ABJ_VI, // 25 - ENCH_BACKLIGHT_I, //jmf: backlight for Corona spell - ENCH_BACKLIGHT_II, - ENCH_BACKLIGHT_III, - ENCH_BACKLIGHT_IV, - ENCH_CHARM = 30, // 30 - ENCH_YOUR_STICKY_FLAME_I, - ENCH_YOUR_STICKY_FLAME_II, - ENCH_YOUR_STICKY_FLAME_III, - ENCH_YOUR_STICKY_FLAME_IV, // 34 - ENCH_GLOWING_SHAPESHIFTER = 38, // 38 - ENCH_SHAPESHIFTER, - ENCH_TP_I, // 40 - ENCH_TP_II, - ENCH_TP_III, - ENCH_TP_IV, // 43 - ENCH_POISON_I = 57, // 57 - ENCH_POISON_II, - ENCH_POISON_III, - ENCH_POISON_IV, // 60 - ENCH_STICKY_FLAME_I, - ENCH_STICKY_FLAME_II, - ENCH_STICKY_FLAME_III, - ENCH_STICKY_FLAME_IV, - ENCH_FRIEND_ABJ_I, // no longer used - ENCH_FRIEND_ABJ_II, // no longer used - ENCH_FRIEND_ABJ_III, // no longer used - ENCH_FRIEND_ABJ_IV, // no longer used - ENCH_FRIEND_ABJ_V, // no longer used - ENCH_FRIEND_ABJ_VI, // no longer used - ENCH_CREATED_FRIENDLY, // no longer used + ENCH_HASTE, + ENCH_FEAR, + ENCH_CONFUSION, + ENCH_INVIS, // 5 + ENCH_POISON, + ENCH_BERSERK, + ENCH_ROT, + ENCH_SUMMON, + ENCH_ABJ, // 10 + ENCH_BACKLIGHT, + ENCH_CHARM, + ENCH_STICKY_FLAME, + ENCH_GLOWING_SHAPESHIFTER, + ENCH_SHAPESHIFTER, // 15 + ENCH_TP, ENCH_SLEEP_WARY, - ENCH_SUBMERGED, // 73 (includes air elementals in air) - ENCH_SHORT_LIVED, // 74 for ball lightning - - ENCH_PARALYSIS, + ENCH_SUBMERGED, + ENCH_SHORT_LIVED, + ENCH_PARALYSIS, // 20 NUM_ENCHANTMENTS }; @@ -1652,6 +1613,7 @@ enum kill_method_type NUM_KILLBY }; +// This order is *critical*. Don't mess with it (see mon_enchant) enum kill_category { KC_YOU, diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h index 9793c5cc34..0b50040f56 100644 --- a/crawl-ref/source/externs.h +++ b/crawl-ref/source/externs.h @@ -20,6 +20,7 @@ #include <list> #include <string> #include <map> +#include <set> #include <memory> #include <time.h> @@ -108,6 +109,7 @@ public: virtual int id() const = 0; virtual actor_type atype() const = 0; + virtual kill_category kill_alignment() const = 0; virtual god_type deity() const = 0; virtual bool alive() const = 0; @@ -704,6 +706,8 @@ public: bool is_levitating() const; bool cannot_speak() const; + kill_category kill_alignment() const; + bool has_spell(int spell) const; size_type transform_size(int psize = PSIZE_TORSO) const; @@ -821,15 +825,40 @@ class level_id; struct mon_enchant { enchant_type ench; - kill_category who; // Who set this enchantment? int degree; + kill_category who; // Who set this enchantment? + + mon_enchant(enchant_type e = ENCH_NONE, int deg = 0, + kill_category whose = KC_OTHER) + : ench(e), degree(deg), who(whose) + { + } + + int killer() const; + int kill_agent() const; + + operator std::string () const; + const char *kill_category_desc(kill_category) const; + void merge_killer(kill_category who); + void cap_degree(); - mon_enchant(enchant_type e, int deg = 1, kill_category whose = KC_OTHER) - : ench(e), who(whose), degree(deg) + bool operator < (const mon_enchant &other) const { + return (ench < other.ench); } + + bool operator == (const mon_enchant &other) const + { + // NOTE: This does *not* check who/degree. + return (ench == other.ench); + } + + mon_enchant &operator += (const mon_enchant &other); + mon_enchant operator + (const mon_enchant &other) const; }; +typedef std::set<mon_enchant> mon_enchant_list; + class monsters : public actor { public: @@ -856,7 +885,7 @@ public: unsigned char attitude; // from MONS_ATTITUDE unsigned int behaviour; unsigned int foe; - FixedVector<unsigned int, NUM_MON_ENCHANTS> enchantment; + mon_enchant_list enchantments; unsigned long flags; // bitfield of boolean flags unsigned int number; // #heads (hydra), etc. @@ -870,6 +899,23 @@ public: std::auto_ptr<ghost_demon> ghost; // Ghost information. public: + kill_category kill_alignment() const; + + bool has_ench(enchant_type ench, + enchant_type ench2 = ENCH_NONE) const; + mon_enchant get_ench(enchant_type ench, + enchant_type ench2 = ENCH_NONE) const; + bool add_ench(const mon_enchant &); + void update_ench(const mon_enchant &); + bool del_ench(enchant_type ench, bool quiet = false); + + void lose_ench_levels(const mon_enchant &e, int levels); + void remove_enchantment_effect(const mon_enchant &me, bool quiet = false); + void apply_enchantments(int speed); + void apply_enchantment(mon_enchant me, int speed); + + void timeout_enchantments(int levels); + bool needs_transit() const; void set_transit(level_id destination); bool find_place_to_live(bool near_player = false); diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc index 14257e3861..201bc02a90 100644 --- a/crawl-ref/source/fight.cc +++ b/crawl-ref/source/fight.cc @@ -823,7 +823,7 @@ bool melee_attack::player_apply_aux_unarmed() attack_strength_punctuation().c_str()); if (damage_brand == SPWPN_VENOM && coinflip()) - poison_monster( def, true ); + poison_monster( def, KC_YOU ); if (mons_holiness(def) == MH_HOLY) did_god_conduct(DID_KILL_ANGEL, 1); @@ -1870,7 +1870,7 @@ void melee_attack::player_apply_staff_damage() { // Poison monster message needs to arrive after hit message. emit_nodmg_hit_message(); - poison_monster(def, true); + poison_monster(def, KC_YOU); } break; } @@ -2120,7 +2120,7 @@ int melee_attack::player_to_hit(bool random_factor) // Check for backlight (Corona). if (defender && defender->atype() == ACT_MONSTER - && mons_has_ench(def, ENCH_BACKLIGHT_I, ENCH_BACKLIGHT_IV)) + && def->has_ench(ENCH_BACKLIGHT)) { your_to_hit += 2 + random2(8); } @@ -2141,7 +2141,7 @@ void melee_attack::player_stab_check() } // confused (but not perma-confused) - if (mons_has_ench(def, ENCH_CONFUSION) + if (def->has_ench(ENCH_CONFUSION) && !mons_class_flag(def->type, M_CONFUSED)) { stab_attempt = true; diff --git a/crawl-ref/source/it_use3.cc b/crawl-ref/source/it_use3.cc index a7b96a93ca..7ae760b26f 100644 --- a/crawl-ref/source/it_use3.cc +++ b/crawl-ref/source/it_use3.cc @@ -189,7 +189,7 @@ void special_wielded(void) if (random2(8) <= player_spec_death()) { did_god_conduct( DID_NECROMANCY, 1 ); - create_monster( MONS_SHADOW, ENCH_ABJ_II, BEH_FRIENDLY, + create_monster( MONS_SHADOW, 2, BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target, 250 ); } @@ -404,7 +404,7 @@ bool evoke_wielded( void ) : MONS_HELLION + random2(10)); bool good_summon = (create_monster( spell_casted, - ENCH_ABJ_VI, BEH_HOSTILE, + 6, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250) != -1); @@ -630,7 +630,7 @@ bool evoke_wielded( void ) else { mpr("You produce a hideous howling noise!"); - int midx = create_monster( MONS_BEAST, ENCH_ABJ_IV, + int midx = create_monster( MONS_BEAST, 4, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250 ); // avoid scumming; also prevents it from showing up on notes @@ -725,7 +725,7 @@ static bool efreet_flask(void) mpr("You open the flask..."); - const int efreet = create_monster( MONS_EFREET, ENCH_ABJ_V, behaviour, + const int efreet = create_monster( MONS_EFREET, 5, behaviour, you.x_pos, you.y_pos, MHITYOU, 250, false, false, true ); if (efreet != -1) @@ -923,7 +923,7 @@ void tome_of_power(char sc_read_2) case 10: - if (create_monster( MONS_ABOMINATION_SMALL, ENCH_ABJ_VI, BEH_HOSTILE, + if (create_monster( MONS_ABOMINATION_SMALL, 6, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250 ) != -1) { mpr("A horrible Thing appears!"); @@ -1023,7 +1023,7 @@ static bool box_of_beasts(void) int beh = (one_chance_in(you.skills[SK_EVOCATIONS] + 5) ? BEH_HOSTILE : BEH_FRIENDLY); - if (create_monster( beasty, ENCH_ABJ_II + random2(4), beh, + if (create_monster( beasty, 2 + random2(4), beh, you.x_pos, you.y_pos, MHITYOU, 250 ) != -1) { mpr("...and something leaps out!"); diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc index 3e7d167c8a..c26b4ea707 100644 --- a/crawl-ref/source/item_use.cc +++ b/crawl-ref/source/item_use.cc @@ -3343,7 +3343,7 @@ void read_scroll(void) break; case SCR_SUMMONING: - if (create_monster( MONS_ABOMINATION_SMALL, ENCH_ABJ_VI, BEH_FRIENDLY, + if (create_monster( MONS_ABOMINATION_SMALL, 6, BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target, 250 ) != -1) { mpr("A horrible Thing appears!"); diff --git a/crawl-ref/source/items.cc b/crawl-ref/source/items.cc index 98be971353..734bec9fd6 100644 --- a/crawl-ref/source/items.cc +++ b/crawl-ref/source/items.cc @@ -2079,155 +2079,6 @@ void update_corpses(double elapsedTime) } } -static bool remove_enchant_levels( struct monsters *mon, int slot, int min, - int levels ) -{ - const int new_level = mon->enchantment[slot] - levels; - - if (new_level < min) - { - mons_del_ench( mon, - mon->enchantment[slot], mon->enchantment[slot], true ); - return (true); - } - else - { - mon->enchantment[slot] = new_level; - } - - return (false); -} - -//--------------------------------------------------------------- -// -// update_enchantments -// -// Update a monster's enchantments when the player returns -// to the level. -// -// Management for enchantments... problems with this are the oddities -// (monster dying from poison several thousands of turns later), and -// game balance. -// -// Consider: Poison/Sticky Flame a monster at range and leave, monster -// dies but can't leave level to get to player (implied game balance of -// the delayed damage is that the monster could be a danger before -// it dies). This could be fixed by keeping some monsters active -// off level and allowing them to take stairs (a very serious change). -// -// Compare this to the current abuse where the player gets -// effectively extended duration of these effects (although only -// the actual effects only occur on level, the player can leave -// and heal up without having the effect disappear). -// -// This is a simple compromise between the two... the enchantments -// go away, but the effects don't happen off level. -- bwr -// -//--------------------------------------------------------------- -static void update_enchantments( struct monsters *mon, int levels ) -{ - int i; - - for (i = 0; i < NUM_MON_ENCHANTS; i++) - { - switch (mon->enchantment[i]) - { - case ENCH_YOUR_POISON_I: - case ENCH_YOUR_POISON_II: - case ENCH_YOUR_POISON_III: - case ENCH_YOUR_POISON_IV: - remove_enchant_levels( mon, i, ENCH_YOUR_POISON_I, levels ); - break; - - case ENCH_YOUR_ROT_I: - case ENCH_YOUR_ROT_II: - case ENCH_YOUR_ROT_III: - case ENCH_YOUR_ROT_IV: - remove_enchant_levels( mon, i, ENCH_YOUR_ROT_I, levels ); - break; - - case ENCH_BACKLIGHT_I: - case ENCH_BACKLIGHT_II: - case ENCH_BACKLIGHT_III: - case ENCH_BACKLIGHT_IV: - remove_enchant_levels( mon, i, ENCH_BACKLIGHT_I, levels ); - break; - - case ENCH_YOUR_STICKY_FLAME_I: - case ENCH_YOUR_STICKY_FLAME_II: - case ENCH_YOUR_STICKY_FLAME_III: - case ENCH_YOUR_STICKY_FLAME_IV: - remove_enchant_levels( mon, i, ENCH_YOUR_STICKY_FLAME_I, levels ); - break; - - case ENCH_POISON_I: - case ENCH_POISON_II: - case ENCH_POISON_III: - case ENCH_POISON_IV: - remove_enchant_levels( mon, i, ENCH_POISON_I, levels ); - break; - - case ENCH_STICKY_FLAME_I: - case ENCH_STICKY_FLAME_II: - case ENCH_STICKY_FLAME_III: - case ENCH_STICKY_FLAME_IV: - remove_enchant_levels( mon, i, ENCH_STICKY_FLAME_I, levels ); - break; - - case ENCH_ABJ_I: - case ENCH_ABJ_II: - case ENCH_ABJ_III: - case ENCH_ABJ_IV: - case ENCH_ABJ_V: - case ENCH_ABJ_VI: - if (remove_enchant_levels( mon, i, ENCH_ABJ_I, levels )) - { - // Re-add ABJ_I so that monster_die doesn't try to send the - // monster to the Abyss on KILL_RESET. - mons_add_ench( mon, ENCH_ABJ_I ); - monster_die( mon, KILL_RESET, 0 ); - } - break; - - - case ENCH_SHORT_LIVED: - mons_add_ench( mon, ENCH_ABJ_I ); - monster_die( mon, KILL_RESET, 0 ); - break; - - case ENCH_TP_I: - case ENCH_TP_II: - case ENCH_TP_III: - case ENCH_TP_IV: - monster_teleport( mon, true ); - break; - - case ENCH_CONFUSION: - monster_blink( mon ); - break; - - case ENCH_GLOWING_SHAPESHIFTER: - case ENCH_SHAPESHIFTER: - case ENCH_CREATED_FRIENDLY: - case ENCH_SUBMERGED: - default: - // don't touch these - break; - - case ENCH_SLOW: - case ENCH_HASTE: - case ENCH_FEAR: - case ENCH_INVIS: - case ENCH_CHARM: - case ENCH_SLEEP_WARY: - // delete enchantment (using function to get this done cleanly) - mons_del_ench(mon, mon->enchantment[i], mon->enchantment[i], true); - break; - } - } -} - - //--------------------------------------------------------------- // // update_level @@ -2279,7 +2130,7 @@ void update_level( double elapsedTime ) } if (turns >= 10) - update_enchantments( mon, turns / 10 ); + mon->timeout_enchantments( turns / 10 ); // Don't move water, lava, or stationary monsters around if (monster_habitat( mon->type ) != DNGN_FLOOR diff --git a/crawl-ref/source/libutil.h b/crawl-ref/source/libutil.h index 6baf428aa0..4e5db549b3 100644 --- a/crawl-ref/source/libutil.h +++ b/crawl-ref/source/libutil.h @@ -100,7 +100,8 @@ std::string comma_separated_line(Z start, Z end, { if (i != start) { - if (i + 1 != end) + Z tmp = i; + if (++tmp != end) text += comma; else text += andc; diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc index 9b61ec053c..a7a7a35de6 100644 --- a/crawl-ref/source/mon-util.cc +++ b/crawl-ref/source/mon-util.cc @@ -516,8 +516,8 @@ char mons_see_invis( struct monsters *mon ) // with respect to mon's perception, but doesn't do walls or range. bool mons_monster_visible( struct monsters *mon, struct monsters *targ ) { - if (mons_has_ench(targ, ENCH_SUBMERGED) - || (mons_has_ench(targ, ENCH_INVIS) && !mons_see_invis(mon))) + if (targ->has_ench(ENCH_SUBMERGED) + || (targ->has_ench(ENCH_INVIS) && !mons_see_invis(mon))) { return (false); } @@ -952,7 +952,7 @@ bool mons_has_lifeforce( const monsters *mon ) const int holy = mons_holiness( mon ); return (holy == MH_NATURAL || holy == MH_PLANT); - // && !mons_has_ench( mon, ENCH_PETRIFY )); + // && !mon->has_ench(ENCH_PETRIFY)); } int mons_skeleton(int mc) @@ -1382,8 +1382,7 @@ void define_monster(int index) mons_load_spells( &mons, spells ); // reset monster enchantments - for (int i = 0; i < NUM_MON_ENCHANTS; i++) - mons.enchantment[i] = ENCH_NONE; + mons.enchantments.clear(); } // end define_monster() std::string str_monam(const monsters *mon, description_level_type desc, @@ -1695,7 +1694,7 @@ bool mons_aligned(int m1, int m2) else { mon1 = &menv[m1]; - fr1 = (mon1->attitude == ATT_FRIENDLY) || mons_has_ench(mon1, ENCH_CHARM); + fr1 = (mon1->attitude == ATT_FRIENDLY) || mon1->has_ench(ENCH_CHARM); } if (m2 == MHITYOU) @@ -1703,7 +1702,7 @@ bool mons_aligned(int m1, int m2) else { mon2 = &menv[m2]; - fr2 = (mon2->attitude == ATT_FRIENDLY) || mons_has_ench(mon2, ENCH_CHARM); + fr2 = (mon2->attitude == ATT_FRIENDLY) || mon2->has_ench(ENCH_CHARM); } return (fr1 == fr2); @@ -1716,7 +1715,7 @@ bool mons_wields_two_weapons(const monsters *m) bool mons_is_summoned(const monsters *m) { - return (mons_has_ench(m, ENCH_ABJ_I, ENCH_ABJ_VI)); + return (m->has_ench(ENCH_ABJ)); } // Does not check whether the monster can dual-wield - that is the @@ -1741,23 +1740,23 @@ int mons_size(const monsters *m) bool mons_friendly(const monsters *m) { - return (m->attitude == ATT_FRIENDLY || mons_has_ench(m, ENCH_CHARM)); + return (m->attitude == ATT_FRIENDLY || m->has_ench(ENCH_CHARM)); } bool mons_is_submerged( const monsters *mon ) { // FIXME, switch to 4.1's MF_SUBMERGED system which is much cleaner. - return (mons_has_ench(mon, ENCH_SUBMERGED)); + return (mon->has_ench(ENCH_SUBMERGED)); } bool mons_is_paralysed(const monsters *m) { - return (mons_has_ench(m, ENCH_PARALYSIS)); + return (m->has_ench(ENCH_PARALYSIS)); } bool mons_is_confused(const monsters *m) { - return (mons_has_ench(m, ENCH_CONFUSION) && + return (m->has_ench(ENCH_CONFUSION) && !mons_class_flag(m->type, M_CONFUSED)); } @@ -1836,194 +1835,6 @@ bool mons_should_fire(struct bolt &beam) return (false); } -int mons_has_ench(const monsters *mon, unsigned int ench, unsigned int ench2) -{ - // silliness - if (ench == ENCH_NONE) - return (ench); - - if (ench2 == ENCH_NONE) - ench2 = ench; - - for (int p = 0; p < NUM_MON_ENCHANTS; p++) - { - if (mon->enchantment[p] >= ench && mon->enchantment[p] <= ench2) - return (mon->enchantment[p]); - } - - return (ENCH_NONE); -} - -// Returning the deleted enchantment is important! See abjuration. -- bwr -int mons_del_ench( struct monsters *mon, unsigned int ench, unsigned int ench2, - bool quiet ) -{ - unsigned int p; - int ret_val = ENCH_NONE; - - // silliness - if (ench == ENCH_NONE) - return (ENCH_NONE); - - if (ench2 == ENCH_NONE) - ench2 = ench; - - for (p = 0; p < NUM_MON_ENCHANTS; p++) - { - if (mon->enchantment[p] >= ench && mon->enchantment[p] <= ench2) - break; - } - - if (p == NUM_MON_ENCHANTS) - return (ENCH_NONE); - - ret_val = mon->enchantment[p]; - mon->enchantment[p] = ENCH_NONE; - - // check for slow/haste - if (ench == ENCH_HASTE) - { - if (mon->speed >= 100) - mon->speed = 100 + ((mon->speed - 100) / 2); - else - mon->speed /= 2; - } - - if (ench == ENCH_SLOW) - { - if (mon->speed >= 100) - mon->speed = 100 + ((mon->speed - 100) * 2); - else - mon->speed *= 2; - } - - if (ench == ENCH_PARALYSIS) - { - if (!quiet) - simple_monster_message(mon, " is no longer paralysed."); - - behaviour_event(mon, ME_EVAL); - } - - if (ench == ENCH_FEAR) - { - if (!quiet) - simple_monster_message(mon, " seems to regain its courage."); - - // reevaluate behaviour - behaviour_event(mon, ME_EVAL); - } - - if (ench == ENCH_CONFUSION) - { - if (!quiet) - simple_monster_message(mon, " seems less confused."); - - // reevaluate behaviour - behaviour_event(mon, ME_EVAL); - } - - if (ench == ENCH_INVIS) - { - // invisible monsters stay invisible - if (mons_class_flag(mon->type, M_INVIS)) - { - mon->enchantment[p] = ENCH_INVIS; - } - else if (mons_near(mon) && !player_see_invis() - && !mons_has_ench( mon, ENCH_SUBMERGED )) - { - if (!quiet) - { - strcpy( info, ptr_monam( mon, DESC_CAP_A ) ); - strcat( info, " appears!" ); - mpr( info ); - } - seen_monster(mon); - } - } - - if (ench == ENCH_CHARM) - { - if (!quiet) - simple_monster_message(mon, " is no longer charmed."); - - // reevaluate behaviour - behaviour_event(mon, ME_EVAL); - } - - if (ench == ENCH_BACKLIGHT_I) - { - if (!quiet) - simple_monster_message(mon, " stops glowing."); - } - - if (ench == ENCH_STICKY_FLAME_I || ench == ENCH_YOUR_STICKY_FLAME_I) - { - if (!quiet) - simple_monster_message(mon, " stops burning."); - } - - if (ench == ENCH_POISON_I || ench == ENCH_YOUR_POISON_I) - { - if (!quiet) - simple_monster_message(mon, " looks more healthy."); - } - - if (ench == ENCH_YOUR_ROT_I) - { - if (!quiet) - simple_monster_message(mon, " is no longer rotting."); - } - - return (ret_val); -} - -bool mons_add_ench(struct monsters *mon, unsigned int ench) -{ - // silliness - if (ench == ENCH_NONE) - return (false); - - int newspot = -1; - - // don't double-add - for (int p = 0; p < NUM_MON_ENCHANTS; p++) - { - if (mon->enchantment[p] == ench) - return (true); - - if (mon->enchantment[p] == ENCH_NONE && newspot < 0) - newspot = p; - } - - if (newspot < 0) - return (false); - - mon->enchantment[newspot] = ench; -// if ench == ENCH_FEAR //mv: withou this fear & repel undead spell doesn't work - - - // check for slow/haste - if (ench == ENCH_HASTE) - { - if (mon->speed >= 100) - mon->speed = 100 + ((mon->speed - 100) * 2); - else - mon->speed *= 2; - } - - if (ench == ENCH_SLOW) - { - if (mon->speed >= 100) - mon->speed = 100 + ((mon->speed - 100) / 2); - else - mon->speed /= 2; - } - - return (true); -} - // used to determine whether or not a monster should always // fire this spell if selected. If not, we should use a // tracer. @@ -2251,12 +2062,12 @@ bool ms_waste_of_time( struct monsters *mon, int monspell ) switch (monspell) { case MS_HASTE: - if (mons_has_ench( mon, ENCH_HASTE )) + if (mon->has_ench(ENCH_HASTE)) ret = true; break; case MS_INVIS: - if (mons_has_ench( mon, ENCH_INVIS ) || + if (mon->has_ench(ENCH_INVIS) || (mons_friendly(mon) && !player_see_invis(false))) ret = true; break; @@ -2268,7 +2079,7 @@ bool ms_waste_of_time( struct monsters *mon, int monspell ) case MS_TELEPORT: // Monsters aren't smart enough to know when to cancel teleport. - if (mons_has_ench( mon, ENCH_TP_I, ENCH_TP_IV )) + if (mon->has_ench( ENCH_TP )) ret = true; break; @@ -2281,7 +2092,7 @@ bool ms_waste_of_time( struct monsters *mon, int monspell ) } else if (mon->foe != MHITNOT) { - if (mons_has_ench( &menv[mon->foe], ENCH_TP_I, ENCH_TP_IV)) + if (menv[mon->foe].has_ench(ENCH_TP)) return (true); } // intentional fall-through @@ -2576,7 +2387,7 @@ monsters::monsters() : type(-1), hit_points(0), max_hit_points(0), hit_dice(0), ac(0), ev(0), speed(0), speed_increment(0), x(0), y(0), target_x(0), target_y(0), inv(), spells(), attitude(ATT_NEUTRAL), - behaviour(BEH_WANDER), foe(MHITYOU), enchantment(), flags(0L), + behaviour(BEH_WANDER), foe(MHITYOU), enchantments(), flags(0L), number(0), colour(BLACK), foe_memory(0), god(GOD_NO_GOD), ghost() { @@ -2612,7 +2423,7 @@ void monsters::init_with(const monsters &mon) attitude = mon.attitude; behaviour = mon.behaviour; foe = mon.foe; - enchantment = mon.enchantment; + enchantments = mon.enchantments; flags = mon.flags; number = mon.number; colour = mon.colour; @@ -2905,8 +2716,8 @@ void monsters::poison(actor *agent, int amount) // Scale poison down for monsters. if (!(amount /= 2)) amount = 1; - - poison_monster(this, agent->atype() == ACT_PLAYER, amount); + + poison_monster(this, agent->kill_alignment(), amount); } int monsters::skill(skill_type sk, bool) const @@ -3039,7 +2850,7 @@ void monsters::ghost_init() load_spells(MST_GHOST); inv.init(NON_ITEM); - enchantment.init(ENCH_NONE); + enchantments.clear(); find_place_to_live(); } @@ -3119,7 +2930,7 @@ void monsters::reset() { destroy_inventory(); - enchantment.init(ENCH_NONE); + enchantments.clear(); inv.init(NON_ITEM); flags = 0; @@ -3133,6 +2944,7 @@ void monsters::reset() attitude = ATT_HOSTILE; behaviour = BEH_SLEEP; foe = MHITNOT; + number = 0; if (in_bounds(x, y)) mgrd[x][y] = NON_MONSTER; @@ -3146,7 +2958,7 @@ bool monsters::needs_transit() const return ((mons_is_unique(type) || (flags & MF_BANISHED) || (you.level_type == LEVEL_DUNGEON && hit_dice > 8 + random2(25))) - && !mons_has_ench(this, ENCH_ABJ_I, ENCH_ABJ_VI)); + && !mons_is_summoned(this)); } void monsters::set_transit(level_id dest) @@ -3192,3 +3004,628 @@ void monsters::load_spells(int book) } } } + +bool monsters::has_ench(enchant_type ench, + enchant_type ench2) const +{ + if (ench2 == ENCH_NONE) + ench2 = ench; + + for (int i = ench; i <= ench2; ++i) + { + if (enchantments.find( static_cast<enchant_type>(i) ) != + enchantments.end()) + { + return (true); + } + } + return (false); +} + +mon_enchant monsters::get_ench(enchant_type ench1, + enchant_type ench2) const +{ + if (ench2 == ENCH_NONE) + ench2 = ench1; + + for (int e = ench1; e <= ench2; ++e) + { + mon_enchant_list::const_iterator i = + enchantments.find(static_cast<enchant_type>(e)); + if (i != enchantments.end()) + return (*i); + } + + return (mon_enchant()); +} + +void monsters::update_ench(const mon_enchant &ench) +{ + if (ench.ench != ENCH_NONE) + { + mon_enchant_list::iterator i = enchantments.find(ench); + if (i != enchantments.end()) + enchantments.erase(i); + enchantments.insert(ench); + } +} + +bool monsters::add_ench(const mon_enchant &ench) +{ + // silliness + if (ench.ench == ENCH_NONE) + return (false); + + mon_enchant_list::iterator i = enchantments.find(ench); + if (i == enchantments.end()) + enchantments.insert(ench); + else + { + mon_enchant new_ench = *i + ench; + enchantments.erase(i); + enchantments.insert(new_ench); + } + + // check for slow/haste + if (ench.ench == ENCH_HASTE) + { + if (speed >= 100) + speed = 100 + ((speed - 100) * 2); + else + speed *= 2; + } + + if (ench.ench == ENCH_SLOW) + { + if (speed >= 100) + speed = 100 + ((speed - 100) / 2); + else + speed /= 2; + } + + return (true); +} + +bool monsters::del_ench(enchant_type ench, bool quiet) +{ + mon_enchant_list::iterator i = enchantments.find(ench); + if (i == enchantments.end()) + return (false); + + mon_enchant me = *i; + enchantments.erase(i); + + remove_enchantment_effect(me, quiet); + return (true); +} + +void monsters::remove_enchantment_effect(const mon_enchant &me, bool quiet) +{ + switch (me.ench) + { + case ENCH_HASTE: + if (speed >= 100) + speed = 100 + ((speed - 100) / 2); + else + speed /= 2; + break; + + case ENCH_SLOW: + if (speed >= 100) + speed = 100 + ((speed - 100) * 2); + else + speed *= 2; + break; + + case ENCH_PARALYSIS: + if (!quiet) + simple_monster_message(this, " is no longer paralysed."); + + behaviour_event(this, ME_EVAL); + break; + + case ENCH_FEAR: + if (!quiet) + simple_monster_message(this, " seems to regain its courage."); + + // reevaluate behaviour + behaviour_event(this, ME_EVAL); + break; + + case ENCH_CONFUSION: + if (!quiet) + simple_monster_message(this, " seems less confused."); + + // reevaluate behaviour + behaviour_event(this, ME_EVAL); + break; + + case ENCH_INVIS: + // invisible monsters stay invisible + if (mons_class_flag(type, M_INVIS)) + add_ench( mon_enchant(ENCH_INVIS) ); + else if (mons_near(this) && !player_see_invis() + && !has_ench( ENCH_SUBMERGED )) + { + if (!quiet) + mprf("%s appears!", name(DESC_CAP_A).c_str() ); + + seen_monster(this); + } + break; + + case ENCH_CHARM: + if (!quiet) + simple_monster_message(this, " is no longer charmed."); + + // reevaluate behaviour + behaviour_event(this, ME_EVAL); + break; + + case ENCH_BACKLIGHT: + if (!quiet) + simple_monster_message(this, " stops glowing."); + break; + + case ENCH_STICKY_FLAME: + if (!quiet) + simple_monster_message(this, " stops burning."); + break; + + case ENCH_POISON: + if (!quiet) + simple_monster_message(this, " looks more healthy."); + break; + + case ENCH_ROT: + if (!quiet) + simple_monster_message(this, " is no longer rotting."); + break; + + case ENCH_ABJ: + case ENCH_SHORT_LIVED: + add_ench( mon_enchant(ENCH_ABJ) ); + monster_die( this, quiet? KILL_DISMISSED : KILL_RESET, 0 ); + break; + + default: + break; + } +} + +void monsters::lose_ench_levels(const mon_enchant &e, int levels) +{ + if (!levels) + return; + + mon_enchant me(e); + me.degree -= levels; + + if (me.degree < 1) + del_ench(e.ench); + else + update_ench(me); +} + +//--------------------------------------------------------------- +// +// timeout_enchantments +// +// Update a monster's enchantments when the player returns +// to the level. +// +// Management for enchantments... problems with this are the oddities +// (monster dying from poison several thousands of turns later), and +// game balance. +// +// Consider: Poison/Sticky Flame a monster at range and leave, monster +// dies but can't leave level to get to player (implied game balance of +// the delayed damage is that the monster could be a danger before +// it dies). This could be fixed by keeping some monsters active +// off level and allowing them to take stairs (a very serious change). +// +// Compare this to the current abuse where the player gets +// effectively extended duration of these effects (although only +// the actual effects only occur on level, the player can leave +// and heal up without having the effect disappear). +// +// This is a simple compromise between the two... the enchantments +// go away, but the effects don't happen off level. -- bwr +// +//--------------------------------------------------------------- +void monsters::timeout_enchantments(int levels) +{ + for (mon_enchant_list::iterator i = enchantments.begin(); + i != enchantments.end(); ) + { + mon_enchant_list::iterator cur = i++; + + switch (cur->ench) + { + case ENCH_POISON: case ENCH_ROT: case ENCH_BACKLIGHT: + case ENCH_STICKY_FLAME: case ENCH_ABJ: case ENCH_SHORT_LIVED: + case ENCH_SLOW: case ENCH_HASTE: case ENCH_FEAR: + case ENCH_INVIS: case ENCH_CHARM: case ENCH_SLEEP_WARY: + lose_ench_levels(*cur, levels); + break; + + case ENCH_TP: + teleport(true); + break; + + case ENCH_CONFUSION: + blink(); + break; + + default: + break; + } + } +} + +// used to adjust time durations in handle_enchantment() for monster speed +static inline int mod_speed( int val, int speed ) +{ + return (speed ? (val * 10) / speed : val); +} + +void monsters::apply_enchantment(mon_enchant me, int spd) +{ + switch (me.ench) + { + case ENCH_SLOW: + if (random2(250) <= mod_speed( hit_dice + 10, spd )) + del_ench(me.ench); + break; + + case ENCH_HASTE: + if (random2(1000) < mod_speed( 25, spd )) + del_ench(ENCH_HASTE); + break; + + case ENCH_FEAR: + if (random2(150) <= mod_speed( hit_dice + 5, spd )) + del_ench(ENCH_FEAR); + break; + + case ENCH_PARALYSIS: + if (random2(120) < mod_speed( hit_dice + 5, spd )) + del_ench(ENCH_PARALYSIS); + break; + + case ENCH_CONFUSION: + if (random2(120) < mod_speed( hit_dice + 5, spd )) + { + // don't delete perma-confusion + if (!mons_class_flag(type, M_CONFUSED)) + del_ench(ENCH_CONFUSION); + } + break; + + case ENCH_INVIS: + if (random2(1000) < mod_speed( 25, spd )) + { + // don't delete perma-invis + if (!mons_class_flag( type, M_INVIS )) + del_ench(ENCH_INVIS); + } + break; + + case ENCH_SUBMERGED: + { + // not even air elementals unsubmerge into clouds + if (env.cgrid[x][y] != EMPTY_CLOUD) + break; + + // Air elementals are a special case, as their + // submerging in air isn't up to choice. -- bwr + if (type == MONS_AIR_ELEMENTAL) + { + heal_monster( this, 1, one_chance_in(5) ); + + if (one_chance_in(5)) + del_ench(ENCH_SUBMERGED); + + break; + } + + // Now we handle the others: + int grid = grd[x][y]; + + // Badly injured monsters prefer to stay submerged... + // electrical eels and lava snakes have ranged attacks + // and are more likely to surface. -- bwr + if (!monster_can_submerge(type, grid)) + del_ench(ENCH_SUBMERGED); // forced to surface + else if (hit_points <= max_hit_points / 2) + break; + else if (((type == MONS_ELECTRICAL_EEL + || type == MONS_LAVA_SNAKE) + && (random2(1000) < mod_speed( 20, spd ) + || (mons_near(this) + && hit_points == max_hit_points + && !one_chance_in(10)))) + || random2(2000) < mod_speed(10, spd) + || (mons_near(this) + && hit_points == max_hit_points + && !one_chance_in(5))) + { + del_ench(ENCH_SUBMERGED); + } + break; + } + case ENCH_POISON: + { + int poisonval = me.degree; + int dam = (poisonval >= 4) ? 1 : 0; + + if (coinflip()) + dam += roll_dice( 1, poisonval + 1 ); + + if (mons_res_poison(this) < 0) + dam += roll_dice( 2, poisonval ) - 1; + + // We adjust damage for monster speed (since this is applied + // only when the monster moves), and we handle the factional + // part as well (so that speed 30 creatures will take damage). + dam *= 10; + dam = (dam / spd) + ((random2(spd) < (dam % spd)) ? 1 : 0); + + if (dam > 0) + { + hurt_monster( this, dam ); + +#if DEBUG_DIAGNOSTICS + // for debugging, we don't have this silent. + simple_monster_message( this, " takes poison damage.", + MSGCH_DIAGNOSTICS ); + snprintf( info, INFO_SIZE, "poison damage: %d", dam ); + mpr( info, MSGCH_DIAGNOSTICS ); +#endif + + if (hit_points < 1) + { + monster_die(this, me.killer(), me.kill_agent()); + break; + } + } + + // chance to get over poison (1 in 8, modified for speed) + if (random2(1000) < mod_speed( 125, spd )) + lose_ench_levels(me, 1); + break; + } + case ENCH_ROT: + if (hit_points > 1 + && random2(1000) < mod_speed( 333, spd )) + { + hurt_monster(this, 1); + } + + if (random2(1000) < mod_speed( me.degree == 1? 250 : 333, spd )) + lose_ench_levels(me, 1); + + break; + + case ENCH_BACKLIGHT: + if (random2(1000) < mod_speed( me.degree == 1? 100 : 200, spd )) + lose_ench_levels(me, 1); + break; + + // assumption: mons_res_fire has already been checked + case ENCH_STICKY_FLAME: + { + int dam = roll_dice( 2, 4 ) - 1; + + if (mons_res_fire( this ) < 0) + dam += roll_dice( 2, 5 ) - 1; + + // We adjust damage for monster speed (since this is applied + // only when the monster moves), and we handle the factional + // part as well (so that speed 30 creatures will take damage). + dam *= 10; + dam = (dam / spd) + ((random2(spd) < (dam % spd)) ? 1 : 0); + + if (dam > 0) + { + hurt_monster( this, dam ); + simple_monster_message(this, " burns!"); + +#if DEBUG_DIAGNOSTICS + mprf( MSGCH_DIAGNOSTICS, "sticky flame damage: %d", dam ); +#endif + + if (hit_points < 1) + { + monster_die(this, me.killer(), me.kill_agent()); + break; + } + } + + // chance to get over sticky flame (1 in 5, modified for speed) + if (random2(1000) < mod_speed( 200, spd )) + lose_ench_levels(me, 1); + break; + } + + case ENCH_SHORT_LIVED: + // This should only be used for ball lightning -- bwr + if (random2(1000) < mod_speed( 200, spd )) + hit_points = -1; + break; + + // 19 is taken by summoning: + // If these are changed, must also change abjuration + case ENCH_ABJ: + { + const int mspd = + me.degree == 6? 10 : + me.degree == 5? 20 : 100; + + if (random2(1000) < mod_speed( mspd, spd )) + lose_ench_levels(me, 1); + break; + } + + case ENCH_CHARM: + if (random2(500) <= mod_speed( hit_dice + 10, spd )) + del_ench(ENCH_CHARM); + break; + + case ENCH_GLOWING_SHAPESHIFTER: // this ench never runs out + // number of actions is fine for shapeshifters + if (type == MONS_GLOWING_SHAPESHIFTER + || random2(1000) < mod_speed( 250, spd )) + { + monster_polymorph(this, RANDOM_MONSTER, 0); + } + break; + + case ENCH_SHAPESHIFTER: // this ench never runs out + if (type == MONS_SHAPESHIFTER + || random2(1000) < mod_speed( 1000 / ((15 * hit_dice) / 5), spd )) + { + monster_polymorph(this, RANDOM_MONSTER, 0); + } + break; + + case ENCH_TP: + if (me.degree <= 1) + { + del_ench(ENCH_TP); + monster_teleport( this, true ); + } + else + { + int tmp = mod_speed( 1000, spd ); + + if (tmp < 1000 && random2(1000) < tmp) + lose_ench_levels(me, 1); + else if (me.degree - tmp / 1000 >= 1) + { + lose_ench_levels(me, tmp / 1000); + tmp %= 1000; + + if (random2(1000) < tmp) + { + if (me.degree > 1) + lose_ench_levels(me, 1); + else + { + del_ench( ENCH_TP ); + monster_teleport( this, true ); + } + } + } + else + { + del_ench( ENCH_TP ); + monster_teleport( this, true ); + } + } + break; + + case ENCH_SLEEP_WARY: + if (random2(1000) < mod_speed( 50, spd )) + del_ench(ENCH_SLEEP_WARY); + break; + + default: + break; + } +} + +void monsters::apply_enchantments(int spd) +{ + for (mon_enchant_list::iterator i = enchantments.begin(); + i != enchantments.end(); ) + { + mon_enchant_list::iterator cur = i++; + apply_enchantment(*cur, spd); + } +} + +kill_category monsters::kill_alignment() const +{ + return (attitude == ATT_FRIENDLY? KC_FRIENDLY : KC_OTHER); +} + +///////////////////////////////////////////////////////////////////////// +// mon_enchant + +static const char *enchant_names[] = +{ + "none", "slow", "haste", "fear", "conf", "inv", "pois", "bers", + "rot", "summon", "abj", "backlit", "charm", "fire", + "gloshifter", "shifter", "tp", "wary", "submerged", + "short lived", "paralysis", "bug" +}; + +const char *mons_enchantment_name(enchant_type ench) +{ + ASSERT(NUM_ENCHANTMENTS == + (sizeof(enchant_names) / sizeof(*enchant_names)) - 1); + + if (ench > NUM_ENCHANTMENTS) + ench = NUM_ENCHANTMENTS; + + return (enchant_names[ench]); +} + +mon_enchant::operator std::string () const +{ + return make_stringf("%s (%d%s)", + mons_enchantment_name(ench), + degree, + kill_category_desc(who)); +} + +const char *mon_enchant::kill_category_desc(kill_category k) const +{ + return (k == KC_YOU? "you" : + k == KC_FRIENDLY? "pet" : ""); +} + +void mon_enchant::merge_killer(kill_category k) +{ + who = who < k? who : k; +} + +void mon_enchant::cap_degree() +{ + // Hard cap to simulate old enum behaviour, we should really throw this + // out entirely. + const int max = ench == ENCH_ABJ? 6 : 4; + if (degree > max) + degree = max; +} + +mon_enchant &mon_enchant::operator += (const mon_enchant &other) +{ + if (ench == other.ench) + { + degree += other.degree; + cap_degree(); + merge_killer(other.who); + } + return (*this); +} + +mon_enchant mon_enchant::operator + (const mon_enchant &other) const +{ + mon_enchant tmp(*this); + tmp += other; + return (tmp); +} + +int mon_enchant::killer() const +{ + return (who == KC_YOU? KILL_YOU : + who == KC_FRIENDLY? KILL_MON : + KILL_MISC); +} + +int mon_enchant::kill_agent() const +{ + return (who == KC_FRIENDLY? ANON_FRIENDLY_MONSTER : 0); +} diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h index 20774df6d8..f35f9cce2f 100644 --- a/crawl-ref/source/mon-util.h +++ b/crawl-ref/source/mon-util.h @@ -415,14 +415,6 @@ bool mons_has_lifeforce( const monsters *mon ); monster_type mons_genus( int mc ); monster_type mons_species( int mc ); -int mons_has_ench( const monsters *mon, unsigned int ench, - unsigned int ench2 = ENCH_NONE ); - -int mons_del_ench( struct monsters *mon, unsigned int ench, - unsigned int ench2 = ENCH_NONE, bool quiet = false ); - -bool mons_add_ench( struct monsters *mon, unsigned int ench ); - bool mons_looks_stabbable(const monsters *m); bool mons_looks_distracted(const monsters *m); diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc index 46dba3c92c..4ffaf59650 100644 --- a/crawl-ref/source/monplace.cc +++ b/crawl-ref/source/monplace.cc @@ -447,13 +447,9 @@ static int place_monster_aux( int mon_type, char behaviour, int target, if (id == MAX_MONSTERS) return -1; - // scrap monster inventory - for (i = 0; i < NUM_MONSTER_SLOTS; i++) - menv[id].inv[i] = NON_ITEM; - + menv[id].inv.init(NON_ITEM); // scrap monster enchantments - for (i = 0; i < NUM_MON_ENCHANTS; i++) - menv[id].enchantment[i] = ENCH_NONE; + menv[id].enchantments.clear(); // setup habitat and placement if (first_band_member) @@ -530,16 +526,16 @@ static int place_monster_aux( int mon_type, char behaviour, int target, menv[id].number = extra; if (mons_class_flag(mon_type, M_INVIS)) - mons_add_ench(&menv[id], ENCH_INVIS); + menv[id].add_ench(ENCH_INVIS); if (mons_class_flag(mon_type, M_CONFUSED)) - mons_add_ench(&menv[id], ENCH_CONFUSION); + menv[id].add_ench(ENCH_CONFUSION); if (mon_type == MONS_SHAPESHIFTER) - mons_add_ench(&menv[id], ENCH_SHAPESHIFTER); + menv[id].add_ench(ENCH_SHAPESHIFTER); if (mon_type == MONS_GLOWING_SHAPESHIFTER) - mons_add_ench(&menv[id], ENCH_GLOWING_SHAPESHIFTER); + menv[id].add_ench(ENCH_GLOWING_SHAPESHIFTER); if (mon_type == MONS_GIANT_BAT || mon_type == MONS_UNSEEN_HORROR || mon_type == MONS_GIANT_BLOWFLY) @@ -549,7 +545,7 @@ static int place_monster_aux( int mon_type, char behaviour, int target, if (monster_can_submerge(mon_type, grd[fx][fy]) && !one_chance_in(5)) - mons_add_ench( &menv[id], ENCH_SUBMERGED ); + menv[id].add_ench(ENCH_SUBMERGED); menv[id].flags |= MF_JUST_SUMMONED; @@ -597,9 +593,9 @@ static int place_monster_aux( int mon_type, char behaviour, int target, menv[id].behaviour = BEH_WANDER; } - // dur should always be ENCH_ABJ_xx - if (dur >= ENCH_ABJ_I && dur <= ENCH_ABJ_VI) - mons_add_ench(&menv[id], dur ); + // dur should always be 1-6 for monsters that can be abjured. + if (dur >= 1 && dur <= 6) + menv[id].add_ench( mon_enchant(ENCH_ABJ, dur) ); menv[id].foe = target; @@ -1266,7 +1262,7 @@ int mons_place( int mon_type, char behaviour, int target, bool summoned, if (behaviour == BEH_CHARMED) { creation->attitude = ATT_HOSTILE; - mons_add_ench(creation, ENCH_CHARM); + creation->add_ench(ENCH_CHARM); } // make summoned being aware of player's presence @@ -1358,8 +1354,8 @@ int create_monster( int cls, int dur, int beha, int cr_x, int cr_y, struct monsters *const creation = &menv[summd]; // dur should always be ENCH_ABJ_xx - if (dur >= ENCH_ABJ_I && dur <= ENCH_ABJ_VI) - mons_add_ench(creation, dur ); + if (dur >= 1 && dur <= 6) + creation->add_ench( mon_enchant(ENCH_ABJ, dur) ); // look at special cases: CHARMED, FRIENDLY, HOSTILE, GOD_GIFT // alert summoned being to player's presence @@ -1377,7 +1373,7 @@ int create_monster( int cls, int dur, int beha, int cr_x, int cr_y, if (beha == BEH_CHARMED) { creation->attitude = ATT_HOSTILE; - mons_add_ench(creation, ENCH_CHARM); + creation->add_ench(ENCH_CHARM); } // make summoned being aware of player's presence @@ -1385,7 +1381,7 @@ int create_monster( int cls, int dur, int beha, int cr_x, int cr_y, } if (creation->type == MONS_RAKSHASA_FAKE && !one_chance_in(3)) - mons_add_ench(creation, ENCH_INVIS); + creation->add_ench(ENCH_INVIS); } // the return value is either -1 (failure of some sort) diff --git a/crawl-ref/source/monspeak.cc b/crawl-ref/source/monspeak.cc index 9d816115fd..47678b005d 100644 --- a/crawl-ref/source/monspeak.cc +++ b/crawl-ref/source/monspeak.cc @@ -53,7 +53,7 @@ bool mons_speaks(struct monsters *monster) const char *m_name = ptr_monam(monster, DESC_CAP_THE); strcpy(info, m_name); - if (mons_has_ench(monster, ENCH_INVIS)) + if (monster->has_ench(ENCH_INVIS)) return false; // invisible monster tries to remain unnoticed @@ -63,7 +63,7 @@ bool mons_speaks(struct monsters *monster) if (!one_chance_in(3)) return false; // while silenced, don't bother so often - if (mons_has_ench(monster, ENCH_CONFUSION)) + if (monster->has_ench(ENCH_CONFUSION)) { temp_rand = random2(10); strcat(info, (temp_rand < 4) ? " gestures wildly." : @@ -111,10 +111,10 @@ bool mons_speaks(struct monsters *monster) } // end silenced monster // charmed monsters aren't too expressive - if (mons_has_ench(monster, ENCH_CHARM)) + if (monster->has_ench(ENCH_CHARM)) return false; - if (mons_has_ench(monster, ENCH_CONFUSION)) + if (monster->has_ench(ENCH_CONFUSION)) { if (mons_holiness( monster ) == MH_DEMONIC && monster->type != MONS_IMP) diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc index 92066944ea..66bb45a775 100644 --- a/crawl-ref/source/monstuff.cc +++ b/crawl-ref/source/monstuff.cc @@ -294,9 +294,9 @@ static void place_monster_corpse(const monsters *monster) if (corpse_class == MONS_DRACONIAN) corpse_class = draco_subspecies(monster); - if (mons_has_ench(monster, ENCH_SHAPESHIFTER)) + if (monster->has_ench(ENCH_SHAPESHIFTER)) corpse_class = MONS_SHAPESHIFTER; - else if (mons_has_ench(monster, ENCH_GLOWING_SHAPESHIFTER)) + else if (monster->has_ench(ENCH_GLOWING_SHAPESHIFTER)) corpse_class = MONS_GLOWING_SHAPESHIFTER; if (mons_weight(corpse_class) == 0 @@ -384,8 +384,11 @@ void monster_die(monsters *monster, char killer, int i, bool silent) if (you.prev_targ == monster_killed) you.prev_targ = MHITNOT; - const bool pet_kill = (MON_KILL(killer) && ((i >= 0 && i < 200) - && mons_friendly(&menv[i]))); + const bool pet_kill = + (MON_KILL(killer) + && (i == ANON_FRIENDLY_MONSTER || + ((i >= 0 && i < 200) + && mons_friendly(&menv[i])))); if (monster->type == MONS_GIANT_SPORE || monster->type == MONS_BALL_LIGHTNING) @@ -588,11 +591,11 @@ void monster_die(monsters *monster, char killer, int i, bool silent) if (!testbits(monster->flags, MF_CREATED_FRIENDLY) && pet_kill) { bool notice = false; - + const bool anon = (i == ANON_FRIENDLY_MONSTER); gain_exp(exper_value( monster ) / 2 + 1); int targ_holy = mons_holiness(monster), - attacker_holy = mons_holiness(&menv[i]); + attacker_holy = anon? MH_NATURAL : mons_holiness(&menv[i]); if (attacker_holy == MH_UNDEAD) { @@ -603,7 +606,7 @@ void monster_die(monsters *monster, char killer, int i, bool silent) } else if (you.religion == GOD_VEHUMET || you.religion == GOD_MAKHLEB - || testbits( menv[i].flags, MF_GOD_GIFT )) + || (!anon && testbits( menv[i].flags, MF_GOD_GIFT ))) { // Yes, we are splitting undead pets from the others // as a way to focus Necomancy vs Summoning (ignoring @@ -757,7 +760,7 @@ void monster_die(monsters *monster, char killer, int i, bool silent) you.kills.record_kill(monster, killer, pet_kill); - if (mons_has_ench(monster, ENCH_ABJ_I, ENCH_ABJ_VI)) + if (monster->has_ench(ENCH_ABJ)) { if (mons_weight(mons_species(monster->type))) { @@ -878,11 +881,7 @@ static bool jelly_divide(struct monsters * parent) child->foe = parent->foe; child->attitude = parent->attitude; child->colour = parent->colour; - - // duplicate enchantments - for ( int i = 0; i < NUM_MON_ENCHANTS; ++i ) - child->enchantment[i] = parent->enchantment[i]; - + child->enchantments = parent->enchantments; child->x = parent->x + jex; child->y = parent->y + jey; @@ -1009,21 +1008,21 @@ bool monster_polymorph( struct monsters *monster, int targetc, int power ) return (player_messaged); } - // If old monster is visible to the player, and is interesting, - // then note why the interesting monster went away. - if (player_monster_visible(monster) && mons_near(monster) + // If old monster is visible to the player, and is interesting, + // then note why the interesting monster went away. + if (player_monster_visible(monster) && mons_near(monster) && MONST_INTERESTING(monster)) { - take_note(Note(NOTE_POLY_MONSTER, monster->type, 0, - ptr_monam(monster, DESC_NOCAP_A, true))); - } + take_note(Note(NOTE_POLY_MONSTER, monster->type, 0, + ptr_monam(monster, DESC_NOCAP_A, true))); + } // messaging: {dlb} bool invis = (mons_class_flag( targetc, M_INVIS ) - || mons_has_ench( monster, ENCH_INVIS )) && + || monster->has_ench(ENCH_INVIS)) && (!player_see_invis()); - if (mons_has_ench( monster, ENCH_GLOWING_SHAPESHIFTER, ENCH_SHAPESHIFTER )) + if (monster->has_ench(ENCH_GLOWING_SHAPESHIFTER, ENCH_SHAPESHIFTER)) strcat( str_polymon, " changes into " ); else if (targetc == MONS_PULSATING_LUMP) strcat( str_polymon, " degenerates into " ); @@ -1052,22 +1051,18 @@ bool monster_polymorph( struct monsters *monster, int targetc, int power ) monster->type = targetc; monster->number = 250; - int abj = mons_has_ench( monster, ENCH_ABJ_I, ENCH_ABJ_VI ); - int shifter = mons_has_ench( monster, ENCH_GLOWING_SHAPESHIFTER, - ENCH_SHAPESHIFTER ); + mon_enchant abj = monster->get_ench(ENCH_ABJ); + mon_enchant shifter = monster->get_ench(ENCH_GLOWING_SHAPESHIFTER, + ENCH_SHAPESHIFTER); // Note: define_monster() will clear out all enchantments! -- bwr define_monster( monster_index(monster) ); - // put back important enchantments: - if (abj != ENCH_NONE) - mons_add_ench( monster, abj ); - - if (shifter != ENCH_NONE) - mons_add_ench( monster, shifter ); + monster->add_ench(abj); + monster->add_ench(shifter); if (mons_class_flag( monster->type, M_INVIS )) - mons_add_ench( monster, ENCH_INVIS ); + monster->add_ench(ENCH_INVIS); monster->hit_points = monster->max_hit_points * ((old_hp * 100) / old_hp_max) / 100 @@ -1402,7 +1397,7 @@ void behaviour_event( struct monsters *mon, int event, int src, case ME_CORNERED: // just set behaviour.. foe doesn't change. - if (mon->behaviour != BEH_CORNERED && !mons_has_ench(mon,ENCH_FEAR)) + if (mon->behaviour != BEH_CORNERED && !mon->has_ench(ENCH_FEAR)) simple_monster_message(mon, " turns to fight!"); mon->behaviour = BEH_CORNERED; @@ -1430,7 +1425,7 @@ void behaviour_event( struct monsters *mon, int event, int src, // now, break charms if appropriate if (breakCharm) - mons_del_ench( mon, ENCH_CHARM ); + mon->del_ench(ENCH_CHARM); // do any resultant foe or state changes handle_behaviour( mon ); @@ -1453,11 +1448,11 @@ static void handle_behaviour(struct monsters *mon) bool isHurt = (mon->hit_points <= mon->max_hit_points / 4 - 1); bool isHealthy = (mon->hit_points > mon->max_hit_points / 2); bool isSmart = (mons_intel(mon->type) > I_ANIMAL); - bool isScared = mons_has_ench(mon, ENCH_FEAR); + bool isScared = mon->has_ench(ENCH_FEAR); bool isMobile = !mons_is_stationary(mon); // check for confusion -- early out. - if (mons_has_ench(mon, ENCH_CONFUSION)) + if (mon->has_ench(ENCH_CONFUSION)) { mon->target_x = 10 + random2(GXM - 10); mon->target_y = 10 + random2(GYM - 10); @@ -1821,20 +1816,8 @@ bool simple_monster_message(struct monsters *monster, const char *event, return (false); } // end simple_monster_message() -// used to adjust time durations in handle_enchantment() for monster speed -static inline int mod_speed( int val, int speed ) -{ - return (speed ? (val * 10) / speed : val); -} - static bool handle_enchantment(struct monsters *monster) { - bool died = false; - int grid; - int poisonval; - int dam; - int tmp; - // Yes, this is the speed we want. This function will be called in // two circumstances: (1) the monster can move and has enough energy, // and (2) the monster cannot move (speed == 0) and the monster loop @@ -1864,336 +1847,8 @@ static bool handle_enchantment(struct monsters *monster) // // -- bwr const int speed = (monster->speed == 0) ? you.time_taken : monster->speed; - - for (int p = 0; p < NUM_MON_ENCHANTS && !died; p++) - { - switch (monster->enchantment[p]) - { - case ENCH_SLOW: - if (random2(250) <= mod_speed( monster->hit_dice + 10, speed )) - mons_del_ench(monster, ENCH_SLOW); - break; - - case ENCH_HASTE: - if (random2(1000) < mod_speed( 25, speed )) - mons_del_ench(monster, ENCH_HASTE); - break; - - case ENCH_FEAR: - if (random2(150) <= mod_speed( monster->hit_dice + 5, speed )) - mons_del_ench(monster, ENCH_FEAR); - break; - - case ENCH_PARALYSIS: - if (random2(120) < mod_speed( monster->hit_dice + 5, speed )) - mons_del_ench(monster, ENCH_PARALYSIS); - break; - - case ENCH_CONFUSION: - if (random2(120) < mod_speed( monster->hit_dice + 5, speed )) - { - // don't delete perma-confusion - if (!mons_class_flag(monster->type, M_CONFUSED)) - mons_del_ench(monster, ENCH_CONFUSION); - } - break; - - case ENCH_INVIS: - if (random2(1000) < mod_speed( 25, speed )) - { - // don't delete perma-invis - if (!mons_class_flag( monster->type, M_INVIS )) - mons_del_ench(monster, ENCH_INVIS); - } - break; - - case ENCH_SUBMERGED: - // not even air elementals unsubmerge into clouds - if (env.cgrid[monster->x][monster->y] != EMPTY_CLOUD) - break; - - // Air elementals are a special case, as their - // submerging in air isn't up to choice. -- bwr - if (monster->type == MONS_AIR_ELEMENTAL) - { - heal_monster( monster, 1, one_chance_in(5) ); - - if (one_chance_in(5)) - mons_del_ench( monster, ENCH_SUBMERGED ); - - break; - } - - // Now we handle the others: - grid = grd[monster->x][monster->y]; - - // Badly injured monsters prefer to stay submerged... - // electrical eels and lava snakes have ranged attacks - // and are more likely to surface. -- bwr - if (!monster_can_submerge(monster->type, grid)) - mons_del_ench( monster, ENCH_SUBMERGED ); // forced to surface - else if (monster->hit_points <= monster->max_hit_points / 2) - break; - else if (((monster->type == MONS_ELECTRICAL_EEL - || monster->type == MONS_LAVA_SNAKE) - && (random2(1000) < mod_speed( 20, speed ) - || (mons_near(monster) - && monster->hit_points == monster->max_hit_points - && !one_chance_in(10)))) - || random2(2000) < mod_speed(10, speed) - || (mons_near(monster) - && monster->hit_points == monster->max_hit_points - && !one_chance_in(5))) - { - mons_del_ench( monster, ENCH_SUBMERGED ); - } - break; - - case ENCH_POISON_I: - case ENCH_POISON_II: - case ENCH_POISON_III: - case ENCH_POISON_IV: - case ENCH_YOUR_POISON_I: - case ENCH_YOUR_POISON_II: - case ENCH_YOUR_POISON_III: - case ENCH_YOUR_POISON_IV: - poisonval = monster->enchantment[p] - ENCH_POISON_I; - - if (poisonval < 0 || poisonval > 3) - poisonval = monster->enchantment[p] - ENCH_YOUR_POISON_I; - - dam = (poisonval >= 3) ? 1 : 0; - - if (coinflip()) - dam += roll_dice( 1, poisonval + 2 ); - - if (mons_res_poison(monster) < 0) - dam += roll_dice( 2, poisonval ) - 1; - - // We adjust damage for monster speed (since this is applied - // only when the monster moves), and we handle the factional - // part as well (so that speed 30 creatures will take damage). - dam *= 10; - dam = (dam / speed) + ((random2(speed) < (dam % speed)) ? 1 : 0); - - if (dam > 0) - { - hurt_monster( monster, dam ); - -#if DEBUG_DIAGNOSTICS - // for debugging, we don't have this silent. - simple_monster_message( monster, " takes poison damage.", - MSGCH_DIAGNOSTICS ); - snprintf( info, INFO_SIZE, "poison damage: %d", dam ); - mpr( info, MSGCH_DIAGNOSTICS ); -#endif - - if (monster->hit_points < 1) - { - monster_die(monster, - ((monster->enchantment[p] < ENCH_POISON_I) - ? KILL_YOU : KILL_MISC), 0); - died = true; - } - } - - // chance to get over poison (1 in 8, modified for speed) - if (random2(1000) < mod_speed( 125, speed )) - { - if (monster->enchantment[p] == ENCH_POISON_I) - mons_del_ench(monster, ENCH_POISON_I); - else if (monster->enchantment[p] == ENCH_YOUR_POISON_I) - mons_del_ench(monster, ENCH_YOUR_POISON_I); - else - monster->enchantment[p]--; - } - break; - - case ENCH_YOUR_ROT_I: - if (random2(1000) < mod_speed( 250, speed )) - mons_del_ench(monster, ENCH_YOUR_ROT_I); - else if (monster->hit_points > 1 - && random2(1000) < mod_speed( 333, speed )) - { - hurt_monster(monster, 1); - } - break; - - //jmf: FIXME: if (undead) make_small_rot_cloud(); - case ENCH_YOUR_ROT_II: - case ENCH_YOUR_ROT_III: - case ENCH_YOUR_ROT_IV: - if (monster->hit_points > 1 - && random2(1000) < mod_speed( 333, speed )) - { - hurt_monster(monster, 1); - } - - if (random2(1000) < mod_speed( 250, speed )) - monster->enchantment[p]--; - break; - - case ENCH_BACKLIGHT_I: - if (random2(1000) < mod_speed( 100, speed )) - mons_del_ench( monster, ENCH_BACKLIGHT_I ); - break; - - case ENCH_BACKLIGHT_II: - case ENCH_BACKLIGHT_III: - case ENCH_BACKLIGHT_IV: - if (random2(1000) < mod_speed( 200, speed )) - monster->enchantment[p]--; - break; - - // assumption: mons_res_fire has already been checked - case ENCH_STICKY_FLAME_I: - case ENCH_STICKY_FLAME_II: - case ENCH_STICKY_FLAME_III: - case ENCH_STICKY_FLAME_IV: - case ENCH_YOUR_STICKY_FLAME_I: - case ENCH_YOUR_STICKY_FLAME_II: - case ENCH_YOUR_STICKY_FLAME_III: - case ENCH_YOUR_STICKY_FLAME_IV: - dam = roll_dice( 2, 4 ) - 1; - - if (mons_res_fire( monster ) < 0) - dam += roll_dice( 2, 5 ) - 1; - - // We adjust damage for monster speed (since this is applied - // only when the monster moves), and we handle the factional - // part as well (so that speed 30 creatures will take damage). - dam *= 10; - dam = (dam / speed) + ((random2(speed) < (dam % speed)) ? 1 : 0); - - if (dam > 0) - { - hurt_monster( monster, dam ); - simple_monster_message(monster, " burns!"); - -#if DEBUG_DIAGNOSTICS - snprintf( info, INFO_SIZE, "sticky flame damage: %d", dam ); - mpr( info, MSGCH_DIAGNOSTICS ); -#endif - - if (monster->hit_points < 1) - { - monster_die(monster, - ((monster->enchantment[p] < ENCH_STICKY_FLAME_I) - ? KILL_YOU : KILL_MISC), 0); - died = true; - } - } - - // chance to get over sticky flame (1 in 5, modified for speed) - if (random2(1000) < mod_speed( 200, speed )) - { - if (monster->enchantment[p] == ENCH_STICKY_FLAME_I) - mons_del_ench( monster, ENCH_STICKY_FLAME_I ); - else if (monster->enchantment[p] == ENCH_YOUR_STICKY_FLAME_I) - mons_del_ench( monster, ENCH_YOUR_STICKY_FLAME_I ); - else - monster->enchantment[p]--; - } - break; - - case ENCH_SHORT_LIVED: - // This should only be used for ball lightning -- bwr - if (random2(1000) < mod_speed( 200, speed )) - monster->hit_points = -1; - break; - - // 19 is taken by summoning: - // If these are changed, must also change abjuration - case ENCH_ABJ_I: - case ENCH_ABJ_II: - case ENCH_ABJ_III: - case ENCH_ABJ_IV: - if (random2(1000) < mod_speed( 100, speed )) - monster->enchantment[p]--; - - if (monster->enchantment[p] < ENCH_ABJ_I) - { - monster->enchantment[p] = ENCH_ABJ_I; - monster_die(monster, KILL_RESET, 0); - died = true; - } - break; - - case ENCH_ABJ_V: - if (random2(1000) < mod_speed( 20, speed )) - monster->enchantment[p] = ENCH_ABJ_IV; - break; - - case ENCH_ABJ_VI: - if (random2(1000) < mod_speed( 10, speed )) - monster->enchantment[p] = ENCH_ABJ_V; - break; - - case ENCH_CHARM: - if (random2(500) <= mod_speed( monster->hit_dice + 10, speed )) - mons_del_ench(monster, ENCH_CHARM); - break; - - case ENCH_GLOWING_SHAPESHIFTER: // this ench never runs out - // number of actions is fine for shapeshifters - if (monster->type == MONS_GLOWING_SHAPESHIFTER - || random2(1000) < mod_speed( 250, speed )) - { - monster_polymorph(monster, RANDOM_MONSTER, 0); - } - break; - - case ENCH_SHAPESHIFTER: // this ench never runs out - if (monster->type == MONS_SHAPESHIFTER - || random2(1000) < mod_speed( 1000 / ((15 * monster->hit_dice) / 5), speed )) - { - monster_polymorph(monster, RANDOM_MONSTER, 0); - } - break; - - case ENCH_TP_I: - mons_del_ench( monster, ENCH_TP_I ); - monster_teleport( monster, true ); - break; - - case ENCH_TP_II: - case ENCH_TP_III: - case ENCH_TP_IV: - tmp = mod_speed( 1000, speed ); - - if (tmp < 1000 && random2(1000) < tmp) - monster->enchantment[p]--; - else if (monster->enchantment[p] - tmp / 1000 >= ENCH_TP_I) - { - monster->enchantment[p] -= tmp / 1000; - tmp %= 1000; - - if (random2(1000) < tmp) - { - if (monster->enchantment[p] > ENCH_TP_I) - monster->enchantment[p]--; - else - { - mons_del_ench( monster, ENCH_TP_I, ENCH_TP_IV ); - monster_teleport( monster, true ); - } - } - } - else - { - mons_del_ench( monster, ENCH_TP_I, ENCH_TP_IV ); - monster_teleport( monster, true ); - } - break; - - case ENCH_SLEEP_WARY: - if (random2(1000) < mod_speed( 50, speed )) - mons_del_ench(monster, ENCH_SLEEP_WARY); - break; - } - } - - return (died); + monster->apply_enchantments(speed); + return (!monster->alive()); } // end handle_enchantment() //--------------------------------------------------------------- @@ -2277,7 +1932,7 @@ static void handle_nearby_ability(struct monsters *monster) { if (!mons_near( monster ) || monster->behaviour == BEH_SLEEP - || mons_has_ench( monster, ENCH_SUBMERGED )) + || monster->has_ench(ENCH_SUBMERGED)) { return; } @@ -2332,7 +1987,7 @@ static void handle_nearby_ability(struct monsters *monster) // XXX: We're being a bit player-centric here right now... // really we should replace the grid_distance() check // with one that checks for unaligned monsters as well. -- bwr - if (mons_has_ench( monster, ENCH_SUBMERGED)) + if (monster->has_ench(ENCH_SUBMERGED)) { if (grd[monster->x][monster->y] == DNGN_SHALLOW_WATER || grd[monster->x][monster->y] == DNGN_BLUE_FOUNTAIN @@ -2343,7 +1998,7 @@ static void handle_nearby_ability(struct monsters *monster) || (monster->hit_points > monster->max_hit_points / 2 && coinflip())))) { - mons_del_ench( monster, ENCH_SUBMERGED ); + monster->del_ench(ENCH_SUBMERGED); } } else if (monster_can_submerge(monster->type, @@ -2359,13 +2014,13 @@ static void handle_nearby_ability(struct monsters *monster) || monster->hit_points <= monster->max_hit_points / 2) || env.cgrid[monster->x][monster->y] != EMPTY_CLOUD) { - mons_add_ench( monster, ENCH_SUBMERGED ); + monster->add_ench(ENCH_SUBMERGED); } break; case MONS_AIR_ELEMENTAL: if (one_chance_in(5)) - mons_add_ench( monster, ENCH_SUBMERGED ); + monster->add_ench(ENCH_SUBMERGED); break; case MONS_PANDEMONIUM_DEMON: @@ -2394,7 +2049,7 @@ static bool handle_special_ability(struct monsters *monster, bolt & beem) if (!mons_near( monster ) || monster->behaviour == BEH_SLEEP - || mons_has_ench( monster, ENCH_SUBMERGED )) + || monster->has_ench(ENCH_SUBMERGED)) { return (false); } @@ -2458,7 +2113,7 @@ static bool handle_special_ability(struct monsters *monster, bolt & beem) break; case MONS_LAVA_SNAKE: - if (mons_has_ench(monster, ENCH_CONFUSION)) + if (monster->has_ench(ENCH_CONFUSION)) break; if (!mons_player_visible( monster )) @@ -2493,7 +2148,7 @@ static bool handle_special_ability(struct monsters *monster, bolt & beem) break; case MONS_ELECTRICAL_EEL: - if (mons_has_ench(monster, ENCH_CONFUSION)) + if (monster->has_ench(ENCH_CONFUSION)) break; if (!mons_player_visible( monster )) @@ -2531,7 +2186,7 @@ static bool handle_special_ability(struct monsters *monster, bolt & beem) case MONS_ACID_BLOB: case MONS_OKLOB_PLANT: case MONS_YELLOW_DRACONIAN: - if (mons_has_ench(monster, ENCH_CONFUSION)) + if (monster->has_ench(ENCH_CONFUSION)) break; if (!mons_player_visible( monster )) @@ -2547,7 +2202,7 @@ static bool handle_special_ability(struct monsters *monster, bolt & beem) break; // deliberate fall through case MONS_FIEND: - if (mons_has_ench(monster, ENCH_CONFUSION)) + if (monster->has_ench(ENCH_CONFUSION)) break; // friendly fiends won't use torment, preferring hellfire @@ -2610,7 +2265,7 @@ static bool handle_special_ability(struct monsters *monster, bolt & beem) if (!mons_player_visible( monster )) break; - if (mons_has_ench(monster, ENCH_CONFUSION)) + if (monster->has_ench(ENCH_CONFUSION)) break; if (!mons_near(monster)) @@ -2664,7 +2319,7 @@ static bool handle_special_ability(struct monsters *monster, bolt & beem) if (!mons_player_visible( monster )) break; - if (mons_has_ench(monster, ENCH_CONFUSION)) + if (monster->has_ench(ENCH_CONFUSION)) break; if ((monster->type != MONS_HELL_HOUND && random2(13) < 3) @@ -2786,7 +2441,7 @@ static bool handle_reaching(struct monsters *monster) if (mons_aligned(monster_index(monster), monster->foe)) return (false); - if (mons_has_ench( monster, ENCH_SUBMERGED )) + if (monster->has_ench(ENCH_SUBMERGED)) return (false); if (wpn != NON_ITEM && get_weapon_brand( mitm[wpn] ) == SPWPN_REACHING ) @@ -2837,9 +2492,9 @@ static bool handle_reaching(struct monsters *monster) static bool handle_scroll(struct monsters *monster) { // yes, there is a logic to this ordering {dlb}: - if (mons_has_ench(monster, ENCH_CONFUSION) + if (monster->has_ench(ENCH_CONFUSION) || monster->behaviour == BEH_SLEEP - || mons_has_ench( monster, ENCH_SUBMERGED )) + || monster->has_ench(ENCH_SUBMERGED)) { return (false); } @@ -2855,7 +2510,7 @@ static bool handle_scroll(struct monsters *monster) switch (mitm[monster->inv[MSLOT_SCROLL]].sub_type) { case SCR_TELEPORTATION: - if (!mons_has_ench(monster, ENCH_TP_I, ENCH_TP_IV)) + if (!monster->has_ench(ENCH_TP)) { if (monster->behaviour == BEH_FLEE) { @@ -2883,7 +2538,7 @@ static bool handle_scroll(struct monsters *monster) if (mons_near(monster)) { simple_monster_message(monster, " reads a scroll."); - create_monster( MONS_ABOMINATION_SMALL, ENCH_ABJ_II, + create_monster( MONS_ABOMINATION_SMALL, 2, SAME_ATTITUDE(monster), monster->x, monster->y, monster->foe, 250 ); read = true; @@ -2916,7 +2571,7 @@ static bool handle_wand(struct monsters *monster, bolt &beem) return (false); else if (!mons_near(monster)) return (false); - else if (mons_has_ench( monster, ENCH_SUBMERGED )) + else if (monster->has_ench(ENCH_SUBMERGED)) return (false); else if (monster->inv[MSLOT_WAND] == NON_ITEM || mitm[monster->inv[MSLOT_WAND]].plus <= 0) @@ -2980,7 +2635,7 @@ static bool handle_wand(struct monsters *monster, bolt &beem) // these are wands that monsters will aim at themselves {dlb}: case WAND_HASTING: - if (!mons_has_ench(monster, ENCH_HASTE)) + if (!monster->has_ench(ENCH_HASTE)) { beem.target_x = monster->x; beem.target_y = monster->y; @@ -3002,8 +2657,8 @@ static bool handle_wand(struct monsters *monster, bolt &beem) return (false); case WAND_INVISIBILITY: - if (!mons_has_ench( monster, ENCH_INVIS ) - && !mons_has_ench( monster, ENCH_SUBMERGED ) + if (!monster->has_ench(ENCH_INVIS) + && !monster->has_ench(ENCH_SUBMERGED) && (!mons_friendly(monster) || player_see_invis(false))) { beem.target_x = monster->x; @@ -3017,7 +2672,7 @@ static bool handle_wand(struct monsters *monster, bolt &beem) case WAND_TELEPORTATION: if (monster->hit_points <= monster->max_hit_points / 2) { - if (!mons_has_ench(monster, ENCH_TP_I, ENCH_TP_IV) + if (!monster->has_ench(ENCH_TP) && !one_chance_in(20)) { beem.target_x = monster->x; @@ -3144,19 +2799,19 @@ static bool handle_spell( monsters *monster, bolt & beem ) if (monster->behaviour == BEH_SLEEP || (!mons_class_flag(monster->type, M_SPELLCASTER) && draco_breath == MS_NO_SPELL) - || mons_has_ench( monster, ENCH_SUBMERGED )) + || monster->has_ench(ENCH_SUBMERGED)) { return (false); } if ((mons_class_flag(monster->type, M_ACTUAL_SPELLS) || mons_class_flag(monster->type, M_PRIEST)) - && (mons_has_ench(monster, ENCH_GLOWING_SHAPESHIFTER, ENCH_SHAPESHIFTER))) + && (monster->has_ench(ENCH_GLOWING_SHAPESHIFTER, ENCH_SHAPESHIFTER))) { return (false); //jmf: shapeshiftes don't get spells, just // physical powers. } - else if (mons_has_ench(monster, ENCH_CONFUSION) + else if (monster->has_ench(ENCH_CONFUSION) && !mons_class_flag(monster->type, M_CONFUSED)) { return (false); @@ -3467,7 +3122,7 @@ static bool handle_spell( monsters *monster, bolt & beem ) break; case MONS_VAPOUR: - mons_add_ench( monster, ENCH_SUBMERGED ); + monster->add_ench(ENCH_SUBMERGED); break; case MONS_BRAIN_WORM: @@ -3537,9 +3192,9 @@ static bool handle_spell( monsters *monster, bolt & beem ) static bool handle_throw(struct monsters *monster, bolt & beem) { // yes, there is a logic to this ordering {dlb}: - if (mons_has_ench(monster, ENCH_CONFUSION) + if (monster->has_ench(ENCH_CONFUSION) || monster->behaviour == BEH_SLEEP - || mons_has_ench( monster, ENCH_SUBMERGED )) + || monster->has_ench(ENCH_SUBMERGED)) { return (false); } @@ -3603,8 +3258,8 @@ static bool handle_throw(struct monsters *monster, bolt & beem) static bool handle_monster_spell(monsters *monster, bolt &beem) { // shapeshifters don't get spells - if (!mons_has_ench( monster, ENCH_GLOWING_SHAPESHIFTER, - ENCH_SHAPESHIFTER ) + if (!monster->has_ench( ENCH_GLOWING_SHAPESHIFTER, + ENCH_SHAPESHIFTER ) || !mons_class_flag( monster->type, M_ACTUAL_SPELLS )) { if (handle_spell(monster, beem)) @@ -3677,7 +3332,7 @@ static void handle_monster_move(int i, monsters *monster) if (monster->speed == 0) { if (env.cgrid[monster->x][monster->y] != EMPTY_CLOUD - && !mons_has_ench( monster, ENCH_SUBMERGED )) + && !monster->has_ench(ENCH_SUBMERGED)) { mons_in_cloud( monster ); } @@ -3691,11 +3346,11 @@ static void handle_monster_move(int i, monsters *monster) monster->foe_memory--; if (monster->type == MONS_GLOWING_SHAPESHIFTER) - mons_add_ench( monster, ENCH_GLOWING_SHAPESHIFTER ); + monster->add_ench(ENCH_GLOWING_SHAPESHIFTER); // otherwise there are potential problems with summonings if (monster->type == MONS_SHAPESHIFTER) - mons_add_ench( monster, ENCH_SHAPESHIFTER ); + monster->add_ench(ENCH_SHAPESHIFTER); // We reset batty monsters from wander to seek here, instead // of in handle_behaviour() since that will be called with @@ -3717,7 +3372,7 @@ static void handle_monster_move(int i, monsters *monster) if (env.cgrid[monster->x][monster->y] != EMPTY_CLOUD) { - if (mons_has_ench( monster, ENCH_SUBMERGED )) + if (monster->has_ench(ENCH_SUBMERGED)) break; if (monster->type == -1) @@ -3746,7 +3401,7 @@ static void handle_monster_move(int i, monsters *monster) if (monster_can_submerge(monster->type, grd[monster->x][monster->y]) && env.cgrid[monster->x][monster->y] != EMPTY_CLOUD) { - mons_add_ench( monster, ENCH_SUBMERGED ); + monster->add_ench(ENCH_SUBMERGED); } if (monster->speed >= 100) @@ -3779,7 +3434,7 @@ static void handle_monster_move(int i, monsters *monster) if (mons_is_confused( monster ) || (monster->type == MONS_AIR_ELEMENTAL - && mons_has_ench( monster, ENCH_SUBMERGED ))) + && monster->has_ench(ENCH_SUBMERGED))) { std::vector<coord_def> moves; @@ -4036,7 +3691,7 @@ static bool handle_pickup(struct monsters *monster) bool monsterNearby = mons_near(monster); int item = NON_ITEM; - if (mons_has_ench( monster, ENCH_SUBMERGED )) + if (monster->has_ench(ENCH_SUBMERGED)) return (false); if (monster->behaviour == BEH_SLEEP) @@ -5191,7 +4846,8 @@ static void mons_in_cloud(struct monsters *monster) if (mons_res_poison(monster) > 0) return; - poison_monster(monster, (env.cloud[wc].type == CLOUD_POISON)); + poison_monster(monster, + env.cloud[wc].type == CLOUD_POISON? KC_YOU : KC_OTHER); // If the monster got poisoned, wake it up. wake = true; @@ -5230,7 +4886,8 @@ static void mons_in_cloud(struct monsters *monster) || monster->type == MONS_DEATH_DRAKE) return; - poison_monster(monster, (env.cloud[wc].type == CLOUD_MIASMA)); + poison_monster(monster, + (env.cloud[wc].type == CLOUD_MIASMA? KC_YOU : KC_OTHER)); if (monster->max_hit_points > 4 && coinflip()) monster->max_hit_points--; diff --git a/crawl-ref/source/mstuff2.cc b/crawl-ref/source/mstuff2.cc index 2294ce549c..a7f85242c4 100644 --- a/crawl-ref/source/mstuff2.cc +++ b/crawl-ref/source/mstuff2.cc @@ -296,7 +296,7 @@ void mons_trap(struct monsters *monster) } if (apply_poison) - poison_monster( monster, false ); + poison_monster( monster, KC_OTHER ); // generate "fallen" projectile, where appropriate: {dlb} if (random2(10) < 7) @@ -400,7 +400,7 @@ void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast) } } - create_monster( mons, ENCH_ABJ_V, SAME_ATTITUDE(monster), + create_monster( mons, 5, SAME_ATTITUDE(monster), monster->x, monster->y, monster->foe, 250 ); } return; @@ -417,7 +417,7 @@ void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast) for (sumcount = 0; sumcount < sumcount2; sumcount++) { - create_monster( RANDOM_MONSTER, ENCH_ABJ_V, SAME_ATTITUDE(monster), + create_monster( RANDOM_MONSTER, 5, SAME_ATTITUDE(monster), monster->x, monster->y, monster->foe, 250 ); } return; @@ -427,7 +427,7 @@ void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast) for (sumcount = 0; sumcount < sumcount2; sumcount++) { - create_monster( MONS_RAKSHASA_FAKE, ENCH_ABJ_III, + create_monster( MONS_RAKSHASA_FAKE, 3, SAME_ATTITUDE(monster), monster->x, monster->y, monster->foe, 250 ); } @@ -443,10 +443,7 @@ void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast) sumcount2 = 1 + random2(2) + random2( monster->hit_dice / 10 + 1 ); - duration = ENCH_ABJ_II + monster->hit_dice / 10; - if (duration > ENCH_ABJ_VI) - duration = ENCH_ABJ_VI; - + duration = cap_int(2 + monster->hit_dice / 10, 6); for (sumcount = 0; sumcount < sumcount2; sumcount++) { create_monster( summon_any_demon(DEMON_COMMON), duration, @@ -463,10 +460,7 @@ void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast) case MS_SUMMON_DEMON_LESSER: // class 5 demons sumcount2 = 1 + random2(3) + random2( monster->hit_dice / 5 + 1 ); - duration = ENCH_ABJ_II + monster->hit_dice / 5; - if (duration > ENCH_ABJ_VI) - duration = ENCH_ABJ_VI; - + duration = cap_int(2 + monster->hit_dice / 5, 6); for (sumcount = 0; sumcount < sumcount2; sumcount++) { create_monster( summon_any_demon(DEMON_LESSER), duration, @@ -478,9 +472,7 @@ void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast) case MS_SUMMON_UFETUBUS: sumcount2 = 2 + random2(2) + random2( monster->hit_dice / 5 + 1 ); - duration = ENCH_ABJ_II + monster->hit_dice / 5; - if (duration > ENCH_ABJ_VI) - duration = ENCH_ABJ_VI; + duration = cap_int(2 + monster->hit_dice / 5, 6); for (sumcount = 0; sumcount < sumcount2; sumcount++) { @@ -490,7 +482,7 @@ void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast) return; case MS_SUMMON_BEAST: // Geryon - create_monster( MONS_BEAST, ENCH_ABJ_IV, SAME_ATTITUDE(monster), + create_monster( MONS_BEAST, 4, SAME_ATTITUDE(monster), monster->x, monster->y, monster->foe, 250 ); return; @@ -504,10 +496,7 @@ void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast) sumcount2 = 1 + random2(2) + random2( monster->hit_dice / 4 + 1 ); - duration = ENCH_ABJ_II + monster->hit_dice / 5; - if (duration > ENCH_ABJ_VI) - duration = ENCH_ABJ_VI; - + duration = cap_int(2 + monster->hit_dice / 5, 6); for (int i = 0; i < sumcount2; ++i) create_monster(MONS_WANDERING_MUSHROOM, duration, SAME_ATTITUDE(monster), @@ -526,10 +515,7 @@ void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast) sumcount2 = 2 + random2(2) + random2( monster->hit_dice / 4 + 1 ); - duration = ENCH_ABJ_II + monster->hit_dice / 5; - if (duration > ENCH_ABJ_VI) - duration = ENCH_ABJ_VI; - + duration = cap_int(2 + monster->hit_dice / 5, 6); for (sumcount = 0; sumcount < sumcount2; sumcount++) { do @@ -539,7 +525,7 @@ void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast) while (mons_class_holiness(summonik) != MH_UNDEAD); create_monster(summonik, duration, SAME_ATTITUDE(monster), - you.x_pos, you.y_pos, monster->foe, 250); + monster->x, monster->y, monster->foe, 250); } return; @@ -562,10 +548,7 @@ void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast) sumcount2 = 1 + random2( monster->hit_dice / 10 + 1 ); - duration = ENCH_ABJ_II + monster->hit_dice / 10; - if (duration > ENCH_ABJ_VI) - duration = ENCH_ABJ_VI; - + duration = cap_int(2 + monster->hit_dice / 10, 6); for (sumcount = 0; sumcount < sumcount2; sumcount++) { create_monster( summon_any_demon(DEMON_GREATER), duration, @@ -585,9 +568,7 @@ void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast) sumcount2 = 1 + random2(3) + random2( monster->hit_dice / 5 + 1 ); - duration = ENCH_ABJ_II + monster->hit_dice / 10; - if (duration > ENCH_ABJ_VI) - duration = ENCH_ABJ_VI; + duration = cap_int(2 + monster->hit_dice / 10, 6); { std::vector<int> monsters; @@ -776,13 +757,13 @@ void monster_teleport(struct monsters *monster, bool instan, bool silent) { if (!instan) { - if (mons_del_ench(monster, ENCH_TP_I, ENCH_TP_IV)) + if (monster->del_ench(ENCH_TP)) { if (!silent) simple_monster_message(monster, " seems more stable."); } else - mons_add_ench(monster, (coinflip() ? ENCH_TP_III : ENCH_TP_IV )); + monster->add_ench( mon_enchant(ENCH_TP, coinflip()? 3 : 4) ); return; } @@ -1880,8 +1861,6 @@ static unsigned char monster_abjuration(int pow, bool test) for (int ab = 0; ab < MAX_MONSTERS && abjure_str; ab++) { - int abjLevel; - monster = &menv[ab]; if (monster->type == -1 || !mons_near(monster)) @@ -1890,8 +1869,8 @@ static unsigned char monster_abjuration(int pow, bool test) if (!mons_friendly(monster)) continue; - abjLevel = mons_has_ench(monster, ENCH_ABJ_I, ENCH_ABJ_VI); - if (abjLevel == ENCH_NONE) + mon_enchant abjLevel = monster->get_ench(ENCH_ABJ); + if (abjLevel.ench == ENCH_NONE) continue; result++; @@ -1899,15 +1878,14 @@ static unsigned char monster_abjuration(int pow, bool test) if (test) continue; - abjLevel -= abjure_str; + abjLevel.degree -= abjure_str; - if (abjLevel < ENCH_ABJ_I) + if (abjLevel.degree <= 0) monster_die(monster, KILL_RESET, 0); else { simple_monster_message(monster, " shudders."); - mons_del_ench(monster, ENCH_ABJ_I, ENCH_ABJ_VI); - mons_add_ench(monster, abjLevel); + monster->update_ench(abjLevel); } if (!(abjure_str = div_rand_round(abjure_str, 2))) @@ -1930,7 +1908,7 @@ bool silver_statue_effects(monsters *mons) create_monster( summon_any_demon((coinflip() ? DEMON_COMMON : DEMON_LESSER)), - ENCH_ABJ_V, BEH_HOSTILE, + 5, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250 ); return (true); diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc index 2de57145b7..462a38abae 100644 --- a/crawl-ref/source/player.cc +++ b/crawl-ref/source/player.cc @@ -2053,8 +2053,8 @@ int player_see_invis(bool calc_unid) // to find if the square the monster is in is visible see mons_near(). bool player_monster_visible( const monsters *mon ) { - if (mons_has_ench( mon, ENCH_SUBMERGED ) - || (mons_has_ench( mon, ENCH_INVIS ) && !player_see_invis())) + if (mon->has_ench(ENCH_SUBMERGED) + || (mon->has_ench(ENCH_INVIS) && !player_see_invis())) { return (false); } @@ -5203,3 +5203,8 @@ god_type player::deity() const { return (religion); } + +kill_category player::kill_alignment() const +{ + return (KC_YOU); +} diff --git a/crawl-ref/source/religion.cc b/crawl-ref/source/religion.cc index ca56d3888b..1d4f48e51d 100644 --- a/crawl-ref/source/religion.cc +++ b/crawl-ref/source/religion.cc @@ -965,23 +965,23 @@ void Xom_acts(bool niceness, int sever, bool force_sever) dancing_weapon(100, true); // nasty, but fun else { - create_monster(MONS_NEQOXEC + random2(5), ENCH_ABJ_III, + create_monster(MONS_NEQOXEC + random2(5), 3, BEH_HOSTILE, you.x_pos, you.y_pos, MHITNOT, 250); if (one_chance_in(3)) - create_monster(MONS_NEQOXEC + random2(5), ENCH_ABJ_III, + create_monster(MONS_NEQOXEC + random2(5), 3, BEH_HOSTILE, you.x_pos, you.y_pos, MHITNOT, 250); if (one_chance_in(4)) - create_monster(MONS_NEQOXEC + random2(5), ENCH_ABJ_III, + create_monster(MONS_NEQOXEC + random2(5), 3, BEH_HOSTILE, you.x_pos, you.y_pos, MHITNOT, 250); if (one_chance_in(3)) - create_monster(MONS_HELLION + random2(10), ENCH_ABJ_III, + create_monster(MONS_HELLION + random2(10), 3, BEH_HOSTILE, you.x_pos, you.y_pos, MHITNOT, 250); if (one_chance_in(4)) - create_monster(MONS_HELLION + random2(10), ENCH_ABJ_III, + create_monster(MONS_HELLION + random2(10), 3, BEH_HOSTILE, you.x_pos, you.y_pos, MHITNOT, 250); } @@ -1061,31 +1061,31 @@ void Xom_acts(bool niceness, int sever, bool force_sever) (temp_rand == 1) ? "Xom grants you some temporary aid." : "Xom opens a gate."); - create_monster( MONS_NEQOXEC + random2(5), ENCH_ABJ_III, + create_monster( MONS_NEQOXEC + random2(5), 3, BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target, 250 ); - create_monster( MONS_NEQOXEC + random2(5), ENCH_ABJ_III, + create_monster( MONS_NEQOXEC + random2(5), 3, BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target, 250 ); if (random2( you.experience_level ) >= 8) { - create_monster( MONS_NEQOXEC + random2(5), ENCH_ABJ_III, + create_monster( MONS_NEQOXEC + random2(5), 3, BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target, 250 ); } if (random2( you.experience_level ) >= 8) { - create_monster( MONS_HELLION + random2(10), ENCH_ABJ_III, + create_monster( MONS_HELLION + random2(10), 3, BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target, 250 ); } if (random2( you.experience_level ) >= 8) { - create_monster( MONS_HELLION + random2(10), ENCH_ABJ_III, + create_monster( MONS_HELLION + random2(10), 3, BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target, 250 ); } diff --git a/crawl-ref/source/spells1.cc b/crawl-ref/source/spells1.cc index 81abfc781b..f4697c7e52 100644 --- a/crawl-ref/source/spells1.cc +++ b/crawl-ref/source/spells1.cc @@ -654,30 +654,18 @@ void abjuration(int pow) { monster = &menv[ab]; - int abjLevel; - if (monster->type == -1 || !mons_near(monster)) continue; if (mons_friendly(monster)) continue; - abjLevel = mons_del_ench(monster, ENCH_ABJ_I, ENCH_ABJ_VI); - if (abjLevel != ENCH_NONE) - { - abjLevel -= 1 + (random2(pow) / 8); - - if (abjLevel < ENCH_ABJ_I) - { - mons_add_ench(monster, ENCH_ABJ_I); - monster_die(monster, KILL_RESET, 0); - } - else - { - simple_monster_message(monster, " shudders."); - mons_add_ench(monster, abjLevel); - } - } + mon_enchant abj = monster->get_ench(ENCH_ABJ); + if (abj.ench != ENCH_NONE) + monster->lose_ench_levels(abj, 1 + (random2(pow) / 8)); + + if (monster->has_ench(ENCH_ABJ)) + simple_monster_message(monster, " shudders."); } } // end abjuration() diff --git a/crawl-ref/source/spells2.cc b/crawl-ref/source/spells2.cc index 457bbd72e9..6975c80d32 100644 --- a/crawl-ref/source/spells2.cc +++ b/crawl-ref/source/spells2.cc @@ -749,7 +749,7 @@ void turn_undead(int pow) continue; } - if (!mons_add_ench(monster, ENCH_FEAR)) + if (!monster->add_ench(ENCH_FEAR)) continue; simple_monster_message( monster, " is repelled!" ); @@ -800,7 +800,7 @@ void holy_word(int pow, bool silent) if (monster->speed_increment >= 25) monster->speed_increment -= 20; - mons_add_ench(monster, ENCH_FEAR); + monster->add_ench(ENCH_FEAR); } // end "if mons_holiness" } // end "for tu" } // end holy_word() @@ -837,12 +837,12 @@ void cast_toxic_radiance(void) if (monster->type != -1 && mons_near(monster)) { - if (!mons_has_ench(monster, ENCH_INVIS)) + if (!monster->has_ench(ENCH_INVIS)) { - poison_monster(monster, true); + poison_monster(monster, KC_YOU); if (coinflip()) // 50-50 chance for a "double hit" {dlb} - poison_monster(monster, true); + poison_monster(monster, KC_YOU); } else if (player_see_invis()) @@ -920,7 +920,7 @@ void cast_refrigeration(int pow) //jmf: "slow snakes" finally available if (mons_class_flag( monster->type, M_COLD_BLOOD ) && coinflip()) - mons_add_ench(monster, ENCH_SLOW); + monster->add_ench(ENCH_SLOW); } } } @@ -1157,7 +1157,7 @@ char burn_freeze(int pow, char flavour) if (mons_class_flag( monster->type, M_COLD_BLOOD ) && coinflip()) { - mons_add_ench(monster, ENCH_SLOW); + monster->add_ench(ENCH_SLOW); } const int cold_res = mons_res_cold( monster ); @@ -1189,10 +1189,7 @@ int summon_elemental(int pow, int restricted_type, int targ_x; int targ_y; - int numsc = ENCH_ABJ_II + (random2(pow) / 5); - - if (numsc > ENCH_ABJ_VI) - numsc = ENCH_ABJ_VI; + int numsc = cap_int(2 + (random2(pow) / 5), 6); for (;;) { @@ -1356,7 +1353,7 @@ void summon_small_mammals(int pow) break; } - create_monster( thing_called, ENCH_ABJ_III, BEH_FRIENDLY, + create_monster( thing_called, 3, BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target, 250 ); } } // end summon_small_mammals() @@ -1371,7 +1368,7 @@ void summon_scorpions(int pow) { if (random2(pow) <= 3) { - if (create_monster( MONS_SCORPION, ENCH_ABJ_III, BEH_HOSTILE, + if (create_monster( MONS_SCORPION, 3, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250 ) != -1) { mpr("A scorpion appears. It doesn't look very happy."); @@ -1379,7 +1376,7 @@ void summon_scorpions(int pow) } else { - if (create_monster( MONS_SCORPION, ENCH_ABJ_III, BEH_FRIENDLY, + if (create_monster( MONS_SCORPION, 3, BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target, 250 ) != -1) { @@ -1391,12 +1388,9 @@ void summon_scorpions(int pow) void summon_ice_beast_etc(int pow, int ibc, bool divine_gift) { - int numsc = ENCH_ABJ_II + (random2(pow) / 4); + int numsc = cap_int(2 + (random2(pow) / 4), 6); int beha = divine_gift? BEH_GOD_GIFT : BEH_FRIENDLY; - if (numsc > ENCH_ABJ_VI) - numsc = ENCH_ABJ_VI; - switch (ibc) { case MONS_ICE_BEAST: @@ -1504,7 +1498,7 @@ bool summon_swarm( int pow, bool unfriendly, bool god_gift ) else if (!unfriendly && random2(pow) > 7) behaviour = BEH_FRIENDLY; - if (create_monster( thing_called, ENCH_ABJ_III, behaviour, + if (create_monster( thing_called, 3, behaviour, you.x_pos, you.y_pos, MHITYOU, 250 )) { summoned = true; @@ -1534,7 +1528,7 @@ void summon_undead(int pow) if (random2(pow) < 6) { - if (create_monster( thing_called, ENCH_ABJ_V, BEH_HOSTILE, + if (create_monster( thing_called, 5, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250 ) != -1) { mpr("You sense a hostile presence."); @@ -1542,7 +1536,7 @@ void summon_undead(int pow) } else { - if (create_monster( thing_called, ENCH_ABJ_V, BEH_FRIENDLY, + if (create_monster( thing_called, 5, BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target, 250 ) != -1) { mpr("An insubstantial figure forms in the air."); @@ -1588,7 +1582,7 @@ void summon_things( int pow ) while (big_things > 0) { - create_monster( MONS_TENTACLED_MONSTROSITY, ENCH_ABJ_VI, + create_monster( MONS_TENTACLED_MONSTROSITY, 6, BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target, 250 ); big_things--; @@ -1596,7 +1590,7 @@ void summon_things( int pow ) while (numsc > 0) { - create_monster( MONS_ABOMINATION_LARGE, ENCH_ABJ_VI, BEH_FRIENDLY, + create_monster( MONS_ABOMINATION_LARGE, 6, BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target, 250 ); numsc--; } diff --git a/crawl-ref/source/spells3.cc b/crawl-ref/source/spells3.cc index ecf1d28b04..b5a19d385c 100644 --- a/crawl-ref/source/spells3.cc +++ b/crawl-ref/source/spells3.cc @@ -401,7 +401,7 @@ void simulacrum(int power) for (int i = 0; i < max_num; i++) { - if (create_monster( MONS_SIMULACRUM_SMALL, ENCH_ABJ_VI, + if (create_monster( MONS_SIMULACRUM_SMALL, 6, BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target, mons_type ) != -1) { @@ -428,12 +428,9 @@ void simulacrum(int power) void dancing_weapon(int pow, bool force_hostile) { - int numsc = ENCH_ABJ_II + (random2(pow) / 5); + int numsc = cap_int(2 + (random2(pow) / 5), 6); char str_pass[ ITEMNAME_SIZE ]; - if (numsc > ENCH_ABJ_VI) - numsc = ENCH_ABJ_VI; - int i; int summs = 0; char behavi = BEH_FRIENDLY; diff --git a/crawl-ref/source/spells4.cc b/crawl-ref/source/spells4.cc index 341bc90502..1575e8cc12 100644 --- a/crawl-ref/source/spells4.cc +++ b/crawl-ref/source/spells4.cc @@ -616,7 +616,7 @@ void cast_summon_butterflies(int pow) for (int scount = 1; scount < num; scount++) { - create_monster( MONS_BUTTERFLY, ENCH_ABJ_III, BEH_FRIENDLY, + create_monster( MONS_BUTTERFLY, 3, BEH_FRIENDLY, you.x_pos, you.y_pos, MHITYOU, 250 ); } } @@ -654,22 +654,16 @@ void cast_summon_large_mammal(int pow) } } - create_monster( mon, ENCH_ABJ_III, BEH_FRIENDLY, you.x_pos, you.y_pos, + create_monster( mon, 3, BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target, 250 ); } void cast_sticks_to_snakes(int pow) { int mon, i, behaviour; - int how_many = 0; - int max = 1 + random2( 1 + you.skills[SK_TRANSMIGRATION] ) / 4; - - int dur = ENCH_ABJ_III + random2(pow) / 20; - if (dur > ENCH_ABJ_V) - dur = ENCH_ABJ_V; - + int dur = cap_int(3 + random2(pow) / 20, 5); const int weapon = you.equip[EQ_WEAPON]; if (weapon == -1) @@ -790,7 +784,7 @@ void cast_summon_dragon(int pow) // a very high level spell so it might be okay). -- bwr happy = (random2(pow) > 5); - if (create_monster( MONS_DRAGON, ENCH_ABJ_III, + if (create_monster( MONS_DRAGON, 3, (happy ? BEH_FRIENDLY : BEH_HOSTILE), you.x_pos, you.y_pos, MHITYOU, 250 ) != -1) { @@ -844,7 +838,7 @@ void cast_conjure_ball_lightning( int pow ) if (mon != -1) { - mons_add_ench( &menv[mon], ENCH_SHORT_LIVED ); + menv[mon].add_ench(ENCH_SHORT_LIVED); summoned = true; } } @@ -869,13 +863,13 @@ static int sleep_monsters(int x, int y, int pow, int garbage) //jmf: now that sleep == hibernation: if (mons_res_cold( &menv[mnstr] ) > 0 && coinflip()) return 0; - if (mons_has_ench( &menv[mnstr], ENCH_SLEEP_WARY )) return 0; + if (menv[mnstr].has_ench(ENCH_SLEEP_WARY)) return 0; menv[mnstr].behaviour = BEH_SLEEP; - mons_add_ench( &menv[mnstr], ENCH_SLEEP_WARY ); + menv[mnstr].add_ench(ENCH_SLEEP_WARY); if (mons_class_flag( menv[mnstr].type, M_COLD_BLOOD ) && coinflip()) - mons_add_ench( &menv[mnstr], ENCH_SLOW ); + menv[mnstr].add_ench(ENCH_SLOW); return 1; } // end sleep_monsters() @@ -919,7 +913,7 @@ static int tame_beast_monsters(int x, int y, int pow, int garbage) if (random2(100) < random2(pow / 10)) monster->attitude = ATT_FRIENDLY; // permanent, right? else - mons_add_ench(monster, ENCH_CHARM); + monster->add_ench(ENCH_CHARM); return 1; } // end tame_beast_monsters() @@ -1036,15 +1030,10 @@ static int ignite_poison_monsters(int x, int y, int pow, int garbage) int strength = 0; // first check for player poison: - int ench = mons_has_ench( mon, ENCH_YOUR_POISON_I, ENCH_YOUR_POISON_IV ); - if (ench != ENCH_NONE) - strength += ench - ENCH_YOUR_POISON_I + 1; - - // ... now monster poison: - ench = mons_has_ench( mon, ENCH_POISON_I, ENCH_POISON_IV ); - if (ench != ENCH_NONE) - strength += ench - ENCH_POISON_I + 1; - + mon_enchant ench = mon->get_ench(ENCH_POISON); + if (ench.ench != ENCH_NONE) + strength += ench.degree; + // strength is now the sum of both poison types (although only // one should actually be present at a given time): dam_dice.num += strength; @@ -1062,9 +1051,7 @@ static int ignite_poison_monsters(int x, int y, int pow, int garbage) if (!player_hurt_monster( mon_index, damage )) { // Monster survived, remove any poison. - mons_del_ench( mon, ENCH_POISON_I, ENCH_POISON_IV ); - mons_del_ench( mon, ENCH_YOUR_POISON_I, ENCH_YOUR_POISON_IV ); - + mon->del_ench(ENCH_POISON); behaviour_event( mon, ME_ALERT ); } @@ -1720,7 +1707,7 @@ static int intoxicate_monsters(int x, int y, int pow, int garbage) if (mons_res_poison(&menv[mon]) > 0) return 0; - mons_add_ench(&menv[mon], ENCH_CONFUSION); + menv[mon].add_ench(ENCH_CONFUSION); return 1; } // end intoxicate_monsters() @@ -1782,15 +1769,15 @@ static int glamour_monsters(int x, int y, int pow, int garbage) switch (random2(6)) { case 0: - mons_add_ench(&menv[mon], ENCH_FEAR); + menv[mon].add_ench(ENCH_FEAR); break; case 1: case 4: - mons_add_ench(&menv[mon], ENCH_CONFUSION); + menv[mon].add_ench(ENCH_CONFUSION); break; case 2: case 5: - mons_add_ench(&menv[mon], ENCH_CHARM); + menv[mon].add_ench(ENCH_CHARM); break; case 3: menv[mon].behaviour = BEH_SLEEP; @@ -1874,22 +1861,23 @@ bool backlight_monsters(int x, int y, int pow, int garbage) break; } - int lvl = mons_has_ench( &menv[mon], ENCH_BACKLIGHT_I, ENCH_BACKLIGHT_IV ); + mon_enchant bklt = menv[mon].get_ench(ENCH_BACKLIGHT); + int lvl = bklt.degree; - if (lvl == ENCH_NONE) + if (lvl == 0) simple_monster_message( &menv[mon], " is outlined in light." ); - else if (lvl == ENCH_BACKLIGHT_IV) + else if (lvl == 4) simple_monster_message( &menv[mon], " glows brighter for a moment." ); else { // remove old level - mons_del_ench( &menv[mon], ENCH_BACKLIGHT_I, ENCH_BACKLIGHT_III, true ); + menv[mon].del_ench(ENCH_BACKLIGHT, true); simple_monster_message( &menv[mon], " glows brighter." ); } // this enchantment wipes out invisibility (neat) - mons_del_ench( &menv[mon], ENCH_INVIS ); - mons_add_ench( &menv[mon], ENCH_BACKLIGHT_IV ); + menv[mon].del_ench(ENCH_INVIS); + menv[mon].add_ench(ENCH_BACKLIGHT); return (true); } // end backlight_monsters() @@ -2220,17 +2208,9 @@ static int rot_living(int x, int y, int pow, int message) return 0; ench = ((random2(pow) + random2(pow) + random2(pow) + random2(pow)) / 4); + ench = 1 + (ench >= 20) + (ench >= 35) + (ench >= 50); - if (ench >= 50) - ench = ENCH_YOUR_ROT_IV; - else if (ench >= 35) - ench = ENCH_YOUR_ROT_III; - else if (ench >= 20) - ench = ENCH_YOUR_ROT_II; - else - ench = ENCH_YOUR_ROT_I; - - mons_add_ench(&menv[mon], ench); + menv[mon].add_ench( mon_enchant(ENCH_ROT, ench) ); return 1; } // end rot_living() @@ -2286,17 +2266,9 @@ static int rot_undead(int x, int y, int pow, int garbage) } ench = ((random2(pow) + random2(pow) + random2(pow) + random2(pow)) / 4); + ench = 1 + (ench >= 20) + (ench >= 35) + (ench >= 50); - if (ench >= 50) - ench = ENCH_YOUR_ROT_IV; - else if (ench >= 35) - ench = ENCH_YOUR_ROT_III; - else if (ench >= 20) - ench = ENCH_YOUR_ROT_II; - else - ench = ENCH_YOUR_ROT_I; - - mons_add_ench(&menv[mon], ench); + menv[mon].add_ench( mon_enchant(ENCH_ROT, ench) ); return 1; } // end rot_undead() diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc index 87f7318d8c..d9c6690a3a 100644 --- a/crawl-ref/source/spl-cast.cc +++ b/crawl-ref/source/spl-cast.cc @@ -1465,7 +1465,7 @@ int your_spells( int spc2, int powc, bool allow_fail ) if (dem_hor == BEH_CHARMED) mpr("You don't feel so good about this..."); - create_monster( summon_any_demon(DEMON_GREATER), ENCH_ABJ_V, dem_hor, + create_monster( summon_any_demon(DEMON_GREATER), 5, dem_hor, you.x_pos, you.y_pos, MHITYOU, 250 ); break; @@ -1671,7 +1671,7 @@ int your_spells( int spc2, int powc, bool allow_fail ) { mpr( "Wisps of shadow whirl around you..." ); const int which_mons = - create_monster( RANDOM_MONSTER, ENCH_ABJ_II, BEH_FRIENDLY, + create_monster( RANDOM_MONSTER, 2, BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target, 250 ); if (which_mons != -1 && which_mons != NON_MONSTER) menv[which_mons].flags |= MF_HARD_RESET; @@ -2287,7 +2287,7 @@ bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail, break; case 5: mpr("Space twists in upon itself!"); - create_monster( MONS_SPATIAL_VORTEX, ENCH_ABJ_III, BEH_HOSTILE, + create_monster( MONS_SPATIAL_VORTEX, 3, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250 ); break; } @@ -2319,7 +2319,7 @@ bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail, for (loopj = 0; loopj < 2 + random2(3); loopj++) { - create_monster( MONS_SPATIAL_VORTEX, ENCH_ABJ_III, + create_monster( MONS_SPATIAL_VORTEX, 3, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250 ); } @@ -2411,13 +2411,13 @@ bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail, case 3: mpr("Space twists in upon itself!"); - create_monster( MONS_SPATIAL_VORTEX, ENCH_ABJ_III, BEH_HOSTILE, + create_monster( MONS_SPATIAL_VORTEX, 3, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250 ); break; case 4: case 5: - if (create_monster( summon_any_demon(DEMON_LESSER), ENCH_ABJ_V, + if (create_monster( summon_any_demon(DEMON_LESSER), 5, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250 ) != -1) { @@ -2434,7 +2434,7 @@ bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail, for (loopj = 0; loopj < 2 + random2(3); loopj++) { - create_monster( MONS_SPATIAL_VORTEX, ENCH_ABJ_III, + create_monster( MONS_SPATIAL_VORTEX, 3, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250 ); } @@ -2442,7 +2442,7 @@ bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail, case 1: case 2: - if (create_monster( summon_any_demon(DEMON_COMMON), ENCH_ABJ_V, + if (create_monster( summon_any_demon(DEMON_COMMON), 5, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250) != -1) { @@ -2454,24 +2454,24 @@ bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail, case 4: case 5: mpr("A chorus of chattering voices calls out to you!"); - create_monster( summon_any_demon(DEMON_LESSER), ENCH_ABJ_V, + create_monster( summon_any_demon(DEMON_LESSER), 5, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250 ); - create_monster( summon_any_demon(DEMON_LESSER), ENCH_ABJ_V, + create_monster( summon_any_demon(DEMON_LESSER), 5, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250 ); if (coinflip()) { - create_monster( summon_any_demon(DEMON_LESSER), ENCH_ABJ_V, + create_monster( summon_any_demon(DEMON_LESSER), 5, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250 ); } if (coinflip()) { - create_monster( summon_any_demon(DEMON_LESSER), ENCH_ABJ_V, + create_monster( summon_any_demon(DEMON_LESSER), 5, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250 ); } @@ -2502,17 +2502,17 @@ bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail, case 2: mpr("Something turns its malign attention towards you..."); - create_monster( summon_any_demon(DEMON_COMMON), ENCH_ABJ_III, + create_monster( summon_any_demon(DEMON_COMMON), 3, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250 ); - create_monster( summon_any_demon(DEMON_COMMON), ENCH_ABJ_III, + create_monster( summon_any_demon(DEMON_COMMON), 3, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250); if (coinflip()) { - create_monster(summon_any_demon(DEMON_COMMON), ENCH_ABJ_III, + create_monster(summon_any_demon(DEMON_COMMON), 3, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250); } @@ -2711,18 +2711,18 @@ bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail, case 0: mpr("Flickering shadows surround you."); - create_monster( MONS_SHADOW, ENCH_ABJ_II, BEH_HOSTILE, + create_monster( MONS_SHADOW, 2, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250 ); if (coinflip()) { - create_monster( MONS_SHADOW, ENCH_ABJ_II, BEH_HOSTILE, + create_monster( MONS_SHADOW, 2, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250 ); } if (coinflip()) { - create_monster( MONS_SHADOW, ENCH_ABJ_II, BEH_HOSTILE, + create_monster( MONS_SHADOW, 2, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250 ); } break; @@ -2783,7 +2783,7 @@ bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail, break; case 4: - if (create_monster( MONS_SOUL_EATER, ENCH_ABJ_IV, BEH_HOSTILE, + if (create_monster( MONS_SOUL_EATER, 4, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250) != -1) { mpr("Something reaches out for you..."); @@ -2791,7 +2791,7 @@ bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail, break; case 5: - if (create_monster( MONS_REAPER, ENCH_ABJ_IV, BEH_HOSTILE, + if (create_monster( MONS_REAPER, 4, BEH_HOSTILE, you.x_pos, you.y_pos, MHITYOU, 250) != -1) { mpr("Death has come for you..."); diff --git a/crawl-ref/source/stuff.h b/crawl-ref/source/stuff.h index fb55be530e..9c958361a1 100644 --- a/crawl-ref/source/stuff.h +++ b/crawl-ref/source/stuff.h @@ -107,8 +107,12 @@ inline bool testbits(unsigned long flags, unsigned long test) return ((flags & test) == test); } -bool is_trap_square(int x, int y); +inline int cap_int(int val, int cap) +{ + return (val > cap? cap : val); +} +bool is_trap_square(int x, int y); void zap_los_monsters(); #endif diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc index ebf7587c2c..9b1125d44c 100644 --- a/crawl-ref/source/tags.cc +++ b/crawl-ref/source/tags.cc @@ -1409,6 +1409,22 @@ static void tag_construct_level_items(struct tagHeader &th) marshall_item(th, mitm[i]); } +static void marshall_mon_enchant(tagHeader &th, const mon_enchant &me) +{ + marshallShort(th, me.ench); + marshallShort(th, me.degree); + marshallShort(th, me.who); +} + +static mon_enchant unmarshall_mon_enchant(tagHeader &th) +{ + mon_enchant me; + me.ench = static_cast<enchant_type>( unmarshallShort(th) ); + me.degree = unmarshallShort(th); + me.who = static_cast<kill_category>( unmarshallShort(th) ); + return (me); +} + static void marshall_monster(tagHeader &th, const monsters &m) { marshallByte(th, m.ac); @@ -1423,8 +1439,12 @@ static void marshall_monster(tagHeader &th, const monsters &m) marshallByte(th, m.target_y); marshallLong(th, m.flags); - for (int j = 0; j < NUM_MON_ENCHANTS; j++) - marshallByte(th, m.enchantment[j]); + marshallShort(th, m.enchantments.size()); + for (mon_enchant_list::const_iterator i = m.enchantments.begin(); + i != m.enchantments.end(); ++i) + { + marshall_mon_enchant(th, *i); + } marshallShort(th, m.type); marshallShort(th, m.hit_points); @@ -1457,8 +1477,6 @@ static void tag_construct_level_monsters(struct tagHeader &th) // how many monsters? marshallShort(th, MAX_MONSTERS); - // how many monster enchantments? - marshallByte(th, NUM_MON_ENCHANTS); // how many monster inventory slots? marshallByte(th, NUM_MONSTER_SLOTS); @@ -1574,8 +1592,9 @@ static void unmarshall_monster(tagHeader &th, monsters &m) m.target_y = unmarshallByte(th); m.flags = unmarshallLong(th); - for (int j = 0; j < NUM_MON_ENCHANTS; j++) - m.enchantment[j] = unmarshallByte(th); + const int nenchs = unmarshallShort(th); + for (int i = 0; i < nenchs; ++i) + m.enchantments.insert( unmarshall_mon_enchant(th) ); m.type = unmarshallShort(th); m.hit_points = unmarshallShort(th); @@ -1599,7 +1618,7 @@ static void unmarshall_monster(tagHeader &th, monsters &m) static void tag_read_level_monsters(struct tagHeader &th, char minorVersion) { int i; - int count, ecount, icount; + int count, icount; // how many mons_alloc? count = unmarshallByte(th); @@ -1608,8 +1627,6 @@ static void tag_read_level_monsters(struct tagHeader &th, char minorVersion) // how many monsters? count = unmarshallShort(th); - // how many monster enchantments? - ecount = unmarshallByte(th); // how many monster inventory slots? icount = unmarshallByte(th); @@ -1675,7 +1692,7 @@ void tag_missing_level_attitude() new_beh = BEH_SEEK; break; case 7: // old BEH_ENSLAVED - if (!mons_has_ench(&menv[i], ENCH_CHARM)) + if (!menv[i].has_ench(ENCH_CHARM)) isFriendly = true; break; default: diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc index cd5d8fcaa1..e7b444efa1 100644 --- a/crawl-ref/source/view.cc +++ b/crawl-ref/source/view.cc @@ -729,7 +729,7 @@ bool check_awaken(int mons_aw) if (mon_holy == MH_NATURAL) { // monster is "hibernating"... reduce chance of waking - if (mons_has_ench( monster, ENCH_SLEEP_WARY )) + if (monster->has_ench(ENCH_SLEEP_WARY)) mons_perc -= 10; } else // unnatural creature |