summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/teleport.cc
diff options
context:
space:
mode:
authorShmuale Mark <shm.mark@gmail.com>2014-06-19 16:05:04 -0400
committerShmuale Mark <shm.mark@gmail.com>2014-06-22 10:03:45 -0400
commit465957cba490a2a9d5444a64523572a90cfb837f (patch)
tree536c94ce0702e60217120aa2bb27325aff1b8f2d /crawl-ref/source/teleport.cc
parent393eda0d444702a7eda580e6c363bbdcaba8d54e (diff)
downloadcrawl-ref-465957cba490a2a9d5444a64523572a90cfb837f.tar.gz
crawl-ref-465957cba490a2a9d5444a64523572a90cfb837f.zip
The great mon-stuff migration.
A good deal of functions move to the two new files, mon-poly and mon-message. Of the others, some go to where they are used, some to mon-util, and a few are made member methods of monster. This probably breaks Xcode compilation, and I'm not able to test the changes I made to MSVC that will (hopefully) keep it working.
Diffstat (limited to 'crawl-ref/source/teleport.cc')
-rw-r--r--crawl-ref/source/teleport.cc249
1 files changed, 248 insertions, 1 deletions
diff --git a/crawl-ref/source/teleport.cc b/crawl-ref/source/teleport.cc
index b028924267..92e18e03ee 100644
--- a/crawl-ref/source/teleport.cc
+++ b/crawl-ref/source/teleport.cc
@@ -7,22 +7,27 @@
#include "teleport.h"
+#include "act-iter.h"
#include "cloud.h"
#include "coord.h"
#include "coordit.h"
#include "delay.h"
#include "env.h"
#include "fprop.h"
+#include "libutil.h"
#include "los.h"
#include "losglobal.h"
#include "monster.h"
-#include "mon-stuff.h"
+#include "mon-behv.h"
+#include "mon-death.h"
+#include "mon-place.h"
#include "player.h"
#include "random.h"
#include "random-weight.h"
#include "state.h"
#include "stuff.h"
#include "terrain.h"
+#include "view.h"
bool player::blink_to(const coord_def& dest, bool quiet)
{
@@ -114,6 +119,248 @@ bool monster::blink_to(const coord_def& dest, bool quiet, bool jump)
return true;
}
+// If the returned value is mon.pos(), then nothing was found.
+static coord_def _random_monster_nearby_habitable_space(const monster& mon)
+{
+ const bool respect_sanctuary = mon.wont_attack();
+
+ coord_def target;
+ int tries;
+
+ for (tries = 0; tries < 150; ++tries)
+ {
+ const coord_def delta(random2(13) - 6, random2(13) - 6);
+
+ // Check that we don't get something too close to the
+ // starting point.
+ if (delta.origin())
+ continue;
+
+ // Blinks by 1 cell are not allowed.
+ if (delta.rdist() == 1)
+ continue;
+
+ // Update target.
+ target = delta + mon.pos();
+
+ // Check that the target is valid and survivable.
+ if (!in_bounds(target))
+ continue;
+
+ if (!monster_habitable_grid(&mon, grd(target)))
+ continue;
+
+ if (respect_sanctuary && is_sanctuary(target))
+ continue;
+
+ if (target == you.pos())
+ continue;
+
+ if (!cell_see_cell(mon.pos(), target, LOS_NO_TRANS))
+ continue;
+
+ // Survived everything, break out (with a good value of target.)
+ break;
+ }
+
+ if (tries == 150)
+ target = mon.pos();
+
+ return target;
+}
+
+bool monster_blink(monster* mons, bool quiet)
+{
+ coord_def near = _random_monster_nearby_habitable_space(*mons);
+ return mons->blink_to(near, quiet);
+}
+
+bool monster_space_valid(const monster* mons, coord_def target,
+ bool forbid_sanctuary)
+{
+ if (!in_bounds(target))
+ return false;
+
+ // Don't land on top of another monster.
+ if (actor_at(target))
+ return false;
+
+ if (is_sanctuary(target) && forbid_sanctuary)
+ return false;
+
+ // Don't go into no_ctele_into or n_rtele_into cells.
+ if (testbits(env.pgrid(target), FPROP_NO_CTELE_INTO))
+ return false;
+ if (testbits(env.pgrid(target), FPROP_NO_RTELE_INTO))
+ return false;
+
+ return monster_habitable_grid(mons, grd(target));
+}
+
+static bool _monster_random_space(const monster* mons, coord_def& target,
+ bool forbid_sanctuary)
+{
+ int tries = 0;
+ while (tries++ < 1000)
+ {
+ target = random_in_bounds();
+ if (monster_space_valid(mons, target, forbid_sanctuary))
+ return true;
+ }
+
+ return false;
+}
+
+void mons_relocated(monster* mons)
+{
+ // If the main body teleports get rid of the tentacles
+ if (mons_is_tentacle_head(mons_base_type(mons)))
+ {
+ int headnum = mons->mindex();
+
+ if (invalid_monster_index(headnum))
+ return;
+
+ for (monster_iterator mi; mi; ++mi)
+ {
+ if (mi->is_child_tentacle_of(mons))
+ {
+ for (monster_iterator connect; connect; ++connect)
+ {
+ if (connect->is_child_tentacle_of(*mi))
+ monster_die(*connect, KILL_RESET, -1, true, false);
+ }
+ monster_die(*mi, KILL_RESET, -1, true, false);
+ }
+ }
+ }
+ // If a tentacle/segment is relocated just kill the tentacle
+ else if (mons->is_child_monster())
+ {
+ int base_id = mons->mindex();
+
+ monster* tentacle = mons;
+
+ if (mons->is_child_tentacle_segment()
+ && !::invalid_monster_index(base_id)
+ && menv[base_id].is_parent_monster_of(mons))
+ {
+ tentacle = &menv[base_id];
+ }
+
+ for (monster_iterator connect; connect; ++connect)
+ {
+ if (connect->is_child_tentacle_of(tentacle))
+ monster_die(*connect, KILL_RESET, -1, true, false);
+ }
+
+ monster_die(tentacle, KILL_RESET, -1, true, false);
+ }
+ else if (mons->type == MONS_ELDRITCH_TENTACLE
+ || mons->type == MONS_ELDRITCH_TENTACLE_SEGMENT)
+ {
+ int base_id = mons->type == MONS_ELDRITCH_TENTACLE
+ ? mons->mindex() : mons->number;
+
+ monster_die(&menv[base_id], KILL_RESET, -1, true, false);
+
+ for (monster_iterator mit; mit; ++mit)
+ {
+ if (mit->type == MONS_ELDRITCH_TENTACLE_SEGMENT
+ && (int) mit->number == base_id)
+ {
+ monster_die(*mit, KILL_RESET, -1, true, false);
+ }
+ }
+
+ }
+
+ mons->clear_clinging();
+}
+
+void monster_teleport(monster* mons, bool instan, bool silent)
+{
+ bool was_seen = !silent && you.can_see(mons) && !mons_is_lurking(mons);
+
+ if (!instan)
+ {
+ if (mons->del_ench(ENCH_TP))
+ {
+ if (!silent)
+ simple_monster_message(mons, " seems more stable.");
+ }
+ else
+ {
+ if (!silent)
+ simple_monster_message(mons, " looks slightly unstable.");
+
+ mons->add_ench(mon_enchant(ENCH_TP, 0, 0,
+ random_range(20, 30)));
+ }
+
+ return;
+ }
+
+ coord_def newpos;
+
+ if (newpos.origin())
+ _monster_random_space(mons, newpos, !mons->wont_attack());
+
+ // XXX: If the above function didn't find a good spot, return now
+ // rather than continue by slotting the monster (presumably)
+ // back into its old location (previous behaviour). This seems
+ // to be much cleaner and safer than relying on what appears to
+ // have been a mistake.
+ if (newpos.origin())
+ return;
+
+ if (!silent)
+ simple_monster_message(mons, " disappears!");
+
+ const coord_def oldplace = mons->pos();
+
+ // Pick the monster up.
+ mgrd(oldplace) = NON_MONSTER;
+
+ // Move it to its new home.
+ mons->moveto(newpos, true);
+
+ // And slot it back into the grid.
+ mgrd(mons->pos()) = mons->mindex();
+
+ const bool now_visible = mons_near(mons);
+ if (!silent && now_visible)
+ {
+ if (was_seen)
+ simple_monster_message(mons, " reappears nearby!");
+ else
+ {
+ // Even if it doesn't interrupt an activity (the player isn't
+ // delayed, the monster isn't hostile) we still want to give
+ // a message.
+ activity_interrupt_data ai(mons, SC_TELEPORT_IN);
+ if (!interrupt_activity(AI_SEE_MONSTER, ai))
+ simple_monster_message(mons, " appears out of thin air!");
+ }
+ }
+
+ if (mons->visible_to(&you) && now_visible)
+ handle_seen_interrupt(mons);
+
+ // Leave a purple cloud.
+ // XXX: If silent is true, this is not an actual teleport, but
+ // the game moving a monster out of the way.
+ if (!silent && !cell_is_solid(oldplace))
+ place_cloud(CLOUD_TLOC_ENERGY, oldplace, 1 + random2(3), mons);
+
+ mons->check_redraw(oldplace);
+ mons->apply_location_effects(oldplace);
+
+ mons_relocated(mons);
+
+ shake_off_monsters(mons);
+}
+
// Try to find a "safe" place for moved close or far from the target.
// keep_los indicates that the destination should be in LOS of the target.
//