mirror of
https://github.com/rwengine/openrw.git
synced 2024-09-19 17:01:44 +02:00
clang-format files in rwengine/src/engine
This commit is contained in:
parent
8534d7ff5d
commit
80e6317c24
@ -1,23 +1,19 @@
|
||||
#include <engine/Animator.hpp>
|
||||
#include <loaders/LoaderDFF.hpp>
|
||||
#include <data/Model.hpp>
|
||||
#include <data/Skeleton.hpp>
|
||||
#include <engine/Animator.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <loaders/LoaderDFF.hpp>
|
||||
|
||||
Animator::Animator(Model* model, Skeleton* skeleton)
|
||||
: model(model)
|
||||
, skeleton(skeleton)
|
||||
{
|
||||
: model(model), skeleton(skeleton) {
|
||||
}
|
||||
|
||||
void Animator::tick(float dt)
|
||||
{
|
||||
if( model == nullptr || animations.empty() ) {
|
||||
void Animator::tick(float dt) {
|
||||
if (model == nullptr || animations.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct BoneTransform
|
||||
{
|
||||
struct BoneTransform {
|
||||
glm::vec3 translation;
|
||||
glm::quat rotation;
|
||||
};
|
||||
@ -25,18 +21,17 @@ void Animator::tick(float dt)
|
||||
// Blend all active animations together
|
||||
std::map<unsigned int, BoneTransform> blendFrames;
|
||||
|
||||
for (AnimationState& state : animations)
|
||||
{
|
||||
RW_CHECK(state.animation != nullptr, "AnimationState with no animation");
|
||||
for (AnimationState& state : animations) {
|
||||
RW_CHECK(state.animation != nullptr,
|
||||
"AnimationState with no animation");
|
||||
if (state.animation == nullptr) continue;
|
||||
|
||||
if (state.boneInstances.size() == 0) {
|
||||
for( unsigned int f = 0; f < model->frames.size(); ++f )
|
||||
{
|
||||
auto bit = state.animation->bones.find( model->frames[f]->getName() );
|
||||
if( bit != state.animation->bones.end() )
|
||||
{
|
||||
state.boneInstances.insert( { bit->second, { f } } );
|
||||
for (unsigned int f = 0; f < model->frames.size(); ++f) {
|
||||
auto bit =
|
||||
state.animation->bones.find(model->frames[f]->getName());
|
||||
if (bit != state.animation->bones.end()) {
|
||||
state.boneInstances.insert({bit->second, {f}});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -44,29 +39,23 @@ void Animator::tick(float dt)
|
||||
state.time = state.time + dt;
|
||||
|
||||
float animTime = state.time;
|
||||
if (! state.repeat)
|
||||
{
|
||||
if (!state.repeat) {
|
||||
animTime = std::min(animTime, state.animation->duration);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
animTime = fmod(animTime, state.animation->duration);
|
||||
}
|
||||
|
||||
for( auto& b : state.boneInstances )
|
||||
{
|
||||
for (auto& b : state.boneInstances) {
|
||||
if (b.first->frames.size() == 0) continue;
|
||||
auto kf = b.first->getInterpolatedKeyframe(animTime);
|
||||
|
||||
BoneTransform xform;
|
||||
if(b.first->type == AnimationBone::R00 ) {
|
||||
if (b.first->type == AnimationBone::R00) {
|
||||
xform.rotation = kf.rotation;
|
||||
}
|
||||
else if(b.first->type == AnimationBone::RT0) {
|
||||
} else if (b.first->type == AnimationBone::RT0) {
|
||||
xform.rotation = kf.rotation;
|
||||
xform.translation = kf.position;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
xform.rotation = kf.rotation;
|
||||
xform.translation = kf.position;
|
||||
}
|
||||
@ -88,45 +77,39 @@ void Animator::tick(float dt)
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& p : blendFrames)
|
||||
{
|
||||
for (auto& p : blendFrames) {
|
||||
auto& data = skeleton->getData(p.first);
|
||||
Skeleton::FrameData fd;
|
||||
fd.b = data.a;
|
||||
fd.enabled = data.enabled;
|
||||
|
||||
fd.a.translation = model->frames[p.first]->getDefaultTranslation()
|
||||
+ p.second.translation;
|
||||
fd.a.translation = model->frames[p.first]->getDefaultTranslation() +
|
||||
p.second.translation;
|
||||
fd.a.rotation = p.second.rotation;
|
||||
|
||||
skeleton->setData(p.first, fd);
|
||||
}
|
||||
}
|
||||
|
||||
bool Animator::isCompleted(unsigned int slot) const
|
||||
{
|
||||
if (slot < animations.size())
|
||||
{
|
||||
return animations[slot].animation ?
|
||||
animations[slot].time >= animations[slot].animation->duration
|
||||
bool Animator::isCompleted(unsigned int slot) const {
|
||||
if (slot < animations.size()) {
|
||||
return animations[slot].animation
|
||||
? animations[slot].time >=
|
||||
animations[slot].animation->duration
|
||||
: true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
float Animator::getAnimationTime(unsigned int slot) const
|
||||
{
|
||||
if (slot < animations.size())
|
||||
{
|
||||
float Animator::getAnimationTime(unsigned int slot) const {
|
||||
if (slot < animations.size()) {
|
||||
return animations[slot].time;
|
||||
}
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
void Animator::setAnimationTime(unsigned int slot, float time)
|
||||
{
|
||||
if (slot < animations.size())
|
||||
{
|
||||
void Animator::setAnimationTime(unsigned int slot, float time) {
|
||||
if (slot < animations.size()) {
|
||||
animations[slot].time = time;
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
#pragma once
|
||||
#ifndef _ANIMATOR_HPP_
|
||||
#define _ANIMATOR_HPP_
|
||||
#include <map>
|
||||
#include <cstdint>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
#include <rw/defines.hpp>
|
||||
#include <loaders/LoaderIFP.hpp>
|
||||
#include <map>
|
||||
#include <rw/defines.hpp>
|
||||
|
||||
class Model;
|
||||
class ModelFrame;
|
||||
@ -23,21 +23,19 @@ class Skeleton;
|
||||
*
|
||||
* The Animator will blend all active animations together.
|
||||
*/
|
||||
class Animator
|
||||
{
|
||||
class Animator {
|
||||
/**
|
||||
* @brief Stores data required to animate a model frame
|
||||
*/
|
||||
struct BoneInstanceData
|
||||
{
|
||||
struct BoneInstanceData {
|
||||
unsigned int frameIndex;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The AnimationState struct stores information about playing animations
|
||||
* @brief The AnimationState struct stores information about playing
|
||||
* animations
|
||||
*/
|
||||
struct AnimationState
|
||||
{
|
||||
struct AnimationState {
|
||||
Animation* animation;
|
||||
/// Timestamp of the last frame
|
||||
float time;
|
||||
@ -64,32 +62,26 @@ class Animator
|
||||
std::vector<AnimationState> animations;
|
||||
|
||||
public:
|
||||
|
||||
Animator(Model* model, Skeleton* skeleton);
|
||||
|
||||
Animation* getAnimation(unsigned int slot)
|
||||
{
|
||||
if (slot < animations.size())
|
||||
{
|
||||
Animation* getAnimation(unsigned int slot) {
|
||||
if (slot < animations.size()) {
|
||||
return animations[slot].animation;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void playAnimation(unsigned int slot, Animation* anim, float speed, bool repeat)
|
||||
{
|
||||
if (slot >= animations.size())
|
||||
{
|
||||
animations.resize(slot+1);
|
||||
void playAnimation(unsigned int slot, Animation* anim, float speed,
|
||||
bool repeat) {
|
||||
if (slot >= animations.size()) {
|
||||
animations.resize(slot + 1);
|
||||
}
|
||||
animations[slot] = { anim, 0.f, speed, repeat, {} };
|
||||
animations[slot] = {anim, 0.f, speed, repeat, {}};
|
||||
}
|
||||
|
||||
void setAnimationSpeed(unsigned int slot, float speed)
|
||||
{
|
||||
void setAnimationSpeed(unsigned int slot, float speed) {
|
||||
RW_CHECK(slot < animations.size(), "Slot out of range");
|
||||
if (slot < animations.size())
|
||||
{
|
||||
if (slot < animations.size()) {
|
||||
animations[slot].speed = speed;
|
||||
}
|
||||
}
|
||||
|
@ -1,43 +1,40 @@
|
||||
#include <engine/GameData.hpp>
|
||||
#include <engine/GameWorld.hpp>
|
||||
#include <engine/GameState.hpp>
|
||||
#include <loaders/LoaderIPL.hpp>
|
||||
#include <loaders/LoaderDFF.hpp>
|
||||
#include <loaders/LoaderIDE.hpp>
|
||||
#include <loaders/LoaderCOL.hpp>
|
||||
#include <data/Model.hpp>
|
||||
#include <data/ObjectData.hpp>
|
||||
#include <data/WeaponData.hpp>
|
||||
#include <engine/GameData.hpp>
|
||||
#include <engine/GameState.hpp>
|
||||
#include <engine/GameWorld.hpp>
|
||||
#include <loaders/LoaderCOL.hpp>
|
||||
#include <loaders/LoaderDFF.hpp>
|
||||
#include <loaders/LoaderIDE.hpp>
|
||||
#include <loaders/LoaderIPL.hpp>
|
||||
#include <script/SCMFile.hpp>
|
||||
#include <data/Model.hpp>
|
||||
|
||||
#include <core/Logger.hpp>
|
||||
#include <loaders/BackgroundLoader.hpp>
|
||||
#include <loaders/GenericDATLoader.hpp>
|
||||
#include <loaders/LoaderGXT.hpp>
|
||||
#include <loaders/BackgroundLoader.hpp>
|
||||
#include <core/Logger.hpp>
|
||||
#include <platform/FileIndex.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
GameData::GameData(Logger* log, WorkContext* work, const std::string& path)
|
||||
: datpath(path), logger(log), workContext(work), engine(nullptr)
|
||||
{
|
||||
: datpath(path), logger(log), workContext(work), engine(nullptr) {
|
||||
}
|
||||
|
||||
GameData::~GameData()
|
||||
{
|
||||
for(auto& m : models) {
|
||||
if(m.second->resource) {
|
||||
GameData::~GameData() {
|
||||
for (auto& m : models) {
|
||||
if (m.second->resource) {
|
||||
delete m.second->resource;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameData::load()
|
||||
{
|
||||
void GameData::load() {
|
||||
index.indexGameDirectory(datpath);
|
||||
index.indexTree(datpath);
|
||||
|
||||
@ -65,130 +62,110 @@ void GameData::load()
|
||||
loadIFP("ped.ifp");
|
||||
}
|
||||
|
||||
void GameData::loadLevelFile(const std::string& path)
|
||||
{
|
||||
void GameData::loadLevelFile(const std::string& path) {
|
||||
auto datpath = index.findFilePath(path);
|
||||
std::ifstream datfile(datpath.string());
|
||||
|
||||
if(!datfile.is_open())
|
||||
{
|
||||
if (!datfile.is_open()) {
|
||||
logger->error("Data", "Failed to open game file " + path);
|
||||
return;
|
||||
}
|
||||
|
||||
for(std::string line, cmd; std::getline(datfile, line);)
|
||||
{
|
||||
if(line.size() == 0 || line[0] == '#') continue;
|
||||
#ifndef RW_WINDOWS
|
||||
line.erase(line.size()-1);
|
||||
#endif
|
||||
for (std::string line, cmd; std::getline(datfile, line);) {
|
||||
if (line.size() == 0 || line[0] == '#') continue;
|
||||
#ifndef RW_WINDOWS
|
||||
line.erase(line.size() - 1);
|
||||
#endif
|
||||
|
||||
size_t space = line.find_first_of(' ');
|
||||
if(space != line.npos)
|
||||
{
|
||||
if (space != line.npos) {
|
||||
cmd = line.substr(0, space);
|
||||
if(cmd == "IDE")
|
||||
{
|
||||
auto path = line.substr(space+1);
|
||||
if (cmd == "IDE") {
|
||||
auto path = line.substr(space + 1);
|
||||
loadIDE(path);
|
||||
}
|
||||
else if(cmd == "SPLASH")
|
||||
{
|
||||
splash = line.substr(space+1);
|
||||
}
|
||||
else if(cmd == "COLFILE")
|
||||
{
|
||||
int zone = atoi(line.substr(space+1,1).c_str());
|
||||
auto path = line.substr(space+3);
|
||||
} else if (cmd == "SPLASH") {
|
||||
splash = line.substr(space + 1);
|
||||
} else if (cmd == "COLFILE") {
|
||||
int zone = atoi(line.substr(space + 1, 1).c_str());
|
||||
auto path = line.substr(space + 3);
|
||||
loadCOL(zone, path);
|
||||
}
|
||||
else if(cmd == "IPL")
|
||||
{
|
||||
auto path = line.substr(space+1);
|
||||
} else if (cmd == "IPL") {
|
||||
auto path = line.substr(space + 1);
|
||||
loadIPL(path);
|
||||
}
|
||||
else if(cmd == "TEXDICTION")
|
||||
{
|
||||
auto path = line.substr(space+1);
|
||||
} else if (cmd == "TEXDICTION") {
|
||||
auto path = line.substr(space + 1);
|
||||
/// @todo improve TXD handling
|
||||
auto name = index.findFilePath(path).filename().string();
|
||||
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
|
||||
std::transform(name.begin(), name.end(), name.begin(),
|
||||
::tolower);
|
||||
loadTXD(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameData::loadIDE(const std::string& path)
|
||||
{
|
||||
void GameData::loadIDE(const std::string& path) {
|
||||
auto systempath = index.findFilePath(path).string();
|
||||
LoaderIDE idel;
|
||||
|
||||
if(idel.load(systempath)) {
|
||||
if (idel.load(systempath)) {
|
||||
objectTypes.insert(idel.objects.begin(), idel.objects.end());
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
logger->error("Data", "Failed to load IDE " + path);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t GameData::findModelObject(const std::string model)
|
||||
{
|
||||
auto defit = std::find_if(objectTypes.begin(), objectTypes.end(),
|
||||
[&](const decltype(objectTypes)::value_type& d)
|
||||
{
|
||||
if(d.second->class_type == ObjectInformation::_class("OBJS"))
|
||||
{
|
||||
uint16_t GameData::findModelObject(const std::string model) {
|
||||
auto defit = std::find_if(
|
||||
objectTypes.begin(), objectTypes.end(),
|
||||
[&](const decltype(objectTypes)::value_type& d) {
|
||||
if (d.second->class_type == ObjectInformation::_class("OBJS")) {
|
||||
auto dat = static_cast<ObjectData*>(d.second.get());
|
||||
return boost::iequals(dat->modelName, model);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if( defit != objectTypes.end() ) return defit->first;
|
||||
if (defit != objectTypes.end()) return defit->first;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void GameData::loadCOL(const size_t zone, const std::string& name)
|
||||
{
|
||||
void GameData::loadCOL(const size_t zone, const std::string& name) {
|
||||
RW_UNUSED(zone);
|
||||
|
||||
LoaderCOL col;
|
||||
|
||||
auto systempath = index.findFilePath(name).string();
|
||||
|
||||
if(col.load(systempath)) {
|
||||
for( size_t i = 0; i < col.instances.size(); ++i ) {
|
||||
if (col.load(systempath)) {
|
||||
for (size_t i = 0; i < col.instances.size(); ++i) {
|
||||
collisions[col.instances[i]->name] = std::move(col.instances[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameData::loadIMG(const std::string& name)
|
||||
{
|
||||
void GameData::loadIMG(const std::string& name) {
|
||||
auto syspath = index.findFilePath(name).string();
|
||||
index.indexArchive(syspath);
|
||||
}
|
||||
|
||||
void GameData::loadIPL(const std::string& path)
|
||||
{
|
||||
void GameData::loadIPL(const std::string& path) {
|
||||
auto systempath = index.findFilePath(path).string();
|
||||
iplLocations.insert({path, systempath});
|
||||
}
|
||||
|
||||
bool GameData::loadZone(const std::string& path)
|
||||
{
|
||||
bool GameData::loadZone(const std::string& path) {
|
||||
LoaderIPL ipll;
|
||||
|
||||
if( ipll.load(path)) {
|
||||
if( ipll.zones.size() > 0) {
|
||||
for(auto& z : ipll.zones) {
|
||||
if (ipll.load(path)) {
|
||||
if (ipll.zones.size() > 0) {
|
||||
for (auto& z : ipll.zones) {
|
||||
zones.insert({z.name, z});
|
||||
}
|
||||
logger->info("Data", "Loaded " + std::to_string(ipll.zones.size()) + " zones from " + path);
|
||||
logger->info("Data", "Loaded " + std::to_string(ipll.zones.size()) +
|
||||
" zones from " + path);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
logger->error("Data", "Failed to load zones from " + path);
|
||||
}
|
||||
|
||||
@ -203,50 +180,42 @@ enum ColSection {
|
||||
CAR4 ///> Used in GTASA, contains quadruple colors
|
||||
};
|
||||
|
||||
void GameData::loadCarcols(const std::string& path)
|
||||
{
|
||||
void GameData::loadCarcols(const std::string& path) {
|
||||
auto syspath = index.findFilePath(path);
|
||||
std::ifstream fstream(syspath.string());
|
||||
|
||||
std::string line;
|
||||
ColSection currentSection = Unknown;
|
||||
while( std::getline(fstream, line)) {
|
||||
if( line.substr(0, 1) == "#") { // Comment
|
||||
while (std::getline(fstream, line)) {
|
||||
if (line.substr(0, 1) == "#") { // Comment
|
||||
continue;
|
||||
}
|
||||
else if( currentSection == Unknown) {
|
||||
if( line.substr(0, 3) == "col") {
|
||||
} else if (currentSection == Unknown) {
|
||||
if (line.substr(0, 3) == "col") {
|
||||
currentSection = COL;
|
||||
}
|
||||
else if( line.substr(0, 3) == "car") {
|
||||
} else if (line.substr(0, 3) == "car") {
|
||||
currentSection = CAR;
|
||||
}
|
||||
}
|
||||
else if( line.substr(0, 3) == "end") {
|
||||
} else if (line.substr(0, 3) == "end") {
|
||||
currentSection = Unknown;
|
||||
}
|
||||
else {
|
||||
if( currentSection == COL) {
|
||||
} else {
|
||||
if (currentSection == COL) {
|
||||
std::string r, g, b;
|
||||
std::stringstream ss(line);
|
||||
|
||||
if( std::getline(ss, r, ',') && std::getline(ss, g, ',') && std::getline(ss, b)) {
|
||||
if (std::getline(ss, r, ',') && std::getline(ss, g, ',') &&
|
||||
std::getline(ss, b)) {
|
||||
vehicleColours.push_back(glm::u8vec3(
|
||||
atoi(r.c_str()),
|
||||
atoi(g.c_str()),
|
||||
atoi(b.c_str())
|
||||
));
|
||||
atoi(r.c_str()), atoi(g.c_str()), atoi(b.c_str())));
|
||||
}
|
||||
}
|
||||
else if( currentSection == CAR) {
|
||||
} else if (currentSection == CAR) {
|
||||
std::string vehicle, p, s;
|
||||
std::stringstream ss(line);
|
||||
|
||||
std::getline(ss, vehicle, ',');
|
||||
std::vector<std::pair<size_t, size_t>> colours;
|
||||
|
||||
while( std::getline(ss, p, ',') && std::getline(ss, s, ',') ) {
|
||||
colours.push_back({ atoi(p.c_str()), atoi(s.c_str()) });
|
||||
while (std::getline(ss, p, ',') && std::getline(ss, s, ',')) {
|
||||
colours.push_back({atoi(p.c_str()), atoi(s.c_str())});
|
||||
}
|
||||
|
||||
vehiclePalettes.insert({vehicle, colours});
|
||||
@ -255,22 +224,19 @@ void GameData::loadCarcols(const std::string& path)
|
||||
}
|
||||
}
|
||||
|
||||
void GameData::loadWeather(const std::string &path)
|
||||
{
|
||||
void GameData::loadWeather(const std::string& path) {
|
||||
auto syspath = index.findFilePath(path).string();
|
||||
weatherLoader.load(syspath);
|
||||
}
|
||||
|
||||
void GameData::loadHandling(const std::string& path)
|
||||
{
|
||||
void GameData::loadHandling(const std::string& path) {
|
||||
GenericDATLoader l;
|
||||
auto syspath = index.findFilePath(path).string();
|
||||
|
||||
l.loadHandling(syspath, vehicleInfo);
|
||||
}
|
||||
|
||||
SCMFile *GameData::loadSCM(const std::string &path)
|
||||
{
|
||||
SCMFile* GameData::loadSCM(const std::string& path) {
|
||||
auto scm_h = index.openFilePath(path);
|
||||
SCMFile* scm = new SCMFile;
|
||||
scm->loadFile(scm_h->data, scm_h->length);
|
||||
@ -278,38 +244,37 @@ SCMFile *GameData::loadSCM(const std::string &path)
|
||||
return scm;
|
||||
}
|
||||
|
||||
void GameData::loadGXT(const std::string &name)
|
||||
{
|
||||
void GameData::loadGXT(const std::string& name) {
|
||||
auto file = index.openFilePath(name);
|
||||
|
||||
LoaderGXT loader;
|
||||
|
||||
loader.load( texts, file );
|
||||
loader.load(texts, file);
|
||||
}
|
||||
|
||||
void GameData::loadWaterpro(const std::string& path)
|
||||
{
|
||||
void GameData::loadWaterpro(const std::string& path) {
|
||||
auto syspath = index.findFilePath(path);
|
||||
std::ifstream ifstr(syspath.string(), std::ios_base::binary);
|
||||
|
||||
if(ifstr.is_open()) {
|
||||
if (ifstr.is_open()) {
|
||||
uint32_t numlevels;
|
||||
ifstr.read(reinterpret_cast<char*>(&numlevels), sizeof(uint32_t));
|
||||
ifstr.read(reinterpret_cast<char*>(&waterHeights), sizeof(float)*48);
|
||||
ifstr.read(reinterpret_cast<char*>(&waterHeights), sizeof(float) * 48);
|
||||
|
||||
ifstr.seekg(0x03C4);
|
||||
ifstr.read(reinterpret_cast<char*>(&visibleWater), sizeof(char)*64*64);
|
||||
ifstr.read(reinterpret_cast<char*>(&realWater), sizeof(char)*128*128);
|
||||
ifstr.read(reinterpret_cast<char*>(&visibleWater),
|
||||
sizeof(char) * 64 * 64);
|
||||
ifstr.read(reinterpret_cast<char*>(&realWater),
|
||||
sizeof(char) * 128 * 128);
|
||||
}
|
||||
}
|
||||
|
||||
void GameData::loadWater(const std::string& path)
|
||||
{
|
||||
void GameData::loadWater(const std::string& path) {
|
||||
std::ifstream ifstr(path.c_str());
|
||||
|
||||
std::string line;
|
||||
while( std::getline(ifstr, line)) {
|
||||
if( line[0] == ';') {
|
||||
while (std::getline(ifstr, line)) {
|
||||
if (line[0] == ';') {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -318,26 +283,21 @@ void GameData::loadWater(const std::string& path)
|
||||
std::string a, b, c, d, e;
|
||||
float fa, fb, fc, fd, fe;
|
||||
|
||||
if( std::getline(ss, a, ',') && std::getline(ss, b, ',') && std::getline(ss, c, ',') && std::getline(ss, d, ',') && std::getline(ss, e, ',')) {
|
||||
if (std::getline(ss, a, ',') && std::getline(ss, b, ',') &&
|
||||
std::getline(ss, c, ',') && std::getline(ss, d, ',') &&
|
||||
std::getline(ss, e, ',')) {
|
||||
fa = atof(a.c_str());
|
||||
fb = atof(b.c_str());
|
||||
fc = atof(c.c_str());
|
||||
fd = atof(d.c_str());
|
||||
fe = atof(e.c_str());
|
||||
waterBlocks.push_back({
|
||||
fa,
|
||||
fb,
|
||||
fc,
|
||||
fd,
|
||||
fe
|
||||
});
|
||||
waterBlocks.push_back({fa, fb, fc, fd, fe});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameData::loadTXD(const std::string& name, bool async)
|
||||
{
|
||||
if( loadedFiles.find(name) != loadedFiles.end() ) {
|
||||
void GameData::loadTXD(const std::string& name, bool async) {
|
||||
if (loadedFiles.find(name) != loadedFiles.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -345,73 +305,64 @@ void GameData::loadTXD(const std::string& name, bool async)
|
||||
|
||||
auto j = new LoadTextureArchiveJob(workContext, &index, textures, name);
|
||||
|
||||
if( async ) {
|
||||
workContext->queueJob( j );
|
||||
}
|
||||
else {
|
||||
if (async) {
|
||||
workContext->queueJob(j);
|
||||
} else {
|
||||
j->work();
|
||||
j->complete();
|
||||
delete j;
|
||||
}
|
||||
}
|
||||
|
||||
void GameData::loadDFF(const std::string& name, bool async)
|
||||
{
|
||||
void GameData::loadDFF(const std::string& name, bool async) {
|
||||
auto realname = name.substr(0, name.size() - 4);
|
||||
if( models.find(realname) != models.end() ) {
|
||||
if (models.find(realname) != models.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Before starting the job make sure the file isn't loaded again.
|
||||
loadedFiles.insert({name, true});
|
||||
|
||||
models[realname] = ModelRef( new ResourceHandle<Model>(realname) );
|
||||
models[realname] = ModelRef(new ResourceHandle<Model>(realname));
|
||||
|
||||
auto job = new BackgroundLoaderJob<Model, LoaderDFF>
|
||||
{ workContext, &this->index, name, models[realname] };
|
||||
auto job = new BackgroundLoaderJob<Model, LoaderDFF>{
|
||||
workContext, &this->index, name, models[realname]};
|
||||
|
||||
if( async ) {
|
||||
workContext->queueJob( job );
|
||||
}
|
||||
else {
|
||||
if (async) {
|
||||
workContext->queueJob(job);
|
||||
} else {
|
||||
job->work();
|
||||
job->complete();
|
||||
delete job;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GameData::loadIFP(const std::string &name)
|
||||
{
|
||||
void GameData::loadIFP(const std::string& name) {
|
||||
auto f = index.openFile(name);
|
||||
|
||||
if(f)
|
||||
{
|
||||
if (f) {
|
||||
LoaderIFP loader;
|
||||
if( loader.loadFromMemory(f->data) ) {
|
||||
animations.insert(loader.animations.begin(), loader.animations.end());
|
||||
if (loader.loadFromMemory(f->data)) {
|
||||
animations.insert(loader.animations.begin(),
|
||||
loader.animations.end());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void GameData::loadDynamicObjects(const std::string& name)
|
||||
{
|
||||
void GameData::loadDynamicObjects(const std::string& name) {
|
||||
GenericDATLoader l;
|
||||
|
||||
l.loadDynamicObjects(name, dynamicObjectData);
|
||||
}
|
||||
|
||||
void GameData::loadWeaponDAT(const std::string &path)
|
||||
{
|
||||
void GameData::loadWeaponDAT(const std::string& path) {
|
||||
GenericDATLoader l;
|
||||
auto syspath = index.findFilePath(path).string();
|
||||
|
||||
l.loadWeapons(syspath, weaponData);
|
||||
}
|
||||
|
||||
bool GameData::loadAudioStream(const std::string &name)
|
||||
{
|
||||
bool GameData::loadAudioStream(const std::string& name) {
|
||||
auto systempath = index.findFilePath("audio/" + name).string();
|
||||
|
||||
if (engine->cutsceneAudio.length() > 0) {
|
||||
@ -426,20 +377,19 @@ bool GameData::loadAudioStream(const std::string &name)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GameData::loadAudioClip(const std::string& name, const std::string& fileName)
|
||||
{
|
||||
bool GameData::loadAudioClip(const std::string& name,
|
||||
const std::string& fileName) {
|
||||
auto systempath = index.findFilePath("audio/" + fileName).string();
|
||||
|
||||
if (systempath.find(".mp3") != std::string::npos)
|
||||
{
|
||||
if (systempath.find(".mp3") != std::string::npos) {
|
||||
logger->error("Data", "MP3 Audio unsupported outside cutscenes");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool loaded = engine->sound.loadSound(name, systempath);
|
||||
|
||||
if ( ! loaded) {
|
||||
logger->error("Data", "Error loading audio clip "+ systempath);
|
||||
if (!loaded) {
|
||||
logger->error("Data", "Error loading audio clip " + systempath);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -448,8 +398,7 @@ bool GameData::loadAudioClip(const std::string& name, const std::string& fileNam
|
||||
return true;
|
||||
}
|
||||
|
||||
void GameData::loadSplash(const std::string &name)
|
||||
{
|
||||
void GameData::loadSplash(const std::string& name) {
|
||||
std::string lower(name);
|
||||
std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
|
||||
|
||||
@ -458,36 +407,34 @@ void GameData::loadSplash(const std::string &name)
|
||||
engine->state->currentSplash = lower;
|
||||
}
|
||||
|
||||
int GameData::getWaterIndexAt(const glm::vec3 &ws) const
|
||||
{
|
||||
auto wX = (int) ((ws.x + WATER_WORLD_SIZE/2.f) / (WATER_WORLD_SIZE/WATER_HQ_DATA_SIZE));
|
||||
auto wY = (int) ((ws.y + WATER_WORLD_SIZE/2.f) / (WATER_WORLD_SIZE/WATER_HQ_DATA_SIZE));
|
||||
int GameData::getWaterIndexAt(const glm::vec3& ws) const {
|
||||
auto wX = (int)((ws.x + WATER_WORLD_SIZE / 2.f) /
|
||||
(WATER_WORLD_SIZE / WATER_HQ_DATA_SIZE));
|
||||
auto wY = (int)((ws.y + WATER_WORLD_SIZE / 2.f) /
|
||||
(WATER_WORLD_SIZE / WATER_HQ_DATA_SIZE));
|
||||
|
||||
if( wX >= 0 && wX < WATER_HQ_DATA_SIZE && wY >= 0 && wY < WATER_HQ_DATA_SIZE ) {
|
||||
int i = (wX*WATER_HQ_DATA_SIZE) + wY;
|
||||
if (wX >= 0 && wX < WATER_HQ_DATA_SIZE && wY >= 0 &&
|
||||
wY < WATER_HQ_DATA_SIZE) {
|
||||
int i = (wX * WATER_HQ_DATA_SIZE) + wY;
|
||||
return engine->data->realWater[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
float GameData::getWaveHeightAt(const glm::vec3 &ws) const
|
||||
{
|
||||
return (1+sin(engine->getGameTime() + (ws.x + ws.y) * WATER_SCALE)) * WATER_HEIGHT;
|
||||
float GameData::getWaveHeightAt(const glm::vec3& ws) const {
|
||||
return (1 + sin(engine->getGameTime() + (ws.x + ws.y) * WATER_SCALE)) *
|
||||
WATER_HEIGHT;
|
||||
}
|
||||
|
||||
bool GameData::isValidGameDirectory(const std::string& path)
|
||||
{
|
||||
if(path.empty())
|
||||
{
|
||||
bool GameData::isValidGameDirectory(const std::string& path) {
|
||||
if (path.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LoaderIMG i;
|
||||
if(! i.load(path + "/models/gta3.img") )
|
||||
{
|
||||
if (!i.load(path + "/models/gta3.img")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -4,17 +4,17 @@
|
||||
|
||||
class Logger;
|
||||
|
||||
#include <rw/types.hpp>
|
||||
#include <loaders/LoaderIMG.hpp>
|
||||
#include <loaders/LoaderTXD.hpp>
|
||||
#include <loaders/LoaderDFF.hpp>
|
||||
#include <loaders/LoaderIDE.hpp>
|
||||
#include <loaders/LoaderIFP.hpp>
|
||||
#include <loaders/WeatherLoader.hpp>
|
||||
#include <objects/VehicleInfo.hpp>
|
||||
#include <data/CollisionModel.hpp>
|
||||
#include <data/GameTexts.hpp>
|
||||
#include <data/ZoneData.hpp>
|
||||
#include <loaders/LoaderDFF.hpp>
|
||||
#include <loaders/LoaderIDE.hpp>
|
||||
#include <loaders/LoaderIFP.hpp>
|
||||
#include <loaders/LoaderIMG.hpp>
|
||||
#include <loaders/LoaderTXD.hpp>
|
||||
#include <loaders/WeatherLoader.hpp>
|
||||
#include <objects/VehicleInfo.hpp>
|
||||
#include <rw/types.hpp>
|
||||
|
||||
#include <audio/MADStream.hpp>
|
||||
#include <gl/TextureData.hpp>
|
||||
@ -36,17 +36,15 @@ class SCMFile;
|
||||
* @todo Improve how Loaders and written and used
|
||||
* @todo Considering implementation of streaming data and object handles.
|
||||
*/
|
||||
class GameData
|
||||
{
|
||||
class GameData {
|
||||
private:
|
||||
|
||||
std::string datpath;
|
||||
std::string splash;
|
||||
|
||||
Logger* logger;
|
||||
WorkContext* workContext;
|
||||
public:
|
||||
|
||||
public:
|
||||
/**
|
||||
* ctor
|
||||
* @param path Path to the root of the game data.
|
||||
@ -59,16 +57,14 @@ public:
|
||||
/**
|
||||
* Returns the current platform
|
||||
*/
|
||||
std::string getPlatformString()
|
||||
{
|
||||
std::string getPlatformString() {
|
||||
return "PC";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the game data path
|
||||
*/
|
||||
const std::string& getDataPath() const
|
||||
{
|
||||
const std::string& getDataPath() const {
|
||||
return datpath;
|
||||
}
|
||||
|
||||
@ -147,8 +143,8 @@ public:
|
||||
|
||||
void loadSplash(const std::string& name);
|
||||
|
||||
TextureData::Handle findTexture( const std::string& name, const std::string& alpha = "" )
|
||||
{
|
||||
TextureData::Handle findTexture(const std::string& name,
|
||||
const std::string& alpha = "") {
|
||||
return textures[{name, alpha}];
|
||||
}
|
||||
|
||||
@ -181,13 +177,12 @@ public:
|
||||
|
||||
uint16_t findModelObject(const std::string model);
|
||||
|
||||
template<class T> std::shared_ptr<T> findObjectType(ObjectID id)
|
||||
{
|
||||
template <class T>
|
||||
std::shared_ptr<T> findObjectType(ObjectID id) {
|
||||
auto f = objectTypes.find(id);
|
||||
/// @TODO don't instanciate an object here just to read .type
|
||||
T tmp;
|
||||
if( f != objectTypes.end() && f->second->class_type == tmp.class_type )
|
||||
{
|
||||
if (f != objectTypes.end() && f->second->class_type == tmp.class_type) {
|
||||
return std::static_pointer_cast<T>(f->second);
|
||||
}
|
||||
return nullptr;
|
||||
@ -201,7 +196,8 @@ public:
|
||||
/**
|
||||
* The vehicle colours for each vehicle type
|
||||
*/
|
||||
std::map<std::string, std::vector<std::pair<size_t,size_t>>> vehiclePalettes;
|
||||
std::map<std::string, std::vector<std::pair<size_t, size_t>>>
|
||||
vehiclePalettes;
|
||||
|
||||
/**
|
||||
* Vehicle information
|
||||
@ -254,8 +250,7 @@ public:
|
||||
* @struct WaterArea
|
||||
* Stores Water Rectangle Information
|
||||
*/
|
||||
struct WaterArea
|
||||
{
|
||||
struct WaterArea {
|
||||
float height;
|
||||
float xLeft, yBottom;
|
||||
float xRight, yTop;
|
||||
@ -274,12 +269,12 @@ public:
|
||||
/**
|
||||
* Visible water heights
|
||||
*/
|
||||
uint8_t visibleWater[64*64];
|
||||
uint8_t visibleWater[64 * 64];
|
||||
|
||||
/**
|
||||
* The "real" water heights
|
||||
*/
|
||||
uint8_t realWater[128*128];
|
||||
uint8_t realWater[128 * 128];
|
||||
|
||||
int getWaterIndexAt(const glm::vec3& ws) const;
|
||||
float getWaveHeightAt(const glm::vec3& ws) const;
|
||||
|
@ -1,8 +1,7 @@
|
||||
#ifndef RWENGINE_GAMEINPUTSTATE_HPP
|
||||
#define RWENGINE_GAMEINPUTSTATE_HPP
|
||||
|
||||
struct GameInputState
|
||||
{
|
||||
struct GameInputState {
|
||||
static constexpr float kButtonOnThreshold = 0.1f;
|
||||
|
||||
/// Inputs that can be controlled
|
||||
@ -56,15 +55,13 @@ struct GameInputState
|
||||
*
|
||||
* For buttons, this will result in either 0 or 1.
|
||||
*/
|
||||
float currentLevels[_MaxControls] = { };
|
||||
float currentLevels[_MaxControls] = {};
|
||||
|
||||
float operator[] (Control c) const
|
||||
{
|
||||
float operator[](Control c) const {
|
||||
return currentLevels[c];
|
||||
}
|
||||
|
||||
bool pressed(Control c) const
|
||||
{
|
||||
bool pressed(Control c) const {
|
||||
return currentLevels[c] > kButtonOnThreshold;
|
||||
}
|
||||
};
|
||||
|
@ -1,95 +1,95 @@
|
||||
#include <engine/GameState.hpp>
|
||||
|
||||
BasicState::BasicState()
|
||||
: saveName { 0 }
|
||||
, saveTime { 0, 0, 0, 0, 0, 0, 0, 0 }
|
||||
, islandNumber { 0 }
|
||||
, cameraPosition { }
|
||||
, gameMinuteMS { 0 }
|
||||
, lastTick { 0 }
|
||||
, gameHour { 0 }
|
||||
, gameMinute { 0 }
|
||||
, padMode { 0 }
|
||||
, timeMS { 0 }
|
||||
, timeScale { 0 }
|
||||
, timeStep { 0 }
|
||||
, timeStep_unclipped { 0 }
|
||||
, frameCounter { 0 }
|
||||
, timeStep2 { 0 }
|
||||
, framesPerUpdate { 0 }
|
||||
, timeScale2 { 0 }
|
||||
, lastWeather { 0 }
|
||||
, nextWeather { 0 }
|
||||
, forcedWeather { 0 }
|
||||
, weatherInterpolation { 0 }
|
||||
, weatherType { 0 }
|
||||
, cameraData { 0 }
|
||||
, cameraData2 { 0 }
|
||||
{ }
|
||||
: saveName{0}
|
||||
, saveTime{0, 0, 0, 0, 0, 0, 0, 0}
|
||||
, islandNumber{0}
|
||||
, cameraPosition{}
|
||||
, gameMinuteMS{0}
|
||||
, lastTick{0}
|
||||
, gameHour{0}
|
||||
, gameMinute{0}
|
||||
, padMode{0}
|
||||
, timeMS{0}
|
||||
, timeScale{0}
|
||||
, timeStep{0}
|
||||
, timeStep_unclipped{0}
|
||||
, frameCounter{0}
|
||||
, timeStep2{0}
|
||||
, framesPerUpdate{0}
|
||||
, timeScale2{0}
|
||||
, lastWeather{0}
|
||||
, nextWeather{0}
|
||||
, forcedWeather{0}
|
||||
, weatherInterpolation{0}
|
||||
, weatherType{0}
|
||||
, cameraData{0}
|
||||
, cameraData2{0} {
|
||||
}
|
||||
|
||||
PlayerInfo::PlayerInfo()
|
||||
: money { 0 }
|
||||
, displayedMoney { 0 }
|
||||
, hiddenPackagesCollected { 0 }
|
||||
, hiddenPackageCount { 0 }
|
||||
, neverTired { 0 }
|
||||
, fastReload { 0 }
|
||||
, thaneOfLibertyCity { 0 }
|
||||
, singlePayerHealthcare { 0 }
|
||||
{ }
|
||||
: money{0}
|
||||
, displayedMoney{0}
|
||||
, hiddenPackagesCollected{0}
|
||||
, hiddenPackageCount{0}
|
||||
, neverTired{0}
|
||||
, fastReload{0}
|
||||
, thaneOfLibertyCity{0}
|
||||
, singlePayerHealthcare{0} {
|
||||
}
|
||||
|
||||
GameStats::GameStats()
|
||||
: playerKills { 0 }
|
||||
, otherKills { 0 }
|
||||
, carsExploded { 0 }
|
||||
, shotsHit { 0 }
|
||||
, pedTypesKilled { }
|
||||
, helicoptersDestroyed { 0 }
|
||||
, playerProgress { 0 }
|
||||
, explosiveKgsUsed { 0 }
|
||||
, bulletsFired { 0 }
|
||||
, bulletsHit { 0 }
|
||||
, carsCrushed { 0 }
|
||||
, headshots { 0 }
|
||||
, timesBusted { 0 }
|
||||
, timesHospital { 0 }
|
||||
, daysPassed { 0 }
|
||||
, mmRainfall { 0 }
|
||||
, insaneJumpMaxDistance { 0 }
|
||||
, insaneJumpMaxHeight { 0 }
|
||||
, insaneJumpMaxFlips { 0 }
|
||||
, insangeJumpMaxRotation { 0 }
|
||||
, bestStunt { 0 }
|
||||
, uniqueStuntsFound { 0 }
|
||||
, uniqueStuntsTotal { 0 }
|
||||
, missionAttempts { 0 }
|
||||
, missionsPassed { 0 }
|
||||
, passengersDroppedOff { 0 }
|
||||
, taxiRevenue { 0 }
|
||||
, portlandPassed { 0 }
|
||||
, stauntonPassed { 0 }
|
||||
, shoresidePassed { 0 }
|
||||
, bestTurismoTime { 0 }
|
||||
, distanceWalked { 0 }
|
||||
, distanceDriven { 0 }
|
||||
, patriotPlaygroundTime { 0 }
|
||||
, aRideInTheParkTime { 0 }
|
||||
, grippedTime { 0 }
|
||||
, multistoryMayhemTime { 0 }
|
||||
, peopleSaved { 0 }
|
||||
, criminalsKilled { 0 }
|
||||
, highestParamedicLevel { 0 }
|
||||
, firesExtinguished { 0 }
|
||||
, longestDodoFlight { 0 }
|
||||
, bombDefusalTime { 0 }
|
||||
, rampagesPassed { 0 }
|
||||
, totalRampages { 0 }
|
||||
, totalMissions { 0 }
|
||||
, highestScore { }
|
||||
, peopleKilledSinceCheckpoint { 0 }
|
||||
, peopleKilledSinceLastBustedOrWasted { 0 }
|
||||
, lastMissionGXT { "" }
|
||||
{ }
|
||||
: playerKills{0}
|
||||
, otherKills{0}
|
||||
, carsExploded{0}
|
||||
, shotsHit{0}
|
||||
, pedTypesKilled{}
|
||||
, helicoptersDestroyed{0}
|
||||
, playerProgress{0}
|
||||
, explosiveKgsUsed{0}
|
||||
, bulletsFired{0}
|
||||
, bulletsHit{0}
|
||||
, carsCrushed{0}
|
||||
, headshots{0}
|
||||
, timesBusted{0}
|
||||
, timesHospital{0}
|
||||
, daysPassed{0}
|
||||
, mmRainfall{0}
|
||||
, insaneJumpMaxDistance{0}
|
||||
, insaneJumpMaxHeight{0}
|
||||
, insaneJumpMaxFlips{0}
|
||||
, insangeJumpMaxRotation{0}
|
||||
, bestStunt{0}
|
||||
, uniqueStuntsFound{0}
|
||||
, uniqueStuntsTotal{0}
|
||||
, missionAttempts{0}
|
||||
, missionsPassed{0}
|
||||
, passengersDroppedOff{0}
|
||||
, taxiRevenue{0}
|
||||
, portlandPassed{0}
|
||||
, stauntonPassed{0}
|
||||
, shoresidePassed{0}
|
||||
, bestTurismoTime{0}
|
||||
, distanceWalked{0}
|
||||
, distanceDriven{0}
|
||||
, patriotPlaygroundTime{0}
|
||||
, aRideInTheParkTime{0}
|
||||
, grippedTime{0}
|
||||
, multistoryMayhemTime{0}
|
||||
, peopleSaved{0}
|
||||
, criminalsKilled{0}
|
||||
, highestParamedicLevel{0}
|
||||
, firesExtinguished{0}
|
||||
, longestDodoFlight{0}
|
||||
, bombDefusalTime{0}
|
||||
, rampagesPassed{0}
|
||||
, totalRampages{0}
|
||||
, totalMissions{0}
|
||||
, highestScore{}
|
||||
, peopleKilledSinceCheckpoint{0}
|
||||
, peopleKilledSinceLastBustedOrWasted{0}
|
||||
, lastMissionGXT{""} {
|
||||
}
|
||||
|
||||
GameState::GameState()
|
||||
: basic{}
|
||||
@ -115,22 +115,15 @@ GameState::GameState()
|
||||
, importExportShoreside(0)
|
||||
, importExportUnused(0)
|
||||
, world(nullptr)
|
||||
, script(nullptr)
|
||||
{
|
||||
|
||||
, script(nullptr) {
|
||||
}
|
||||
|
||||
int GameState::addRadarBlip(BlipData& blip)
|
||||
{
|
||||
int GameState::addRadarBlip(BlipData& blip) {
|
||||
int l = 0;
|
||||
for ( auto x = radarBlips.begin(); x != radarBlips.end(); ++x )
|
||||
{
|
||||
if ( (x->first) != l )
|
||||
{
|
||||
l = x->first-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto x = radarBlips.begin(); x != radarBlips.end(); ++x) {
|
||||
if ((x->first) != l) {
|
||||
l = x->first - 1;
|
||||
} else {
|
||||
l++;
|
||||
}
|
||||
}
|
||||
@ -141,11 +134,9 @@ int GameState::addRadarBlip(BlipData& blip)
|
||||
return l;
|
||||
}
|
||||
|
||||
void GameState::removeBlip(int blip)
|
||||
{
|
||||
auto it = radarBlips.find( blip );
|
||||
if ( it != radarBlips.end() )
|
||||
{
|
||||
void GameState::removeBlip(int blip) {
|
||||
auto it = radarBlips.find(blip);
|
||||
if (it != radarBlips.end()) {
|
||||
radarBlips.erase(it);
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
#pragma once
|
||||
#ifndef _GAMESTATE_HPP_
|
||||
#define _GAMESTATE_HPP_
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
#include <string>
|
||||
#include <bitset>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <objects/ObjectTypes.hpp>
|
||||
#include <engine/ScreenText.hpp>
|
||||
#include <data/VehicleGenerator.hpp>
|
||||
#include <engine/GameInputState.hpp>
|
||||
#include <engine/ScreenText.hpp>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
#include <map>
|
||||
#include <objects/ObjectTypes.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class GameWorld;
|
||||
class GameObject;
|
||||
@ -18,8 +18,7 @@ class ScriptMachine;
|
||||
class PlayerController;
|
||||
struct CutsceneData;
|
||||
|
||||
struct SystemTime
|
||||
{
|
||||
struct SystemTime {
|
||||
uint16_t year;
|
||||
uint16_t month;
|
||||
uint16_t dayOfWeek;
|
||||
@ -31,8 +30,7 @@ struct SystemTime
|
||||
};
|
||||
|
||||
/** Block 0 State */
|
||||
struct BasicState
|
||||
{
|
||||
struct BasicState {
|
||||
GameStringChar saveName[24];
|
||||
SystemTime saveTime;
|
||||
uint32_t unknown;
|
||||
@ -66,12 +64,11 @@ struct BasicState
|
||||
float cameraData;
|
||||
float cameraData2;
|
||||
|
||||
BasicState ();
|
||||
BasicState();
|
||||
};
|
||||
|
||||
/** Block 16 player info */
|
||||
struct PlayerInfo
|
||||
{
|
||||
struct PlayerInfo {
|
||||
uint32_t money;
|
||||
uint8_t unknown1;
|
||||
uint32_t unknown2;
|
||||
@ -86,12 +83,11 @@ struct PlayerInfo
|
||||
uint8_t singlePayerHealthcare;
|
||||
uint8_t unknown5[70];
|
||||
|
||||
PlayerInfo ();
|
||||
PlayerInfo();
|
||||
};
|
||||
|
||||
/** Block 17 */
|
||||
struct GameStats
|
||||
{
|
||||
struct GameStats {
|
||||
uint32_t playerKills;
|
||||
uint32_t otherKills;
|
||||
uint32_t carsExploded;
|
||||
@ -155,11 +151,10 @@ struct GameStats
|
||||
uint32_t peopleKilledSinceLastBustedOrWasted;
|
||||
char lastMissionGXT[8];
|
||||
|
||||
GameStats ();
|
||||
GameStats();
|
||||
};
|
||||
|
||||
struct TextDisplayData
|
||||
{
|
||||
struct TextDisplayData {
|
||||
// This is set by the final display text command.
|
||||
GameString text;
|
||||
glm::vec2 position;
|
||||
@ -171,12 +166,10 @@ struct TextDisplayData
|
||||
/**
|
||||
* Data about a blip
|
||||
*/
|
||||
struct BlipData
|
||||
{
|
||||
struct BlipData {
|
||||
int id;
|
||||
|
||||
enum BlipType
|
||||
{
|
||||
enum BlipType {
|
||||
Location = 0,
|
||||
Vehicle = 1,
|
||||
Pickup = 2,
|
||||
@ -194,23 +187,15 @@ struct BlipData
|
||||
|
||||
uint16_t size = 3; // Only used if texture is empty
|
||||
|
||||
enum DisplayMode
|
||||
{
|
||||
Hide = 0,
|
||||
MarkerOnly = 1,
|
||||
RadarOnly = 2,
|
||||
ShowBoth = 3
|
||||
};
|
||||
enum DisplayMode { Hide = 0, MarkerOnly = 1, RadarOnly = 2, ShowBoth = 3 };
|
||||
|
||||
/* Should the blip be displayed? */
|
||||
DisplayMode display;
|
||||
|
||||
BlipData()
|
||||
: id(-1), type(Location), target(0), display(ShowBoth)
|
||||
{ }
|
||||
BlipData() : id(-1), type(Location), target(0), display(ShowBoth) {
|
||||
}
|
||||
|
||||
int getScriptObjectID() const
|
||||
{
|
||||
int getScriptObjectID() const {
|
||||
return id;
|
||||
}
|
||||
};
|
||||
@ -218,8 +203,7 @@ struct BlipData
|
||||
/**
|
||||
* Data for garages
|
||||
*/
|
||||
struct GarageInfo
|
||||
{
|
||||
struct GarageInfo {
|
||||
enum /*GarageType*/ {
|
||||
GARAGE_MISSION = 1,
|
||||
GARAGE_BOMBSHOP1 = 2,
|
||||
@ -248,18 +232,11 @@ struct GarageInfo
|
||||
glm::vec3 max;
|
||||
int type;
|
||||
|
||||
GarageInfo(int id_,
|
||||
const glm::vec3 min_,
|
||||
const glm::vec3 max_,
|
||||
int type_)
|
||||
: id(id_)
|
||||
, min(min_)
|
||||
, max(max_)
|
||||
, type(type_)
|
||||
{ }
|
||||
GarageInfo(int id_, const glm::vec3 min_, const glm::vec3 max_, int type_)
|
||||
: id(id_), min(min_), max(max_), type(type_) {
|
||||
}
|
||||
|
||||
int getScriptObjectID() const
|
||||
{
|
||||
int getScriptObjectID() const {
|
||||
return id;
|
||||
}
|
||||
};
|
||||
@ -268,8 +245,7 @@ struct GarageInfo
|
||||
* Gameplay state object that holds persistent state, and references runtime
|
||||
* world state.
|
||||
*/
|
||||
class GameState
|
||||
{
|
||||
class GameState {
|
||||
public:
|
||||
/**
|
||||
Basic Game State
|
||||
@ -298,7 +274,8 @@ public:
|
||||
GameObjectID playerObject;
|
||||
|
||||
/**
|
||||
* @brief Stores a pointer to script global that stores the on-mission state.
|
||||
* @brief Stores a pointer to script global that stores the on-mission
|
||||
* state.
|
||||
*/
|
||||
int32_t* scriptOnMissionFlag;
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -8,8 +8,8 @@ class Logger;
|
||||
class GameData;
|
||||
class GameState;
|
||||
|
||||
#include <ai/AIGraphNode.hpp>
|
||||
#include <ai/AIGraph.hpp>
|
||||
#include <ai/AIGraphNode.hpp>
|
||||
#include <audio/SoundManager.hpp>
|
||||
|
||||
class CutsceneObject;
|
||||
@ -23,8 +23,8 @@ class VehicleObject;
|
||||
class PickupObject;
|
||||
|
||||
class ViewCamera;
|
||||
#include <render/VisualFX.hpp>
|
||||
#include <data/ObjectData.hpp>
|
||||
#include <render/VisualFX.hpp>
|
||||
|
||||
struct BlipData;
|
||||
class InventoryItem;
|
||||
@ -35,38 +35,32 @@ struct VehicleGenerator;
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
#include <btBulletCollisionCommon.h>
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <random>
|
||||
#include <array>
|
||||
#include <random>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* Information about "Goal" locations so they can be rendered
|
||||
* (this doesn't really belong here).
|
||||
*/
|
||||
struct AreaIndicatorInfo
|
||||
{
|
||||
enum AreaIndicatorType
|
||||
{
|
||||
Cylinder
|
||||
};
|
||||
struct AreaIndicatorInfo {
|
||||
enum AreaIndicatorType { Cylinder };
|
||||
|
||||
AreaIndicatorType type;
|
||||
glm::vec3 position;
|
||||
glm::vec3 radius;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Handles all data relating to object instances and other "worldly" state.
|
||||
* @brief Handles all data relating to object instances and other "worldly"
|
||||
* state.
|
||||
*/
|
||||
class GameWorld
|
||||
{
|
||||
class GameWorld {
|
||||
public:
|
||||
|
||||
GameWorld(Logger* log, WorkContext* work, GameData* dat);
|
||||
|
||||
~GameWorld();
|
||||
@ -90,7 +84,8 @@ public:
|
||||
void createTraffic(const ViewCamera& viewCamera);
|
||||
|
||||
/**
|
||||
* @brief cleanupTraffic Cleans up traffic too far away from the given camera
|
||||
* @brief cleanupTraffic Cleans up traffic too far away from the given
|
||||
* camera
|
||||
* @param viewCamera
|
||||
*/
|
||||
void cleanupTraffic(const ViewCamera& viewCamera);
|
||||
@ -98,27 +93,36 @@ public:
|
||||
/**
|
||||
* Creates an instance
|
||||
*/
|
||||
InstanceObject *createInstance(const uint16_t id, const glm::vec3& pos, const glm::quat& rot = glm::quat());
|
||||
InstanceObject* createInstance(const uint16_t id, const glm::vec3& pos,
|
||||
const glm::quat& rot = glm::quat());
|
||||
|
||||
/**
|
||||
* @brief Creates an InstanceObject for use in the current Cutscene.
|
||||
*/
|
||||
CutsceneObject *createCutsceneObject(const uint16_t id, const glm::vec3& pos, const glm::quat& rot = glm::quat());
|
||||
CutsceneObject* createCutsceneObject(const uint16_t id,
|
||||
const glm::vec3& pos,
|
||||
const glm::quat& rot = glm::quat());
|
||||
|
||||
/**
|
||||
* Creates a vehicle
|
||||
*/
|
||||
VehicleObject *createVehicle(const uint16_t id, const glm::vec3& pos, const glm::quat& rot = glm::quat(), GameObjectID gid = 0);
|
||||
VehicleObject* createVehicle(const uint16_t id, const glm::vec3& pos,
|
||||
const glm::quat& rot = glm::quat(),
|
||||
GameObjectID gid = 0);
|
||||
|
||||
/**
|
||||
* Creates a pedestrian.
|
||||
*/
|
||||
CharacterObject* createPedestrian(const uint16_t id, const glm::vec3& pos, const glm::quat& rot = glm::quat(), GameObjectID gid = 0);
|
||||
CharacterObject* createPedestrian(const uint16_t id, const glm::vec3& pos,
|
||||
const glm::quat& rot = glm::quat(),
|
||||
GameObjectID gid = 0);
|
||||
|
||||
/**
|
||||
* Creates a player
|
||||
*/
|
||||
CharacterObject* createPlayer(const glm::vec3& pos, const glm::quat& rot = glm::quat(), GameObjectID gid = 0);
|
||||
CharacterObject* createPlayer(const glm::vec3& pos,
|
||||
const glm::quat& rot = glm::quat(),
|
||||
GameObjectID gid = 0);
|
||||
|
||||
/**
|
||||
* Creates a pickup
|
||||
@ -143,7 +147,7 @@ public:
|
||||
/**
|
||||
* Performs a weapon scan against things in the world
|
||||
*/
|
||||
void doWeaponScan(const WeaponScan &scan );
|
||||
void doWeaponScan(const WeaponScan& scan);
|
||||
|
||||
/**
|
||||
* Allocates a new VisualFX of the given type
|
||||
@ -206,8 +210,7 @@ public:
|
||||
* Each object type is allocated from a pool. This object helps manage
|
||||
* the individual pools.
|
||||
*/
|
||||
struct ObjectPool
|
||||
{
|
||||
struct ObjectPool {
|
||||
std::map<GameObjectID, GameObject*> objects;
|
||||
|
||||
/**
|
||||
@ -248,7 +251,7 @@ public:
|
||||
* @param blip
|
||||
* @return The targetted object of the given blip
|
||||
*/
|
||||
GameObject *getBlipTarget(const BlipData &blip) const;
|
||||
GameObject* getBlipTarget(const BlipData& blip) const;
|
||||
|
||||
/**
|
||||
* Map of Model Names to Instances
|
||||
@ -284,14 +287,16 @@ public:
|
||||
* @brief physicsNearCallback
|
||||
* Used to implement uprooting and other physics oddities.
|
||||
*/
|
||||
static bool ContactProcessedCallback(btManifoldPoint& mp, void* body0, void* body1);
|
||||
static bool ContactProcessedCallback(btManifoldPoint& mp, void* body0,
|
||||
void* body1);
|
||||
|
||||
/**
|
||||
* @brief PhysicsTickCallback updates object each physics tick.
|
||||
* @param physWorld
|
||||
* @param timeStep
|
||||
*/
|
||||
static void PhysicsTickCallback(btDynamicsWorld* physWorld, btScalar timeStep);
|
||||
static void PhysicsTickCallback(btDynamicsWorld* physWorld,
|
||||
btScalar timeStep);
|
||||
|
||||
/**
|
||||
* Work related
|
||||
@ -314,15 +319,21 @@ public:
|
||||
/**
|
||||
* @brief loads a model into a special character slot.
|
||||
*/
|
||||
void loadSpecialCharacter(const unsigned short index, const std::string& name);
|
||||
void loadSpecialCharacter(const unsigned short index,
|
||||
const std::string& name);
|
||||
void loadSpecialModel(const unsigned short index, const std::string& name);
|
||||
|
||||
void disableAIPaths(AIGraphNode::NodeType type, const glm::vec3& min, const glm::vec3& max);
|
||||
void enableAIPaths(AIGraphNode::NodeType type, const glm::vec3& min, const glm::vec3& max);
|
||||
void disableAIPaths(AIGraphNode::NodeType type, const glm::vec3& min,
|
||||
const glm::vec3& max);
|
||||
void enableAIPaths(AIGraphNode::NodeType type, const glm::vec3& min,
|
||||
const glm::vec3& max);
|
||||
|
||||
void drawAreaIndicator(AreaIndicatorInfo::AreaIndicatorType type, glm::vec3 position, glm::vec3 radius);
|
||||
void drawAreaIndicator(AreaIndicatorInfo::AreaIndicatorType type,
|
||||
glm::vec3 position, glm::vec3 radius);
|
||||
|
||||
const std::vector<AreaIndicatorInfo>& getAreaIndicators() const { return areaIndicators; }
|
||||
const std::vector<AreaIndicatorInfo>& getAreaIndicators() const {
|
||||
return areaIndicators;
|
||||
}
|
||||
|
||||
void clearTickData();
|
||||
|
||||
@ -335,7 +346,6 @@ public:
|
||||
VehicleObject* tryToSpawnVehicle(VehicleGenerator& gen);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* @brief Used by objects to delete themselves during updates.
|
||||
*/
|
||||
|
@ -1,16 +1,16 @@
|
||||
#include <engine/SaveGame.hpp>
|
||||
#include <ai/PlayerController.hpp>
|
||||
#include <cstring>
|
||||
#include <engine/GameData.hpp>
|
||||
#include <engine/GameState.hpp>
|
||||
#include <engine/GameWorld.hpp>
|
||||
#include <objects/GameObject.hpp>
|
||||
#include <engine/GameData.hpp>
|
||||
#include <objects/VehicleObject.hpp>
|
||||
#include <objects/CharacterObject.hpp>
|
||||
#include <objects/InstanceObject.hpp>
|
||||
#include <script/ScriptMachine.hpp>
|
||||
#include <script/SCMFile.hpp>
|
||||
#include <ai/PlayerController.hpp>
|
||||
#include <engine/SaveGame.hpp>
|
||||
#include <items/WeaponItem.hpp>
|
||||
#include <cstring>
|
||||
#include <objects/CharacterObject.hpp>
|
||||
#include <objects/GameObject.hpp>
|
||||
#include <objects/InstanceObject.hpp>
|
||||
#include <objects/VehicleObject.hpp>
|
||||
#include <script/SCMFile.hpp>
|
||||
#include <script/ScriptMachine.hpp>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
@ -47,7 +47,7 @@ struct Block0RunningScript {
|
||||
BlockDword unknown1;
|
||||
BlockWord stackCounter;
|
||||
BlockWord unknown2;
|
||||
SCMByte variables[16*4];
|
||||
SCMByte variables[16 * 4];
|
||||
BlockDword timerA;
|
||||
BlockDword timerB;
|
||||
uint8_t ifFlag;
|
||||
@ -358,7 +358,6 @@ struct Block10Data {
|
||||
Block10Blip blips[32];
|
||||
};
|
||||
|
||||
|
||||
struct Block11Zone {
|
||||
char name[8];
|
||||
glm::vec3 coordA;
|
||||
@ -472,31 +471,31 @@ struct Block19Data {
|
||||
Block19PedType types[23];
|
||||
};
|
||||
|
||||
void SaveGame::writeGame(GameState& state, const std::string& file)
|
||||
{
|
||||
void SaveGame::writeGame(GameState& state, const std::string& file) {
|
||||
RW_UNUSED(state);
|
||||
RW_UNUSED(file);
|
||||
RW_UNIMPLEMENTED("Saving the game is not implemented yet.");
|
||||
}
|
||||
|
||||
template<class T> bool readBlock(std::FILE* str, T& out) {
|
||||
template <class T>
|
||||
bool readBlock(std::FILE* str, T& out) {
|
||||
return std::fread(&out, sizeof(out), 1, str) == 1;
|
||||
}
|
||||
|
||||
#define READ_VALUE(var) \
|
||||
if (! readBlock(loadFile, var)) { \
|
||||
if (!readBlock(loadFile, var)) { \
|
||||
std::cerr << file << ": Failed to load block " #var << std::endl; \
|
||||
return false; \
|
||||
}
|
||||
#define READ_SIZE(var) \
|
||||
if (! readBlock(loadFile, var)) { \
|
||||
if (!readBlock(loadFile, var)) { \
|
||||
std::cerr << file << ": Failed to load size " #var << std::endl; \
|
||||
return false; \
|
||||
}
|
||||
#define CHECK_SIG(expected) \
|
||||
{\
|
||||
{ \
|
||||
char signature[4]; \
|
||||
if(fread(signature, sizeof(char), 4, loadFile) != 4) { \
|
||||
if (fread(signature, sizeof(char), 4, loadFile) != 4) { \
|
||||
std::cerr << "Failed to read signature" << std::endl; \
|
||||
return false; \
|
||||
} \
|
||||
@ -504,14 +503,13 @@ template<class T> bool readBlock(std::FILE* str, T& out) {
|
||||
std::cerr << "Signature " expected " incorrect" << std::endl; \
|
||||
return false; \
|
||||
} \
|
||||
}
|
||||
}
|
||||
#define BLOCK_HEADER(sizevar) \
|
||||
fseek(loadFile, nextBlock, SEEK_SET); \
|
||||
READ_SIZE(sizevar) \
|
||||
nextBlock += sizeof(sizevar) + sizevar;
|
||||
|
||||
bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
{
|
||||
bool SaveGame::loadGame(GameState& state, const std::string& file) {
|
||||
std::FILE* loadFile = std::fopen(file.c_str(), "rb");
|
||||
if (loadFile == nullptr) {
|
||||
std::cerr << "Failed to open save file" << std::endl;
|
||||
@ -524,7 +522,8 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
BlockDword blockSize;
|
||||
BLOCK_HEADER(blockSize);
|
||||
|
||||
static_assert(sizeof(BasicState) == 0xBC, "BasicState is not the right size");
|
||||
static_assert(sizeof(BasicState) == 0xBC,
|
||||
"BasicState is not the right size");
|
||||
READ_VALUE(state.basic)
|
||||
|
||||
BlockDword scriptBlockSize;
|
||||
@ -537,15 +536,15 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
READ_SIZE(scriptVarCount)
|
||||
assert(scriptVarCount == state.script->getFile()->getGlobalsSize());
|
||||
|
||||
if(fread(state.script->getGlobals(), sizeof(SCMByte), scriptVarCount, loadFile) != scriptVarCount)
|
||||
{
|
||||
if (fread(state.script->getGlobals(), sizeof(SCMByte), scriptVarCount,
|
||||
loadFile) != scriptVarCount) {
|
||||
std::cerr << "Failed to read script memory" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
BlockDword scriptDataBlockSize;
|
||||
READ_SIZE(scriptDataBlockSize);
|
||||
if( scriptDataBlockSize != 0x03C8 ) {
|
||||
if (scriptDataBlockSize != 0x03C8) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -555,8 +554,7 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
BlockDword numScripts;
|
||||
READ_SIZE(numScripts)
|
||||
std::vector<Block0RunningScript> scripts(numScripts);
|
||||
for (size_t i = 0; i < numScripts; ++i)
|
||||
{
|
||||
for (size_t i = 0; i < numScripts; ++i) {
|
||||
READ_VALUE(scripts[i]);
|
||||
}
|
||||
|
||||
@ -569,7 +567,7 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
READ_SIZE(playerCount)
|
||||
|
||||
std::vector<Block1PlayerPed> players(playerCount);
|
||||
for(unsigned int p = 0; p < playerCount; ++p) {
|
||||
for (unsigned int p = 0; p < playerCount; ++p) {
|
||||
Block1PlayerPed& ped = players[p];
|
||||
READ_VALUE(ped.unknown0)
|
||||
READ_VALUE(ped.unknown1)
|
||||
@ -581,11 +579,13 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
READ_VALUE(ped.align)
|
||||
|
||||
#if RW_DEBUG
|
||||
std::cout << "Player Health: " << ped.info.health << " (" << ped.info.armour << ")" << std::endl;
|
||||
std::cout << "Player Health: " << ped.info.health << " ("
|
||||
<< ped.info.armour << ")" << std::endl;
|
||||
std::cout << "Player model: " << ped.modelName << std::endl;
|
||||
for(int w = 0; w < 13; ++w) {
|
||||
for (int w = 0; w < 13; ++w) {
|
||||
auto& wep = players[p].info.weapons[w];
|
||||
std::cout << "ID " << wep.weaponId << " " << wep.inClip << " " << wep.totalBullets << std::endl;
|
||||
std::cout << "ID " << wep.weaponId << " " << wep.inClip << " "
|
||||
<< wep.totalBullets << std::endl;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -610,8 +610,7 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
READ_VALUE(garageData.cars)
|
||||
|
||||
std::vector<StructGarage> garages(garageData.garageCount);
|
||||
for (size_t i = 0; i < garageData.garageCount; ++i)
|
||||
{
|
||||
for (size_t i = 0; i < garageData.garageCount; ++i) {
|
||||
READ_VALUE(garages[i]);
|
||||
}
|
||||
|
||||
@ -619,14 +618,17 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
std::cout << "Garages: " << garageData.garageCount << std::endl;
|
||||
std::cout << "Bombs Free: " << garageData.freeBombs << std::endl;
|
||||
std::cout << "Sprays Free: " << garageData.freeResprays << std::endl;
|
||||
std::cout << "Portland IE: " << garageData.bfImportExportPortland << std::endl;
|
||||
std::cout << "Shoreside IE: " << garageData.bfImportExportShoreside << std::endl;
|
||||
std::cout << "Portland IE: " << garageData.bfImportExportPortland
|
||||
<< std::endl;
|
||||
std::cout << "Shoreside IE: " << garageData.bfImportExportShoreside
|
||||
<< std::endl;
|
||||
std::cout << "GA21 last shown: " << garageData.GA_21lastTime << std::endl;
|
||||
for (int c = 0; c < 18; ++c) {
|
||||
StructStoredCar& car = garageData.cars[c];
|
||||
if (car.modelId == 0) continue;
|
||||
std::cout << " " << car.modelId << " " << uint16_t(car.colorFG) << "/" << uint16_t(car.colorBG)
|
||||
<< " " << car.immunities << std::endl;
|
||||
std::cout << " " << car.modelId << " " << uint16_t(car.colorFG) << "/"
|
||||
<< uint16_t(car.colorBG) << " " << car.immunities
|
||||
<< std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -642,25 +644,29 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
READ_VALUE(boatCount)
|
||||
|
||||
std::vector<Block3Vehicle> vehicles(vehicleCount);
|
||||
for(size_t v = 0; v < vehicleCount; ++v) {
|
||||
for (size_t v = 0; v < vehicleCount; ++v) {
|
||||
Block3Vehicle& veh = vehicles[v];
|
||||
READ_VALUE(veh.unknown1)
|
||||
READ_VALUE(veh.modelId)
|
||||
READ_VALUE(veh.unknown2)
|
||||
READ_VALUE(veh.state)
|
||||
#if RW_DEBUG
|
||||
std::cout << " v " << veh.modelId << " " << veh.state.position.x << " " << veh.state.position.y << " " << veh.state.position.z << std::endl;
|
||||
std::cout << " v " << veh.modelId << " " << veh.state.position.x << " "
|
||||
<< veh.state.position.y << " " << veh.state.position.z
|
||||
<< std::endl;
|
||||
#endif
|
||||
}
|
||||
std::vector<Block3Boat> boats(boatCount);
|
||||
for(size_t v = 0; v < boatCount; ++v) {
|
||||
for (size_t v = 0; v < boatCount; ++v) {
|
||||
Block3Boat& veh = boats[v];
|
||||
READ_VALUE(veh.unknown1)
|
||||
READ_VALUE(veh.modelId)
|
||||
READ_VALUE(veh.unknown2)
|
||||
READ_VALUE(veh.state)
|
||||
#if RW_DEBUG
|
||||
std::cout << " b " << veh.modelId << " " << veh.state.position.x << " " << veh.state.position.y << " " << veh.state.position.z << std::endl;
|
||||
std::cout << " b " << veh.modelId << " " << veh.state.position.x << " "
|
||||
<< veh.state.position.y << " " << veh.state.position.z
|
||||
<< std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -674,9 +680,8 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
READ_VALUE(objectCount);
|
||||
|
||||
std::vector<Block4Object> objects(objectCount);
|
||||
for(size_t o = 0; o < objectCount; ++o)
|
||||
{
|
||||
Block4Object &obj = objects[o];
|
||||
for (size_t o = 0; o < objectCount; ++o) {
|
||||
Block4Object& obj = objects[o];
|
||||
READ_VALUE(obj.modelId)
|
||||
READ_VALUE(obj.reference)
|
||||
READ_VALUE(obj.position)
|
||||
@ -694,11 +699,15 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
}
|
||||
|
||||
for (size_t o = 0; o < objectCount; ++o) {
|
||||
auto &obj = objects[o];
|
||||
GameObject* inst = state.world->createInstance(obj.modelId, obj.position);
|
||||
glm::vec3 right = glm::normalize(glm::vec3(obj.rotation[0], obj.rotation[1], obj.rotation[2]));
|
||||
glm::vec3 forward = glm::normalize(glm::vec3(obj.rotation[3], obj.rotation[4], obj.rotation[5]));
|
||||
glm::vec3 down = glm::normalize(glm::vec3(obj.rotation[6], obj.rotation[7], obj.rotation[8]));
|
||||
auto& obj = objects[o];
|
||||
GameObject* inst =
|
||||
state.world->createInstance(obj.modelId, obj.position);
|
||||
glm::vec3 right = glm::normalize(
|
||||
glm::vec3(obj.rotation[0], obj.rotation[1], obj.rotation[2]));
|
||||
glm::vec3 forward = glm::normalize(
|
||||
glm::vec3(obj.rotation[3], obj.rotation[4], obj.rotation[5]));
|
||||
glm::vec3 down = glm::normalize(
|
||||
glm::vec3(obj.rotation[6], obj.rotation[7], obj.rotation[8]));
|
||||
glm::mat3 m = glm::mat3(right, forward, -down);
|
||||
inst->setRotation(glm::normalize(static_cast<glm::quat>(m)));
|
||||
}
|
||||
@ -706,15 +715,22 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
#if RW_DEBUG
|
||||
std::cout << "Objects " << objectCount << std::endl;
|
||||
for (size_t o = 0; o < objectCount; ++o) {
|
||||
auto &obj = objects[o];
|
||||
glm::vec3 right = glm::normalize(glm::vec3(obj.rotation[0], obj.rotation[1], obj.rotation[2]));
|
||||
glm::vec3 forward = glm::normalize(glm::vec3(obj.rotation[3], obj.rotation[4], obj.rotation[5]));
|
||||
glm::vec3 down = glm::normalize(glm::vec3(obj.rotation[6], obj.rotation[7], obj.rotation[8]));
|
||||
auto& obj = objects[o];
|
||||
glm::vec3 right = glm::normalize(
|
||||
glm::vec3(obj.rotation[0], obj.rotation[1], obj.rotation[2]));
|
||||
glm::vec3 forward = glm::normalize(
|
||||
glm::vec3(obj.rotation[3], obj.rotation[4], obj.rotation[5]));
|
||||
glm::vec3 down = glm::normalize(
|
||||
glm::vec3(obj.rotation[6], obj.rotation[7], obj.rotation[8]));
|
||||
std::cout << "modelId " << obj.modelId << " ";
|
||||
std::cout << "position " << obj.position.x << " "<< obj.position.y << " " << obj.position.z << " ";
|
||||
std::cout << "right " << right.x << " "<< right.y << " " << right.z << " ";
|
||||
std::cout << "forward " << forward.x << " "<< forward.y << " " << forward.z << " ";
|
||||
std::cout << "down " << down.x << " " << down.y << " " << down.z << std::endl;
|
||||
std::cout << "position " << obj.position.x << " " << obj.position.y
|
||||
<< " " << obj.position.z << " ";
|
||||
std::cout << "right " << right.x << " " << right.y << " " << right.z
|
||||
<< " ";
|
||||
std::cout << "forward " << forward.x << " " << forward.y << " "
|
||||
<< forward.z << " ";
|
||||
std::cout << "down " << down.x << " " << down.y << " " << down.z
|
||||
<< std::endl;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
@ -741,17 +757,19 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
Block6Data craneData;
|
||||
READ_VALUE(craneData.numCranes)
|
||||
READ_VALUE(craneData.militaryCollected)
|
||||
for(size_t c = 0; c < craneData.numCranes; ++c) {
|
||||
Block6Crane &crane = craneData.cranes[c];
|
||||
for (size_t c = 0; c < craneData.numCranes; ++c) {
|
||||
Block6Crane& crane = craneData.cranes[c];
|
||||
READ_VALUE(crane)
|
||||
}
|
||||
|
||||
#if RW_DEBUG
|
||||
std::cout << "Cranes: " << craneData.numCranes << std::endl;
|
||||
for(size_t c = 0; c < craneData.numCranes; ++c) {
|
||||
Block6Crane &crane = craneData.cranes[c];
|
||||
std::cout << "pickup " << crane.x1Pickup << " " << crane.y1Pickup << " " << crane.x2Pickup << " " << crane.y2Pickup << std::endl;
|
||||
std::cout << "vehicles collected " << uint16_t(crane.vehiclesCollected) << std::endl;
|
||||
for (size_t c = 0; c < craneData.numCranes; ++c) {
|
||||
Block6Crane& crane = craneData.cranes[c];
|
||||
std::cout << "pickup " << crane.x1Pickup << " " << crane.y1Pickup << " "
|
||||
<< crane.x2Pickup << " " << crane.y2Pickup << std::endl;
|
||||
std::cout << "vehicles collected " << uint16_t(crane.vehiclesCollected)
|
||||
<< std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -765,10 +783,11 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
READ_VALUE(pickupData);
|
||||
|
||||
#if RW_DEBUG
|
||||
for(int c = 0; c < 336; ++c) {
|
||||
Block7Pickup &p = pickupData.pickups[c];
|
||||
for (int c = 0; c < 336; ++c) {
|
||||
Block7Pickup& p = pickupData.pickups[c];
|
||||
if (p.type == 0) continue;
|
||||
std::cout << " " << uint16_t(p.type) << " " << p.position.x << " " << p.position.y << " " << p.position.z << std::endl;
|
||||
std::cout << " " << uint16_t(p.type) << " " << p.position.x << " "
|
||||
<< p.position.y << " " << p.position.z << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -782,15 +801,17 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
READ_VALUE(phoneData);
|
||||
std::vector<Block8Phone> phones(phoneData.numPhones);
|
||||
for (size_t p = 0; p < phoneData.numPhones; ++p) {
|
||||
Block8Phone &phone = phones[p];
|
||||
Block8Phone& phone = phones[p];
|
||||
READ_VALUE(phone)
|
||||
}
|
||||
|
||||
#if RW_DEBUG
|
||||
std::cout << "Phones: " << phoneData.numPhones << std::endl;
|
||||
for (size_t p = 0; p < phoneData.numPhones; ++p) {
|
||||
Block8Phone &phone = phones[p];
|
||||
std::cout << " " << uint16_t(phone.state) << " " << phone.position.x << " " << phone.position.y << " " << phone.position.z << std::endl;
|
||||
Block8Phone& phone = phones[p];
|
||||
std::cout << " " << uint16_t(phone.state) << " " << phone.position.x
|
||||
<< " " << phone.position.y << " " << phone.position.z
|
||||
<< std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -806,14 +827,17 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
READ_VALUE(restartData);
|
||||
|
||||
#if RW_DEBUG
|
||||
std::cout << "Hospitals: " << restartData.numHospitals << " police: " << restartData.numPolice << std::endl;
|
||||
for(int s = 0; s < restartData.numHospitals; ++s) {
|
||||
Block9Restart &p = restartData.hospitalRestarts[s];
|
||||
std::cout << " H " << p.position.x << " " << p.position.y << " " << p.position.z << std::endl;
|
||||
std::cout << "Hospitals: " << restartData.numHospitals
|
||||
<< " police: " << restartData.numPolice << std::endl;
|
||||
for (int s = 0; s < restartData.numHospitals; ++s) {
|
||||
Block9Restart& p = restartData.hospitalRestarts[s];
|
||||
std::cout << " H " << p.position.x << " " << p.position.y << " "
|
||||
<< p.position.z << std::endl;
|
||||
}
|
||||
for(int s = 0; s < restartData.numPolice; ++s) {
|
||||
Block9Restart &p = restartData.policeRestarts[s];
|
||||
std::cout << " P " << p.position.x << " " << p.position.y << " " << p.position.z << std::endl;
|
||||
for (int s = 0; s < restartData.numPolice; ++s) {
|
||||
Block9Restart& p = restartData.policeRestarts[s];
|
||||
std::cout << " P " << p.position.x << " " << p.position.y << " "
|
||||
<< p.position.z << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -829,10 +853,11 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
READ_VALUE(radarData);
|
||||
|
||||
#if RW_DEBUG
|
||||
for(int b = 0; b < 32; ++b) {
|
||||
Block10Blip &p = radarData.blips[b];
|
||||
for (int b = 0; b < 32; ++b) {
|
||||
Block10Blip& p = radarData.blips[b];
|
||||
if (p.type == 0) continue;
|
||||
std::cout << " " << p.position.x << " " << p.position.y << " " << p.position.z << std::endl;
|
||||
std::cout << " " << p.position.x << " " << p.position.y << " "
|
||||
<< p.position.z << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -850,7 +875,7 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
READ_VALUE(zoneData.findIndex);
|
||||
READ_VALUE(zoneData.align);
|
||||
for (int z = 0; z < 50; z++) {
|
||||
Block11Zone &zone = zoneData.navZones[z];
|
||||
Block11Zone& zone = zoneData.navZones[z];
|
||||
READ_VALUE(zone.name);
|
||||
READ_VALUE(zone.coordA);
|
||||
READ_VALUE(zone.coordB);
|
||||
@ -863,14 +888,14 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
READ_VALUE(zone.siblingZone);
|
||||
}
|
||||
for (int z = 0; z < 100; z++) {
|
||||
Block11ZoneInfo &info = zoneData.dayNightInfo[z];
|
||||
Block11ZoneInfo& info = zoneData.dayNightInfo[z];
|
||||
READ_VALUE(info.density)
|
||||
READ_VALUE(info.unknown1)
|
||||
}
|
||||
READ_VALUE(zoneData.numNavZones);
|
||||
READ_VALUE(zoneData.numZoneInfos);
|
||||
for (int z = 0; z < 25; z++) {
|
||||
Block11Zone &zone = zoneData.mapZones[z];
|
||||
Block11Zone& zone = zoneData.mapZones[z];
|
||||
READ_VALUE(zone.name);
|
||||
READ_VALUE(zone.coordA);
|
||||
READ_VALUE(zone.coordB);
|
||||
@ -889,14 +914,15 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
READ_VALUE(zoneData.numAudioZones);
|
||||
|
||||
#if RW_DEBUG
|
||||
std::cout << "zones: " << zoneData.numNavZones << " " << zoneData.numZoneInfos << " "
|
||||
<< zoneData.numMapZones << " " << zoneData.numAudioZones << std::endl;
|
||||
for(int z = 0; z < zoneData.numNavZones; ++z) {
|
||||
Block11Zone &zone = zoneData.navZones[z];
|
||||
std::cout << "zones: " << zoneData.numNavZones << " "
|
||||
<< zoneData.numZoneInfos << " " << zoneData.numMapZones << " "
|
||||
<< zoneData.numAudioZones << std::endl;
|
||||
for (int z = 0; z < zoneData.numNavZones; ++z) {
|
||||
Block11Zone& zone = zoneData.navZones[z];
|
||||
std::cout << " " << zone.name << std::endl;
|
||||
}
|
||||
for(int z = 0; z < zoneData.numMapZones; ++z) {
|
||||
Block11Zone &zone = zoneData.mapZones[z];
|
||||
for (int z = 0; z < zoneData.numMapZones; ++z) {
|
||||
Block11Zone& zone = zoneData.mapZones[z];
|
||||
std::cout << " " << zone.name << std::endl;
|
||||
}
|
||||
#endif
|
||||
@ -913,9 +939,10 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
READ_VALUE(gangData);
|
||||
|
||||
#if RW_DEBUG
|
||||
for(int g = 0; g < 9; ++g) {
|
||||
Block12Gang &p = gangData.gangs[g];
|
||||
std::cout << " " << p.carModelId << " " << p.weaponPrimary << " " << p.weaponSecondary << std::endl;
|
||||
for (int g = 0; g < 9; ++g) {
|
||||
Block12Gang& p = gangData.gangs[g];
|
||||
std::cout << " " << p.carModelId << " " << p.weaponPrimary << " "
|
||||
<< p.weaponSecondary << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -930,16 +957,19 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
Block13Data carGeneratorData;
|
||||
READ_VALUE(carGeneratorData);
|
||||
|
||||
std::vector<Block13CarGenerator> carGenerators(carGeneratorData.generatorCount);
|
||||
for(size_t g = 0; g < carGeneratorData.generatorCount; ++g) {
|
||||
std::vector<Block13CarGenerator> carGenerators(
|
||||
carGeneratorData.generatorCount);
|
||||
for (size_t g = 0; g < carGeneratorData.generatorCount; ++g) {
|
||||
READ_VALUE(carGenerators[g])
|
||||
}
|
||||
|
||||
#if RW_DEBUG
|
||||
std::cout << "Car generators: " << carGeneratorData.generatorCount << std::endl;
|
||||
for(size_t g = 0; g < carGeneratorData.generatorCount; ++g) {
|
||||
Block13CarGenerator &gen = carGenerators[g];
|
||||
std::cout << " " << gen.modelId << " " << gen.position.x << " "<< gen.position.y << " " << gen.position.z << std::endl;
|
||||
std::cout << "Car generators: " << carGeneratorData.generatorCount
|
||||
<< std::endl;
|
||||
for (size_t g = 0; g < carGeneratorData.generatorCount; ++g) {
|
||||
Block13CarGenerator& gen = carGenerators[g];
|
||||
std::cout << " " << gen.modelId << " " << gen.position.x << " "
|
||||
<< gen.position.y << " " << gen.position.z << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -952,7 +982,7 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
BlockDword particleCount;
|
||||
READ_VALUE(particleCount);
|
||||
std::vector<Block14Particle> particles(particleCount);
|
||||
for(size_t p = 0; p < particleCount; ++p) {
|
||||
for (size_t p = 0; p < particleCount; ++p) {
|
||||
READ_VALUE(particles[p])
|
||||
}
|
||||
|
||||
@ -972,7 +1002,7 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
READ_VALUE(audioCount)
|
||||
|
||||
std::vector<Block15AudioObject> audioObjects(audioCount);
|
||||
for(size_t a = 0; a < audioCount; ++a) {
|
||||
for (size_t a = 0; a < audioCount; ++a) {
|
||||
READ_VALUE(audioObjects[a])
|
||||
}
|
||||
|
||||
@ -1000,7 +1030,8 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
READ_VALUE(state.playerInfo.unknown5)
|
||||
|
||||
#if RW_DEBUG
|
||||
std::cout << "Player money: " << state.playerInfo.money << " (" << state.playerInfo.displayedMoney << ")" << std::endl;
|
||||
std::cout << "Player money: " << state.playerInfo.money << " ("
|
||||
<< state.playerInfo.displayedMoney << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
// Block 17
|
||||
@ -1063,7 +1094,8 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
|
||||
#if RW_DEBUG
|
||||
std::cout << "Player kills: " << state.gameStats.playerKills << std::endl;
|
||||
std::cout << "longest flight " << state.gameStats.longestDodoFlight << std::endl;
|
||||
std::cout << "longest flight " << state.gameStats.longestDodoFlight
|
||||
<< std::endl;
|
||||
#endif
|
||||
|
||||
// Block 18
|
||||
@ -1076,14 +1108,13 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
READ_VALUE(streamingData);
|
||||
|
||||
#if RW_DEBUG && 0 // No idea what the data in the section means yet
|
||||
static const size_t streamSize = sqrt(200*8);
|
||||
static const size_t streamSize = sqrt(200 * 8);
|
||||
for (int x = 0; x < streamSize; ++x) {
|
||||
for (int y = 0; y < streamSize; ++y) {
|
||||
size_t coord = (y * streamSize) + x;
|
||||
if (streamingData.unknown1[(coord/8)] & (0x1 << (coord%8))) {
|
||||
if (streamingData.unknown1[(coord / 8)] & (0x1 << (coord % 8))) {
|
||||
std::cout << "\u2588";
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
std::cout << " ";
|
||||
}
|
||||
}
|
||||
@ -1105,7 +1136,8 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
#if RW_DEBUG && 0 // Nor this
|
||||
for (int i = 0; i < 23; ++i) {
|
||||
if (pedTypeData.types[i].unknown1 & (0x1 << i) != 0) continue;
|
||||
std::cout << pedTypeData.types[i].unknown1 << " " << pedTypeData.types[i].unknown7 << std::endl;
|
||||
std::cout << pedTypeData.types[i].unknown1 << " "
|
||||
<< pedTypeData.types[i].unknown7 << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1114,28 +1146,29 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
// We keep track of the game time as a float for now
|
||||
state.gameTime = state.basic.timeMS / 1000.f;
|
||||
|
||||
state.scriptOnMissionFlag = (int32_t*)(state.script->getGlobals() + (size_t)scriptData.onMissionOffset);
|
||||
state.scriptOnMissionFlag = (int32_t*)(state.script->getGlobals() +
|
||||
(size_t)scriptData.onMissionOffset);
|
||||
|
||||
auto& threads = state.script->getThreads();
|
||||
for(size_t s = 0; s < numScripts; ++s) {
|
||||
for (size_t s = 0; s < numScripts; ++s) {
|
||||
state.script->startThread(scripts[s].programCounter);
|
||||
SCMThread& thread = threads.back();
|
||||
// thread.baseAddress // ??
|
||||
strncpy(thread.name, scripts[s].name, sizeof(SCMThread::name)-1);
|
||||
strncpy(thread.name, scripts[s].name, sizeof(SCMThread::name) - 1);
|
||||
thread.conditionResult = scripts[s].ifFlag;
|
||||
thread.conditionCount = scripts[s].ifNumber;
|
||||
thread.stackDepth = scripts[s].stackCounter;
|
||||
for(int i = 0; i < SCM_STACK_DEPTH; ++i) {
|
||||
for (int i = 0; i < SCM_STACK_DEPTH; ++i) {
|
||||
thread.calls[i] = scripts[s].stack[i];
|
||||
}
|
||||
/* TODO not hardcode +33 ms */
|
||||
thread.wakeCounter = scripts[s].wakeTimer - state.basic.lastTick + 33;
|
||||
for(size_t i = 0; i < sizeof(Block0RunningScript::variables); ++i) {
|
||||
for (size_t i = 0; i < sizeof(Block0RunningScript::variables); ++i) {
|
||||
thread.locals[i] = scripts[s].variables[i];
|
||||
}
|
||||
}
|
||||
|
||||
if( playerCount > 0 ) {
|
||||
if (playerCount > 0) {
|
||||
auto& ply = players[0];
|
||||
std::cout << ply.reference << std::endl;
|
||||
auto player = state.world->createPlayer(players[0].info.position);
|
||||
@ -1144,7 +1177,7 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
cs.armour = players[0].info.armour;
|
||||
state.playerObject = player->getGameObjectID();
|
||||
state.maxWantedLevel = players[0].maxWantedLevel;
|
||||
for(int w = 0; w < 13; ++w) {
|
||||
for (int w = 0; w < 13; ++w) {
|
||||
auto& wep = ply.info.weapons[w];
|
||||
cs.weapons[w].weaponId = wep.weaponId;
|
||||
cs.weapons[w].bulletsClip = wep.inClip;
|
||||
@ -1154,26 +1187,21 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
|
||||
// TODO restore garage data
|
||||
// http://gtaforums.com/topic/758692-gta-iii-save-file-documentation/
|
||||
for(size_t g = 0; g < garageData.garageCount; ++g) {
|
||||
for (size_t g = 0; g < garageData.garageCount; ++g) {
|
||||
auto& garage = garages[g];
|
||||
state.garages.push_back({
|
||||
(int)g,
|
||||
glm::vec3(garage.x1, garage.y1, garage.z1),
|
||||
glm::vec3(garage.x2, garage.y2, garage.z2),
|
||||
garage.type
|
||||
});
|
||||
state.garages.push_back(
|
||||
{(int)g, glm::vec3(garage.x1, garage.y1, garage.z1),
|
||||
glm::vec3(garage.x2, garage.y2, garage.z2), garage.type});
|
||||
}
|
||||
for(int c = 0; c < 18; ++c) {
|
||||
if(garageData.cars[c].modelId == 0) continue;
|
||||
for (int c = 0; c < 18; ++c) {
|
||||
if (garageData.cars[c].modelId == 0) continue;
|
||||
auto& car = garageData.cars[c];
|
||||
glm::quat rotation(
|
||||
glm::mat3(
|
||||
glm::cross(car.rotation, glm::vec3(0.f, 0.f, 1.f)),
|
||||
car.rotation,
|
||||
glm::vec3(0.f, 0.f, 1.f)
|
||||
));
|
||||
glm::mat3(glm::cross(car.rotation, glm::vec3(0.f, 0.f, 1.f)),
|
||||
car.rotation, glm::vec3(0.f, 0.f, 1.f)));
|
||||
|
||||
VehicleObject* vehicle = state.world->createVehicle(car.modelId, car.position, rotation);
|
||||
VehicleObject* vehicle =
|
||||
state.world->createVehicle(car.modelId, car.position, rotation);
|
||||
vehicle->setPrimaryColour(car.colorFG);
|
||||
vehicle->setSecondaryColour(car.colorBG);
|
||||
}
|
||||
@ -1181,18 +1209,9 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
for (unsigned g = 0; g < carGenerators.size(); ++g) {
|
||||
auto& gen = carGenerators[g];
|
||||
state.vehicleGenerators.emplace_back(
|
||||
g,
|
||||
gen.position,
|
||||
gen.angle,
|
||||
gen.modelId,
|
||||
gen.colourFG,
|
||||
gen.colourBG,
|
||||
gen.force,
|
||||
gen.alarmChance,
|
||||
gen.lockedChance,
|
||||
gen.minDelay,
|
||||
gen.maxDelay,
|
||||
gen.timestamp,
|
||||
g, gen.position, gen.angle, gen.modelId, gen.colourFG, gen.colourBG,
|
||||
gen.force, gen.alarmChance, gen.lockedChance, gen.minDelay,
|
||||
gen.maxDelay, gen.timestamp,
|
||||
101 /// @todo determine where the remainingSpawns should be
|
||||
);
|
||||
}
|
||||
@ -1207,8 +1226,7 @@ bool SaveGame::loadGame(GameState& state, const std::string& file)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveGame::getSaveInfo(const std::string& file, BasicState *basicState)
|
||||
{
|
||||
bool SaveGame::getSaveInfo(const std::string& file, BasicState* basicState) {
|
||||
std::FILE* loadFile = std::fopen(file.c_str(), "rb");
|
||||
|
||||
SaveGameInfo info;
|
||||
@ -1216,12 +1234,12 @@ bool SaveGame::getSaveInfo(const std::string& file, BasicState *basicState)
|
||||
|
||||
// BLOCK 0
|
||||
BlockDword blockSize;
|
||||
if( fread(&blockSize, sizeof(BlockDword), 1, loadFile) == 0 ) {
|
||||
if (fread(&blockSize, sizeof(BlockDword), 1, loadFile) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read block 0 into state
|
||||
if( fread(basicState, sizeof(BasicState), 1, loadFile) == 0 ) {
|
||||
if (fread(basicState, sizeof(BasicState), 1, loadFile) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1230,13 +1248,12 @@ bool SaveGame::getSaveInfo(const std::string& file, BasicState *basicState)
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<SaveGameInfo> SaveGame::getAllSaveGameInfo()
|
||||
{
|
||||
std::vector<SaveGameInfo> SaveGame::getAllSaveGameInfo() {
|
||||
using namespace boost::filesystem;
|
||||
|
||||
// TODO consider windows
|
||||
auto homedir = getenv("HOME");
|
||||
if( homedir == nullptr ) {
|
||||
if (homedir == nullptr) {
|
||||
std::cerr << "Unable to determine home directory" << std::endl;
|
||||
return {};
|
||||
}
|
||||
@ -1245,15 +1262,17 @@ std::vector<SaveGameInfo> SaveGame::getAllSaveGameInfo()
|
||||
path gamePath(homedir);
|
||||
gamePath /= gameDir;
|
||||
|
||||
if(!exists(gamePath) || !is_directory(gamePath))
|
||||
return {};
|
||||
if (!exists(gamePath) || !is_directory(gamePath)) return {};
|
||||
|
||||
std::vector<SaveGameInfo> infos;
|
||||
for(const path& save_path : boost::make_iterator_range(directory_iterator(gamePath), {})) {
|
||||
if(save_path.extension() == ".b") {
|
||||
for (const path& save_path :
|
||||
boost::make_iterator_range(directory_iterator(gamePath), {})) {
|
||||
if (save_path.extension() == ".b") {
|
||||
std::cout << save_path.string() << std::endl;
|
||||
infos.emplace_back(SaveGameInfo {save_path.string(), false, BasicState()});
|
||||
infos.back().valid = getSaveInfo(infos.back().savePath, &infos.back().basicState);
|
||||
infos.emplace_back(
|
||||
SaveGameInfo{save_path.string(), false, BasicState()});
|
||||
infos.back().valid =
|
||||
getSaveInfo(infos.back().savePath, &infos.back().basicState);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,8 +12,7 @@
|
||||
class GameWorld;
|
||||
class ScriptMachine;
|
||||
|
||||
struct SaveGameInfo
|
||||
{
|
||||
struct SaveGameInfo {
|
||||
std::string savePath;
|
||||
bool valid;
|
||||
BasicState basicState;
|
||||
@ -22,10 +21,8 @@ struct SaveGameInfo
|
||||
/**
|
||||
* Reads and Writes GameStates to disk, restoring the required state information
|
||||
*/
|
||||
class SaveGame
|
||||
{
|
||||
class SaveGame {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Writes the entire game state to a file format that closely approximates
|
||||
* the format used in GTA III
|
||||
|
@ -1,35 +1,29 @@
|
||||
#include <engine/ScreenText.hpp>
|
||||
|
||||
void ScreenText::tick(float dt)
|
||||
{
|
||||
void ScreenText::tick(float dt) {
|
||||
int millis = dt * 1000;
|
||||
|
||||
// Remove all the immedate text
|
||||
m_textQueues[static_cast<size_t>(ScreenTextType::Immediate)].clear();
|
||||
|
||||
for (unsigned int t = 0; t < m_textQueues.size(); ++t)
|
||||
{
|
||||
for (unsigned int i = 0; i < m_textQueues[t].size();)
|
||||
{
|
||||
for (unsigned int t = 0; t < m_textQueues.size(); ++t) {
|
||||
for (unsigned int i = 0; i < m_textQueues[t].size();) {
|
||||
auto& big = m_textQueues[t][i];
|
||||
|
||||
big.displayedMS += millis;
|
||||
if (big.displayedMS >= big.durationMS)
|
||||
{
|
||||
m_textQueues[t].erase(m_textQueues[t].begin()+i);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (big.displayedMS >= big.durationMS) {
|
||||
m_textQueues[t].erase(m_textQueues[t].begin() + i);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScreenTextEntry ScreenTextEntry::makeBig(const GameStringKey& id, const GameString& str, int style, int durationMS)
|
||||
{
|
||||
switch(style) {
|
||||
|
||||
ScreenTextEntry ScreenTextEntry::makeBig(const GameStringKey& id,
|
||||
const GameString& str, int style,
|
||||
int durationMS) {
|
||||
switch (style) {
|
||||
// Color: Blue
|
||||
// Font: Pricedown
|
||||
// Style: Italic (lowercase only)
|
||||
@ -37,19 +31,17 @@ ScreenTextEntry ScreenTextEntry::makeBig(const GameStringKey& id, const GameStri
|
||||
// Vertically: Baseline at y = 252 (from top)
|
||||
// Size: 25 Pixel high letters ('S', 'l')
|
||||
case 1:
|
||||
return {
|
||||
str,
|
||||
return {str,
|
||||
{320.f, 252.f},
|
||||
1,
|
||||
50,
|
||||
{ 2, 0, 0, 0},
|
||||
{2, 0, 0, 0},
|
||||
{58, 119, 133},
|
||||
1,
|
||||
durationMS,
|
||||
0,
|
||||
600,
|
||||
id
|
||||
};
|
||||
id};
|
||||
|
||||
// Color: Yellow/Gold
|
||||
// Font: Pricedown
|
||||
@ -58,19 +50,17 @@ ScreenTextEntry ScreenTextEntry::makeBig(const GameStringKey& id, const GameStri
|
||||
// Vertically: Baseline at y = 380 (from top)
|
||||
// Size: 22 Pixel high letters ('S', 'l')
|
||||
case 2:
|
||||
return {
|
||||
str,
|
||||
return {str,
|
||||
{620.f, 380.f},
|
||||
1,
|
||||
30,
|
||||
{ 2, 3, 0, 0},
|
||||
{2, 3, 0, 0},
|
||||
{214, 171, 9},
|
||||
2,
|
||||
durationMS,
|
||||
0,
|
||||
600,
|
||||
id
|
||||
};
|
||||
id};
|
||||
|
||||
// Color: Light brown
|
||||
// Font: Pricedown
|
||||
@ -79,19 +69,17 @@ ScreenTextEntry ScreenTextEntry::makeBig(const GameStringKey& id, const GameStri
|
||||
// Vertically: Baseline at y = 427 (from top)
|
||||
// Size: 28 Pixel high letters ('S', 'l')
|
||||
case 3:
|
||||
return {
|
||||
str,
|
||||
return {str,
|
||||
{320.f, 400.f},
|
||||
1,
|
||||
50,
|
||||
{ 5, 5, 0, 0},
|
||||
{5, 5, 0, 0},
|
||||
{169, 123, 88}, /// @todo verify
|
||||
1,
|
||||
durationMS,
|
||||
0,
|
||||
600,
|
||||
id
|
||||
};
|
||||
id};
|
||||
|
||||
// Color: Blue
|
||||
// Font: Arial
|
||||
@ -101,19 +89,18 @@ ScreenTextEntry ScreenTextEntry::makeBig(const GameStringKey& id, const GameStri
|
||||
// Size: 20 Pixel high letters ('S', 'l')
|
||||
case 4:
|
||||
case 5:
|
||||
return {
|
||||
str,
|
||||
return {str,
|
||||
{320.f, 176.f},
|
||||
2,
|
||||
50,
|
||||
((style == 4) ? glm::u8vec4({ 2, 2, 0, 0}) : glm::u8vec4({ -2, -2, 0, 0 })),
|
||||
((style == 4) ? glm::u8vec4({2, 2, 0, 0})
|
||||
: glm::u8vec4({-2, -2, 0, 0})),
|
||||
{90, 115, 150}, /// @todo verify
|
||||
1,
|
||||
durationMS,
|
||||
0,
|
||||
600,
|
||||
id
|
||||
};
|
||||
id};
|
||||
|
||||
// Color: Brown
|
||||
// Font: Arial
|
||||
@ -122,27 +109,24 @@ ScreenTextEntry ScreenTextEntry::makeBig(const GameStringKey& id, const GameStri
|
||||
// Vertically: Baseline at y = 240 (from top)
|
||||
// Size: 16 Pixel high letters ('S', 'l')
|
||||
case 6:
|
||||
return {
|
||||
str,
|
||||
return {str,
|
||||
{320.f, 240.f},
|
||||
2,
|
||||
50,
|
||||
{ 2, 2, 0, 0},
|
||||
{2, 2, 0, 0},
|
||||
{152, 89, 39},
|
||||
1,
|
||||
durationMS,
|
||||
0,
|
||||
600,
|
||||
id
|
||||
};
|
||||
id};
|
||||
|
||||
default:
|
||||
RW_ERROR("Unhandled text style");
|
||||
break;
|
||||
}
|
||||
|
||||
return {
|
||||
GameStringUtil::fromString("Error, style " + std::to_string(style)),
|
||||
return {GameStringUtil::fromString("Error, style " + std::to_string(style)),
|
||||
{320.f, 400.f},
|
||||
2,
|
||||
50,
|
||||
@ -152,20 +136,19 @@ ScreenTextEntry ScreenTextEntry::makeBig(const GameStringKey& id, const GameStri
|
||||
durationMS,
|
||||
0,
|
||||
600,
|
||||
id
|
||||
};
|
||||
id};
|
||||
}
|
||||
|
||||
ScreenTextEntry ScreenTextEntry::makeHighPriority(const GameStringKey& id, const GameString& str, int durationMS)
|
||||
{
|
||||
ScreenTextEntry ScreenTextEntry::makeHighPriority(const GameStringKey& id,
|
||||
const GameString& str,
|
||||
int durationMS) {
|
||||
// Color: ?
|
||||
// Font: Arial
|
||||
// Style: Italic
|
||||
// Horizontally: Centered
|
||||
// @todo verify: Vertically: Baseline at y = 431 (from top)
|
||||
// @todo verify: Size: 15 Pixel high letters ('S', 'l')
|
||||
return {
|
||||
str,
|
||||
return {str,
|
||||
{320.f, 420.f},
|
||||
2,
|
||||
18,
|
||||
@ -175,23 +158,11 @@ ScreenTextEntry ScreenTextEntry::makeHighPriority(const GameStringKey& id, const
|
||||
durationMS,
|
||||
0,
|
||||
50,
|
||||
id
|
||||
};
|
||||
id};
|
||||
}
|
||||
|
||||
ScreenTextEntry ScreenTextEntry::makeHelp(const GameStringKey& id, const GameString& str)
|
||||
{
|
||||
return {
|
||||
str,
|
||||
{20.f, 20.f},
|
||||
2,
|
||||
18,
|
||||
{ 0, 0, 0, 255},
|
||||
{255, 255, 255},
|
||||
0,
|
||||
5000,
|
||||
0,
|
||||
35,
|
||||
id
|
||||
};
|
||||
ScreenTextEntry ScreenTextEntry::makeHelp(const GameStringKey& id,
|
||||
const GameString& str) {
|
||||
return {str, {20.f, 20.f}, 2, 18, {0, 0, 0, 255}, {255, 255, 255}, 0, 5000,
|
||||
0, 35, id};
|
||||
}
|
||||
|
@ -1,14 +1,13 @@
|
||||
#ifndef RWENGINE_SCREENTEXT_HPP
|
||||
#define RWENGINE_SCREENTEXT_HPP
|
||||
#include <rw/types.hpp>
|
||||
#include <data/GameTexts.hpp>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <data/GameTexts.hpp>
|
||||
#include <rw/types.hpp>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
enum class ScreenTextType
|
||||
{
|
||||
enum class ScreenTextType {
|
||||
/// Big text will be rendered according to the proscribed style.
|
||||
/// Adding a 2nd big text will cause the first to terminate.
|
||||
Big = 0,
|
||||
@ -23,15 +22,15 @@ enum class ScreenTextType
|
||||
///
|
||||
_Count = 5
|
||||
};
|
||||
constexpr unsigned int ScreenTypeTextCount = static_cast<unsigned int>(ScreenTextType::_Count);
|
||||
constexpr unsigned int ScreenTypeTextCount =
|
||||
static_cast<unsigned int>(ScreenTextType::_Count);
|
||||
|
||||
/**
|
||||
* @brief The ScreenTextEntry struct
|
||||
*
|
||||
* Text string and fading information.
|
||||
*/
|
||||
struct ScreenTextEntry
|
||||
{
|
||||
struct ScreenTextEntry {
|
||||
/// After processing numbers
|
||||
GameString text;
|
||||
/// in the virtual 640x480 screen space
|
||||
@ -56,8 +55,7 @@ struct ScreenTextEntry
|
||||
GameStringKey id;
|
||||
|
||||
static ScreenTextEntry makeBig(const GameStringKey& id,
|
||||
const GameString& str,
|
||||
int style,
|
||||
const GameString& str, int style,
|
||||
int durationMS);
|
||||
|
||||
static ScreenTextEntry makeHighPriority(const GameStringKey& id,
|
||||
@ -88,14 +86,11 @@ struct ScreenTextEntry
|
||||
* Immediate text is only rendered once, the text is removed at the
|
||||
* start of each tick and must be re-added to keep it on screen.
|
||||
*/
|
||||
class ScreenText
|
||||
{
|
||||
using EntryList =
|
||||
std::vector<ScreenTextEntry>;
|
||||
using EntryQueues =
|
||||
std::array<EntryList, ScreenTypeTextCount>;
|
||||
public:
|
||||
class ScreenText {
|
||||
using EntryList = std::vector<ScreenTextEntry>;
|
||||
using EntryQueues = std::array<EntryList, ScreenTypeTextCount>;
|
||||
|
||||
public:
|
||||
///
|
||||
/// \brief tick Apply display and fading rules to the text
|
||||
/// \param dt
|
||||
@ -103,52 +98,50 @@ public:
|
||||
void tick(float dt);
|
||||
|
||||
template <ScreenTextType Q, class... Args>
|
||||
void addText(Args&&...args)
|
||||
{
|
||||
static_assert(static_cast<size_t>(Q) < ScreenTypeTextCount, "Queue out of range");
|
||||
m_textQueues[static_cast<size_t>(Q)].emplace_back(std::forward<Args...>(args...));
|
||||
void addText(Args&&... args) {
|
||||
static_assert(static_cast<size_t>(Q) < ScreenTypeTextCount,
|
||||
"Queue out of range");
|
||||
m_textQueues[static_cast<size_t>(Q)].emplace_back(
|
||||
std::forward<Args...>(args...));
|
||||
}
|
||||
|
||||
template <ScreenTextType Q>
|
||||
const EntryList& getText() const
|
||||
{
|
||||
static_assert(static_cast<size_t>(Q) < ScreenTypeTextCount, "Queue out of range");
|
||||
const EntryList& getText() const {
|
||||
static_assert(static_cast<size_t>(Q) < ScreenTypeTextCount,
|
||||
"Queue out of range");
|
||||
return m_textQueues[static_cast<size_t>(Q)];
|
||||
}
|
||||
|
||||
template <ScreenTextType Q>
|
||||
void clear()
|
||||
{
|
||||
static_assert(static_cast<size_t>(Q) < ScreenTypeTextCount, "Queue out of range");
|
||||
void clear() {
|
||||
static_assert(static_cast<size_t>(Q) < ScreenTypeTextCount,
|
||||
"Queue out of range");
|
||||
m_textQueues[static_cast<size_t>(Q)].clear();
|
||||
}
|
||||
|
||||
template <ScreenTextType Q>
|
||||
void remove(const std::string& id)
|
||||
{
|
||||
static_assert(static_cast<size_t>(Q) < ScreenTypeTextCount, "Queue out of range");
|
||||
void remove(const std::string& id) {
|
||||
static_assert(static_cast<size_t>(Q) < ScreenTypeTextCount,
|
||||
"Queue out of range");
|
||||
auto& list = m_textQueues[static_cast<size_t>(Q)];
|
||||
list.erase(
|
||||
std::remove_if(list.begin(), list.end(),
|
||||
[&id](const ScreenTextEntry& e){ return e.id == id; }),
|
||||
list.end()
|
||||
);
|
||||
list.erase(std::remove_if(
|
||||
list.begin(), list.end(),
|
||||
[&id](const ScreenTextEntry& e) { return e.id == id; }),
|
||||
list.end());
|
||||
}
|
||||
|
||||
const EntryQueues& getAllText() const
|
||||
{
|
||||
const EntryQueues& getAllText() const {
|
||||
return m_textQueues;
|
||||
}
|
||||
|
||||
template<class...Args>
|
||||
static GameString format(GameString format, Args&&...args)
|
||||
{
|
||||
template <class... Args>
|
||||
static GameString format(GameString format, Args&&... args) {
|
||||
static auto kReplacementMarker = GameStringUtil::fromString("~1~");
|
||||
const std::array<GameString, sizeof...(args)> vals = { args... };
|
||||
const std::array<GameString, sizeof...(args)> vals = {args...};
|
||||
size_t x = 0, val = 0;
|
||||
// We're only looking for numerical replacement markers
|
||||
while ((x = format.find(kReplacementMarker)) != GameString::npos && val < vals.size())
|
||||
{
|
||||
while ((x = format.find(kReplacementMarker)) != GameString::npos &&
|
||||
val < vals.size()) {
|
||||
format = format.substr(0, x) + vals[val++] + format.substr(x + 3);
|
||||
}
|
||||
return format;
|
||||
|
Loading…
Reference in New Issue
Block a user