void AICmdFlyAround::Setup(Body *obstructor, double alt, double vel, int targmode, Body *target, Frame *targframe, const vector3d &posoff) { m_obstructor = obstructor; m_alt = alt; m_vel = vel; m_targmode = targmode; m_target = target; m_targframe = targframe; m_posoff = posoff; // generate suitable velocity if none provided double minacc = (targmode == 3) ? 0 : m_ship->GetAccelMin(); double mass = obstructor->IsType(Object::TERRAINBODY) ? obstructor->GetMass() : 0; if (vel < 1e-30) m_vel = sqrt(m_alt*0.8*minacc + mass*G/m_alt); // check if altitude is within obstructor frame if (alt > 0.9 * GetNonRotFrame(obstructor)->GetRadius()) { m_ship->AIMessage(Ship::AIERROR_ORBIT_IMPOSSIBLE); m_targmode = 1; m_target = 0; // force an exit } }
// Pursue ship, not body AICmdFlyTo::AICmdFlyTo(Ship *ship, Ship *target, float hungriness) : AICommand (ship, CMD_FLYTO) { double dist = std::max(VICINITY_MIN, VICINITY_MUL*MaxEffectRad(target, ship)); m_targframe = GetNonRotFrame(target); m_posoff = dist * m_ship->GetPositionRelTo(m_targframe).Normalized(); m_posoff += target->GetPosition(); m_endvel = 0; m_tangent = 0; m_state = -1; m_frame = 0; // check if we're already close enough if (dist > m_ship->GetPositionRelTo(target).Length()) m_state = 5; m_fuelEconomy = Clamp(hungriness, 0.0f, 1.0f);; m_targetShip = target; }
// Fly to "vicinity" of body AICmdFlyTo::AICmdFlyTo(Ship *ship, Body *target) : AICommand (ship, CMD_FLYTO) { double dist = std::max(VICINITY_MIN, VICINITY_MUL*MaxEffectRad(target, ship)); if (target->IsType(Object::SPACESTATION) && static_cast<SpaceStation *>(target)->IsGroundStation()) { matrix4x4d rot; target->GetRotMatrix(rot); m_posoff = target->GetPosition() + dist * vector3d(rot[4], rot[5], rot[6]); // up vector for starport m_targframe = target->GetFrame(); } else { m_targframe = GetNonRotFrame(target); m_posoff = dist * m_ship->GetPositionRelTo(m_targframe).Normalized(); m_posoff += target->GetPosition(); } m_endvel = 0; m_tangent = 0; m_state = -1; m_frame = 0; // check if we're already close enough if (dist > m_ship->GetPositionRelTo(target).Length()) m_state = 5; }
bool AICmdFlyAround::TimeStepUpdate() { if (m_targmode == 1 && !m_target) return true; if (!ProcessChild()) return false; // Not necessary unless it's a tier 1 AI if (m_ship->GetFlightState() == Ship::FLYING) m_ship->SetWheelState(false); else { LaunchShip(m_ship); return false; } double timestep = Pi::game->GetTimeStep(); vector3d targpos = Targpos(); // target position in ship's frame vector3d obspos = m_obstructor->GetPositionRelTo(m_ship); double obsdist = obspos.Length(); vector3d obsdir = obspos / obsdist; vector3d relpos = targpos - m_ship->GetPosition(); // if too far away, fly to tangent if (obsdist > 1.1*m_alt) { double v; Frame *obsframe = GetNonRotFrame(m_obstructor); vector3d tangent = GenerateTangent(m_ship, obsframe, targpos, m_alt); vector3d tpos_obs = GetPosInFrame(obsframe, m_ship->GetFrame(), targpos); if (m_targmode != 1 && m_targmode != 2) v = m_vel; else if (relpos.LengthSqr() < obsdist) v = 0.0; else v = MaxVel((tpos_obs-tangent).Length(), tpos_obs.Length()); m_child = new AICmdFlyTo(m_ship, obsframe, tangent, v, true); ProcessChild(); return false; } // limit m_vel by target proximity & distance covered per frame double vel = (m_targmode != 1 && m_targmode != 2) ? m_vel : MaxVel(relpos.Length(), targpos.Length()); // all calculations in ship's frame vector3d fwddir = (obsdir.Cross(relpos).Cross(obsdir)).Normalized(); vector3d tanvel = vel * fwddir; // frame body suicide check, response if (CheckSuicide(m_ship, -obsdir)) { m_ship->AIFaceDirection(m_ship->GetPosition()); // face away from planet m_ship->AIMatchVel(vector3d(0.0)); return false; } // max feature avoidance check, response if (obsdist < MaxFeatureRad(m_obstructor)) { double ang = m_ship->AIFaceDirection(-obsdir); m_ship->AIMatchVel(ang < 0.05 ? 1000.0 * -obsdir : 0.0); return false; } // calculate target velocity double alt = (tanvel * timestep + obspos).Length(); // unnecessary? double ivel = calc_ivel(alt - m_alt, 0.0, m_ship->GetAccelMin()); vector3d finalvel = tanvel + ivel * obsdir; m_ship->AIMatchVel(finalvel); m_ship->AIFaceDirection(fwddir); // vector3d newhead = GenerateTangent(m_ship, m_obstructor->GetFrame(), fwddir); // newhead = GetPosInFrame(m_ship->GetFrame(), m_obstructor->GetFrame(), newhead); // m_ship->AIFaceDirection(newhead-m_ship->GetPosition()); // termination condition for orbits vector3d thrust = m_ship->GetThrusterState(); if (m_targmode >= 3 && thrust.LengthSqr() < 0.01) m_targmode++; if (m_targmode == 5) { m_ship->SetThrusterState(vector3d(0.0)); return true; } return false; }