/* * Method: GetDockedWith * * Get the station that the ship is currently docked with * * > station = ship:GetDockedWith() * * Return: * * station - a <SpaceStation> object for the station, or nil if the ship is * not docked * * Availability: * * alpha 10 * * Status: * * stable */ static int l_ship_get_docked_with(lua_State *l) { Ship *s = LuaObject<Ship>::CheckFromLua(1); if (s->GetFlightState() != Ship::DOCKED) return 0; LuaObject<SpaceStation>::PushToLua(s->GetDockedWith()); return 1; }
/* Method: UseECM * * Activates ECM of ship, destroying nearby missile with probability * proportional to proximity. * * > success, recharge_wait = Ship:UseECM() * * Return: * * success - is true or false depending on if the ECM was activated * or not. False indicating wither it is not fully * recharged, or there is no ECM to activate. * * recharge_wait - time left to recharge. * * Availability: * * 2014 July * * Status: * * experimental */ static int l_ship_use_ecm(lua_State *l) { Ship *s = LuaObject<Ship>::CheckFromLua(1); if (s->GetFlightState() == Ship::HYPERSPACE) return luaL_error(l, "Ship:UseECM() cannot be called on a ship in hyperspace"); Ship::ECMResult result = s->UseECM(); float recharge; if(result == Ship::ECMResult::ECM_ACTIVATED) { recharge = s->GetECMRechargeRemain(); lua_pushboolean(l, true); lua_pushnumber(l, recharge); } else if(result == Ship::ECMResult::ECM_RECHARGING) { recharge = s->GetECMRechargeRemain(); lua_pushboolean(l, false); lua_pushnumber(l, recharge); } else if(result == Ship::ECMResult::ECM_NOT_INSTALLED) { lua_pushboolean(l, false); lua_pushnil(l); } return 2; }
/* * Method: AIDockWith * * Fly to and dock with a given station * * > ship:AIDockWith(target) * * Parameters: * * target - the <SpaceStation> to dock with * * Availability: * * alpha 10 * * Status: * * experimental */ static int l_ship_ai_dock_with(lua_State *l) { Ship *s = LuaObject<Ship>::CheckFromLua(1); if (s->GetFlightState() == Ship::HYPERSPACE) return luaL_error(l, "Ship:AIDockWith() cannot be called on a ship in hyperspace"); SpaceStation *target = LuaObject<SpaceStation>::CheckFromLua(2); s->AIDock(target); return 0; }
/* * Method: AIFlyTo * * Fly to the vicinity of a given physics body * * > ship:AIFlyTo(target) * * Parameters: * * target - the <Body> to fly to * * Availability: * * alpha 10 * * Status: * * experimental */ static int l_ship_ai_fly_to(lua_State *l) { Ship *s = LuaObject<Ship>::CheckFromLua(1); if (s->GetFlightState() == Ship::HYPERSPACE) return luaL_error(l, "Ship:AIFlyTo() cannot be called on a ship in hyperspace"); Body *target = LuaObject<Body>::CheckFromLua(2); s->AIFlyTo(target); return 0; }
/* * Method: AIKamikaze * * Crash into the target ship. * * > ship:AIKamikaze(target) * * Parameters: * * target - the <Ship> to destroy * * Availability: * * alpha 26 * * Status: * * experimental */ static int l_ship_ai_kamikaze(lua_State *l) { Ship *s = LuaObject<Ship>::GetFromLua(1); if (s->GetFlightState() == Ship::HYPERSPACE) return luaL_error(l, "Ship:AIKamikaze() cannot be called on a ship in hyperspace"); Ship *target = LuaObject<Ship>::GetFromLua(2); s->AIKamikaze(target); return 0; }
/* * Method: BlastOff * * Blast off, in normal direction to the ground, and retract landingear * * > success = ship:BlastOff() * * <Event.onShipBlastOff> will be triggered once unlanding is complete * * Availability: * * Scout+ 2015 * * Status: * * experimental */ static int l_ship_blastoff(lua_State *l) { Ship *s = LuaObject<Ship>::CheckFromLua(1); if (s->GetFlightState() != Ship::LANDED) luaL_error(l, "Can't BlastOff if not landed"); s->Blastoff(); s->SetWheelState(false); return 1; }
/* * Method: AIEnterHighOrbit * * Fly to and enter a high orbit around a given planet or star * * > ship:AIEnterHighOrbit(target) * * Parameters: * * target - the <Star> or <Planet> to orbit * * Availability: * * alpha 10 * * Status: * * experimental */ static int l_ship_ai_enter_high_orbit(lua_State *l) { Ship *s = LuaObject<Ship>::CheckFromLua(1); if (s->GetFlightState() == Ship::HYPERSPACE) return luaL_error(l, "Ship:AIEnterHighOrbit() cannot be called on a ship in hyperspace"); Body *target = LuaObject<Body>::CheckFromLua(2); if (!target->IsType(Object::PLANET) && !target->IsType(Object::STAR)) luaL_argerror(l, 2, "expected a Planet or a Star"); s->AIOrbit(target, 3.2); return 0; }
static int l_ship_explode(lua_State *l) { LUA_DEBUG_START(l); Ship *s = LuaObject<Ship>::CheckFromLua(1); if (s->GetFlightState() == Ship::HYPERSPACE) return luaL_error(l, "Ship:Explode() cannot be called on a ship in hyperspace"); s->Explode(); LUA_DEBUG_END(l, 0); return 0; }
/* * Method: AIKamikaze * * Crash into the target ship. * * > ship:AIKamikaze(target) * * Parameters: * * target - the <Ship> to destroy * * Returns: * true if the command could be enacted, false otherwise * * Availability: * * alpha 26 * * Status: * * experimental */ static int l_ship_ai_kamikaze(lua_State *l) { Ship *s = LuaObject<Ship>::GetFromLua(1); if (s->GetFlightState() == Ship::HYPERSPACE) return luaL_error(l, "Ship:AIKamikaze() cannot be called on a ship in hyperspace"); Ship *target = LuaObject<Ship>::GetFromLua(2); if (target != nullptr) { s->AIKamikaze(target); lua_pushboolean(l, true); } else { lua_pushboolean(l, false); } return 1; }
/* Method: SpawnMissile * * Spawn a missile near the ship. * * > missile = ship:SpawnMissile(type, target, power) * * Parameters: * * shiptype - a string for the missile type. specifying an * ship that is not a missile will result in a Lua error * * target - the <Ship> to fire the missile at * * power - the power of the missile. If unspecified, the default power for the * * Return: * * missile - The missile spawned, or nil if it was unsuccessful. * * Availability: * * alpha 26 * * Status: * * experimental */ static int l_ship_spawn_missile(lua_State *l) { Ship *s = LuaObject<Ship>::CheckFromLua(1); if (s->GetFlightState() == Ship::HYPERSPACE) return luaL_error(l, "Ship:SpawnMissile() cannot be called on a ship in hyperspace"); ShipType::Id missile_type(luaL_checkstring(l, 2)); if (missile_type != ShipType::MISSILE_UNGUIDED && missile_type != ShipType::MISSILE_GUIDED && missile_type != ShipType::MISSILE_SMART && missile_type != ShipType::MISSILE_NAVAL) luaL_error(l, "Ship type '%s' is not a valid missile type", lua_tostring(l, 2)); int power = (lua_isnone(l, 3))? -1 : lua_tointeger(l, 3); Missile * missile = s->SpawnMissile(missile_type, power); if (missile) LuaObject<Missile>::PushToLua(missile); else lua_pushnil(l); return 1; }
/* * Attribute: flightState * * The current flight state of the ship. A <Constants.ShipFlightState> string. * * Availability: * * alpha 25 * * Status: * * experimental */ static int l_ship_attr_flight_state(lua_State *l) { Ship *s = LuaObject<Ship>::CheckFromLua(1); lua_pushstring(l, EnumStrings::GetString("ShipFlightState", s->GetFlightState())); return 1; }
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); Pi::luaOnShipAlertChanged->Queue(this, LuaConstants::GetConstantString(Pi::luaManager->GetLuaState(), "ShipAlertStatus", ALERT_NONE)); } return; } bool ship_is_near = false, ship_is_firing = false; for (Space::bodiesIter_t i = Space::bodies.begin(); i != Space::bodies.end(); i++) { if ((*i) == this) continue; if (!(*i)->IsType(Object::SHIP) || (*i)->IsType(Object::MISSILE)) continue; Ship *ship = static_cast<Ship*>(*i); if (ship->GetFlightState() == LANDED || ship->GetFlightState() == DOCKED) continue; if (GetPositionRelTo(ship).LengthSqr() < 100000.0*100000.0) { 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::GetGameTime(); 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::GetGameTime(); 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::GetGameTime(); } else if (m_lastFiringAlert + 60.0 <= Pi::GetGameTime()) { SetAlertState(ALERT_SHIP_NEARBY); changed = true; } break; } if (changed) Pi::luaOnShipAlertChanged->Queue(this, LuaConstants::GetConstantString(Pi::luaManager->GetLuaState(), "ShipAlertStatus", GetAlertState())); }
void ScannerWidget::Update() { m_contacts.clear(); if (Pi::player->m_equipment.Get(Equip::SLOT_SCANNER) != Equip::SCANNER) { m_mode = SCANNER_MODE_AUTO; m_currentRange = m_manualRange = m_targetRange = SCANNER_RANGE_MIN; return; } 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 for (Space::bodiesIter_t i = Space::bodies.begin(); i != Space::bodies.end(); ++i) { if ((*i) == Pi::player) continue; float dist = float((*i)->GetPositionRelTo(Pi::player).Length()); if (dist > SCANNER_RANGE_MAX) continue; 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<Missile*>(*i)->GetOwner() == Pi::player) { c.isSpecial = true; break; } // fall through case Object::SHIP: { Ship *s = static_cast<Ship*>(*i); if (s->GetFlightState() != Ship::FLYING && s->GetFlightState() != Ship::LANDED) continue; if (m_mode == SCANNER_MODE_AUTO && range_type != RANGE_COMBAT) { if ((*i) == Pi::player->GetCombatTarget()) { 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: // XXX could maybe add orbital stations if (m_mode == SCANNER_MODE_AUTO && range_type != RANGE_NAV && range_type != RANGE_COMBAT) { if ((*i) == Pi::player->GetNavTarget()) { 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() && m_manualRange > SCANNER_RANGE_MIN) { 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); } // range priority is combat target > ship/missile > nav target > other 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; }