Ship::HyperjumpStatus Ship::CheckHyperjumpCapability() const { if (GetFlightState() == HYPERSPACE) return HYPERJUMP_DRIVE_ACTIVE; if (GetFlightState() != FLYING && GetFlightState() != JUMPING) return HYPERJUMP_SAFETY_LOCKOUT; return HYPERJUMP_OK; }
void Ship::EnterHyperspace() { assert(GetFlightState() != Ship::HYPERSPACE); const SystemPath dest = GetHyperspaceDest(); int fuel_cost; Ship::HyperjumpStatus status = CheckHyperspaceTo(dest, fuel_cost, m_hyperspace.duration); if (status != HYPERJUMP_OK) { // XXX something has changed (fuel loss, mass change, whatever). // could report it to the player but better would be to cancel the // countdown before this is reached. either way do something return; } Equip::Type fuelType = GetHyperdriveFuelType(); m_equipment.Remove(fuelType, fuel_cost); if (fuelType == Equip::MILITARY_FUEL) { m_equipment.Add(Equip::RADIOACTIVES, fuel_cost); } UpdateEquipStats(); LuaEvent::Queue("onLeaveSystem", this); SetFlightState(Ship::HYPERSPACE); // virtual call, do class-specific things OnEnterHyperspace(); }
bool Ship::FireMissile(int idx, Ship *target) { assert(target); if (GetFlightState() != FLYING) return false; const Equip::Type t = m_equipment.Get(Equip::SLOT_MISSILE, idx); if (t == Equip::NONE) { return false; } m_equipment.Set(Equip::SLOT_MISSILE, idx, Equip::NONE); UpdateEquipStats(); ShipType::Id mtype; switch (t) { case Equip::MISSILE_SMART: mtype = ShipType::MISSILE_SMART; break; case Equip::MISSILE_NAVAL: mtype = ShipType::MISSILE_NAVAL; break; case Equip::MISSILE_UNGUIDED: mtype = ShipType::MISSILE_UNGUIDED; break; default: case Equip::MISSILE_GUIDED: mtype = ShipType::MISSILE_GUIDED; break; } Missile *missile = new Missile(mtype, this, target); missile->SetOrient(GetOrient()); missile->SetFrame(GetFrame()); // XXX DODGY! need to put it in a sensible location vector3d dir = -GetOrient().VectorZ(); missile->SetPosition(GetPosition()+50.0*dir); missile->SetVelocity(GetVelocity()); Pi::game->GetSpace()->AddBody(missile); return true; }
void Player::StaticUpdate(const float timeStep) { Body *b; vector3d v; matrix4x4d m; if (GetFlightState() == Ship::FLYING) { switch (m_flightControlState) { case CONTROL_FIXSPEED: if (Pi::GetView() == Pi::worldView) PollControls(timeStep); b = (GetCombatTarget() ? GetCombatTarget() : GetNavTarget()); GetRotMatrix(m); v = m * vector3d(0, 0, -m_setSpeed); if (b) v += b->GetVelocityRelativeTo(this->GetFrame()); AIMatchVel(v); break; case CONTROL_MANUAL: if (Pi::GetView() == Pi::worldView) PollControls(timeStep); break; case CONTROL_AUTOPILOT: break; } } Ship::StaticUpdate(timeStep); // also calls autopilot AI if (m_flightControlState == CONTROL_AUTOPILOT && !AIIsActive()) { Pi::RequestTimeAccel(1); SetFlightControlState(CONTROL_MANUAL); //FIXSPEED); // m_setSpeed = 0; } /* This wank probably shouldn't be in Player... */ /* Ship engine noise. less loud inside */ float v_env = (Pi::worldView->GetCamType() == WorldView::CAM_EXTERNAL ? 1.0f : 0.5f); static Sound::Event sndev; float volBoth = 0.0f; volBoth += 0.5f*fabs(GetThrusterState().y); volBoth += 0.5f*fabs(GetThrusterState().z); float targetVol[2] = { volBoth, volBoth }; if (GetThrusterState().x > 0.0) targetVol[0] += 0.5f*(float)GetThrusterState().x; else targetVol[1] += -0.5f*(float)GetThrusterState().x; targetVol[0] = v_env * Clamp(targetVol[0], 0.0f, 1.0f); targetVol[1] = v_env * Clamp(targetVol[1], 0.0f, 1.0f); float dv_dt[2] = { 4.0f, 4.0f }; if (!sndev.VolumeAnimate(targetVol, dv_dt)) { sndev.Play("Thruster_large", 0.0f, 0.0f, Sound::OP_REPEAT); sndev.VolumeAnimate(targetVol, dv_dt); } float angthrust = 0.1f * v_env * (float)Pi::player->GetAngThrusterState().Length(); static Sound::Event angThrustSnd; if (!angThrustSnd.VolumeAnimate(angthrust, angthrust, 5.0f, 5.0f)) { angThrustSnd.Play("Thruster_Small", 0.0f, 0.0f, Sound::OP_REPEAT); angThrustSnd.VolumeAnimate(angthrust, angthrust, 5.0f, 5.0f); } }
void Ship::EnterSystem() { assert(GetFlightState() == Ship::HYPERSPACE); // virtual call, do class-specific things OnEnterSystem(); SetFlightState(Ship::FLYING); LuaEvent::Queue("onEnterSystem", this); }
Ship::HyperjumpStatus Ship::CheckHyperspaceTo(const SystemPath &dest, int &outFuelRequired, double &outDurationSecs) { assert(dest.HasValidSystem()); outFuelRequired = 0; outDurationSecs = 0.0; if (GetFlightState() != FLYING) return HYPERJUMP_SAFETY_LOCKOUT; return GetHyperspaceDetails(dest, outFuelRequired, outDurationSecs); }
Missile * Ship::SpawnMissile(ShipType::Id missile_type, int power) { if (GetFlightState() != FLYING) return 0; Missile *missile = new Missile(missile_type, this, power); missile->SetOrient(GetOrient()); missile->SetFrame(GetFrame()); const vector3d pos = GetOrient() * vector3d(0, GetAabb().min.y - 10, GetAabb().min.z); const vector3d vel = -40.0 * GetOrient().VectorZ(); missile->SetPosition(GetPosition()+pos); missile->SetVelocity(GetVelocity()+vel); Pi::game->GetSpace()->AddBody(missile); return missile; }
Missile * Ship::SpawnMissile(ShipType::Id missile_type, int power) { if (GetFlightState() != FLYING) return 0; Missile *missile = new Missile(missile_type, this, power); missile->SetOrient(GetOrient()); missile->SetFrame(GetFrame()); // XXX DODGY! need to put it in a sensible location vector3d dir = -GetOrient().VectorZ(); missile->SetPosition(GetPosition()+50.0*dir); missile->SetVelocity(GetVelocity()); Pi::game->GetSpace()->AddBody(missile); return missile; }
Ship::HyperjumpStatus Ship::InitiateHyperjumpTo(const SystemPath &dest, int warmup_time, double duration, LuaRef checks) { if (!dest.HasValidSystem() || GetFlightState() != FLYING || warmup_time < 1) return HYPERJUMP_SAFETY_LOCKOUT; StarSystem *s = Pi::game->GetSpace()->GetStarSystem().Get(); if (s && s->GetPath().IsSameSystem(dest)) return HYPERJUMP_CURRENT_SYSTEM; m_hyperspace.dest = dest; m_hyperspace.countdown = warmup_time; m_hyperspace.now = false; m_hyperspace.duration = duration; m_hyperspace.checks = checks; return Ship::HYPERJUMP_OK; }
void Ship::EnterHyperspace() { assert(GetFlightState() != Ship::HYPERSPACE); // Is it still a good idea, with the onLeaveSystem moved elsewhere? Ship::HyperjumpStatus status = CheckHyperjumpCapability(); if (status != HYPERJUMP_OK && status != HYPERJUMP_INITIATED) { if (m_flightState == JUMPING) SetFlightState(FLYING); return; } // Clear ships cached list of nearby bodies so we don't try to access them. m_nearbyBodies.clear(); SetFlightState(Ship::HYPERSPACE); // virtual call, do class-specific things OnEnterHyperspace(); }
Ship::HyperjumpStatus Ship::GetHyperspaceDetails(const SystemPath &dest, int &outFuelRequired, double &outDurationSecs) { assert(dest.HasValidSystem()); outFuelRequired = 0; outDurationSecs = 0.0; UpdateStats(); if (GetFlightState() == HYPERSPACE) return HYPERJUMP_DRIVE_ACTIVE; Equip::Type t = m_equipment.Get(Equip::SLOT_ENGINE); Equip::Type fuelType = GetHyperdriveFuelType(); int hyperclass = Equip::types[t].pval; int fuel = m_equipment.Count(Equip::SLOT_CARGO, fuelType); if (hyperclass == 0) return HYPERJUMP_NO_DRIVE; StarSystem *s = Pi::game->GetSpace()->GetStarSystem().Get(); if (s && s->GetPath().IsSameSystem(dest)) return HYPERJUMP_CURRENT_SYSTEM; float dist = distance_to_system(dest); outFuelRequired = Pi::CalcHyperspaceFuelOut(hyperclass, dist, m_stats.hyperspace_range_max); double m_totalmass = GetMass()/1000; if (dist > m_stats.hyperspace_range_max) { outFuelRequired = 0; return HYPERJUMP_OUT_OF_RANGE; } else if (fuel < outFuelRequired) { return HYPERJUMP_INSUFFICIENT_FUEL; } else { outDurationSecs = Pi::CalcHyperspaceDuration(hyperclass, m_totalmass, dist); if (outFuelRequired <= fuel) { return HYPERJUMP_OK; } else { return HYPERJUMP_INSUFFICIENT_FUEL; } } }
void Player::PollControls(const float timeStep) { static bool stickySpeedKey = false; if (Pi::game->GetTimeAccel() == Game::TIMEACCEL_PAUSED || Pi::player->IsDead() || GetFlightState() != FLYING) return; // if flying { ClearThrusterState(); SetGunState(0,0); SetGunState(1,0); vector3d wantAngVel(0.0); double angThrustSoftness = 50.0; // have to use this function. SDL mouse position event is bugged in windows int mouseMotion[2]; SDL_GetRelativeMouseState (mouseMotion+0, mouseMotion+1); // call to flush if (Pi::MouseButtonState(SDL_BUTTON_RIGHT)) { matrix4x4d rot; GetRotMatrix(rot); if (!m_mouseActive) { m_mouseDir = vector3d(-rot[8],-rot[9],-rot[10]); // in world space m_mouseX = m_mouseY = 0; m_mouseActive = true; } vector3d objDir = m_mouseDir * rot; const double radiansPerPixel = 0.002; m_mouseX += mouseMotion[0] * radiansPerPixel; double modx = clipmouse(objDir.x, m_mouseX); m_mouseX -= modx; const bool invertY = (Pi::IsMouseYInvert() ? !m_invertMouse : m_invertMouse); m_mouseY += mouseMotion[1] * radiansPerPixel * (invertY ? -1 : 1); double mody = clipmouse(objDir.y, m_mouseY); m_mouseY -= mody; if(!float_is_zero_general(modx) || !float_is_zero_general(mody)) { matrix4x4d mrot = matrix4x4d::RotateYMatrix(modx); mrot.RotateX(mody); m_mouseDir = (rot * (mrot * objDir)).Normalized(); } } else m_mouseActive = false; // disable all keyboard controls while the console is active if (!Pi::IsConsoleActive()) { if (m_flightControlState == CONTROL_FIXSPEED) { double oldSpeed = m_setSpeed; if (stickySpeedKey) { if (!(KeyBindings::increaseSpeed.IsActive() || KeyBindings::decreaseSpeed.IsActive())) { stickySpeedKey = false; } } if (!stickySpeedKey) { if (KeyBindings::increaseSpeed.IsActive()) m_setSpeed += std::max(fabs(m_setSpeed)*0.05, 1.0); if (KeyBindings::decreaseSpeed.IsActive()) m_setSpeed -= std::max(fabs(m_setSpeed)*0.05, 1.0); if ( ((oldSpeed < 0.0) && (m_setSpeed >= 0.0)) || ((oldSpeed > 0.0) && (m_setSpeed <= 0.0)) ) { // flipped from going forward to backwards. make the speed 'stick' at zero // until the player lets go of the key and presses it again stickySpeedKey = true; m_setSpeed = 0; } } } if (KeyBindings::thrustForward.IsActive()) SetThrusterState(2, -1.0); if (KeyBindings::thrustBackwards.IsActive()) SetThrusterState(2, 1.0); if (KeyBindings::thrustUp.IsActive()) SetThrusterState(1, 1.0); if (KeyBindings::thrustDown.IsActive()) SetThrusterState(1, -1.0); if (KeyBindings::thrustLeft.IsActive()) SetThrusterState(0, -1.0); if (KeyBindings::thrustRight.IsActive()) SetThrusterState(0, 1.0); if (KeyBindings::fireLaser.IsActive() || (Pi::MouseButtonState(SDL_BUTTON_LEFT) && Pi::MouseButtonState(SDL_BUTTON_RIGHT))) { SetGunState(Pi::worldView->GetActiveWeapon(), 1); } if (KeyBindings::yawLeft.IsActive()) wantAngVel.y += 1.0; if (KeyBindings::yawRight.IsActive()) wantAngVel.y += -1.0; if (KeyBindings::pitchDown.IsActive()) wantAngVel.x += -1.0; if (KeyBindings::pitchUp.IsActive()) wantAngVel.x += 1.0; if (KeyBindings::rollLeft.IsActive()) wantAngVel.z += 1.0; if (KeyBindings::rollRight.IsActive()) wantAngVel.z -= 1.0; if (KeyBindings::fastRotate.IsActive()) angThrustSoftness = 10.0; } vector3d changeVec; changeVec.x = KeyBindings::pitchAxis.GetValue(); changeVec.y = KeyBindings::yawAxis.GetValue(); changeVec.z = KeyBindings::rollAxis.GetValue(); // Deadzone if(changeVec.LengthSqr() < m_joystickDeadzone) changeVec = vector3d(0.0); changeVec *= 2.0; wantAngVel += changeVec; double invTimeAccelRate = 1.0 / Pi::game->GetTimeAccelRate(); for (int axis=0; axis<3; axis++) wantAngVel[axis] = Clamp(wantAngVel[axis], -invTimeAccelRate, invTimeAccelRate); if (m_mouseActive) AIFaceDirection(m_mouseDir); else AIModelCoordsMatchAngVel(wantAngVel, angThrustSoftness); } }
void Player::StaticUpdate(const float timeStep) { vector3d v; matrix4x4d m; Ship::StaticUpdate(timeStep); // also calls autopilot AI if (GetFlightState() == Ship::FLYING) { switch (m_flightControlState) { case CONTROL_FIXSPEED: if (Pi::GetView() == Pi::worldView) PollControls(timeStep); if (IsAnyThrusterKeyDown()) break; GetRotMatrix(m); v = m * vector3d(0, 0, -m_setSpeed); if (m_setSpeedTarget) { v += m_setSpeedTarget->GetVelocityRelTo(GetFrame()); } AIMatchVel(v); break; case CONTROL_MANUAL: if (Pi::GetView() == Pi::worldView) PollControls(timeStep); break; case CONTROL_AUTOPILOT: if (AIIsActive()) break; Pi::game->RequestTimeAccel(Game::TIMEACCEL_1X); // AIMatchVel(vector3d(0.0)); // just in case autopilot doesn't... // actually this breaks last timestep slightly in non-relative target cases AIMatchAngVelObjSpace(vector3d(0.0)); if (GetFrame()->IsRotatingFrame()) SetFlightControlState(CONTROL_FIXSPEED); else SetFlightControlState(CONTROL_MANUAL); m_setSpeed = 0.0; break; } } else SetFlightControlState(CONTROL_MANUAL); /* This wank probably shouldn't be in Player... */ /* Ship engine noise. less loud inside */ float v_env = (Pi::worldView->GetCamType() == WorldView::CAM_EXTERNAL ? 1.0f : 0.5f) * Sound::GetSfxVolume(); static Sound::Event sndev; float volBoth = 0.0f; volBoth += 0.5f*fabs(GetThrusterState().y); volBoth += 0.5f*fabs(GetThrusterState().z); float targetVol[2] = { volBoth, volBoth }; if (GetThrusterState().x > 0.0) targetVol[0] += 0.5f*float(GetThrusterState().x); else targetVol[1] += -0.5f*float(GetThrusterState().x); targetVol[0] = v_env * Clamp(targetVol[0], 0.0f, 1.0f); targetVol[1] = v_env * Clamp(targetVol[1], 0.0f, 1.0f); float dv_dt[2] = { 4.0f, 4.0f }; if (!sndev.VolumeAnimate(targetVol, dv_dt)) { sndev.Play("Thruster_large", 0.0f, 0.0f, Sound::OP_REPEAT); sndev.VolumeAnimate(targetVol, dv_dt); } float angthrust = 0.1f * v_env * float(Pi::player->GetAngThrusterState().Length()); static Sound::Event angThrustSnd; if (!angThrustSnd.VolumeAnimate(angthrust, angthrust, 5.0f, 5.0f)) { angThrustSnd.Play("Thruster_Small", 0.0f, 0.0f, Sound::OP_REPEAT); angThrustSnd.VolumeAnimate(angthrust, angthrust, 5.0f, 5.0f); } }
void Player::PollControls(const float timeStep) { double time_accel = Pi::GetTimeAccel(); double invTimeAccel = 1.0 / time_accel; static bool stickySpeedKey = false; if ((time_accel == 0) || GetDockedWith() || Pi::player->IsDead() || (GetFlightState() != FLYING)) { return; } // if flying { ClearThrusterState(); vector3d wantAngVel(0.0); // have to use this function. SDL mouse position event is bugged in windows int mouseMotion[2]; SDL_GetRelativeMouseState (mouseMotion+0, mouseMotion+1); // call to flush if (Pi::MouseButtonState(3)) { matrix4x4d rot; GetRotMatrix(rot); if (!m_mouseActive) { m_mouseDir = vector3d(-rot[8],-rot[9],-rot[10]); // in world space m_mouseX = m_mouseY = 0; m_mouseActive = true; } vector3d objDir = m_mouseDir * rot; m_mouseX += mouseMotion[0] * 0.002; double modx = clipmouse(objDir.x, m_mouseX); m_mouseX -= modx; m_mouseY += mouseMotion[1] * 0.002; // factor pixels => radians double mody = clipmouse(objDir.y, m_mouseY); m_mouseY -= mody; if(modx != 0.0 || mody != 0.0) { matrix4x4d mrot = matrix4x4d::RotateYMatrix(modx); mrot.RotateX(mody); m_mouseDir = (rot * (mrot * objDir)).Normalized(); } } else m_mouseActive = false; if (m_flightControlState == CONTROL_FIXSPEED) { double oldSpeed = m_setSpeed; if (stickySpeedKey) { if (!(KeyBindings::increaseSpeed.IsActive() || KeyBindings::decreaseSpeed.IsActive())) { stickySpeedKey = false; } } if (!stickySpeedKey) { if (KeyBindings::increaseSpeed.IsActive()) m_setSpeed += std::max(m_setSpeed*0.05, 1.0); if (KeyBindings::decreaseSpeed.IsActive()) m_setSpeed -= std::max(m_setSpeed*0.05, 1.0); if ( ((oldSpeed < 0.0) && (m_setSpeed >= 0.0)) || ((oldSpeed > 0.0) && (m_setSpeed <= 0.0)) ) { // flipped from going forward to backwards. make the speed 'stick' at zero // until the player lets go of the key and presses it again stickySpeedKey = true; m_setSpeed = 0; } } } if (KeyBindings::thrustForward.IsActive()) SetThrusterState(2, -1.0); if (KeyBindings::thrustBackwards.IsActive()) SetThrusterState(2, 1.0); if (KeyBindings::thrustUp.IsActive()) SetThrusterState(1, 1.0); if (KeyBindings::thrustDown.IsActive()) SetThrusterState(1, -1.0); if (KeyBindings::thrustLeft.IsActive()) SetThrusterState(0, -1.0); if (KeyBindings::thrustRight.IsActive()) SetThrusterState(0, 1.0); SetGunState(0,0); SetGunState(1,0); if (KeyBindings::fireLaser.IsActive() || (Pi::MouseButtonState(1) && Pi::MouseButtonState(3))) { SetGunState(Pi::worldView->GetActiveWeapon(), 1); } if (KeyBindings::yawLeft.IsActive()) wantAngVel.y += 1.0; if (KeyBindings::yawRight.IsActive()) wantAngVel.y += -1.0; if (KeyBindings::pitchDown.IsActive()) wantAngVel.x += -1.0; if (KeyBindings::pitchUp.IsActive()) wantAngVel.x += 1.0; if (KeyBindings::rollLeft.IsActive()) wantAngVel.z += 1.0; if (KeyBindings::rollRight.IsActive()) wantAngVel.z -= 1.0; wantAngVel.x += 2 * KeyBindings::pitchAxis.GetValue(); wantAngVel.y += 2 * KeyBindings::yawAxis.GetValue(); wantAngVel.z += 2 * KeyBindings::rollAxis.GetValue(); for (int axis=0; axis<3; axis++) wantAngVel[axis] = Clamp(wantAngVel[axis], -invTimeAccel, invTimeAccel); // matrix4x4d rot; GetRotMatrix(rot); const double angThrustSoftness = KeyBindings::fastRotate.IsActive() ? 10.0 : 50.0; if (m_mouseActive) AIFaceDirection(m_mouseDir); else AIModelCoordsMatchAngVel(wantAngVel, angThrustSoftness); } }