void L1_GetSectorOppositeEdge() { 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 (strmatch(sector->getName(), name)) { if (sector->getNumVertices() != 4) warning("GetSectorOppositeEdge(): cheat box with %d (!= 4) edges!", sector->getNumVertices()); Graphics::Vector3d* vertices = sector->getVertices(); Sector::ExitInfo e; sector->getExitInfo(actor->getPos(), -actor->getPuckVector(), &e); float frac = (e.exitPoint - vertices[e.edgeVertex + 1]).magnitude() / e.edgeDir.magnitude(); e.edgeVertex -= 2; if (e.edgeVertex < 0) e.edgeVertex += sector->getNumVertices(); Graphics::Vector3d edge = vertices[e.edgeVertex + 1] - vertices[e.edgeVertex]; Graphics::Vector3d p = vertices[e.edgeVertex] + edge * frac; lua_pushnumber(p.x()); lua_pushnumber(p.y()); lua_pushnumber(p.z()); return; } } lua_pushnil(); }
void Actor::walkForward() { float dist = g_grim->getPerSecond(_walkRate); // Limit the amount of the movement per frame, otherwise with low fps // scripts that use WalkActorForward and proximity may break. if ((dist > 0 && dist > _walkRate / 5.f) || (dist < 0 && dist < _walkRate / 5.f)) dist = _walkRate / 5.f; _walking = false; if (! _constrain) { Math::Vector3d forwardVec(-_moveYaw.getSine() * _pitch.getCosine(), _moveYaw.getCosine() * _pitch.getCosine(), _pitch.getSine()); // EMI: Y is up-down, sectors use an X-Z plane for movement if (g_grim->getGameType() == GType_MONKEY4) { float temp = forwardVec.z(); forwardVec.z() = forwardVec.y(); forwardVec.y() = temp; } _pos += forwardVec * dist; _walkedCur = true; return; } bool backwards = false; if (dist < 0) { dist = -dist; backwards = true; } int tries = 0; while (dist > 0.0f) { Math::Vector3d forwardVec(-_moveYaw.getSine() * _pitch.getCosine(), _moveYaw.getCosine() * _pitch.getCosine(), _pitch.getSine()); // EMI: Y is up-down, sectors use an X-Z plane for movement if (g_grim->getGameType() == GType_MONKEY4) { float temp = forwardVec.z(); forwardVec.z() = forwardVec.y(); forwardVec.y() = temp; } if (backwards) forwardVec = -forwardVec; Sector *currSector = NULL, *prevSector = NULL, *startSector = NULL; Sector::ExitInfo ei; g_grim->getCurrSet()->findClosestSector(_pos, &currSector, &_pos); if (!currSector) { // Shouldn't happen... moveTo(_pos + forwardVec * dist); _walkedCur = true; return; } startSector = currSector; float oldDist = dist; while (currSector) { prevSector = currSector; Math::Vector3d puckVec = currSector->getProjectionToPuckVector(forwardVec); puckVec /= puckVec.getMagnitude(); currSector->getExitInfo(_pos, puckVec, &ei); float exitDist = (ei.exitPoint - _pos).getMagnitude(); if (dist < exitDist) { moveTo(_pos + puckVec * dist); _walkedCur = true; return; } _pos = ei.exitPoint; dist -= exitDist; if (exitDist > 0.0001) _walkedCur = true; // Check for an adjacent sector which can continue // the path currSector = g_grim->getCurrSet()->findPointSector(ei.exitPoint + (float)0.0001 * puckVec, Sector::WalkType); // EMI: some sectors are significantly higher/lower than others. if (currSector && g_grim->getGameType() == GType_MONKEY4) { float planeDist = currSector->distanceToPoint(_pos); if (fabs(planeDist) < 1.f) _pos -= planeDist * currSector->getNormal(); } if (currSector == prevSector || currSector == startSector) break; } int turnDir = 1; if (ei.angleWithEdge > 90) { ei.angleWithEdge = 180 - ei.angleWithEdge; ei.edgeDir = -ei.edgeDir; turnDir = -1; } if (ei.angleWithEdge > _reflectionAngle) return; ei.angleWithEdge += (float)1.0f; turnTo(0, _moveYaw + ei.angleWithEdge * turnDir, 0); if (oldDist <= dist + 0.001f) { // If we didn't move at all, keep trying a couple more times // in case we can move in the new direction. tries++; if (tries > 3) break; } } }