summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source
diff options
context:
space:
mode:
Diffstat (limited to 'crawl-ref/source')
-rw-r--r--crawl-ref/source/mon-util.cc40
-rw-r--r--crawl-ref/source/monplace.cc4
-rw-r--r--crawl-ref/source/monplace.h5
-rw-r--r--crawl-ref/source/monstuff.cc15
-rw-r--r--crawl-ref/source/mstuff2.cc124
-rw-r--r--crawl-ref/source/mstuff2.h1
6 files changed, 183 insertions, 6 deletions
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 7e8785814b..3e8ab4d865 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -1144,6 +1144,12 @@ mon_attack_def mons_attack_spec(const monsters *mon, int attk_number)
attk.flavour = RANDOM_ELEMENT(flavours);
}
+ // Slime creature attacks are multiplied by the number merged.
+ if(mon->mons_species() == MONS_SLIME_CREATURE)
+ {
+ attk.damage *= mon->number;
+ }
+
return (zombified ? downscale_zombie_attack(mon, attk) : attk);
}
@@ -1621,8 +1627,18 @@ int exper_value(const monsters *monster)
// These four are the original arguments.
const int mclass = monster->type;
- const int mHD = monster->hit_dice;
- const int maxhp = monster->max_hit_points;
+ int mHD = monster->hit_dice;
+ int maxhp = monster->max_hit_points;
+
+ // Hacks to make merged slime creatures not worth so much
+ // exp. We will calculate the experience we would get for 1
+ // blob then just multiply it so that exp is linear with blobs
+ // merged. -cao
+ if(monster->mons_species() == MONS_SLIME_CREATURE)
+ {
+ mHD /= monster->number;
+ maxhp /= monster->number;
+ }
// These are some values we care about.
const int speed = mons_base_speed(monster);
@@ -1737,6 +1753,13 @@ int exper_value(const monsters *monster)
x_val /= 10;
}
+ // Slime creature exp hack part 2, scale exp back up by the
+ // number of blobs merged. -cao
+ if(monster->mons_species() == MONS_SLIME_CREATURE)
+ {
+ x_val *= monster->number;
+ }
+
// Reductions for big values. -- bwr
if (x_val > 100)
x_val = 100 + ((x_val - 100) * 3) / 4;
@@ -2182,6 +2205,19 @@ static std::string _str_monam(const monsters& mon, description_level_type desc,
break;
}
+ if(mon.mons_species() == MONS_SLIME_CREATURE && desc != DESC_DBNAME)
+ {
+ if (mon.number < 11)
+ {
+ const char* cardinals[] = {"one", "two", "three", "four", "five",
+ "six", "seven", "eight", "nine", "ten"};
+ result += cardinals[mon.number - 1];
+ }
+ else
+ result += make_stringf("%d", mon.number);
+
+ result += "-blob ";
+ }
// Done here to cover cases of undead versions of hydras.
if (mons_species(nametype) == MONS_HYDRA
&& mon.number > 0 && desc != DESC_DBNAME)
diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc
index be27711eef..a340ff226a 100644
--- a/crawl-ref/source/monplace.cc
+++ b/crawl-ref/source/monplace.cc
@@ -1221,6 +1221,10 @@ static int _place_monster_aux(const mgen_data &mg,
if (mg.cls == MONS_MANTICORE)
menv[id].number = 8 + random2(9);
+ // Slime creatures start off as only a single merged blob.
+ if (mg.cls == MONS_SLIME_CREATURE)
+ menv[id].number = 1;
+
// Set attitude, behaviour and target.
menv[id].attitude = ATT_HOSTILE;
menv[id].behaviour = mg.behaviour;
diff --git a/crawl-ref/source/monplace.h b/crawl-ref/source/monplace.h
index eb30a97db2..709d147c57 100644
--- a/crawl-ref/source/monplace.h
+++ b/crawl-ref/source/monplace.h
@@ -152,8 +152,9 @@ struct mgen_data
// indicate whose priest they are.
god_type god;
- // The number of hydra heads or manticore attack volleys. Note:
- // in older version this field was used for both this and for base_type.
+ // The number of hydra heads, manticore attack volleys, or merged
+ // slime creatures. Note: in older version this field was used for
+ // both this and for base_type.
int number;
// The colour of the monster.
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index c6dcc55c7b..0fce237d74 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -5883,6 +5883,13 @@ static bool _handle_special_ability(monsters *monster, bolt & beem)
used = ugly_thing_mutate(monster, true);
break;
+ case MONS_SLIME_CREATURE:
+ // Slime creatures may split or merge depending on the situation
+ used = slime_split_merge(monster);
+ if(!monster->alive())
+ return true;
+ break;
+
case MONS_ORC_KNIGHT:
case MONS_ORC_WARLORD:
case MONS_SAINT_ROKA:
@@ -7843,7 +7850,9 @@ static void _handle_monster_move(monsters *monster)
if (!mons_is_sleeping(monster) && !mons_is_wandering(monster)
// Berserking monsters are limited to running up and
// hitting their foes.
- && !monster->has_ench(ENCH_BERSERK))
+ && !monster->has_ench(ENCH_BERSERK)
+ // Slime creatures can split while wandering or resting
+ || monster->type == MONS_SLIME_CREATURE)
{
bolt beem;
@@ -7855,7 +7864,9 @@ static void _handle_monster_move(monsters *monster)
mons_friendly(monster) || monster->near_foe();
// Prevents unfriendlies from nuking you from offscreen.
// How nice!
- if (friendly_or_near || monster->type == MONS_TEST_SPAWNER)
+ // Slime creatures can split when offscreen
+ if (friendly_or_near || monster->type == MONS_TEST_SPAWNER
+ || monster->type == MONS_SLIME_CREATURE)
{
// [ds] Special abilities shouldn't overwhelm spellcasting
// in monsters that have both. This aims to give them both
diff --git a/crawl-ref/source/mstuff2.cc b/crawl-ref/source/mstuff2.cc
index 2c6bc1fe7d..6dcf1f66a3 100644
--- a/crawl-ref/source/mstuff2.cc
+++ b/crawl-ref/source/mstuff2.cc
@@ -2588,6 +2588,130 @@ bool ugly_thing_mutate(monsters *ugly, bool proximity)
return (false);
}
+// Calculate slime creature Hp and hd based on how many are merged.
+static void _stats_from_blob_count(monsters * slime, float hp_per_blob)
+{
+ int hd_per_blob = 11;
+
+ slime->max_hit_points = int(slime->number * hp_per_blob);
+ slime->hit_points = slime->max_hit_points;
+
+ slime->hit_dice = slime->number * hd_per_blob;
+}
+
+static bool _split_slime(monsters * thing, coord_def & target)
+{
+ mprf("Splitting slime at pos %d, %d", thing->pos().x, thing->pos().y);
+ mprf("splitting to %d, %d", target.x, target.y);
+
+ // create a new slime
+ int slime_idx = create_monster(mgen_data(MONS_SLIME_CREATURE,
+ thing->behaviour,
+ 0,
+ 0,
+ target,
+ thing->foe,
+ MG_FORCE_PLACE));
+
+ if(slime_idx == -1)
+ return false;
+
+ monsters * new_slime = &env.mons[slime_idx];
+
+ if(!new_slime)
+ return false;
+
+ int split_off = thing->number / 2;
+ float hp_per_blob = thing->max_hit_points / float(thing->number);
+
+ thing->number -= split_off;
+ new_slime->number = split_off;
+
+ _stats_from_blob_count(thing, hp_per_blob);
+ _stats_from_blob_count(new_slime, hp_per_blob);
+
+ return true;
+}
+
+static bool _merge_slimes(monsters * initial_slime, monsters * merge_to)
+{
+ mprf("Merging slimes, inital at %d, %d", initial_slime->pos().x, initial_slime->pos().y);
+ mprf("Merging to %d, %d", merge_to->pos().x, merge_to->pos().y);
+
+ merge_to->number += initial_slime->number;
+ merge_to->max_hit_points += initial_slime->max_hit_points;
+ merge_to->hit_points += initial_slime->max_hit_points;
+ merge_to->hit_dice += initial_slime->hit_dice;
+
+ // have to 'kill' the slime doing the merging
+ monster_die(initial_slime, KILL_MISC, NON_MONSTER, true);
+
+ return true;
+}
+
+bool slime_split_merge(monsters * thing)
+{
+ int compass_idx[8] = {0, 1, 2, 3, 4, 5, 6 ,7};
+ std::random_shuffle(compass_idx, compass_idx+8);
+
+ coord_def origin = thing->pos();
+
+ int max_slime_merge = 8;
+
+ // We can split if in an 'inactive' state (wandering or sleeping for now)
+ if (mons_is_sleeping(thing) || mons_is_wandering(thing)
+ || thing->foe == MHITNOT)
+ {
+ if(thing->number > 1 && thing->hit_points == thing->max_hit_points)
+ {
+ // Anywhere we can place a offspring?
+ // If so split.
+ for (int i = 0; i < 8; i++)
+ {
+ coord_def target=origin + Compass[i];
+
+ if(mons_class_can_pass(MONS_SLIME_CREATURE,
+ env.grid(target))
+ && !actor_at(target))
+ {
+
+ return _split_slime(thing, target);
+ }
+ } // end adjacent squares check
+ }// end non singular check
+ }
+ // Otherwise see if a merge is viable.
+ else if(!mons_is_fleeing(thing))
+ {
+ // Check for adjacent slime creatures.
+ for(int i=0;i<8;i++)
+ {
+ coord_def target=origin + Compass[i];
+ monsters * other_thing = monster_at(target);
+
+ // We can merge if we find another adjacent slime which isn't
+ // already at the merge cap and is closer to the target than
+ // our current position.
+ if(other_thing
+ && other_thing->mons_species() == MONS_SLIME_CREATURE
+ && other_thing->attitude == thing->attitude)
+ {
+ int new_blob_count = other_thing->number + thing->number;
+
+ if(new_blob_count < max_slime_merge
+ && grid_distance(thing->target, thing->pos()) >
+ grid_distance(thing->target, target))
+ {
+ return _merge_slimes(thing, other_thing);
+ }
+ }
+ } // end check adjacent
+ }// end merge check
+
+ // Couldn't merge or split
+ return false;
+}
+
bool orc_battle_cry(monsters *chief)
{
const actor *foe = chief->get_foe();
diff --git a/crawl-ref/source/mstuff2.h b/crawl-ref/source/mstuff2.h
index 70238e5835..e5f50f1f42 100644
--- a/crawl-ref/source/mstuff2.h
+++ b/crawl-ref/source/mstuff2.h
@@ -28,6 +28,7 @@ bool monster_random_space(monster_type mon, coord_def& target,
bool forbid_sanctuary = false);
void monster_teleport(monsters *monster, bool instan, bool silent = false);
bool ugly_thing_mutate(monsters *ugly, bool proximity = false);
+bool slime_split_merge(monsters * thing);
bool orc_battle_cry(monsters *chief);
bool orange_statue_effects(monsters *mons);
bool silver_statue_effects(monsters *mons);