summaryrefslogtreecommitdiffstats
path: root/crawl-ref
diff options
context:
space:
mode:
authordshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2008-03-31 19:09:19 +0000
committerdshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2008-03-31 19:09:19 +0000
commit3846460d200480f3af4c345c4137f9bbee818b24 (patch)
treeeb6b79180b45751bc973523a2c6b76235bcf15d0 /crawl-ref
parent900c6efcaf6fb292d518249ffe65abf92a01afc2 (diff)
downloadcrawl-ref-3846460d200480f3af4c345c4137f9bbee818b24.tar.gz
crawl-ref-3846460d200480f3af4c345c4137f9bbee818b24.zip
Give monsters better natural regeneration increasing with HD. Monsters will still never heal more than 1 hp per turn.
Increase royal jelly movement speed, hp and attack damage. The royal jelly now spits out high-level jellies when it takes a high-damage hit of any kind. No experience for the expelled jellies, given that they're technically part of the royal jelly, and the royal jelly already gives a heap of xp. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@3985 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref')
-rw-r--r--crawl-ref/source/cloud.cc6
-rw-r--r--crawl-ref/source/cloud.h2
-rw-r--r--crawl-ref/source/externs.h2
-rw-r--r--crawl-ref/source/fight.cc4
-rw-r--r--crawl-ref/source/mon-data.h8
-rw-r--r--crawl-ref/source/mon-util.cc60
-rw-r--r--crawl-ref/source/monplace.cc82
-rw-r--r--crawl-ref/source/monplace.h3
-rw-r--r--crawl-ref/source/monstuff.cc56
-rw-r--r--crawl-ref/source/travel.cc2
-rw-r--r--crawl-ref/source/travel.h2
11 files changed, 202 insertions, 25 deletions
diff --git a/crawl-ref/source/cloud.cc b/crawl-ref/source/cloud.cc
index 351f1a3773..3aa74613df 100644
--- a/crawl-ref/source/cloud.cc
+++ b/crawl-ref/source/cloud.cc
@@ -297,6 +297,12 @@ bool is_opaque_cloud(unsigned char cloud_idx)
(ctype >= CLOUD_GREY_SMOKE && ctype <= CLOUD_STEAM) );
}
+cloud_type cloud_type_at(const coord_def &c)
+{
+ const int cloudno = env.cgrid(c);
+ return (cloudno == EMPTY_CLOUD? CLOUD_NONE : env.cloud[cloudno].type);
+}
+
cloud_type random_smoke_type()
{
// excludes black (reproducing existing behaviour)
diff --git a/crawl-ref/source/cloud.h b/crawl-ref/source/cloud.h
index 8ca697cf9f..3df9df85ca 100644
--- a/crawl-ref/source/cloud.h
+++ b/crawl-ref/source/cloud.h
@@ -35,6 +35,8 @@ struct fog_machine_data
cloud_type random_smoke_type();
+cloud_type cloud_type_at(const coord_def &pos);
+
void delete_cloud( int cloud );
void move_cloud( int cloud, int new_x, int new_y );
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index 4f2d73a671..0fdb94ad99 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -1066,6 +1066,8 @@ public:
void scale_hp(int num, int den);
bool gain_exp(int exp);
+ void react_to_damage(int damage);
+
void add_enchantment_effect(const mon_enchant &me, bool quiet = false);
void remove_enchantment_effect(const mon_enchant &me, bool quiet = false);
void apply_enchantments();
diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc
index 62a4c9f76b..f6d5ae9471 100644
--- a/crawl-ref/source/fight.cc
+++ b/crawl-ref/source/fight.cc
@@ -728,8 +728,6 @@ bool melee_attack::player_attack()
bleed_onto_floor(where.x, where.y, defender->id(), blood, true);
}
- player_hurt_monster();
-
if (damage_done > 0 || !defender_visible)
player_announce_hit();
else if (!shield_blocked && damage_done <= 0)
@@ -738,6 +736,8 @@ bool melee_attack::player_attack()
make_stringf("You %s %s.", attack_verb.c_str(),
defender->name(DESC_NOCAP_THE).c_str());
}
+
+ player_hurt_monster();
if (damage_done)
player_exercise_combat_skills();
diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h
index 8657178a59..9bd80cc10d 100644
--- a/crawl-ref/source/mon-data.h
+++ b/crawl-ref/source/mon-data.h
@@ -2166,13 +2166,13 @@
{
MONS_ROYAL_JELLY, 'J', YELLOW, "royal jelly",
- M_NO_SKELETON | M_SENSE_INVIS | M_ACID_SPLASH,
+ M_NO_SKELETON | M_SENSE_INVIS | M_SPECIAL_ABILITY | M_ACID_SPLASH,
MR_RES_POISON | MR_RES_ASPHYX | MR_RES_ACID,
0, 20, MONS_JELLY, MONS_ROYAL_JELLY, MH_NATURAL, -7,
- { {AT_HIT, AF_ACID, 50}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
- { 21, 0, 0, 111 },
+ { {AT_HIT, AF_ACID, 50}, {AT_HIT, AF_ACID, 30}, AT_NO_ATK, AT_NO_ATK },
+ { 21, 0, 0, 230 },
8, 4, MST_NO_SPELLS, CE_CLEAN, Z_NOZOMBIE, S_SILENT, I_PLANT,
- HT_LAND, 12, DEFAULT_ENERGY, MONUSE_EATS_ITEMS, SIZE_SMALL
+ HT_LAND, 16, DEFAULT_ENERGY, MONUSE_EATS_ITEMS, SIZE_SMALL
},
// kobolds ('K')
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index bc381f03dc..24225112de 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -5201,6 +5201,66 @@ void monsters::lose_energy(energy_use_type et)
speed_increment -= action_energy(et);
}
+static inline monster_type _royal_jelly_ejectable_monster()
+{
+ return static_cast<monster_type>(
+ random_choose( MONS_ACID_BLOB,
+ MONS_AZURE_JELLY,
+ MONS_DEATH_OOZE,
+ -1 ) );
+}
+
+void monsters::react_to_damage(int damage)
+{
+ // The royal jelly objects to taking damage and will SULK. :-)
+ if (type == MONS_ROYAL_JELLY && alive()
+ && damage > 8 && random2(50) < damage)
+ {
+ const int tospawn =
+ 1 + random2avg(1 + std::min((damage - 8) / 8, 5), 2);
+ mprf(MSGCH_DIAGNOSTICS, "Trying to spawn %d jellies.", tospawn);
+ const beh_type sbehaviour = SAME_ATTITUDE(this);
+ int spawned = 0;
+ for (int i = 0; i < tospawn; ++i)
+ {
+ const monster_type jelly = _royal_jelly_ejectable_monster();
+ coord_def jpos = find_newmons_square_contiguous(jelly, pos());
+ if (!in_bounds(jpos))
+ continue;
+
+ const int nmons =
+ mons_place( jelly, sbehaviour, foe, true, jpos.x, jpos.y,
+ you.level_type, PROX_ANYWHERE, MONS_PROGRAM_BUG,
+ 0, false );
+
+ if (nmons != -1 && nmons != NON_MONSTER)
+ {
+ // Don't allow milking the royal jelly.
+ menv[nmons].flags |= MF_CREATED_FRIENDLY;
+ spawned++;
+ }
+ }
+
+ const bool needs_message =
+ spawned && mons_near(this) && player_monster_visible(this);
+
+ if (needs_message)
+ {
+ const std::string mname = name(DESC_CAP_THE);
+ mprf("%s shudders%s.", mname.c_str(),
+ spawned >= 5 ? " alarmingly" :
+ spawned >= 3 ? " violently" :
+ spawned > 1 ? " vigorously" : "");
+ if (spawned == 1)
+ mprf("%s spits out another jelly.", mname.c_str());
+ else
+ mprf("%s spits out %s more jellies.",
+ mname.c_str(),
+ number_in_words(spawned).c_str());
+ }
+ }
+}
+
/////////////////////////////////////////////////////////////////////////
// mon_enchant
diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc
index efea2a6e94..e0aa3b0d3d 100644
--- a/crawl-ref/source/monplace.cc
+++ b/crawl-ref/source/monplace.cc
@@ -1579,6 +1579,84 @@ int mons_place( int mon_type, beh_type behaviour, int target, bool summoned,
return (mid);
} // end mons_place()
+static dungeon_feature_type _monster_habitat_feature(int mtype)
+{
+ return ((mtype == RANDOM_MONSTER) ? DNGN_FLOOR
+ : habitat2grid( mons_habitat_by_type(mtype) ));
+}
+
+class newmons_square_find : public travel_pathfind
+{
+private:
+ dungeon_feature_type grid_wanted;
+ coord_def start;
+ int maxdistance;
+
+ int best_distance;
+ int nfound;
+public:
+ // Terrain that we can't spawn on, but that we can skip through.
+ std::set<dungeon_feature_type> passable;
+public:
+ newmons_square_find(dungeon_feature_type grdw,
+ const coord_def &pos,
+ int maxdist = 0)
+ : grid_wanted(grdw), start(pos), maxdistance(maxdist),
+ best_distance(0), nfound(0)
+ {
+ }
+
+ coord_def pathfind()
+ {
+ set_floodseed(start);
+ return travel_pathfind::pathfind(RMODE_EXPLORE);
+ }
+
+ bool path_flood(const coord_def &c, const coord_def &dc)
+ {
+ if (best_distance && traveled_distance > best_distance)
+ return (true);
+
+ if (!in_bounds(dc)
+ || (maxdistance > 0 && traveled_distance > maxdistance))
+ {
+ return (false);
+ }
+ if (!grid_compatible(grid_wanted, grd(dc), true))
+ {
+ if (passable.find(grd(dc)) != passable.end())
+ good_square(dc);
+ return (false);
+ }
+ if (mgrd(dc) == NON_MONSTER && dc != you.pos()
+ && one_chance_in(++nfound))
+ {
+ greedy_dist = traveled_distance;
+ greedy_place = dc;
+ best_distance = traveled_distance;
+ }
+ else
+ {
+ good_square(dc);
+ }
+ return (false);
+ }
+};
+
+/*
+ * Finds a square for a monster of the given class, pathfinding
+ * through only contiguous squares of habitable terrain.
+ */
+coord_def find_newmons_square_contiguous(monster_type mons_class,
+ const coord_def &start,
+ int distance)
+{
+ newmons_square_find nmfind(_monster_habitat_feature(mons_class),
+ start, distance);
+ const coord_def p = nmfind.pathfind();
+ return (in_bounds(p)? p : coord_def(-1, -1));
+}
+
coord_def find_newmons_square(int mons_class, int x, int y)
{
FixedVector < char, 2 > empty;
@@ -1590,9 +1668,7 @@ coord_def find_newmons_square(int mons_class, int x, int y)
if (mons_class == WANDERING_MONSTER)
mons_class = RANDOM_MONSTER;
- dungeon_feature_type spcw =
- ((mons_class == RANDOM_MONSTER) ? DNGN_FLOOR
- : habitat2grid( mons_habitat_by_type(mons_class) ));
+ const dungeon_feature_type spcw = _monster_habitat_feature(mons_class);
// Might be better if we chose a space and tried to match the monster
// to it in the case of RANDOM_MONSTER, that way if the target square
diff --git a/crawl-ref/source/monplace.h b/crawl-ref/source/monplace.h
index 953f303151..b7139abde6 100644
--- a/crawl-ref/source/monplace.h
+++ b/crawl-ref/source/monplace.h
@@ -185,6 +185,9 @@ bool monster_habitable_grid(int monster_class,
bool paralysed = false);
bool monster_can_submerge(const monsters *mons, dungeon_feature_type grid);
coord_def find_newmons_square(int mons_class, int x, int y);
+coord_def find_newmons_square_contiguous(monster_type mons_class,
+ const coord_def &start,
+ int maxdistance = 3);
void spawn_random_monsters();
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index 63e285dbc0..107951b5b2 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -4443,6 +4443,35 @@ static void _monster_add_energy(monsters *monster)
monster->speed_increment += energy_gained;
}
+static int _monster_natural_regen_roll(monsters *monster)
+{
+ // A HD divider ranging from 3 (at 1 HD) to 1 (at 8 HD).
+ int divider =
+ std::max(div_rand_round(15 - monster->hit_dice, 4), 1);
+
+ // The undead have a harder time regenerating.
+ switch (monster->holiness())
+ {
+ // The undead don't regenerate easily.
+ case MH_UNDEAD:
+ divider *= 4;
+ break;
+
+ // And golems have it worse.
+ case MH_NONLIVING:
+ divider *= 5;
+ break;
+
+ default:
+ break;
+ }
+
+ const int regen_rate =
+ std::max(div_rand_round(monster->hit_dice, divider), 1);
+
+ return (random2(25) < regen_rate);
+}
+
// Do natural regeneration for monster.
static void _monster_regenerate(monsters *monster)
{
@@ -4455,25 +4484,20 @@ static void _monster_regenerate(monsters *monster)
{
return;
}
-
- // regenerate:
+
if (monster_descriptor(monster->type, MDSC_REGENERATES)
-
|| (monster->type == MONS_FIRE_ELEMENTAL
- && (grd[monster->x][monster->y] == DNGN_LAVA
- || (env.cgrid(monster->pos()) != EMPTY_CLOUD
- && env.cloud[env.cgrid(monster->pos())].type
- == CLOUD_FIRE)))
-
+ && (grd(monster->pos()) == DNGN_LAVA
+ || cloud_type_at(monster->pos()) == CLOUD_FIRE))
+
|| (monster->type == MONS_WATER_ELEMENTAL
- && (grd[monster->x][monster->y] == DNGN_SHALLOW_WATER
- || grd[monster->x][monster->y] == DNGN_DEEP_WATER))
-
+ && grid_is_watery(grd(monster->pos())))
+
|| (monster->type == MONS_AIR_ELEMENTAL
- && env.cgrid[monster->x][monster->y] == EMPTY_CLOUD
+ && env.cgrid(monster->pos()) == EMPTY_CLOUD
&& one_chance_in(3))
-
- || one_chance_in(25))
+
+ || _monster_natural_regen_roll(monster))
{
heal_monster(monster, 1, false);
}
@@ -6463,6 +6487,10 @@ int hurt_monster(monsters * victim, int damage_dealt)
{
damage_dealt = std::max(std::min(damage_dealt, victim->hit_points), 0);
victim->hit_points -= damage_dealt;
+
+ // Allow the victim to exhibit passive damage behaviour (royal jelly).
+ victim->react_to_damage(damage_dealt);
+
return (damage_dealt);
}
diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc
index d3315077c2..f48abe8b81 100644
--- a/crawl-ref/source/travel.cc
+++ b/crawl-ref/source/travel.cc
@@ -1452,7 +1452,7 @@ const coord_def travel_pathfind::unexplored_square() const
* The travel algorithm is based on the NetHack travel code written by Warwick
* Allison - used with his permission.
*/
-const coord_def travel_pathfind::pathfind(run_mode_type rmode)
+coord_def travel_pathfind::pathfind(run_mode_type rmode)
{
if (rmode == RMODE_INTERLEVEL)
rmode = RMODE_TRAVEL;
diff --git a/crawl-ref/source/travel.h b/crawl-ref/source/travel.h
index f9f4b616d1..78b924ad66 100644
--- a/crawl-ref/source/travel.h
+++ b/crawl-ref/source/travel.h
@@ -576,7 +576,7 @@ public:
virtual ~travel_pathfind();
// Finds travel direction or explore target.
- const coord_def pathfind(run_mode_type rt);
+ coord_def pathfind(run_mode_type rt);
// For flood-fills (explore), sets starting (seed) square.
void set_floodseed(const coord_def &seed, bool double_flood = false);