void SkeletalCreature::snapDownFoot() { // TODO: this isn't very well thought-out. int orig_footpart = (downfoot_left ? 11 : 12); float footx = x + attachmentX(orig_footpart, 1); float footy = y + attachmentY(orig_footpart, 1); MetaRoom *m = world.map.metaRoomAt(x, y); if (!m) return; // TODO: exceptiony death shared_ptr<Room> newroom; if (downfootroom) { if (downfootroom->containsPoint(footx, footy)) { newroom = downfootroom; } else { if (downfootroom->x_left <= footx && downfootroom->x_right >= footx) { newroom = downfootroom; // TODO, we're just forcing for now } else { float ydiff = 10000.0f; // TODO: big number for (std::map<weak_ptr<Room>,RoomDoor *>::iterator i = downfootroom->doors.begin(); i != downfootroom->doors.end(); i++) { shared_ptr<Room> thisroom = i->first.lock(); if (engine.version == 2 && size.getInt() > i->second->perm) continue; if (thisroom->x_left <= footx && thisroom->x_right >= footx) { float thisydiff = fabs(footy - thisroom->floorYatX(footx)); if (thisydiff < ydiff) { newroom = thisroom; ydiff = thisydiff; } } } } } } else { newroom = bestRoomAt(footx, footy, 3, m, shared_ptr<Room>()); // insane emergency handling float newfooty = footy; while (!newroom && newfooty > (footy - 500.0f)) { newroom = m->roomAt(footx, newfooty); newfooty--; } // TODO: give up here footy = newfooty; } bool newroomchosen = (newroom != downfootroom) && downfootroom; bool hadroom = (downfootroom); downfootroom = newroom; if (!downfootroom /*|| !falling */) { // TODO: hackery to cope with scripts moving us, this needs handling correctly somewhere if (fabs(lastgoodfootx - attachmentX(orig_footpart, 1) - x) > 50.0f || fabs(lastgoodfooty - attachmentY(orig_footpart, 1) - y) > 50.0f) { downfootroom = bestRoomAt(footx, footy, 3, m, shared_ptr<Room>()); if (downfootroom) { snapDownFoot(); return; } else { std::cout << "Creature out of room system at (" << footx << ", " << footy << ")!" << std::endl; // TODO: exceptiony death? return; } } // We fell out of the room system! How did that happen? Push ourselves back in, run collision script. std::cout << "Creature out of room system at (" << footx << ", " << footy << "), pushing it back in." << std::endl; // TODO: sucky code x = lastgoodfootx - attachmentX(orig_footpart, 1); footx = lastgoodfootx; footy = lastgoodfooty; downfootroom = m->roomAt(footx, footy); queueScript(6); if (!downfootroom) { std::cout << "no down foot room! (" << footx << ", " << footy << ")" << std::endl; // TODO: exceptiony death return; } } bool belowfloor = false; float newy = downfootroom->floorYatX(footx); if (engine.version == 2 && hadroom && y > newy) { // TODO: hilar hack: cope with walking below floors belowfloor = true; newy = downfootroom->bot.pointAtX(footx).y; } if (engine.version > 1) { // TODO: hilar hack: enable gravity if we're snapping by much if (newroomchosen && abs(y - (newy - (footy - y))) > 20) { falling = true; return; } } moveTo(x, newy - (footy - y)); lastgoodfootx = footx; lastgoodfooty = footy; if (engine.version > 2) { if (engine.version == 2 && !belowfloor && downfootroom->floorpoints.size()) { // TODO: hilar hack: same as above for floorvalue if (size.getInt() <= downfootroom->floorvalue.getInt()) { falling = true; return; } } else { // TODO: hilar hack: same as above for perm shared_ptr<Room> downroom = world.map.roomAt(footx, downfootroom->y_left_floor + 1); if (downfootroom->doors.find(downroom) != downfootroom->doors.end()) { int permsize = (engine.version == 2 ? size.getInt() : perm); if (permsize <= downfootroom->doors[downroom]->perm) { falling = true; return; } } } } }
// Creatures 2 collision finding void Agent::findCollisionInDirection(unsigned int i, class MetaRoom *m, Point src, int &dx, int &dy, Point &deltapt, double &delta, bool &collided, bool followrooms) { src.x = (int)src.x; src.y = (int)src.y; if (m->wraparound()) { if (src.x > m->x() + m->width() || (dx > 0 && src.x == m->x() + m->width())) src.x -= m->width(); else if (src.x < m->x() || (dx < 0 && src.x == m->x())) src.x += m->width(); } // TODO: caching rooms affects behaviour - work out if that's a problem shared_ptr<Room> room = roomcache[i].lock(); if (!room || !room->containsPoint(src.x, src.y)) { room = bestRoomAt(src.x, src.y, i, m, shared_ptr<Room>()); roomcache[i] = room; } if (!room) { // out of room system if (!displaycore) unhandledException(boost::str(boost::format("out of room system at (%f, %f)") % src.x % src.y), false); falling = false; displaycore = true; return; } int lastdirection = 0; bool steep = abs(dy) > abs(dx); int signdx = dx < 0 ? -1 : 1; int signdy = dy < 0 ? -1 : 1; Line l(Point(0,0),Point(dx,dy)); Point lastpoint(0,0); Vehicle *vehicle = 0; if (invehicle) vehicle = dynamic_cast<Vehicle *>(invehicle.get()); for (int loc = 0; loc <= abs(steep ? dy : dx); loc++) { Point p = steep ? l.pointAtY(loc*signdy) : l.pointAtX(loc*signdx); p.x = (int)p.x; p.y = (int)p.y; if (vehicle) { if (src.x + p.x < vehicle->x + vehicle->cabinleft) { lastdirection = 0; collided = true; break; } if (src.x + p.x > vehicle->x + vehicle->cabinright) { lastdirection = 1; collided = true; break; } if (src.y + p.y < vehicle->y + vehicle->cabintop) { lastdirection = 2; collided = true; break; } if (src.y + p.y > vehicle->y + vehicle->cabinbottom) { lastdirection = 3; collided = true; break; } lastpoint = p; continue; } bool trycollisions = false; bool endofroom = false; if (src.x + p.x < room->x_left) { if (i != 1 && dx < 0) { trycollisions = true; lastdirection = 0; } endofroom = true; } if (src.x + p.x > room->x_right) { if (i != 0 && dx > 0) { trycollisions = true; lastdirection = 1; } endofroom = true; } if (src.y + p.y < room->y_left_ceiling) { if (i != 3 && dy < 0) { trycollisions = true; lastdirection = 2; } endofroom = true; } if (src.y + p.y > room->y_left_floor) { if (i != 2 && dy > 0) { trycollisions = true; lastdirection = 3; } endofroom = true; } // find the next room, if necessary, and work out whether we should move into it or break out if (endofroom) { if (m->wraparound()) { if (dx > 0 && src.x + p.x >= m->x() + m->width()) src.x -= m->width(); else if (dx < 0 && src.x + p.x <= m->x()) src.x += m->width(); } shared_ptr<Room> newroom = bestRoomAt(src.x + p.x, src.y + p.y, i, m, room); bool collision = false; // collide if we're out of the room system if (!newroom) { collision = true; } // collide if there's no new room connected to this one else if (room->doors.find(newroom) == room->doors.end()) { collision = true; } // collide if the PERM between this room and the new room is smaller than or equal to our size else if (size.getInt() > room->doors[newroom]->perm) { collision = true; } if (collision && (trycollisions || (!newroom))) { collided = true; break; } // move to the new room and keep going! room = newroom; } if (room->floorpoints.size() && i == 3 && dy >= 0 && size.getInt() > room->floorvalue.getInt()) { // TODO: Hack! // TODO: we don't check floorYatX isn't returning a 'real' room floor, but floorpoints should cover the whole floor anyway int floory = room->floorYatX(src.x + p.x); // never collide when the top point of an object is below the floor. Point top = boundingBoxPoint(2); // TODO: consider steep floors if (src.y + p.y > floory && top.y < floory) { collided = true; lastdirection = 3; break; } } if ((!followrooms) && endofroom) break; lastpoint = p; } double length2 = (lastpoint.x * lastpoint.x) + (lastpoint.y * lastpoint.y); if (length2 < delta) { // TODO: !followrooms is a horrible way to detect a non-physics call if (collided && followrooms) lastcollidedirection = lastdirection; deltapt = lastpoint; delta = length2; } }