pioneer/src/Body.cpp

264 lines
6.8 KiB
C++

// Copyright © 2008-2021 Pioneer Developers. See AUTHORS.txt for details
// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
#include "Body.h"
#include "CargoBody.h"
#include "Frame.h"
#include "GameSaveError.h"
#include "HyperspaceCloud.h"
#include "Missile.h"
#include "Planet.h"
#include "Player.h"
#include "Projectile.h"
#include "Ship.h"
#include "Space.h"
#include "SpaceStation.h"
#include "Star.h"
#include "lua/LuaEvent.h"
Body::Body() :
PropertiedObject(Lua::manager),
m_flags(0),
m_interpPos(0.0),
m_interpOrient(matrix3x3d::Identity()),
m_pos(0.0),
m_orient(matrix3x3d::Identity()),
m_frame(FrameId::Invalid),
m_dead(false),
m_clipRadius(0.0),
m_physRadius(0.0)
{
Properties().Set("label", m_label);
}
Body::Body(const Json &jsonObj, Space *space) :
PropertiedObject(Lua::manager),
m_flags(0),
m_interpPos(0.0),
m_interpOrient(matrix3x3d::Identity()),
m_frame(FrameId::Invalid)
{
try {
Json bodyObj = jsonObj["body"];
Properties().LoadFromJson(bodyObj);
m_frame = bodyObj["index_for_frame"];
m_label = bodyObj["label"].get<std::string>();
Properties().Set("label", m_label);
m_dead = bodyObj["dead"];
m_pos = bodyObj["pos"];
m_orient = bodyObj["orient"];
m_physRadius = bodyObj["phys_radius"];
m_clipRadius = bodyObj["clip_radius"];
} catch (Json::type_error &) {
throw SavedGameCorruptException();
}
}
Body::~Body()
{
}
void Body::SaveToJson(Json &jsonObj, Space *space)
{
Json bodyObj = Json::object(); // Create JSON object to contain body data.
Properties().SaveToJson(bodyObj);
bodyObj["index_for_frame"] = m_frame.id();
bodyObj["label"] = m_label;
bodyObj["dead"] = m_dead;
bodyObj["pos"] = m_pos;
bodyObj["orient"] = m_orient;
bodyObj["phys_radius"] = m_physRadius;
bodyObj["clip_radius"] = m_clipRadius;
jsonObj["body"] = bodyObj; // Add body object to supplied object.
}
void Body::ToJson(Json &jsonObj, Space *space)
{
jsonObj["body_type"] = int(GetType());
switch (GetType()) {
case ObjectType::STAR:
case ObjectType::PLANET:
case ObjectType::SPACESTATION:
case ObjectType::SHIP:
case ObjectType::PLAYER:
case ObjectType::MISSILE:
case ObjectType::CARGOBODY:
case ObjectType::PROJECTILE:
case ObjectType::HYPERSPACECLOUD:
SaveToJson(jsonObj, space);
break;
default:
assert(0);
}
}
Body *Body::FromJson(const Json &jsonObj, Space *space)
{
if (!jsonObj["body_type"].is_number_integer())
throw SavedGameCorruptException();
ObjectType type = ObjectType(jsonObj["body_type"]);
switch (type) {
case ObjectType::STAR:
return new Star(jsonObj, space);
case ObjectType::PLANET:
return new Planet(jsonObj, space);
case ObjectType::SPACESTATION:
return new SpaceStation(jsonObj, space);
case ObjectType::SHIP: {
Ship *s = new Ship(jsonObj, space);
// Here because of comments in Ship.cpp on following function
s->UpdateLuaStats();
return static_cast<Body *>(s);
}
case ObjectType::PLAYER: {
Player *p = new Player(jsonObj, space);
// Read comments in Ship.cpp on following function
p->UpdateLuaStats();
return static_cast<Body *>(p);
}
case ObjectType::MISSILE:
return new Missile(jsonObj, space);
case ObjectType::PROJECTILE:
return new Projectile(jsonObj, space);
case ObjectType::CARGOBODY:
return new CargoBody(jsonObj, space);
case ObjectType::HYPERSPACECLOUD:
return new HyperspaceCloud(jsonObj, space);
default:
assert(0);
}
return nullptr;
}
vector3d Body::GetPositionRelTo(FrameId relToId) const
{
Frame *frame = Frame::GetFrame(m_frame);
vector3d fpos = frame->GetPositionRelTo(relToId);
matrix3x3d forient = frame->GetOrientRelTo(relToId);
return forient * GetPosition() + fpos;
}
vector3d Body::GetInterpPositionRelTo(FrameId relToId) const
{
Frame *frame = Frame::GetFrame(m_frame);
vector3d fpos = frame->GetInterpPositionRelTo(relToId);
matrix3x3d forient = frame->GetInterpOrientRelTo(relToId);
return forient * GetInterpPosition() + fpos;
}
vector3d Body::GetPositionRelTo(const Body *relTo) const
{
return GetPositionRelTo(relTo->m_frame) - relTo->GetPosition();
}
vector3d Body::GetInterpPositionRelTo(const Body *relTo) const
{
return GetInterpPositionRelTo(relTo->m_frame) - relTo->GetInterpPosition();
}
matrix3x3d Body::GetOrientRelTo(FrameId relToId) const
{
Frame *frame = Frame::GetFrame(m_frame);
matrix3x3d forient = frame->GetOrientRelTo(relToId);
return forient * GetOrient();
}
matrix3x3d Body::GetInterpOrientRelTo(FrameId relToId) const
{
Frame *frame = Frame::GetFrame(m_frame);
matrix3x3d forient = frame->GetInterpOrientRelTo(relToId);
return forient * GetInterpOrient();
}
vector3d Body::GetVelocityRelTo(FrameId relToId) const
{
Frame *frame = Frame::GetFrame(m_frame);
matrix3x3d forient = frame->GetOrientRelTo(relToId);
vector3d vel = GetVelocity();
if (m_frame != relToId) vel -= frame->GetStasisVelocity(GetPosition());
return forient * vel + frame->GetVelocityRelTo(relToId);
}
vector3d Body::GetVelocityRelTo(const Body *relTo) const
{
return GetVelocityRelTo(relTo->m_frame) - relTo->GetVelocityRelTo(relTo->m_frame);
}
void Body::OrientOnSurface(double radius, double latitude, double longitude)
{
vector3d up = vector3d(cos(latitude) * cos(longitude), sin(latitude) * cos(longitude), sin(longitude));
SetPosition(radius * up);
vector3d right = up.Cross(vector3d(0, 0, 1)).Normalized();
SetOrient(matrix3x3d::FromVectors(right, up));
}
void Body::SwitchToFrame(FrameId newFrameId)
{
const Frame *newFrame = Frame::GetFrame(newFrameId);
const Frame *frame = Frame::GetFrame(m_frame);
const vector3d vel = GetVelocityRelTo(newFrameId); // do this first because it uses position
const vector3d fpos = frame->GetPositionRelTo(newFrameId);
const matrix3x3d forient = frame->GetOrientRelTo(newFrameId);
SetPosition(forient * GetPosition() + fpos);
SetOrient(forient * GetOrient());
SetVelocity(vel + newFrame->GetStasisVelocity(GetPosition()));
SetFrame(newFrameId);
LuaEvent::Queue("onFrameChanged", this);
}
void Body::UpdateFrame()
{
if (!(m_flags & FLAG_CAN_MOVE_FRAME)) return;
const Frame *frame = Frame::GetFrame(m_frame);
// falling out of frames
if (frame->GetRadius() < GetPosition().Length()) {
FrameId parent = frame->GetParent();
Frame *newFrame = Frame::GetFrame(parent);
if (newFrame) { // don't fall out of root frame
Log::Verbose("{} leaves frame{}\n", GetLabel(), frame->GetLabel());
SwitchToFrame(parent);
return;
}
}
// entering into frames
for (FrameId kid : frame->GetChildren()) {
Frame *kid_frame = Frame::GetFrame(kid);
const vector3d pos = GetPositionRelTo(kid);
if (pos.Length() >= kid_frame->GetRadius()) continue;
SwitchToFrame(kid);
Log::Verbose("{} enters frame{}\n", GetLabel(), frame->GetLabel());
break;
}
}
vector3d Body::GetTargetIndicatorPosition() const
{
return vector3d(0, 0, 0);
}
void Body::SetLabel(const std::string &label)
{
m_label = label;
Properties().Set("label", label);
}