summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/mon-project.cc
diff options
context:
space:
mode:
authorChris Campbell <chriscampbell89@gmail.com>2012-03-31 17:21:43 +0100
committerChris Campbell <chriscampbell89@gmail.com>2012-03-31 17:21:43 +0100
commit3ca1b2e54e3361b83636cc96518596fa68403962 (patch)
tree9de834a48fa43e83f40b5a33c1b79574ec722cfe /crawl-ref/source/mon-project.cc
parent62922bcad0094f95a4fae3e58d2d00e4b28debb9 (diff)
parentd1ec1219830de0075c12e99f8c0caf8ed04c58f5 (diff)
downloadcrawl-ref-3ca1b2e54e3361b83636cc96518596fa68403962.tar.gz
crawl-ref-3ca1b2e54e3361b83636cc96518596fa68403962.zip
Merge branch 'boulder_beetles'
Diffstat (limited to 'crawl-ref/source/mon-project.cc')
-rw-r--r--crawl-ref/source/mon-project.cc305
1 files changed, 305 insertions, 0 deletions
diff --git a/crawl-ref/source/mon-project.cc b/crawl-ref/source/mon-project.cc
index 4fb3531462..2550134cd9 100644
--- a/crawl-ref/source/mon-project.cc
+++ b/crawl-ref/source/mon-project.cc
@@ -538,3 +538,308 @@ void iood_catchup(monster* mons, int pturns)
if (_iood_catchup_move(mon))
return;
}
+
+bool boulder_start(monster *mon, bolt *beam)
+{
+ mon->add_ench(ENCH_ROLLING);
+ simple_monster_message(mon, " curls into a ball and starts rolling!");
+ // Work out x/y/vx/vy from beam
+ beam->choose_ray();
+ mon->props["boulder_x"].get_float() = beam->ray.r.start.x - 0.5;
+ mon->props["boulder_y"].get_float() = beam->ray.r.start.y - 0.5;
+ mon->props["boulder_vx"].get_float() = beam->ray.r.dir.x;
+ mon->props["boulder_vy"].get_float() = beam->ray.r.dir.y;
+ boulder_act(*mon);
+ return true;
+}
+bool boulder_flee(monster *mon, bolt *beam)
+{
+ mon->add_ench(ENCH_ROLLING);
+ simple_monster_message(mon, " curls into a ball and rolls away!");
+ // Work out x/y/vx/vy from beam
+ beam->choose_ray();
+ mon->props["boulder_x"].get_float() = beam->ray.r.start.x - 0.5;
+ mon->props["boulder_y"].get_float() = beam->ray.r.start.y - 0.5;
+ mon->props["boulder_vx"].get_float() = -beam->ray.r.dir.x;
+ mon->props["boulder_vy"].get_float() = -beam->ray.r.dir.y;
+ boulder_act(*mon);
+ return true;
+}
+
+static void _boulder_stop(monster& mon, bool msg = true)
+{
+ if (mon.type==MONS_BOULDER_BEETLE)
+ {
+ /*
+ if (msg)
+ simple_monster_message(&mon, " comes to a halt.");
+ */
+
+ mon.del_ench(ENCH_ROLLING,!msg);
+ }
+}
+
+// Alas, too much differs to reuse beam shield blocks :(
+static bool _boulder_shielded(monster& mon, actor &victim)
+{
+ if (!victim.shield() || victim.incapacitated())
+ return (false);
+
+ const int to_hit = 15 + mon.hit_dice/2;
+ const int con_block = random2(to_hit + victim.shield_block_penalty());
+ const int pro_block = victim.shield_bonus();
+ dprf("boulder shield: pro %d, con %d", pro_block, con_block);
+ return (pro_block >= con_block);
+}
+
+static bool _boulder_hit(monster& mon, const coord_def &pos)
+{
+ bolt beam;
+ beam.name = "rolling boulder";
+ beam.flavour = BEAM_MISSILE;
+ beam.attitude = mon.attitude;
+
+ actor *caster = &mon;
+ beam.set_agent(caster);
+ beam.colour = WHITE;
+ beam.glyph = dchar_glyph(DCHAR_FIRED_BURST);
+ beam.range = 1;
+ beam.source = pos;
+ beam.target = pos;
+ beam.hit = AUTOMATIC_HIT;
+ beam.source_name = mon.name(DESC_PLAIN, true);
+
+ int pow = mon.hit_dice * 6;
+ pow = stepdown_value(pow, 30, 30, 200, -1);
+ beam.damage = dice_def(4, pow / 4);
+
+ beam.ex_size = 1;
+ beam.loudness = 5;
+
+ beam.fire();
+
+ return (true);
+}
+
+bool boulder_act(monster& mon)
+{
+ // Handles Boulder Beetle in Rolling form
+ // returns true if stopped rolling
+
+ float x = mon.props["boulder_x"];
+ float y = mon.props["boulder_y"];
+ float vx = mon.props["boulder_vx"];
+ float vy = mon.props["boulder_vy"];
+
+ dprf("boulder_act: pos=(%d,%d) rpos=(%f,%f) v=(%f,%f) foe=%d",
+ mon.pos().x, mon.pos().y,
+ x, y, vx, vy, mon.foe);
+
+ if (!vx && !vy) // not initialized
+ {
+ _boulder_stop(mon);
+ return (true);
+ }
+
+ _normalize(vx, vy);
+ /* IOOD swerving code, could reinstigate if it make boulders more fun
+ const actor *foe = mon.get_foe();
+ // If the target is gone, the orb continues on a ballistic course since
+ // picking a new one would require intelligence.
+
+ if (foe)
+ {
+ const coord_def target = foe->pos();
+ float dx = target.x - x;
+ float dy = target.y - y;
+ _normalize(dx, dy);
+
+ // Special case:
+ // Moving diagonally when the orb is just about to hit you
+ // 2
+ // ->*1
+ // (from 1 to 2) would be a guaranteed escape. This may be
+ // realistic (strafing!), but since the game has no non-cheesy
+ // means of waiting a small fraction of a turn, we don't want it.
+ const int old_t_pos = mon.props["iood_tpos"].get_short();
+ const coord_def rpos(static_cast<int>(round(x)), static_cast<int>(round(y)));
+ if (old_t_pos && old_t_pos != (256 * target.x + target.y)
+ && (rpos - target).rdist() <= 1
+ // ... but following an orb is ok.
+ && _in_front(vx, vy, dx, dy, 1.5)) // ~97 degrees
+ {
+ vx = dx;
+ vy = dy;
+ }
+ mon.props["iood_tpos"].get_short() = 256 * target.x + target.y;
+
+ if (!_in_front(vx, vy, dx, dy, 0.3)) // ~17 degrees
+ {
+ float ax, ay;
+ if (dy*vx < dx*vy)
+ ax = vy, ay = -vx, dprf("iood: veering left");
+ else
+ ax = -vy, ay = vx, dprf("iood: veering right");
+ vx += ax * 0.3;
+ vy += ay * 0.3;
+ }
+ else
+ dprf("iood: keeping course");
+
+ _normalize(vx, vy);
+ mon.props["iood_vx"] = vx;
+ mon.props["iood_vy"] = vy;
+ }
+ */
+move_again:
+
+ x += vx;
+ y += vy;
+
+ mon.props["boulder_x"] = x;
+ mon.props["boulder_y"] = y;
+// mon.props["iood_distance"].get_int()++;
+
+ const coord_def pos(static_cast<int>(round(x)), static_cast<int>(round(y)));
+ if (!in_bounds(pos))
+ {
+ _boulder_stop(mon);
+ return (true);
+ }
+
+ if (pos == mon.pos())
+ return (false);
+
+ // Place a dust trail (so we can see which way it's rolling)
+ place_cloud(CLOUD_DUST_TRAIL, mon.pos(), 2 + random2(3), &mon);
+
+ actor *victim = actor_at(pos);
+ if (cell_is_solid(pos) || victim)
+ {
+ if (cell_is_solid(pos))
+ {
+ if (you.see_cell(pos))
+ {
+ mprf("%s hits %s", mon.name(DESC_THE, true).c_str(),
+ feature_description(pos, false, DESC_A).c_str());
+ }
+ _boulder_stop(mon,you.see_cell(pos));
+ }
+
+ monster* mons = (victim && victim->atype() == ACT_MONSTER) ?
+ (monster*) victim : 0;
+
+ if (mons && mons_is_boulder(mons))
+ {
+ if (mon.observable())
+ mpr("The boulders collide with a stupendous crash!");
+ else
+ noisy(20, pos, "You hear a loud crashing sound!");
+
+ // Remove ROLLING and add DAZED
+ mon.del_ench(ENCH_ROLLING,true);
+ mons->del_ench(ENCH_ROLLING,true);
+ mon.add_ench(ENCH_CONFUSION);
+ mons->add_ench(ENCH_CONFUSION);
+ return (true);
+ }
+
+ if (mons && mons->submerged())
+ {
+ // Try to swap with the submerged creature.
+ if (mons->is_habitable(mon.pos()))
+ {
+ dprf("boulder: Swapping with a submerged monster.");
+ mons->set_position(mon.pos());
+ mon.set_position(pos);
+ mgrd(mons->pos()) = mons->mindex();
+ mgrd(pos) = mon.mindex();
+
+ return (false);
+ }
+ else // if swap fails, move ahead
+ {
+ dprf("boulder: Boosting above a submerged monster (can't swap).");
+ mon.lose_energy(EUT_MOVE);
+ goto move_again;
+ }
+ }
+
+ if (victim && _boulder_shielded(mon, *victim))
+ {
+ item_def *shield = victim->shield();
+ if (!shield_reflects(*shield))
+ {
+ if (victim->atype() == ACT_PLAYER)
+ {
+ mprf("You block %s.", mon.name(DESC_THE, true).c_str());
+ }
+ else
+ {
+ simple_monster_message(mons, (" blocks "
+ + mon.name(DESC_THE, true) + ".").c_str());
+ }
+ victim->shield_block_succeeded(&mon);
+ _boulder_stop(mon);
+ return (true);
+ }
+
+ if (victim->atype() == ACT_PLAYER)
+ {
+ mprf("Your %s reflects %s!",
+ shield->name(DESC_PLAIN).c_str(),
+ mon.name(DESC_THE, true).c_str());
+ ident_reflector(shield);
+ }
+ else if (you.see_cell(pos))
+ {
+ if (victim->observable())
+ {
+ mprf("%s reflects %s with %s %s!",
+ victim->name(DESC_THE, true).c_str(),
+ mon.name(DESC_THE, true).c_str(),
+ mon.pronoun(PRONOUN_POSSESSIVE).c_str(),
+ shield->name(DESC_PLAIN).c_str());
+ ident_reflector(shield);
+ }
+ else
+ {
+ mprf("%s bounces off thin air!",
+ mon.name(DESC_THE, true).c_str());
+ }
+ }
+ victim->shield_block_succeeded(&mon);
+
+ mon.props["boulder_vx"] = vx = -vx;
+ mon.props["boulder_vy"] = vy = -vy;
+
+ // Need to get out of the victim's square.
+
+ mon.lose_energy(EUT_MOVE);
+ goto move_again;
+ }
+
+ // Yay for inconsistencies in beam-vs-player and beam-vs-monsters.
+ if (victim == &you)
+ mprf("%s hits you!", mon.name(DESC_THE, true).c_str());
+
+ if (_boulder_hit(mon, pos))
+ {
+ if (victim && victim->alive())
+ _boulder_stop(mon);
+ return (true);
+ }
+ }
+
+ if (!mon.move_to_pos(pos))
+ {
+ _boulder_stop(mon);
+ return (true);
+ }
+
+ // move_to_pos() just trashed the coords, set them again
+ mon.props["boulder_x"] = x;
+ mon.props["boulder_y"] = y;
+
+ return (false);
+}