示例#1
0
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;
				}
			}
		}
	}
}
示例#2
0
// 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;
	}
}