diff options
author | dshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573> | 2007-10-09 12:53:14 +0000 |
---|---|---|
committer | dshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573> | 2007-10-09 12:53:14 +0000 |
commit | 3662d6c86b915654e6ce1e43888a1bfe179ec931 (patch) | |
tree | 35e84669202e8b4e49b9c9980959f8707248f178 | |
parent | 937b43bdb80dbf4ef1b6b6e18411ea8840c5246c (diff) | |
download | crawl-ref-3662d6c86b915654e6ce1e43888a1bfe179ec931.tar.gz crawl-ref-3662d6c86b915654e6ce1e43888a1bfe179ec931.zip |
Orc battle cry for 0.3.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/branches/stone_soup-0.3@2391 c06c8d41-db1a-0410-9941-cceddc491573
-rw-r--r-- | crawl-ref/source/debug.cc | 25 | ||||
-rw-r--r-- | crawl-ref/source/direct.cc | 7 | ||||
-rw-r--r-- | crawl-ref/source/enum.h | 4 | ||||
-rw-r--r-- | crawl-ref/source/externs.h | 8 | ||||
-rw-r--r-- | crawl-ref/source/fight.cc | 15 | ||||
-rw-r--r-- | crawl-ref/source/mon-util.cc | 50 | ||||
-rw-r--r-- | crawl-ref/source/mon-util.h | 4 | ||||
-rw-r--r-- | crawl-ref/source/monstuff.cc | 7 | ||||
-rw-r--r-- | crawl-ref/source/mstuff2.cc | 95 | ||||
-rw-r--r-- | crawl-ref/source/mstuff2.h | 1 | ||||
-rw-r--r-- | crawl-ref/source/player.cc | 18 |
11 files changed, 198 insertions, 36 deletions
diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc index 8c26fa8ae4..c6a4e3c740 100644 --- a/crawl-ref/source/debug.cc +++ b/crawl-ref/source/debug.cc @@ -412,31 +412,6 @@ void create_spec_monster_name(int x, int y) const mons_spec mspec = mlist.get_monster(0); if (!force_place && mspec.mid != -1) { - // Only one ghost allowed per level - if (mspec.mid == MONS_PLAYER_GHOST) - { - for (int i = 0; i < MAX_MONSTERS; i++) - if (menv[i].type == MONS_PLAYER_GHOST - && menv[i].alive()) - { - mpr("Only one player ghost per level allowed, " - "and this level already has one."); - return; - } - } - // Only one pandemonium lord allowed per level as well. - else if (mspec.mid == MONS_PANDEMONIUM_DEMON) - { - for (int i = 0; i < MAX_MONSTERS; i++) - if (menv[i].type == MONS_PANDEMONIUM_DEMON - && menv[i].alive()) - { - mpr("Only one Pandemonium lord per level allowed, " - "and this level already has one."); - return; - } - } - coord_def place = find_newmons_square(mspec.mid, x, y); if (in_bounds(place)) { diff --git a/crawl-ref/source/direct.cc b/crawl-ref/source/direct.cc index 184a4745fc..d51b07994d 100644 --- a/crawl-ref/source/direct.cc +++ b/crawl-ref/source/direct.cc @@ -1588,8 +1588,11 @@ static std::string describe_mons_enchantment(const monsters &mons, if (paralysed && (ench.ench == ENCH_SLOW || ench.ench == ENCH_HASTE)) return ""; - if (ench.ench == ENCH_HASTE && mons.has_ench(ENCH_BERSERK)) + if ((ench.ench == ENCH_HASTE || ench.ench == ENCH_BATTLE_FRENZY) + && mons.has_ench(ENCH_BERSERK)) + { return ""; + } switch (ench.ench) { @@ -1605,6 +1608,8 @@ static std::string describe_mons_enchantment(const monsters &mons, return "moving slowly"; case ENCH_BERSERK: return "berserk"; + case ENCH_BATTLE_FRENZY: + return "consumed by blood-lust"; case ENCH_HASTE: return "moving very quickly"; case ENCH_CONFUSION: diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h index ebb4ff3e8d..2a72d1ba2b 100644 --- a/crawl-ref/source/enum.h +++ b/crawl-ref/source/enum.h @@ -823,6 +823,9 @@ enum dungeon_feature_type DNGN_WAX_WALL, // 8 DNGN_PERMAROCK_WALL, // 9 - for undiggable walls + // XXX: highest grid value which is opaque + DNGN_MAXOPAQUE = DNGN_PERMAROCK_WALL, + // XXX: lowest grid value which can be seen through DNGN_MINSEE = 11, @@ -1072,6 +1075,7 @@ enum enchant_type ENCH_SLEEPY, // Monster can't wake until this wears off. ENCH_FATIGUE, // Post-berserk fatigue. ENCH_HELD, // caught in a net + ENCH_BATTLE_FRENZY, // Monster is in a battle frenzy NUM_ENCHANTMENTS }; diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h index 63678d5f49..f7ac02b85c 100644 --- a/crawl-ref/source/externs.h +++ b/crawl-ref/source/externs.h @@ -107,8 +107,10 @@ public: virtual void attacking(actor *other) = 0; virtual bool can_go_berserk() const = 0; virtual bool can_see_invisible() const = 0; - virtual bool is_icy() const = 0; virtual bool invisible() const = 0; + virtual bool visible_to(const actor *looker) const = 0; + virtual bool can_see(const actor *target) const = 0; + virtual bool is_icy() const = 0; virtual void go_berserk(bool intentional) = 0; virtual void mutate() = 0; virtual void hurt(const actor *attacker, int amount) = 0; @@ -688,6 +690,8 @@ public: bool cannot_speak() const; bool invisible() const; bool can_see_invisible() const; + bool visible_to(const actor *looker) const; + bool can_see(const actor *target) const; bool is_icy() const; bool light_flight() const; @@ -1029,6 +1033,8 @@ public: flight_type flies() const; bool invisible() const; bool can_see_invisible() const; + bool visible_to(const actor *looker) const ; + bool can_see(const actor *target) const; bool is_icy() const; bool paralysed() const; bool confused() const; diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc index cb0663d3eb..0dfb910968 100644 --- a/crawl-ref/source/fight.cc +++ b/crawl-ref/source/fight.cc @@ -2844,6 +2844,21 @@ int melee_attack::mons_calc_damage(const mon_attack_def &attk) // Berserk monsters get bonus damage. if (atk->has_ench(ENCH_BERSERK)) damage = damage * 3 / 2; + else if (atk->has_ench(ENCH_BATTLE_FRENZY)) + { + const mon_enchant ench = atk->get_ench(ENCH_BATTLE_FRENZY); + +#ifdef DEBUG_DIAGNOSTICS + const int orig_damage = damage; +#endif + + damage = damage * (115 + ench.degree * 15) / 100; + +#ifdef DEBUG_DIAGNOSTICS + mprf(MSGCH_DIAGNOSTICS, "%s frenzy damage: %d->%d", + attacker->name(DESC_PLAIN).c_str(), orig_damage, damage); +#endif + } if (water_attack) damage *= 2; diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc index 20c87ce015..f6f3df95c4 100644 --- a/crawl-ref/source/mon-util.cc +++ b/crawl-ref/source/mon-util.cc @@ -609,7 +609,7 @@ bool mons_see_invis(const monsters *mon) // This does NOT do line of sight! It checks the targ's visibility // with respect to mon's perception, but doesn't do walls or range. -bool mons_monster_visible( struct monsters *mon, struct monsters *targ ) +bool mons_monster_visible( const monsters *mon, const monsters *targ ) { if (targ->has_ench(ENCH_SUBMERGED) || (targ->invisible() && !mons_see_invis(mon))) @@ -622,7 +622,7 @@ bool mons_monster_visible( struct monsters *mon, struct monsters *targ ) // This does NOT do line of sight! It checks the player's visibility // with respect to mon's perception, but doesn't do walls or range. -bool mons_player_visible( struct monsters *mon ) +bool mons_player_visible( const monsters *mon ) { if (you.invisible()) { @@ -3121,9 +3121,9 @@ bool monsters::fumbles_attack(bool verbose) { if (verbose) { - const bool can_see = + const bool player_can_see = mons_near(this) && player_monster_visible(this); - if (can_see) + if (player_can_see) mprf("%s splashes around in the water.", this->name(DESC_CAP_THE).c_str()); else if (!silenced(you.x_pos, you.y_pos) && !silenced(x, y)) @@ -3951,6 +3951,7 @@ void monsters::timeout_enchantments(int levels) case ENCH_SLOW: case ENCH_HASTE: case ENCH_FEAR: case ENCH_INVIS: case ENCH_CHARM: case ENCH_SLEEP_WARY: case ENCH_SICK: case ENCH_SLEEPY: case ENCH_PARALYSIS: + case ENCH_BATTLE_FRENZY: lose_ench_levels(i->second, levels); break; @@ -4082,6 +4083,10 @@ void monsters::apply_enchantment(const mon_enchant &me) case ENCH_SLEEP_WARY: decay_enchantment(me); break; + + case ENCH_BATTLE_FRENZY: + decay_enchantment(me, false); + break; case ENCH_HELD: { @@ -4569,6 +4574,41 @@ bool monsters::invisible() const return (has_ench(ENCH_INVIS) && !backlit()); } +bool monsters::visible_to(const actor *looker) const +{ + if (this == looker) + return (!invisible() || can_see_invisible()); + + if (looker->atype() == ACT_PLAYER) + return player_monster_visible(this); + else + { + const monsters* mon = dynamic_cast<const monsters*>(looker); + return mons_monster_visible(mon, this); + } +} + +bool monsters::can_see(const actor *target) const +{ + if (this == target) + return visible_to(target); + + if (!target->visible_to(this)) + return false; + + if (target->atype() == ACT_PLAYER) + return mons_near(this); + + const monsters* mon = dynamic_cast<const monsters*>(target); + int tx = mon->x; + int ty = mon->y; + + // Assume we can see any monster within LOS radius. This is inaccurate, + // but can be followed up with a tracer if essential. Trunk does full + // (expensive) ray tracing up front to figure this out. + return (distance(x, y, tx, ty) <= LOS_RADIUS); +} + void monsters::mutate() { if (holiness() != MH_NATURAL) @@ -4621,7 +4661,7 @@ static const char *enchant_names[] = "rot", "summon", "abj", "backlit", "charm", "fire", "gloshifter", "shifter", "tp", "wary", "submerged", "short lived", "paralysis", "sick", "sleep", "fatigue", "held", - "bug" + "blood-lust", "bug" }; const char *mons_enchantment_name(enchant_type ench) diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h index 9354469d08..2c64da6f20 100644 --- a/crawl-ref/source/mon-util.h +++ b/crawl-ref/source/mon-util.h @@ -328,8 +328,8 @@ mon_itemuse_type mons_itemuse(int mc); * *********************************************************************** */ bool mons_see_invis(const monsters *mon); bool mons_sense_invis(const monsters *mon); -bool mons_monster_visible( struct monsters *mon, struct monsters *targ ); -bool mons_player_visible( struct monsters *mon ); +bool mons_monster_visible( const monsters *mon, const monsters *targ ); +bool mons_player_visible( const monsters *mon ); // last updated 12may2000 {dlb} diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc index 821256afc6..0458dbea59 100644 --- a/crawl-ref/source/monstuff.cc +++ b/crawl-ref/source/monstuff.cc @@ -2289,10 +2289,13 @@ static bool handle_special_ability(monsters *monster, bolt & beem) return (false); } -// losight(show, grd, you.x_pos, you.y_pos); - switch (mclass) { + case MONS_ORC_KNIGHT: + case MONS_ORC_WARLORD: + used = orc_battle_cry(monster); + break; + case MONS_ORANGE_STATUE: used = orange_statue_effects(monster); break; diff --git a/crawl-ref/source/mstuff2.cc b/crawl-ref/source/mstuff2.cc index a202ea04dc..3f5b4e98b8 100644 --- a/crawl-ref/source/mstuff2.cc +++ b/crawl-ref/source/mstuff2.cc @@ -1311,6 +1311,24 @@ bool mons_throw(struct monsters *monster, struct bolt &pbolt, int hand_used) } pbolt.damage.size = diceMult * pbolt.damage.size / 100; + if (monster->has_ench(ENCH_BATTLE_FRENZY)) + { + const mon_enchant ench = monster->get_ench(ENCH_BATTLE_FRENZY); + +#ifdef DEBUG_DIAGNOSTICS + const dice_def orig_damage = pbolt.damage; +#endif + + pbolt.damage.size = pbolt.damage.size * (115 + ench.degree * 15) / 100; + +#ifdef DEBUG_DIAGNOSTICS + mprf(MSGCH_DIAGNOSTICS, "%s frenzy damage: %dd%d -> %dd%d", + monster->name(DESC_PLAIN).c_str(), + orig_damage.num, orig_damage.size, + pbolt.damage.num, pbolt.damage.size); +#endif + } + // Skilled archers get better to-hit and damage. if (skilled) { @@ -2111,6 +2129,83 @@ bool orange_statue_effects(monsters *mons) return (false); } +bool orc_battle_cry(monsters *chief) +{ + const actor *foe = chief->get_foe(); + if (foe && !silenced(chief->x, chief->y) + && chief->can_see(foe) + && coinflip()) + { + const int boss_index = monster_index(chief); + const int level = chief->hit_dice > 12? 2 : 1; + std::vector<monsters*> affected; + for (int i = 0; i < MAX_MONSTERS; ++i) + { + monsters *mons = &menv[i]; + if (mons != chief + && mons->alive() + && mons_species(mons->type) == MONS_ORC + && mons_aligned(boss_index, i) + && mons->hit_dice < chief->hit_dice + && chief->can_see(mons)) + { + mon_enchant ench = mons->get_ench(ENCH_BATTLE_FRENZY); + if (ench.ench == ENCH_NONE || ench.degree < level) + { + const int dur = + random_range(9, 15) * speed_to_duration(mons->speed); + + if (ench.ench != ENCH_NONE) + { + ench.degree = level; + ench.duration = std::max(ench.duration, dur); + mons->update_ench(ench); + } + else + { + mons->add_ench( + mon_enchant(ENCH_BATTLE_FRENZY, level, + KC_OTHER, + dur)); + } + affected.push_back(mons); + } + } + } + + if (!affected.empty()) + { + if (you.can_see(chief) && player_can_hear(chief->x, chief->y)) + { + mprf(MSGCH_SOUND, "%s roars a battle-cry!", + chief->name(DESC_CAP_THE).c_str()); + noisy(15, chief->x, chief->y); + } + + // Disabling detailed frenzy announcement because it's so spammy. +#ifdef ANNOUNCE_BATTLE_FRENZY + std::map<std::string, int> names; + for (int i = 0, size = affected.size(); i < size; ++i) + { + if (you.can_see(affected[i])) + names[affected[i]->name(DESC_PLAIN)]++; + } + + for (std::map<std::string,int>::const_iterator i = names.begin(); + i != names.end(); ++i) + { + const std::string s = + i->second> 1? pluralise(i->first) : i->first; + mprf("The %s go%s into a battle-frenzy!", + s.c_str(), i->second == 1? "es" : ""); + } +#endif + } + } + // Orc battle cry doesn't cost the monster an action. + return (false); +} + static bool make_monster_angry(const monsters *mon, monsters *targ) { if (mons_friendly(mon) != mons_friendly(targ)) diff --git a/crawl-ref/source/mstuff2.h b/crawl-ref/source/mstuff2.h index 9c75055bd4..25cc10a3bf 100644 --- a/crawl-ref/source/mstuff2.h +++ b/crawl-ref/source/mstuff2.h @@ -92,6 +92,7 @@ void monster_teleport(struct monsters *monster, bool instan, * *********************************************************************** */ void spore_goes_pop(struct monsters *monster); +bool orc_battle_cry(monsters *chief); bool orange_statue_effects(monsters *mons); bool silver_statue_effects(monsters *mons); bool moth_incite_monsters(const monsters *mon); diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc index 7a61cca71b..84320a8dc1 100644 --- a/crawl-ref/source/player.cc +++ b/crawl-ref/source/player.cc @@ -5796,6 +5796,24 @@ bool player::invisible() const return (duration[DUR_INVIS] && !backlit()); } +bool player::visible_to(const actor *looker) const +{ + if (this == looker) + return (!invisible() || can_see_invisible()); + + const monsters* mon = dynamic_cast<const monsters*>(looker); + return mons_player_visible(mon); +} + +bool player::can_see(const actor *target) const +{ + if (this == target) + return visible_to(target); + + const monsters* mon = dynamic_cast<const monsters*>(target); + return (mons_near(mon) && target->visible_to(this)); +} + bool player::backlit() const { return (magic_contamination >= 5 || duration[DUR_BACKLIGHT]); |