[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Enigma-cvs] enigma/src actors.cc,1.44,1.45
From: |
Ralf Westram <address@hidden> |
Subject: |
[Enigma-cvs] enigma/src actors.cc,1.44,1.45 |
Date: |
Tue, 21 Oct 2003 19:46:48 +0000 |
Update of /cvsroot/enigma/enigma/src
In directory subversions:/tmp/cvs-serv25276
Modified Files:
actors.cc
Log Message:
- checks for other actors when selecting a respawn destination
- FreeRespawnLocationFinder: tests all fields affected by startingpos
[e.g. when Actor appears on the edge between two fields, both will be
checked].
- respawn avoids some dangerous floors (water, abyss and space)
and items (it-burnable-ignited)
- added assertions testing value returned by get_max_radius()
- const correctness for predicates
Index: actors.cc
===================================================================
RCS file: /cvsroot/enigma/enigma/src/actors.cc,v
retrieving revision 1.44
retrieving revision 1.45
diff -C2 -d -r1.44 -r1.45
*** actors.cc 20 Oct 2003 17:03:48 -0000 1.44
--- actors.cc 21 Oct 2003 19:46:46 -0000 1.45
***************
*** 47,50 ****
--- 47,54 ----
}
+ double Actor::get_max_radius() {
+ return 24/64.0;
+ }
+
void Actor::think(double /*dtime*/) {
GridPos field(actorinfo.pos);
***************
*** 67,70 ****
--- 71,75 ----
namespace {
+ // helper class to find good respawn positions
struct ExaminedLocation : public GridPos {
***************
*** 79,184 ****
typedef std::set<ExaminedLocation> ExaminedLocations;
! class FreeRespawnLocationFinder {
ExaminedLocations checked;
ExaminedLocations blocked;
ExaminedLocations candidates;
! void examine(GridPos p) {
! if (checked.find(p) == checked.end()) {
! if (Floor *fl = GetFloor(p)) {
! const string& k = fl->get_kind();
! if (k != "fl-abyss" && k != "fl-water" && k !=
"fl-space") { // good destination floor
! if (Stone *st = GetStone(p)) {
! if (st->is_movable() || st->is_floating())
! blocked.insert(p);
}
- else
- candidates.insert(p); // no stone -> good location
}
}
! checked.insert(p); // don't examine position multiple times
}
}
! public:
! FreeRespawnLocationFinder(GridPos p) {
! blocked.insert(p);
! checked.insert(p);
! while (candidates.empty()) {
! ExaminedLocations curr_blocked;
! swap(curr_blocked, blocked);
! if (curr_blocked.empty())
! break; // no chance to find a candidate
! for (ExaminedLocations::const_iterator bl =
curr_blocked.begin(); bl != curr_blocked.end(); ++bl) {
! examine(move(*bl, NORTH));
! examine(move(*bl, SOUTH));
! examine(move(*bl, EAST));
! examine(move(*bl, WEST));
! }
}
! if (candidates.empty())
! candidates.insert(p); // if no location found -> use original
respawn position
}
! GridPos choose() const {
! assert(!candidates.empty());
! ExaminedLocations::const_iterator c = candidates.begin();
! advance(c, IntegerRand(0, candidates.size()-1));
! assert(c != candidates.end());
! return *c;
! }
! };
! }
! void
! Actor::find_respawnpos()
! {
! if (!use_respawnpos) {
! GridPos non_blocking;
! bool non_blocking_found = false;
! bool blocking_found = false;
! // check all fields that may overlap with respawn position
! for (int xoff = -1; xoff <= 1; ++xoff) {
! for (int yoff = -1; yoff <= 1; ++yoff) {
! double x = startingpos[0] + xoff*.4;
! double y = startingpos[1] + yoff*.4;
! GridPos odest(V2(x, y));
! if (GetStone(odest) != 0) {
! blocking_found = true;
}
! else {
! non_blocking_found = true;
! non_blocking = odest;
}
}
}
! if (blocking_found) {
! if (non_blocking_found) {
! // this only happens when the old startingpos was not
! // in the center of a GridPos
! startingpos = non_blocking.center();
! }
! else {
! GridPos dest(startingpos);
! FreeRespawnLocationFinder unblocked(dest);
! GridPos new_dest = unblocked.choose();
! startingpos = new_dest.center();
! }
! }
}
}
--- 84,307 ----
typedef std::set<ExaminedLocation> ExaminedLocations;
! class FreeRespawnLocationFinder
! {
ExaminedLocations checked;
ExaminedLocations blocked;
ExaminedLocations candidates;
! const Actor &actor_to_set;
! bool actor_is_marble;
! V2 preferred_position;
! double max_enemy_gap;
! V2 max_gap_pos;
!
! static const double MAX_DISTANCE_WANTED = 5.0;
!
! static bool is_marble(const string& k) {
! // true if kind 'k' is a marble
! return k == "ac-blackball" || k == "ac-whiteball" || k ==
"ac-whiteball-small";
! }
!
! static bool is_respawn_floor(const string& k) {
! // true if marble may appear on floors of kind 'k'
! return
! k != "fl-abyss" &&
! k != "fl-water" &&
! k != "fl-space"; // player cannot be moved on fl-space
! }
!
! static bool is_respawn_item(const string& k) {
! // true if marble may appear on items of kind 'k'
! return
! k != "it-laserbeam" &&
! k != "it-burnable-ignited";
! }
!
! static bool search_through_stone(const Stone& st) {
! if (st.is_movable() || st.is_floating()) return true;
!
! const string& k = st.get_kind();
! return k == "st-puzzle";
! }
!
! static double wanted_distance_to(const string& k) {
! // returns the size of the gap wanted between a marble and an
actor of kind 'k'
!
! if (k == "ac-rotor") return MAX_DISTANCE_WANTED;
! if (k == "ac-top") return 3.0;
! if (k == "ac-killerball" || k == "ac-bug") return 1.5;
! return 0.3;
! }
!
! double distance_wanted_to(const Actor& a) {
! double dist = 0.3;
!
! if (actor_is_marble) dist =
wanted_distance_to(a.get_kind());
! else if (is_marble(a.get_kind())) dist =
wanted_distance_to(actor_to_set.get_kind());
!
! assert(dist <= MAX_DISTANCE_WANTED);
! return dist;
! }
!
! bool enemyActorAt(const V2& p) {
! vector<Actor*> found_actors;
! double range = actor_to_set.get_radius() +
MAX_DISTANCE_WANTED + Actor::get_max_radius();
!
! if (GetActorsInRange(p, range, found_actors)) {
! bool found_near_enemy = false;
! double min_enemy_gap = 1000.0;
!
! for (vector<Actor*>::const_iterator ai = found_actors.begin();
! ai != found_actors.end();
! ++ai)
! {
! Actor *a = *ai;
!
! a->warning(" found nearby actor");
!
! if (a != &actor_to_set) {
! double distance = length(p - a->get_pos());
! double gap_between = distance -
actor_to_set.get_radius() - a->get_radius();
! double wanted_gap = distance_wanted_to(*a);
!
! a->warning(" distance=%f gap_between=%f
wanted_gap=%f", distance, gap_between, wanted_gap);
!
! if (gap_between < wanted_gap)
! found_near_enemy = true;
!
! if (gap_between < min_enemy_gap)
! min_enemy_gap = gap_between;
! }
! }
!
! if (found_near_enemy) {
! if (min_enemy_gap<999.0) {
! if (min_enemy_gap > max_enemy_gap) {
! max_enemy_gap = min_enemy_gap;
! max_gap_pos = p;
}
}
}
! return found_near_enemy;
}
+
+ return false;
}
! void examine(GridPos p) {
! fprintf(stderr, " examining position %i/%i\n", p.x, p.y);
! if (checked.find(p) != checked.end()) return; // already examined
! checked.insert(p); // never check again
! Floor *fl = GetFloor(p);
! if (!fl || !is_respawn_floor(fl->get_kind())) return; // bad floor
!
! bool may_respawn = true;
! bool continue_search = true;
!
! Item *it = GetItem(p);
! if (it && !is_respawn_item(it->get_kind())) may_respawn = false;
// bad item
!
! Stone *st = GetStone(p);
! if (st) {
! st->warning("examine");
! if (!search_through_stone(*st)) continue_search = false;
! may_respawn = false;
}
! if (may_respawn) { // may be a candidate -> check for enemy actors
! if (enemyActorAt(p.center())) may_respawn = false;
! }
!
! fprintf(stderr, " examine result: may_respawn=%i
continue_search=%i\n", int(may_respawn), int(continue_search));
!
! if (continue_search) blocked.insert(p);
! if (may_respawn) candidates.insert(p);
}
! public:
! FreeRespawnLocationFinder(V2 p, const Actor& actor)
! : actor_to_set(actor)
! , preferred_position(p)
! , max_enemy_gap(-1000.0)
! {
! actor_is_marble = is_marble(actor_to_set.get_kind());
! ExaminedLocations affected; // all locations affected by current
respawn position
! {
! double radius = actor_to_set.get_radius();
! int xmin = int(p[0]-radius);
! int xmax = int(p[0]+radius);
! int ymin = int(p[1]-radius);
! int ymax = int(p[1]+radius);
! for (int x = xmin; x <= xmax; ++x) {
! for (int y = ymin; y <= ymax; ++y) {
! affected.insert(GridPos(x, y));
! }
! }
! }
! fprintf(stderr, "Examining affected positions:\n");
! for (ExaminedLocations::const_iterator ai = affected.begin(); ai
!= affected.end(); ++ai) {
! examine(*ai);
! }
! fprintf(stderr, "Examining affected positions done.\n");
! if (candidates.size() != affected.size()) { // if any affected
location may not be used for respawning
! // choose alternate respawn location
! blocked = affected; // start with all affected positions
! while (candidates.empty()) {
! ExaminedLocations curr_blocked;
! swap(curr_blocked, blocked);
! if (curr_blocked.empty()) {
! fprintf(stderr, "No blocked locations left\n");
! break; // no chance to find a candidate
! }
! fprintf(stderr, "Examining blocked positions:\n");
! for (ExaminedLocations::const_iterator bl =
curr_blocked.begin(); bl != curr_blocked.end(); ++bl) {
! examine(move(*bl, NORTH));
! examine(move(*bl, SOUTH));
! examine(move(*bl, EAST));
! examine(move(*bl, WEST));
! }
! fprintf(stderr, "Examining blocked positions done.\n");
}
!
! if (candidates.empty()) { // no better location -> take least
worse tested location
! if (max_enemy_gap > 0.0) {
! fprintf(stderr, "Taking least worse position\n");
! preferred_position = max_gap_pos;
! }
! }
! else { // a better location has been found
! ExaminedLocations::const_iterator c = candidates.begin();
! advance(c, IntegerRand(0, candidates.size()-1));
!
! assert(c != candidates.end());
! preferred_position = c->center();
! fprintf(stderr, "Randomly choose 1 of %i candidates\n",
candidates.size());
}
}
}
! V2 get_position() const { return preferred_position; }
! };
! }
! void
! Actor::find_respawnpos()
! {
! if (!use_respawnpos) {
! FreeRespawnLocationFinder unblocked(startingpos, *this);
! startingpos = unblocked.get_position();
}
}
***************
*** 265,270 ****
// Actor interface.
void think (double dtime);
! bool is_dead() { return false; }
! bool is_flying() { return true; }
void on_hit(Actor *a) {
--- 388,393 ----
// Actor interface.
void think (double dtime);
! bool is_dead() const { return false; }
! bool is_flying() const { return true; }
void on_hit(Actor *a) {
***************
*** 281,284 ****
--- 404,409 ----
ai->mass = 0.8;
+ assert(ai->radius <= Actor::get_max_radius());
+
set_attrib ("range", 5.0);
set_attrib ("force", 10.0);
***************
*** 316,322 ****
ai->radius = 12/64.0;
ai->mass = 0.7;
}
! bool is_flying() { return true; }
! bool is_dead() { return false; }
};
}
--- 441,449 ----
ai->radius = 12/64.0;
ai->mass = 0.7;
+
+ assert(ai->radius <= Actor::get_max_radius());
}
! bool is_flying() const { return true; }
! bool is_dead() const { return false; }
};
}
***************
*** 335,341 ****
ai->radius = 24/64.0;
ai->mass = 1.2;
}
! bool is_flying() { return true; }
! bool is_dead() { return false; }
};
}
--- 462,470 ----
ai->radius = 24/64.0;
ai->mass = 1.2;
+
+ assert(ai->radius <= Actor::get_max_radius());
}
! bool is_flying() const { return true; }
! bool is_dead() const { return false; }
};
}
***************
*** 355,360 ****
ai->radius = 13/64.0;
ai->mass = 0.7;
}
! bool is_dead() { return false; }
void on_hit(Actor *a) {
--- 484,491 ----
ai->radius = 13/64.0;
ai->mass = 0.7;
+
+ assert(ai->radius <= Actor::get_max_radius());
}
! bool is_dead() const { return false; }
void on_hit(Actor *a) {
***************
*** 375,380 ****
CannonBall() : Actor ("ac-cannonball", V2()) {
}
! bool is_flying() { return true; }
! bool is_dead() { return false; }
};
}
--- 506,511 ----
CannonBall() : Actor ("ac-cannonball", V2()) {
}
! bool is_flying() const { return true; }
! bool is_dead() const { return false; }
};
}
***************
*** 447,456 ****
}
! bool is_dead();
! bool is_movable() { return (state!=DEAD && state!=RESURRECTED); }
! bool is_flying() { return state == JUMPING; }
! bool is_on_floor();
! bool can_drop_items();
! bool can_pickup_items();
bool has_shield() const;
--- 578,587 ----
}
! bool is_dead() const;
! bool is_movable() const { return (state!=DEAD && state!=RESURRECTED); }
! bool is_flying() const { return state == JUMPING; }
! bool is_on_floor() const;
! bool can_drop_items() const;
! bool can_pickup_items() const;
bool has_shield() const;
***************
*** 494,500 ****
ai->radius = radius;
ai->mass = mass;
}
! bool BasicBall::is_dead()
{
return state == DEAD;
--- 625,633 ----
ai->radius = radius;
ai->mass = mass;
+
+ assert(ai->radius <= Actor::get_max_radius());
}
! bool BasicBall::is_dead() const
{
return state == DEAD;
***************
*** 502,506 ****
! bool BasicBall::is_on_floor()
{
return state == NORMAL || state == SINKING ||
--- 635,639 ----
! bool BasicBall::is_on_floor() const
{
return state == NORMAL || state == SINKING ||
***************
*** 508,512 ****
}
! bool BasicBall::can_drop_items()
{
return state == NORMAL || state == SINKING ||
--- 641,645 ----
}
! bool BasicBall::can_drop_items() const
{
return state == NORMAL || state == SINKING ||
***************
*** 514,518 ****
}
! bool BasicBall::can_pickup_items()
{
return state == NORMAL || state == SINKING || state == JUMP_VORTEX;
--- 647,651 ----
}
! bool BasicBall::can_pickup_items() const
{
return state == NORMAL || state == SINKING || state == JUMP_VORTEX;
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Enigma-cvs] enigma/src actors.cc,1.44,1.45,
Ralf Westram <address@hidden> <=
- Prev by Date:
[Enigma-cvs] enigma/src stones_simple.cc, 1.57, 1.58 stones_complex.cc, 1.48, 1.49 object_mixins.hh, 1.13, 1.14 laser.cc, 1.20, 1.21
- Next by Date:
[Enigma-cvs] enigma/src objects.hh,1.53,1.54
- Previous by thread:
[Enigma-cvs] enigma/src stones_simple.cc, 1.57, 1.58 stones_complex.cc, 1.48, 1.49 object_mixins.hh, 1.13, 1.14 laser.cc, 1.20, 1.21
- Next by thread:
[Enigma-cvs] enigma/src objects.hh,1.53,1.54
- Index(es):