2012-09-12 04:38:30 -07:00
// Copyright © 2008-2012 Pioneer Developers. See AUTHORS.txt for details
// Licensed under the terms of the GPL v3. See COPYING.txt for details
2008-06-24 03:17:31 -07:00
# include "SpaceStation.h"
# include "Ship.h"
2009-07-18 07:09:31 -07:00
# include "Planet.h"
2008-09-07 16:32:16 -07:00
# include "gameconsts.h"
2012-04-04 18:53:58 -07:00
# include "galaxy/StarSystem.h"
2008-09-18 19:23:48 -07:00
# include "Serializer.h"
2008-12-27 17:02:45 -08:00
# include "Frame.h"
2008-12-05 14:02:43 -08:00
# include "Pi.h"
2009-07-25 07:23:05 -07:00
# include "CityOnPlanet.h"
2009-08-07 07:34:14 -07:00
# include "Player.h"
2009-10-08 16:49:43 -07:00
# include "Polit.h"
2010-01-12 07:21:56 -08:00
# include "LmrModel.h"
2012-05-05 12:01:31 -07:00
# include "LuaVector.h"
2012-08-29 17:33:54 -07:00
# include "LuaEvent.h"
2010-03-16 09:51:50 -07:00
# include "Polit.h"
# include "Space.h"
2011-07-27 03:46:56 -07:00
# include "Lang.h"
2011-08-23 20:18:53 -07:00
# include "StringF.h"
# include <algorithm>
2011-11-19 02:33:36 -08:00
# include "Game.h"
2012-07-24 22:51:17 -07:00
# include "graphics/Graphics.h"
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
2011-02-17 20:06:05 -08:00
void SpaceStationType : : _ReadStageDurations ( const char * key , int * outNumStages , double * * durationArray ) {
2010-09-05 08:09:32 -07:00
lua_State * L = LmrGetLuaState ( ) ;
2011-09-23 23:40:02 -07:00
LUA_DEBUG_START ( L ) ;
2010-09-05 08:09:32 -07:00
model - > PushAttributeToLuaStack ( key ) ;
assert ( lua_istable ( L , - 1 ) ) ;
2012-05-06 11:41:51 -07:00
int num = lua_rawlen ( L , - 1 ) ;
2010-09-05 08:09:32 -07:00
* outNumStages = num ;
if ( num = = 0 ) {
* durationArray = 0 ;
} else {
2011-02-17 20:06:05 -08:00
* durationArray = new double [ num ] ;
2010-09-05 08:09:32 -07:00
for ( int i = 1 ; i < = num ; i + + ) {
lua_pushinteger ( L , i ) ;
lua_gettable ( L , - 2 ) ;
( * durationArray ) [ i - 1 ] = lua_tonumber ( L , - 1 ) ;
lua_pop ( L , 1 ) ;
2010-03-11 07:46:04 -08:00
}
2010-01-31 08:18:37 -08:00
}
2010-09-05 08:09:32 -07:00
if ( outNumStages < = 0 ) {
Error ( " Space station %s must have atleast 1 docking and 1 undocking animation stage. " ,
modelName ) ;
2010-01-31 08:18:37 -08:00
}
2011-09-23 23:40:02 -07:00
2011-09-23 23:50:22 -07:00
lua_pop ( L , 1 ) ;
2011-09-23 23:40:02 -07:00
LUA_DEBUG_END ( L , 0 ) ;
2010-09-05 08:09:32 -07:00
}
// read from lua model definition
void SpaceStationType : : ReadStageDurations ( ) {
_ReadStageDurations ( " dock_anim_stage_duration " , & numDockingStages , & dockAnimStageDuration ) ;
_ReadStageDurations ( " undock_anim_stage_duration " , & numUndockStages , & undockAnimStageDuration ) ;
}
2010-01-31 08:18:37 -08:00
2010-09-05 08:09:32 -07:00
bool SpaceStationType : : GetShipApproachWaypoints ( int port , int stage , positionOrient_t & outPosOrient ) const
{
lua_State * L = LmrGetLuaState ( ) ;
2011-09-23 23:40:02 -07:00
LUA_DEBUG_START ( L ) ;
2011-03-28 03:56:42 -07:00
lua_pushcfunction ( L , pi_lua_panic ) ;
2010-09-05 08:09:32 -07:00
model - > PushAttributeToLuaStack ( " ship_approach_waypoints " ) ;
if ( ! lua_isfunction ( L , - 1 ) ) {
printf ( " no function \n " ) ;
2010-09-10 06:40:21 -07:00
lua_pop ( L , 2 ) ;
2011-09-23 23:40:02 -07:00
LUA_DEBUG_END ( L , 0 ) ;
2010-09-05 08:09:32 -07:00
return false ;
}
2011-09-23 23:40:02 -07:00
2010-09-05 08:09:32 -07:00
lua_pushinteger ( L , port + 1 ) ;
lua_pushinteger ( L , stage ) ;
2010-09-10 06:40:21 -07:00
lua_pcall ( L , 2 , 1 , - 4 ) ;
2010-09-05 08:09:32 -07:00
bool gotOrient ;
if ( lua_istable ( L , - 1 ) ) {
gotOrient = true ;
lua_pushinteger ( L , 1 ) ;
lua_gettable ( L , - 2 ) ;
2012-05-05 12:01:31 -07:00
outPosOrient . pos = * LuaVector : : CheckFromLua ( L , - 1 ) ;
2010-09-05 08:09:32 -07:00
lua_pop ( L , 1 ) ;
2010-02-01 12:13:52 -08:00
2010-09-05 08:09:32 -07:00
lua_pushinteger ( L , 2 ) ;
lua_gettable ( L , - 2 ) ;
2012-05-05 12:01:31 -07:00
outPosOrient . xaxis = * LuaVector : : CheckFromLua ( L , - 1 ) ;
2010-09-05 08:09:32 -07:00
lua_pop ( L , 1 ) ;
2010-02-01 12:13:52 -08:00
2010-09-05 08:09:32 -07:00
lua_pushinteger ( L , 3 ) ;
lua_gettable ( L , - 2 ) ;
2012-05-05 12:01:31 -07:00
outPosOrient . yaxis = * LuaVector : : CheckFromLua ( L , - 1 ) ;
2010-01-31 08:18:37 -08:00
lua_pop ( L , 1 ) ;
2010-09-05 08:09:32 -07:00
} else {
gotOrient = false ;
}
2011-09-23 23:50:22 -07:00
lua_pop ( L , 2 ) ;
2011-09-23 23:40:02 -07:00
LUA_DEBUG_END ( L , 0 ) ;
2010-09-05 08:09:32 -07:00
return gotOrient ;
}
/* when ship is on rails it returns true and fills outPosOrient.
* when ship has been released ( or docked ) it returns false .
* Note station animations may continue for any number of stages after
* ship has been released and is under player control again */
2011-02-17 20:06:05 -08:00
bool SpaceStationType : : GetDockAnimPositionOrient ( int port , int stage , double t , const vector3d & from , positionOrient_t & outPosOrient , const Ship * ship ) const
2010-09-05 08:09:32 -07:00
{
if ( ( stage < 0 ) & & ( ( - stage ) > numUndockStages ) ) return false ;
if ( ( stage > 0 ) & & ( stage > numDockingStages ) ) return false ;
2011-09-23 23:40:02 -07:00
2010-09-05 08:09:32 -07:00
lua_State * L = LmrGetLuaState ( ) ;
2011-09-23 23:40:02 -07:00
LUA_DEBUG_START ( L ) ;
2011-03-28 03:56:42 -07:00
lua_pushcfunction ( L , pi_lua_panic ) ;
2010-09-05 08:09:32 -07:00
// It's a function of form function(stage, t, from)
model - > PushAttributeToLuaStack ( " ship_dock_anim " ) ;
if ( ! lua_isfunction ( L , - 1 ) ) {
2010-09-10 06:40:21 -07:00
Error ( " Spacestation model %s needs ship_dock_anim method " , model - > GetName ( ) ) ;
2010-01-31 08:18:37 -08:00
}
2010-09-05 08:09:32 -07:00
lua_pushinteger ( L , port + 1 ) ;
lua_pushinteger ( L , stage ) ;
2011-05-10 17:57:37 -07:00
lua_pushnumber ( L , double ( t ) ) ;
2012-05-05 12:01:31 -07:00
LuaVector : : PushToLua ( L , from ) ;
2010-09-05 08:09:32 -07:00
// push model aabb as lua table: { min: vec3, max: vec3 }
{
Aabb aabb ;
ship - > GetAabb ( aabb ) ;
lua_createtable ( L , 0 , 2 ) ;
2012-05-05 12:01:31 -07:00
LuaVector : : PushToLua ( L , aabb . max ) ;
2010-09-05 08:09:32 -07:00
lua_setfield ( L , - 2 , " max " ) ;
2012-05-05 12:01:31 -07:00
LuaVector : : PushToLua ( L , aabb . min ) ;
2010-09-05 08:09:32 -07:00
lua_setfield ( L , - 2 , " min " ) ;
}
2010-09-10 06:40:21 -07:00
lua_pcall ( L , 5 , 1 , - 7 ) ;
2010-09-05 08:09:32 -07:00
bool gotOrient ;
if ( lua_istable ( L , - 1 ) ) {
gotOrient = true ;
lua_pushinteger ( L , 1 ) ;
lua_gettable ( L , - 2 ) ;
2012-05-05 12:01:31 -07:00
outPosOrient . pos = * LuaVector : : CheckFromLua ( L , - 1 ) ;
2010-09-05 08:09:32 -07:00
lua_pop ( L , 1 ) ;
2010-01-31 08:18:37 -08:00
2010-09-05 08:09:32 -07:00
lua_pushinteger ( L , 2 ) ;
lua_gettable ( L , - 2 ) ;
2012-05-05 12:01:31 -07:00
outPosOrient . xaxis = * LuaVector : : CheckFromLua ( L , - 1 ) ;
2010-09-05 08:09:32 -07:00
lua_pop ( L , 1 ) ;
2010-01-31 08:18:37 -08:00
2010-09-05 08:09:32 -07:00
lua_pushinteger ( L , 3 ) ;
lua_gettable ( L , - 2 ) ;
2012-05-05 12:01:31 -07:00
outPosOrient . yaxis = * LuaVector : : CheckFromLua ( L , - 1 ) ;
2010-09-05 08:09:32 -07:00
lua_pop ( L , 1 ) ;
} else {
gotOrient = false ;
}
2011-09-23 23:50:22 -07:00
lua_pop ( L , 2 ) ;
2011-09-23 23:40:02 -07:00
LUA_DEBUG_END ( L , 0 ) ;
2010-09-05 08:09:32 -07:00
return gotOrient ;
}
2008-09-07 16:32:16 -07:00
2010-01-17 12:25:52 -08:00
static bool stationTypesInitted = false ;
static std : : vector < SpaceStationType > surfaceStationTypes ;
static std : : vector < SpaceStationType > orbitalStationTypes ;
/* Must be called after LmrModel init is called */
void SpaceStation : : Init ( )
{
if ( stationTypesInitted ) return ;
stationTypesInitted = true ;
for ( int is_orbital = 0 ; is_orbital < 2 ; is_orbital + + ) {
std : : vector < LmrModel * > models ;
if ( is_orbital ) LmrGetModelsWithTag ( " orbital_station " , models ) ;
else LmrGetModelsWithTag ( " surface_station " , models ) ;
for ( std : : vector < LmrModel * > : : iterator i = models . begin ( ) ;
i ! = models . end ( ) ; + + i ) {
SpaceStationType t ;
t . modelName = ( * i ) - > GetName ( ) ;
2010-01-31 08:18:37 -08:00
t . model = LmrLookupModelByName ( t . modelName ) ;
2011-05-10 17:57:37 -07:00
t . dockMethod = SpaceStationType : : DOCKMETHOD ( is_orbital ) ;
2010-01-31 08:18:37 -08:00
t . numDockingPorts = ( * i ) - > GetIntAttribute ( " num_docking_ports " ) ;
2010-09-23 07:17:42 -07:00
t . dockOneAtATimePlease = ( * i ) - > GetBoolAttribute ( " dock_one_at_a_time_please " ) ;
2010-01-31 08:18:37 -08:00
t . ReadStageDurations ( ) ;
2011-12-16 12:50:09 -08:00
//printf("one at a time? %s\n", t.dockOneAtATimePlease ? "yes" : "no");
//printf("%s: %d docking ports\n", t.modelName, t.numDockingPorts);
2010-01-17 13:22:09 -08:00
if ( is_orbital ) {
t . angVel = ( * i ) - > GetFloatAttribute ( " angular_velocity " ) ;
orbitalStationTypes . push_back ( t ) ;
}
2010-01-17 12:25:52 -08:00
else surfaceStationTypes . push_back ( t ) ;
}
}
2012-02-19 10:55:29 -08:00
//printf(SIZET_FMT " orbital station types and " SIZET_FMT " surface station types.\n", orbitalStationTypes.size(), surfaceStationTypes.size());
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 ( )
{
std : : vector < SpaceStationType > : : iterator i ;
for ( i = surfaceStationTypes . begin ( ) ; i ! = surfaceStationTypes . end ( ) ; + + i ) {
delete [ ] ( * i ) . dockAnimStageDuration ;
delete [ ] ( * i ) . undockAnimStageDuration ;
}
for ( i = orbitalStationTypes . begin ( ) ; i ! = orbitalStationTypes . end ( ) ; + + i ) {
delete [ ] ( * i ) . dockAnimStageDuration ;
delete [ ] ( * i ) . undockAnimStageDuration ;
}
}
2010-01-17 13:22:09 -08:00
float SpaceStation : : GetDesiredAngVel ( ) const
{
return m_type - > angVel ;
}
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
}
2009-08-02 05:40:09 -07:00
for ( int i = 0 ; i < MAX_DOCKING_PORTS ; 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
2011-05-10 17:57:37 -07:00
wr . Float ( float ( m_openAnimState [ i ] ) ) ;
wr . Float ( float ( m_dockAnimState [ i ] ) ) ;
2009-08-02 05:40:09 -07: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 ) ;
}
2009-08-02 05:40:09 -07:00
for ( int i = 0 ; i < MAX_DOCKING_PORTS ; i + + ) {
2011-05-12 05:31:08 -07:00
m_shipDocking [ i ] . shipIndex = rd . Int32 ( ) ;
2010-05-22 10:26:25 -07:00
m_shipDocking [ i ] . stage = rd . Int32 ( ) ;
m_shipDocking [ i ] . stagePos = rd . Float ( ) ;
m_shipDocking [ i ] . fromPos = rd . Vector3d ( ) ;
2010-08-03 03:28:18 -07:00
m_shipDocking [ i ] . fromRot = rd . RdQuaternionf ( ) ;
2009-08-03 04:16:31 -07:00
2010-05-22 10:26:25 -07:00
m_openAnimState [ i ] = rd . Float ( ) ;
m_dockAnimState [ i ] = rd . Float ( ) ;
2009-08-02 05:40:09 -07: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
{
for ( int i = 0 ; i < MAX_DOCKING_PORTS ; 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
}
}
2009-11-18 06:57:04 -08:00
double SpaceStation : : GetBoundingRadius ( ) const
{
return ModelBody : : GetBoundingRadius ( ) + CITY_ON_PLANET_RADIUS ;
}
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 ;
2011-11-08 13:39:53 -08:00
2009-08-03 04:16:31 -07:00
for ( int i = 0 ; i < MAX_DOCKING_PORTS ; i + + ) {
m_shipDocking [ i ] . ship = 0 ;
2010-02-01 12:13:52 -08:00
m_shipDocking [ i ] . stage = 0 ;
m_shipDocking [ i ] . stagePos = 0 ;
2009-08-03 04:16:31 -07:00
m_openAnimState [ i ] = 0 ;
m_dockAnimState [ i ] = 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-04-17 18:53:53 -07:00
if ( m_sbody - > type = = SystemBody : : TYPE_STARPORT_ORBITAL ) {
2010-01-17 12:25:52 -08:00
m_type = & orbitalStationTypes [ rand . Int32 ( orbitalStationTypes . size ( ) ) ] ;
2011-02-20 22:55:28 -08:00
m_hasDoubleFrame = true ;
2010-01-17 12:25:52 -08:00
} else {
m_type = & surfaceStationTypes [ rand . Int32 ( surfaceStationTypes . size ( ) ) ] ;
}
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 " ;
2010-01-17 12:25:52 -08:00
SetModel ( m_type - > modelName , true ) ;
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 ( ) ) {
Body * planet = GetFrame ( ) - > m_astroBody ;
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 ( ) ;
}
2011-02-17 20:06:05 -08:00
void SpaceStation : : DoDockingAnimation ( const double timeStep )
2009-08-02 05:40:09 -07:00
{
2009-08-06 04:19:22 -07:00
matrix4x4d rot , wantRot ;
2009-08-06 08:00:08 -07:00
vector3d p1 , p2 , zaxis ;
2009-08-02 05:40:09 -07:00
for ( int i = 0 ; i < MAX_DOCKING_PORTS ; i + + ) {
shipDocking_t & dt = m_shipDocking [ i ] ;
2010-02-01 12:13:52 -08:00
if ( ! dt . ship ) continue ;
if ( ! dt . stage ) continue ;
// docked stage is m_type->numDockingPorts + 1
if ( dt . stage > m_type - > numDockingStages ) continue ;
2009-08-06 08:00:08 -07:00
GetRotMatrix ( rot ) ;
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 ) {
// SPECIAL stage! Docking granted but waiting for ship
// to dock
2009-08-03 04:16:31 -07:00
m_openAnimState [ i ] + = 0.3 * timeStep ;
m_dockAnimState [ i ] - = 0.3 * timeStep ;
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 ) {
2010-02-01 12:13:52 -08:00
dt . stagePos = 0 ;
if ( dt . stage > = 0 ) dt . stage + + ;
else dt . stage - - ;
2010-03-05 05:16:11 -08:00
dt . fromPos = rot . InverseOf ( ) * ( dt . ship - > GetPosition ( ) - GetPosition ( ) ) ;
2010-02-01 12:13:52 -08:00
matrix4x4d temp ;
dt . ship - > GetRotMatrix ( temp ) ;
2011-02-17 20:06:05 -08:00
dt . fromRot = Quaterniond : : FromMatrix4x4 ( temp ) ;
2010-02-01 12:13:52 -08:00
}
2009-08-06 04:19:22 -07:00
2010-02-01 12:13:52 -08:00
SpaceStationType : : positionOrient_t shipOrient ;
2010-03-05 05:16:11 -08:00
bool onRails = m_type - > GetDockAnimPositionOrient ( i , dt . stage , dt . stagePos , dt . fromPos , shipOrient , dt . ship ) ;
2012-07-04 12:13:48 -07:00
2010-02-01 12:13:52 -08:00
if ( onRails ) {
2010-03-05 05:16:11 -08:00
dt . ship - > SetPosition ( GetPosition ( ) + rot * shipOrient . pos ) ;
2009-08-07 07:34:14 -07:00
wantRot = matrix4x4d : : MakeRotMatrix (
2010-02-01 12:13:52 -08:00
shipOrient . xaxis , shipOrient . yaxis ,
2011-02-17 19:11:10 -08:00
shipOrient . xaxis . Cross ( shipOrient . yaxis ) ) * rot ;
2010-02-01 12:13:52 -08:00
// use quaternion spherical linear interpolation to do
// rotation smoothly
2011-02-17 20:06:05 -08:00
Quaterniond wantQuat = Quaterniond : : FromMatrix4x4 ( wantRot ) ;
Quaterniond q = Quaterniond : : Nlerp ( dt . fromRot , wantQuat , dt . stagePos ) ;
2010-02-01 12:13:52 -08:00
wantRot = q . ToMatrix4x4 < double > ( ) ;
2010-10-18 05:13:44 -07:00
// wantRot.Renormalize();
2010-02-01 12:13:52 -08:00
dt . ship - > SetRotMatrix ( wantRot ) ;
} else {
if ( dt . stage > = 0 ) {
// set docked
2009-08-02 05:40:09 -07:00
dt . ship - > SetDockedWith ( this , i ) ;
2012-08-28 15:30:50 -07:00
LuaEvent : : Queue ( " onShipDocked " , dt . ship , this ) ;
2010-02-01 12:13:52 -08:00
} else {
if ( ! dt . ship - > IsEnabled ( ) ) {
// launch ship
dt . ship - > Enable ( ) ;
dt . ship - > SetFlightState ( Ship : : FLYING ) ;
dt . ship - > SetAngVelocity ( GetFrame ( ) - > GetAngVelocity ( ) ) ;
dt . ship - > SetForce ( vector3d ( 0 , 0 , 0 ) ) ;
dt . ship - > SetTorque ( vector3d ( 0 , 0 , 0 ) ) ;
2010-03-11 07:46:04 -08:00
if ( m_type - > dockMethod = = SpaceStationType : : SURFACE ) {
2011-02-07 16:37:09 -08:00
dt . ship - > SetThrusterState ( 1 , 1.0 ) ; // up
2010-03-11 07:46:04 -08:00
} else {
dt . ship - > SetVelocity ( GetFrame ( ) - > GetStasisVelocityAtPosition ( dt . ship - > GetPosition ( ) ) ) ;
2011-02-07 16:37:09 -08:00
dt . ship - > SetThrusterState ( 2 , - 1.0 ) ; // forward
2010-03-11 07:46:04 -08:00
}
2012-08-28 15:30:50 -07:00
LuaEvent : : Queue ( " onShipUndocked " , dt . ship , this ) ;
2010-02-01 12:13:52 -08:00
}
2009-08-02 05:40:09 -07:00
}
2010-02-01 12:13:52 -08:00
}
if ( ( dt . stage < 0 ) & & ( ( - dt . stage ) > m_type - > numUndockStages ) ) {
dt . stage = 0 ;
dt . ship = 0 ;
2009-08-02 05:40:09 -07:00
}
2010-01-12 10:42:51 -08:00
}
for ( int i = 0 ; i < MAX_DOCKING_PORTS ; i + + ) {
2011-02-17 20:06:05 -08:00
m_openAnimState [ i ] = Clamp ( m_openAnimState [ i ] , 0.0 , 1.0 ) ;
m_dockAnimState [ i ] = Clamp ( m_dockAnimState [ i ] , 0.0 , 1.0 ) ;
2009-08-02 05:40:09 -07:00
}
}
2010-03-16 09:51:50 -07:00
void SpaceStation : : DoLawAndOrder ( )
{
Sint64 fine , crimeBitset ;
Polit : : GetCrime ( & crimeBitset , & fine ) ;
2011-06-24 02:45:41 -07:00
if ( Pi : : player - > GetFlightState ( ) ! = Ship : : DOCKED
& & m_numPoliceDocked
2010-03-16 09:51:50 -07:00
& & ( fine > 1000 )
2011-05-10 17:57:37 -07:00
& & ( GetPositionRelTo ( static_cast < Body * > ( Pi : : player ) ) . Length ( ) < 100000.0 ) ) {
2010-03-16 09:51:50 -07:00
int port = GetFreeDockingPort ( ) ;
if ( port ! = - 1 ) {
m_numPoliceDocked - - ;
// Make police ship intent on killing the player
Ship * ship = new Ship ( ShipType : : LADYBIRD ) ;
2011-01-30 23:14:27 -08:00
ship - > AIKill ( Pi : : player ) ;
2010-03-16 09:51:50 -07:00
ship - > SetFrame ( GetFrame ( ) ) ;
ship - > SetDockedWith ( this , port ) ;
2011-11-19 02:33:36 -08:00
Pi : : game - > GetSpace ( ) - > AddBody ( ship ) ;
2010-03-16 09:51:50 -07:00
{ // blue and white thang
ShipFlavour f ;
f . type = ShipType : : LADYBIRD ;
2012-03-26 12:52:10 -07:00
f . regid = Lang : : POLICE_SHIP_REGISTRATION ;
2010-03-16 09:51:50 -07:00
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 ;
2011-04-18 04:59:46 -07:00
ship - > ResetFlavour ( & f ) ;
2010-03-16 09:51:50 -07:00
}
2010-12-25 16:45:45 -08:00
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 ) ;
2012-03-25 16:10:18 -07:00
ship - > UpdateStats ( ) ;
2010-03-16 09:51:50 -07:00
}
}
}
2009-06-22 06:02:59 -07:00
void SpaceStation : : TimeStepUpdate ( const float timeStep )
{
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
2009-08-03 04:16:31 -07:00
DoDockingAnimation ( timeStep ) ;
2010-03-16 09:51:50 -07:00
DoLawAndOrder ( ) ;
2009-06-22 06:02:59 -07:00
}
2008-09-07 16:32:16 -07:00
bool SpaceStation : : IsGroundStation ( ) const
{
2010-01-17 12:25:52 -08:00
return ( m_type - > dockMethod = = SpaceStationType : : SURFACE ) ;
2008-09-07 16:32:16 -07:00
}
2010-02-01 12:13:52 -08:00
/* XXX THIS and PositionDockedShip do almost the same thing */
2008-09-10 07:15:20 -07:00
void SpaceStation : : OrientDockedShip ( Ship * ship , int port ) const
2008-09-07 16:32:16 -07:00
{
2010-02-01 12:13:52 -08:00
SpaceStationType : : positionOrient_t dport ;
2010-09-23 07:17:42 -07:00
if ( ! m_type - > GetDockAnimPositionOrient ( port , m_type - > numDockingStages , 1.0f , vector3d ( 0.0 ) , dport , ship ) ) {
Error ( " Space station model %s does not specify valid ship_dock_anim positions " , m_type - > modelName ) ;
}
2010-02-01 12:13:52 -08:00
// const positionOrient_t *dport = &this->port[port];
2010-01-17 12:25:52 -08:00
const int dockMethod = m_type - > dockMethod ;
2008-09-07 16:32:16 -07:00
if ( dockMethod = = SpaceStationType : : SURFACE ) {
matrix4x4d stationRot ;
GetRotMatrix ( stationRot ) ;
2011-02-17 19:11:10 -08:00
vector3d port_z = dport . xaxis . Cross ( dport . yaxis ) ;
2010-02-01 12:13:52 -08:00
matrix4x4d rot = stationRot * matrix4x4d : : MakeRotMatrix ( dport . xaxis , dport . yaxis , port_z ) ;
vector3d pos = GetPosition ( ) + stationRot * dport . pos ;
2008-09-10 09:00:25 -07:00
// position with wheels perfectly on ground :D
Aabb aabb ;
ship - > GetAabb ( aabb ) ;
pos + = stationRot * vector3d ( 0 , - aabb . min . y , 0 ) ;
ship - > SetPosition ( pos ) ;
2008-09-07 16:32:16 -07:00
ship - > SetRotMatrix ( rot ) ;
}
}
2012-04-01 10:22:47 -07:00
int SpaceStation : : GetFreeDockingPort ( ) const
2010-03-16 09:51:50 -07:00
{
for ( int i = 0 ; i < m_type - > numDockingPorts ; i + + ) {
if ( m_shipDocking [ i ] . ship = = 0 ) {
return i ;
}
}
return - 1 ;
}
2010-02-01 12:13:52 -08:00
void SpaceStation : : SetDocked ( Ship * ship , int port )
{
PositionDockedShip ( ship , port ) ;
m_shipDocking [ port ] . ship = ship ;
m_shipDocking [ port ] . stage = m_type - > numDockingStages + 1 ;
}
2009-10-01 08:42:49 -07:00
void SpaceStation : : PositionDockedShip ( Ship * ship , int port )
2008-09-07 16:32:16 -07:00
{
2010-02-01 12:13:52 -08:00
SpaceStationType : : positionOrient_t dport ;
2010-03-13 10:33:15 -08:00
PiVerify ( m_type - > GetDockAnimPositionOrient ( port , m_type - > numDockingStages , 1.0f , vector3d ( 0.0 ) , dport , ship ) ) ;
2010-02-01 12:13:52 -08:00
// const positionOrient_t *dport = &this->port[port];
2010-01-17 12:25:52 -08:00
const int dockMethod = m_type - > dockMethod ;
2008-09-07 16:32:16 -07:00
if ( dockMethod = = SpaceStationType : : ORBITAL ) {
2009-10-01 08:42:49 -07:00
matrix4x4d rot ;
GetRotMatrix ( rot ) ;
2010-02-01 12:13:52 -08:00
vector3d p = GetPosition ( ) + rot * dport . pos ;
2012-07-04 12:13:48 -07:00
2009-08-02 05:40:09 -07:00
ship - > SetFrame ( GetFrame ( ) ) ;
2009-10-01 08:42:49 -07:00
ship - > SetPosition ( p ) ;
// duplicated from DoDockingAnimation()
2011-02-17 19:11:10 -08:00
vector3d zaxis = dport . xaxis . Cross ( dport . yaxis ) ;
2010-02-01 12:13:52 -08:00
ship - > SetRotMatrix ( matrix4x4d : : MakeRotMatrix ( dport . xaxis ,
dport . yaxis , zaxis ) * rot ) ;
2009-10-01 08:42:49 -07:00
} else {
2009-08-01 10:23:51 -07:00
Aabb aabb ;
ship - > GetAabb ( aabb ) ;
2008-09-07 16:32:16 -07:00
2009-08-01 10:23:51 -07:00
matrix4x4d stationRot ;
2008-09-07 16:32:16 -07:00
GetRotMatrix ( stationRot ) ;
2011-02-17 19:11:10 -08:00
vector3d port_z = dport . xaxis . Cross ( dport . yaxis ) ;
2010-02-01 12:13:52 -08:00
matrix4x4d rot = stationRot * matrix4x4d : : MakeRotMatrix ( dport . xaxis , dport . yaxis , port_z ) ;
2009-08-01 10:23:51 -07:00
// position slightly (1m) off landing surface
2010-02-01 12:13:52 -08:00
vector3d pos = GetPosition ( ) + stationRot * ( dport . pos +
2012-07-04 12:13:48 -07:00
dport . yaxis -
2010-02-01 12:13:52 -08:00
dport . yaxis * aabb . min . y ) ;
2009-08-01 10:23:51 -07:00
ship - > SetPosition ( pos ) ;
2008-09-07 16:32:16 -07:00
ship - > SetRotMatrix ( rot ) ;
2009-10-01 08:42:49 -07:00
}
}
2010-09-23 07:17:42 -07:00
bool SpaceStation : : LaunchShip ( Ship * ship , int port )
2009-10-01 08:42:49 -07:00
{
2010-09-23 07:17:42 -07:00
/* XXX bad to keep duplicating this */
if ( m_type - > dockOneAtATimePlease ) {
for ( int i = 0 ; i < m_type - > numDockingPorts ; i + + ) {
if ( m_shipDocking [ i ] . ship & & m_shipDocking [ i ] . stage & &
( m_shipDocking [ i ] . stage ! = m_type - > numDockingStages + 1 ) ) {
return false ;
}
}
}
2010-03-05 05:16:11 -08:00
matrix4x4d rot ;
GetRotMatrix ( rot ) ;
2010-03-11 07:46:04 -08:00
shipDocking_t & sd = m_shipDocking [ port ] ;
sd . ship = ship ;
sd . stage = - 1 ;
sd . stagePos = 0 ;
sd . fromPos = rot . InverseOf ( ) * ( ship - > GetPosition ( ) - GetPosition ( ) ) ;
{
matrix4x4d temp ;
ship - > GetRotMatrix ( temp ) ;
2011-02-17 20:06:05 -08:00
sd . fromRot = Quaterniond : : FromMatrix4x4 ( temp ) ;
2008-09-07 16:32:16 -07:00
}
2010-03-11 07:46:04 -08:00
ship - > SetFlightState ( Ship : : DOCKING ) ;
2011-04-23 03:37:29 -07:00
2009-10-01 08:42:49 -07:00
PositionDockedShip ( ship , port ) ;
2010-09-23 07:17:42 -07:00
return true ;
2008-09-07 16:32:16 -07:00
}
2009-08-03 04:16:31 -07:00
bool SpaceStation : : GetDockingClearance ( Ship * s , std : : string & outMsg )
2008-08-11 08:45:25 -07:00
{
2009-08-03 04:16:31 -07:00
for ( int i = 0 ; i < MAX_DOCKING_PORTS ; i + + ) {
2010-02-01 12:13:52 -08:00
if ( i > = m_type - > numDockingPorts ) break ;
2010-03-05 05:16:11 -08:00
if ( ( m_shipDocking [ i ] . ship = = s ) & & ( m_shipDocking [ i ] . stage > 0 ) ) {
2011-08-23 20:18:53 -07:00
outMsg = stringf ( Lang : : CLEARANCE_ALREADY_GRANTED_BAY_N , formatarg ( " bay " , i + 1 ) ) ;
2009-08-03 04:16:31 -07:00
return true ;
}
}
for ( int i = 0 ; i < MAX_DOCKING_PORTS ; i + + ) {
2010-02-01 12:13:52 -08:00
if ( i > = m_type - > numDockingPorts ) break ;
2009-08-03 04:16:31 -07:00
if ( m_shipDocking [ i ] . ship ! = 0 ) continue ;
shipDocking_t & sd = m_shipDocking [ i ] ;
sd . ship = s ;
2010-02-01 12:13:52 -08:00
sd . stage = 1 ;
2009-08-03 04:16:31 -07:00
sd . stagePos = 0 ;
2011-08-23 20:18:53 -07:00
outMsg = stringf ( Lang : : CLEARANCE_GRANTED_BAY_N , formatarg ( " bay " , i + 1 ) ) ;
2009-08-03 04:16:31 -07:00
return true ;
}
2011-07-27 03:46:56 -07:00
outMsg = Lang : : CLEARANCE_DENIED_NO_BAYS ;
2009-08-03 04:16:31 -07:00
return false ;
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-10-22 04:02:19 -07:00
bool SpaceStation : : OnCollision ( Object * b , Uint32 flags , double relVel )
2008-06-24 03:17:31 -07:00
{
2010-09-23 07:17:42 -07:00
if ( ( flags & 0x10 ) & & ( b - > IsType ( Object : : SHIP ) ) ) {
Ship * s = static_cast < Ship * > ( b ) ;
2010-03-05 05:16:11 -08:00
matrix4x4d rot ;
GetRotMatrix ( rot ) ;
2012-07-04 12:13:48 -07:00
2010-09-23 07:17:42 -07:00
bool canDock = true ;
int port = - 1 ;
for ( int i = 0 ; i < MAX_DOCKING_PORTS ; i + + ) {
if ( m_shipDocking [ i ] . ship = = s ) { port = i ; break ; }
}
if ( m_type - > dockOneAtATimePlease ) {
for ( int i = 0 ; i < m_type - > numDockingPorts ; i + + ) {
2011-04-27 03:00:33 -07:00
if ( m_shipDocking [ i ] . ship & & m_shipDocking [ i ] . stage ! = 1 & &
2010-09-23 07:17:42 -07:00
( m_shipDocking [ i ] . stage ! = m_type - > numDockingStages + 1 ) ) {
canDock = false ;
break ;
}
}
} else {
// for non-dockOneAtATimePlease, the ship is expected
// to hit the right docking trigger surface for that port
if ( m_shipDocking [ flags & 0xf ] . ship ! = s ) canDock = false ;
}
if ( port = = - 1 ) canDock = false ;
2010-03-05 05:16:11 -08:00
2008-07-13 02:32:40 -07:00
// hitting docking area of a station
2010-09-23 07:17:42 -07:00
if ( canDock ) {
2010-03-05 05:16:11 -08:00
SpaceStationType : : positionOrient_t dport ;
// why stage 2? Because stage 1 is permission to dock
// granted, stage 2 is start of docking animation.
2010-09-23 07:17:42 -07:00
PiVerify ( m_type - > GetDockAnimPositionOrient ( port , 2 , 0.0f , vector3d ( 0.0 ) , dport , s ) ) ;
2012-07-04 12:13:48 -07:00
2008-11-07 08:50:24 -08:00
double speed = s - > GetVelocity ( ) . Length ( ) ;
2012-07-04 12:13:48 -07:00
2008-09-07 16:32:16 -07:00
// must be oriented sensibly and have wheels down
if ( IsGroundStation ( ) ) {
2010-03-05 05:16:11 -08:00
matrix4x4d shiprot ;
s - > GetRotMatrix ( shiprot ) ;
matrix4x4d invShipRot = shiprot . InverseOf ( ) ;
2012-07-04 12:13:48 -07:00
2010-03-05 05:16:11 -08:00
vector3d dockingNormal = rot * dport . yaxis ;
2008-09-07 16:32:16 -07:00
// check player is sortof sensibly oriented for landing
2011-02-17 17:01:00 -08:00
const double dot = vector3d ( invShipRot [ 1 ] , invShipRot [ 5 ] , invShipRot [ 9 ] ) . Dot ( dockingNormal ) ;
2011-08-18 18:48:37 -07:00
if ( ( dot < 0.99 ) | | ( s - > GetWheelState ( ) < 1.0 ) ) return false ;
2008-09-07 16:32:16 -07:00
}
2012-07-04 12:13:48 -07:00
2008-09-07 16:32:16 -07:00
if ( ( speed < MAX_LANDING_SPEED ) & &
( ! s - > GetDockedWith ( ) ) & &
2010-09-23 07:17:42 -07:00
( m_shipDocking [ port ] . stage = = 1 ) ) {
2009-08-02 05:40:09 -07:00
// if there is more docking port anim to do,
// don't set docked yet
2010-02-01 12:13:52 -08:00
if ( m_type - > numDockingStages > = 2 ) {
2010-09-23 07:17:42 -07:00
shipDocking_t & sd = m_shipDocking [ port ] ;
2009-08-02 05:40:09 -07:00
sd . ship = s ;
2010-02-01 12:13:52 -08:00
sd . stage = 2 ;
2009-08-02 05:40:09 -07:00
sd . stagePos = 0 ;
2010-03-05 05:16:11 -08:00
sd . fromPos = rot . InverseOf ( ) * ( s - > GetPosition ( ) - GetPosition ( ) ) ;
2010-02-01 12:13:52 -08:00
matrix4x4d temp ;
s - > GetRotMatrix ( temp ) ;
2011-02-17 20:06:05 -08:00
sd . fromRot = Quaterniond : : FromMatrix4x4 ( temp ) ;
2009-09-29 06:58:48 -07:00
s - > Disable ( ) ;
2011-08-27 13:32:04 -07:00
s - > ClearThrusterState ( ) ;
2009-08-02 05:40:09 -07:00
s - > SetFlightState ( Ship : : DOCKING ) ;
} else {
2010-09-23 07:17:42 -07:00
s - > SetDockedWith ( this , port ) ;
2012-08-28 15:30:50 -07:00
LuaEvent : : Queue ( " onShipDocked " , s , this ) ;
2009-08-02 05:40:09 -07:00
}
2008-07-13 02:32:40 -07:00
}
2008-06-24 03:17:31 -07:00
}
2010-09-23 07:17:42 -07:00
return false ;
2008-06-24 03:17:31 -07:00
} else {
return true ;
}
}
2011-11-14 14:09:29 -08:00
void SpaceStation : : NotifyRemoved ( const Body * const removedBody )
2009-08-02 05:40:09 -07:00
{
for ( int i = 0 ; i < MAX_DOCKING_PORTS ; i + + ) {
2011-11-14 14:09:29 -08:00
if ( m_shipDocking [ i ] . ship = = removedBody ) {
2009-08-02 05:40:09 -07:00
m_shipDocking [ i ] . ship = 0 ;
}
}
}
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
// * multiple suns
// * sun positions relative to up direction i.e. light is dimmed as suns set
// * 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
// * 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 ( ) ;
double dist = upDir . Length ( ) ;
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-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
const vector3d lightDir = ( l - > GetBody ( ) - > GetInterpolatedPositionRelTo ( planet - > GetFrame ( ) ) . Normalized ( ) ) ;
sunAngle = lightDir . Dot ( upDir ) ;
} else
// light is the default light for systems without lights
sunAngle = 1.0 ;
//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
const double endAngle = - 0.08 ;
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-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
2012-07-19 05:15:52 -07:00
double fraction = ( 0.4 + 0.4 * (
2012-07-24 22:51:17 -07:00
1.0 - light_clamped * ( Clamp ( ( opticalThicknessFraction ) , 0.0 , 1.0 ) )
2012-07-14 13:51:03 -07:00
) * 0.8 + 0.2 ) ; //fraction goes from 0.6 to 1.0
// fraction of light left over to be lit directly
intensity = ( 1.0 - fraction ) * intensity ;
// scale ambient by amount of light
ambient = fraction * ( Clamp ( ( light ) , 0.0 , 1.0 ) ) ;
}
2012-07-19 05:15:52 -07:00
// if twilight or night fade in model at close ranges by increasing scene ambient lighting to minIllumination
// dist is distance in meters to model in camera space
2012-07-23 10:51:51 -07:00
void FadeInModelIfDark ( Graphics : : Renderer * r , double modelRadius , double dist , double fadeInEnd , double fadeInLength , double illumination , double minIllumination )
2012-07-19 05:15:52 -07:00
{
if ( illumination < = minIllumination ) {
2012-07-23 10:51:51 -07:00
fadeInEnd = std : : max ( std : : max ( modelRadius , 10.0 ) , fadeInEnd ) ;
2012-07-19 05:15:52 -07:00
const double fadeInStart = fadeInLength + fadeInEnd ;
// 0 to 1 as dist goes from fadeInEnd to fadeInStart
double sceneAmbient = 1.0 - ( Clamp ( dist , fadeInEnd , fadeInStart ) - fadeInEnd ) / ( ( fadeInStart - fadeInEnd ) ) ;
//set scene ambient to the amount needed to take illumination level to 0.2
sceneAmbient * = minIllumination - illumination ;
r - > SetAmbientColor ( Color ( sceneAmbient , sceneAmbient , sceneAmbient , 1.0 ) ) ;
}
}
2012-07-23 10:51:51 -07:00
// Renders space station and adjacent city if applicable
// For orbital starports: renders as normal
// For surface starports:
// 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
// Adds an ambient light at close ranges if dark by manipulating the global ambient level
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
2009-08-03 04:16:31 -07:00
for ( int i = 0 ; i < MAX_DOCKING_PORTS ; 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-07-28 15:11:23 -07:00
Body * b = GetFrame ( ) - > m_astroBody ;
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-09 06:47:47 -07:00
RenderLmrModel ( viewCoords , viewTransform ) ;
2012-07-28 15:11:23 -07:00
}
else {
Planet * planet = static_cast < Planet * > ( b ) ;
2012-07-20 02:41:05 -07: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 ;
2012-08-11 02:36:42 -07:00
CalcLighting ( planet , ambient , intensity , lightSources ) ;
std : : vector < Graphics : : Light > origLights , newLights ;
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 ca = light . GetAmbient ( ) ;
Color cs = light . GetSpecular ( ) ;
2012-07-24 07:51:18 -07:00
ca . r = c . r * float ( ambient ) ;
ca . g = c . g * float ( ambient ) ;
ca . b = c . b * float ( ambient ) ;
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 . SetAmbient ( ca ) ;
light . SetSpecular ( cs ) ;
newLights . push_back ( light ) ;
2012-07-09 06:47:47 -07:00
}
2012-08-11 02:36:42 -07:00
r - > SetLights ( newLights . size ( ) , & newLights [ 0 ] ) ;
2012-07-09 06:47:47 -07:00
2012-07-19 05:15:52 -07:00
double overallLighting = ambient + intensity ;
2012-07-09 06:47:47 -07:00
2012-07-14 13:51:03 -07:00
// turn off global ambient color
2012-08-20 17:34:29 -07:00
const Color oldAmbient = r - > GetAmbientColor ( ) ;
2012-08-19 08:49:54 -07:00
r - > SetAmbientColor ( Color : : BLACK ) ;
2012-07-14 13:51:03 -07:00
2012-07-19 05:15:52 -07:00
// as the camera gets close adjust scene ambient so that intensity+ambient = minIllumination
2012-07-23 10:51:51 -07:00
double fadeInEnd , fadeInLength , minIllumination ;
if ( Graphics : : AreShadersEnabled ( ) ) {
2012-07-29 01:50:41 -07:00
minIllumination = 0.125 ;
2012-07-23 10:51:51 -07:00
fadeInEnd = 800.0 ;
2012-07-29 01:50:41 -07:00
fadeInLength = 2000.0 ;
2012-07-23 10:51:51 -07:00
}
else {
2012-07-29 01:50:41 -07:00
minIllumination = 0.25 ;
2012-07-23 10:51:51 -07:00
fadeInEnd = 1500.0 ;
fadeInLength = 3000.0 ;
}
2012-07-09 06:47:47 -07:00
/* don't render city if too far away */
if ( viewCoords . Length ( ) < 1000000.0 ) {
2012-09-05 15:09:27 -07:00
r - > SetAmbientColor ( Color : : BLACK ) ;
2009-07-28 08:36:37 -07:00
if ( ! m_adjacentCity ) {
m_adjacentCity = new CityOnPlanet ( planet , this , m_sbody - > seed ) ;
}
2012-07-19 05:15:52 -07:00
m_adjacentCity - > Render ( r , camera , this , viewCoords , viewTransform , overallLighting , minIllumination ) ;
2012-07-09 06:47:47 -07:00
}
2012-09-05 15:09:27 -07:00
r - > SetAmbientColor ( Color : : BLACK ) ;
FadeInModelIfDark ( r , GetLmrCollMesh ( ) - > GetBoundingRadius ( ) ,
viewCoords . Length ( ) , fadeInEnd , fadeInLength , overallLighting , minIllumination ) ;
RenderLmrModel ( viewCoords , viewTransform ) ;
2012-07-24 07:51:18 -07:00
// restore old lights
2012-08-11 02:36:42 -07:00
r - > SetLights ( origLights . size ( ) , & origLights [ 0 ] ) ;
2012-07-14 13:51:03 -07:00
// restore old ambient color
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-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
2011-12-02 08:10:21 -08:00
for ( int i = 0 ; i < MAX_DOCKING_PORTS ; i + + ) {
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 ) ) ;
matrix4x4d rot ;
GetRotMatrix ( rot ) ;
matrix4x4d m ;
Frame : : GetFrameRenderTransform ( GetFrame ( ) , relTo , m ) ;
return m * ( GetInterpolatedPosition ( ) + ( rot * dport . pos ) ) ;
}
}
return GetInterpolatedPositionRelTo ( relTo ) ;
2012-01-18 02:43:28 -08:00
}