2019-12-31 05:05:16 -08:00
// Copyright © 2008-2020 Pioneer Developers. See AUTHORS.txt for details
2012-09-15 17:59:15 -07:00
// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
2012-09-12 04:38:30 -07:00
2008-06-24 03:17:31 -07:00
# include "SpaceStation.h"
2019-02-03 04:27:34 -08:00
2019-10-16 12:10:22 -07:00
# include "Camera.h"
2012-11-17 17:56:43 -08:00
# include "CityOnPlanet.h"
2020-11-12 10:03:03 -08:00
# include "EnumStrings.h"
2008-12-27 17:02:45 -08:00
# include "Frame.h"
2012-11-17 17:56:43 -08:00
# include "Game.h"
2019-01-13 12:11:57 -08:00
# include "GameLog.h"
2019-01-02 08:59:07 -08:00
# include "GameSaveError.h"
2019-01-13 13:51:55 -08:00
# include "Json.h"
2012-11-17 17:56:43 -08:00
# include "Lang.h"
2019-10-16 12:10:22 -07:00
# include "NavLights.h"
2008-12-05 14:02:43 -08:00
# include "Pi.h"
2012-11-17 17:56:43 -08:00
# include "Planet.h"
2009-08-07 07:34:14 -07:00
# include "Player.h"
2012-11-17 17:56:43 -08:00
# include "Ship.h"
2010-03-16 09:51:50 -07:00
# include "Space.h"
2011-08-23 20:18:53 -07:00
# include "StringF.h"
2019-06-01 13:04:44 -07:00
# include "graphics/Renderer.h"
2020-01-20 15:13:45 -08:00
# include "lua/LuaEvent.h"
2019-02-15 15:05:44 -08:00
# include "scenegraph/Animation.h"
# include "scenegraph/MatrixTransform.h"
2014-01-26 13:39:09 -08:00
# include "scenegraph/ModelSkin.h"
2010-01-31 08:18:37 -08:00
2019-01-27 07:30:50 -08:00
SpaceStation : : SpaceStation ( const SystemBody * sbody ) :
ModelBody ( ) ,
m_type ( nullptr )
2015-02-16 15:47:01 -08:00
{
2019-01-27 07:30:50 -08:00
m_sbody = sbody ;
2015-02-16 15:47:01 -08:00
2019-01-27 07:30:50 -08:00
m_oldAngDisplacement = 0.0 ;
2015-02-16 15:47:01 -08:00
2019-01-27 07:30:50 -08:00
m_doorAnimationStep = m_doorAnimationState = 0.0 ;
2015-02-16 15:47:01 -08:00
2019-01-27 07:30:50 -08:00
InitStation ( ) ;
2015-02-16 15:47:01 -08:00
}
2019-01-27 07:30:50 -08:00
SpaceStation : : SpaceStation ( const Json & jsonObj , Space * space ) :
2019-02-02 09:48:25 -08:00
ModelBody ( jsonObj , space ) ,
2019-01-27 07:30:50 -08:00
m_type ( nullptr )
2015-02-16 15:47:01 -08:00
{
2015-06-07 10:50:23 -07:00
GetModel ( ) - > SetLabel ( GetLabel ( ) ) ;
2015-02-16 15:47:01 -08:00
2018-10-11 08:10:23 -07:00
try {
Json spaceStationObj = jsonObj [ " space_station " ] ;
2015-02-16 15:47:01 -08:00
2018-10-11 08:10:23 -07:00
m_oldAngDisplacement = 0.0 ;
2015-02-16 15:47:01 -08:00
2018-10-11 08:10:23 -07:00
Json shipDockingArray = spaceStationObj [ " ship_docking " ] . get < Json : : array_t > ( ) ;
m_shipDocking . reserve ( shipDockingArray . size ( ) ) ;
2019-01-02 08:59:07 -08:00
for ( Uint32 i = 0 ; i < shipDockingArray . size ( ) ; i + + ) {
2018-10-11 08:10:23 -07:00
m_shipDocking . push_back ( shipDocking_t ( ) ) ;
shipDocking_t & sd = m_shipDocking . back ( ) ;
Json shipDockingArrayEl = shipDockingArray [ i ] ;
2019-01-02 08:59:07 -08:00
if ( shipDockingArrayEl . count ( " index_for_body " ) )
2018-10-11 08:10:23 -07:00
sd . shipIndex = shipDockingArrayEl [ " index_for_body " ] ;
2019-01-02 08:59:07 -08:00
if ( shipDockingArrayEl . count ( " stage " ) )
2018-10-11 08:10:23 -07:00
sd . stage = shipDockingArrayEl [ " stage " ] ;
2019-01-02 08:59:07 -08:00
if ( shipDockingArrayEl . count ( " stage_pos " ) )
2018-10-11 08:10:23 -07:00
sd . stagePos = shipDockingArrayEl [ " stage_pos " ] ; // For some reason stagePos was saved as a float in pre-JSON system (saved & loaded as double here).
2019-01-02 08:59:07 -08:00
if ( shipDockingArrayEl . count ( " from_pos " ) )
2018-10-11 08:10:23 -07:00
sd . fromPos = shipDockingArrayEl [ " from_pos " ] ;
2019-01-02 08:59:07 -08:00
if ( shipDockingArrayEl . count ( " from_rot " ) )
2018-10-11 08:10:23 -07:00
sd . fromRot = shipDockingArrayEl [ " from_rot " ] ;
}
2015-02-16 15:47:01 -08:00
2018-10-11 08:10:23 -07:00
// retrieve each of the port details and bay IDs
Json portArray = spaceStationObj [ " ports " ] . get < Json : : array_t > ( ) ;
m_ports . reserve ( portArray . size ( ) ) ;
2019-01-02 08:59:07 -08:00
for ( Uint32 i = 0 ; i < portArray . size ( ) ; i + + ) {
2018-10-11 08:10:23 -07:00
m_ports . push_back ( SpaceStationType : : SPort ( ) ) ;
SpaceStationType : : SPort & port = m_ports . back ( ) ;
2015-02-16 15:47:01 -08:00
2018-10-11 08:10:23 -07:00
Json portArrayEl = portArray [ i ] ;
if ( portArrayEl [ " in_use " ] . is_boolean ( ) )
port . inUse = portArrayEl [ " in_use " ] ;
}
2015-02-16 15:47:01 -08:00
2018-10-11 08:10:23 -07:00
m_sbody = space - > GetSystemBodyByIndex ( spaceStationObj [ " index_for_system_body " ] ) ;
2015-02-16 15:47:01 -08:00
2018-10-11 08:10:23 -07:00
m_doorAnimationStep = spaceStationObj [ " door_animation_step " ] ;
m_doorAnimationState = spaceStationObj [ " door_animation_state " ] ;
2015-02-16 15:47:01 -08:00
2018-10-11 08:10:23 -07:00
InitStation ( ) ;
2015-02-16 15:47:01 -08:00
2018-10-11 08:10:23 -07:00
m_navLights - > LoadFromJson ( spaceStationObj ) ;
2018-10-17 13:38:23 -07:00
} catch ( Json : : type_error & ) {
2018-10-11 08:10:23 -07:00
throw SavedGameCorruptException ( ) ;
}
2015-02-16 15:47:01 -08:00
}
2019-01-27 07:30:50 -08:00
void SpaceStation : : Init ( )
2009-08-02 05:40:09 -07:00
{
2019-01-27 07:30:50 -08:00
SpaceStationType : : Init ( ) ;
2009-08-02 05:40:09 -07:00
}
2019-01-27 07:30:50 -08:00
void SpaceStation : : SaveToJson ( Json & jsonObj , Space * space )
2008-06-24 03:17:31 -07:00
{
2019-01-27 07:30:50 -08:00
ModelBody : : SaveToJson ( jsonObj , space ) ;
2011-11-08 13:39:53 -08:00
2019-01-27 07:30:50 -08:00
Json spaceStationObj ( { } ) ; // Create JSON object to contain space station data.
2011-10-12 19:18:46 -07:00
2019-01-27 07:30:50 -08:00
Json shipDockingArray = Json : : array ( ) ; // Create JSON array to contain ship docking data.
for ( Uint32 i = 0 ; i < m_shipDocking . size ( ) ; i + + ) {
Json shipDockingArrayEl ( { } ) ; // Create JSON object to contain ship docking.
Uint32 bodyIndex = space - > GetIndexForBody ( m_shipDocking [ i ] . ship ) ;
if ( bodyIndex ! = 0 ) {
shipDockingArrayEl [ " index_for_body " ] = bodyIndex ;
shipDockingArrayEl [ " stage " ] = m_shipDocking [ i ] . stage ;
shipDockingArrayEl [ " stage_pos " ] = m_shipDocking [ i ] . stagePos ; // stagePos is a double but was saved as a float in pre-JSON system for some reason (saved as double here).
shipDockingArrayEl [ " from_pos " ] = m_shipDocking [ i ] . fromPos ;
shipDockingArrayEl [ " from_rot " ] = m_shipDocking [ i ] . fromRot ;
}
shipDockingArray . push_back ( shipDockingArrayEl ) ; // Append ship docking object to array.
}
spaceStationObj [ " ship_docking " ] = shipDockingArray ; // Add ship docking array to space station object.
2013-05-02 04:05:14 -07:00
2019-01-27 07:30:50 -08:00
// store each of the port details and bay IDs
Json portArray = Json : : array ( ) ; // Create JSON array to contain port data.
for ( Uint32 i = 0 ; i < m_ports . size ( ) ; i + + ) {
Json portArrayEl ( { } ) ; // Create JSON object to contain port.
if ( m_ports [ i ] . inUse )
portArrayEl [ " in_use " ] = m_ports [ i ] . inUse ;
portArray . push_back ( portArrayEl ) ; // Append port object to array.
}
spaceStationObj [ " ports " ] = portArray ; // Add port array to space station object.
spaceStationObj [ " index_for_system_body " ] = space - > GetIndexForSystemBody ( m_sbody ) ;
spaceStationObj [ " door_animation_step " ] = m_doorAnimationStep ;
spaceStationObj [ " door_animation_state " ] = m_doorAnimationState ;
m_navLights - > SaveToJson ( spaceStationObj ) ;
jsonObj [ " space_station " ] = spaceStationObj ; // Add space station object to supplied object.
}
void SpaceStation : : PostLoadFixup ( Space * space )
{
ModelBody : : PostLoadFixup ( space ) ;
for ( Uint32 i = 0 ; i < m_shipDocking . size ( ) ; i + + ) {
m_shipDocking [ i ] . ship = static_cast < Ship * > ( space - > GetBodyByIndex ( m_shipDocking [ i ] . shipIndex ) ) ;
}
2008-09-18 19:23:48 -07:00
}
2010-01-17 12:25:52 -08:00
void SpaceStation : : InitStation ( )
2008-09-18 19:23:48 -07:00
{
2009-07-27 04:28:05 -07:00
m_adjacentCity = 0 ;
2019-01-02 08:59:07 -08:00
for ( int i = 0 ; i < NUM_STATIC_SLOTS ; i + + )
m_staticSlot [ i ] = false ;
2014-02-20 13:40:31 -08:00
Random rand ( m_sbody - > GetSeed ( ) ) ;
2014-11-20 11:26:57 -08:00
const bool ground = m_sbody - > GetType ( ) = = SystemBody : : TYPE_STARPORT_ORBITAL ? false : true ;
2017-04-26 04:34:46 -07:00
const std : : string & space_station_type = m_sbody - > GetSpaceStationType ( ) ;
2019-01-02 08:59:07 -08:00
if ( space_station_type ! = " " ) {
2017-04-26 04:34:46 -07:00
m_type = SpaceStationType : : FindByName ( space_station_type ) ;
2019-01-02 08:59:07 -08:00
if ( m_type = = nullptr )
2017-04-26 04:34:46 -07:00
Output ( " WARNING: SpaceStation::InitStation wants to initialize a custom station of type %s, but no station type with that id has been found. \n " , space_station_type . c_str ( ) ) ;
}
2019-01-02 08:59:07 -08:00
if ( m_type = = nullptr )
2017-04-26 04:34:46 -07:00
m_type = SpaceStationType : : RandomStationType ( rand , ground ) ;
2013-01-24 14:02:01 -08:00
2019-01-02 08:59:07 -08:00
if ( m_shipDocking . empty ( ) ) {
2014-11-20 11:26:57 -08:00
m_shipDocking . reserve ( m_type - > NumDockingPorts ( ) ) ;
2019-01-02 08:59:07 -08:00
for ( unsigned int i = 0 ; i < m_type - > NumDockingPorts ( ) ; i + + ) {
2013-05-14 14:58:05 -07:00
m_shipDocking . push_back ( shipDocking_t ( ) ) ;
}
// only (re)set these if we've not come from the ::Load method
m_doorAnimationStep = m_doorAnimationState = 0.0 ;
}
2014-11-20 11:26:57 -08:00
assert ( m_shipDocking . size ( ) = = m_type - > NumDockingPorts ( ) ) ;
2012-07-20 02:41:05 -07:00
2014-09-06 07:29:23 -07:00
// This SpaceStation's bay ports are an instance of...
2019-01-02 08:59:07 -08:00
if ( m_ports . size ( ) ! = m_type - > Ports ( ) . size ( ) ) {
2018-09-22 07:35:06 -07:00
m_ports = m_type - > Ports ( ) ;
2019-01-02 08:59:07 -08:00
} else {
2018-09-22 07:35:06 -07:00
// since we might have loaded from JSON we've got a little bit of useful info in m_ports already
// backup the current data
auto backup = m_ports ;
// clear it all to default
m_ports = m_type - > Ports ( ) ;
// now restore the "inUse" variable only since it's the only bit that might have changed
2020-04-28 12:41:39 -07:00
for ( size_t p = 0 ; p < m_ports . size ( ) ; p + + ) {
2018-09-22 07:35:06 -07:00
m_ports [ p ] . inUse = backup [ p ] . inUse ;
}
}
2012-07-20 02:41:05 -07:00
2019-01-02 08:59:07 -08:00
SetStatic ( ground ) ; // orbital stations are dynamic now
2013-02-08 13:59:03 -08:00
2013-05-14 14:58:05 -07:00
// XXX hack. if we loaded a game then ModelBody::Load already restored the
// model and we shouldn't overwrite it
if ( ! GetModel ( ) )
2014-11-20 11:26:57 -08:00
SetModel ( m_type - > ModelName ( ) . c_str ( ) ) ;
2012-11-25 19:05:43 -08:00
2014-01-26 13:38:24 -08:00
SceneGraph : : Model * model = GetModel ( ) ;
m_navLights . reset ( new NavLights ( model , 2.2f ) ) ;
2013-02-16 08:36:19 -08:00
m_navLights - > SetEnabled ( true ) ;
2020-11-11 16:33:04 -08:00
if ( ground ) SetClipRadius ( CityOnPlanet : : RADIUS ) ; // overrides setmodel
2013-02-18 23:45:58 -08:00
2014-01-26 13:38:24 -08:00
m_doorAnimation = model - > FindAnimation ( " doors " ) ;
2014-01-26 13:39:09 -08:00
SceneGraph : : ModelSkin skin ;
skin . SetDecal ( " pioneer " ) ;
2017-01-05 11:39:14 -08:00
2016-09-21 03:52:24 -07:00
skin . SetRandomColors ( rand ) ;
skin . Apply ( model ) ;
2014-09-05 10:36:12 -07:00
if ( model - > SupportsPatterns ( ) ) {
2019-01-02 08:59:07 -08:00
model - > SetPattern ( rand . Int32 ( 0 , model - > GetNumPatterns ( ) - 1 ) ) ;
2014-09-05 10:36:12 -07:00
}
2008-06-24 03:17:31 -07:00
}
SpaceStation : : ~ SpaceStation ( )
{
2009-07-27 04:28:05 -07:00
if ( m_adjacentCity ) delete m_adjacentCity ;
2008-06-24 03:17:31 -07:00
}
2019-01-02 08:59:07 -08:00
void SpaceStation : : NotifyRemoved ( const Body * const removedBody )
2012-11-18 21:25:00 -08:00
{
2019-01-02 08:59:07 -08:00
for ( Uint32 i = 0 ; i < m_shipDocking . size ( ) ; i + + ) {
2012-11-18 21:25:00 -08:00
if ( m_shipDocking [ i ] . ship = = removedBody ) {
m_shipDocking [ i ] . ship = 0 ;
}
}
}
int SpaceStation : : GetMyDockingPort ( const Ship * s ) const
{
2019-01-02 08:59:07 -08:00
for ( Uint32 i = 0 ; i < m_shipDocking . size ( ) ; i + + ) {
2012-11-18 21:25:00 -08:00
if ( s = = m_shipDocking [ i ] . ship ) return i ;
}
return - 1 ;
}
2013-11-08 14:45:38 -08:00
int SpaceStation : : NumShipsDocked ( ) const
{
Sint32 numShipsDocked = 0 ;
2019-01-02 08:59:07 -08:00
for ( Uint32 i = 0 ; i < m_shipDocking . size ( ) ; i + + ) {
2014-07-03 20:52:34 -07:00
if ( NULL ! = m_shipDocking [ i ] . ship )
2013-11-08 14:45:38 -08:00
+ + numShipsDocked ;
}
return numShipsDocked ;
}
int SpaceStation : : GetFreeDockingPort ( const Ship * s ) const
2012-11-18 21:25:00 -08:00
{
2013-11-18 10:55:41 -08:00
assert ( s ) ;
2019-01-02 08:59:07 -08:00
for ( unsigned int i = 0 ; i < m_type - > NumDockingPorts ( ) ; i + + ) {
2015-04-23 13:23:16 -07:00
if ( m_shipDocking [ i ] . ship = = nullptr ) {
2013-11-18 10:55:41 -08:00
// size-of-ship vs size-of-bay check
2014-09-06 07:29:23 -07:00
const SpaceStationType : : SPort * const pPort = m_type - > FindPortByBay ( i ) ;
2019-01-02 08:59:07 -08:00
if ( ! pPort ) continue ;
2013-11-18 10:55:41 -08:00
const Aabb & bbox = s - > GetAabb ( ) ;
const double bboxRad = bbox . GetRadius ( ) ;
2019-01-02 08:59:07 -08:00
if ( pPort - > minShipSize < bboxRad & & bboxRad < pPort - > maxShipSize ) {
2013-11-08 14:45:38 -08:00
return i ;
}
2012-11-18 21:25:00 -08:00
}
}
return - 1 ;
}
2014-07-20 07:19:18 -07:00
void SpaceStation : : SetDocked ( Ship * ship , const int port )
2012-11-18 21:25:00 -08:00
{
2014-07-20 07:19:18 -07:00
assert ( m_shipDocking . size ( ) > Uint32 ( port ) ) ;
2012-11-18 21:25:00 -08:00
m_shipDocking [ port ] . ship = ship ;
2019-01-02 08:59:07 -08:00
m_shipDocking [ port ] . stage = m_type - > NumDockingStages ( ) + 3 ;
2012-11-18 21:25:00 -08:00
// have to do this crap again in case it was called directly (Ship::SetDockWith())
ship - > SetFlightState ( Ship : : DOCKED ) ;
ship - > SetVelocity ( vector3d ( 0.0 ) ) ;
ship - > SetAngVelocity ( vector3d ( 0.0 ) ) ;
2012-12-15 16:22:24 -08:00
PositionDockedShip ( ship , port ) ;
2012-11-18 21:25:00 -08:00
}
2013-11-18 10:55:41 -08:00
void SpaceStation : : SwapDockedShipsPort ( const int oldPort , const int newPort )
2013-11-08 14:45:38 -08:00
{
2019-01-02 08:59:07 -08:00
if ( oldPort = = newPort )
2013-11-08 14:45:38 -08:00
return ;
// set new location
2013-11-18 10:55:41 -08:00
Ship * ship = m_shipDocking [ oldPort ] . ship ;
assert ( ship ) ;
2013-11-08 14:45:38 -08:00
ship - > SetDockedWith ( this , newPort ) ;
m_shipDocking [ oldPort ] . ship = 0 ;
m_shipDocking [ oldPort ] . stage = 0 ;
}
2014-07-20 07:19:18 -07:00
bool SpaceStation : : LaunchShip ( Ship * ship , const int port )
2012-11-18 21:25:00 -08:00
{
shipDocking_t & sd = m_shipDocking [ port ] ;
2020-07-06 20:01:30 -07:00
if ( sd . stage < 0 ) return true ; // already launching
2019-01-02 08:59:07 -08:00
if ( IsPortLocked ( port ) ) return false ; // another ship docking
2013-02-03 05:03:52 -08:00
LockPort ( port , true ) ;
2012-11-18 21:25:00 -08:00
sd . ship = ship ;
sd . stage = - 1 ;
2013-02-25 09:47:04 -08:00
sd . stagePos = 0.0 ;
2012-11-18 21:25:00 -08:00
2013-02-18 23:45:58 -08:00
m_doorAnimationStep = 0.3 ; // open door
2017-01-05 11:39:14 -08:00
const vector3d up = ship - > GetOrient ( ) . VectorY ( ) . Normalized ( ) * ship - > GetLandingPosOffset ( ) ;
2013-06-26 18:07:40 -07:00
2019-01-02 08:59:07 -08:00
sd . fromPos = ( ship - > GetPosition ( ) - GetPosition ( ) + up ) * GetOrient ( ) ; // station space
2017-01-05 11:39:14 -08:00
sd . fromRot = Quaterniond : : FromMatrix3x3 ( GetOrient ( ) . Transpose ( ) * ship - > GetOrient ( ) ) ;
2012-11-18 21:25:00 -08:00
2015-10-07 02:57:53 -07:00
ship - > SetFlightState ( Ship : : UNDOCKING ) ;
2013-02-18 23:45:58 -08:00
2012-11-18 21:25:00 -08:00
return true ;
}
2020-11-12 10:03:03 -08:00
// gets number of undocked ships within a given radius from the station
int SpaceStation : : GetNearbyTraffic ( double radius )
{
int shipsNearby = 0 ;
Space : : BodyNearList traffic = Pi : : game - > GetSpace ( ) - > GetBodiesMaybeNear ( this , radius ) ;
for ( Body * body : traffic ) {
2020-11-12 12:12:35 -08:00
if ( ! body - > IsType ( ObjectType : : SHIP ) ) continue ;
2020-11-12 10:03:03 -08:00
shipsNearby + + ;
}
return shipsNearby - NumShipsDocked ( ) ;
}
bool SpaceStation : : GetDockingClearance ( Ship * s )
2012-11-18 21:25:00 -08:00
{
2014-11-20 11:26:57 -08:00
assert ( m_shipDocking . size ( ) = = m_type - > NumDockingPorts ( ) ) ;
2019-01-02 08:59:07 -08:00
for ( Uint32 i = 0 ; i < m_shipDocking . size ( ) ; i + + ) {
2013-05-02 04:12:49 -07:00
if ( m_shipDocking [ i ] . ship = = s ) {
2020-11-12 10:03:03 -08:00
LuaEvent : : Queue ( " onDockingClearanceDenied " , this , s ,
EnumStrings : : GetString ( " DockingRefusedReason " , int ( DockingRefusedReason : : ClearanceAlreadyGranted ) ) ) ;
2013-05-02 04:12:49 -07:00
return ( m_shipDocking [ i ] . stage > 0 ) ; // grant docking only if the ship is not already docked/undocking
2012-11-18 21:25:00 -08:00
}
}
2014-12-29 07:54:01 -08:00
const Aabb & bbox = s - > GetAabb ( ) ;
2019-01-02 08:59:07 -08:00
const float bboxRad = vector2f ( float ( bbox . max . x ) , float ( bbox . max . z ) ) . Length ( ) ;
2014-12-29 07:54:01 -08:00
2019-01-02 08:59:07 -08:00
for ( Uint32 i = 0 ; i < m_shipDocking . size ( ) ; i + + ) {
2013-05-14 14:58:05 -07:00
// initial unoccupied check
2012-11-18 21:25:00 -08:00
if ( m_shipDocking [ i ] . ship ! = 0 ) continue ;
2013-05-14 14:58:05 -07:00
// size-of-ship vs size-of-bay check
2014-09-06 07:29:23 -07:00
const SpaceStationType : : SPort * const pPort = m_type - > FindPortByBay ( i ) ;
2019-01-02 08:59:07 -08:00
if ( ! pPort ) continue ;
2013-05-14 14:58:05 -07:00
2018-07-09 05:56:07 -07:00
// distance-to-station check
const double shipDist = s - > GetPositionRelTo ( this ) . Length ( ) ;
double requestDist = 100000.0 ; //100km
2020-11-11 16:33:04 -08:00
if ( s - > IsType ( ObjectType : : PLAYER ) & & shipDist > requestDist ) {
2020-11-12 10:03:03 -08:00
LuaEvent : : Queue ( " onDockingClearanceDenied " , this , s ,
EnumStrings : : GetString ( " DockingRefusedReason " , int ( DockingRefusedReason : : TooFarFromStation ) ) ) ;
2018-07-09 05:56:07 -07:00
return false ;
}
2019-01-02 08:59:07 -08:00
if ( pPort - > minShipSize < bboxRad & & bboxRad < pPort - > maxShipSize ) {
2013-05-14 14:58:05 -07:00
shipDocking_t & sd = m_shipDocking [ i ] ;
sd . ship = s ;
sd . stage = 1 ;
sd . stagePos = 0 ;
2017-02-08 16:39:32 -08:00
// Note: maxOffset is squared
2019-01-02 08:59:07 -08:00
sd . maxOffset = std : : max ( ( pPort - > maxShipSize / 2 - bboxRad ) , float ( pPort - > maxShipSize / 5.0 ) ) ;
2017-02-08 16:39:32 -08:00
sd . maxOffset * = sd . maxOffset ;
2020-11-12 10:03:03 -08:00
LuaEvent : : Queue ( " onDockingClearanceGranted " , this , s ) ;
2013-05-14 14:58:05 -07:00
return true ;
}
2012-11-18 21:25:00 -08:00
}
2020-11-12 10:03:03 -08:00
LuaEvent : : Queue ( " onDockingClearanceDenied " , this , s ,
EnumStrings : : GetString ( " DockingRefusedReason " , int ( DockingRefusedReason : : NoBaysAvailable ) ) ) ;
2012-11-18 21:25:00 -08:00
return false ;
}
2020-11-11 16:33:04 -08:00
bool SpaceStation : : OnCollision ( Body * b , Uint32 flags , double relVel )
2012-11-18 21:25:00 -08:00
{
2020-11-11 16:33:04 -08:00
if ( ( flags & 0x10 ) & & ( b - > IsType ( ObjectType : : SHIP ) ) ) {
2019-01-02 08:59:07 -08:00
Ship * s = static_cast < Ship * > ( b ) ;
2012-11-18 21:25:00 -08:00
int port = - 1 ;
2019-01-02 08:59:07 -08:00
for ( Uint32 i = 0 ; i < m_shipDocking . size ( ) ; i + + ) {
if ( m_shipDocking [ i ] . ship = = s ) {
port = i ;
break ;
}
2012-11-18 21:25:00 -08:00
}
2017-02-06 13:46:58 -08:00
if ( port = = - 1 ) {
2017-04-29 04:57:30 -07:00
if ( IsGroundStation ( ) ) {
2019-01-02 08:59:07 -08:00
return DoShipDamage ( s , flags , relVel ) ; // no permission
} else
return false ;
2017-02-06 13:46:58 -08:00
}
2013-03-12 12:15:51 -07:00
if ( IsPortLocked ( port ) ) {
2017-02-06 13:46:58 -08:00
return DoShipDamage ( s , flags , relVel ) ;
2012-11-18 21:25:00 -08:00
}
2019-01-02 08:59:07 -08:00
if ( m_shipDocking [ port ] . stage ! = 1 ) return DoShipDamage ( s , flags , relVel ) ; // already docking?
2012-11-18 21:25:00 -08:00
SpaceStationType : : positionOrient_t dport ;
if ( IsGroundStation ( ) ) {
2017-01-05 11:39:14 -08:00
// must be oriented sensibly and have wheels down
PiVerify ( m_type - > GetDockAnimPositionOrient ( port , m_type - > NumDockingStages ( ) , 1.0f , vector3d ( 0.0 ) , dport , s ) ) ;
2019-01-02 08:59:07 -08:00
vector3d dockingNormal = GetOrient ( ) * dport . yaxis ;
2012-11-18 21:25:00 -08:00
const double dot = s - > GetOrient ( ) . VectorY ( ) . Dot ( dockingNormal ) ;
2019-01-02 08:59:07 -08:00
if ( ( dot < 0.99 ) | | ( s - > GetWheelState ( ) < 1.0 ) ) return DoShipDamage ( s , flags , relVel ) ; // <0.99 harsh?
2017-01-05 11:39:14 -08:00
// check speed
2017-02-06 13:46:58 -08:00
if ( s - > GetVelocity ( ) . Length ( ) > MAX_LANDING_SPEED ) return DoShipDamage ( s , flags , relVel ) ;
2017-01-05 11:39:14 -08:00
// check if you're near your pad
2019-01-02 08:59:07 -08:00
float dist = ( s - > GetPosition ( ) - GetPosition ( ) - GetOrient ( ) * dport . pos ) . LengthSqr ( ) ;
2017-02-08 16:39:32 -08:00
// docking allowed only if inside a circle 70% greater than pad itself (*1.7)
2019-01-02 08:59:07 -08:00
float maxDist = static_cast < float > ( m_type - > FindPortByBay ( port ) - > maxShipSize / 2 ) * 1.7 ;
if ( dist > ( maxDist * maxDist ) ) return DoShipDamage ( s , flags , relVel ) ;
2012-11-18 21:25:00 -08:00
}
2017-01-05 11:39:14 -08:00
// 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.0 , vector3d ( 0.0 ) , dport , s ) ) ;
2012-11-18 21:25:00 -08:00
// if there is more docking port anim to do, don't set docked yet
2014-11-20 11:26:57 -08:00
if ( m_type - > NumDockingStages ( ) > = 2 ) {
2012-11-18 21:25:00 -08:00
shipDocking_t & sd = m_shipDocking [ port ] ;
sd . ship = s ;
sd . stage = 2 ;
sd . stagePos = 0 ;
2019-01-02 08:59:07 -08:00
sd . fromPos = ( s - > GetPosition ( ) - GetPosition ( ) ) * GetOrient ( ) ; // station space
2012-11-18 21:25:00 -08:00
sd . fromRot = Quaterniond : : FromMatrix3x3 ( GetOrient ( ) . Transpose ( ) * s - > GetOrient ( ) ) ;
2013-02-03 05:03:52 -08:00
LockPort ( port , true ) ;
2012-11-18 21:25:00 -08:00
s - > SetFlightState ( Ship : : DOCKING ) ;
s - > SetVelocity ( vector3d ( 0.0 ) ) ;
s - > SetAngVelocity ( vector3d ( 0.0 ) ) ;
s - > ClearThrusterState ( ) ;
} else {
2019-01-02 08:59:07 -08:00
s - > SetDockedWith ( this , port ) ; // bounces back to SS::SetDocked()
2012-11-18 21:25:00 -08:00
LuaEvent : : Queue ( " onShipDocked " , s , this ) ;
}
2017-04-29 04:57:30 -07:00
// If this is reached, then you have permission
// to dock and a collision with docking surface
return false ;
2012-11-18 21:25:00 -08:00
} else {
return true ;
}
}
2019-01-02 08:59:07 -08:00
bool SpaceStation : : DoShipDamage ( Ship * s , Uint32 flags , double relVel )
{
if ( s = = nullptr ) return false ;
2017-02-06 13:46:58 -08:00
s - > DynamicBody : : OnCollision ( this , flags , relVel ) ;
return true ;
}
2013-02-18 23:45:58 -08:00
// XXX SGModel door animation. We have one station (hoop_spacestation) with a
// door, so this is pretty much based on how it does things. This all needs
// rewriting to handle triggering animations at waypoints.
//
// Docking:
// Stage 1 (clearance granted): open
// (clearance expired): close
// Docked: close
2013-06-26 18:07:40 -07:00
//
2013-02-18 23:45:58 -08:00
// Undocking:
// Stage -1 (LaunchShip): open
// Post-launch: close
2013-06-26 18:07:40 -07:00
//
2013-02-18 23:45:58 -08:00
2012-11-18 21:25:00 -08:00
void SpaceStation : : DockingUpdate ( const double timeStep )
2009-08-02 05:40:09 -07:00
{
2019-01-02 08:59:07 -08:00
for ( Uint32 i = 0 ; i < m_shipDocking . size ( ) ; i + + ) {
2009-08-02 05:40:09 -07:00
shipDocking_t & dt = m_shipDocking [ i ] ;
2010-02-01 12:13:52 -08:00
if ( ! dt . ship ) continue ;
2017-01-05 11:39:14 -08:00
if ( dt . stage > m_type - > NumDockingStages ( ) ) {
int extraStage = dt . stage - m_type - > NumDockingStages ( ) ;
SpaceStationType : : positionOrient_t dport ;
float dist = 0.0 ;
2019-01-02 08:59:07 -08:00
switch ( extraStage ) {
case 1 : // Level ship & Reposition eval
// PS: This is to avoid to float around if dock
// at high time steps on an orbital
if ( ! IsGroundStation ( ) ) {
2020-07-06 20:01:30 -07:00
dt . fromPos = vector3d ( 0.0 ) ; //No offset
2019-01-02 08:59:07 -08:00
dt . fromRot = Quaterniond ( 1.0 , 0.0 , 0.0 , 0.0 ) ; //Identity (no rotation)
dt . stage + = 2 ;
2017-01-05 11:39:14 -08:00
continue ;
2019-01-02 08:59:07 -08:00
}
if ( ! LevelShip ( dt . ship , i , timeStep ) ) continue ;
PiVerify ( m_type - > GetDockAnimPositionOrient ( i , m_type - > NumDockingStages ( ) , 1.0f , dt . fromPos , dport , dt . ship ) ) ;
dist = ( dt . ship - > GetPosition ( ) - GetPosition ( ) - GetOrient ( ) * dport . pos ) . LengthSqr ( ) ;
if ( dist > dt . maxOffset ) {
// Reposition needed
dt . fromPos = dt . ship - > GetPosition ( ) ;
matrix3x3d padOrient = matrix3x3d : : FromVectors ( dport . xaxis , dport . yaxis , dport . zaxis ) ;
dt . fromRot = Quaterniond : : FromMatrix3x3 ( ( GetOrient ( ) * padOrient ) . Transpose ( ) * dt . ship - > GetOrient ( ) ) ;
2017-01-05 11:39:14 -08:00
dt . stage + + ;
2019-01-02 08:59:07 -08:00
dt . stagePos = 0.0 ;
} else {
// Save ship position
dt . fromPos = ( dt . ship - > GetPosition ( ) - GetPosition ( ) - GetOrient ( ) * dport . pos ) * GetOrient ( ) ;
matrix3x3d padOrient = matrix3x3d : : FromVectors ( dport . xaxis , dport . yaxis , dport . zaxis ) ;
dt . fromRot = Quaterniond : : FromMatrix3x3 ( ( GetOrient ( ) * padOrient ) . Transpose ( ) * dt . ship - > GetOrient ( ) ) ;
dt . stage + = 2 ;
}
continue ;
case 2 : // Reposition stage
dt . stagePos + = timeStep / 2.0 ;
if ( dt . stagePos > = 1.0 ) {
dt . stage + + ;
2020-07-06 20:01:30 -07:00
dt . fromPos = vector3d ( 0.0 ) ; //No offset
2019-01-02 08:59:07 -08:00
dt . fromRot = Quaterniond ( 1.0 , 0.0 , 0.0 , 0.0 ) ; //Identity (no rotation)
}
continue ;
case 3 : // Just docked
dt . ship - > SetDockedWith ( this , i ) ;
LuaEvent : : Queue ( " onShipDocked " , dt . ship , this ) ;
if ( dt . fromPos . LengthSqr ( ) > 0.5 ) LuaEvent : : Queue ( " onShipBadDocked " , dt . ship , this ) ;
LockPort ( i , false ) ;
m_doorAnimationStep = - 0.3 ; // close door
dt . stage + + ;
continue ;
case 4 : // Docked
default : continue ;
2017-01-05 11:39:14 -08:00
}
}
2009-08-03 04:16:31 -07:00
2011-02-17 20:06:05 -08:00
double stageDuration = ( dt . stage > 0 ?
2019-01-02 08:59:07 -08:00
m_type - > GetDockAnimStageDuration ( dt . stage - 1 ) :
m_type - > GetUndockAnimStageDuration ( abs ( dt . stage ) - 1 ) ) ;
2010-02-01 12:13:52 -08:00
dt . stagePos + = timeStep / stageDuration ;
2009-08-06 08:00:08 -07:00
2010-02-01 12:13:52 -08:00
if ( dt . stage = = 1 ) {
2012-11-18 21:25:00 -08:00
// SPECIAL stage! Docking granted but waiting for ship to dock
2013-02-18 23:45:58 -08:00
m_doorAnimationStep = 0.3 ; // open door
2009-08-03 04:16:31 -07:00
if ( dt . stagePos > = 1.0 ) {
2020-11-12 10:03:03 -08:00
LuaEvent : : Queue ( " onDockingClearanceExpired " , this , dt . ship ) ;
2009-08-03 04:16:31 -07:00
dt . ship = 0 ;
2010-02-01 12:13:52 -08:00
dt . stage = 0 ;
2013-02-18 23:45:58 -08:00
m_doorAnimationStep = - 0.3 ; // close door
2009-08-03 04:16:31 -07:00
}
2010-02-01 12:13:52 -08:00
continue ;
}
2012-07-04 12:13:48 -07:00
2011-02-17 20:06:05 -08:00
if ( dt . stagePos > 1.0 ) {
2012-12-30 13:52:40 -08:00
// use end position of last segment for start position of new segment
SpaceStationType : : positionOrient_t dport ;
PiVerify ( m_type - > GetDockAnimPositionOrient ( i , dt . stage , 1.0f , dt . fromPos , dport , dt . ship ) ) ;
2013-01-28 08:16:16 -08:00
matrix3x3d fromRot = matrix3x3d : : FromVectors ( dport . xaxis , dport . yaxis , dport . zaxis ) ;
2012-12-30 13:52:40 -08:00
dt . fromRot = Quaterniond : : FromMatrix3x3 ( fromRot ) ;
dt . fromPos = dport . pos ;
2012-11-18 21:25:00 -08:00
// transition between docking stages
2010-02-01 12:13:52 -08:00
dt . stagePos = 0 ;
2019-01-02 08:59:07 -08:00
if ( dt . stage > = 0 )
dt . stage + + ;
else
dt . stage - - ;
2010-02-01 12:13:52 -08:00
}
2009-08-06 04:19:22 -07:00
2014-11-20 11:26:57 -08:00
if ( dt . stage < - m_type - > ShipLaunchStage ( ) & & dt . ship - > GetFlightState ( ) ! = Ship : : FLYING ) {
2012-11-18 21:25:00 -08:00
// launch ship
dt . ship - > SetFlightState ( Ship : : FLYING ) ;
2012-12-08 17:07:16 -08:00
dt . ship - > SetAngVelocity ( GetAngVelocity ( ) ) ;
2014-11-20 11:26:57 -08:00
if ( m_type - > IsSurfaceStation ( ) ) {
2019-01-02 08:59:07 -08:00
dt . ship - > SetThrusterState ( 1 , 1.0 ) ; // up
2010-02-01 12:13:52 -08:00
} else {
2019-01-02 08:59:07 -08:00
dt . ship - > SetThrusterState ( 2 , - 1.0 ) ; // forward
2009-08-02 05:40:09 -07:00
}
2012-11-18 21:25:00 -08:00
LuaEvent : : Queue ( " onShipUndocked " , dt . ship , this ) ;
2010-02-01 12:13:52 -08:00
}
2014-11-20 11:26:57 -08:00
if ( dt . stage < - m_type - > NumUndockStages ( ) ) {
2012-11-18 21:25:00 -08:00
// undock animation finished, clear port
dt . stage = 0 ;
2017-01-05 11:39:14 -08:00
dt . ship = nullptr ;
dt . stagePos = 0 ;
dt . maxOffset = 0 ;
2013-02-03 05:03:52 -08:00
LockPort ( i , false ) ;
2013-02-18 23:45:58 -08:00
m_doorAnimationStep = - 0.3 ; // close door
2009-08-02 05:40:09 -07:00
}
2010-01-12 10:42:51 -08:00
}
2013-06-26 18:07:40 -07:00
2019-01-02 08:59:07 -08:00
m_doorAnimationState = Clamp ( m_doorAnimationState + m_doorAnimationStep * timeStep , 0.0 , 1.0 ) ;
2013-02-18 23:45:58 -08:00
if ( m_doorAnimation )
m_doorAnimation - > SetProgress ( m_doorAnimationState ) ;
2009-08-02 05:40:09 -07:00
}
2017-01-05 11:39:14 -08:00
bool SpaceStation : : LevelShip ( Ship * ship , int port , const float timeStep ) const
2010-03-16 09:51:50 -07:00
{
2012-11-18 21:25:00 -08:00
const shipDocking_t & dt = m_shipDocking [ port ] ;
SpaceStationType : : positionOrient_t dport ;
PiVerify ( m_type - > GetDockAnimPositionOrient ( port , dt . stage , dt . stagePos , dt . fromPos , dport , ship ) ) ;
2017-01-05 11:39:14 -08:00
matrix3x3d shipOrient = ship - > GetOrient ( ) ;
2019-01-02 08:59:07 -08:00
vector3d dockingNormal = GetOrient ( ) * dport . yaxis ;
2017-01-05 11:39:14 -08:00
const vector3d & shipPos = ship - > GetPosition ( ) ;
2019-01-02 08:59:07 -08:00
vector3d dist = ( shipPos - GetPosition ( ) ) * GetOrient ( ) - dport . pos ;
2017-01-05 11:39:14 -08:00
2019-01-02 08:59:07 -08:00
double cosUp = dockingNormal . Dot ( shipOrient . VectorY ( ) ) ;
2017-01-05 11:39:14 -08:00
ship - > ClearThrusterState ( ) ;
2019-01-02 08:59:07 -08:00
if ( cosUp < 0.999999 ) {
2017-01-05 11:39:14 -08:00
// need level ship
double angle ;
2019-01-02 08:59:07 -08:00
if ( cosUp < 0.985 )
angle = - 0.8 * timeStep ;
else
angle = - acos ( cosUp ) ;
vector3d rotAxis = dockingNormal . Cross ( shipOrient . VectorY ( ) ) ;
2017-01-05 11:39:14 -08:00
rotAxis = rotAxis . NormalizedSafe ( ) ;
2019-01-02 08:59:07 -08:00
shipOrient = matrix3x3d : : Rotate ( angle , rotAxis ) * shipOrient ;
ship - > SetOrient ( shipOrient ) ;
2017-01-05 11:39:14 -08:00
}
2019-01-02 08:59:07 -08:00
if ( fabs ( dist . y ) > 0.01 ) {
2017-01-05 11:39:14 -08:00
vector3d inc ( 0.0 , - dist . y , 0.0 ) ;
2019-01-02 08:59:07 -08:00
inc = GetOrient ( ) * inc ;
ship - > SetPosition ( shipPos + inc ) ;
2017-01-05 11:39:14 -08:00
}
2019-01-02 08:59:07 -08:00
return ( cosUp > = 0.999999 ) & & ( fabs ( dist . y ) < 0.01 ) ;
2017-01-05 11:39:14 -08:00
}
2012-12-28 17:34:56 -08:00
2017-01-05 11:39:14 -08:00
void SpaceStation : : PositionDockingShip ( Ship * ship , int port ) const
{
const shipDocking_t & dt = m_shipDocking [ port ] ;
SpaceStationType : : positionOrient_t dport ;
PiVerify ( m_type - > GetDockAnimPositionOrient ( port , dt . stage , dt . stagePos , dt . fromPos , dport , ship ) ) ;
2019-01-02 08:59:07 -08:00
if ( dt . stage > m_type - > NumDockingStages ( ) ) {
if ( dt . stage = = m_type - > NumDockingStages ( ) + 1 ) {
2017-01-05 11:39:14 -08:00
// Leveling
return ;
2019-01-02 08:59:07 -08:00
} else if ( dt . stage = = m_type - > NumDockingStages ( ) + 2 ) {
2017-01-05 11:39:14 -08:00
// Repositioning
2019-01-02 08:59:07 -08:00
vector3d wantPos = GetPosition ( ) + GetOrient ( ) * dport . pos ;
ship - > SetPosition ( dt . fromPos - ( dt . fromPos - wantPos ) * dt . stagePos ) ;
2017-01-05 11:39:14 -08:00
}
2012-12-28 17:34:56 -08:00
} else {
2019-01-02 08:59:07 -08:00
ship - > SetPosition ( GetPosition ( ) + GetOrient ( ) * dport . pos ) ;
2010-03-16 09:51:50 -07:00
}
2017-01-05 11:39:14 -08:00
matrix3x3d wantRot = matrix3x3d : : FromVectors ( dport . xaxis , dport . yaxis , dport . zaxis ) ;
// use quaternion spherical linear interpolation to do
// rotation smoothly
Quaterniond wantQuat = Quaterniond : : FromMatrix3x3 ( wantRot ) ;
Quaterniond q = Quaterniond : : Nlerp ( dt . fromRot , wantQuat , dt . stagePos ) ;
wantRot = q . ToMatrix3x3 < double > ( ) ;
ship - > SetOrient ( GetOrient ( ) * wantRot ) ;
}
void SpaceStation : : PositionDockedShip ( Ship * ship , int port ) const
{
const shipDocking_t & dt = m_shipDocking [ port ] ;
SpaceStationType : : positionOrient_t dport ;
PiVerify ( m_type - > GetDockAnimPositionOrient ( port , dt . stage , dt . stagePos , dt . fromPos , dport , ship ) ) ;
assert ( dt . ship = = ship ) ;
2019-01-02 08:59:07 -08:00
ship - > SetPosition ( GetPosition ( ) + GetOrient ( ) * ( dport . pos + dt . fromPos ) ) ;
2017-01-05 11:39:14 -08:00
// Note: ship bounding box is used to generate dport.pos
Quaterniond dportQ = Quaterniond : : FromMatrix3x3 ( matrix3x3d : : FromVectors ( dport . xaxis , dport . yaxis , dport . zaxis ) ) ;
2019-01-02 08:59:07 -08:00
dportQ = dportQ * dt . fromRot ;
2017-01-05 11:39:14 -08:00
matrix3x3d shipRot = dportQ . ToMatrix3x3 < double > ( ) ;
2019-01-02 08:59:07 -08:00
ship - > SetOrient ( GetOrient ( ) * shipRot ) ;
2010-03-16 09:51:50 -07:00
}
2012-11-18 10:13:47 -08:00
void SpaceStation : : StaticUpdate ( const float timeStep )
2009-06-22 06:02:59 -07:00
{
2012-11-18 21:25:00 -08:00
DockingUpdate ( timeStep ) ;
2013-02-16 08:36:19 -08:00
m_navLights - > Update ( timeStep ) ;
2009-06-22 06:02:59 -07:00
}
2012-11-18 10:13:47 -08:00
void SpaceStation : : TimeStepUpdate ( const float timeStep )
{
2013-02-14 02:46:57 -08:00
// rotate the thing
2014-11-20 11:26:57 -08:00
double len = m_type - > AngVel ( ) * timeStep ;
2012-11-25 19:05:43 -08:00
if ( ! is_zero_exact ( len ) ) {
2019-01-02 08:59:07 -08:00
matrix3x3d r = matrix3x3d : : RotateY ( - len ) ; // RotateY is backwards
2012-11-18 10:13:47 -08:00
SetOrient ( r * GetOrient ( ) ) ;
}
2012-11-25 19:05:43 -08:00
m_oldAngDisplacement = len ;
2012-11-18 10:13:47 -08:00
2012-11-18 21:25:00 -08:00
// reposition the ships that are docked or docking here
2019-01-02 08:59:07 -08:00
for ( unsigned int i = 0 ; i < m_type - > NumDockingPorts ( ) ; i + + ) {
2012-11-18 21:25:00 -08:00
const shipDocking_t & dt = m_shipDocking [ i ] ;
2013-02-16 08:36:19 -08:00
if ( ! dt . ship ) { //free
2019-06-01 13:04:44 -07:00
m_navLights - > SetColor ( i + 1 , NavLights : : NAVLIGHT_OFF ) ;
continue ;
}
if ( dt . stage = = 1 ) { // reserved
2019-01-02 08:59:07 -08:00
m_navLights - > SetColor ( i + 1 , NavLights : : NAVLIGHT_GREEN ) ;
2019-06-01 13:04:44 -07:00
m_navLights - > SetMask ( i + 1 , 0x33 ) ; // 00110011 on two off two
2013-02-16 08:36:19 -08:00
continue ;
}
2019-06-01 13:04:44 -07:00
if ( dt . stage = = - 1 ) { // undocking anim
2019-01-02 08:59:07 -08:00
m_navLights - > SetColor ( i + 1 , NavLights : : NAVLIGHT_YELLOW ) ;
2013-04-27 14:13:34 -07:00
}
2019-06-01 13:04:44 -07:00
if ( dt . stage = = m_type - > NumDockingStages ( ) + 3 ) { // just docked
m_navLights - > SetColor ( i + 1 , NavLights : : NAVLIGHT_BLUE ) ;
m_navLights - > SetMask ( i + 1 , 0xf6 ) ; // 11110110
}
if ( dt . ship - > GetFlightState ( ) = = Ship : : DOCKED ) { //docked
2017-01-05 11:39:14 -08:00
PositionDockedShip ( dt . ship , i ) ;
2019-06-01 13:04:44 -07:00
} else if ( dt . ship - > GetFlightState ( ) = = Ship : : DOCKING | | dt . ship - > GetFlightState ( ) = = Ship : : UNDOCKING ) {
PositionDockingShip ( dt . ship , i ) ;
2017-01-05 11:39:14 -08:00
}
2009-10-01 08:42:49 -07:00
}
2013-02-18 23:45:58 -08:00
2013-10-20 13:55:15 -07:00
ModelBody : : TimeStepUpdate ( timeStep ) ;
2009-10-01 08:42:49 -07:00
}
2012-11-25 19:05:43 -08:00
void SpaceStation : : UpdateInterpTransform ( double alpha )
{
2019-01-02 08:59:07 -08:00
double len = m_oldAngDisplacement * ( 1.0 - alpha ) ;
2012-11-25 19:05:43 -08:00
if ( ! is_zero_exact ( len ) ) {
2019-01-02 08:59:07 -08:00
matrix3x3d rot = matrix3x3d : : RotateY ( len ) ; // RotateY is backwards
2012-11-25 19:05:43 -08:00
m_interpOrient = rot * GetOrient ( ) ;
2019-01-02 08:59:07 -08:00
} else
m_interpOrient = GetOrient ( ) ;
2012-11-25 19:05:43 -08:00
m_interpPos = GetPosition ( ) ;
}
2012-11-18 21:25:00 -08:00
bool SpaceStation : : IsGroundStation ( ) const
2009-10-01 08:42:49 -07:00
{
2014-11-20 11:26:57 -08:00
return m_type - > IsSurfaceStation ( ) ;
2008-09-07 16:32:16 -07:00
}
2012-07-23 10:51:51 -07:00
// Renders space station and adjacent city if applicable
// For orbital starports: renders as normal
2012-12-22 14:26:30 -08:00
// For surface starports:
2012-07-23 10:51:51 -07:00
// Lighting: Calculates available light for model and splits light between directly and ambiently lit
// Lighting is done by manipulating global lights or setting uniforms in atmospheric models shader
2013-06-26 18:07:40 -07:00
static const double SQRMAXCITYDIST = 1e5 * 1e5 ;
2012-07-24 22:51:17 -07:00
void SpaceStation : : Render ( Graphics : : Renderer * r , const Camera * camera , const vector3d & viewCoords , const matrix4x4d & viewTransform )
2008-06-24 03:17:31 -07:00
{
2019-10-07 09:12:28 -07:00
Body * b = Frame : : GetFrame ( GetFrame ( ) ) - > GetBody ( ) ;
2012-07-28 15:11:23 -07:00
assert ( b ) ;
2020-11-11 16:33:04 -08:00
if ( ! b - > IsType ( ObjectType : : PLANET ) ) {
2012-07-14 13:51:03 -07:00
// orbital spaceport -- don't make city turds or change lighting based on atmosphere
2013-03-13 21:05:31 -07:00
RenderModel ( r , camera , viewCoords , viewTransform ) ;
2016-11-21 03:56:15 -08:00
m_navLights - > Render ( r ) ;
2015-03-21 16:18:39 -07:00
r - > GetStats ( ) . AddToStatCount ( Graphics : : Stats : : STAT_SPACESTATIONS , 1 ) ;
2013-04-26 09:47:49 -07:00
} else {
// don't render city if too far away
2013-06-22 04:46:38 -07:00
if ( viewCoords . LengthSqr ( ) > = SQRMAXCITYDIST ) {
2013-04-26 09:47:49 -07:00
return ;
}
2013-03-16 20:34:55 -07:00
std : : vector < Graphics : : Light > oldLights ;
Color oldAmbient ;
2013-04-01 04:46:39 -07:00
SetLighting ( r , camera , oldLights , oldAmbient ) ;
2013-03-16 20:34:55 -07:00
2013-04-26 09:47:49 -07:00
if ( ! m_adjacentCity ) {
2019-01-02 08:59:07 -08:00
m_adjacentCity = new CityOnPlanet ( static_cast < Planet * > ( b ) , this , m_sbody - > GetSeed ( ) ) ;
2012-12-22 14:26:30 -08:00
}
2014-01-07 13:30:37 -08:00
m_adjacentCity - > Render ( r , camera - > GetContext ( ) - > GetFrustum ( ) , this , viewCoords , viewTransform ) ;
2012-07-09 06:47:47 -07:00
2013-03-16 20:34:55 -07:00
RenderModel ( r , camera , viewCoords , viewTransform , false ) ;
2016-09-14 14:45:16 -07:00
m_navLights - > Render ( r ) ;
2013-03-16 20:34:55 -07:00
ResetLighting ( r , oldLights , oldAmbient ) ;
2015-03-21 16:18:39 -07:00
r - > GetStats ( ) . AddToStatCount ( Graphics : : Stats : : STAT_GROUNDSTATIONS , 1 ) ;
2009-07-18 07:09:31 -07:00
}
2008-06-24 03:17:31 -07:00
}
2011-03-14 22:34:46 -07:00
2014-01-26 02:29:29 -08:00
void SpaceStation : : SetLabel ( const std : : string & label )
{
assert ( GetModel ( ) ) ;
GetModel ( ) - > SetLabel ( label ) ;
Body : : SetLabel ( label ) ;
}
2011-03-14 22:34:46 -07:00
// find an empty position for a static ship and mark it as used. these aren't
// saved and are only needed to help modules place bulk ships. this isn't a
// great place for this, but its gotta be tracked somewhere
2019-01-02 08:59:07 -08:00
bool SpaceStation : : AllocateStaticSlot ( int & slot )
2011-03-14 22:34:46 -07:00
{
2012-12-31 00:18:58 -08:00
// no slots at ground stations
if ( IsGroundStation ( ) )
return false ;
2019-01-02 08:59:07 -08:00
for ( int i = 0 ; i < NUM_STATIC_SLOTS ; i + + ) {
2011-03-14 22:34:46 -07:00
if ( ! m_staticSlot [ i ] ) {
m_staticSlot [ i ] = true ;
slot = i ;
return true ;
}
}
return false ;
}
2011-04-26 21:44:07 -07:00
2020-07-06 20:00:26 -07:00
vector3d SpaceStation : : GetTargetIndicatorPosition ( ) const
2011-12-02 08:10:21 -08:00
{
2012-05-10 18:37:49 -07:00
// return the next waypoint if permission has been granted for player,
// and the docking point's position once the docking anim starts
2019-01-02 08:59:07 -08:00
for ( Uint32 i = 0 ; i < m_shipDocking . size ( ) ; i + + ) {
2014-11-20 11:26:57 -08:00
if ( i > = m_type - > NumDockingPorts ( ) ) break ;
2017-04-19 01:58:49 -07:00
if ( ( m_shipDocking [ i ] . ship = = Pi : : player ) & & ( m_shipDocking [ i ] . stage > 0 ) & & ( m_shipDocking [ i ] . stage ! = m_type - > NumDockingStages ( ) + 1 ) ) { // last part is "not currently docked"
2011-12-02 08:10:21 -08:00
SpaceStationType : : positionOrient_t dport ;
2019-01-02 08:59:07 -08:00
if ( ! m_type - > GetShipApproachWaypoints ( i , m_shipDocking [ i ] . stage + 1 , dport ) )
2014-11-20 11:26:57 -08:00
PiVerify ( m_type - > GetDockAnimPositionOrient ( i , m_type - > NumDockingStages ( ) ,
2019-01-02 08:59:07 -08:00
1.0f , vector3d ( 0.0 ) , dport , m_shipDocking [ i ] . ship ) ) ;
2011-12-02 08:10:21 -08:00
2020-07-06 20:00:26 -07:00
return dport . pos ;
2011-12-02 08:10:21 -08:00
}
}
2020-07-06 20:00:26 -07:00
return Body : : GetTargetIndicatorPosition ( ) ;
2012-01-18 02:43:28 -08:00
}
2012-11-18 21:25:00 -08:00
2013-02-03 05:03:52 -08:00
bool SpaceStation : : IsPortLocked ( const int bay ) const
{
2019-01-02 08:59:07 -08:00
for ( auto & bayIter : m_ports ) {
for ( auto & idIter : bayIter . bayIDs ) {
if ( idIter . first = = bay ) {
2014-07-20 07:19:18 -07:00
return bayIter . inUse ;
2013-02-03 05:03:52 -08:00
}
}
}
2013-02-16 07:46:53 -08:00
// is it safer to return that the is loacked?
2013-02-03 05:03:52 -08:00
return true ;
}
void SpaceStation : : LockPort ( const int bay , const bool lockIt )
{
2019-01-02 08:59:07 -08:00
for ( auto & bayIter : m_ports ) {
for ( auto & idIter : bayIter . bayIDs ) {
if ( idIter . first = = bay ) {
2014-07-20 07:19:18 -07:00
bayIter . inUse = lockIt ;
2013-02-03 06:25:41 -08:00
return ;
2013-02-03 05:03:52 -08:00
}
}
}
}