summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarshan Shaligram <dshaligram@users.sourceforge.net>2009-12-29 19:48:21 +0530
committerDarshan Shaligram <dshaligram@users.sourceforge.net>2009-12-29 19:48:21 +0530
commit9cc1ba155f353a235d38e785c1eefc984f4d42c1 (patch)
tree9a956049f0d39a37b727bb06154743fee883b3c0
parentcfdb6e14f51f38e104444acf22e17706fcda104d (diff)
downloadcrawl-ref-9cc1ba155f353a235d38e785c1eefc984f4d42c1.tar.gz
crawl-ref-9cc1ba155f353a235d38e785c1eefc984f4d42c1.zip
Boost Ilsuiw stats and give her Call Tide, which strongly boosts the tide in Shoals, pegs it towards high tide, and includes a local high tide maximum centered on Ilsuiw, which can be double the height of the normal high tide.
-rw-r--r--crawl-ref/source/dgn-shoals.cc108
-rw-r--r--crawl-ref/source/dgn-shoals.h3
-rw-r--r--crawl-ref/source/enum.h2
-rw-r--r--crawl-ref/source/main.cc2
-rw-r--r--crawl-ref/source/mon-abil.cc12
-rw-r--r--crawl-ref/source/mon-cast.cc13
-rw-r--r--crawl-ref/source/mon-data.h2
-rw-r--r--crawl-ref/source/mon-gear.cc12
-rw-r--r--crawl-ref/source/mon-spll.h5
-rw-r--r--crawl-ref/source/mon-stuff.cc3
-rw-r--r--crawl-ref/source/mon-util.cc7
-rw-r--r--crawl-ref/source/monster.cc7
-rw-r--r--crawl-ref/source/monster.h1
-rw-r--r--crawl-ref/source/spl-data.h12
-rw-r--r--crawl-ref/source/view.cc13
-rw-r--r--crawl-ref/source/view.h1
16 files changed, 169 insertions, 34 deletions
diff --git a/crawl-ref/source/dgn-shoals.cc b/crawl-ref/source/dgn-shoals.cc
index b88873d5b5..b91dc3a195 100644
--- a/crawl-ref/source/dgn-shoals.cc
+++ b/crawl-ref/source/dgn-shoals.cc
@@ -1,6 +1,7 @@
#include "AppHdr.h"
#include "branch.h"
+#include "colour.h"
#include "coord.h"
#include "coordit.h"
#include "dungeon.h"
@@ -10,10 +11,12 @@
#include "items.h"
#include "maps.h"
#include "mgen_data.h"
+#include "mon-iter.h"
#include "mon-place.h"
#include "mon-util.h"
#include "random.h"
#include "terrain.h"
+#include "view.h"
#include <algorithm>
#include <vector>
@@ -42,6 +45,23 @@ const int N_PERTURB_OFFSET_HIGH = 45;
const int PERTURB_OFFSET_RADIUS_LOW = 2;
const int PERTURB_OFFSET_RADIUS_HIGH = 7;
+// The raw tide height / TIDE_MULTIPLIER is the actual tide height. The higher
+// the tide multiplier, the slower the tide advances and recedes. A multiplier
+// of X implies that the tide will advance visibly about once in X turns.
+const int TIDE_MULTIPLIER = 30;
+
+const int LOW_TIDE = -18 * TIDE_MULTIPLIER;
+const int HIGH_TIDE = 25 * TIDE_MULTIPLIER;
+
+// The highest a tide can be called by a tide caller such as Ilsuiw.
+const int HIGH_CALLED_TIDE = 25;
+const int TIDE_DECEL_MARGIN = 8;
+const int PEAK_TIDE_ACCEL = 2;
+
+// The area around the user of a call tide spell that is subject to
+// local tide elevation.
+const int TIDE_CALL_RADIUS = 8;
+
const int _shoals_margin = 6;
enum shoals_height_thresholds
@@ -60,6 +80,10 @@ enum tide_direction
};
static tide_direction _shoals_tide_direction;
+static monsters *tide_caller = NULL;
+static coord_def tide_caller_pos;
+static long tide_called_turns = 0L;
+static int tide_called_peak = 0;
static dungeon_feature_type _shoals_feature_by_height(int height)
{
@@ -816,18 +840,16 @@ void shoals_postprocess_level()
}
}
-// The raw tide height / TIDE_MULTIPLIER is the actual tide height. The higher
-// the tide multiplier, the slower the tide advances and recedes. A multiplier
-// of X implies that the tide will advance visibly about once in X turns.
-const int TIDE_MULTIPLIER = 30;
-
-const int LOW_TIDE = -18 * TIDE_MULTIPLIER;
-const int HIGH_TIDE = 25 * TIDE_MULTIPLIER;
-const int TIDE_DECEL_MARGIN = 8;
-const int START_TIDE_RISE = 2;
-
static void _shoals_run_tide(int &tide, int &acc)
{
+ // If someone is calling the tide, the acceleration is clamped high.
+ if (tide_caller)
+ acc = 15;
+ // If there's no tide caller and our acceleration is suspiciously high,
+ // reset it to a falling tide at peak acceleration.
+ else if (abs(acc) > PEAK_TIDE_ACCEL)
+ acc = -PEAK_TIDE_ACCEL;
+
tide += acc;
tide = std::max(std::min(tide, HIGH_TIDE), LOW_TIDE);
if ((tide == HIGH_TIDE && acc > 0)
@@ -836,7 +858,7 @@ static void _shoals_run_tide(int &tide, int &acc)
bool in_decel_margin =
(abs(tide - HIGH_TIDE) < TIDE_DECEL_MARGIN)
|| (abs(tide - LOW_TIDE) < TIDE_DECEL_MARGIN);
- if ((abs(acc) == 2) == in_decel_margin)
+ if ((abs(acc) > 1) == in_decel_margin)
acc = in_decel_margin? acc / 2 : acc * 2;
}
@@ -956,6 +978,23 @@ static void _shoals_apply_tide_at(coord_def c, int tide)
_shoals_apply_tide_feature_at(c, newfeat);
}
+static int _shoals_tide_at(coord_def pos, int base_tide)
+{
+ if (!tide_caller)
+ return base_tide;
+
+ const int rl_distance = grid_distance(pos, tide_caller_pos);
+ if (rl_distance > TIDE_CALL_RADIUS)
+ return base_tide;
+
+ const int distance =
+ static_cast<int>(sqrt((pos - tide_caller->pos()).abs()));
+ if (distance > TIDE_CALL_RADIUS)
+ return base_tide;
+
+ return (base_tide + std::max(0, tide_called_peak - distance * 3));
+}
+
static void _shoals_apply_tide(int tide)
{
std::vector<coord_def> pages[2];
@@ -980,7 +1019,7 @@ static void _shoals_apply_tide(int tide)
coord_def c(cpage[i]);
const bool was_wet(_shoals_tide_passable_feat(grd(c)));
seen_points(c) = true;
- _shoals_apply_tide_at(c, tide);
+ _shoals_apply_tide_at(c, _shoals_tide_at(c, tide));
const bool is_wet(feat_is_water(grd(c)));
// Only squares that were wet (before applying tide
@@ -1017,13 +1056,22 @@ static void _shoals_init_tide()
if (!env.properties.exists(ENVP_SHOALS_TIDE_KEY))
{
env.properties[ENVP_SHOALS_TIDE_KEY] = short(0);
- env.properties[ENVP_SHOALS_TIDE_VEL] = short(2);
+ env.properties[ENVP_SHOALS_TIDE_VEL] = short(PEAK_TIDE_ACCEL);
}
}
-void shoals_apply_tides(int turns_elapsed)
+static monsters *_shoals_find_tide_caller()
+{
+ for (monster_iterator mi; mi; ++mi)
+ if (mi->has_ench(ENCH_TIDE))
+ return *mi;
+ return NULL;
+}
+
+void shoals_apply_tides(int turns_elapsed, bool force)
{
- if (!player_in_branch(BRANCH_SHOALS) || !turns_elapsed
+ if (!player_in_branch(BRANCH_SHOALS)
+ || (!turns_elapsed && !force)
|| !env.heightmap.get())
{
return;
@@ -1035,6 +1083,20 @@ void shoals_apply_tides(int turns_elapsed)
turns_elapsed = turns_elapsed % TIDE_UNIT + TIDE_UNIT;
_shoals_init_tide();
+
+ unwind_var<monsters*> tide_caller_unwind(tide_caller,
+ _shoals_find_tide_caller());
+ if (tide_caller)
+ {
+ tide_called_turns = tide_caller->props[TIDE_CALL_TURN].get_long();
+ tide_called_turns = you.num_turns - tide_called_turns;
+ if (tide_called_turns < 1L)
+ tide_called_turns = 1L;
+ tide_called_peak = std::min(HIGH_CALLED_TIDE,
+ int(tide_called_turns * 5));
+ tide_caller_pos = tide_caller->pos();
+ }
+
int tide = env.properties[ENVP_SHOALS_TIDE_KEY].get_short();
int acc = env.properties[ENVP_SHOALS_TIDE_VEL].get_short();
const int old_tide = tide;
@@ -1042,10 +1104,24 @@ void shoals_apply_tides(int turns_elapsed)
_shoals_run_tide(tide, acc);
env.properties[ENVP_SHOALS_TIDE_KEY] = short(tide);
env.properties[ENVP_SHOALS_TIDE_VEL] = short(acc);
- if (old_tide / TIDE_MULTIPLIER != tide / TIDE_MULTIPLIER)
+ if (force
+ || tide_caller
+ || old_tide / TIDE_MULTIPLIER != tide / TIDE_MULTIPLIER)
{
_shoals_tide_direction =
tide > old_tide ? TIDE_RISING : TIDE_FALLING;
_shoals_apply_tide(tide / TIDE_MULTIPLIER);
}
}
+
+void shoals_release_tide(monsters *mons)
+{
+ if (player_in_branch(BRANCH_SHOALS)
+ && player_can_hear(you.pos()))
+ {
+ mprf(MSGCH_SOUND, "The tide is released from %s call.",
+ mons->name(DESC_NOCAP_YOUR, true).c_str());
+ flash_view_delay(ETC_WATER, 150);
+ shoals_apply_tides(0, true);
+ }
+}
diff --git a/crawl-ref/source/dgn-shoals.h b/crawl-ref/source/dgn-shoals.h
index f558f6606f..1d14c620f2 100644
--- a/crawl-ref/source/dgn-shoals.h
+++ b/crawl-ref/source/dgn-shoals.h
@@ -3,6 +3,7 @@
void prepare_shoals(int level_number);
void shoals_postprocess_level();
-void shoals_apply_tides(int turns_elapsed);
+void shoals_apply_tides(int turns_elapsed, bool force = false);
+void shoals_release_tide(monsters *caller);
#endif
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index 08ae63c36e..f770323cfc 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -1254,6 +1254,7 @@ enum enchant_type
ENCH_SPORE_PRODUCTION, // 35
ENCH_SLOUCH,
ENCH_SWIFT,
+ ENCH_TIDE,
// Update enchantment names in mon-util.cc when adding or removing
// enchantments.
@@ -2930,6 +2931,7 @@ enum spell_type
SPELL_SUMMON_RAKSHASA,
SPELL_SUMMON_PLAYER_GHOST,
SPELL_PRIMAL_WAVE,
+ SPELL_CALL_TIDE,
NUM_SPELLS
};
diff --git a/crawl-ref/source/main.cc b/crawl-ref/source/main.cc
index 7f3ccb2592..1ad6e1af6c 100644
--- a/crawl-ref/source/main.cc
+++ b/crawl-ref/source/main.cc
@@ -4631,7 +4631,7 @@ static void _compile_time_asserts()
COMPILE_CHECK(SP_VAMPIRE == 30 , c3);
COMPILE_CHECK(SPELL_DEBUGGING_RAY == 103 , c4);
COMPILE_CHECK(SPELL_RETURNING_AMMUNITION == 162 , c5);
- COMPILE_CHECK(NUM_SPELLS == 216 , c6);
+ COMPILE_CHECK(NUM_SPELLS == 217 , c6);
//jmf: NEW ASSERTS: we ought to do a *lot* of these
COMPILE_CHECK(NUM_SPECIES < SP_UNKNOWN , c7);
diff --git a/crawl-ref/source/mon-abil.cc b/crawl-ref/source/mon-abil.cc
index 5325d3f27b..781778d6d3 100644
--- a/crawl-ref/source/mon-abil.cc
+++ b/crawl-ref/source/mon-abil.cc
@@ -303,17 +303,7 @@ static bool _do_merge(monsters *initial_slime, monsters *merge_to)
merge_to->name(DESC_NOCAP_A).c_str());
}
- flash_view(LIGHTGREEN);
-
- int flash_delay = 150;
- // Scale delay to match change in arena_delay.
- if (crawl_state.arena)
- {
- flash_delay *= Options.arena_delay;
- flash_delay /= 600;
- }
-
- delay(flash_delay);
+ flash_view_delay(LIGHTGREEN, 150);
}
else if (you.can_see(initial_slime))
mpr("A slime creature suddenly disappears!");
diff --git a/crawl-ref/source/mon-cast.cc b/crawl-ref/source/mon-cast.cc
index 42b7b52da5..5190625c61 100644
--- a/crawl-ref/source/mon-cast.cc
+++ b/crawl-ref/source/mon-cast.cc
@@ -839,6 +839,7 @@ bool setup_mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast,
case SPELL_SUMMON_EYEBALLS:
case SPELL_SUMMON_BUTTERFLIES:
case SPELL_MISLEAD:
+ case SPELL_CALL_TIDE:
return (true);
default:
if (check_validity)
@@ -1678,6 +1679,18 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast,
simple_monster_message(monster, " seems to move somewhat quicker.");
return;
+ case SPELL_CALL_TIDE:
+ {
+ const int tide_duration = random_range(18, 50, 2);
+ monster->add_ench(mon_enchant(ENCH_TIDE, 0, KC_OTHER,
+ tide_duration * 10));
+ monster->props[TIDE_CALL_TURN] = you.num_turns;
+ simple_monster_message(monster,
+ " sings a water chant to call the tide!");
+ flash_view_delay(ETC_WATER, 300);
+ return;
+ }
+
case SPELL_SUMMON_SMALL_MAMMALS:
case SPELL_VAMPIRE_SUMMON:
if (spell_cast == SPELL_SUMMON_SMALL_MAMMALS)
diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h
index e5e5fb7b98..6ce2103a22 100644
--- a/crawl-ref/source/mon-data.h
+++ b/crawl-ref/source/mon-data.h
@@ -4626,7 +4626,7 @@ static monsterentry mondata[] = {
MR_RES_POISON | MR_RES_COLD,
500, 10, MONS_MERFOLK, MONS_MERFOLK, MH_NATURAL, -7,
{ {AT_HIT, AF_PLAIN, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
- { 9, 0, 0, 54 },
+ { 16, 0, 0, 150 },
5, 18, MST_ILSUIW, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT,
I_NORMAL, HT_AMPHIBIOUS_WATER, FL_NONE, 10, DEFAULT_ENERGY,
MONUSE_WEAPONS_ARMOUR, MONEAT_NOTHING, SIZE_MEDIUM
diff --git a/crawl-ref/source/mon-gear.cc b/crawl-ref/source/mon-gear.cc
index 393d4680b7..8affc9587f 100644
--- a/crawl-ref/source/mon-gear.cc
+++ b/crawl-ref/source/mon-gear.cc
@@ -12,6 +12,7 @@
#include "mon-gear.h"
#include "artefact.h"
+#include "colour.h"
#include "dungeon.h"
#include "env.h"
#include "itemprop.h"
@@ -582,6 +583,17 @@ static item_make_species_type _give_weapon(monsters *mon, int level,
}
break;
+ case MONS_ILSUIW:
+ item_race = MAKE_ITEM_NO_RACE;
+ item.base_type = OBJ_WEAPONS;
+ item.sub_type = WPN_TRIDENT;
+ item.special = SPWPN_FREEZING;
+ item.plus = random_range(-1, 6, 2);
+ item.plus2 = random_range(-1, 6, 2);
+ item.colour = ETC_ICE;
+ force_item = true;
+ break;
+
case MONS_MERFOLK_IMPALER:
item_race = MAKE_ITEM_NO_RACE;
item.base_type = OBJ_WEAPONS;
diff --git a/crawl-ref/source/mon-spll.h b/crawl-ref/source/mon-spll.h
index 2137cbbacb..344ae8e6b8 100644
--- a/crawl-ref/source/mon-spll.h
+++ b/crawl-ref/source/mon-spll.h
@@ -1043,8 +1043,8 @@
{ MST_ILSUIW,
{
- SPELL_THROW_FROST, // was: SPELL_CONFUSED (jpeg)
- SPELL_SLOW,
+ SPELL_THROW_ICICLE,
+ SPELL_CALL_TIDE,
SPELL_INVISIBILITY,
SPELL_BLINK,
SPELL_WATER_ELEMENTALS,
@@ -1323,7 +1323,6 @@
{
SPELL_PRIMAL_WAVE,
SPELL_BOLT_OF_COLD,
- // Ice form would be neat.
SPELL_THROW_ICICLE,
SPELL_NO_SPELL,
SPELL_NO_SPELL,
diff --git a/crawl-ref/source/mon-stuff.cc b/crawl-ref/source/mon-stuff.cc
index 3db902c13b..ca7b9cf12c 100644
--- a/crawl-ref/source/mon-stuff.cc
+++ b/crawl-ref/source/mon-stuff.cc
@@ -1422,6 +1422,9 @@ int monster_die(monsters *monster, killer_type killer,
return (-1);
}
+ // If the monster was calling the tide, let go now.
+ monster->del_ench(ENCH_TIDE);
+
crawl_state.inc_mon_acting(monster);
ASSERT(!( YOU_KILL(killer) && crawl_state.arena ));
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 3687e1711c..5895a0c542 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -2390,6 +2390,13 @@ bool ms_waste_of_time( const monsters *mon, spell_type monspell )
// handled here as well. - bwr
switch (monspell)
{
+ case SPELL_CALL_TIDE:
+ return (!player_in_branch(BRANCH_SHOALS)
+ || mon->has_ench(ENCH_TIDE)
+ || !foe
+ || (grd(mon->pos()) == DNGN_DEEP_WATER
+ && grd(foe->pos()) == DNGN_DEEP_WATER));
+
case SPELL_BRAIN_FEED:
ret = (foe != &you);
break;
diff --git a/crawl-ref/source/monster.cc b/crawl-ref/source/monster.cc
index f6003c3b81..2f83c01d6f 100644
--- a/crawl-ref/source/monster.cc
+++ b/crawl-ref/source/monster.cc
@@ -12,6 +12,7 @@
#include "coordit.h"
#include "delay.h"
#include "dgnevent.h"
+#include "dgn-shoals.h"
#include "directn.h"
#include "env.h"
#include "fight.h"
@@ -4305,6 +4306,10 @@ void monsters::remove_enchantment_effect(const mon_enchant &me, bool quiet)
{
switch (me.ench)
{
+ case ENCH_TIDE:
+ shoals_release_tide(this);
+ break;
+
case ENCH_BERSERK:
scale_hp(2, 3);
break;
@@ -6031,7 +6036,7 @@ static const char *enchant_names[] =
"short-lived", "paralysis", "sick", "sleep", "fatigue", "held",
"blood-lust", "neutral", "petrifying", "petrified", "magic-vulnerable",
"soul-ripe", "decay", "hungry", "flopping", "spore-producing",
- "downtrodden", "swift", "bug"
+ "downtrodden", "swift", "tide", "bug"
};
static const char *_mons_enchantment_name(enchant_type ench)
diff --git a/crawl-ref/source/monster.h b/crawl-ref/source/monster.h
index 16ec367332..b93ed65571 100644
--- a/crawl-ref/source/monster.h
+++ b/crawl-ref/source/monster.h
@@ -4,6 +4,7 @@
#include "actor.h"
const int KRAKEN_TENTACLE_RANGE = 3;
+#define TIDE_CALL_TURN "tide-call-turn"
class mon_enchant
{
diff --git a/crawl-ref/source/spl-data.h b/crawl-ref/source/spl-data.h
index 6a62b9ed09..db5979a031 100644
--- a/crawl-ref/source/spl-data.h
+++ b/crawl-ref/source/spl-data.h
@@ -2654,6 +2654,18 @@
false
},
+{
+ SPELL_CALL_TIDE, "Call Tide",
+ SPTYP_TRANSLOCATION,
+ SPFLAG_MONSTER,
+ 7,
+ 0,
+ -1, -1,
+ 0,
+ NULL,
+ false,
+ false
+},
{
SPELL_NO_SPELL, "nonexistent spell",
diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc
index b8e6447a89..94ad2a572c 100644
--- a/crawl-ref/source/view.cc
+++ b/crawl-ref/source/view.cc
@@ -635,6 +635,19 @@ void flash_view(int colour)
viewwindow(false, false);
}
+void flash_view_delay(int colour, long flash_delay)
+{
+ flash_view(colour);
+ // Scale delay to match change in arena_delay.
+ if (crawl_state.arena)
+ {
+ flash_delay *= Options.arena_delay;
+ flash_delay /= 600;
+ }
+
+ delay(flash_delay);
+}
+
static void _debug_pane_bounds()
{
#if DEBUG_PANE_BOUNDS
diff --git a/crawl-ref/source/view.h b/crawl-ref/source/view.h
index 7a618c182b..70029c000d 100644
--- a/crawl-ref/source/view.h
+++ b/crawl-ref/source/view.h
@@ -37,6 +37,7 @@ std::string screenshot(bool fullscreen = false);
bool view_update();
void view_update_at(const coord_def &pos);
void flash_view(int colour = BLACK); // inside #ifndef USE_TILE?
+void flash_view_delay(int colour = BLACK, long delay = 150);
#ifndef USE_TILE
void flash_monster_colour(const monsters *mon, unsigned char fmc_colour,
int fmc_delay);