void Missile::TimeStepUpdate(const float timeStep) { const vector3d thrust=GetActualLinThrust(); AddRelForce( thrust ); AddRelTorque( GetActualAngThrust() ); DynamicBody::TimeStepUpdate(timeStep); Propulsion::UpdateFuel(timeStep); const float MISSILE_DETECTION_RADIUS = 100.0f; if (!m_owner) { Explode(); } else if (m_armed) { Space::BodyNearList nearby; Pi::game->GetSpace()->GetBodiesMaybeNear(this, MISSILE_DETECTION_RADIUS, nearby); for (Space::BodyNearIterator i = nearby.begin(); i != nearby.end(); ++i) { if (*i == this) continue; double dist = ((*i)->GetPosition() - GetPosition()).Length(); if (dist < MISSILE_DETECTION_RADIUS) { Explode(); break; } } } }
Ship::ECMResult Ship::UseECM() { int ecm_power_cap = 0; Properties().Get("ecm_power_cap", ecm_power_cap); if (m_ecmRecharge > 0.0f) return ECM_RECHARGING; if (ecm_power_cap > 0) { Sound::BodyMakeNoise(this, "ECM", 1.0f); m_ecmRecharge = GetECMRechargeTime(); // damage neaby missiles const float ECM_RADIUS = 4000.0f; Space::BodyNearList nearby; Pi::game->GetSpace()->GetBodiesMaybeNear(this, ECM_RADIUS, nearby); for (Space::BodyNearIterator i = nearby.begin(); i != nearby.end(); ++i) { if ((*i)->GetFrame() != GetFrame()) continue; if (!(*i)->IsType(Object::MISSILE)) continue; double dist = ((*i)->GetPosition() - GetPosition()).Length(); if (dist < ECM_RADIUS) { // increasing chance of destroying it with proximity if (Pi::rng.Double() > (dist / ECM_RADIUS)) { static_cast<Missile*>(*i)->ECMAttack(ecm_power_cap); } } } return ECM_ACTIVATED; } else return ECM_NOT_INSTALLED; }
void Ship::UseECM() { const Equip::Type t = m_equipment.Get(Equip::SLOT_ECM); if (m_ecmRecharge > 0.0f) return; if (t != Equip::NONE) { Sound::BodyMakeNoise(this, "ECM", 1.0f); m_ecmRecharge = GetECMRechargeTime(); // damage neaby missiles const float ECM_RADIUS = 4000.0f; Space::BodyNearList nearby; Pi::game->GetSpace()->GetBodiesMaybeNear(this, ECM_RADIUS, nearby); for (Space::BodyNearIterator i = nearby.begin(); i != nearby.end(); ++i) { if ((*i)->GetFrame() != GetFrame()) continue; if (!(*i)->IsType(Object::MISSILE)) continue; double dist = ((*i)->GetPosition() - GetPosition()).Length(); if (dist < ECM_RADIUS) { // increasing chance of destroying it with proximity if (Pi::rng.Double() > (dist / ECM_RADIUS)) { static_cast<Missile*>(*i)->ECMAttack(Equip::types[t].pval); } } } } }
void Sensors::Update(float time) { PROFILE_SCOPED(); if (m_owner != Pi::player) return; PopulateStaticContacts(); //no need to do all the time //Find nearby contacts, same range as radar scanner. It should use these //contacts, worldview labels too. Space::BodyNearList nearby; Pi::game->GetSpace()->GetBodiesMaybeNear(m_owner, 100000.0f, nearby); for (Space::BodyNearIterator i = nearby.begin(); i != nearby.end(); ++i) { if ((*i) == m_owner || !(*i)->IsType(Object::SHIP)) continue; if ((*i)->IsDead()) continue; auto cit = m_radarContacts.begin(); while (cit != m_radarContacts.end()) { if (cit->body == (*i)) break; ++cit; } //create new contact or refresh old if (cit == m_radarContacts.end()) { m_radarContacts.push_back(RadarContact()); RadarContact &rc = m_radarContacts.back(); rc.body = (*i); rc.iff = CheckIFF(rc.body); rc.trail = new HudTrail(rc.body, IFFColor(rc.iff)); } else { cit->fresh = true; } } //update contacts and delete stale ones auto it = m_radarContacts.begin(); while (it != m_radarContacts.end()) { if (!it->fresh) { m_radarContacts.erase(it++); } else { const Ship *ship = dynamic_cast<Ship *>(it->body); if (ship && Ship::FLYING == ship->GetFlightState()) { it->distance = m_owner->GetPositionRelTo(it->body).Length(); it->trail->Update(time); } else { it->trail->Reset(nullptr); } it->fresh = false; ++it; } } }
void Missile::TimeStepUpdate(const float timeStep) { Ship::TimeStepUpdate(timeStep); const float MISSILE_DETECTION_RADIUS = 100.0f; if (!m_owner) { Explode(); } else if (m_armed) { Space::BodyNearList nearby; Pi::game->GetSpace()->GetBodiesMaybeNear(this, MISSILE_DETECTION_RADIUS, nearby); for (Space::BodyNearIterator i = nearby.begin(); i != nearby.end(); ++i) { if (*i == this) continue; double dist = ((*i)->GetPosition() - GetPosition()).Length(); if (dist < MISSILE_DETECTION_RADIUS) { Explode(); break; } } } }
void Missile::Explode() { Pi::game->GetSpace()->KillBody(this); const double damageRadius = 200.0; const double kgDamage = 10000.0; CollisionContact dummy; Space::BodyNearList nearby; Pi::game->GetSpace()->GetBodiesMaybeNear(this, damageRadius, nearby); for (Space::BodyNearIterator i = nearby.begin(); i != nearby.end(); ++i) { if ((*i)->GetFrame() != GetFrame()) continue; double dist = ((*i)->GetPosition() - GetPosition()).Length(); if (dist < damageRadius) { // linear damage decay with distance (*i)->OnDamage(m_owner, kgDamage * (damageRadius - dist) / damageRadius, dummy); if ((*i)->IsType(Object::SHIP)) LuaEvent::Queue("onShipHit", dynamic_cast<Ship*>(*i), m_owner); } } Sfx::Add(this, Sfx::TYPE_EXPLOSION); }
void ScannerWidget::Update() { if(Pi::IsScannerCompact() != isCompact) { InitScaling(); GenerateBaseGeometry(); GenerateRingsAndSpokes(); } m_contacts.clear(); int scanner_cap = 0; Pi::player->Properties().Get("scanner_cap", scanner_cap); if (scanner_cap <= 0) { m_mode = SCANNER_MODE_AUTO; m_currentRange = m_manualRange = m_targetRange = SCANNER_RANGE_MIN; return; } // range priority is combat target > ship/missile > nav target > other enum { RANGE_MAX, RANGE_FAR_OTHER, RANGE_NAV, RANGE_FAR_SHIP, RANGE_COMBAT } range_type = RANGE_MAX; float combat_dist = 0, far_ship_dist = 0, nav_dist = 0, far_other_dist = 0; // collect the bodies to be displayed, and if AUTO, distances Space::BodyNearList nearby; Pi::game->GetSpace()->GetBodiesMaybeNear(Pi::player, SCANNER_RANGE_MAX, nearby); for (Space::BodyNearIterator i = nearby.begin(); i != nearby.end(); ++i) { if ((*i) == Pi::player) continue; float dist = float((*i)->GetPositionRelTo(Pi::player).Length()); Contact c; c.type = (*i)->GetType(); c.pos = (*i)->GetPositionRelTo(Pi::player); c.isSpecial = false; switch ((*i)->GetType()) { case Object::MISSILE: // player's own missiles are ignored for range calc but still shown if (static_cast<const Missile*>(*i)->GetOwner() == Pi::player) { c.isSpecial = true; break; } // else fall through case Object::SHIP: { const Ship *s = static_cast<const Ship*>(*i); if (s->GetFlightState() != Ship::FLYING && s->GetFlightState() != Ship::LANDED) continue; if ((*i) == Pi::player->GetCombatTarget()) c.isSpecial = true; if (m_mode == SCANNER_MODE_AUTO && range_type != RANGE_COMBAT) { if (c.isSpecial == true) { combat_dist = dist; range_type = RANGE_COMBAT; } else if (dist > far_ship_dist) { far_ship_dist = dist; range_type = RANGE_FAR_SHIP; } } break; } case Object::SPACESTATION: case Object::CARGOBODY: case Object::HYPERSPACECLOUD: if ((*i) == Pi::player->GetNavTarget()) c.isSpecial = true; if (m_mode == SCANNER_MODE_AUTO && range_type < RANGE_NAV) { if (c.isSpecial == true) { nav_dist = dist; range_type = RANGE_NAV; } else if (dist > far_other_dist) { far_other_dist = dist; range_type = RANGE_FAR_OTHER; } } break; default: continue; } m_contacts.push_back(c); } if (KeyBindings::increaseScanRange.IsActive()) { if (m_mode == SCANNER_MODE_AUTO) { m_manualRange = m_targetRange; m_mode = SCANNER_MODE_MANUAL; } else m_manualRange = m_currentRange; m_manualRange = Clamp(m_manualRange * 1.05f, SCANNER_RANGE_MIN, SCANNER_RANGE_MAX); } else if (KeyBindings::decreaseScanRange.IsActive()) { if (m_mode == SCANNER_MODE_AUTO) { m_manualRange = m_targetRange; m_mode = SCANNER_MODE_MANUAL; } else m_manualRange = m_currentRange; m_manualRange = Clamp(m_manualRange * 0.95f, SCANNER_RANGE_MIN, SCANNER_RANGE_MAX); } if (m_mode == SCANNER_MODE_AUTO) { switch (range_type) { case RANGE_COMBAT: m_targetRange = Clamp(combat_dist * A_BIT, SCANNER_RANGE_MIN, SCANNER_RANGE_MAX); break; case RANGE_FAR_SHIP: m_targetRange = Clamp(far_ship_dist * A_BIT, SCANNER_RANGE_MIN, SCANNER_RANGE_MAX); break; case RANGE_NAV: m_targetRange = Clamp(nav_dist * A_BIT, SCANNER_RANGE_MIN, SCANNER_RANGE_MAX); break; case RANGE_FAR_OTHER: m_targetRange = Clamp(far_other_dist * A_BIT, SCANNER_RANGE_MIN, SCANNER_RANGE_MAX); break; default: m_targetRange = SCANNER_RANGE_MAX; break; } } else m_targetRange = m_manualRange; }
void Ship::UpdateAlertState() { // no alerts if no scanner if (m_equipment.Get(Equip::SLOT_SCANNER) == Equip::NONE) { // clear existing alert state if there was one if (GetAlertState() != ALERT_NONE) { SetAlertState(ALERT_NONE); LuaEvent::Queue("onShipAlertChanged", this, EnumStrings::GetString("ShipAlertStatus", ALERT_NONE)); } return; } static const double ALERT_DISTANCE = 100000.0; // 100km Space::BodyNearList nearby; Pi::game->GetSpace()->GetBodiesMaybeNear(this, ALERT_DISTANCE, nearby); bool ship_is_near = false, ship_is_firing = false; for (Space::BodyNearIterator i = nearby.begin(); i != nearby.end(); ++i) { if ((*i) == this) continue; if (!(*i)->IsType(Object::SHIP) || (*i)->IsType(Object::MISSILE)) continue; const Ship *ship = static_cast<const Ship*>(*i); if (ship->GetShipType().tag == ShipType::TAG_STATIC_SHIP) continue; if (ship->GetFlightState() == LANDED || ship->GetFlightState() == DOCKED) continue; if (GetPositionRelTo(ship).LengthSqr() < ALERT_DISTANCE*ALERT_DISTANCE) { ship_is_near = true; Uint32 gunstate = 0; for (int j = 0; j < ShipType::GUNMOUNT_MAX; j++) gunstate |= ship->m_gunState[j]; if (gunstate) { ship_is_firing = true; break; } } } bool changed = false; switch (m_alertState) { case ALERT_NONE: if (ship_is_near) { SetAlertState(ALERT_SHIP_NEARBY); changed = true; } if (ship_is_firing) { m_lastFiringAlert = Pi::game->GetTime(); SetAlertState(ALERT_SHIP_FIRING); changed = true; } break; case ALERT_SHIP_NEARBY: if (!ship_is_near) { SetAlertState(ALERT_NONE); changed = true; } else if (ship_is_firing) { m_lastFiringAlert = Pi::game->GetTime(); SetAlertState(ALERT_SHIP_FIRING); changed = true; } break; case ALERT_SHIP_FIRING: if (!ship_is_near) { SetAlertState(ALERT_NONE); changed = true; } else if (ship_is_firing) { m_lastFiringAlert = Pi::game->GetTime(); } else if (m_lastFiringAlert + 60.0 <= Pi::game->GetTime()) { SetAlertState(ALERT_SHIP_NEARBY); changed = true; } break; } if (changed) LuaEvent::Queue("onShipAlertChanged", this, EnumStrings::GetString("ShipAlertStatus", GetAlertState())); }