bool Agent::validInRoomSystem(Point p, float w, float h, int testperm) { // Return true if this agent is inside the world room system at the specified point, or false if it isn't. MetaRoom *m = world.map.metaRoomAt(p.x, p.y); if (!m) return false; for (unsigned int i = 0; i < 4; i++) { Point src, dest; switch (i) { case 0: src = boundingBoxPoint(0, p, w, h); dest = boundingBoxPoint(3, p, w, h); break; // left to bottom case 1: src = boundingBoxPoint(1, p, w, h); dest = boundingBoxPoint(3, p, w, h); break; // right to bottom case 2: src = boundingBoxPoint(2, p, w, h); dest = boundingBoxPoint(0, p, w, h); break; // top to left case 3: src = boundingBoxPoint(2, p, w, h); dest = boundingBoxPoint(1, p, w, h); break; // top to right } if (engine.version == 2) { // Creatures 2 physics int dx = dest.x - src.x; int dy = dest.y - src.y; Point deltapt(0,0); double delta = 1000000000; bool collided = false; // TODO: check suffercollisions? // TODO: muh, provided direction here is kinda a hack findCollisionInDirection((i < 2) ? 3 : 2, m, src, dx, dy, deltapt, delta, collided, true); if (collided) return false; } else { // Creatures 3 physics float srcx = src.x, srcy = src.y; shared_ptr<Room> ourRoom = m->roomAt(srcx, srcy); if (!ourRoom) return false; unsigned int dir; Line wall; world.map.collideLineWithRoomSystem(src, dest, ourRoom, src, wall, dir, testperm); if (src != dest) return false; } } return true; }
MetaRoom *Map::metaRoomAt(unsigned int _x, unsigned int _y) { for (std::vector<MetaRoom *>::iterator i = metarooms.begin(); i != metarooms.end(); i++) { MetaRoom *r = *i; if ((_x >= r->x()) && (_y >= r->y())) if ((_x <= (r->x() + r->width())) && (_y <= (r->y() + r->height()))) return r; } return 0; }
void Agent::updateAudio(boost::shared_ptr<AudioSource> s) { assert(s); MetaRoom *room = world.map.metaRoomAt(x, y); if (!room) { // TODO: think about inrange when positioning outside-metaroom agents s->setPos(x + getWidth() / 2, y + getHeight() / 2, zorder); return; } float xc = x; bool inrange = false; if (inrange_at(room, x, y, getWidth(), getHeight())) { xc = x; inrange = true; } else if (room->wraparound()) { if (inrange_at(room, x - room->width(), y, getWidth(), getHeight())) { xc = x - room->width(); inrange = true; } else if (inrange_at(room, x + room->width(), y, getWidth(), getHeight())) { xc = x + room->width(); inrange = true; } } s->setMute(!inrange); if (inrange) s->setPos(xc + getWidth() / 2, y + getHeight() / 2, zorder); // TODO: setVelocity? }
void Agent::moveTo(float _x, float _y, bool force) { // Move ourselves to the specified location. wasmoved = true; // if we're being carried and aren't being forced to move (prbly by our carrier), forget it if (carriedby && !force) return; // TODO: what if we move while being carried? doomy explosions ensue, that's what! float xoffset = _x - x; float yoffset = _y - y; x = _x; y = _y; // handle wraparound // TODO: this is perhaps non-ideal if (engine.version < 3 && xoffset != 0.0f) { // TODO: it'd be nice to handle multiple metarooms MetaRoom *m = world.map.getFallbackMetaroom(); assert(m); if (x < m->x()) { x += m->width(); } else if (x > m->x() + m->width()) { x -= m->width(); } } for (std::vector<AgentRef>::iterator i = floated.begin(); i != floated.end(); i++) { assert(*i); (*i)->moveTo((*i)->x + xoffset, (*i)->y + yoffset); } adjustCarried(xoffset, yoffset); }
shared_ptr<Room> Map::roomAt(float _x, float _y) { MetaRoom *m = metaRoomAt((unsigned int)_x, (unsigned int)_y); // TODO: good casts? if (!m) return shared_ptr<Room>(); return m->roomAt(_x, _y); }
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; } } } } }
shared_ptr<Room> roomContainingAgent(AgentRef agent) { MetaRoom *m = world.map.metaRoomAt(agent->x, agent->y); if (!m) return shared_ptr<Room>(); return m->roomAt(agent->x + (agent->getWidth() / 2.0f), agent->y + (agent->getHeight() / 2.0f)); }
bool Agent::fireScript(unsigned short event, Agent *from, caosVar one, caosVar two) { // Start running the specified script on the VM of this agent, with FROM set to the provided agent. if (dying) return false; CreatureAgent *c = 0; if (event <= 3 || event == 4 || event == 12 || event == 13 || event == 14) c = dynamic_cast<CreatureAgent *>(from); switch (event) { case 0: // deactivate if (c && !cr_can_stop) return false; // TODO: not sure if this is the right place to do this. actv.setInt(event); break; case 1: // activate 1 if (c && !cr_can_push) return false; // TODO: not sure if this is the right place to do this. actv.setInt(event); break; case 2: // activate 2 if (c && !cr_can_pull) return false; // TODO: not sure if this is the right place to do this. actv.setInt(event); break; case 3: // hit if (c && !cr_can_hit) return false; break; case 4: // pickup if (c && !cr_can_pickup) return false; if (!from) return false; if (from == world.hand()) { if (!mouseable()) return false; } else if (!c) { // TODO: valid check for vehicles? if (!carryable()) return false; } from->addCarried(this); // TODO: correct behaviour? break; case 5: // drop if (!from) return false; // TODO: this check isn't very good for vehicles ;p // if (from != carriedby) return false; from->dropCarried(this); // TODO: correct? break; case 12: // eat if (c && !cr_can_eat) return false; break; case 13: // hold hands with pointer if (c) { // TODO } break; case 14: // stop holding hands with pointer if (c) { // TODO } break; case 92: // TODO: hack for 'UI Mouse Down' event - we need a real event system! std::cout << "faking event 92 on " << identify() << std::endl; CompoundPart *p = world.partAt(world.hand()->pointerX(), world.hand()->pointerY()); if (!p || p->getParent() != this) // if something is horridly broken here, return return false; // was caos_assert(p && p->getParent() == this); p->handleClick(world.hand()->pointerX() - p->x - p->getParent()->x, world.hand()->pointerY() - p->y - p->getParent()->y); // TODO: we're [obviously] missing firing the pointer script here, but it's a hack for now break; } bool ranscript = false; shared_ptr<script> s = findScript(event); if (s) { bool madevm = false; if (!vm) { madevm = true; vm = world.getVM(this); } if (vm->fireScript(s, event == 9, from)) { lastScript = event; zotstack(); vm->setVariables(one, two); // TODO: we should set _it_ in a more sensible way CreatureAgent *a = dynamic_cast<CreatureAgent *>(this); if (a) { Creature *c = a->getCreature(); assert(c); vm->_it_ = c->getAttentionFocus(); } vmTick(); ranscript = true; } else if (madevm) { world.freeVM(vm); vm = 0; } } switch (event) { case 5: if (invehicle) break; if (engine.version > 1) break; // Creatures 1 drop snapping // TODO: this probably doesn't belong here, but it has to be run after the // drop script starts (see for instance C1 carrots, which change pose) MetaRoom* m = world.map.metaRoomAt(x, y); if (!m) break; shared_ptr<Room> r = m->nextFloorFromPoint(x, y); if (!r) break; moveTo(x, r->bot.pointAtX(x).y - getHeight()); break; } return ranscript; }