void SpaceStation::StaticUpdate(const float timeStep) { bool update = false; // if there's no BB and there are ships here, make one if (!m_bbCreated && GetFreeDockingPort() != 0) { CreateBB(); update = true; } // if there is and it hasn't had an update for a while, update it else if (Pi::game->GetTime() > m_lastUpdatedShipyard) { LuaEvent::Queue("onUpdateBB", this); update = true; } if (update) { UpdateShipyard(); // update again in an hour or two m_lastUpdatedShipyard = Pi::game->GetTime() + 3600.0 + 3600.0*Pi::rng.Double(); } DoLawAndOrder(timeStep); DockingUpdate(timeStep); m_navLights->Update(timeStep); }
bool SpaceStation::OnCollision(Object *b, Uint32 flags, double relVel) { if ((flags & 0x10) && (b->IsType(Object::SHIP))) { Ship *s = static_cast<Ship*>(b); matrix4x4d rot; GetRotMatrix(rot); bool canDock = true; int port = -1; for (int i=0; i<MAX_DOCKING_PORTS; i++) { if (m_shipDocking[i].ship == s) { port = i; break; } } if (m_type->dockOneAtATimePlease) { for (int i=0; i<m_type->numDockingPorts; i++) { if (m_shipDocking[i].ship && m_shipDocking[i].stage != 1 && (m_shipDocking[i].stage != m_type->numDockingStages+1)) { canDock = false; break; } } } else { // for non-dockOneAtATimePlease, the ship is expected // to hit the right docking trigger surface for that port if (m_shipDocking[flags&0xf].ship != s) canDock = false; } if (port == -1) canDock = false; // hitting docking area of a station if (canDock) { SpaceStationType::positionOrient_t dport; // why stage 2? Because stage 1 is permission to dock // granted, stage 2 is start of docking animation. PiVerify(m_type->GetDockAnimPositionOrient(port, 2, 0.0f, vector3d(0.0), dport, s)); double speed = s->GetVelocity().Length(); // must be oriented sensibly and have wheels down if (IsGroundStation()) { matrix4x4d shiprot; s->GetRotMatrix(shiprot); matrix4x4d invShipRot = shiprot.InverseOf(); vector3d dockingNormal = rot*dport.yaxis; // check player is sortof sensibly oriented for landing const double dot = vector3d(invShipRot[1], invShipRot[5], invShipRot[9]).Dot(dockingNormal); if ((dot < 0.99) || (s->GetWheelState() != 1.0)) return false; } if ((speed < MAX_LANDING_SPEED) && (!s->GetDockedWith()) && (m_shipDocking[port].stage == 1)) { // if there is more docking port anim to do, // don't set docked yet if (m_type->numDockingStages >= 2) { shipDocking_t &sd = m_shipDocking[port]; sd.ship = s; sd.stage = 2; sd.stagePos = 0; sd.fromPos = rot.InverseOf() * (s->GetPosition() - GetPosition()); matrix4x4d temp; s->GetRotMatrix(temp); sd.fromRot = Quaterniond::FromMatrix4x4(temp); s->Disable(); s->SetFlightState(Ship::DOCKING); } else { s->SetDockedWith(this, port); CreateBB(); Pi::luaOnShipDocked.Queue(s, this); } } } return false; } else { return true; } }
void SpaceStation::DoDockingAnimation(const double timeStep) { matrix4x4d rot, wantRot; vector3d p1, p2, zaxis; for (int i=0; i<MAX_DOCKING_PORTS; i++) { shipDocking_t &dt = m_shipDocking[i]; if (!dt.ship) continue; if (!dt.stage) continue; // docked stage is m_type->numDockingPorts + 1 if (dt.stage > m_type->numDockingStages) continue; GetRotMatrix(rot); double stageDuration = (dt.stage > 0 ? m_type->dockAnimStageDuration[dt.stage-1] : m_type->undockAnimStageDuration[abs(dt.stage)-1]); dt.stagePos += timeStep / stageDuration; if (dt.stage == 1) { // SPECIAL stage! Docking granted but waiting for ship // to dock m_openAnimState[i] += 0.3*timeStep; m_dockAnimState[i] -= 0.3*timeStep; if (dt.stagePos >= 1.0) { if (dt.ship == static_cast<Ship*>(Pi::player)) Pi::onDockingClearanceExpired.emit(this); dt.ship = 0; dt.stage = 0; } continue; } if (dt.stagePos > 1.0) { dt.stagePos = 0; if (dt.stage >= 0) dt.stage++; else dt.stage--; dt.fromPos = rot.InverseOf() * (dt.ship->GetPosition() - GetPosition()); matrix4x4d temp; dt.ship->GetRotMatrix(temp); dt.fromRot = Quaterniond::FromMatrix4x4(temp); } SpaceStationType::positionOrient_t shipOrient; bool onRails = m_type->GetDockAnimPositionOrient(i, dt.stage, dt.stagePos, dt.fromPos, shipOrient, dt.ship); if (onRails) { dt.ship->SetPosition(GetPosition() + rot*shipOrient.pos); wantRot = matrix4x4d::MakeRotMatrix( shipOrient.xaxis, shipOrient.yaxis, shipOrient.xaxis.Cross(shipOrient.yaxis)) * rot; // use quaternion spherical linear interpolation to do // rotation smoothly Quaterniond wantQuat = Quaterniond::FromMatrix4x4(wantRot); Quaterniond q = Quaterniond::Nlerp(dt.fromRot, wantQuat, dt.stagePos); wantRot = q.ToMatrix4x4<double>(); // wantRot.Renormalize(); dt.ship->SetRotMatrix(wantRot); } else { if (dt.stage >= 0) { // set docked dt.ship->SetDockedWith(this, i); CreateBB(); Pi::luaOnShipDocked.Queue(dt.ship, this); } else { if (!dt.ship->IsEnabled()) { // launch ship dt.ship->Enable(); dt.ship->SetFlightState(Ship::FLYING); dt.ship->SetAngVelocity(GetFrame()->GetAngVelocity()); dt.ship->SetForce(vector3d(0,0,0)); dt.ship->SetTorque(vector3d(0,0,0)); if (m_type->dockMethod == SpaceStationType::SURFACE) { dt.ship->SetThrusterState(1, 1.0); // up } else { dt.ship->SetVelocity(GetFrame()->GetStasisVelocityAtPosition(dt.ship->GetPosition())); dt.ship->SetThrusterState(2, -1.0); // forward } Pi::luaOnShipUndocked.Queue(dt.ship, this); } } } if ((dt.stage < 0) && ((-dt.stage) > m_type->numUndockStages)) { dt.stage = 0; dt.ship = 0; } } for (int i=0; i<MAX_DOCKING_PORTS; i++) { m_openAnimState[i] = Clamp(m_openAnimState[i], 0.0, 1.0); m_dockAnimState[i] = Clamp(m_dockAnimState[i], 0.0, 1.0); } }