void L1_IsActorInSector() { lua_Object actorObj = lua_getparam(1); lua_Object nameObj = lua_getparam(2); if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R')) return; if (!lua_isstring(nameObj)) { lua_pushnil(); return; } Actor *actor = getactor(actorObj); const char *name = lua_getstring(nameObj); int numSectors = g_grim->getCurrScene()->getSectorCount(); for (int i = 0; i < numSectors; i++) { Sector *sector = g_grim->getCurrScene()->getSectorBase(i); if (strstr(sector->getName(), name)) { if (sector->isPointInSector(actor->getPos())) { lua_pushnumber(sector->getSectorId()); lua_pushstring(sector->getName()); lua_pushnumber(sector->getType()); return; } } } lua_pushnil(); }
void L1_IsPointInSector() { lua_Object xObj = lua_getparam(1); lua_Object yObj = lua_getparam(2); lua_Object zObj = lua_getparam(3); lua_Object nameObj = lua_getparam(4); if (!lua_isstring(nameObj)) { lua_pushnil(); return; } const char *name = lua_getstring(nameObj); float x = lua_getnumber(xObj); float y = lua_getnumber(yObj); float z = lua_getnumber(zObj); Graphics::Vector3d pos(x, y, z); int numSectors = g_grim->getCurrScene()->getSectorCount(); for (int i = 0; i < numSectors; i++) { Sector *sector = g_grim->getCurrScene()->getSectorBase(i); if (strstr(sector->getName(), name)) { if (sector->isPointInSector(pos)) { lua_pushnumber(sector->getSectorId()); lua_pushstring(sector->getName()); lua_pushnumber(sector->getType()); return; } } } lua_pushnil(); }
/* Find the sector (of any type) which contains * the requested coordinate (x,y,z). */ void L1_GetPointSector() { lua_Object xObj = lua_getparam(1); lua_Object yObj = lua_getparam(2); lua_Object zObj = lua_getparam(3); lua_Object typeObj = lua_getparam(4); Sector::SectorType sectorType; if (!lua_isnumber(xObj) || !lua_isnumber(yObj) || !lua_isnumber(zObj)) { lua_pushnil(); return; } if (lua_isnil(typeObj)) sectorType = Sector::WalkType; else sectorType = (Sector::SectorType)(int)lua_getnumber(typeObj); float x = lua_getnumber(xObj); float y = lua_getnumber(yObj); float z = lua_getnumber(zObj); Graphics::Vector3d point(x, y, z); Sector *result = g_grim->getCurrScene()->findPointSector(point, sectorType); if (result) { lua_pushnumber(result->getSectorId()); lua_pushstring(const_cast<char *>(result->getName())); lua_pushnumber(result->getType()); } else { lua_pushnil(); } }
Sector *Set::findPointSector(const Math::Vector3d &p, Sector::SectorType type) { for (int i = 0; i < _numSectors; i++) { Sector *sector = _sectors[i]; if (sector && (sector->getType() & type) && sector->isVisible() && sector->isPointInSector(p)) return sector; } return NULL; }
void L1_GetActorSector() { lua_Object actorObj = lua_getparam(1); lua_Object typeObj = lua_getparam(2); if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R')) return; if (!lua_isnumber(typeObj)) return; Actor *actor = getactor(actorObj); Sector::SectorType sectorType = (Sector::SectorType)(int)lua_getnumber(typeObj); Graphics::Vector3d pos = actor->getPos(); Sector *result = g_grim->getCurrScene()->findPointSector(pos, sectorType); if (result) { lua_pushnumber(result->getSectorId()); lua_pushstring(const_cast<char *>(result->getName())); lua_pushnumber(result->getType()); } else { lua_pushnil(); } }
void Set::findClosestSector(const Math::Vector3d &p, Sector **sect, Math::Vector3d *closestPoint) { Sector *resultSect = NULL; Math::Vector3d resultPt = p; float minDist = 0.0; for (int i = 0; i < _numSectors; i++) { Sector *sector = _sectors[i]; if ((sector->getType() & Sector::WalkType) == 0 || !sector->isVisible()) continue; Math::Vector3d closestPt = sector->getClosestPoint(p); float thisDist = (closestPt - p).getMagnitude(); if (!resultSect || thisDist < minDist) { resultSect = sector; resultPt = closestPt; minDist = thisDist; } } if (sect) *sect = resultSect; if (closestPoint) *closestPoint = resultPt; }
void Sector::shrink(float radius) { if ((getType() & WalkType) == 0 || _shrinkRadius == radius) return; _shrinkRadius = radius; if (!_origVertices) { _origVertices = _vertices; _vertices = new Math::Vector3d[_numVertices + 1]; } // Move each vertex inwards by the given amount. for (int j = 0; j < _numVertices; j++) { Math::Vector3d shrinkDir; for (int k = 0; k < g_grim->getCurrSet()->getSectorCount(); k++) { Sector *other = g_grim->getCurrSet()->getSectorBase(k); if ((other->getType() & WalkType) == 0) continue; for (int l = 0; l < other->_numVertices; l++) { Math::Vector3d *otherVerts = other->_vertices; if (other->_origVertices) otherVerts = other->_origVertices; if ((otherVerts[l] - _origVertices[j]).getMagnitude() < 0.01f) { Math::Vector3d e1 = otherVerts[l + 1] - otherVerts[l]; Math::Vector3d e2; if (l - 1 >= 0) e2 = otherVerts[l] - otherVerts[l - 1]; else e2 = otherVerts[l] - otherVerts[other->_numVertices - 1]; e1.normalize(); e2.normalize(); Math::Vector3d bisector = (e1 - e2); bisector.normalize(); shrinkDir += bisector; } } } if (shrinkDir.getMagnitude() > 0.1f) { shrinkDir.normalize(); _vertices[j] = _origVertices[j] + shrinkDir * radius; } else { _vertices[j] = _origVertices[j]; } } _vertices[_numVertices] = _vertices[0]; // Make sure the sector is still convex. for (int j = 0; j < _numVertices; j++) { Math::Vector3d e1 = _vertices[j + 1] - _vertices[j]; Math::Vector3d e2; if (j - 1 >= 0) e2 = _vertices[j] - _vertices[j - 1]; else e2 = _vertices[j] - _vertices[_numVertices - 1]; if (e1.x() * e2.y() > e1.y() * e2.x()) { // Not convex, so mark the sector invalid. _invalid = true; delete[] _vertices; _vertices = _origVertices; _origVertices = nullptr; break; } } }
void Actor::walkTo(const Math::Vector3d &p) { if (p == _pos) _walking = false; else { _walking = true; _destPos = p; _path.clear(); if (_constrain) { g_grim->getCurrSet()->findClosestSector(p, NULL, &_destPos); Common::List<PathNode *> openList; Common::List<PathNode *> closedList; PathNode *start = new PathNode; start->parent = NULL; start->pos = _pos; start->dist = 0.f; start->cost = 0.f; openList.push_back(start); g_grim->getCurrSet()->findClosestSector(_pos, &start->sect, NULL); Common::List<Sector *> sectors; for (int i = 0; i < g_grim->getCurrSet()->getSectorCount(); ++i) { Sector *s = g_grim->getCurrSet()->getSectorBase(i); int type = s->getType(); if ((type == Sector::WalkType || type == Sector::HotType || type == Sector::FunnelType) && s->isVisible()) { sectors.push_back(s); } } Sector *endSec = NULL; g_grim->getCurrSet()->findClosestSector(_destPos, &endSec, NULL); do { PathNode *node = NULL; float cost = -1.f; for (Common::List<PathNode *>::iterator j = openList.begin(); j != openList.end(); ++j) { PathNode *n = *j; float c = n->dist + n->cost; if (cost < 0.f || c < cost) { cost = c; node = n; } } closedList.push_back(node); openList.remove(node); Sector *sector = node->sect; if (sector == endSec) { PathNode *n = closedList.back(); // Don't put the start position in the list, or else // the first angle calculated in updateWalk() will be // meaningless. The only node without parent is the start // one. while (n->parent) { _path.push_back(n->pos); n = n->parent; } break; } for (Common::List<Sector *>::iterator i = sectors.begin(); i != sectors.end(); ++i) { Sector *s = *i; bool inClosed = false; for (Common::List<PathNode *>::iterator j = closedList.begin(); j != closedList.end(); ++j) { if ((*j)->sect == s) { inClosed = true; break; } } if (inClosed) continue; Common::List<Math::Line3d> bridges = sector->getBridgesTo(s); if (bridges.empty()) continue; // The sectors are not adjacent. Math::Vector3d closestPoint = s->getClosestPoint(_destPos); Math::Vector3d best; float bestDist = 1e6f; Math::Line3d l(node->pos, closestPoint); while (!bridges.empty()) { Math::Line3d bridge = bridges.back(); Math::Vector3d pos; const bool useXZ = (g_grim->getGameType() == GType_MONKEY4); if (!bridge.intersectLine2d(l, &pos, useXZ)) { pos = bridge.middle(); } float dist = (pos - closestPoint).getMagnitude(); if (dist < bestDist) { bestDist = dist; best = pos; } bridges.pop_back(); } best = handleCollisionTo(node->pos, best); PathNode *n = NULL; for (Common::List<PathNode *>::iterator j = openList.begin(); j != openList.end(); ++j) { if ((*j)->sect == s) { n = *j; break; } } if (n) { float newCost = node->cost + (best - node->pos).getMagnitude(); if (newCost < n->cost) { n->cost = newCost; n->parent = node; n->pos = best; n->dist = (n->pos - _destPos).getMagnitude(); } } else { n = new PathNode; n->parent = node; n->sect = s; n->pos = best; n->dist = (n->pos - _destPos).getMagnitude(); n->cost = node->cost + (n->pos - node->pos).getMagnitude(); openList.push_back(n); } } } while (!openList.empty()); for (Common::List<PathNode *>::iterator j = closedList.begin(); j != closedList.end(); ++j) { delete *j; } for (Common::List<PathNode *>::iterator j = openList.begin(); j != openList.end(); ++j) { delete *j; } } _path.push_front(_destPos); } }