diff options
-rw-r--r-- | crawl-ref/source/beam.cc | 123 | ||||
-rw-r--r-- | crawl-ref/source/beam.h | 3 | ||||
-rw-r--r-- | crawl-ref/source/cloud.cc | 7 | ||||
-rw-r--r-- | crawl-ref/source/enum.h | 4 | ||||
-rw-r--r-- | crawl-ref/source/externs.h | 4 | ||||
-rw-r--r-- | crawl-ref/source/item_use.cc | 153 | ||||
-rw-r--r-- | crawl-ref/source/item_use.h | 2 | ||||
-rw-r--r-- | crawl-ref/source/mon-util.cc | 58 | ||||
-rw-r--r-- | crawl-ref/source/mon-util.h | 18 | ||||
-rw-r--r-- | crawl-ref/source/monplace.cc | 3 | ||||
-rw-r--r-- | crawl-ref/source/monplace.h | 37 | ||||
-rw-r--r-- | crawl-ref/source/monstuff.cc | 140 | ||||
-rw-r--r-- | crawl-ref/source/mstuff2.cc | 172 | ||||
-rw-r--r-- | crawl-ref/source/mstuff2.h | 4 | ||||
-rw-r--r-- | crawl-ref/source/spells1.cc | 16 | ||||
-rw-r--r-- | crawl-ref/source/spells2.cc | 6 | ||||
-rw-r--r-- | crawl-ref/source/spells3.cc | 2 | ||||
-rw-r--r-- | crawl-ref/source/spl-cast.cc | 13 | ||||
-rw-r--r-- | crawl-ref/source/view.cc | 4 | ||||
-rw-r--r-- | crawl-ref/source/xom.cc | 7 |
20 files changed, 527 insertions, 249 deletions
diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc index bde83713a3..d7d7a3dd47 100644 --- a/crawl-ref/source/beam.cc +++ b/crawl-ref/source/beam.cc @@ -93,6 +93,8 @@ static void _zappy(zap_type z_type, int power, bolt &pbolt); static bool _nasty_beam(monsters *mon, const bolt &beam); static bool _nice_beam(monsters *mon, const bolt &beam); +static beam_type _chaos_beam_flavour(); + static std::set<std::string> beam_message_cache; static bool _beam_is_blockable(bolt &pbolt) @@ -146,10 +148,6 @@ void zap_animation(int colour, const monsters *mon, bool force) { coord_def p = you.pos(); - // Default to whatever colour magic is today. - if (colour == -1) - colour = element_colour(EC_MAGIC); - if (mon) { if (!force && !player_monster_visible( mon )) @@ -165,6 +163,10 @@ void zap_animation(int colour, const monsters *mon, bool force) if (in_los_bounds(drawp)) { + // Default to whatever colour magic is today. + if (colour == -1) + colour = EC_MAGIC; + #ifdef USE_TILE tiles.add_overlay(p, tileidx_zap(colour)); #else @@ -185,6 +187,8 @@ static void _ench_animation( int flavour, const monsters *mon, bool force ) (flavour == BEAM_PAIN) ? EC_UNHOLY : (flavour == BEAM_DISPEL_UNDEAD) ? EC_HOLY : (flavour == BEAM_POLYMORPH) ? EC_MUTAGENIC : + (flavour == BEAM_CHAOS + || flavour == BEAM_RANDOM) ? EC_RANDOM : (flavour == BEAM_TELEPORT || flavour == BEAM_BANISH || flavour == BEAM_BLINK) ? EC_WARP @@ -201,6 +205,7 @@ static void _beam_set_default_values(bolt &beam, int power) beam.damage = dice_def( 1, 0 ); // default for "0" beams (I think) beam.type = 0; // default for "0" beams beam.flavour = BEAM_MAGIC; // default for "0" beams + beam.real_flavour = BEAM_MAGIC; // default for "0" beams beam.ench_power = power; beam.obvious_effect = false; beam.is_beam = false; // default for all beams. @@ -1348,6 +1353,7 @@ static void _zappy( zap_type z_type, int power, bolt &pbolt ) // Fill pbolt.name = zinfo->name; pbolt.flavour = zinfo->flavour; + pbolt.real_flavour = zinfo->flavour; pbolt.colour = zinfo->colour; pbolt.type = dchar_glyph(zinfo->glyph); pbolt.obvious_effect = zinfo->always_obvious; @@ -1405,6 +1411,33 @@ static bool _affect_mon_in_wall(bolt &pbolt, item_def *item, return (false); } +static beam_type _chaos_beam_flavour() +{ + const beam_type flavour = static_cast<beam_type>( + random_choose_weighted( + 10, BEAM_FIRE, + 10, BEAM_COLD, + 10, BEAM_ELECTRICITY, + 10, BEAM_POISON, + 10, BEAM_NEG, + 10, BEAM_ACID, + 10, BEAM_HELLFIRE, + 10, BEAM_NAPALM, + 10, BEAM_HELLFROST, + 10, BEAM_SLOW, + 10, BEAM_HASTE, + 10, BEAM_HEALING, + 10, BEAM_PARALYSIS, + 10, BEAM_CONFUSION, + 10, BEAM_INVISIBILITY, + 10, BEAM_POLYMORPH, + 10, BEAM_BANISH, + 10, BEAM_DISINTEGRATION, + 0 )); + + return (flavour); +} + /* * Beam pseudo code: * @@ -1432,6 +1465,8 @@ static bool _affect_mon_in_wall(bolt &pbolt, item_def *item, void fire_beam(bolt &pbolt) { + pbolt.real_flavour = pbolt.flavour; + const int reflections = pbolt.reflections; if (reflections == 0) { @@ -1536,6 +1571,13 @@ void fire_beam(bolt &pbolt) { testpos = ray.pos(); + // Random beams: randomize before affect(). + if (pbolt.real_flavour == BEAM_RANDOM) + pbolt.flavour = static_cast<beam_type>( + random_range(BEAM_FIRE, BEAM_ACID)); + else if (pbolt.real_flavour == BEAM_CHAOS) + pbolt.flavour = _chaos_beam_flavour(); + // Shooting through clouds affects accuracy. if (env.cgrid(testpos) != EMPTY_CLOUD) pbolt.hit = std::max(pbolt.hit - 2, 0); @@ -1628,14 +1670,6 @@ void fire_beam(bolt &pbolt) // hit and the beam is type 'term on target'. if (!beamTerminate || !pbolt.is_explosion) { - // Random beams: randomize before affect(). - bool random_beam = false; - if (pbolt.flavour == BEAM_RANDOM) - { - random_beam = true; - pbolt.flavour = static_cast<beam_type>( - random_range(BEAM_FIRE, BEAM_ACID)); - } if (!pbolt.affects_nothing) { @@ -1643,12 +1677,6 @@ void fire_beam(bolt &pbolt) if (pbolt.reflections > reflections) return; } - - if (random_beam) - { - pbolt.flavour = BEAM_RANDOM; - pbolt.effect_known = false; - } } ASSERT(pbolt.reflections == reflections); @@ -1667,8 +1695,13 @@ void fire_beam(bolt &pbolt) if (pbolt.aimed_at_feet) beamTerminate = true; - // Actually draw the beam/missile/whatever, - // if the player can see the cell. + // Reset chaos beams so that it won't be considered an invisible + // enchantment beam for the purposes of animation. + if (pbolt.real_flavour == BEAM_CHAOS) + pbolt.flavour = pbolt.real_flavour; + + // Actually draw the beam/missile/whatever, if the player can see + // the cell. if (!pbolt.is_tracer && !pbolt.is_enchantment() && see_grid(testpos)) { // We don't clean up the old position. @@ -1696,7 +1729,8 @@ void fire_beam(bolt &pbolt) #ifndef USE_TILE cgotoxy(drawpos.x, drawpos.y); put_colour_ch( - pbolt.colour == BLACK ? random_colour() : pbolt.colour, + pbolt.colour == BLACK ? random_colour() + : element_colour(pbolt.colour), pbolt.type ); #endif // Get curses to update the screen so we can see the beam. @@ -2663,6 +2697,13 @@ void mimic_alert(monsters *mimic) static bool _isBouncy(bolt &beam, unsigned char gridtype) { + if ( beam.real_flavour == BEAM_CHAOS + && grid_is_solid(static_cast<dungeon_feature_type>(gridtype)) + && coinflip() ) + { + return (true); + } + if (beam.is_enchantment()) return (false); @@ -3378,7 +3419,7 @@ static void _affect_place_explosion_clouds(bolt &beam, const coord_def& p) _whose_kill(beam) == KC_OTHER ? BEH_HOSTILE : BEH_FRIENDLY; mons_place( - mgen_data(MONS_FIRE_VORTEX, att, 2, p, + mgen_data(MONS_FIRE_VORTEX, att, 2, SPELL_FIRE_STORM, p, MHITNOT, 0, god)); } } @@ -3616,6 +3657,8 @@ static void _reflect_beam(bolt &beam) #endif } + beam.flavour = beam.real_flavour; + fire_beam(beam); } @@ -3809,7 +3852,7 @@ static int _affect_player( bolt &beam, item_def *item, bool affect_items ) return (_range_used_on_hit(beam)); } - _ench_animation( beam.flavour ); + _ench_animation( beam.real_flavour ); // these colors are misapplied - see mons_ench_f2() {dlb} switch (beam.flavour) @@ -4404,7 +4447,7 @@ static int _affect_monster(bolt &beam, monsters *mon, item_def *item) // Doing this here so that the player gets to see monsters // "flicker and vanish" when turning invisible.... - _ench_animation( beam.flavour, mon ); + _ench_animation( beam.real_flavour, mon ); // now do enchantment affect mon_resist_type ench_result = _affect_monster_enchantment(beam, mon); @@ -5184,6 +5227,8 @@ int explosion( bolt &beam, bool hole_in_the_middle, bool explode_in_wall, bool stop_at_statues, bool stop_at_walls, bool show_more, bool affect_items) { + beam.real_flavour = beam.flavour; + if (in_bounds(beam.source) && beam.source != beam.target && (!explode_in_wall || stop_at_statues || stop_at_walls)) { @@ -5398,23 +5443,20 @@ int explosion( bolt &beam, bool hole_in_the_middle, static void _explosion_cell(bolt &beam, const coord_def& p, bool drawOnly, bool affect_items) { - bool random_beam = false; coord_def realpos = beam.target + p; if (!drawOnly) { - // Random beams: randomize before affect(). - if (beam.flavour == BEAM_RANDOM) - { - random_beam = true; + // Random/chaos beams: randomize before affect(). + if (beam.real_flavour == BEAM_RANDOM) beam.flavour = static_cast<beam_type>( random_range(BEAM_FIRE, BEAM_ACID) ); - } + else if (beam.real_flavour == BEAM_CHAOS) + beam.flavour = _chaos_beam_flavour(); affect(beam, realpos, NULL, affect_items); - if (random_beam) - beam.flavour = BEAM_RANDOM; + beam.flavour = beam.real_flavour; } // Early out for tracer. @@ -5580,14 +5622,15 @@ static bool _nice_beam(monsters *mon, const bolt &beam) // (extended from setup_mons_cast() and zapping() which act as limited ones). bolt::bolt() : range(0), type('*'), colour(BLACK), - flavour(BEAM_MAGIC), drop_item(false), item(NULL), source(), - target(), pos(), damage(0,0), ench_power(0), hit(0), - thrower(KILL_MISC), ex_size(0), beam_source(MHITNOT), name(), - is_beam(false), is_explosion(false), is_big_cloud(false), - aimed_at_spot(false), aux_source(), affects_nothing(false), - effect_known(true), obvious_effect(false), fr_count(0), - foe_count(0), fr_power(0), foe_power(0), fr_hurt(0), - foe_hurt(0), fr_helped(0), foe_helped(0), + flavour(BEAM_MAGIC), real_flavour(BEAM_MAGIC), drop_item(false), + item(NULL), source(), target(), pos(), damage(0,0), + ench_power(0), hit(0), thrower(KILL_MISC), ex_size(0), + beam_source(MHITNOT), name(), is_beam(false), + is_explosion(false), is_big_cloud(false), aimed_at_spot(false), + aux_source(), affects_nothing(false), effect_known(true), + obvious_effect(false), + fr_count(0), foe_count(0), fr_power(0), foe_power(0), + fr_hurt(0), foe_hurt(0), fr_helped(0),foe_helped(0), dropped_item(false), item_pos(), item_index(NON_ITEM), range_used(0), is_tracer(false), aimed_at_feet(false), msg_generated(false), in_explosion_phase(false), diff --git a/crawl-ref/source/beam.h b/crawl-ref/source/beam.h index 69d12c6051..c805611783 100644 --- a/crawl-ref/source/beam.h +++ b/crawl-ref/source/beam.h @@ -40,6 +40,9 @@ struct bolt unsigned type; // missile gfx int colour; beam_type flavour; + beam_type real_flavour; // for random and chaos beams this + // will remain the same while flavour + // changes bool drop_item; // should drop an item when done item_def* item; // item to drop coord_def source; // beam origin diff --git a/crawl-ref/source/cloud.cc b/crawl-ref/source/cloud.cc index daed16067d..f664ccc5c3 100644 --- a/crawl-ref/source/cloud.cc +++ b/crawl-ref/source/cloud.cc @@ -411,6 +411,8 @@ cloud_type beam2cloud(beam_type flavour) case BEAM_MIASMA: case BEAM_POTION_MIASMA: return CLOUD_MIASMA; + case BEAM_CHAOS: + return CLOUD_CHAOS; case BEAM_RANDOM: return CLOUD_RANDOM; } @@ -443,6 +445,8 @@ beam_type cloud2beam(cloud_type flavour) return BEAM_STEAM; case CLOUD_MIASMA: return BEAM_MIASMA; + case CLOUD_CHAOS: + return BEAM_CHAOS; case CLOUD_RANDOM: return BEAM_RANDOM; } @@ -619,6 +623,7 @@ bool is_damaging_cloud(cloud_type type, bool temp) // ... unless a Ring of Flames is up and it's a fire cloud. if (temp && you.duration[DUR_FIRE_SHIELD]) return (false); + case CLOUD_CHAOS: case CLOUD_COLD: return (true); @@ -682,6 +687,8 @@ std::string cloud_name(cloud_type type) return "black smoke"; case CLOUD_MIST: return "thin mist"; + case CLOUD_CHAOS: + return "seething chaos"; default: return "buggy goodness"; } diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h index e8eaf0cf59..4523d77359 100644 --- a/crawl-ref/source/enum.h +++ b/crawl-ref/source/enum.h @@ -209,7 +209,7 @@ enum beam_type // beam[].flavour BEAM_ICE, BEAM_NUKE, BEAM_RANDOM, // currently translates into FIRE..ACID - // 24 + BEAM_CHAOS, // Enchantments BEAM_FIRST_ENCHANTMENT = 25, // 25 @@ -411,6 +411,7 @@ enum cloud_type CLOUD_STEAM, CLOUD_MIASMA, CLOUD_MIST, + CLOUD_CHAOS, CLOUD_RANDOM = 98, CLOUD_DEBUGGING = 99 // 99: used once as 'nonexistent cloud' {dlb} }; @@ -3016,6 +3017,7 @@ enum zap_type ZAP_PETRIFY, ZAP_ENSLAVE_SOUL, ZAP_HELLFROST, + ZAP_CHAOS, NUM_ZAPS }; diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h index fe7983ae6a..44d6910904 100644 --- a/crawl-ref/source/externs.h +++ b/crawl-ref/source/externs.h @@ -1237,7 +1237,9 @@ public: void init_experience(); - void mark_summoned(int longevity, bool mark_items_summoned ); + void mark_summoned(int longevity, bool mark_items_summoned, + int summon_type = 0); + bool is_summoned(int* duration = NULL, int* summon_type = NULL) const; bool has_action_energy() const; void check_redraw(const coord_def &oldpos) const; void apply_location_effects(const coord_def &oldpos); diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc index bb053758d6..51250a0145 100644 --- a/crawl-ref/source/item_use.cc +++ b/crawl-ref/source/item_use.cc @@ -1748,140 +1748,6 @@ void _merge_ammo_in_inventory(int slot) } } -std::string setup_chaos_ammo(bolt &pbolt, item_def ammo) -{ - ASSERT(!is_artefact(ammo)); - - const bool poisoned = (get_ammo_brand(ammo) == SPMSL_POISONED); - - // Don't choose BEAM_POISON or BEAM_HEALING if we have poisoned ammo. - const int pois_weight = poisoned ? 0 : 10; - const int heal_weight = poisoned ? 0 : 10; - - const beam_type flavour = static_cast<beam_type>( - random_choose_weighted( pois_weight, BEAM_POISON, - heal_weight, BEAM_HEALING, - - 10, BEAM_FIRE, - 10, BEAM_COLD, - 10, BEAM_ELECTRICITY, - 10, BEAM_NEG, - 10, BEAM_ACID, - 10, BEAM_HELLFIRE, - 10, BEAM_NAPALM, - 10, BEAM_HELLFROST, - 10, BEAM_SLOW, - 10, BEAM_HASTE, - 10, BEAM_PARALYSIS, - 10, BEAM_CONFUSION, - 10, BEAM_INVISIBILITY, - 10, BEAM_POLYMORPH, - 10, BEAM_BANISH, - 10, BEAM_DISINTEGRATION, - 0 )); - - std::string name; - int colour; - - if (poisoned) - name = "poison "; - - switch(flavour) - { - case BEAM_POISON: - name += "poison"; - colour = EC_POISON; - break; - case BEAM_HEALING: - name += "healing"; - colour = EC_HEAL; - break; - case BEAM_FIRE: - name += "flame"; - colour = EC_FIRE; - break; - case BEAM_COLD: - name += "frost"; - colour = EC_ICE; - break; - case BEAM_ELECTRICITY: - name += "lightning"; - colour = EC_ELECTRICITY; - break; - case BEAM_NEG: - name += "negative energy"; - colour = EC_NECRO; - break; - case BEAM_ACID: - name += "acid"; - colour = YELLOW; - break; - case BEAM_HELLFIRE: - name += "hellfire"; - colour = EC_FIRE; - break; - case BEAM_NAPALM: - name += "sticky fire"; - colour = EC_FIRE; - break; - case BEAM_HELLFROST: - name += "hellfrost"; - colour = EC_ICE; - break; - case BEAM_SLOW: - name += "slowing"; - colour = EC_ENCHANT; - break; - case BEAM_HASTE: - name += "hasting"; - colour = EC_ENCHANT; - break; - case BEAM_PARALYSIS: - name += "paralysis"; - colour = EC_ENCHANT; - break; - case BEAM_CONFUSION: - name += "confusion"; - colour = EC_ENCHANT; - break; - case BEAM_INVISIBILITY: - name += "invisibility"; - colour = EC_ENCHANT; - break; - case BEAM_POLYMORPH: - name += "polymorphing"; - colour = EC_MUTAGENIC; - break; - case BEAM_BANISH: - name += "banishment"; - colour = EC_WARP; - break; - case BEAM_DISINTEGRATION: - name += "disintegration"; - colour = EC_DEATH; - break; - default: - ASSERT(!"Invalid chaos ammo flavour."); - break; - } - - pbolt.name = "bolt of "; - pbolt.name += name; - - pbolt.flavour = flavour; - pbolt.colour = colour; - pbolt.type = dchar_glyph(DCHAR_FIRED_BOLT); - - // Get name for a plain arrow/bolt/dart/needle. - ammo.special = 0; - - std::string ammo_name = ammo.name(DESC_NOCAP_A); - ammo_name += " of "; - ammo_name += name; - - return ammo_name; -} - // throw_it - currently handles player throwing only. Monster // throwing is handled in mstuff2:mons_throw() // Note: If teleport is true, assume that pbolt is already set up, @@ -2542,12 +2408,23 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus, // Chaos overides flame and frost/ice. if (bow_brand == SPWPN_CHAOS || ammo_brand == SPMSL_CHAOS) { - ammo_name = setup_chaos_ammo(pbolt, item); + // Chaos can't be poisoned, since that might conflict with + // the random healing effect or overlap with the random + // poisoning effect. + poisoned = false; // [dshaligram] Branded arrows are much stronger. dice_mult = (dice_mult * 150) / 100; pbolt.effect_known = false; + + pbolt.flavour = BEAM_CHAOS; + pbolt.name = "bolt of chaos"; + + pbolt.colour = EC_RANDOM; + pbolt.type = dchar_glyph(DCHAR_FIRED_BOLT); + pbolt.thrower = KILL_YOU_MISSILE; + pbolt.aux_source.clear(); } else if ((bow_brand == SPWPN_FLAME || ammo_brand == SPMSL_FLAME) && ammo_brand != SPMSL_ICE && bow_brand != SPWPN_FROST) @@ -2664,7 +2541,11 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus, item_def ammo = item; if (ammo.base_type == OBJ_MISSILES) { - if (pbolt.flavour == BEAM_FIRE) + if (pbolt.flavour == BEAM_CHAOS) + { + ammo.special = SPMSL_CHAOS; + } + else if (pbolt.flavour == BEAM_FIRE) { if (ammo.special != SPMSL_FLAME) ammo.special = SPMSL_FLAME; diff --git a/crawl-ref/source/item_use.h b/crawl-ref/source/item_use.h index c6f5820b18..31009b522e 100644 --- a/crawl-ref/source/item_use.h +++ b/crawl-ref/source/item_use.h @@ -160,8 +160,6 @@ bool puton_item(int slot, bool prompt_finger = true); bool enchant_weapon(enchant_stat_type which_stat, bool quiet, item_def &wpn); bool enchant_armour(int &ac_change, bool quiet, item_def &arm); -std::string setup_chaos_ammo(bolt &pbolt, item_def item); - bool throw_it(bolt &pbolt, int throw_2, bool teleport = false, int acc_bonus = 0, dist *target = NULL); diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc index 8421a7eb0a..88eeeabbd6 100644 --- a/crawl-ref/source/mon-util.cc +++ b/crawl-ref/source/mon-util.cc @@ -2316,9 +2316,53 @@ bool mons_self_destructs(const monsters *m) return (m->type == MONS_GIANT_SPORE || m->type == MONS_BALL_LIGHTNING); } -bool mons_is_summoned(const monsters *m) +bool mons_is_summoned(const monsters *m, int *duration, int *summon_type) { - return (m->has_ench(ENCH_ABJ)); + const mon_enchant abj = m->get_ench(ENCH_ABJ); + if (abj.ench == ENCH_NONE) + { + if (duration != NULL) + *duration = -1; + if (summon_type != NULL) + *summon_type = 0; + + return (false); + } + if (duration != NULL) + *duration = abj.duration; + + const mon_enchant summ = m->get_ench(ENCH_SUMMON); + if (summ.ench == ENCH_NONE) + { + if (summon_type != NULL) + *summon_type = 0; + + return (true); + } + if (summon_type != NULL) + *summon_type = summ.degree; + + switch(summ.degree) + { + // Temporarily dancing weapons are really there. + case SPELL_TUKIMAS_DANCE: + + // A corpse/skeleton which was temporarily animated. + case SPELL_ANIMATE_DEAD: + case SPELL_ANIMATE_SKELETON: + + // Fire vortices are made from real fire. + case SPELL_FIRE_STORM: + + // Clones aren't really summoned (though their equipment might be). + case MON_SUMM_CLONE: + + // Some object which was animated, and thus not really summoned. + case MON_SUMM_ANIMATE: + return (false); + } + + return (true); } bool mons_is_shapeshifter(const monsters *m) @@ -6619,9 +6663,12 @@ void monsters::apply_enchantment(const mon_enchant &me) } } -void monsters::mark_summoned(int longevity, bool mark_items) +void monsters::mark_summoned(int longevity, bool mark_items, int summon_type) { add_ench( mon_enchant(ENCH_ABJ, longevity) ); + if (summon_type != 0) + add_ench( mon_enchant(ENCH_SUMMON, summon_type, KC_OTHER, INT_MAX) ); + if (mark_items) { for (int i = 0; i < NUM_MONSTER_SLOTS; ++i) @@ -6633,6 +6680,11 @@ void monsters::mark_summoned(int longevity, bool mark_items) } } +bool monsters::is_summoned(int* duration, int* summon_type) const +{ + return mons_is_summoned(this, duration, summon_type); +} + void monsters::apply_enchantments() { if (enchantments.empty()) diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h index b7536dee3f..4360ea4553 100644 --- a/crawl-ref/source/mon-util.h +++ b/crawl-ref/source/mon-util.h @@ -85,6 +85,21 @@ enum mon_attack_flavour AF_STEAL_FOOD }; +// Non-spell "summoning" types to give to monsters::mark_summoned(), or as +// the fourth paramater of mgen_data's second constructor. +// +// Negative values since spells are non-negative. +enum mon_summon_type +{ + MON_SUMM_CLONE = -10000, // Cloned from another monster + MON_SUMM_ANIMATE, // Item/feature/substance which was animated + MON_SUMM_CHAOS, // Was made from pure chaos + MON_SUMM_MISCAST, // Spell miscast + MON_SUMM_ZOT, // Zot trap + MON_SUMM_WRATH, // Divine wrath + MON_SUMM_AID // Divine aid +}; + // properties of the monster class (other than resists/vulnerabilities) enum mons_class_flags { @@ -547,7 +562,8 @@ bool mons_is_demon( int mc ); bool mons_class_wields_two_weapons(int mc); bool mons_wields_two_weapons(const monsters *m); bool mons_self_destructs(const monsters *m); -bool mons_is_summoned(const monsters *m); +bool mons_is_summoned(const monsters *m, int* duration = NULL, + int *summon_info = NULL); bool mons_is_shapeshifter(const monsters *m); // last updated 12may2000 {dlb} diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc index 2bb70188b6..dc3d6f7af2 100644 --- a/crawl-ref/source/monplace.cc +++ b/crawl-ref/source/monplace.cc @@ -947,7 +947,8 @@ static int _place_monster_aux( const mgen_data &mg, // dur should always be 1-6 for monsters that can be abjured. if (mg.abjuration_duration >= 1 && mg.abjuration_duration <= 6) - menv[id].mark_summoned( mg.abjuration_duration, true ); + menv[id].mark_summoned( mg.abjuration_duration, true, + mg.summon_type ); menv[id].foe = mg.foe; diff --git a/crawl-ref/source/monplace.h b/crawl-ref/source/monplace.h index 4ddd2d1a21..2b4529e59f 100644 --- a/crawl-ref/source/monplace.h +++ b/crawl-ref/source/monplace.h @@ -127,6 +127,11 @@ struct mgen_data // that aren't summoned. int abjuration_duration; + // For summoned monsters this is their type of summoning, either the + // spell which summoned them or one of the values of the enumeration + // mon_summon_type in mon-util.h + int summon_type; + // Where the monster will be created. coord_def pos; @@ -189,10 +194,33 @@ struct mgen_data level_area_type ltype = you.level_type) : cls(mt), base_type(base), behaviour(beh), - abjuration_duration(abj), pos(p), foe(mfoe), flags(monflags), - god(which_god), number(monnumber), colour(moncolour), + abjuration_duration(abj), summon_type(0), pos(p), foe(mfoe), + flags(monflags), god(which_god), number(monnumber), colour(moncolour), + power(monpower), proximity(prox), level_type(ltype), map_mask(0) + { + } + + mgen_data(monster_type mt, + beh_type beh, + int abj, + int st, + const coord_def &p = coord_def(-1, -1), + unsigned short mfoe = MHITNOT, + unsigned monflags = 0, + god_type which_god = GOD_NO_GOD, + monster_type base = MONS_PROGRAM_BUG, + int monnumber = 0, + int moncolour = BLACK, + int monpower = you.your_level, + proximity_type prox = PROX_ANYWHERE, + level_area_type ltype = you.level_type) + + : cls(mt), base_type(base), behaviour(beh), + abjuration_duration(abj), summon_type(st), pos(p), foe(mfoe), + flags(monflags), god(which_god), number(monnumber), colour(moncolour), power(monpower), proximity(prox), level_type(ltype), map_mask(0) { + ASSERT(summon_type == 0 || (abj >= 1 && abj <= 6)); } bool permit_bands() const { return (flags & MG_PERMIT_BANDS); } @@ -217,9 +245,10 @@ struct mgen_data int abj_deg = 0, unsigned flags = 0, bool alert = false, - god_type god = GOD_NO_GOD) + god_type god = GOD_NO_GOD, + int summon_type = 0) { - return mgen_data(what, BEH_HOSTILE, abj_deg, where, + return mgen_data(what, BEH_HOSTILE, abj_deg, summon_type, where, alert ? MHITYOU : MHITNOT, flags, god); } diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc index a9cc692af0..e884628f9a 100644 --- a/crawl-ref/source/monstuff.cc +++ b/crawl-ref/source/monstuff.cc @@ -308,9 +308,23 @@ void monster_drop_ething(monsters *monster, bool mark_item_origins, mprf(MSGCH_SOUND, grid_item_destruction_message(grd(monster->pos()))); } -static void _place_monster_corpse(const monsters *monster) +static void _place_monster_corpse(const monsters *monster, bool silent, + int summon_type) { - int corpse_class = mons_species(monster->type); + bool force = false; + int corpse_class = mons_species(monster->type); + + // If this was a corpse that was temporarily animated then turn the + // monster back into a corpse. + if (mons_class_is_zombified(monster->type) + && (summon_type == SPELL_ANIMATE_DEAD + || summon_type == SPELL_ANIMATE_SKELETON + || summon_type == MON_SUMM_ANIMATE)) + { + force = true; + corpse_class = mons_zombie_base(monster); + } + if (corpse_class == MONS_DRACONIAN) corpse_class = draco_subspecies(monster); @@ -321,7 +335,7 @@ static void _place_monster_corpse(const monsters *monster) // Doesn't leave a corpse. if (mons_weight(corpse_class) == 0 || mons_enslaved_body_and_soul(monster) - || coinflip()) + || (!force && coinflip())) { return; } @@ -355,7 +369,15 @@ static void _place_monster_corpse(const monsters *monster) move_item_to_grid( &o, monster->pos() ); if (see_grid(monster->pos())) { - const bool poison = (mons_corpse_effect(monster->type) == CE_POISONOUS + if (force && !silent) + { + if (you.can_see(monster)) + simple_monster_message(monster, " turns back into a corpse!"); + else + mprf("%s appears out of nowhere!", + mitm[o].name(DESC_CAP_A).c_str()); + } + const bool poison = (mons_corpse_effect(corpse_class) == CE_POISONOUS && player_res_poison() <= 0); tutorial_dissection_reminder(!poison); } @@ -864,6 +886,76 @@ static void _spore_goes_pop(monsters *monster, killer_type killer, mgrd(monster->pos()) = monster_index(monster); } +void _monster_die_cloud(const monsters* monster, bool corpse, bool silent, + bool summoned, int summon_type) +{ + // Chaos spawn always leave behind a cloud of chaos. + if (monster->type == MONS_CHAOS_SPAWN) + { + summoned = true; + corpse = false; + } + + if (!summoned) + return; + + std::string prefix; + std::string msg = " disappears in a puff of smoke!"; + cloud_type cloud = random_smoke_type(); + int dur = 1 + random2(3); + + if (corpse) + { + if (mons_weight(mons_species(monster->type)) == 0) + return; + + prefix = "'s corpse"; + } + + switch(summon_type) + { + case SPELL_SHADOW_CREATURES: + msg = " disolves into shadows!"; + cloud = CLOUD_NONE; + break; + + case MON_SUMM_CHAOS: + msg = " degenerates into a cloud of primal chaos!"; + cloud = CLOUD_CHAOS; + break; + + case MON_SUMM_WRATH: + case MON_SUMM_AID: + if (is_good_god(monster->god)) + { + msg = " disolves into sparkling lights!"; + cloud = CLOUD_NONE; + } + break; + } + + if (monster->god == GOD_XOM && one_chance_in(10) + || cloud != CLOUD_NONE && monster->type == MONS_CHAOS_SPAWN) + { + msg = " degenerates into a cloud of primal chaos!"; + cloud = CLOUD_CHAOS; + } + + if (mons_is_holy(monster) && summon_type != SPELL_SHADOW_CREATURES + && summon_type != MON_SUMM_CHAOS) + { + msg = " disolves into sparkling lights!"; + cloud = CLOUD_NONE; + } + + if (!silent) + simple_monster_message(monster, (prefix + msg).c_str()); + + if (cloud != CLOUD_NONE) + place_cloud( cloud, monster->pos(), dur, + monster->kill_alignment() ); +} + void monster_die(monsters *monster, killer_type killer, int killer_index, bool silent, bool wizard) { @@ -882,9 +974,11 @@ void monster_die(monsters *monster, killer_type killer, if (mons_near(monster) || wizard) remove_auto_exclude(monster); + int summon_type = 0; + const bool summoned = mons_is_summoned(monster, NULL, &summon_type); const int monster_killed = monster_index(monster); const bool hard_reset = testbits(monster->flags, MF_HARD_RESET); - const bool gives_xp = !mons_is_summoned(monster) + const bool gives_xp = !summoned && !mons_enslaved_body_and_soul(monster); const bool drop_items = !hard_reset && !mons_is_holy(monster); @@ -1372,15 +1466,9 @@ void monster_die(monsters *monster, killer_type killer, // Monster doesn't die, just goes back to wherever it came from // This must only be called by monsters running out of time (or // abjuration), because it uses the beam variables! Or does it??? - if (!silent) - { - simple_monster_message( monster, - " disappears in a puff of smoke!" ); - } - - place_cloud( random_smoke_type(), - monster->pos(), 1 + random2(3), - monster->kill_alignment() ); + if (!wizard) + _monster_die_cloud(monster, false, silent, summoned, + summon_type); // KILL_RESET monsters no longer lose their whole inventory, only // items they were generated with. @@ -1462,23 +1550,10 @@ void monster_die(monsters *monster, killer_type killer, curr_PlaceInfo += delta; curr_PlaceInfo.assert_validity(); - if (monster->has_ench(ENCH_ABJ)) - { - if (mons_weight(mons_species(monster->type))) - { - simple_monster_message(monster, - "'s corpse disappears in a puff of smoke!"); - - place_cloud( random_smoke_type(), - monster->pos(), 1 + random2(3), - monster->kill_alignment() ); - } - } - else - { + _monster_die_cloud(monster, true, silent, summoned, summon_type); + if (!summoned) // Have to add case for disintegration effect here? {dlb} - _place_monster_corpse(monster); - } + _place_monster_corpse(monster, silent, summon_type); } _fire_monster_death_event(monster, killer, killer_index); @@ -1767,6 +1842,7 @@ bool monster_polymorph(monsters *monster, monster_type targetc, mon_enchant neutral = monster->get_ench(ENCH_NEUTRAL); mon_enchant shifter = monster->get_ench(ENCH_GLOWING_SHAPESHIFTER, ENCH_SHAPESHIFTER); + mon_enchant summon = monster->get_ench(ENCH_SUMMON); mon_enchant tp = monster->get_ench(ENCH_TP); // Note: define_monster() will clear out all enchantments! -- bwr @@ -1776,6 +1852,7 @@ bool monster_polymorph(monsters *monster, monster_type targetc, monster->add_ench(charm); monster->add_ench(neutral); monster->add_ench(shifter); + monster->add_ench(summon); monster->add_ench(tp); monster->ench_countdown = old_ench_countdown; @@ -1783,8 +1860,7 @@ bool monster_polymorph(monsters *monster, monster_type targetc, if (mons_class_flag(monster->type, M_INVIS)) monster->add_ench(ENCH_INVIS); - if (!player_messaged && mons_near(monster) - && player_monster_visible(monster)) + if (!player_messaged && you.can_see(monster)) { mprf("%s appears out of thin air!", monster->name(DESC_CAP_A).c_str()); player_messaged = true; diff --git a/crawl-ref/source/mstuff2.cc b/crawl-ref/source/mstuff2.cc index 76ab701b82..0c6a7a269e 100644 --- a/crawl-ref/source/mstuff2.cc +++ b/crawl-ref/source/mstuff2.cc @@ -203,6 +203,7 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast) { create_monster( mgen_data(RANDOM_MONSTER, SAME_ATTITUDE(monster), 5, + SPELL_SHADOW_CREATURES, monster->pos(), monster->foe)); } return; @@ -931,9 +932,9 @@ bool mons_throw(struct monsters *monster, struct bolt &pbolt, int hand_used) // fire/ice and incorrect ammo. They now have the same restrictions // as players. - int bow_brand = SPWPN_NORMAL; - const int ammo_brand = get_ammo_brand(item); - const bool poison = (ammo_brand == SPMSL_POISONED); + int bow_brand = SPWPN_NORMAL; + const int ammo_brand = get_ammo_brand(item); + bool poison = (ammo_brand == SPMSL_POISONED); if (projected == LRET_LAUNCHED) { @@ -1044,9 +1045,19 @@ bool mons_throw(struct monsters *monster, struct bolt &pbolt, int hand_used) // Chaos overides flame and frost if (bow_brand == SPWPN_CHAOS || ammo_brand == SPMSL_CHAOS) { - (void) setup_chaos_ammo(pbolt, item); - baseHit += 2; + // Chaos can't be poisoned, since that might conflict with + // the random healing effect or overlap with the random + // poisoning effect. + poison = false; + + baseHit += 2; exDamBonus += 6; + + pbolt.flavour = BEAM_CHAOS; + pbolt.name = "bolt of chaos"; + + pbolt.colour = EC_RANDOM; + pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); } // WEAPON or AMMO of FIRE else if (bow_brand == SPWPN_FLAME && ammo_brand != SPMSL_ICE @@ -1797,27 +1808,36 @@ static int _monster_abjure_square(const coord_def &pos, if (!target->alive() || ((bool)wont_attack == mons_wont_attack(target))) return (0); - mon_enchant abj = target->get_ench(ENCH_ABJ); - if (abj.ench == ENCH_NONE) + int duration; + + if (!target->is_summoned(&duration)) return (0); pow = std::max(20, fuzz_value(pow, 40, 25)); if (!actual) - return (pow > 40 || pow >= abj.duration); + return (pow > 40 || pow >= duration); // TSO and Trog's abjuration protection. + bool shielded = false; if (you.religion == GOD_SHINING_ONE) { pow = pow * (30 - target->hit_dice) / 30; - if (pow < abj.duration) - simple_god_message(" protects your fellow warrior from evil magic!"); + if (pow < duration) + { + simple_god_message(" protects your fellow warrior from evil " + "magic!"); + shielded = true; + } } else if (you.religion == GOD_TROG) { pow = pow * 4 / 5; - if (pow < abj.duration) + if (pow < duration) + { simple_god_message(" shields your ally from puny magic!"); + shielded = true; + } } else if (is_sanctuary(target->pos())) { @@ -1828,10 +1848,11 @@ static int _monster_abjure_square(const coord_def &pos, #ifdef DEBUG_DIAGNOSTICS mprf(MSGCH_DIAGNOSTICS, "Abj: dur: %d, pow: %d, ndur: %d", - abj.duration, pow, abj.duration - pow); + duration, pow, duration - pow); #endif - if (!target->lose_ench_duration(abj, pow)) + mon_enchant abj = target->get_ench(ENCH_ABJ); + if (!target->lose_ench_duration(abj, pow) && !shielded) simple_monster_message(target, " shudders."); return (1); @@ -2117,3 +2138,128 @@ void mons_clear_trapping_net(monsters *mon) mon->del_ench(ENCH_HELD, true); } + +bool mons_clonable(const monsters* mon, bool needs_adjacent) +{ + // No uniques, pandemonium lords or player ghosts. Also, figuring + // out the name for the clone of a named monster isn't worth it. + if (mons_is_unique(mon->type) || mon->is_named() || mon->ghost.get()) + return (false); + + if (needs_adjacent) + { + // Is there space for the clone? + bool square_found = false; + for (int i = 0; i < 8; i++) + { + const coord_def p = mon->pos() + Compass[i]; + + if (in_bounds(p) && p != you.pos() && mgrd(p) == NON_MONSTER + && monster_habitable_grid(mon, grd(p))) + { + square_found = true; + break; + } + } + if (!square_found) + return (false); + } + + // Is the monster carrying an artefact? + for (int i = 0; i < NUM_MONSTER_SLOTS; i++) + { + const int index = mon->inv[i]; + + if (index == NON_ITEM) + continue; + + if (is_artefact(mitm[index])) + return (false); + } + + return (true); +} + +int clone_mons(const monsters* orig, bool quiet, bool* obvious, + coord_def pos) +{ + // Is there an open slot in menv? + int midx = NON_MONSTER; + for (int i = 0; i < MAX_MONSTERS; i++) + if (menv[i].type == -1) + { + midx = i; + break; + } + + if (midx == NON_MONSTER) + return (NON_MONSTER); + + if (!in_bounds(pos)) + { + // Find an adjacent square. + int squares = 0; + for (int i = 0; i < 8; i++) + { + const coord_def p = orig->pos() + Compass[i]; + + if (in_bounds(p) && p != you.pos() && mgrd(p) == NON_MONSTER + && monster_habitable_grid(orig, grd(p))) + { + if (one_chance_in(++squares)) + pos = p; + } + } + if (squares == 0) + return (NON_MONSTER); + } + + ASSERT(mgrd(pos) == NON_MONSTER && you.pos() != pos); + + monsters &mon(menv[midx]); + + mon = *orig; + mon.position = pos; + mgrd(pos) = midx; + + // Duplicate objects, or unequip them if they can't be duplicated. + for (int i = 0; i < NUM_MONSTER_SLOTS; i++) + { + const int old_index = orig->inv[i]; + + if (old_index == NON_ITEM) + continue; + + const int new_index = get_item_slot(0); + if (new_index == NON_ITEM) + { + mon.unequip(mitm[old_index], i, 0, true); + mon.inv[i] = NON_ITEM; + continue; + } + + mon.inv[i] = new_index; + mitm[new_index] = mitm[old_index]; + } + + bool _obvious; + if (obvious == NULL) + obvious = &_obvious; + *obvious = false; + + if (you.can_see(orig) && you.can_see(&mon)) + { + if (!quiet) + simple_monster_message(orig, " is duplicated!"); + *obvious = true; + } + + mark_interesting_monst(&mon, mon.behaviour); + if (you.can_see(&mon)) + { + seen_monster(&mon); + viewwindow(true, false); + } + + return (midx); +} diff --git a/crawl-ref/source/mstuff2.h b/crawl-ref/source/mstuff2.h index d0f9a32744..d1ec4febdd 100644 --- a/crawl-ref/source/mstuff2.h +++ b/crawl-ref/source/mstuff2.h @@ -36,4 +36,8 @@ bool silver_statue_effects(monsters *mons); bool moth_incite_monsters(const monsters *mon); void mons_clear_trapping_net(monsters *mon); +bool mons_clonable(const monsters* orig, bool needs_adjacent = true); +int clone_mons(const monsters* orig, bool quiet = false, + bool* obvious = NULL, coord_def pos = coord_def(0, 0) ); + #endif diff --git a/crawl-ref/source/spells1.cc b/crawl-ref/source/spells1.cc index dd1e0b7497..7353430c9a 100644 --- a/crawl-ref/source/spells1.cc +++ b/crawl-ref/source/spells1.cc @@ -1086,36 +1086,40 @@ void abjuration(int pow) if (mons_wont_attack(monster)) continue; - mon_enchant abj = monster->get_ench(ENCH_ABJ); - if (abj.ench != ENCH_NONE) + int duration; + if (monster->is_summoned(&duration)) { int sockage = std::max(fuzz_value(abjdur, 60, 30), 40); #ifdef DEBUG_DIAGNOSTICS mprf(MSGCH_DIAGNOSTICS, "%s abj: dur: %d, abj: %d", - monster->name(DESC_PLAIN).c_str(), abj.duration, sockage); + monster->name(DESC_PLAIN).c_str(), duration, sockage); #endif + bool shielded = false; // TSO and Trog's abjuration protection. if (mons_is_god_gift(monster, GOD_SHINING_ONE)) { sockage = sockage * (30 - monster->hit_dice) / 45; - if (sockage < abj.duration) + if (sockage < duration) { simple_god_message(" protects a fellow warrior from your evil magic!", GOD_SHINING_ONE); + shielded = true; } } else if (mons_is_god_gift(monster, GOD_TROG)) { sockage = sockage * 8 / 15; - if (sockage < abj.duration) + if (sockage < duration) { simple_god_message(" shields an ally from your puny magic!", GOD_TROG); + shielded = true; } } - if (!monster->lose_ench_duration(abj, sockage)) + mon_enchant abj = monster->get_ench(ENCH_ABJ); + if (!monster->lose_ench_duration(abj, sockage) && !shielded) simple_monster_message(monster, " shudders."); } } diff --git a/crawl-ref/source/spells2.cc b/crawl-ref/source/spells2.cc index 379ac587a4..f67085a98f 100644 --- a/crawl-ref/source/spells2.cc +++ b/crawl-ref/source/spells2.cc @@ -1624,8 +1624,8 @@ static bool _summon_holy_being_wrapper(int pow, god_type god, monster_type mon, create_monster( mgen_data(mon, friendly ? BEH_FRIENDLY : BEH_HOSTILE, - dur, you.pos(), - friendly ? you.pet_target : MHITYOU, + dur, friendly ? MON_SUMM_AID : MON_SUMM_WRATH, + you.pos(), friendly ? you.pet_target : MHITYOU, MG_FORCE_BEH, god)); if (monster == -1) @@ -1709,7 +1709,7 @@ bool cast_tukimas_dance(int pow, god_type god, create_monster( mgen_data(MONS_DANCING_WEAPON, friendly ? BEH_FRIENDLY : BEH_HOSTILE, - dur, you.pos(), + dur, SPELL_TUKIMAS_DANCE, you.pos(), friendly ? you.pet_target : MHITYOU, 0, god)); diff --git a/crawl-ref/source/spells3.cc b/crawl-ref/source/spells3.cc index 2a796129b8..a63facdc81 100644 --- a/crawl-ref/source/spells3.cc +++ b/crawl-ref/source/spells3.cc @@ -546,7 +546,7 @@ bool cast_shadow_creatures(god_type god) const int monster = create_monster( - mgen_data(RANDOM_MONSTER, BEH_FRIENDLY, 2, + mgen_data(RANDOM_MONSTER, BEH_FRIENDLY, 2, SPELL_SHADOW_CREATURES, you.pos(), you.pet_target, MG_FORCE_BEH, god), false); diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc index b78045eea0..164a716382 100644 --- a/crawl-ref/source/spl-cast.cc +++ b/crawl-ref/source/spl-cast.cc @@ -2446,7 +2446,7 @@ void MiscastEffect::do_miscast() { severity = (pow * fail * (10 + pow) / 7 * WILD_MAGIC_NASTINESS) / 100; -#if DEBUG_DIAGNOSTICS || DEBUG_MISCAT +#if DEBUG_DIAGNOSTICS || DEBUG_MISCAST mprf(MSGCH_DIAGNOSTICS, "'%s' miscast power: %d", spell != SPELL_NO_SPELL ? spell_title(spell) : spelltype_short_name(sp_type), @@ -2468,7 +2468,7 @@ void MiscastEffect::do_miscast() severity = 0; } -#if DEBUG_DIAGNOSTICS || DEBUG_MISCAT +#if DEBUG_DIAGNOSTICS || DEBUG_MISCAST mprf(MSGCH_DIAGNOSTICS, "Sptype: %s, severity: %d", spelltype_short_name(sp_type), severity ); #endif @@ -2715,6 +2715,15 @@ bool MiscastEffect::_create_monster(monster_type what, int abj_deg, data.abjuration_duration = 6; } + // If data.abjuration_duration == 0 then data.summon_type will simply + // be ignored. + if (you.penance[god] > 0) + data.summon_type = MON_SUMM_WRATH; + else if (source == ZOT_TRAP_MISCAST) + data.summon_type = MON_SUMM_ZOT; + else + data.summon_type = MON_SUMM_MISCAST; + return (create_monster(data) != -1); } diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc index 45cfbb0a74..935db3a3ef 100644 --- a/crawl-ref/source/view.cc +++ b/crawl-ref/source/view.cc @@ -1532,6 +1532,10 @@ inline static void _update_cloud_grid(int cloudno) which_colour = EC_MIST; break; + case CLOUD_CHAOS: + which_colour = EC_RANDOM; + break; + default: which_colour = LIGHTGREY; break; diff --git a/crawl-ref/source/xom.cc b/crawl-ref/source/xom.cc index 54b797c3d5..dd75840a3f 100644 --- a/crawl-ref/source/xom.cc +++ b/crawl-ref/source/xom.cc @@ -742,7 +742,7 @@ static bool _xom_is_good(int sever) summons[i] = create_monster( - mgen_data(monster, BEH_FRIENDLY, 3, + mgen_data(monster, BEH_FRIENDLY, 3, MON_SUMM_AID, you.pos(), you.pet_target, MG_FORCE_BEH, GOD_XOM)); if (summons[i] != -1) @@ -818,7 +818,7 @@ static bool _xom_is_good(int sever) const int summons = create_monster( - mgen_data(mon, beha, 6, + mgen_data(mon, beha, 6, MON_SUMM_AID, you.pos(), hitting, MG_FORCE_BEH, GOD_XOM)); if (summons != -1) @@ -1153,7 +1153,8 @@ static bool _xom_is_bad(int sever) if (create_monster( mgen_data::hostile_at( _xom_random_punishment_demon(sever), - you.pos(), 4, 0, true, GOD_XOM)) != -1) + you.pos(), 4, 0, true, GOD_XOM, + MON_SUMM_WRATH)) != -1) { success = true; } |