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"
|
2008-09-18 19:23:48 -07:00
|
|
|
#include "StarSystem.h"
|
|
|
|
#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"
|
2010-03-16 09:51:50 -07:00
|
|
|
#include "Polit.h"
|
|
|
|
#include "Space.h"
|
2010-08-08 03:31:24 -07:00
|
|
|
#include <algorithm>
|
2011-07-27 03:46:56 -07:00
|
|
|
#include "Lang.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();
|
|
|
|
model->PushAttributeToLuaStack(key);
|
|
|
|
assert(lua_istable(L, -1));
|
|
|
|
|
|
|
|
int num = lua_objlen(L, -1);
|
|
|
|
*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
|
|
|
}
|
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-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);
|
2010-09-05 08:09:32 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
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);
|
|
|
|
outPosOrient.pos = vector3f(*MyLuaVec::checkVec(L, -1));
|
|
|
|
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);
|
|
|
|
outPosOrient.xaxis = vector3f(*MyLuaVec::checkVec(L, -1));
|
|
|
|
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);
|
|
|
|
outPosOrient.yaxis = vector3f(*MyLuaVec::checkVec(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;
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
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;
|
|
|
|
lua_State *L = LmrGetLuaState();
|
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));
|
2010-09-05 08:09:32 -07:00
|
|
|
vector3f *_from = MyLuaVec::pushVec(L);
|
|
|
|
*_from = vector3f(from);
|
|
|
|
// push model aabb as lua table: { min: vec3, max: vec3 }
|
|
|
|
{
|
|
|
|
Aabb aabb;
|
|
|
|
ship->GetAabb(aabb);
|
|
|
|
lua_createtable (L, 0, 2);
|
|
|
|
vector3f *v = MyLuaVec::pushVec(L);
|
|
|
|
*v = aabb.max;
|
|
|
|
lua_setfield(L, -2, "max");
|
|
|
|
v = MyLuaVec::pushVec(L);
|
|
|
|
*v = aabb.min;
|
|
|
|
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);
|
|
|
|
outPosOrient.pos = vector3f(*MyLuaVec::checkVec(L, -1));
|
|
|
|
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);
|
|
|
|
outPosOrient.xaxis = vector3f(*MyLuaVec::checkVec(L, -1));
|
|
|
|
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);
|
|
|
|
outPosOrient.yaxis = vector3f(*MyLuaVec::checkVec(L, -1));
|
|
|
|
lua_pop(L, 1);
|
|
|
|
} else {
|
|
|
|
gotOrient = false;
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
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();
|
2010-09-23 07:17:42 -07:00
|
|
|
printf("one at a time? %s\n", t.dockOneAtATimePlease ? "yes" : "no");
|
2010-01-31 08:18:37 -08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2011-04-30 05:35:26 -07:00
|
|
|
printf("%lu orbital station types and %lu surface station types.\n", orbitalStationTypes.size(), surfaceStationTypes.size());
|
2010-01-17 12:25:52 -08:00
|
|
|
}
|
2008-07-02 04:44:19 -07:00
|
|
|
|
2010-01-17 13:22:09 -08:00
|
|
|
float SpaceStation::GetDesiredAngVel() const
|
|
|
|
{
|
|
|
|
return m_type->angVel;
|
|
|
|
}
|
|
|
|
|
2010-05-22 10:26:25 -07:00
|
|
|
void SpaceStation::Save(Serializer::Writer &wr)
|
2008-09-18 19:23:48 -07:00
|
|
|
{
|
2010-05-22 10:26:25 -07:00
|
|
|
ModelBody::Save(wr);
|
|
|
|
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++) {
|
2010-05-22 10:26:25 -07:00
|
|
|
wr.Int32(Serializer::LookupBody(m_shipDocking[i].ship));
|
|
|
|
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
|
|
|
}
|
2010-05-22 10:26:25 -07:00
|
|
|
wr.Double(m_lastUpdatedShipyard);
|
|
|
|
wr.Int32(Serializer::LookupSystemBody(m_sbody));
|
|
|
|
wr.Int32(m_numPoliceDocked);
|
2008-09-18 19:23:48 -07:00
|
|
|
}
|
|
|
|
|
2010-05-22 10:26:25 -07:00
|
|
|
void SpaceStation::Load(Serializer::Reader &rd)
|
2008-09-18 19:23:48 -07:00
|
|
|
{
|
2010-05-22 10:26:25 -07:00
|
|
|
ModelBody::Load(rd);
|
|
|
|
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
|
|
|
}
|
2010-05-22 10:26:25 -07:00
|
|
|
m_lastUpdatedShipyard = rd.Double();
|
|
|
|
m_sbody = Serializer::LookupSystemBody(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
|
|
|
}
|
|
|
|
|
2009-08-02 05:40:09 -07:00
|
|
|
void SpaceStation::PostLoadFixup()
|
|
|
|
{
|
|
|
|
for (int i=0; i<MAX_DOCKING_PORTS; i++) {
|
2011-05-12 05:31:08 -07:00
|
|
|
m_shipDocking[i].ship = static_cast<Ship*>(Serializer::LookupBody(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;
|
|
|
|
}
|
|
|
|
|
2009-07-02 04:39:14 -07:00
|
|
|
SpaceStation::SpaceStation(const SBody *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);
|
2008-12-05 14:02:43 -08:00
|
|
|
for (int i=1; i<Equip::TYPE_MAX; i++) {
|
2009-09-29 06:58:32 -07:00
|
|
|
if (EquipType::types[i].slot == Equip::SLOT_CARGO) {
|
|
|
|
m_equipmentStock[i] = Pi::rng.Int32(0,100) * Pi::rng.Int32(1,100);
|
|
|
|
} else {
|
2009-11-01 06:04:17 -08:00
|
|
|
if (EquipType::types[i].techLevel <= Pi::currentSystem->m_techlevel)
|
|
|
|
m_equipmentStock[i] = Pi::rng.Int32(0,100);
|
2009-09-29 06:58:32 -07:00
|
|
|
}
|
2008-12-05 14:02:43 -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;
|
|
|
|
}
|
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;
|
2011-03-14 22:34:46 -07:00
|
|
|
for(int i=0; i<4; i++) m_staticSlot[i] = false;
|
2010-01-17 12:25:52 -08:00
|
|
|
MTRand rand(m_sbody->seed);
|
|
|
|
if (m_sbody->type == SBody::TYPE_STARPORT_ORBITAL) {
|
|
|
|
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()) ];
|
|
|
|
}
|
2011-06-06 04:35:51 -07:00
|
|
|
GetLmrObjParams().argDoubles[ARG_STATION_BAY1_STAGE] = 1.0;
|
|
|
|
GetLmrObjParams().argDoubles[ARG_STATION_BAY1_POS] = 1.0;
|
2010-01-17 12:25:52 -08:00
|
|
|
SetModel(m_type->modelName, true);
|
2011-04-03 14:03:53 -07:00
|
|
|
m_bbCreated = false;
|
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();
|
|
|
|
}
|
|
|
|
|
2009-06-22 06:02:59 -07:00
|
|
|
void SpaceStation::UpdateShipyard()
|
|
|
|
{
|
|
|
|
if (m_shipsOnSale.size() == 0) {
|
|
|
|
// fill shipyard
|
|
|
|
for (int i=Pi::rng.Int32(20); i; i--) {
|
|
|
|
ShipFlavour s;
|
|
|
|
ShipFlavour::MakeTrulyRandom(s);
|
|
|
|
m_shipsOnSale.push_back(s);
|
|
|
|
}
|
|
|
|
} else if (Pi::rng.Int32(2)) {
|
|
|
|
// add one
|
|
|
|
ShipFlavour s;
|
|
|
|
ShipFlavour::MakeTrulyRandom(s);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
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);
|
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);
|
2011-04-30 03:22:35 -07:00
|
|
|
CreateBB();
|
2011-04-19 04:40:08 -07:00
|
|
|
Pi::luaOnShipDocked.Queue(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
|
|
|
}
|
2011-04-23 03:37:29 -07:00
|
|
|
Pi::luaOnShipUndocked.Queue(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);
|
|
|
|
Space::AddBody(ship);
|
|
|
|
{ // blue and white thang
|
|
|
|
ShipFlavour f;
|
|
|
|
f.type = ShipType::LADYBIRD;
|
2011-07-27 03:46:56 -07:00
|
|
|
strncpy(f.regid, Lang::POLICE_SHIP_REGISTRATION, 16);
|
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);
|
2011-03-12 21:42:20 -08:00
|
|
|
ship->UpdateMass();
|
2010-03-16 09:51:50 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-22 06:02:59 -07:00
|
|
|
void SpaceStation::TimeStepUpdate(const float timeStep)
|
|
|
|
{
|
|
|
|
if (Pi::GetGameTime() > m_lastUpdatedShipyard) {
|
2011-04-04 14:19:44 -07:00
|
|
|
if (m_bbCreated) Pi::luaOnUpdateBB.Queue(this);
|
2009-06-22 06:02:59 -07:00
|
|
|
UpdateShipyard();
|
|
|
|
// update again in an hour or two
|
|
|
|
m_lastUpdatedShipyard = Pi::GetGameTime() + 3600.0 + 3600.0*Pi::rng.Double();
|
|
|
|
}
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-16 09:51:50 -07:00
|
|
|
int SpaceStation::GetFreeDockingPort()
|
|
|
|
{
|
|
|
|
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;
|
2009-10-01 08:42:49 -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 +
|
|
|
|
dport.yaxis -
|
|
|
|
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:12:27 -07:00
|
|
|
outMsg = stringf_old(256, Lang::CLEARANCE_ALREADY_GRANTED_BAY_N, 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:12:27 -07:00
|
|
|
outMsg = stringf_old(256, Lang::CLEARANCE_GRANTED_BAY_N, 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 {
|
|
|
|
return Polit::IsCommodityLegal(Pi::currentSystem, t);
|
|
|
|
}
|
|
|
|
|
2009-11-09 06:24:29 -08:00
|
|
|
Sint64 SpaceStation::GetPrice(Equip::Type t) const {
|
|
|
|
Sint64 mul = 100 + Pi::currentSystem->GetCommodityBasePriceModPercent(t);
|
2011-05-10 17:57:37 -07:00
|
|
|
return (mul * Sint64(EquipType::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);
|
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));
|
2008-09-07 16:32:16 -07:00
|
|
|
|
2008-11-07 08:50:24 -08:00
|
|
|
double speed = s->GetVelocity().Length();
|
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();
|
2008-09-07 16:32:16 -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
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
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);
|
2011-04-30 03:22:35 -07:00
|
|
|
CreateBB();
|
2011-04-19 04:40:08 -07:00
|
|
|
Pi::luaOnShipDocked.Queue(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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-04 07:06:36 -08:00
|
|
|
void SpaceStation::NotifyDeleted(const Body* const deletedBody)
|
2009-08-02 05:40:09 -07:00
|
|
|
{
|
|
|
|
for (int i=0; i<MAX_DOCKING_PORTS; i++) {
|
2009-11-04 07:06:36 -08:00
|
|
|
if (m_shipDocking[i].ship == deletedBody) {
|
2009-08-02 05:40:09 -07:00
|
|
|
m_shipDocking[i].ship = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-17 12:25:52 -08:00
|
|
|
static std::vector<LmrModel*> s_advertModels;
|
2009-10-06 08:05:40 -07:00
|
|
|
|
2009-11-18 06:59:51 -08:00
|
|
|
void SpaceStation::Render(const vector3d &viewCoords, const matrix4x4d &viewTransform)
|
2008-06-24 03:17:31 -07:00
|
|
|
{
|
2009-10-06 08:05:40 -07:00
|
|
|
/* Well this is nice... */
|
|
|
|
static int poo=0;
|
|
|
|
if (!poo) {
|
|
|
|
poo = 1;
|
2010-01-17 12:25:52 -08:00
|
|
|
LmrGetModelsWithTag("advert", s_advertModels);
|
2009-10-06 08:05:40 -07:00
|
|
|
}
|
|
|
|
// it is silly to do this every render call
|
|
|
|
//
|
|
|
|
// random advert models in pFlag[16 .. 19]
|
|
|
|
// station name in pText[0]
|
|
|
|
// docking port in pText[1]
|
|
|
|
MTRand rand;
|
|
|
|
rand.seed(m_sbody->seed);
|
2010-01-17 12:25:52 -08:00
|
|
|
|
2010-01-18 09:58:57 -08:00
|
|
|
LmrObjParams ¶ms = GetLmrObjParams();
|
2010-01-17 12:25:52 -08:00
|
|
|
/* random advert models */
|
2010-01-18 09:58:57 -08:00
|
|
|
params.argStrings[4] = s_advertModels[rand.Int32(s_advertModels.size())]->GetName();
|
|
|
|
params.argStrings[5] = s_advertModels[rand.Int32(s_advertModels.size())]->GetName();
|
|
|
|
params.argStrings[6] = s_advertModels[rand.Int32(s_advertModels.size())]->GetName();
|
|
|
|
params.argStrings[7] = s_advertModels[rand.Int32(s_advertModels.size())]->GetName();
|
|
|
|
params.argStrings[0] = 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-06-06 14:16:53 -07:00
|
|
|
params.argDoubles[ARG_STATION_BAY1_STAGE + i] = double(m_shipDocking[i].stage);
|
|
|
|
params.argDoubles[ARG_STATION_BAY1_POS + i] = m_shipDocking[i].stagePos;
|
2009-08-03 04:16:31 -07:00
|
|
|
}
|
2010-02-01 12:13:52 -08:00
|
|
|
|
2010-01-18 09:58:57 -08:00
|
|
|
RenderLmrModel(viewCoords, viewTransform);
|
2009-09-09 10:20:26 -07:00
|
|
|
|
|
|
|
/* don't render city if too far away */
|
2009-11-18 06:59:51 -08:00
|
|
|
if (viewCoords.Length() > 1000000.0) return;
|
2009-07-18 07:09:31 -07:00
|
|
|
|
|
|
|
// find planet Body*
|
|
|
|
Planet *planet;
|
|
|
|
{
|
|
|
|
Body *_planet = GetFrame()->m_astroBody;
|
|
|
|
if ((!_planet) || !_planet->IsType(Object::PLANET)) {
|
|
|
|
// orbital spaceport -- don't make city turds
|
2009-07-28 08:36:37 -07:00
|
|
|
} else {
|
|
|
|
planet = static_cast<Planet*>(_planet);
|
|
|
|
|
|
|
|
if (!m_adjacentCity) {
|
|
|
|
m_adjacentCity = new CityOnPlanet(planet, this, m_sbody->seed);
|
|
|
|
}
|
2009-11-18 06:59:51 -08:00
|
|
|
m_adjacentCity->Render(this, viewCoords, viewTransform);
|
2009-07-27 04:28:05 -07:00
|
|
|
}
|
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)
|
|
|
|
{
|
|
|
|
for (int i=0; i<4; i++) {
|
|
|
|
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;
|
|
|
|
Pi::luaOnCreateBB.Queue(this);
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
for (std::vector<BBAdvert>::const_iterator i = m_bbAdverts.begin(); i != m_bbAdverts.end(); i++)
|
|
|
|
if (i->ref == ref)
|
|
|
|
return &(*i);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SpaceStation::RemoveBBAdvert(int ref)
|
|
|
|
{
|
|
|
|
for (std::vector<BBAdvert>::iterator i = m_bbAdverts.begin(); i != m_bbAdverts.end(); i++)
|
|
|
|
if (i->ref == ref) {
|
|
|
|
m_bbAdverts.erase(i);
|
2011-07-20 04:46:10 -07:00
|
|
|
onBulletinBoardAdvertDeleted.emit(*i);
|
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;
|
|
|
|
for (std::vector<BBAdvert>::const_iterator i = m_bbAdverts.begin(); i != m_bbAdverts.end(); i++)
|
|
|
|
ads.push_back(&(*i));
|
|
|
|
return ads;
|
|
|
|
}
|
|
|
|
|