2012-12-31 17:36:52 -08:00
// Copyright © 2008-2013 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"
2012-11-17 17:56:43 -08:00
# include "CityOnPlanet.h"
# include "FileSystem.h"
2008-12-27 17:02:45 -08:00
# include "Frame.h"
2012-11-17 17:56:43 -08:00
# include "Game.h"
# include "gameconsts.h"
# include "Lang.h"
# include "LmrModel.h"
# include "LuaEvent.h"
# include "LuaVector.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"
2009-10-08 16:49:43 -07:00
# include "Polit.h"
2010-03-16 09:51:50 -07:00
# include "Polit.h"
2012-11-17 17:56:43 -08:00
# include "Serializer.h"
# 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"
2012-11-17 17:56:43 -08:00
# include "galaxy/StarSystem.h"
2012-07-24 22:51:17 -07:00
# include "graphics/Graphics.h"
2012-11-17 17:56:43 -08:00
# include <algorithm>
2010-01-31 08:18:37 -08:00
2010-02-01 12:13:52 -08:00
# define ARG_STATION_BAY1_STAGE 6
# define ARG_STATION_BAY1_POS 10
2010-01-17 12:25:52 -08:00
/* Must be called after LmrModel init is called */
void SpaceStation : : Init ( )
2013-01-06 05:47:38 -08:00
{
2012-11-17 17:56:43 -08:00
SpaceStationType : : Init ( ) ;
2010-01-17 12:25:52 -08:00
}
2008-07-02 04:44:19 -07:00
2011-10-08 21:05:09 -07:00
void SpaceStation : : Uninit ( )
{
2012-11-17 17:56:43 -08:00
SpaceStationType : : Uninit ( ) ;
2011-10-08 21:05:09 -07:00
}
2011-11-17 21:41:00 -08:00
void SpaceStation : : Save ( Serializer : : Writer & wr , Space * space )
2008-09-18 19:23:48 -07:00
{
2011-11-17 21:41:00 -08:00
ModelBody : : Save ( wr , space ) ;
2010-05-22 10:26:25 -07:00
MarketAgent : : Save ( wr ) ;
2010-08-03 03:28:18 -07:00
wr . Int32 ( Equip : : TYPE_MAX ) ;
2008-12-05 14:02:43 -08:00
for ( int i = 0 ; i < Equip : : TYPE_MAX ; i + + ) {
2011-05-10 17:57:37 -07:00
wr . Int32 ( int ( m_equipmentStock [ i ] ) ) ;
2008-12-05 14:02:43 -08:00
}
2009-06-22 06:02:59 -07:00
// save shipyard
2010-05-22 10:26:25 -07:00
wr . Int32 ( m_shipsOnSale . size ( ) ) ;
2009-06-22 06:02:59 -07:00
for ( std : : vector < ShipFlavour > : : iterator i = m_shipsOnSale . begin ( ) ;
i ! = m_shipsOnSale . end ( ) ; + + i ) {
2010-05-22 10:26:25 -07:00
( * i ) . Save ( wr ) ;
2009-06-22 06:02:59 -07:00
}
2013-01-24 14:02:01 -08:00
wr . Int32 ( m_shipDocking . size ( ) ) ;
for ( uint32_t i = 0 ; i < m_shipDocking . size ( ) ; i + + ) {
2011-11-17 00:34:50 -08:00
wr . Int32 ( space - > GetIndexForBody ( m_shipDocking [ i ] . ship ) ) ;
2010-05-22 10:26:25 -07:00
wr . Int32 ( m_shipDocking [ i ] . stage ) ;
2011-05-10 17:57:37 -07:00
wr . Float ( float ( m_shipDocking [ i ] . stagePos ) ) ;
2010-05-22 10:26:25 -07:00
wr . Vector3d ( m_shipDocking [ i ] . fromPos ) ;
wr . WrQuaternionf ( m_shipDocking [ i ] . fromRot ) ;
2009-08-03 04:16:31 -07:00
2013-01-24 14:02:01 -08:00
wr . Float ( float ( m_shipDocking [ i ] . openAnimState ) ) ;
wr . Float ( float ( m_shipDocking [ i ] . dockAnimState ) ) ;
2009-08-02 05:40:09 -07:00
}
2013-02-03 05:03:52 -08:00
// store each of the bay groupings
wr . Int32 ( mBayGroups . size ( ) ) ;
for ( uint32_t i = 0 ; i < mBayGroups . size ( ) ; i + + ) {
wr . Int32 ( mBayGroups [ i ] . minShipSize ) ;
wr . Int32 ( mBayGroups [ i ] . maxShipSize ) ;
wr . Bool ( mBayGroups [ i ] . inUse ) ;
wr . Int32 ( mBayGroups [ i ] . bayIDs . size ( ) ) ;
for ( uint32_t j = 0 ; j < mBayGroups [ i ] . bayIDs . size ( ) ; j + + ) {
wr . Int32 ( mBayGroups [ i ] . bayIDs [ j ] ) ;
}
}
2012-11-18 21:25:00 -08:00
2012-02-24 14:37:57 -08:00
wr . Bool ( m_bbCreated ) ;
2010-05-22 10:26:25 -07:00
wr . Double ( m_lastUpdatedShipyard ) ;
2012-04-17 18:53:53 -07:00
wr . Int32 ( space - > GetIndexForSystemBody ( m_sbody ) ) ;
2010-05-22 10:26:25 -07:00
wr . Int32 ( m_numPoliceDocked ) ;
2008-09-18 19:23:48 -07:00
}
2011-11-17 13:38:06 -08:00
void SpaceStation : : Load ( Serializer : : Reader & rd , Space * space )
2008-09-18 19:23:48 -07:00
{
2011-11-17 13:38:06 -08:00
ModelBody : : Load ( rd , space ) ;
2010-05-22 10:26:25 -07:00
MarketAgent : : Load ( rd ) ;
2010-08-03 03:28:18 -07:00
int num = rd . Int32 ( ) ;
if ( num > Equip : : TYPE_MAX ) throw SavedGameCorruptException ( ) ;
2008-12-05 14:02:43 -08:00
for ( int i = 0 ; i < Equip : : TYPE_MAX ; i + + ) {
2010-08-03 03:28:18 -07:00
m_equipmentStock [ i ] = 0 ;
}
for ( int i = 0 ; i < num ; i + + ) {
2010-05-22 10:26:25 -07:00
m_equipmentStock [ i ] = static_cast < Equip : : Type > ( rd . Int32 ( ) ) ;
2008-12-05 14:02:43 -08:00
}
2009-06-22 06:02:59 -07:00
// load shityard
2010-05-22 10:26:25 -07:00
int numShipsForSale = rd . Int32 ( ) ;
2009-06-22 06:02:59 -07:00
for ( int i = 0 ; i < numShipsForSale ; i + + ) {
ShipFlavour s ;
2010-05-22 10:26:25 -07:00
s . Load ( rd ) ;
2009-06-22 06:02:59 -07:00
m_shipsOnSale . push_back ( s ) ;
}
2013-01-24 14:02:01 -08:00
const int32_t numShipDocking = rd . Int32 ( ) ;
m_shipDocking . reserve ( numShipDocking ) ;
for ( int i = 0 ; i < numShipDocking ; i + + ) {
m_shipDocking . push_back ( shipDocking_t ( ) ) ;
shipDocking_t & sd = m_shipDocking . back ( ) ;
sd . shipIndex = rd . Int32 ( ) ;
sd . stage = rd . Int32 ( ) ;
sd . stagePos = rd . Float ( ) ;
sd . fromPos = rd . Vector3d ( ) ;
sd . fromRot = rd . RdQuaternionf ( ) ;
2009-08-03 04:16:31 -07:00
2013-01-24 14:02:01 -08:00
sd . openAnimState = rd . Float ( ) ;
sd . dockAnimState = rd . Float ( ) ;
2009-08-02 05:40:09 -07:00
}
2013-02-03 05:03:52 -08:00
// retrieve each of the bay groupings
const int32_t numBays = rd . Int32 ( ) ;
mBayGroups . reserve ( numBays ) ;
for ( int32_t i = 0 ; i < numBays ; i + + ) {
mBayGroups . push_back ( SpaceStationType : : SBayGroup ( ) ) ;
SpaceStationType : : SBayGroup & bay = mBayGroups . back ( ) ;
bay . minShipSize = rd . Int32 ( ) ;
bay . maxShipSize = rd . Int32 ( ) ;
bay . inUse = rd . Bool ( ) ;
const int32_t numBayIds = rd . Int32 ( ) ;
bay . bayIDs . reserve ( numBayIds ) ;
for ( int32_t j = 0 ; j < numBayIds ; j + + ) {
const int32_t ID = rd . Int32 ( ) ;
bay . bayIDs . push_back ( ID ) ;
}
}
2012-11-18 21:25:00 -08:00
2012-02-24 14:37:57 -08:00
m_bbCreated = rd . Bool ( ) ;
2010-05-22 10:26:25 -07:00
m_lastUpdatedShipyard = rd . Double ( ) ;
2012-04-17 18:53:53 -07:00
m_sbody = space - > GetSystemBodyByIndex ( rd . Int32 ( ) ) ;
2010-08-03 03:28:18 -07:00
m_numPoliceDocked = rd . Int32 ( ) ;
2010-01-17 12:25:52 -08:00
InitStation ( ) ;
2008-09-18 19:23:48 -07:00
}
2011-11-17 13:38:06 -08:00
void SpaceStation : : PostLoadFixup ( Space * space )
2009-08-02 05:40:09 -07:00
{
2012-12-11 19:18:42 -08:00
ModelBody : : PostLoadFixup ( space ) ;
2013-01-24 14:02:01 -08:00
for ( uint32_t i = 0 ; i < m_shipDocking . size ( ) ; i + + ) {
2011-11-17 00:34:50 -08:00
m_shipDocking [ i ] . ship = static_cast < Ship * > ( space - > GetBodyByIndex ( m_shipDocking [ i ] . shipIndex ) ) ;
2009-08-02 05:40:09 -07:00
}
}
2012-04-17 18:53:53 -07:00
SpaceStation : : SpaceStation ( const SystemBody * sbody ) : ModelBody ( )
2008-06-24 03:17:31 -07:00
{
2009-07-02 04:39:14 -07:00
m_sbody = sbody ;
2009-06-22 06:02:59 -07:00
m_lastUpdatedShipyard = 0 ;
2010-03-16 09:51:50 -07:00
m_numPoliceDocked = Pi : : rng . Int32 ( 3 , 10 ) ;
2012-02-24 14:37:57 -08:00
m_bbCreated = false ;
2012-09-18 22:57:01 -07:00
m_bbShuffled = false ;
2011-11-08 13:39:53 -08:00
2012-11-25 19:05:43 -08:00
m_oldAngDisplacement = 0.0 ;
2011-10-12 19:18:46 -07:00
2008-12-29 12:51:06 -08:00
SetMoney ( 1000000000 ) ;
2010-01-17 12:25:52 -08:00
InitStation ( ) ;
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 ;
2012-07-22 07:44:30 -07:00
for ( int i = 0 ; i < NUM_STATIC_SLOTS ; i + + ) m_staticSlot [ i ] = false ;
2010-01-17 12:25:52 -08:00
MTRand rand ( m_sbody - > seed ) ;
2012-11-18 10:13:47 -08:00
bool ground = m_sbody - > type = = SystemBody : : TYPE_STARPORT_ORBITAL ? false : true ;
2013-01-24 14:02:01 -08:00
if ( ground ) {
m_type = & SpaceStationType : : surfaceStationTypes [ rand . Int32 ( SpaceStationType : : surfaceStationTypes . size ( ) ) ] ;
} else {
m_type = & SpaceStationType : : orbitalStationTypes [ rand . Int32 ( SpaceStationType : : orbitalStationTypes . size ( ) ) ] ;
}
for ( int i = 0 ; i < m_type - > numDockingPorts ; i + + ) {
m_shipDocking . push_back ( shipDocking_t ( ) ) ;
}
2012-07-20 02:41:05 -07:00
2013-02-03 05:03:52 -08:00
// This SpaceStation's bay groups is an instance of...
mBayGroups = m_type - > bayGroups ;
2012-07-20 02:41:05 -07:00
LmrObjParams & params = GetLmrObjParams ( ) ;
params . animStages [ ANIM_DOCKING_BAY_1 ] = 1 ;
params . animValues [ ANIM_DOCKING_BAY_1 ] = 1.0 ;
2011-10-19 08:55:21 -07:00
// XXX the animation namespace must match that in LuaConstants
2012-07-20 02:41:05 -07:00
params . animationNamespace = " SpaceStationAnimation " ;
2012-11-18 10:13:47 -08:00
SetStatic ( ground ) ; // orbital stations are dynamic now
2012-11-17 17:56:43 -08:00
SetModel ( m_type - > modelName . c_str ( ) ) ;
2012-11-25 19:05:43 -08:00
2012-11-26 15:40:03 -08:00
if ( ground ) SetClipRadius ( CITY_ON_PLANET_RADIUS ) ; // overrides setmodel
2008-06-24 03:17:31 -07:00
}
SpaceStation : : ~ SpaceStation ( )
{
2011-04-05 05:30:20 -07:00
onBulletinBoardDeleted . emit ( ) ;
2009-07-27 04:28:05 -07:00
if ( m_adjacentCity ) delete m_adjacentCity ;
2008-06-24 03:17:31 -07:00
}
2009-06-22 09:44:17 -07:00
void SpaceStation : : ReplaceShipOnSale ( int idx , const ShipFlavour * with )
{
m_shipsOnSale [ idx ] = * with ;
onShipsForSaleChanged . emit ( ) ;
}
2012-07-02 18:15:47 -07:00
// Fill the list of starships on sale. Ships that
// can't fit atmo shields are only available in
// atmosphereless environments
2009-06-22 06:02:59 -07:00
void SpaceStation : : UpdateShipyard ( )
{
2012-07-02 18:15:47 -07:00
bool atmospheric = false ;
if ( IsGroundStation ( ) ) {
2012-11-16 17:07:15 -08:00
Body * planet = GetFrame ( ) - > GetBody ( ) ;
2012-07-02 18:15:47 -07:00
atmospheric = planet - > GetSystemBody ( ) - > HasAtmosphere ( ) ;
}
2009-06-22 06:02:59 -07:00
if ( m_shipsOnSale . size ( ) = = 0 ) {
// fill shipyard
for ( int i = Pi : : rng . Int32 ( 20 ) ; i ; i - - ) {
ShipFlavour s ;
2012-07-02 18:15:47 -07:00
ShipFlavour : : MakeTrulyRandom ( s , atmospheric ) ;
2009-06-22 06:02:59 -07:00
m_shipsOnSale . push_back ( s ) ;
}
} else if ( Pi : : rng . Int32 ( 2 ) ) {
// add one
ShipFlavour s ;
2012-07-02 18:15:47 -07:00
ShipFlavour : : MakeTrulyRandom ( s , atmospheric ) ;
2009-06-22 06:02:59 -07:00
m_shipsOnSale . push_back ( s ) ;
} else {
// remove one
int pos = Pi : : rng . Int32 ( m_shipsOnSale . size ( ) ) ;
m_shipsOnSale . erase ( m_shipsOnSale . begin ( ) + pos ) ;
}
onShipsForSaleChanged . emit ( ) ;
}
2012-11-18 21:25:00 -08:00
void SpaceStation : : NotifyRemoved ( const Body * const removedBody )
{
2013-01-24 14:02:01 -08:00
for ( uint32_t 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
{
2013-01-24 14:02:01 -08:00
for ( uint32_t 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 ;
}
int SpaceStation : : GetFreeDockingPort ( ) const
{
for ( int i = 0 ; i < m_type - > numDockingPorts ; i + + ) {
if ( m_shipDocking [ i ] . ship = = 0 ) {
return i ;
}
}
return - 1 ;
}
void SpaceStation : : SetDocked ( Ship * ship , int port )
{
m_shipDocking [ port ] . ship = ship ;
m_shipDocking [ port ] . stage = m_type - > numDockingStages + 1 ;
// 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 ) ) ;
ship - > ClearThrusterState ( ) ;
2012-12-15 16:22:24 -08:00
PositionDockedShip ( ship , port ) ;
2012-11-18 21:25:00 -08:00
}
bool SpaceStation : : LaunchShip ( Ship * ship , int port )
{
shipDocking_t & sd = m_shipDocking [ port ] ;
if ( sd . stage < 0 ) return true ; // already launching
2013-02-03 05:03:52 -08:00
if ( IsPortLocked ( port ) ) return false ; // another ship docking
LockPort ( port , true ) ;
2012-11-18 21:25:00 -08:00
sd . ship = ship ;
sd . stage = - 1 ;
sd . stagePos = 0 ;
sd . fromPos = ( ship - > GetPosition ( ) - GetPosition ( ) ) * GetOrient ( ) ; // station space
sd . fromRot = Quaterniond : : FromMatrix3x3 ( GetOrient ( ) . Transpose ( ) * ship - > GetOrient ( ) ) ;
ship - > SetFlightState ( Ship : : DOCKING ) ;
return true ;
}
bool SpaceStation : : GetDockingClearance ( Ship * s , std : : string & outMsg )
{
2013-01-24 14:02:01 -08:00
for ( uint32_t i = 0 ; i < m_shipDocking . size ( ) ; i + + ) {
2012-11-18 21:25:00 -08:00
if ( i > = m_type - > numDockingPorts ) break ;
if ( ( m_shipDocking [ i ] . ship = = s ) & & ( m_shipDocking [ i ] . stage > 0 ) ) {
outMsg = stringf ( Lang : : CLEARANCE_ALREADY_GRANTED_BAY_N , formatarg ( " bay " , i + 1 ) ) ;
return true ;
}
}
2013-01-24 14:02:01 -08:00
for ( uint32_t i = 0 ; i < m_shipDocking . size ( ) ; i + + ) {
2012-11-18 21:25:00 -08:00
if ( i > = m_type - > numDockingPorts ) break ;
if ( m_shipDocking [ i ] . ship ! = 0 ) continue ;
shipDocking_t & sd = m_shipDocking [ i ] ;
sd . ship = s ;
sd . stage = 1 ;
sd . stagePos = 0 ;
outMsg = stringf ( Lang : : CLEARANCE_GRANTED_BAY_N , formatarg ( " bay " , i + 1 ) ) ;
return true ;
}
outMsg = Lang : : CLEARANCE_DENIED_NO_BAYS ;
return false ;
}
bool SpaceStation : : OnCollision ( Object * b , Uint32 flags , double relVel )
{
if ( ( flags & 0x10 ) & & ( b - > IsType ( Object : : SHIP ) ) ) {
Ship * s = static_cast < Ship * > ( b ) ;
int port = - 1 ;
2013-01-24 14:02:01 -08:00
for ( uint32_t i = 0 ; i < m_shipDocking . size ( ) ; i + + ) {
2012-11-18 21:25:00 -08:00
if ( m_shipDocking [ i ] . ship = = s ) { port = i ; break ; }
}
if ( port = = - 1 ) return false ; // no permission
if ( ! m_type - > dockOneAtATimePlease ) {
2012-12-28 19:06:49 -08:00
if ( port ! = int ( flags & 0xf ) ) return false ; // wrong port
2012-11-18 21:25:00 -08:00
}
if ( m_shipDocking [ port ] . stage ! = 1 ) return false ; // already docking?
SpaceStationType : : positionOrient_t dport ;
// 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 ) ) ;
// must be oriented sensibly and have wheels down
if ( IsGroundStation ( ) ) {
vector3d dockingNormal = GetOrient ( ) * dport . yaxis ;
const double dot = s - > GetOrient ( ) . VectorY ( ) . Dot ( dockingNormal ) ;
if ( ( dot < 0.99 ) | | ( s - > GetWheelState ( ) < 1.0 ) ) return false ; // <0.99 harsh?
if ( s - > GetVelocity ( ) . Length ( ) > MAX_LANDING_SPEED ) return false ;
}
// if there is more docking port anim to do, don't set docked yet
if ( m_type - > numDockingStages > = 2 ) {
shipDocking_t & sd = m_shipDocking [ port ] ;
sd . ship = s ;
sd . stage = 2 ;
sd . stagePos = 0 ;
sd . fromPos = ( s - > GetPosition ( ) - GetPosition ( ) ) * GetOrient ( ) ; // station space
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 {
s - > SetDockedWith ( this , port ) ; // bounces back to SS::SetDocked()
LuaEvent : : Queue ( " onShipDocked " , s , this ) ;
}
return false ;
} else {
return true ;
}
}
void SpaceStation : : DockingUpdate ( const double timeStep )
2009-08-02 05:40:09 -07:00
{
2009-08-06 08:00:08 -07:00
vector3d p1 , p2 , zaxis ;
2013-01-24 14:02:01 -08:00
for ( uint32_t 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 ;
2012-11-18 21:25:00 -08:00
// docked stage is m_type->numDockingPorts + 1 => ship docked
2010-02-01 12:13:52 -08:00
if ( dt . stage > m_type - > numDockingStages ) continue ;
2009-08-03 04:16:31 -07:00
2011-02-17 20:06:05 -08:00
double stageDuration = ( dt . stage > 0 ?
2010-02-01 12:13:52 -08:00
m_type - > dockAnimStageDuration [ dt . stage - 1 ] :
m_type - > undockAnimStageDuration [ abs ( dt . stage ) - 1 ] ) ;
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-01-24 14:02:01 -08:00
m_shipDocking [ i ] . openAnimState + = 0.3 * timeStep ;
m_shipDocking [ i ] . dockAnimState - = 0.3 * timeStep ;
2009-08-03 04:16:31 -07:00
if ( dt . stagePos > = 1.0 ) {
2011-05-10 17:57:37 -07:00
if ( dt . ship = = static_cast < Ship * > ( Pi : : player ) ) Pi : : onDockingClearanceExpired . emit ( this ) ;
2009-08-03 04:16:31 -07:00
dt . ship = 0 ;
2010-02-01 12:13:52 -08:00
dt . stage = 0 ;
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 ;
if ( dt . stage > = 0 ) dt . stage + + ;
else dt . stage - - ;
}
2009-08-06 04:19:22 -07:00
2012-11-23 13:49:47 -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 ( ) ) ;
2012-11-18 21:25:00 -08:00
if ( m_type - > dockMethod = = SpaceStationType : : SURFACE ) {
dt . ship - > SetThrusterState ( 1 , 1.0 ) ; // up
2010-02-01 12:13:52 -08:00
} else {
2012-11-18 21:25:00 -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
}
2012-11-18 21:25:00 -08:00
if ( dt . stage < - m_type - > numUndockStages ) {
// undock animation finished, clear port
dt . stage = 0 ;
dt . ship = 0 ;
2013-02-03 05:03:52 -08:00
LockPort ( i , false ) ;
2012-11-18 21:25:00 -08:00
}
else if ( dt . stage > m_type - > numDockingStages ) {
// set docked
dt . ship - > SetDockedWith ( this , i ) ;
LuaEvent : : Queue ( " onShipDocked " , dt . ship , this ) ;
2013-02-03 05:03:52 -08:00
LockPort ( i , false ) ;
2009-08-02 05:40:09 -07:00
}
2010-01-12 10:42:51 -08:00
}
2013-01-24 14:02:01 -08:00
for ( uint32_t i = 0 ; i < m_shipDocking . size ( ) ; i + + ) {
m_shipDocking [ i ] . openAnimState = Clamp ( m_shipDocking [ i ] . openAnimState , 0.0 , 1.0 ) ;
m_shipDocking [ i ] . dockAnimState = Clamp ( m_shipDocking [ i ] . dockAnimState , 0.0 , 1.0 ) ;
2009-08-02 05:40:09 -07:00
}
}
2012-11-18 21:25:00 -08:00
void SpaceStation : : PositionDockedShip ( Ship * ship , int port ) 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 ) ) ;
2012-12-28 17:34:56 -08:00
assert ( dt . ship = = ship ) ;
ship - > SetPosition ( GetPosition ( ) + GetOrient ( ) * dport . pos ) ;
2012-11-18 21:25:00 -08:00
// Still in docking animation process?
if ( dt . stage < = m_type - > numDockingStages ) {
2013-01-28 08:16:16 -08:00
matrix3x3d wantRot = matrix3x3d : : FromVectors ( dport . xaxis , dport . yaxis , dport . zaxis ) ;
2012-11-18 21:25:00 -08:00
// 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 > ( ) ;
2012-12-28 17:34:56 -08:00
ship - > SetOrient ( GetOrient ( ) * wantRot ) ;
} else {
2012-12-27 16:16:57 -08:00
// Note: ship bounding box is used to generate dport.pos
2013-01-28 08:16:16 -08:00
ship - > SetOrient ( GetOrient ( ) * matrix3x3d : : FromVectors ( dport . xaxis , dport . yaxis , dport . zaxis ) ) ;
2010-03-16 09:51:50 -07:00
}
}
2012-11-18 21:25:00 -08:00
2012-11-18 10:13:47 -08:00
void SpaceStation : : StaticUpdate ( const float timeStep )
2009-06-22 06:02:59 -07:00
{
2012-01-18 02:43:28 -08:00
bool update = false ;
// if there's no BB and there are ships here, make one
if ( ! m_bbCreated & & GetFreeDockingPort ( ) ! = 0 ) {
CreateBB ( ) ;
update = true ;
}
2012-07-04 12:13:48 -07:00
2012-01-18 02:43:28 -08:00
// if there is and it hasn't had an update for a while, update it
else if ( Pi : : game - > GetTime ( ) > m_lastUpdatedShipyard ) {
2012-08-28 15:30:50 -07:00
LuaEvent : : Queue ( " onUpdateBB " , this ) ;
2012-01-18 02:43:28 -08:00
update = true ;
}
if ( update ) {
2009-06-22 06:02:59 -07:00
UpdateShipyard ( ) ;
// update again in an hour or two
2011-11-21 13:33:03 -08:00
m_lastUpdatedShipyard = Pi : : game - > GetTime ( ) + 3600.0 + 3600.0 * Pi : : rng . Double ( ) ;
2009-06-22 06:02:59 -07:00
}
2012-01-18 02:43:28 -08:00
2013-01-23 09:52:34 -08:00
DoLawAndOrder ( timeStep ) ;
2012-11-18 21:25:00 -08:00
DockingUpdate ( timeStep ) ;
2009-06-22 06:02:59 -07:00
}
2012-11-18 10:13:47 -08:00
void SpaceStation : : TimeStepUpdate ( const float timeStep )
{
// rotate the thing
2012-11-25 19:05:43 -08:00
double len = m_type - > angVel * timeStep ;
if ( ! is_zero_exact ( len ) ) {
2012-12-27 17:12:36 -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
2010-03-16 09:51:50 -07:00
for ( int i = 0 ; i < m_type - > numDockingPorts ; i + + ) {
2012-11-18 21:25:00 -08:00
const shipDocking_t & dt = m_shipDocking [ i ] ;
if ( ! dt . ship | | dt . stage = = 1 ) continue ;
if ( dt . ship - > GetFlightState ( ) = = Ship : : FLYING ) continue ;
PositionDockedShip ( dt . ship , i ) ;
2009-10-01 08:42:49 -07:00
}
}
2012-11-25 19:05:43 -08:00
void SpaceStation : : UpdateInterpTransform ( double alpha )
{
double len = m_oldAngDisplacement * ( 1.0 - alpha ) ;
if ( ! is_zero_exact ( len ) ) {
2012-12-27 17:12:36 -08:00
matrix3x3d rot = matrix3x3d : : RotateY ( len ) ; // RotateY is backwards
2012-11-25 19:05:43 -08:00
m_interpOrient = rot * GetOrient ( ) ;
}
else m_interpOrient = GetOrient ( ) ;
m_interpPos = GetPosition ( ) ;
}
2012-11-18 21:25:00 -08:00
bool SpaceStation : : IsGroundStation ( ) const
2009-10-01 08:42:49 -07:00
{
2012-11-18 21:25:00 -08:00
return ( m_type - > dockMethod = = SpaceStationType : : SURFACE ) ;
2008-09-07 16:32:16 -07:00
}
2008-08-11 08:45:25 -07:00
2008-12-18 09:35:25 -08:00
/* MarketAgent shite */
void SpaceStation : : Bought ( Equip : : Type t ) {
2011-05-10 17:57:37 -07:00
m_equipmentStock [ int ( t ) ] + + ;
2008-12-18 09:35:25 -08:00
}
void SpaceStation : : Sold ( Equip : : Type t ) {
2011-05-10 17:57:37 -07:00
m_equipmentStock [ int ( t ) ] - - ;
2008-12-18 09:35:25 -08:00
}
2010-06-19 03:11:48 -07:00
bool SpaceStation : : CanBuy ( Equip : : Type t , bool verbose ) const {
2008-12-18 09:35:25 -08:00
return true ;
}
2010-06-19 03:11:48 -07:00
bool SpaceStation : : CanSell ( Equip : : Type t , bool verbose ) const {
2011-05-10 17:57:37 -07:00
bool result = ( m_equipmentStock [ int ( t ) ] > 0 ) ;
2010-06-19 03:11:48 -07:00
if ( verbose & & ! result ) {
2011-07-27 03:46:56 -07:00
Pi : : Message ( Lang : : ITEM_IS_OUT_OF_STOCK ) ;
2010-06-19 03:11:48 -07:00
}
return result ;
2008-12-18 09:35:25 -08:00
}
2009-10-08 16:49:43 -07:00
bool SpaceStation : : DoesSell ( Equip : : Type t ) const {
2011-11-19 02:33:36 -08:00
return Polit : : IsCommodityLegal ( Pi : : game - > GetSpace ( ) - > GetStarSystem ( ) . Get ( ) , t ) ;
2009-10-08 16:49:43 -07:00
}
2009-11-09 06:24:29 -08:00
Sint64 SpaceStation : : GetPrice ( Equip : : Type t ) const {
2011-11-19 02:33:36 -08:00
Sint64 mul = 100 + Pi : : game - > GetSpace ( ) - > GetStarSystem ( ) - > GetCommodityBasePriceModPercent ( t ) ;
2011-10-09 14:27:49 -07:00
return ( mul * Sint64 ( Equip : : types [ t ] . basePrice ) ) / 100 ;
2008-12-05 14:02:43 -08:00
}
2009-08-02 05:40:09 -07:00
2012-07-19 05:15:52 -07:00
// Calculates the ambiently and directly lit portions of the lighting model taking into account the atmosphere and sun positions at a given location
// 1. Calculates the amount of direct illumination available taking into account
2012-12-22 14:26:30 -08:00
// * multiple suns
// * sun positions relative to up direction i.e. light is dimmed as suns set
2012-07-19 05:15:52 -07:00
// * Thickness of the atmosphere overhead i.e. as atmospheres get thicker light starts dimming earlier as sun sets, without atmosphere the light switches off at point of sunset
// 2. Calculates the split between ambient and directly lit portions taking into account
// * Atmosphere density (optical thickness) of the sky dome overhead
// as optical thickness increases the fraction of ambient light increases
// this takes altitude into account automatically
2012-12-22 14:26:30 -08:00
// * As suns set the split is biased towards ambient
2012-08-11 02:36:42 -07:00
void SpaceStation : : CalcLighting ( Planet * planet , double & ambient , double & intensity , const std : : vector < Camera : : LightSource > & lightSources )
2012-07-14 13:51:03 -07:00
{
// position relative to the rotating frame of the planet
vector3d upDir = GetPosition ( ) ;
2013-01-12 20:40:43 -08:00
const double dist = upDir . Length ( ) ;
2012-07-14 13:51:03 -07:00
upDir = upDir . Normalized ( ) ;
double pressure , density ;
planet - > GetAtmosphericState ( dist , & pressure , & density ) ;
double surfaceDensity ;
Color cl ;
2012-07-28 15:11:23 -07:00
planet - > GetSystemBody ( ) - > GetAtmosphereFlavor ( & cl , & surfaceDensity ) ;
2012-07-14 13:51:03 -07:00
2012-07-19 05:15:52 -07:00
// approximate optical thickness fraction as fraction of density remaining relative to earths
2012-07-24 22:51:17 -07:00
double opticalThicknessFraction = density / EARTH_ATMOSPHERE_SURFACE_DENSITY ;
2012-07-19 05:15:52 -07:00
// tweak optical thickness curve - lower exponent ==> higher altitude before ambient level drops
opticalThicknessFraction = pow ( std : : max ( 0.00001 , opticalThicknessFraction ) , 0.15 ) ; //max needed to avoid 0^power
2012-07-14 13:51:03 -07:00
//step through all the lights and calculate contributions taking into account sun position
double light = 0.0 ;
2012-07-24 22:51:17 -07:00
double light_clamped = 0.0 ;
2012-07-14 13:51:03 -07:00
2012-08-11 02:36:42 -07:00
for ( std : : vector < Camera : : LightSource > : : const_iterator l = lightSources . begin ( ) ;
l ! = lightSources . end ( ) ; + + l ) {
2012-12-22 14:26:30 -08:00
2012-07-14 13:51:03 -07:00
double sunAngle ;
// calculate the extent the sun is towards zenith
if ( l - > GetBody ( ) ) {
// relative to the rotating frame of the planet
2012-11-16 17:07:15 -08:00
const vector3d lightDir = ( l - > GetBody ( ) - > GetInterpPositionRelTo ( planet - > GetFrame ( ) ) . Normalized ( ) ) ;
2012-07-14 13:51:03 -07:00
sunAngle = lightDir . Dot ( upDir ) ;
2013-01-12 20:40:43 -08:00
} else {
2012-07-14 13:51:03 -07:00
// light is the default light for systems without lights
sunAngle = 1.0 ;
2013-01-12 20:40:43 -08:00
}
2012-07-14 13:51:03 -07:00
//0 to 1 as sunangle goes from 0.0 to 1.0
2012-07-24 22:51:17 -07:00
double sunAngle2 = ( Clamp ( sunAngle , 0.0 , 1.0 ) ) / 1.0 ;
2012-07-14 13:51:03 -07:00
2012-07-19 05:15:52 -07:00
//0 to 1 as sunAngle goes from endAngle to startAngle
2012-07-24 22:51:17 -07:00
// angle at which light begins to fade on Earth
const double startAngle = 0.3 ;
// angle at which sun set completes, which should be after sun has dipped below the horizon on Earth
2013-01-03 13:00:45 -08:00
const double endAngle = - 0.18 ;
2012-07-19 05:15:52 -07:00
const double start = std : : min ( ( startAngle * opticalThicknessFraction ) , 1.0 ) ;
const double end = std : : max ( ( endAngle * opticalThicknessFraction ) , - 0.2 ) ;
sunAngle = ( Clamp ( sunAngle , end , start ) - end ) / ( start - end ) ;
2012-12-22 14:26:30 -08:00
2012-07-14 13:51:03 -07:00
light + = sunAngle ;
2012-07-24 22:51:17 -07:00
light_clamped + = sunAngle2 ;
2012-07-14 13:51:03 -07:00
}
2012-07-19 05:15:52 -07:00
2012-07-14 13:51:03 -07:00
// brightness depends on optical depth and intensity of light from all the stars
intensity = ( Clamp ( ( light ) , 0.0 , 1.0 ) ) ;
// ambient light fraction
// alter ratio between directly and ambiently lit portions towards ambiently lit as sun sets
2013-01-12 20:40:43 -08:00
const double fraction = ( 0.1 + 0.8 * (
2012-07-24 22:51:17 -07:00
1.0 - light_clamped * ( Clamp ( ( opticalThicknessFraction ) , 0.0 , 1.0 ) )
2013-01-03 13:00:45 -08:00
) + 0.1 ) ; //fraction goes from 0.6 to 1.0
2012-12-22 14:26:30 -08:00
2012-07-14 13:51:03 -07:00
// fraction of light left over to be lit directly
intensity = ( 1.0 - fraction ) * intensity ;
// scale ambient by amount of light
2013-01-03 13:00:45 -08:00
ambient = fraction * ( Clamp ( ( light ) , 0.0 , 1.0 ) ) * 0.25 ;
2012-07-14 13:51:03 -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
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
{
2010-01-18 09:58:57 -08:00
LmrObjParams & params = GetLmrObjParams ( ) ;
2011-10-09 07:20:33 -07:00
params . label = GetLabel ( ) . c_str ( ) ;
2010-01-30 10:56:37 -08:00
SetLmrTimeParams ( ) ;
2009-10-06 08:05:40 -07:00
2013-01-27 06:42:47 -08:00
const int maxPorts = std : : min ( MAX_LMR_DOCKING_PORTS , int ( m_shipDocking . size ( ) ) ) ;
for ( int i = 0 ; i < maxPorts ; i + + ) {
2011-10-12 18:39:13 -07:00
params . animStages [ ANIM_DOCKING_BAY_1 + i ] = m_shipDocking [ i ] . stage ;
params . animValues [ ANIM_DOCKING_BAY_1 + i ] = m_shipDocking [ i ] . stagePos ;
2009-08-03 04:16:31 -07:00
}
2010-02-01 12:13:52 -08:00
2012-11-16 17:07:15 -08:00
Body * b = GetFrame ( ) - > GetBody ( ) ;
2012-07-28 15:11:23 -07:00
assert ( b ) ;
if ( ! b - > IsType ( Object : : PLANET ) ) {
2012-07-14 13:51:03 -07:00
// orbital spaceport -- don't make city turds or change lighting based on atmosphere
2012-07-29 16:03:00 -07:00
RenderLmrModel ( r , viewCoords , viewTransform ) ;
2012-07-28 15:11:23 -07:00
}
2012-12-22 14:26:30 -08:00
2012-07-28 15:11:23 -07:00
else {
Planet * planet = static_cast < Planet * > ( b ) ;
2012-12-22 14:26:30 -08:00
2012-07-23 10:51:51 -07:00
// calculate lighting
// available light is calculated and split between directly (diffusely/specularly) lit and ambiently lit
2012-08-11 02:36:42 -07:00
const std : : vector < Camera : : LightSource > & lightSources = camera - > GetLightSources ( ) ;
2012-07-14 13:51:03 -07:00
double ambient , intensity ;
2013-01-03 13:00:45 -08:00
2012-08-11 02:36:42 -07:00
CalcLighting ( planet , ambient , intensity , lightSources ) ;
2013-01-12 20:40:43 -08:00
ambient = std : : max ( 0.05 , ambient ) ;
2012-08-11 02:36:42 -07:00
std : : vector < Graphics : : Light > origLights , newLights ;
2012-12-22 14:26:30 -08:00
2012-08-11 02:36:42 -07:00
for ( size_t i = 0 ; i < lightSources . size ( ) ; i + + ) {
Graphics : : Light light ( lightSources [ i ] . GetLight ( ) ) ;
2012-07-09 06:47:47 -07:00
2012-08-11 02:36:42 -07:00
origLights . push_back ( light ) ;
2012-07-09 06:47:47 -07:00
2012-08-11 02:36:42 -07:00
Color c = light . GetDiffuse ( ) ;
Color cs = light . GetSpecular ( ) ;
2012-07-24 07:51:18 -07:00
c . r * = float ( intensity ) ;
c . g * = float ( intensity ) ;
c . b * = float ( intensity ) ;
cs . r * = float ( intensity ) ;
cs . g * = float ( intensity ) ;
cs . b * = float ( intensity ) ;
2012-08-11 02:36:42 -07:00
light . SetDiffuse ( c ) ;
light . SetSpecular ( cs ) ;
newLights . push_back ( light ) ;
2012-07-09 06:47:47 -07:00
}
2012-08-11 02:36:42 -07:00
2012-08-20 17:34:29 -07:00
const Color oldAmbient = r - > GetAmbientColor ( ) ;
2013-01-12 20:40:43 -08:00
r - > SetAmbientColor ( Color ( ambient ) ) ;
r - > SetLights ( newLights . size ( ) , & newLights [ 0 ] ) ;
2012-07-23 10:51:51 -07:00
2012-07-09 06:47:47 -07:00
/* don't render city if too far away */
if ( viewCoords . Length ( ) < 1000000.0 ) {
2009-07-28 08:36:37 -07:00
if ( ! m_adjacentCity ) {
m_adjacentCity = new CityOnPlanet ( planet , this , m_sbody - > seed ) ;
}
2013-01-12 20:40:43 -08:00
m_adjacentCity - > Render ( r , camera , this , viewCoords , viewTransform ) ;
2012-12-22 14:26:30 -08:00
}
2012-07-09 06:47:47 -07:00
2012-09-15 05:23:55 -07:00
RenderLmrModel ( r , viewCoords , viewTransform ) ;
2012-09-05 15:09:27 -07:00
2013-01-12 20:40:43 -08:00
// restore old lights & ambient
2012-08-11 02:36:42 -07:00
r - > SetLights ( origLights . size ( ) , & origLights [ 0 ] ) ;
2012-07-14 13:51:03 -07:00
r - > SetAmbientColor ( oldAmbient ) ;
2009-07-18 07:09:31 -07:00
}
2008-06-24 03:17:31 -07:00
}
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
bool SpaceStation : : AllocateStaticSlot ( int & slot )
{
2012-12-31 00:18:58 -08:00
// no slots at ground stations
if ( IsGroundStation ( ) )
return false ;
2012-07-22 07:44:30 -07: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
2011-04-30 03:22:35 -07:00
void SpaceStation : : CreateBB ( )
{
if ( m_bbCreated ) return ;
2011-11-08 13:39:53 -08:00
// fill the shipyard equipment shop with all kinds of things
// XXX should probably be moved out to a MarketAgent/CommodityWidget type
// thing, or just lua
for ( int i = 1 ; i < Equip : : TYPE_MAX ; i + + ) {
if ( Equip : : types [ i ] . slot = = Equip : : SLOT_CARGO ) {
m_equipmentStock [ i ] = Pi : : rng . Int32 ( 0 , 100 ) * Pi : : rng . Int32 ( 1 , 100 ) ;
} else {
2012-03-30 22:36:37 -07:00
m_equipmentStock [ i ] = Pi : : rng . Int32 ( 0 , 100 ) ;
2011-11-08 13:39:53 -08:00
}
}
2012-08-28 15:30:50 -07:00
LuaEvent : : Queue ( " onCreateBB " , this ) ;
2011-04-30 03:22:35 -07:00
m_bbCreated = true ;
}
2011-04-26 21:44:07 -07:00
static int next_ref = 0 ;
2011-05-29 15:31:18 -07:00
int SpaceStation : : AddBBAdvert ( std : : string description , AdvertFormBuilder builder )
2011-04-26 21:44:07 -07:00
{
int ref = + + next_ref ;
assert ( ref ) ;
BBAdvert ad ;
ad . ref = ref ;
ad . description = description ;
ad . builder = builder ;
m_bbAdverts . push_back ( ad ) ;
2011-04-30 03:54:34 -07:00
onBulletinBoardChanged . emit ( ) ;
2011-04-26 21:44:07 -07:00
return ref ;
}
const BBAdvert * SpaceStation : : GetBBAdvert ( int ref )
{
2012-09-03 07:30:08 -07:00
for ( std : : vector < BBAdvert > : : const_iterator i = m_bbAdverts . begin ( ) ; i ! = m_bbAdverts . end ( ) ; + + i )
2011-04-26 21:44:07 -07:00
if ( i - > ref = = ref )
return & ( * i ) ;
return NULL ;
}
bool SpaceStation : : RemoveBBAdvert ( int ref )
{
2012-09-03 07:30:08 -07:00
for ( std : : vector < BBAdvert > : : iterator i = m_bbAdverts . begin ( ) ; i ! = m_bbAdverts . end ( ) ; + + i )
2011-04-26 21:44:07 -07:00
if ( i - > ref = = ref ) {
2011-09-26 13:52:17 -07:00
BBAdvert ad = ( * i ) ;
2011-04-26 21:44:07 -07:00
m_bbAdverts . erase ( i ) ;
2011-09-26 13:52:17 -07:00
onBulletinBoardAdvertDeleted . emit ( ad ) ;
2011-04-26 21:44:07 -07:00
return true ;
}
return false ;
}
const std : : list < const BBAdvert * > SpaceStation : : GetBBAdverts ( )
{
2011-04-26 21:59:07 -07:00
if ( ! m_bbShuffled ) {
std : : random_shuffle ( m_bbAdverts . begin ( ) , m_bbAdverts . end ( ) ) ;
m_bbShuffled = true ;
}
2011-04-26 21:44:07 -07:00
std : : list < const BBAdvert * > ads ;
2012-09-03 07:30:08 -07:00
for ( std : : vector < BBAdvert > : : const_iterator i = m_bbAdverts . begin ( ) ; i ! = m_bbAdverts . end ( ) ; + + i )
2011-04-26 21:44:07 -07:00
ads . push_back ( & ( * i ) ) ;
return ads ;
}
2011-12-02 08:10:21 -08:00
vector3d SpaceStation : : GetTargetIndicatorPosition ( const Frame * relTo ) const
{
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
2013-01-24 14:02:01 -08:00
for ( uint32_t i = 0 ; i < m_shipDocking . size ( ) ; i + + ) {
2011-12-02 08:10:21 -08:00
if ( i > = m_type - > numDockingPorts ) break ;
if ( ( m_shipDocking [ i ] . ship = = Pi : : player ) & & ( m_shipDocking [ i ] . stage > 0 ) ) {
SpaceStationType : : positionOrient_t dport ;
2012-05-10 18:37:49 -07:00
if ( ! m_type - > GetShipApproachWaypoints ( i , m_shipDocking [ i ] . stage + 1 , dport ) )
PiVerify ( m_type - > GetDockAnimPositionOrient ( i , m_type - > numDockingStages ,
2011-12-02 08:10:21 -08:00
1.0f , vector3d ( 0.0 ) , dport , m_shipDocking [ i ] . ship ) ) ;
2012-11-16 17:07:15 -08:00
vector3d v = GetInterpPositionRelTo ( relTo ) ;
return v + GetInterpOrientRelTo ( relTo ) * dport . pos ;
2011-12-02 08:10:21 -08:00
}
}
2012-11-16 17:07:15 -08:00
return GetInterpPositionRelTo ( relTo ) ;
2012-01-18 02:43:28 -08:00
}
2012-11-18 21:25:00 -08:00
2013-01-27 07:22:26 -08:00
// XXX this whole thing should be done by Lua
2013-01-23 09:52:34 -08:00
void SpaceStation : : DoLawAndOrder ( const double timeStep )
2012-11-18 21:25:00 -08:00
{
Sint64 fine , crimeBitset ;
Polit : : GetCrime ( & crimeBitset , & fine ) ;
if ( Pi : : player - > GetFlightState ( ) ! = Ship : : DOCKED
& & m_numPoliceDocked
& & ( fine > 1000 )
& & ( GetPositionRelTo ( Pi : : player ) . Length ( ) < 100000.0 ) ) {
int port = GetFreeDockingPort ( ) ;
2013-01-27 07:22:26 -08:00
// at 60 Hz updates (ie, 1x time acceleration),
// this spawns a police ship with probability ~0.83% each frame
// This makes it unlikely (but not impossible) that police will spawn on top of each other
// the expected number of game-time seconds between spawns: 120 (2*60 Hz)
// variance is quite high though
2013-01-23 09:52:34 -08:00
if ( port ! = - 1 & & 2.0 * Pi : : rng . Double ( ) < timeStep ) {
2012-11-18 21:25:00 -08:00
m_numPoliceDocked - - ;
// Make police ship intent on killing the player
Ship * ship = new Ship ( ShipType : : LADYBIRD ) ;
ship - > AIKill ( Pi : : player ) ;
ship - > SetFrame ( GetFrame ( ) ) ;
ship - > SetDockedWith ( this , port ) ;
Pi : : game - > GetSpace ( ) - > AddBody ( ship ) ;
{ // blue and white thang
ShipFlavour f ;
f . id = ShipType : : LADYBIRD ;
f . regid = Lang : : POLICE_SHIP_REGISTRATION ;
f . price = ship - > GetFlavour ( ) - > price ;
LmrMaterial m ;
m . diffuse [ 0 ] = 0.0f ; m . diffuse [ 1 ] = 0.0f ; m . diffuse [ 2 ] = 1.0f ; m . diffuse [ 3 ] = 1.0f ;
m . specular [ 0 ] = 0.0f ; m . specular [ 1 ] = 0.0f ; m . specular [ 2 ] = 1.0f ; m . specular [ 3 ] = 1.0f ;
m . emissive [ 0 ] = 0.0f ; m . emissive [ 1 ] = 0.0f ; m . emissive [ 2 ] = 0.0f ; m . emissive [ 3 ] = 0.0f ;
m . shininess = 50.0f ;
f . primaryColor = m ;
m . shininess = 0.0f ;
m . diffuse [ 0 ] = 1.0f ; m . diffuse [ 1 ] = 1.0f ; m . diffuse [ 2 ] = 1.0f ; m . diffuse [ 3 ] = 1.0f ;
f . secondaryColor = m ;
ship - > ResetFlavour ( & f ) ;
}
ship - > m_equipment . Set ( Equip : : SLOT_LASER , 0 , Equip : : PULSECANNON_DUAL_1MW ) ;
ship - > m_equipment . Add ( Equip : : SHIELD_GENERATOR ) ;
ship - > m_equipment . Add ( Equip : : LASER_COOLING_BOOSTER ) ;
ship - > m_equipment . Add ( Equip : : ATMOSPHERIC_SHIELDING ) ;
ship - > UpdateStats ( ) ;
}
}
}
2013-02-03 05:03:52 -08:00
bool SpaceStation : : IsPortLocked ( const int bay ) const
{
SpaceStationType : : TBayGroups : : const_iterator bayIter = mBayGroups . begin ( ) ;
for ( ; bayIter ! = mBayGroups . end ( ) ; + + bayIter ) {
std : : vector < int > : : const_iterator idIter = ( * bayIter ) . bayIDs . begin ( ) ;
for ( ; idIter ! = ( * bayIter ) . bayIDs . end ( ) ; + + idIter ) {
if ( ( * idIter ) = = bay ) {
return ( * bayIter ) . inUse ;
}
}
}
// is it safer to return that the
return true ;
}
void SpaceStation : : LockPort ( const int bay , const bool lockIt )
{
SpaceStationType : : TBayGroups : : iterator bayIter = mBayGroups . begin ( ) ;
for ( ; bayIter ! = mBayGroups . end ( ) ; + + bayIter ) {
std : : vector < int > : : iterator idIter = ( * bayIter ) . bayIDs . begin ( ) ;
for ( ; idIter ! = ( * bayIter ) . bayIDs . end ( ) ; + + idIter ) {
if ( ( * idIter ) = = bay ) {
( * bayIter ) . inUse = lockIt ;
}
}
}
}