Lephisto/src/space_station.cpp

219 lines
6.4 KiB
C++

#include "space_station.h"
#include "ship.h"
#include "model_coll_mesh_data.h"
#include "gameconsts.h"
#include "star_system.h"
#include "serializer.h"
struct SpaceStationType {
Uint32 sbreModel;
enum { ORBITAL, SURFACE } dockMethod;
};
struct SpaceStationType stationTypes[SpaceStation::TYPE_MAX] = {
{ 65, SpaceStationType::ORBITAL },
{ 90, SpaceStationType::SURFACE },
};
void SpaceStation::Save(void) {
using namespace Serializer::Write;
ModelBody::Save();
wr_int((int)m_type);
}
void SpaceStation::Load(void) {
using namespace Serializer::Read;
ModelBody::Load();
m_type = (TYPE)rd_int();
m_numPorts = 0;
Init();
}
static ObjParams params = {
{ 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0.0f, 0.0f, 1.0f }, { 0.0f, 0.0f, 0.0f },
/* pColor[3] */
{
{ { 1.0f, 0.0f, 1.0f }, { 0, 0, 0 }, { 0, 0, 0 }, 0 },
{ { 0.8f, 0.6f, 0.5f }, { 0, 0, 0 }, { 0, 0, 0 }, 0 },
{ { 0.5f, 0.5f, 0.5f }, { 0, 0, 0 }, { 0, 0, 0 }, 0 }
},
/* pText[3][256] */
{ "Hello you!", "CATZ" },
};
void SpaceStation::GetDockingSurface(CollMeshSet* mset, int midx) {
meshinfo_t* const minfo = &mset->meshInfo[midx];
dockingport_t* const dport = &port[minfo->flags & 0xf];
m_numPorts++;
assert(m_numPorts <= MAX_DOCKING_PORTS);
assert((minfo->flags & 0xf) < MAX_DOCKING_PORTS);
assert(minfo->numTris);
dport->center = vector3d(0.0);
const int t = minfo->triStart;
float* const vts = mset->sbreCollMesh->pVertex;
for(int pos = 0; pos < minfo->numTris; pos++) {
vector3d v1(vts + 3*mset->triIndices[t+pos].v1);
vector3d v2(vts + 3*mset->triIndices[t+pos].v2);
vector3d v3(vts + 3*mset->triIndices[t+pos].v3);
/*
* Use first tri to get docking port normal (which points out of the
* docking port).
*/
if(pos == 0) {
dport->normal = vector3d::Cross(v2-v1, v2-v3);
dport->normal.Normalize();
dport->horiz = vector3d::Normalize(v1-v2);
}
dport->center += v1+v2+v3;
}
dport->center *= 1.0/(3.0*minfo->numTris);
/*printf("Docking port center %f,%f,%f, normal %f,%f,%f, horiz %f,%f,%f\n",
dport->center.x,
dport->center.y,
dport->center.z,
dport->normal.x,
dport->normal.y,
dport->normal.z,
dport->horiz.x,
dport->horiz.y,
dport->horiz.z); */
}
SpaceStation::SpaceStation(TYPE type) : ModelBody() {
m_type = type;
m_numPorts = 0;
Init();
}
void SpaceStation::Init(void) {
const Uint32 sbreModel = stationTypes[m_type].sbreModel;
SetModel(sbreModel);
CollMeshSet* mset = GetModelCollMeshSet(sbreModel);
for(int i = 0; i < mset->numMeshParts; i++) {
if(mset->meshInfo[i].flags & 0x10) GetDockingSurface(mset, i);
}
}
SpaceStation::~SpaceStation(void) {
}
bool SpaceStation::IsGroundStation(void) const {
return (stationTypes[m_type].dockMethod == SpaceStationType::SURFACE);
}
void SpaceStation::OrientDockedShip(Ship* ship, int port) const {
const dockingport_t* dport = &this->port[port];
const int dockMethod = stationTypes[m_type].dockMethod;
if(dockMethod == SpaceStationType::SURFACE) {
matrix4x4d stationRot;
GetRotMatrix(stationRot);
vector3d port_y = vector3d::Cross(-dport->horiz, dport->normal);
matrix4x4d rot = stationRot * matrix4x4d::MakeRotMatrix(-dport->horiz, -dport->normal, -port_y);
vector3d pos = GetPosition() + stationRot*dport->center;
/* Position with wheels perfectly on ground. :D */
Aabb aabb;
ship->GetAabb(aabb);
pos += stationRot*vector3d(0, -aabb.min.y, 0);
ship->SetPosition(pos);
ship->SetRotMatrix(rot);
}
}
void SpaceStation::OrientLaunchingShip(Ship* ship, int port) const {
const dockingport_t* dport = &this->port[port];
const int dockMethod = stationTypes[m_type].dockMethod;
if(dockMethod == SpaceStationType::ORBITAL) {
/*
* Position ship in middle of docking bay, pointing out of it.
* TODO: Need to do forced thrusting thing.
* TODO: ang vel not zeroed for some reason..
*/
matrix4x4d stationRot;
GetRotMatrix(stationRot);
vector3d port_y = vector3d::Cross(-dport->horiz, dport->normal);
matrix4x4d rot = stationRot * matrix4x4d::MakeRotMatrix(dport->horiz, port_y, dport->normal);
vector3d pos = GetPosition() + stationRot*dport->center;
ship->SetPosition(pos);
ship->SetRotMatrix(rot);
ship->SetVelocity(vector3d(0,0,0));
ship->SetAngVelocity(vector3d(0,0,0));
}
else if(dockMethod == SpaceStationType::SURFACE) {
ship->Blastoff();
/*
* Not necessary, since for the time being 'SURFACE' starports are on planets
* so the positioning Blastoff does is fine.
*/
#if 0
matrix4x4d stationRot;
GetRotMatrix(stationRot);
vector3d port_y = vector3d::Cross(-dport->horiz, dport->normal);
matrix4x4d rot = stationRot * matrix4x4d::MakeRotMatrix(-dport->horiz, -dport->normal, -port_y);
vector3d pos = GetPosition() + stationRot*dport->center;
ship->SetPosition(pos - stationRot*(10*dport->normal));
ship->SetRotMatrix(rot);
ship->SetVelocity(vector3d(0,0,0));
ship->SetAngVelocity(vector3d(0,0,0));
#endif
} else {
assert(0);
}
}
bool SpaceStation::GetDockingClearance(Ship* s) {
s->SetDockingTimer(68*10);
return true;
}
bool SpaceStation::OnCollision(Body* b, Uint32 flags) {
if(flags & 0x10) {
dockingport_t* dport = &port[flags & 0xf];
/* Hitting docking area of a station. */
if(b->IsType(Object::SHIP)) {
Ship* s = static_cast<Ship*>(b);
double speed = s->GetVelocity().Length();
/* Must be oriented sensibly and have wheels down. */
if(IsGroundStation()) {
matrix4x4d rot;
s->GetRotMatrix(rot);
matrix4x4d invRot = rot.InverseOf();
matrix4x4d stationRot;
GetRotMatrix(stationRot);
vector3d dockingNormal = stationRot*dport->normal;
/* Check player is sort of sensibly oriented for landing. */
const double dot = vector3d::Dot(vector3d(-invRot[1], -invRot[5], -invRot[9]), dockingNormal);
if((dot < 0.99) || (s->GetWheelState() != 1.0)) return false;
}
if((speed < MAX_LANDING_SPEED) &&
(!s->GetDockedWith()) &&
(s->GetDockingTimer() != 0.0f)) {
s->SetDockedWith(this, flags & 0xf);
}
}
return false;
} else {
return true;
}
}
void SpaceStation::Render(const Frame* camFrame) {
RenderSbreModel(camFrame, stationTypes[m_type].sbreModel, &params);
}