2012-12-31 17:36:52 -08:00
|
|
|
// Copyright © 2008-2013 Pioneer Developers. See AUTHORS.txt for details
|
2012-09-15 17:59:15 -07:00
|
|
|
// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
|
2012-09-12 04:38:30 -07:00
|
|
|
|
2008-06-24 03:17:31 -07:00
|
|
|
#include "SpaceStation.h"
|
2012-11-17 17:56:43 -08:00
|
|
|
#include "CityOnPlanet.h"
|
|
|
|
#include "FileSystem.h"
|
2008-12-27 17:02:45 -08:00
|
|
|
#include "Frame.h"
|
2012-11-17 17:56:43 -08:00
|
|
|
#include "Game.h"
|
|
|
|
#include "gameconsts.h"
|
|
|
|
#include "Lang.h"
|
|
|
|
#include "LuaEvent.h"
|
|
|
|
#include "LuaVector.h"
|
2008-12-05 14:02:43 -08:00
|
|
|
#include "Pi.h"
|
2012-11-17 17:56:43 -08:00
|
|
|
#include "Planet.h"
|
2009-08-07 07:34:14 -07:00
|
|
|
#include "Player.h"
|
2009-10-08 16:49:43 -07:00
|
|
|
#include "Polit.h"
|
2010-03-16 09:51:50 -07:00
|
|
|
#include "Polit.h"
|
2012-11-17 17:56:43 -08:00
|
|
|
#include "Serializer.h"
|
|
|
|
#include "Ship.h"
|
2010-03-16 09:51:50 -07:00
|
|
|
#include "Space.h"
|
2011-08-23 20:18:53 -07:00
|
|
|
#include "StringF.h"
|
2012-11-17 17:56:43 -08:00
|
|
|
#include "galaxy/StarSystem.h"
|
2012-07-24 22:51:17 -07:00
|
|
|
#include "graphics/Graphics.h"
|
2012-11-17 17:56:43 -08:00
|
|
|
#include <algorithm>
|
2010-01-31 08:18:37 -08:00
|
|
|
|
2010-01-17 12:25:52 -08:00
|
|
|
void SpaceStation::Init()
|
2013-01-06 05:47:38 -08:00
|
|
|
{
|
2012-11-17 17:56:43 -08:00
|
|
|
SpaceStationType::Init();
|
2010-01-17 12:25:52 -08:00
|
|
|
}
|
2008-07-02 04:44:19 -07:00
|
|
|
|
2011-10-08 21:05:09 -07:00
|
|
|
void SpaceStation::Uninit()
|
|
|
|
{
|
2012-11-17 17:56:43 -08:00
|
|
|
SpaceStationType::Uninit();
|
2011-10-08 21:05:09 -07:00
|
|
|
}
|
|
|
|
|
2011-11-17 21:41:00 -08:00
|
|
|
void SpaceStation::Save(Serializer::Writer &wr, Space *space)
|
2008-09-18 19:23:48 -07:00
|
|
|
{
|
2011-11-17 21:41:00 -08:00
|
|
|
ModelBody::Save(wr, space);
|
2010-05-22 10:26:25 -07:00
|
|
|
MarketAgent::Save(wr);
|
2010-08-03 03:28:18 -07:00
|
|
|
wr.Int32(Equip::TYPE_MAX);
|
2008-12-05 14:02:43 -08:00
|
|
|
for (int i=0; i<Equip::TYPE_MAX; i++) {
|
2011-05-10 17:57:37 -07:00
|
|
|
wr.Int32(int(m_equipmentStock[i]));
|
2008-12-05 14:02:43 -08:00
|
|
|
}
|
2009-06-22 06:02:59 -07:00
|
|
|
// save shipyard
|
2010-05-22 10:26:25 -07:00
|
|
|
wr.Int32(m_shipsOnSale.size());
|
2013-02-11 22:24:48 -08:00
|
|
|
for (std::vector<ShipOnSale>::iterator i = m_shipsOnSale.begin();
|
2009-06-22 06:02:59 -07:00
|
|
|
i != m_shipsOnSale.end(); ++i) {
|
2013-02-11 22:24:48 -08:00
|
|
|
wr.String((*i).id);
|
|
|
|
wr.String((*i).regId);
|
2013-02-13 14:40:05 -08:00
|
|
|
(*i).skin.Save(wr);
|
2009-06-22 06:02:59 -07:00
|
|
|
}
|
2013-01-24 14:02:01 -08:00
|
|
|
wr.Int32(m_shipDocking.size());
|
2013-06-26 18:26:55 -07:00
|
|
|
for (Uint32 i=0; i<m_shipDocking.size(); i++) {
|
2011-11-17 00:34:50 -08:00
|
|
|
wr.Int32(space->GetIndexForBody(m_shipDocking[i].ship));
|
2010-05-22 10:26:25 -07:00
|
|
|
wr.Int32(m_shipDocking[i].stage);
|
2011-05-10 17:57:37 -07:00
|
|
|
wr.Float(float(m_shipDocking[i].stagePos));
|
2010-05-22 10:26:25 -07:00
|
|
|
wr.Vector3d(m_shipDocking[i].fromPos);
|
|
|
|
wr.WrQuaternionf(m_shipDocking[i].fromRot);
|
2009-08-02 05:40:09 -07:00
|
|
|
}
|
2013-02-03 05:03:52 -08:00
|
|
|
// store each of the bay groupings
|
|
|
|
wr.Int32(mBayGroups.size());
|
2013-06-26 18:26:55 -07:00
|
|
|
for (Uint32 i=0; i<mBayGroups.size(); i++) {
|
2013-02-03 05:03:52 -08:00
|
|
|
wr.Int32(mBayGroups[i].minShipSize);
|
|
|
|
wr.Int32(mBayGroups[i].maxShipSize);
|
|
|
|
wr.Bool(mBayGroups[i].inUse);
|
|
|
|
wr.Int32(mBayGroups[i].bayIDs.size());
|
2013-06-26 18:26:55 -07:00
|
|
|
for (Uint32 j=0; j<mBayGroups[i].bayIDs.size(); j++) {
|
2013-02-03 05:03:52 -08:00
|
|
|
wr.Int32(mBayGroups[i].bayIDs[j]);
|
|
|
|
}
|
|
|
|
}
|
2012-11-18 21:25:00 -08:00
|
|
|
|
2012-02-24 14:37:57 -08:00
|
|
|
wr.Bool(m_bbCreated);
|
2010-05-22 10:26:25 -07:00
|
|
|
wr.Double(m_lastUpdatedShipyard);
|
2012-04-17 18:53:53 -07:00
|
|
|
wr.Int32(space->GetIndexForSystemBody(m_sbody));
|
2010-05-22 10:26:25 -07:00
|
|
|
wr.Int32(m_numPoliceDocked);
|
2013-02-16 18:09:36 -08:00
|
|
|
|
2013-04-27 13:49:06 -07:00
|
|
|
wr.Double(m_doorAnimationStep);
|
|
|
|
wr.Double(m_doorAnimationState);
|
|
|
|
|
2013-02-16 18:09:36 -08:00
|
|
|
m_navLights->Save(wr);
|
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
|
|
|
}
|
2013-06-26 18:26:55 -07:00
|
|
|
// load shipyard
|
|
|
|
const Uint32 numShipsForSale = rd.Int32();
|
|
|
|
for (Uint32 i=0; i<numShipsForSale; i++) {
|
2013-02-11 22:24:48 -08:00
|
|
|
ShipType::Id id(rd.String());
|
|
|
|
std::string regId(rd.String());
|
2013-02-13 14:40:05 -08:00
|
|
|
SceneGraph::ModelSkin skin;
|
|
|
|
skin.Load(rd);
|
|
|
|
ShipOnSale sos(id, regId, skin);
|
2013-02-11 22:24:48 -08:00
|
|
|
m_shipsOnSale.push_back(sos);
|
2009-06-22 06:02:59 -07:00
|
|
|
}
|
2013-06-26 18:26:55 -07:00
|
|
|
const Uint32 numShipDocking = rd.Int32();
|
2013-01-24 14:02:01 -08:00
|
|
|
m_shipDocking.reserve(numShipDocking);
|
2013-06-26 18:26:55 -07:00
|
|
|
for (Uint32 i=0; i<numShipDocking; i++) {
|
2013-01-24 14:02:01 -08:00
|
|
|
m_shipDocking.push_back(shipDocking_t());
|
|
|
|
shipDocking_t &sd = m_shipDocking.back();
|
|
|
|
sd.shipIndex = rd.Int32();
|
|
|
|
sd.stage = rd.Int32();
|
|
|
|
sd.stagePos = rd.Float();
|
|
|
|
sd.fromPos = rd.Vector3d();
|
|
|
|
sd.fromRot = rd.RdQuaternionf();
|
2009-08-02 05:40:09 -07:00
|
|
|
}
|
2013-02-03 05:03:52 -08:00
|
|
|
// retrieve each of the bay groupings
|
2013-06-26 18:26:55 -07:00
|
|
|
const Uint32 numBays = rd.Int32();
|
2013-02-03 05:03:52 -08:00
|
|
|
mBayGroups.reserve(numBays);
|
2013-06-26 18:26:55 -07:00
|
|
|
for (Uint32 i=0; i<numBays; i++) {
|
2013-02-03 05:03:52 -08:00
|
|
|
mBayGroups.push_back(SpaceStationType::SBayGroup());
|
|
|
|
SpaceStationType::SBayGroup &bay = mBayGroups.back();
|
|
|
|
bay.minShipSize = rd.Int32();
|
|
|
|
bay.maxShipSize = rd.Int32();
|
|
|
|
bay.inUse = rd.Bool();
|
2013-06-26 18:26:55 -07:00
|
|
|
const Uint32 numBayIds = rd.Int32();
|
2013-02-03 05:03:52 -08:00
|
|
|
bay.bayIDs.reserve(numBayIds);
|
2013-06-26 18:26:55 -07:00
|
|
|
for (Uint32 j=0; j<numBayIds; j++) {
|
|
|
|
const Uint32 ID = rd.Int32();
|
2013-02-03 05:03:52 -08:00
|
|
|
bay.bayIDs.push_back(ID);
|
|
|
|
}
|
2009-08-02 05:40:09 -07:00
|
|
|
}
|
2012-11-18 21:25:00 -08:00
|
|
|
|
2012-02-24 14:37:57 -08:00
|
|
|
m_bbCreated = rd.Bool();
|
2010-05-22 10:26:25 -07:00
|
|
|
m_lastUpdatedShipyard = rd.Double();
|
2012-04-17 18:53:53 -07:00
|
|
|
m_sbody = space->GetSystemBodyByIndex(rd.Int32());
|
2010-08-03 03:28:18 -07:00
|
|
|
m_numPoliceDocked = rd.Int32();
|
2013-04-27 13:49:06 -07:00
|
|
|
|
|
|
|
m_doorAnimationStep = rd.Double();
|
|
|
|
m_doorAnimationState = rd.Double();
|
|
|
|
|
2010-01-17 12:25:52 -08:00
|
|
|
InitStation();
|
2013-02-16 18:09:36 -08:00
|
|
|
|
|
|
|
m_navLights->Load(rd);
|
2008-09-18 19:23:48 -07:00
|
|
|
}
|
|
|
|
|
2011-11-17 13:38:06 -08:00
|
|
|
void SpaceStation::PostLoadFixup(Space *space)
|
2009-08-02 05:40:09 -07:00
|
|
|
{
|
2012-12-11 19:18:42 -08:00
|
|
|
ModelBody::PostLoadFixup(space);
|
2013-06-26 18:26:55 -07:00
|
|
|
for (Uint32 i=0; i<m_shipDocking.size(); i++) {
|
2011-11-17 00:34:50 -08:00
|
|
|
m_shipDocking[i].ship = static_cast<Ship*>(space->GetBodyByIndex(m_shipDocking[i].shipIndex));
|
2009-08-02 05:40:09 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-17 18:53:53 -07:00
|
|
|
SpaceStation::SpaceStation(const SystemBody *sbody): ModelBody()
|
2008-06-24 03:17:31 -07:00
|
|
|
{
|
2009-07-02 04:39:14 -07:00
|
|
|
m_sbody = sbody;
|
2009-06-22 06:02:59 -07:00
|
|
|
m_lastUpdatedShipyard = 0;
|
2010-03-16 09:51:50 -07:00
|
|
|
m_numPoliceDocked = Pi::rng.Int32(3,10);
|
2012-02-24 14:37:57 -08:00
|
|
|
m_bbCreated = false;
|
2012-09-18 22:57:01 -07:00
|
|
|
m_bbShuffled = false;
|
2011-11-08 13:39:53 -08:00
|
|
|
|
2012-11-25 19:05:43 -08:00
|
|
|
m_oldAngDisplacement = 0.0;
|
2011-10-12 19:18:46 -07:00
|
|
|
|
2013-05-02 04:05:14 -07:00
|
|
|
m_doorAnimationStep = m_doorAnimationState = 0.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;
|
2012-07-22 07:44:30 -07:00
|
|
|
for(int i=0; i<NUM_STATIC_SLOTS; i++) m_staticSlot[i] = false;
|
2013-02-14 02:46:57 -08:00
|
|
|
Random rand(m_sbody->seed);
|
2012-11-18 10:13:47 -08:00
|
|
|
bool ground = m_sbody->type == SystemBody::TYPE_STARPORT_ORBITAL ? false : true;
|
2013-06-26 18:07:40 -07:00
|
|
|
if (ground) {
|
2013-01-24 14:02:01 -08:00
|
|
|
m_type = &SpaceStationType::surfaceStationTypes[ rand.Int32(SpaceStationType::surfaceStationTypes.size()) ];
|
2013-06-26 18:07:40 -07:00
|
|
|
} else {
|
2013-01-24 14:02:01 -08:00
|
|
|
m_type = &SpaceStationType::orbitalStationTypes[ rand.Int32(SpaceStationType::orbitalStationTypes.size()) ];
|
|
|
|
}
|
|
|
|
|
2013-05-14 14:58:05 -07:00
|
|
|
if(m_shipDocking.empty()) {
|
|
|
|
m_shipDocking.reserve(m_type->numDockingPorts);
|
|
|
|
for (unsigned int i=0; i<m_type->numDockingPorts; i++) {
|
|
|
|
m_shipDocking.push_back(shipDocking_t());
|
|
|
|
}
|
|
|
|
// only (re)set these if we've not come from the ::Load method
|
|
|
|
m_doorAnimationStep = m_doorAnimationState = 0.0;
|
|
|
|
}
|
|
|
|
assert(m_shipDocking.size() == m_type->numDockingPorts);
|
2012-07-20 02:41:05 -07:00
|
|
|
|
2013-02-03 05:03:52 -08:00
|
|
|
// This SpaceStation's bay groups is an instance of...
|
|
|
|
mBayGroups = m_type->bayGroups;
|
2012-07-20 02:41:05 -07:00
|
|
|
|
2012-11-18 10:13:47 -08:00
|
|
|
SetStatic(ground); // orbital stations are dynamic now
|
2013-02-08 13:59:03 -08:00
|
|
|
|
2013-05-14 14:58:05 -07:00
|
|
|
// XXX hack. if we loaded a game then ModelBody::Load already restored the
|
|
|
|
// model and we shouldn't overwrite it
|
|
|
|
if (!GetModel())
|
2013-02-08 13:59:03 -08:00
|
|
|
SetModel(m_type->modelName.c_str());
|
2012-11-25 19:05:43 -08:00
|
|
|
|
2013-10-29 04:44:49 -07:00
|
|
|
m_navLights.reset(new NavLights(GetModel(), 2.2f));
|
2013-02-16 08:36:19 -08:00
|
|
|
m_navLights->SetEnabled(true);
|
|
|
|
|
2012-11-26 15:40:03 -08:00
|
|
|
if (ground) SetClipRadius(CITY_ON_PLANET_RADIUS); // overrides setmodel
|
2013-02-18 23:45:58 -08:00
|
|
|
|
|
|
|
m_doorAnimation = GetModel()->FindAnimation("doors");
|
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
|
|
|
}
|
|
|
|
|
2013-02-11 22:24:48 -08:00
|
|
|
void SpaceStation::ReplaceShipOnSale(int idx, const ShipOnSale &with)
|
2009-06-22 09:44:17 -07:00
|
|
|
{
|
2013-02-11 22:24:48 -08:00
|
|
|
m_shipsOnSale[idx] = with;
|
2009-06-22 09:44:17 -07:00
|
|
|
onShipsForSaleChanged.emit();
|
|
|
|
}
|
|
|
|
|
2012-07-02 18:15:47 -07:00
|
|
|
// Fill the list of starships on sale. Ships that
|
|
|
|
// can't fit atmo shields are only available in
|
|
|
|
// atmosphereless environments
|
2009-06-22 06:02:59 -07:00
|
|
|
void SpaceStation::UpdateShipyard()
|
|
|
|
{
|
2012-07-02 18:15:47 -07:00
|
|
|
bool atmospheric = false;
|
|
|
|
if (IsGroundStation()) {
|
2012-11-16 17:07:15 -08:00
|
|
|
Body *planet = GetFrame()->GetBody();
|
2012-07-02 18:15:47 -07:00
|
|
|
atmospheric = planet->GetSystemBody()->HasAtmosphere();
|
|
|
|
}
|
|
|
|
|
2013-02-11 22:24:48 -08:00
|
|
|
const std::vector<ShipType::Id> &ships = atmospheric ? ShipType::playable_atmospheric_ships : ShipType::player_ships;
|
|
|
|
|
|
|
|
unsigned int toAdd = 0, toRemove = 0;
|
|
|
|
|
|
|
|
if (m_shipsOnSale.size() == 0)
|
2009-06-22 06:02:59 -07:00
|
|
|
// fill shipyard
|
2013-02-11 22:24:48 -08:00
|
|
|
toAdd = Pi::rng.Int32(20);
|
|
|
|
|
|
|
|
else if (Pi::rng.Int32(2))
|
2009-06-22 06:02:59 -07:00
|
|
|
// add one
|
2013-02-11 22:24:48 -08:00
|
|
|
toAdd = 1;
|
|
|
|
|
|
|
|
else if(m_shipsOnSale.size() > 0)
|
2009-06-22 06:02:59 -07:00
|
|
|
// remove one
|
2013-02-11 22:24:48 -08:00
|
|
|
toRemove = 1;
|
|
|
|
|
|
|
|
else
|
|
|
|
// nothing happens
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (; toAdd > 0; toAdd--) {
|
|
|
|
ShipType::Id id = ships[Pi::rng.Int32(ships.size())];
|
|
|
|
std::string regId = Ship::MakeRandomLabel();
|
2013-02-13 14:40:05 -08:00
|
|
|
SceneGraph::ModelSkin skin;
|
2013-02-13 21:57:58 -08:00
|
|
|
skin.SetRandomColors(Pi::rng);
|
|
|
|
skin.SetPattern(Pi::rng.Int32(0, Pi::FindModel(id)->GetNumPatterns()));
|
2013-02-13 21:59:15 -08:00
|
|
|
skin.SetLabel(regId);
|
2013-02-13 14:40:05 -08:00
|
|
|
ShipOnSale sos(id, regId, skin);
|
2013-02-11 22:24:48 -08:00
|
|
|
m_shipsOnSale.push_back(sos);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; toRemove > 0; toRemove--) {
|
2009-06-22 06:02:59 -07:00
|
|
|
int pos = Pi::rng.Int32(m_shipsOnSale.size());
|
|
|
|
m_shipsOnSale.erase(m_shipsOnSale.begin() + pos);
|
|
|
|
}
|
2013-02-11 22:24:48 -08:00
|
|
|
|
2009-06-22 06:02:59 -07:00
|
|
|
onShipsForSaleChanged.emit();
|
|
|
|
}
|
|
|
|
|
2012-11-18 21:25:00 -08:00
|
|
|
void SpaceStation::NotifyRemoved(const Body* const removedBody)
|
|
|
|
{
|
2013-06-26 18:26:55 -07:00
|
|
|
for (Uint32 i=0; i<m_shipDocking.size(); i++) {
|
2012-11-18 21:25:00 -08:00
|
|
|
if (m_shipDocking[i].ship == removedBody) {
|
|
|
|
m_shipDocking[i].ship = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int SpaceStation::GetMyDockingPort(const Ship *s) const
|
|
|
|
{
|
2013-06-26 18:26:55 -07:00
|
|
|
for (Uint32 i=0; i<m_shipDocking.size(); i++) {
|
2012-11-18 21:25:00 -08:00
|
|
|
if (s == m_shipDocking[i].ship) return i;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-11-08 14:45:38 -08:00
|
|
|
int SpaceStation::NumShipsDocked() const
|
|
|
|
{
|
|
|
|
Sint32 numShipsDocked = 0;
|
|
|
|
for (Uint32 i=0; i<m_shipDocking.size(); i++) {
|
|
|
|
if (NULL != m_shipDocking[i].ship)
|
|
|
|
++numShipsDocked;
|
|
|
|
}
|
|
|
|
return numShipsDocked;
|
|
|
|
}
|
|
|
|
|
|
|
|
int SpaceStation::GetFreeDockingPort(const Ship *s) const
|
2012-11-18 21:25:00 -08:00
|
|
|
{
|
2013-03-11 13:53:03 -07:00
|
|
|
for (unsigned int i=0; i<m_type->numDockingPorts; i++) {
|
2012-11-18 21:25:00 -08:00
|
|
|
if (m_shipDocking[i].ship == 0) {
|
2013-11-08 14:45:38 -08:00
|
|
|
if(s) {
|
|
|
|
// fwing
|
|
|
|
// initial unoccupied check
|
|
|
|
if (m_shipDocking[i].ship != 0) continue;
|
|
|
|
|
|
|
|
// size-of-ship vs size-of-bay check
|
|
|
|
const SpaceStationType::SBayGroup *const pBayGroup = m_type->FindGroupByBay(i);
|
|
|
|
if( !pBayGroup ) continue;
|
|
|
|
|
|
|
|
const Aabb &bbox = s->GetAabb();
|
|
|
|
const double bboxRad = bbox.GetRadius();
|
|
|
|
|
|
|
|
if( pBayGroup->minShipSize < bboxRad && bboxRad < pBayGroup->maxShipSize ) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return i;
|
|
|
|
}
|
2012-11-18 21:25:00 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SpaceStation::SetDocked(Ship *ship, int port)
|
|
|
|
{
|
|
|
|
m_shipDocking[port].ship = ship;
|
|
|
|
m_shipDocking[port].stage = m_type->numDockingStages+1;
|
|
|
|
|
|
|
|
// have to do this crap again in case it was called directly (Ship::SetDockWith())
|
|
|
|
ship->SetFlightState(Ship::DOCKED);
|
|
|
|
ship->SetVelocity(vector3d(0.0));
|
|
|
|
ship->SetAngVelocity(vector3d(0.0));
|
|
|
|
ship->ClearThrusterState();
|
2012-12-15 16:22:24 -08:00
|
|
|
PositionDockedShip(ship, port);
|
2012-11-18 21:25:00 -08:00
|
|
|
}
|
|
|
|
|
2013-11-08 14:45:38 -08:00
|
|
|
void SpaceStation::SwapDockedShipsPort(Ship *ship, const int oldPort, const int newPort)
|
|
|
|
{
|
|
|
|
if( oldPort == newPort )
|
|
|
|
return;
|
|
|
|
|
|
|
|
// set new location
|
|
|
|
//SetDocked(ship, newPort);
|
|
|
|
ship->SetDockedWith(this, newPort);
|
|
|
|
|
|
|
|
m_shipDocking[oldPort].ship = 0;
|
|
|
|
m_shipDocking[oldPort].stage = 0;
|
|
|
|
}
|
|
|
|
|
2012-11-18 21:25:00 -08:00
|
|
|
bool SpaceStation::LaunchShip(Ship *ship, int port)
|
|
|
|
{
|
|
|
|
shipDocking_t &sd = m_shipDocking[port];
|
|
|
|
if (sd.stage < 0) return true; // already launching
|
2013-02-03 05:03:52 -08:00
|
|
|
if (IsPortLocked(port)) return false; // another ship docking
|
|
|
|
LockPort(port, true);
|
2012-11-18 21:25:00 -08:00
|
|
|
|
|
|
|
sd.ship = ship;
|
|
|
|
sd.stage = -1;
|
2013-02-25 09:47:04 -08:00
|
|
|
sd.stagePos = 0.0;
|
2012-11-18 21:25:00 -08:00
|
|
|
|
2013-02-18 23:45:58 -08:00
|
|
|
m_doorAnimationStep = 0.3; // open door
|
|
|
|
|
2013-02-25 09:47:04 -08:00
|
|
|
const Aabb& aabb = ship->GetAabb();
|
|
|
|
const matrix3x3d mt = ship->GetOrient();
|
|
|
|
const vector3d up = mt.VectorY().Normalized() * aabb.min.y;
|
2013-06-26 18:07:40 -07:00
|
|
|
|
2013-02-25 09:47:04 -08:00
|
|
|
sd.fromPos = (ship->GetPosition() - GetPosition() + up) * GetOrient(); // station space
|
|
|
|
sd.fromRot = Quaterniond::FromMatrix3x3(GetOrient().Transpose() * mt);
|
2012-11-18 21:25:00 -08:00
|
|
|
|
|
|
|
ship->SetFlightState(Ship::DOCKING);
|
2013-02-18 23:45:58 -08:00
|
|
|
|
2012-11-18 21:25:00 -08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SpaceStation::GetDockingClearance(Ship *s, std::string &outMsg)
|
|
|
|
{
|
2013-05-02 04:06:53 -07:00
|
|
|
assert(m_shipDocking.size() == m_type->numDockingPorts);
|
2013-06-26 18:26:55 -07:00
|
|
|
for (Uint32 i=0; i<m_shipDocking.size(); i++) {
|
2013-05-02 04:12:49 -07:00
|
|
|
if (m_shipDocking[i].ship == s) {
|
2012-11-18 21:25:00 -08:00
|
|
|
outMsg = stringf(Lang::CLEARANCE_ALREADY_GRANTED_BAY_N, formatarg("bay", i+1));
|
2013-05-02 04:12:49 -07:00
|
|
|
return (m_shipDocking[i].stage > 0); // grant docking only if the ship is not already docked/undocking
|
2012-11-18 21:25:00 -08:00
|
|
|
}
|
|
|
|
}
|
2013-06-26 18:26:55 -07:00
|
|
|
for (Uint32 i=0; i<m_shipDocking.size(); i++) {
|
2013-05-14 14:58:05 -07:00
|
|
|
// initial unoccupied check
|
2012-11-18 21:25:00 -08:00
|
|
|
if (m_shipDocking[i].ship != 0) continue;
|
2013-05-14 14:58:05 -07:00
|
|
|
|
|
|
|
// size-of-ship vs size-of-bay check
|
|
|
|
const SpaceStationType::SBayGroup *const pBayGroup = m_type->FindGroupByBay(i);
|
|
|
|
if( !pBayGroup ) continue;
|
|
|
|
|
|
|
|
const Aabb &bbox = s->GetAabb();
|
|
|
|
const double bboxRad = bbox.GetRadius();
|
|
|
|
|
|
|
|
if( pBayGroup->minShipSize < bboxRad && bboxRad < pBayGroup->maxShipSize ) {
|
|
|
|
shipDocking_t &sd = m_shipDocking[i];
|
|
|
|
sd.ship = s;
|
|
|
|
sd.stage = 1;
|
|
|
|
sd.stagePos = 0;
|
|
|
|
outMsg = stringf(Lang::CLEARANCE_GRANTED_BAY_N, formatarg("bay", i+1));
|
|
|
|
return true;
|
|
|
|
}
|
2012-11-18 21:25:00 -08:00
|
|
|
}
|
|
|
|
outMsg = Lang::CLEARANCE_DENIED_NO_BAYS;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SpaceStation::OnCollision(Object *b, Uint32 flags, double relVel)
|
|
|
|
{
|
|
|
|
if ((flags & 0x10) && (b->IsType(Object::SHIP))) {
|
|
|
|
Ship *s = static_cast<Ship*>(b);
|
|
|
|
|
|
|
|
int port = -1;
|
2013-06-26 18:26:55 -07:00
|
|
|
for (Uint32 i=0; i<m_shipDocking.size(); i++) {
|
2012-11-18 21:25:00 -08:00
|
|
|
if (m_shipDocking[i].ship == s) { port = i; break; }
|
|
|
|
}
|
|
|
|
if (port == -1) return false; // no permission
|
2013-03-12 12:15:51 -07:00
|
|
|
if (IsPortLocked(port)) {
|
|
|
|
return false;
|
2012-11-18 21:25:00 -08:00
|
|
|
}
|
|
|
|
if (m_shipDocking[port].stage != 1) return false; // already docking?
|
|
|
|
|
|
|
|
SpaceStationType::positionOrient_t dport;
|
|
|
|
// why stage 2? Because stage 1 is permission to dock
|
|
|
|
// granted, stage 2 is start of docking animation.
|
|
|
|
PiVerify(m_type->GetDockAnimPositionOrient(port, 2, 0.0, vector3d(0.0), dport, s));
|
|
|
|
|
|
|
|
// must be oriented sensibly and have wheels down
|
|
|
|
if (IsGroundStation()) {
|
|
|
|
vector3d dockingNormal = GetOrient()*dport.yaxis;
|
|
|
|
const double dot = s->GetOrient().VectorY().Dot(dockingNormal);
|
|
|
|
if ((dot < 0.99) || (s->GetWheelState() < 1.0)) return false; // <0.99 harsh?
|
|
|
|
if (s->GetVelocity().Length() > MAX_LANDING_SPEED) return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if there is more docking port anim to do, don't set docked yet
|
|
|
|
if (m_type->numDockingStages >= 2) {
|
|
|
|
shipDocking_t &sd = m_shipDocking[port];
|
|
|
|
sd.ship = s;
|
|
|
|
sd.stage = 2;
|
|
|
|
sd.stagePos = 0;
|
|
|
|
sd.fromPos = (s->GetPosition() - GetPosition()) * GetOrient(); // station space
|
|
|
|
sd.fromRot = Quaterniond::FromMatrix3x3(GetOrient().Transpose() * s->GetOrient());
|
2013-02-03 05:03:52 -08:00
|
|
|
LockPort(port, true);
|
2012-11-18 21:25:00 -08:00
|
|
|
|
|
|
|
s->SetFlightState(Ship::DOCKING);
|
|
|
|
s->SetVelocity(vector3d(0.0));
|
|
|
|
s->SetAngVelocity(vector3d(0.0));
|
|
|
|
s->ClearThrusterState();
|
|
|
|
} else {
|
|
|
|
s->SetDockedWith(this, port); // bounces back to SS::SetDocked()
|
|
|
|
LuaEvent::Queue("onShipDocked", s, this);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-18 23:45:58 -08:00
|
|
|
// XXX SGModel door animation. We have one station (hoop_spacestation) with a
|
|
|
|
// door, so this is pretty much based on how it does things. This all needs
|
|
|
|
// rewriting to handle triggering animations at waypoints.
|
|
|
|
//
|
|
|
|
// Docking:
|
|
|
|
// Stage 1 (clearance granted): open
|
|
|
|
// (clearance expired): close
|
|
|
|
// Docked: close
|
2013-06-26 18:07:40 -07:00
|
|
|
//
|
2013-02-18 23:45:58 -08:00
|
|
|
// Undocking:
|
|
|
|
// Stage -1 (LaunchShip): open
|
|
|
|
// Post-launch: close
|
2013-06-26 18:07:40 -07:00
|
|
|
//
|
2013-02-18 23:45:58 -08:00
|
|
|
|
2012-11-18 21:25:00 -08:00
|
|
|
void SpaceStation::DockingUpdate(const double timeStep)
|
2009-08-02 05:40:09 -07:00
|
|
|
{
|
2009-08-06 08:00:08 -07:00
|
|
|
vector3d p1, p2, zaxis;
|
2013-06-26 18:26:55 -07:00
|
|
|
for (Uint32 i=0; i<m_shipDocking.size(); i++) {
|
2009-08-02 05:40:09 -07:00
|
|
|
shipDocking_t &dt = m_shipDocking[i];
|
2010-02-01 12:13:52 -08:00
|
|
|
if (!dt.ship) continue;
|
2012-11-18 21:25:00 -08:00
|
|
|
// docked stage is m_type->numDockingPorts + 1 => ship docked
|
2010-02-01 12:13:52 -08:00
|
|
|
if (dt.stage > m_type->numDockingStages) continue;
|
2009-08-03 04:16:31 -07:00
|
|
|
|
2011-02-17 20:06:05 -08:00
|
|
|
double stageDuration = (dt.stage > 0 ?
|
2013-04-27 13:22:59 -07:00
|
|
|
m_type->GetDockAnimStageDuration(dt.stage-1) :
|
|
|
|
m_type->GetUndockAnimStageDuration(abs(dt.stage)-1));
|
2010-02-01 12:13:52 -08:00
|
|
|
dt.stagePos += timeStep / stageDuration;
|
2009-08-06 08:00:08 -07:00
|
|
|
|
2010-02-01 12:13:52 -08:00
|
|
|
if (dt.stage == 1) {
|
2012-11-18 21:25:00 -08:00
|
|
|
// SPECIAL stage! Docking granted but waiting for ship to dock
|
2013-02-18 23:45:58 -08:00
|
|
|
|
|
|
|
m_doorAnimationStep = 0.3; // open door
|
2009-08-03 04:16:31 -07:00
|
|
|
|
|
|
|
if (dt.stagePos >= 1.0) {
|
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;
|
2013-02-18 23:45:58 -08:00
|
|
|
m_doorAnimationStep = -0.3; // close door
|
2009-08-03 04:16:31 -07:00
|
|
|
}
|
2010-02-01 12:13:52 -08:00
|
|
|
continue;
|
|
|
|
}
|
2012-07-04 12:13:48 -07:00
|
|
|
|
2011-02-17 20:06:05 -08:00
|
|
|
if (dt.stagePos > 1.0) {
|
2012-12-30 13:52:40 -08:00
|
|
|
// use end position of last segment for start position of new segment
|
|
|
|
SpaceStationType::positionOrient_t dport;
|
|
|
|
PiVerify(m_type->GetDockAnimPositionOrient(i, dt.stage, 1.0f, dt.fromPos, dport, dt.ship));
|
2013-01-28 08:16:16 -08:00
|
|
|
matrix3x3d fromRot = matrix3x3d::FromVectors(dport.xaxis, dport.yaxis, dport.zaxis);
|
2012-12-30 13:52:40 -08:00
|
|
|
dt.fromRot = Quaterniond::FromMatrix3x3(fromRot);
|
|
|
|
dt.fromPos = dport.pos;
|
|
|
|
|
2012-11-18 21:25:00 -08:00
|
|
|
// transition between docking stages
|
2010-02-01 12:13:52 -08:00
|
|
|
dt.stagePos = 0;
|
|
|
|
if (dt.stage >= 0) dt.stage++;
|
|
|
|
else dt.stage--;
|
|
|
|
}
|
2009-08-06 04:19:22 -07:00
|
|
|
|
2012-11-23 13:49:47 -08:00
|
|
|
if (dt.stage < -m_type->shipLaunchStage && dt.ship->GetFlightState() != Ship::FLYING) {
|
2012-11-18 21:25:00 -08:00
|
|
|
// launch ship
|
|
|
|
dt.ship->SetFlightState(Ship::FLYING);
|
2012-12-08 17:07:16 -08:00
|
|
|
dt.ship->SetAngVelocity(GetAngVelocity());
|
2012-11-18 21:25:00 -08:00
|
|
|
if (m_type->dockMethod == SpaceStationType::SURFACE) {
|
|
|
|
dt.ship->SetThrusterState(1, 1.0); // up
|
2010-02-01 12:13:52 -08:00
|
|
|
} else {
|
2012-11-18 21:25:00 -08:00
|
|
|
dt.ship->SetThrusterState(2, -1.0); // forward
|
2009-08-02 05:40:09 -07:00
|
|
|
}
|
2012-11-18 21:25:00 -08:00
|
|
|
LuaEvent::Queue("onShipUndocked", dt.ship, this);
|
2010-02-01 12:13:52 -08:00
|
|
|
}
|
2012-11-18 21:25:00 -08:00
|
|
|
if (dt.stage < -m_type->numUndockStages) {
|
|
|
|
// undock animation finished, clear port
|
|
|
|
dt.stage = 0;
|
|
|
|
dt.ship = 0;
|
2013-02-03 05:03:52 -08:00
|
|
|
LockPort(i, false);
|
2013-02-18 23:45:58 -08:00
|
|
|
m_doorAnimationStep = -0.3; // close door
|
2012-11-18 21:25:00 -08:00
|
|
|
}
|
|
|
|
else if (dt.stage > m_type->numDockingStages) {
|
|
|
|
// set docked
|
|
|
|
dt.ship->SetDockedWith(this, i);
|
|
|
|
LuaEvent::Queue("onShipDocked", dt.ship, this);
|
2013-02-03 05:03:52 -08:00
|
|
|
LockPort(i, false);
|
2013-02-18 23:45:58 -08:00
|
|
|
m_doorAnimationStep = -0.3; // close door
|
2009-08-02 05:40:09 -07:00
|
|
|
}
|
2010-01-12 10:42:51 -08:00
|
|
|
}
|
2013-06-26 18:07:40 -07:00
|
|
|
|
2013-02-18 23:45:58 -08:00
|
|
|
m_doorAnimationState = Clamp(m_doorAnimationState + m_doorAnimationStep*timeStep, 0.0, 1.0);
|
|
|
|
if (m_doorAnimation)
|
|
|
|
m_doorAnimation->SetProgress(m_doorAnimationState);
|
2009-08-02 05:40:09 -07:00
|
|
|
}
|
|
|
|
|
2012-11-18 21:25:00 -08:00
|
|
|
void SpaceStation::PositionDockedShip(Ship *ship, int port) const
|
2010-03-16 09:51:50 -07:00
|
|
|
{
|
2012-11-18 21:25:00 -08:00
|
|
|
const shipDocking_t &dt = m_shipDocking[port];
|
|
|
|
SpaceStationType::positionOrient_t dport;
|
|
|
|
PiVerify(m_type->GetDockAnimPositionOrient(port, dt.stage, dt.stagePos, dt.fromPos, dport, ship));
|
2012-12-28 17:34:56 -08:00
|
|
|
assert(dt.ship == ship);
|
|
|
|
|
|
|
|
ship->SetPosition(GetPosition() + GetOrient()*dport.pos);
|
2012-11-18 21:25:00 -08:00
|
|
|
|
|
|
|
// Still in docking animation process?
|
|
|
|
if (dt.stage <= m_type->numDockingStages) {
|
2013-01-28 08:16:16 -08:00
|
|
|
matrix3x3d wantRot = matrix3x3d::FromVectors(dport.xaxis, dport.yaxis, dport.zaxis);
|
2012-11-18 21:25:00 -08:00
|
|
|
// use quaternion spherical linear interpolation to do
|
|
|
|
// rotation smoothly
|
|
|
|
Quaterniond wantQuat = Quaterniond::FromMatrix3x3(wantRot);
|
|
|
|
Quaterniond q = Quaterniond::Nlerp(dt.fromRot, wantQuat, dt.stagePos);
|
|
|
|
wantRot = q.ToMatrix3x3<double>();
|
2012-12-28 17:34:56 -08:00
|
|
|
ship->SetOrient(GetOrient() * wantRot);
|
|
|
|
} else {
|
2012-12-27 16:16:57 -08:00
|
|
|
// Note: ship bounding box is used to generate dport.pos
|
2013-01-28 08:16:16 -08:00
|
|
|
ship->SetOrient(GetOrient() * matrix3x3d::FromVectors(dport.xaxis, dport.yaxis, dport.zaxis));
|
2010-03-16 09:51:50 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-18 10:13:47 -08:00
|
|
|
void SpaceStation::StaticUpdate(const float timeStep)
|
2009-06-22 06:02:59 -07:00
|
|
|
{
|
2012-01-18 02:43:28 -08:00
|
|
|
bool update = false;
|
|
|
|
|
|
|
|
// if there's no BB and there are ships here, make one
|
2013-11-08 14:45:38 -08:00
|
|
|
if (!m_bbCreated && NumShipsDocked() > 0) {
|
2012-01-18 02:43:28 -08:00
|
|
|
CreateBB();
|
|
|
|
update = true;
|
|
|
|
}
|
2012-07-04 12:13:48 -07:00
|
|
|
|
2012-01-18 02:43:28 -08:00
|
|
|
// if there is and it hasn't had an update for a while, update it
|
|
|
|
else if (Pi::game->GetTime() > m_lastUpdatedShipyard) {
|
2012-08-28 15:30:50 -07:00
|
|
|
LuaEvent::Queue("onUpdateBB", this);
|
2012-01-18 02:43:28 -08:00
|
|
|
update = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (update) {
|
2009-06-22 06:02:59 -07:00
|
|
|
UpdateShipyard();
|
|
|
|
// update again in an hour or two
|
2011-11-21 13:33:03 -08:00
|
|
|
m_lastUpdatedShipyard = Pi::game->GetTime() + 3600.0 + 3600.0*Pi::rng.Double();
|
2009-06-22 06:02:59 -07:00
|
|
|
}
|
2012-01-18 02:43:28 -08:00
|
|
|
|
2013-01-23 09:52:34 -08:00
|
|
|
DoLawAndOrder(timeStep);
|
2012-11-18 21:25:00 -08:00
|
|
|
DockingUpdate(timeStep);
|
2013-02-16 08:36:19 -08:00
|
|
|
m_navLights->Update(timeStep);
|
2009-06-22 06:02:59 -07:00
|
|
|
}
|
|
|
|
|
2012-11-18 10:13:47 -08:00
|
|
|
void SpaceStation::TimeStepUpdate(const float timeStep)
|
|
|
|
{
|
2013-02-14 02:46:57 -08:00
|
|
|
// rotate the thing
|
2012-11-25 19:05:43 -08:00
|
|
|
double len = m_type->angVel * timeStep;
|
|
|
|
if (!is_zero_exact(len)) {
|
2012-12-27 17:12:36 -08:00
|
|
|
matrix3x3d r = matrix3x3d::RotateY(-len); // RotateY is backwards
|
2012-11-18 10:13:47 -08:00
|
|
|
SetOrient(r * GetOrient());
|
|
|
|
}
|
2012-11-25 19:05:43 -08:00
|
|
|
m_oldAngDisplacement = len;
|
2012-11-18 10:13:47 -08:00
|
|
|
|
2012-11-18 21:25:00 -08:00
|
|
|
// reposition the ships that are docked or docking here
|
2013-03-11 13:53:03 -07:00
|
|
|
for (unsigned int i=0; i<m_type->numDockingPorts; i++) {
|
2012-11-18 21:25:00 -08:00
|
|
|
const shipDocking_t &dt = m_shipDocking[i];
|
2013-02-16 08:36:19 -08:00
|
|
|
if (!dt.ship) { //free
|
|
|
|
m_navLights->SetColor(i+1, NavLights::NAVLIGHT_GREEN);
|
|
|
|
continue;
|
|
|
|
}
|
2013-04-27 14:13:34 -07:00
|
|
|
if (dt.stage == 1) {//reserved
|
2013-02-16 08:36:19 -08:00
|
|
|
m_navLights->SetColor(i+1, NavLights::NAVLIGHT_YELLOW);
|
2013-04-27 14:13:34 -07:00
|
|
|
continue;
|
|
|
|
}
|
2013-02-16 08:36:19 -08:00
|
|
|
if (dt.ship->GetFlightState() == Ship::FLYING)
|
|
|
|
continue;
|
2012-11-18 21:25:00 -08:00
|
|
|
PositionDockedShip(dt.ship, i);
|
2013-02-16 08:36:19 -08:00
|
|
|
m_navLights->SetColor(i+1, NavLights::NAVLIGHT_RED); //docked
|
2009-10-01 08:42:49 -07:00
|
|
|
}
|
2013-02-18 23:45:58 -08:00
|
|
|
|
2013-10-20 13:55:15 -07:00
|
|
|
ModelBody::TimeStepUpdate(timeStep);
|
2009-10-01 08:42:49 -07:00
|
|
|
}
|
|
|
|
|
2012-11-25 19:05:43 -08:00
|
|
|
void SpaceStation::UpdateInterpTransform(double alpha)
|
|
|
|
{
|
|
|
|
double len = m_oldAngDisplacement * (1.0-alpha);
|
|
|
|
if (!is_zero_exact(len)) {
|
2012-12-27 17:12:36 -08:00
|
|
|
matrix3x3d rot = matrix3x3d::RotateY(len); // RotateY is backwards
|
2012-11-25 19:05:43 -08:00
|
|
|
m_interpOrient = rot * GetOrient();
|
|
|
|
}
|
|
|
|
else m_interpOrient = GetOrient();
|
|
|
|
m_interpPos = GetPosition();
|
|
|
|
}
|
|
|
|
|
2012-11-18 21:25:00 -08:00
|
|
|
bool SpaceStation::IsGroundStation() const
|
2009-10-01 08:42:49 -07:00
|
|
|
{
|
2012-11-18 21:25:00 -08:00
|
|
|
return (m_type->dockMethod == SpaceStationType::SURFACE);
|
2008-09-07 16:32:16 -07:00
|
|
|
}
|
|
|
|
|
2008-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
|
|
|
}
|
|
|
|
|
2012-07-23 10:51:51 -07:00
|
|
|
// Renders space station and adjacent city if applicable
|
|
|
|
// For orbital starports: renders as normal
|
2012-12-22 14:26:30 -08:00
|
|
|
// For surface starports:
|
2012-07-23 10:51:51 -07:00
|
|
|
// Lighting: Calculates available light for model and splits light between directly and ambiently lit
|
|
|
|
// Lighting is done by manipulating global lights or setting uniforms in atmospheric models shader
|
2013-06-26 18:07:40 -07:00
|
|
|
static const double SQRMAXCITYDIST = 1e5 * 1e5;
|
|
|
|
|
2012-07-24 22:51:17 -07:00
|
|
|
void SpaceStation::Render(Graphics::Renderer *r, const Camera *camera, const vector3d &viewCoords, const matrix4x4d &viewTransform)
|
2008-06-24 03:17:31 -07:00
|
|
|
{
|
2012-11-16 17:07:15 -08:00
|
|
|
Body *b = GetFrame()->GetBody();
|
2012-07-28 15:11:23 -07:00
|
|
|
assert(b);
|
|
|
|
|
|
|
|
if (!b->IsType(Object::PLANET)) {
|
2012-07-14 13:51:03 -07:00
|
|
|
// orbital spaceport -- don't make city turds or change lighting based on atmosphere
|
2013-03-13 21:05:31 -07:00
|
|
|
RenderModel(r, camera, viewCoords, viewTransform);
|
2013-04-26 09:47:49 -07:00
|
|
|
} else {
|
|
|
|
// don't render city if too far away
|
2013-06-22 04:46:38 -07:00
|
|
|
if (viewCoords.LengthSqr() >= SQRMAXCITYDIST) {
|
2013-04-26 09:47:49 -07:00
|
|
|
return;
|
|
|
|
}
|
2013-03-16 20:34:55 -07:00
|
|
|
std::vector<Graphics::Light> oldLights;
|
|
|
|
Color oldAmbient;
|
2013-04-01 04:46:39 -07:00
|
|
|
SetLighting(r, camera, oldLights, oldAmbient);
|
2013-03-16 20:34:55 -07:00
|
|
|
|
2012-07-28 15:11:23 -07:00
|
|
|
Planet *planet = static_cast<Planet*>(b);
|
2013-06-26 18:07:40 -07:00
|
|
|
|
2013-04-26 09:47:49 -07:00
|
|
|
if (!m_adjacentCity) {
|
|
|
|
m_adjacentCity = new CityOnPlanet(planet, this, m_sbody->seed);
|
2012-12-22 14:26:30 -08:00
|
|
|
}
|
2013-04-26 09:47:49 -07:00
|
|
|
m_adjacentCity->Render(r, camera, this, viewCoords, viewTransform);
|
2012-07-09 06:47:47 -07:00
|
|
|
|
2013-03-16 20:34:55 -07:00
|
|
|
RenderModel(r, camera, viewCoords, viewTransform, false);
|
|
|
|
|
|
|
|
ResetLighting(r, oldLights, oldAmbient);
|
2009-07-18 07:09:31 -07:00
|
|
|
}
|
2008-06-24 03:17:31 -07:00
|
|
|
}
|
2011-03-14 22:34:46 -07:00
|
|
|
|
|
|
|
// find an empty position for a static ship and mark it as used. these aren't
|
|
|
|
// saved and are only needed to help modules place bulk ships. this isn't a
|
|
|
|
// great place for this, but its gotta be tracked somewhere
|
|
|
|
bool SpaceStation::AllocateStaticSlot(int& slot)
|
|
|
|
{
|
2012-12-31 00:18:58 -08:00
|
|
|
// no slots at ground stations
|
|
|
|
if (IsGroundStation())
|
|
|
|
return false;
|
|
|
|
|
2012-07-22 07:44:30 -07:00
|
|
|
for (int i=0; i<NUM_STATIC_SLOTS; i++) {
|
2011-03-14 22:34:46 -07:00
|
|
|
if (!m_staticSlot[i]) {
|
|
|
|
m_staticSlot[i] = true;
|
|
|
|
slot = i;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2011-04-26 21:44:07 -07:00
|
|
|
|
2011-04-30 03:22:35 -07:00
|
|
|
void SpaceStation::CreateBB()
|
|
|
|
{
|
|
|
|
if (m_bbCreated) return;
|
2011-11-08 13:39:53 -08:00
|
|
|
|
|
|
|
// fill the shipyard equipment shop with all kinds of things
|
|
|
|
// XXX should probably be moved out to a MarketAgent/CommodityWidget type
|
|
|
|
// thing, or just lua
|
|
|
|
for (int i=1; i<Equip::TYPE_MAX; i++) {
|
|
|
|
if (Equip::types[i].slot == Equip::SLOT_CARGO) {
|
|
|
|
m_equipmentStock[i] = Pi::rng.Int32(0,100) * Pi::rng.Int32(1,100);
|
|
|
|
} else {
|
2012-03-30 22:36:37 -07:00
|
|
|
m_equipmentStock[i] = Pi::rng.Int32(0,100);
|
2011-11-08 13:39:53 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-28 15:30:50 -07:00
|
|
|
LuaEvent::Queue("onCreateBB", this);
|
2011-04-30 03:22:35 -07:00
|
|
|
m_bbCreated = true;
|
|
|
|
}
|
|
|
|
|
2011-04-26 21:44:07 -07:00
|
|
|
static int next_ref = 0;
|
2011-05-29 15:31:18 -07:00
|
|
|
int SpaceStation::AddBBAdvert(std::string description, AdvertFormBuilder builder)
|
2011-04-26 21:44:07 -07:00
|
|
|
{
|
|
|
|
int ref = ++next_ref;
|
|
|
|
assert(ref);
|
|
|
|
|
|
|
|
BBAdvert ad;
|
|
|
|
ad.ref = ref;
|
|
|
|
ad.description = description;
|
|
|
|
ad.builder = builder;
|
|
|
|
|
|
|
|
m_bbAdverts.push_back(ad);
|
|
|
|
|
2011-04-30 03:54:34 -07:00
|
|
|
onBulletinBoardChanged.emit();
|
|
|
|
|
2011-04-26 21:44:07 -07:00
|
|
|
return ref;
|
|
|
|
}
|
|
|
|
|
|
|
|
const BBAdvert *SpaceStation::GetBBAdvert(int ref)
|
|
|
|
{
|
2012-09-03 07:30:08 -07:00
|
|
|
for (std::vector<BBAdvert>::const_iterator i = m_bbAdverts.begin(); i != m_bbAdverts.end(); ++i)
|
2011-04-26 21:44:07 -07:00
|
|
|
if (i->ref == ref)
|
|
|
|
return &(*i);
|
2013-04-18 23:24:07 -07:00
|
|
|
return 0;
|
2011-04-26 21:44:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SpaceStation::RemoveBBAdvert(int ref)
|
|
|
|
{
|
2012-09-03 07:30:08 -07:00
|
|
|
for (std::vector<BBAdvert>::iterator i = m_bbAdverts.begin(); i != m_bbAdverts.end(); ++i)
|
2011-04-26 21:44:07 -07:00
|
|
|
if (i->ref == ref) {
|
2011-09-26 13:52:17 -07:00
|
|
|
BBAdvert ad = (*i);
|
2011-04-26 21:44:07 -07:00
|
|
|
m_bbAdverts.erase(i);
|
2011-09-26 13:52:17 -07:00
|
|
|
onBulletinBoardAdvertDeleted.emit(ad);
|
2011-04-26 21:44:07 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::list<const BBAdvert*> SpaceStation::GetBBAdverts()
|
|
|
|
{
|
2011-04-26 21:59:07 -07:00
|
|
|
if (!m_bbShuffled) {
|
|
|
|
std::random_shuffle(m_bbAdverts.begin(), m_bbAdverts.end());
|
|
|
|
m_bbShuffled = true;
|
|
|
|
}
|
|
|
|
|
2011-04-26 21:44:07 -07:00
|
|
|
std::list<const BBAdvert*> ads;
|
2012-09-03 07:30:08 -07:00
|
|
|
for (std::vector<BBAdvert>::const_iterator i = m_bbAdverts.begin(); i != m_bbAdverts.end(); ++i)
|
2011-04-26 21:44:07 -07:00
|
|
|
ads.push_back(&(*i));
|
|
|
|
return ads;
|
|
|
|
}
|
|
|
|
|
2011-12-02 08:10:21 -08:00
|
|
|
vector3d SpaceStation::GetTargetIndicatorPosition(const Frame *relTo) const
|
|
|
|
{
|
2012-05-10 18:37:49 -07:00
|
|
|
// return the next waypoint if permission has been granted for player,
|
|
|
|
// and the docking point's position once the docking anim starts
|
2013-06-26 18:26:55 -07:00
|
|
|
for (Uint32 i=0; i<m_shipDocking.size(); i++) {
|
2011-12-02 08:10:21 -08:00
|
|
|
if (i >= m_type->numDockingPorts) break;
|
|
|
|
if ((m_shipDocking[i].ship == Pi::player) && (m_shipDocking[i].stage > 0)) {
|
|
|
|
|
|
|
|
SpaceStationType::positionOrient_t dport;
|
2012-05-10 18:37:49 -07:00
|
|
|
if (!m_type->GetShipApproachWaypoints(i, m_shipDocking[i].stage+1, dport))
|
|
|
|
PiVerify(m_type->GetDockAnimPositionOrient(i, m_type->numDockingStages,
|
2011-12-02 08:10:21 -08:00
|
|
|
1.0f, vector3d(0.0), dport, m_shipDocking[i].ship));
|
|
|
|
|
2012-11-16 17:07:15 -08:00
|
|
|
vector3d v = GetInterpPositionRelTo(relTo);
|
|
|
|
return v + GetInterpOrientRelTo(relTo) * dport.pos;
|
2011-12-02 08:10:21 -08:00
|
|
|
}
|
|
|
|
}
|
2012-11-16 17:07:15 -08:00
|
|
|
return GetInterpPositionRelTo(relTo);
|
2012-01-18 02:43:28 -08:00
|
|
|
}
|
2012-11-18 21:25:00 -08:00
|
|
|
|
2013-01-27 07:22:26 -08:00
|
|
|
// XXX this whole thing should be done by Lua
|
2013-01-23 09:52:34 -08:00
|
|
|
void SpaceStation::DoLawAndOrder(const double timeStep)
|
2012-11-18 21:25:00 -08:00
|
|
|
{
|
|
|
|
Sint64 fine, crimeBitset;
|
|
|
|
Polit::GetCrime(&crimeBitset, &fine);
|
|
|
|
if (Pi::player->GetFlightState() != Ship::DOCKED
|
|
|
|
&& m_numPoliceDocked
|
|
|
|
&& (fine > 1000)
|
|
|
|
&& (GetPositionRelTo(Pi::player).Length() < 100000.0)) {
|
2013-11-08 14:45:38 -08:00
|
|
|
Ship *ship = new Ship(ShipType::POLICE);
|
|
|
|
int port = GetFreeDockingPort(ship);
|
2013-01-27 07:22:26 -08:00
|
|
|
// at 60 Hz updates (ie, 1x time acceleration),
|
|
|
|
// this spawns a police ship with probability ~0.83% each frame
|
|
|
|
// This makes it unlikely (but not impossible) that police will spawn on top of each other
|
|
|
|
// the expected number of game-time seconds between spawns: 120 (2*60 Hz)
|
|
|
|
// variance is quite high though
|
2013-01-23 09:52:34 -08:00
|
|
|
if (port != -1 && 2.0*Pi::rng.Double() < timeStep) {
|
2012-11-18 21:25:00 -08:00
|
|
|
m_numPoliceDocked--;
|
|
|
|
// Make police ship intent on killing the player
|
|
|
|
ship->AIKill(Pi::player);
|
|
|
|
ship->SetFrame(GetFrame());
|
|
|
|
ship->SetDockedWith(this, port);
|
|
|
|
Pi::game->GetSpace()->AddBody(ship);
|
2013-02-11 12:33:37 -08:00
|
|
|
ship->SetLabel(Lang::POLICE_SHIP_REGISTRATION);
|
2012-11-18 21:25:00 -08:00
|
|
|
ship->m_equipment.Set(Equip::SLOT_LASER, 0, Equip::PULSECANNON_DUAL_1MW);
|
|
|
|
ship->m_equipment.Add(Equip::LASER_COOLING_BOOSTER);
|
|
|
|
ship->m_equipment.Add(Equip::ATMOSPHERIC_SHIELDING);
|
|
|
|
ship->UpdateStats();
|
2013-11-08 14:45:38 -08:00
|
|
|
} else {
|
|
|
|
delete ship;
|
2012-11-18 21:25:00 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-02-03 05:03:52 -08:00
|
|
|
|
|
|
|
bool SpaceStation::IsPortLocked(const int bay) const
|
|
|
|
{
|
|
|
|
SpaceStationType::TBayGroups::const_iterator bayIter = mBayGroups.begin();
|
|
|
|
for ( ; bayIter!=mBayGroups.end() ; ++bayIter ) {
|
|
|
|
std::vector<int>::const_iterator idIter = (*bayIter).bayIDs.begin();
|
|
|
|
for ( ; idIter!=(*bayIter).bayIDs.end() ; ++idIter ) {
|
|
|
|
if ((*idIter)==bay) {
|
|
|
|
return (*bayIter).inUse;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-02-16 07:46:53 -08:00
|
|
|
// is it safer to return that the is loacked?
|
2013-02-03 05:03:52 -08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SpaceStation::LockPort(const int bay, const bool lockIt)
|
|
|
|
{
|
|
|
|
SpaceStationType::TBayGroups::iterator bayIter = mBayGroups.begin();
|
|
|
|
for ( ; bayIter!=mBayGroups.end() ; ++bayIter ) {
|
|
|
|
std::vector<int>::iterator idIter = (*bayIter).bayIDs.begin();
|
|
|
|
for ( ; idIter!=(*bayIter).bayIDs.end() ; ++idIter ) {
|
|
|
|
if ((*idIter)==bay) {
|
|
|
|
(*bayIter).inUse = lockIt;
|
2013-02-03 06:25:41 -08:00
|
|
|
return;
|
2013-02-03 05:03:52 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|