1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-09-19 08:52:33 +02:00

clang-format files in rwengine/src/engine

This commit is contained in:
Daniel Evans 2016-09-09 21:13:19 +01:00
parent 8534d7ff5d
commit 80e6317c24
13 changed files with 3504 additions and 3709 deletions

View File

@ -1,75 +1,64 @@
#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() ) {
return;
}
void Animator::tick(float dt) {
if (model == nullptr || animations.empty()) {
return;
}
struct BoneTransform
{
glm::vec3 translation;
glm::quat rotation;
};
struct BoneTransform {
glm::vec3 translation;
glm::quat rotation;
};
// Blend all active animations together
std::map<unsigned int, BoneTransform> blendFrames;
// Blend all active animations together
std::map<unsigned int, BoneTransform> blendFrames;
for (AnimationState& state : animations)
{
RW_CHECK(state.animation != nullptr, "AnimationState with no animation");
if (state.animation == nullptr) continue;
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 } } );
}
}
}
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}});
}
}
}
state.time = state.time + dt;
state.time = state.time + dt;
float animTime = state.time;
if (! state.repeat)
{
animTime = std::min(animTime, state.animation->duration);
}
else
{
animTime = fmod(animTime, state.animation->duration);
}
float animTime = state.time;
if (!state.repeat) {
animTime = std::min(animTime, state.animation->duration);
} else {
animTime = fmod(animTime, state.animation->duration);
}
for( auto& b : state.boneInstances )
{
if (b.first->frames.size() == 0) continue;
auto kf = b.first->getInterpolatedKeyframe(animTime);
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 ) {
xform.rotation = kf.rotation;
}
else if(b.first->type == AnimationBone::RT0) {
xform.rotation = kf.rotation;
xform.translation = kf.position;
}
else {
xform.rotation = kf.rotation;
xform.translation = kf.position;
}
BoneTransform xform;
if (b.first->type == AnimationBone::R00) {
xform.rotation = kf.rotation;
} else if (b.first->type == AnimationBone::RT0) {
xform.rotation = kf.rotation;
xform.translation = kf.position;
} else {
xform.rotation = kf.rotation;
xform.translation = kf.position;
}
#if 0
auto prevAnim = blendFrames.find(b.second.frameIndex);
@ -83,50 +72,44 @@ void Animator::tick(float dt)
blendFrames[b.second.frameIndex] = xform;
}
#else
blendFrames[b.second.frameIndex] = xform;
blendFrames[b.second.frameIndex] = xform;
#endif
}
}
}
}
for (auto& p : blendFrames)
{
auto& data = skeleton->getData(p.first);
Skeleton::FrameData fd;
fd.b = data.a;
fd.enabled = data.enabled;
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.rotation = p.second.rotation;
fd.a.translation = model->frames[p.first]->getDefaultTranslation() +
p.second.translation;
fd.a.rotation = p.second.rotation;
skeleton->setData(p.first, fd);
}
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
: true;
}
return false;
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())
{
return animations[slot].time;
}
return 0.f;
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())
{
animations[slot].time = time;
}
void Animator::setAnimationTime(unsigned int slot, float time) {
if (slot < animations.size()) {
animations[slot].time = time;
}
}

View File

@ -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,89 +23,81 @@ class Skeleton;
*
* The Animator will blend all active animations together.
*/
class Animator
{
/**
* @brief Stores data required to animate a model frame
*/
struct BoneInstanceData
{
unsigned int frameIndex;
};
class Animator {
/**
* @brief Stores data required to animate a model frame
*/
struct BoneInstanceData {
unsigned int frameIndex;
};
/**
* @brief The AnimationState struct stores information about playing animations
*/
struct AnimationState
{
Animation* animation;
/// Timestamp of the last frame
float time;
/// Speed multiplier
float speed;
/// Automatically restart
bool repeat;
std::map<AnimationBone*, BoneInstanceData> boneInstances;
};
/**
* @brief The AnimationState struct stores information about playing
* animations
*/
struct AnimationState {
Animation* animation;
/// Timestamp of the last frame
float time;
/// Speed multiplier
float speed;
/// Automatically restart
bool repeat;
std::map<AnimationBone*, BoneInstanceData> boneInstances;
};
/**
* @brief model The model being animated.
*/
Model* model;
/**
* @brief Skeleton instance.
*/
Skeleton* skeleton;
/**
* @brief model The model being animated.
*/
Model* model;
/**
* @brief Currently playing animations
*/
std::vector<AnimationState> animations;
/**
* @brief Skeleton instance.
*/
Skeleton* skeleton;
/**
* @brief Currently playing animations
*/
std::vector<AnimationState> animations;
public:
Animator(Model* model, Skeleton* skeleton);
Animator(Model* model, Skeleton* skeleton);
Animation* getAnimation(unsigned int slot) {
if (slot < animations.size()) {
return animations[slot].animation;
}
return nullptr;
}
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);
}
animations[slot] = {anim, 0.f, speed, repeat, {}};
}
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, {} };
}
void setAnimationSpeed(unsigned int slot, float speed) {
RW_CHECK(slot < animations.size(), "Slot out of range");
if (slot < animations.size()) {
animations[slot].speed = speed;
}
}
void setAnimationSpeed(unsigned int slot, float speed)
{
RW_CHECK(slot < animations.size(), "Slot out of range");
if (slot < animations.size())
{
animations[slot].speed = speed;
}
}
/**
* @brief tick Update animation paramters for server-side data.
* @param dt
*/
void tick(float dt);
/**
* @brief tick Update animation paramters for server-side data.
* @param dt
*/
void tick(float dt);
/**
* Returns true if the animation has finished playing.
*/
bool isCompleted(unsigned int slot) const;
float getAnimationTime(unsigned int slot) const;
void setAnimationTime(unsigned int slot, float time);
/**
* Returns true if the animation has finished playing.
*/
bool isCompleted(unsigned int slot) const;
float getAnimationTime(unsigned int slot) const;
void setAnimationTime(unsigned int slot, float time);
};
#endif

View File

@ -1,493 +1,440 @@
#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) {
delete m.second->resource;
}
}
GameData::~GameData() {
for (auto& m : models) {
if (m.second->resource) {
delete m.second->resource;
}
}
}
void GameData::load()
{
index.indexGameDirectory(datpath);
index.indexTree(datpath);
void GameData::load() {
index.indexGameDirectory(datpath);
index.indexTree(datpath);
loadIMG("models/gta3.img");
/// @todo cuts.img files should be loaded differently to gta3.img
loadIMG("anim/cuts.img");
loadIMG("models/gta3.img");
/// @todo cuts.img files should be loaded differently to gta3.img
loadIMG("anim/cuts.img");
loadLevelFile("data/default.dat");
loadLevelFile("data/gta3.dat");
loadDFF("wheels.dff");
loadDFF("weapons.dff");
loadDFF("arrow.dff");
loadTXD("particle.txd");
loadTXD("icons.txd");
loadTXD("hud.txd");
loadTXD("fonts.txd");
loadCarcols("data/carcols.dat");
loadWeather("data/timecyc.dat");
loadHandling("data/handling.cfg");
loadWaterpro("data/waterpro.dat");
loadWeaponDAT("data/weapon.dat");
loadLevelFile("data/default.dat");
loadLevelFile("data/gta3.dat");
loadIFP("ped.ifp");
loadDFF("wheels.dff");
loadDFF("weapons.dff");
loadDFF("arrow.dff");
loadTXD("particle.txd");
loadTXD("icons.txd");
loadTXD("hud.txd");
loadTXD("fonts.txd");
loadCarcols("data/carcols.dat");
loadWeather("data/timecyc.dat");
loadHandling("data/handling.cfg");
loadWaterpro("data/waterpro.dat");
loadWeaponDAT("data/weapon.dat");
loadIFP("ped.ifp");
}
void GameData::loadLevelFile(const std::string& path)
{
auto datpath = index.findFilePath(path);
std::ifstream datfile(datpath.string());
void GameData::loadLevelFile(const std::string& path) {
auto datpath = index.findFilePath(path);
std::ifstream datfile(datpath.string());
if(!datfile.is_open())
{
logger->error("Data", "Failed to open game file " + path);
return;
}
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)
{
cmd = line.substr(0, space);
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);
loadCOL(zone, path);
}
else if(cmd == "IPL")
{
auto path = line.substr(space+1);
loadIPL(path);
}
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);
loadTXD(name);
}
}
}
size_t space = line.find_first_of(' ');
if (space != line.npos) {
cmd = line.substr(0, space);
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);
loadCOL(zone, path);
} else if (cmd == "IPL") {
auto path = line.substr(space + 1);
loadIPL(path);
} 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);
loadTXD(name);
}
}
}
}
void GameData::loadIDE(const std::string& path)
{
auto systempath = index.findFilePath(path).string();
LoaderIDE idel;
void GameData::loadIDE(const std::string& path) {
auto systempath = index.findFilePath(path).string();
LoaderIDE idel;
if(idel.load(systempath)) {
objectTypes.insert(idel.objects.begin(), idel.objects.end());
}
else {
logger->error("Data", "Failed to load IDE " + path);
}
if (idel.load(systempath)) {
objectTypes.insert(idel.objects.begin(), idel.objects.end());
} 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"))
{
auto dat = static_cast<ObjectData*>(d.second.get());
return boost::iequals(dat->modelName, model);
}
return false;
});
if( defit != objectTypes.end() ) return defit->first;
return -1;
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;
return -1;
}
void GameData::loadCOL(const size_t zone, const std::string& name)
{
RW_UNUSED(zone);
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 ) {
collisions[col.instances[i]->name] = std::move(col.instances[i]);
}
}
LoaderCOL col;
auto systempath = index.findFilePath(name).string();
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)
{
auto syspath = index.findFilePath(name).string();
index.indexArchive(syspath);
void GameData::loadIMG(const std::string& name) {
auto syspath = index.findFilePath(name).string();
index.indexArchive(syspath);
}
void GameData::loadIPL(const std::string& path)
{
auto systempath = index.findFilePath(path).string();
iplLocations.insert({path, systempath});
void GameData::loadIPL(const std::string& path) {
auto systempath = index.findFilePath(path).string();
iplLocations.insert({path, systempath});
}
bool GameData::loadZone(const std::string& path)
{
LoaderIPL ipll;
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);
return true;
}
}
else {
logger->error("Data", "Failed to load zones from " + path);
}
return false;
bool GameData::loadZone(const std::string& path) {
LoaderIPL ipll;
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);
return true;
}
} else {
logger->error("Data", "Failed to load zones from " + path);
}
return false;
}
enum ColSection {
Unknown,
COL,
CAR,
CAR3, ///> Used in GTASA, contains extra specular color
CAR4 ///> Used in GTASA, contains quadruple colors
Unknown,
COL,
CAR,
CAR3, ///> Used in GTASA, contains extra specular color
CAR4 ///> Used in GTASA, contains quadruple colors
};
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
continue;
}
else if( currentSection == Unknown) {
if( line.substr(0, 3) == "col") {
currentSection = COL;
}
else if( line.substr(0, 3) == "car") {
currentSection = CAR;
}
}
else if( line.substr(0, 3) == "end") {
currentSection = Unknown;
}
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)) {
vehicleColours.push_back(glm::u8vec3(
atoi(r.c_str()),
atoi(g.c_str()),
atoi(b.c_str())
));
}
}
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()) });
}
vehiclePalettes.insert({vehicle, colours});
}
}
}
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
continue;
} else if (currentSection == Unknown) {
if (line.substr(0, 3) == "col") {
currentSection = COL;
} else if (line.substr(0, 3) == "car") {
currentSection = CAR;
}
} else if (line.substr(0, 3) == "end") {
currentSection = Unknown;
} 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)) {
vehicleColours.push_back(glm::u8vec3(
atoi(r.c_str()), atoi(g.c_str()), atoi(b.c_str())));
}
} 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())});
}
vehiclePalettes.insert({vehicle, colours});
}
}
}
}
void GameData::loadWeather(const std::string &path)
{
auto syspath = index.findFilePath(path).string();
weatherLoader.load(syspath);
void GameData::loadWeather(const std::string& path) {
auto syspath = index.findFilePath(path).string();
weatherLoader.load(syspath);
}
void GameData::loadHandling(const std::string& path)
{
GenericDATLoader l;
auto syspath = index.findFilePath(path).string();
void GameData::loadHandling(const std::string& path) {
GenericDATLoader l;
auto syspath = index.findFilePath(path).string();
l.loadHandling(syspath, vehicleInfo);
l.loadHandling(syspath, vehicleInfo);
}
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);
scm_h.reset();
return scm;
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);
scm_h.reset();
return scm;
}
void GameData::loadGXT(const std::string &name)
{
auto file = index.openFilePath(name);
void GameData::loadGXT(const std::string& name) {
auto file = index.openFilePath(name);
LoaderGXT loader;
LoaderGXT loader;
loader.load( texts, file );
loader.load(texts, file);
}
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()) {
uint32_t numlevels;
ifstr.read(reinterpret_cast<char*>(&numlevels), sizeof(uint32_t));
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);
}
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()) {
uint32_t numlevels;
ifstr.read(reinterpret_cast<char*>(&numlevels), sizeof(uint32_t));
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);
}
}
void GameData::loadWater(const std::string& path)
{
std::ifstream ifstr(path.c_str());
std::string line;
while( std::getline(ifstr, line)) {
if( line[0] == ';') {
continue;
}
std::stringstream ss(line);
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, ',')) {
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
});
}
}
void GameData::loadWater(const std::string& path) {
std::ifstream ifstr(path.c_str());
std::string line;
while (std::getline(ifstr, line)) {
if (line[0] == ';') {
continue;
}
std::stringstream ss(line);
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, ',')) {
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});
}
}
}
void GameData::loadTXD(const std::string& name, bool async)
{
if( loadedFiles.find(name) != loadedFiles.end() ) {
return;
}
void GameData::loadTXD(const std::string& name, bool async) {
if (loadedFiles.find(name) != loadedFiles.end()) {
return;
}
loadedFiles[name] = true;
loadedFiles[name] = true;
auto j = new LoadTextureArchiveJob(workContext, &index, textures, name);
auto j = new LoadTextureArchiveJob(workContext, &index, textures, name);
if( async ) {
workContext->queueJob( j );
}
else {
j->work();
j->complete();
delete j;
}
if (async) {
workContext->queueJob(j);
} else {
j->work();
j->complete();
delete j;
}
}
void GameData::loadDFF(const std::string& name, bool async)
{
auto realname = name.substr(0, name.size() - 4);
if( models.find(realname) != models.end() ) {
return;
}
void GameData::loadDFF(const std::string& name, bool async) {
auto realname = name.substr(0, name.size() - 4);
if (models.find(realname) != models.end()) {
return;
}
// Before starting the job make sure the file isn't loaded again.
loadedFiles.insert({name, true});
// Before starting the job make sure the file isn't loaded again.
loadedFiles.insert({name, true});
models[realname] = ModelRef( new ResourceHandle<Model>(realname) );
auto job = new BackgroundLoaderJob<Model, LoaderDFF>
{ workContext, &this->index, name, models[realname] };
models[realname] = ModelRef(new ResourceHandle<Model>(realname));
if( async ) {
workContext->queueJob( job );
}
else {
job->work();
job->complete();
delete job;
}
auto job = new BackgroundLoaderJob<Model, LoaderDFF>{
workContext, &this->index, name, models[realname]};
if (async) {
workContext->queueJob(job);
} else {
job->work();
job->complete();
delete job;
}
}
void GameData::loadIFP(const std::string &name)
{
auto f = index.openFile(name);
void GameData::loadIFP(const std::string& name) {
auto f = index.openFile(name);
if(f)
{
LoaderIFP loader;
if( loader.loadFromMemory(f->data) ) {
animations.insert(loader.animations.begin(), loader.animations.end());
}
}
if (f) {
LoaderIFP loader;
if (loader.loadFromMemory(f->data)) {
animations.insert(loader.animations.begin(),
loader.animations.end());
}
}
}
void GameData::loadDynamicObjects(const std::string& name)
{
GenericDATLoader l;
void GameData::loadDynamicObjects(const std::string& name) {
GenericDATLoader l;
l.loadDynamicObjects(name, dynamicObjectData);
l.loadDynamicObjects(name, dynamicObjectData);
}
void GameData::loadWeaponDAT(const std::string &path)
{
GenericDATLoader l;
auto syspath = index.findFilePath(path).string();
void GameData::loadWeaponDAT(const std::string& path) {
GenericDATLoader l;
auto syspath = index.findFilePath(path).string();
l.loadWeapons(syspath, weaponData);
l.loadWeapons(syspath, weaponData);
}
bool GameData::loadAudioStream(const std::string &name)
{
auto systempath = index.findFilePath("audio/" + name).string();
if (engine->cutsceneAudio.length() > 0) {
engine->sound.stopMusic(engine->cutsceneAudio);
}
bool GameData::loadAudioStream(const std::string& name) {
auto systempath = index.findFilePath("audio/" + name).string();
if (engine->sound.loadMusic(name, systempath)) {
engine->cutsceneAudio = name;
return true;
}
if (engine->cutsceneAudio.length() > 0) {
engine->sound.stopMusic(engine->cutsceneAudio);
}
return false;
if (engine->sound.loadMusic(name, systempath)) {
engine->cutsceneAudio = name;
return true;
}
return false;
}
bool GameData::loadAudioClip(const std::string& name, const std::string& fileName)
{
auto systempath = index.findFilePath("audio/" + fileName).string();
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)
{
logger->error("Data", "MP3 Audio unsupported outside cutscenes");
return false;
}
if (systempath.find(".mp3") != std::string::npos) {
logger->error("Data", "MP3 Audio unsupported outside cutscenes");
return false;
}
bool loaded = engine->sound.loadSound(name, systempath);
bool loaded = engine->sound.loadSound(name, systempath);
if ( ! loaded) {
logger->error("Data", "Error loading audio clip "+ systempath);
return false;
}
if (!loaded) {
logger->error("Data", "Error loading audio clip " + systempath);
return false;
}
engine->missionAudio = name;
engine->missionAudio = name;
return true;
return true;
}
void GameData::loadSplash(const std::string &name)
{
std::string lower(name);
std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
void GameData::loadSplash(const std::string& name) {
std::string lower(name);
std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
loadTXD(lower + ".txd", false);
loadTXD(lower + ".txd", false);
engine->state->currentSplash = lower;
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;
return engine->data->realWater[i];
}
return 0;
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())
{
return false;
}
LoaderIMG i;
if(! i.load(path + "/models/gta3.img") )
{
return false;
}
return true;
}
bool GameData::isValidGameDirectory(const std::string& path) {
if (path.empty()) {
return false;
}
LoaderIMG i;
if (!i.load(path + "/models/gta3.img")) {
return false;
}
return true;
}

View File

@ -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,260 +36,255 @@ 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;
std::string datpath;
std::string splash;
Logger* logger;
WorkContext* workContext;
public:
/**
* ctor
* @param path Path to the root of the game data.
*/
GameData(Logger* log, WorkContext* work, const std::string& path = "");
~GameData();
/**
* ctor
* @param path Path to the root of the game data.
*/
GameData(Logger* log, WorkContext* work, const std::string& path = "");
~GameData();
GameWorld* engine;
/**
* Returns the current platform
*/
std::string getPlatformString()
{
return "PC";
}
/**
* Returns the game data path
*/
const std::string& getDataPath() const
{
return datpath;
}
/**
* Loads items defined in the given IDE
*/
void loadIDE(const std::string& path);
GameWorld* engine;
/**
* Handles the parsing of a COL file.
*/
void loadCOL(const size_t zone, const std::string& name);
/**
* Handles the loading of an IMG's data
*/
void loadIMG(const std::string& name);
void loadIPL(const std::string& path);
/**
* Loads the Zones from a zon/IPL file
*/
bool loadZone(const std::string& path);
void loadCarcols(const std::string& path);
/**
* Returns the current platform
*/
std::string getPlatformString() {
return "PC";
}
void loadWeather(const std::string& path);
/**
* Returns the game data path
*/
const std::string& getDataPath() const {
return datpath;
}
void loadHandling(const std::string& path);
/**
* Loads items defined in the given IDE
*/
void loadIDE(const std::string& path);
SCMFile* loadSCM(const std::string& path);
/**
* Handles the parsing of a COL file.
*/
void loadCOL(const size_t zone, const std::string& name);
void loadGXT(const std::string& name);
/**
* Loads water level data
*/
void loadWaterpro(const std::string& path);
void loadWater(const std::string& path);
void load();
/**
* Loads model, placement, models and textures from a level file
*/
void loadLevelFile(const std::string& path);
/**
* Attempts to load a TXD, or does nothing if it has already been loaded
*/
void loadTXD(const std::string& name, bool async = false);
/**
* Handles the loading of an IMG's data
*/
void loadIMG(const std::string& name);
/**
* Attempts to load a DFF or does nothing if is already loaded
*/
void loadDFF(const std::string& name, bool async = false);
void loadIPL(const std::string& path);
/**
* Loads the Zones from a zon/IPL file
*/
bool loadZone(const std::string& path);
void loadCarcols(const std::string& path);
void loadWeather(const std::string& path);
void loadHandling(const std::string& path);
SCMFile* loadSCM(const std::string& path);
void loadGXT(const std::string& name);
/**
* Loads water level data
*/
void loadWaterpro(const std::string& path);
void loadWater(const std::string& path);
void load();
/**
* Loads model, placement, models and textures from a level file
*/
void loadLevelFile(const std::string& path);
/**
* Attempts to load a TXD, or does nothing if it has already been loaded
*/
void loadTXD(const std::string& name, bool async = false);
/**
* Attempts to load a DFF or does nothing if is already loaded
*/
void loadDFF(const std::string& name, bool async = false);
/**
* Loads an IFP file containing animations
*/
void loadIFP(const std::string& name);
/**
* Loads data from an object definition dat.
*/
void loadDynamicObjects(const std::string& name);
/**
* Loads weapon.dat
*/
void loadWeaponDAT(const std::string& path);
/**
* Loads data from an object definition dat.
*/
void loadDynamicObjects(const std::string& name);
bool loadAudioStream(const std::string& name);
bool loadAudioClip(const std::string& name, const std::string& fileName);
/**
* Loads weapon.dat
*/
void loadWeaponDAT(const std::string& path);
void loadSplash(const std::string& name);
bool loadAudioStream(const std::string& name);
bool loadAudioClip(const std::string& name, const std::string& fileName);
TextureData::Handle findTexture( const std::string& name, const std::string& alpha = "" )
{
return textures[{name, alpha}];
}
FileIndex index;
/**
* Files that have been loaded previously
*/
std::map<std::string, bool> loadedFiles;
/**
* IPL file locations
*/
std::map<std::string, std::string> iplLocations;
void loadSplash(const std::string& name);
/**
* Map of loaded archives
*/
std::map<std::string, LoaderIMG> archives;
/**
* Map Zones
*/
std::map<std::string, ZoneData> zones;
TextureData::Handle findTexture(const std::string& name,
const std::string& alpha = "") {
return textures[{name, alpha}];
}
/**
* Object Definitions
*/
std::map<ObjectID, ObjectInformationPtr> objectTypes;
FileIndex index;
uint16_t findModelObject(const std::string model);
/**
* Files that have been loaded previously
*/
std::map<std::string, bool> loadedFiles;
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 )
{
return std::static_pointer_cast<T>(f->second);
}
return nullptr;
}
/**
* IPL file locations
*/
std::map<std::string, std::string> iplLocations;
/**
* The vehicle colour palettes
*/
std::vector<glm::u8vec3> vehicleColours;
/**
* The vehicle colours for each vehicle type
*/
std::map<std::string, std::vector<std::pair<size_t,size_t>>> vehiclePalettes;
/**
* Map of loaded archives
*/
std::map<std::string, LoaderIMG> archives;
/**
* Vehicle information
*/
std::map<std::string, VehicleInfoHandle> vehicleInfo;
/**
* Texture Loader
*/
TextureLoader textureLoader;
/**
* Map Zones
*/
std::map<std::string, ZoneData> zones;
/**
* Weather Loader
*/
WeatherLoader weatherLoader;
/**
* Object Definitions
*/
std::map<ObjectID, ObjectInformationPtr> objectTypes;
/**
* Loaded models
*/
std::map<std::string, ResourceHandle<Model>::Ref> models;
uint16_t findModelObject(const std::string model);
/**
* Loaded textures (Textures are ID by name and alpha pairs)
*/
std::map<std::pair<std::string, std::string>, TextureData::Handle> textures;
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) {
return std::static_pointer_cast<T>(f->second);
}
return nullptr;
}
/**
* Texture atlases.
*/
std::vector<TextureAtlas*> atlases;
/**
* The vehicle colour palettes
*/
std::vector<glm::u8vec3> vehicleColours;
/**
* The vehicle colours for each vehicle type
*/
std::map<std::string, std::vector<std::pair<size_t, size_t>>>
vehiclePalettes;
/**
* Vehicle information
*/
std::map<std::string, VehicleInfoHandle> vehicleInfo;
/**
* Texture Loader
*/
TextureLoader textureLoader;
/**
* Weather Loader
*/
WeatherLoader weatherLoader;
/**
* Loaded models
*/
std::map<std::string, ResourceHandle<Model>::Ref> models;
/**
* Loaded textures (Textures are ID by name and alpha pairs)
*/
std::map<std::pair<std::string, std::string>, TextureData::Handle> textures;
/**
* Texture atlases.
*/
std::vector<TextureAtlas*> atlases;
/**
* Loaded Animations
*/
AnimationSet animations;
/**
* CollisionModel data.
*/
std::map<std::string, std::unique_ptr<CollisionModel>> collisions;
/**
* DynamicObjectData
*/
std::map<std::string, std::shared_ptr<DynamicObjectData>> dynamicObjectData;
std::vector<std::shared_ptr<WeaponData>> weaponData;
/**
* CollisionModel data.
*/
std::map<std::string, std::unique_ptr<CollisionModel>> collisions;
/**
* @struct WaterArea
* Stores Water Rectangle Information
*/
struct WaterArea
{
float height;
float xLeft, yBottom;
float xRight, yTop;
};
/**
* DynamicObjectData
*/
std::map<std::string, std::shared_ptr<DynamicObjectData>> dynamicObjectData;
/**
* Water Areas
*/
std::vector<WaterArea> waterBlocks;
/**
* Water heights
*/
float waterHeights[48];
/**
* Visible water heights
*/
uint8_t visibleWater[64*64];
/**
* The "real" water heights
*/
uint8_t realWater[128*128];
std::vector<std::shared_ptr<WeaponData>> weaponData;
int getWaterIndexAt(const glm::vec3& ws) const;
float getWaveHeightAt(const glm::vec3& ws) const;
/**
* @struct WaterArea
* Stores Water Rectangle Information
*/
struct WaterArea {
float height;
float xLeft, yBottom;
float xRight, yTop;
};
GameTexts texts;
/**
* Determines whether the given path is a valid game directory.
*/
static bool isValidGameDirectory(const std::string& path);
/**
* Water Areas
*/
std::vector<WaterArea> waterBlocks;
/**
* Water heights
*/
float waterHeights[48];
/**
* Visible water heights
*/
uint8_t visibleWater[64 * 64];
/**
* The "real" water heights
*/
uint8_t realWater[128 * 128];
int getWaterIndexAt(const glm::vec3& ws) const;
float getWaveHeightAt(const glm::vec3& ws) const;
GameTexts texts;
/**
* Determines whether the given path is a valid game directory.
*/
static bool isValidGameDirectory(const std::string& path);
};
#endif

View File

@ -1,72 +1,69 @@
#ifndef RWENGINE_GAMEINPUTSTATE_HPP
#define RWENGINE_GAMEINPUTSTATE_HPP
struct GameInputState
{
static constexpr float kButtonOnThreshold = 0.1f;
struct GameInputState {
static constexpr float kButtonOnThreshold = 0.1f;
/// Inputs that can be controlled
/// @todo find any sensible values
enum Control {
/* On Foot */
FireWeapon = 0,
NextWeapon,
NextTarget = NextWeapon,
LastWeapon,
LastTarget = LastWeapon,
GoForward,
GoBackwards,
GoLeft,
GoRight,
ZoomIn,
ZoomOut,
EnterExitVehicle,
ChangeCamera,
Jump,
Sprint,
AimWeapon,
Crouch,
Walk,
LookBehind,
/// Inputs that can be controlled
/// @todo find any sensible values
enum Control {
/* On Foot */
FireWeapon = 0,
NextWeapon,
NextTarget = NextWeapon,
LastWeapon,
LastTarget = LastWeapon,
GoForward,
GoBackwards,
GoLeft,
GoRight,
ZoomIn,
ZoomOut,
EnterExitVehicle,
ChangeCamera,
Jump,
Sprint,
AimWeapon,
Crouch,
Walk,
LookBehind,
/* In Vehicle */
VehicleFireWeapon = FireWeapon,
VehicleAccelerate,
VehicleBrake,
VehicleLeft = GoLeft,
VehicleRight = GoRight,
VehicleDown,
VehicleUp,
ChangeRadio,
Horn,
Submission,
Handbrake,
LookLeft,
LookRight,
VehicleAimLeft,
VehicleAimRight,
VehicleAimUp,
VehicleAimDown,
/* In Vehicle */
VehicleFireWeapon = FireWeapon,
VehicleAccelerate,
VehicleBrake,
VehicleLeft = GoLeft,
VehicleRight = GoRight,
VehicleDown,
VehicleUp,
ChangeRadio,
Horn,
Submission,
Handbrake,
LookLeft,
LookRight,
VehicleAimLeft,
VehicleAimRight,
VehicleAimUp,
VehicleAimDown,
_MaxControls
};
_MaxControls
};
/**
* Current state of each control [0 to 1].
*
* For buttons, this will result in either 0 or 1.
*/
float currentLevels[_MaxControls] = { };
/**
* Current state of each control [0 to 1].
*
* For buttons, this will result in either 0 or 1.
*/
float currentLevels[_MaxControls] = {};
float operator[] (Control c) const
{
return currentLevels[c];
}
float operator[](Control c) const {
return currentLevels[c];
}
bool pressed(Control c) const
{
return currentLevels[c] > kButtonOnThreshold;
}
bool pressed(Control c) const {
return currentLevels[c] > kButtonOnThreshold;
}
};
#endif

View File

@ -1,151 +1,142 @@
#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{}
, gameTime(0.f)
, currentProgress(0)
, maxProgress(1)
, maxWantedLevel(0)
, playerObject(0)
, scriptOnMissionFlag(nullptr)
, fadeOut(true)
, fadeStart(0.f)
, fadeTime(0.f)
, fadeSound(false)
, skipCutscene(false)
, isIntroPlaying(false)
, currentCutscene(nullptr)
, cutsceneStartTime(-1.f)
, isCinematic(false)
, cameraNear(0.1f)
, cameraFixed(false)
, cameraTarget(0)
, importExportPortland(0)
, importExportShoreside(0)
, importExportUnused(0)
, world(nullptr)
, script(nullptr)
{
: basic{}
, gameTime(0.f)
, currentProgress(0)
, maxProgress(1)
, maxWantedLevel(0)
, playerObject(0)
, scriptOnMissionFlag(nullptr)
, fadeOut(true)
, fadeStart(0.f)
, fadeTime(0.f)
, fadeSound(false)
, skipCutscene(false)
, isIntroPlaying(false)
, currentCutscene(nullptr)
, cutsceneStartTime(-1.f)
, isCinematic(false)
, cameraNear(0.1f)
, cameraFixed(false)
, cameraTarget(0)
, importExportPortland(0)
, importExportShoreside(0)
, importExportUnused(0)
, world(nullptr)
, script(nullptr) {
}
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
{
l++;
}
}
blip.id = l;
radarBlips.insert({l, blip});
return l;
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 {
l++;
}
}
blip.id = l;
radarBlips.insert({l, blip});
return l;
}
void GameState::removeBlip(int blip)
{
auto it = radarBlips.find( blip );
if ( it != radarBlips.end() )
{
radarBlips.erase(it);
}
void GameState::removeBlip(int blip) {
auto it = radarBlips.find(blip);
if (it != radarBlips.end()) {
radarBlips.erase(it);
}
}

View File

@ -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,373 +18,350 @@ class ScriptMachine;
class PlayerController;
struct CutsceneData;
struct SystemTime
{
uint16_t year;
uint16_t month;
uint16_t dayOfWeek;
uint16_t day;
uint16_t hour;
uint16_t minute;
uint16_t second;
uint16_t millisecond;
struct SystemTime {
uint16_t year;
uint16_t month;
uint16_t dayOfWeek;
uint16_t day;
uint16_t hour;
uint16_t minute;
uint16_t second;
uint16_t millisecond;
};
/** Block 0 State */
struct BasicState
{
GameStringChar saveName[24];
SystemTime saveTime;
uint32_t unknown;
uint16_t islandNumber;
glm::vec3 cameraPosition;
uint32_t gameMinuteMS;
uint32_t lastTick;
uint8_t gameHour;
uint8_t _align0[3];
uint8_t gameMinute;
uint8_t _align1[3];
uint16_t padMode;
uint8_t _align2[2];
uint32_t timeMS;
float timeScale;
float timeStep;
float timeStep_unclipped; // Unknown purpose
uint32_t frameCounter;
float timeStep2;
float framesPerUpdate;
float timeScale2;
uint16_t lastWeather;
uint8_t _align3[2];
uint16_t nextWeather;
uint8_t _align4[2];
uint16_t forcedWeather;
uint8_t _align5[2];
float weatherInterpolation;
uint8_t dateTime[24]; // Unused
uint32_t weatherType;
float cameraData;
float cameraData2;
struct BasicState {
GameStringChar saveName[24];
SystemTime saveTime;
uint32_t unknown;
uint16_t islandNumber;
glm::vec3 cameraPosition;
uint32_t gameMinuteMS;
uint32_t lastTick;
uint8_t gameHour;
uint8_t _align0[3];
uint8_t gameMinute;
uint8_t _align1[3];
uint16_t padMode;
uint8_t _align2[2];
uint32_t timeMS;
float timeScale;
float timeStep;
float timeStep_unclipped; // Unknown purpose
uint32_t frameCounter;
float timeStep2;
float framesPerUpdate;
float timeScale2;
uint16_t lastWeather;
uint8_t _align3[2];
uint16_t nextWeather;
uint8_t _align4[2];
uint16_t forcedWeather;
uint8_t _align5[2];
float weatherInterpolation;
uint8_t dateTime[24]; // Unused
uint32_t weatherType;
float cameraData;
float cameraData2;
BasicState ();
BasicState();
};
/** Block 16 player info */
struct PlayerInfo
{
uint32_t money;
uint8_t unknown1;
uint32_t unknown2;
uint16_t unknown3;
float unknown4;
uint32_t displayedMoney;
uint32_t hiddenPackagesCollected;
uint32_t hiddenPackageCount;
uint8_t neverTired;
uint8_t fastReload;
uint8_t thaneOfLibertyCity;
uint8_t singlePayerHealthcare;
uint8_t unknown5[70];
struct PlayerInfo {
uint32_t money;
uint8_t unknown1;
uint32_t unknown2;
uint16_t unknown3;
float unknown4;
uint32_t displayedMoney;
uint32_t hiddenPackagesCollected;
uint32_t hiddenPackageCount;
uint8_t neverTired;
uint8_t fastReload;
uint8_t thaneOfLibertyCity;
uint8_t singlePayerHealthcare;
uint8_t unknown5[70];
PlayerInfo ();
PlayerInfo();
};
/** Block 17 */
struct GameStats
{
uint32_t playerKills;
uint32_t otherKills;
uint32_t carsExploded;
uint32_t shotsHit;
uint32_t pedTypesKilled[23];
uint32_t helicoptersDestroyed;
uint32_t playerProgress;
uint32_t explosiveKgsUsed;
uint32_t bulletsFired;
uint32_t bulletsHit;
uint32_t carsCrushed;
uint32_t headshots;
uint32_t timesBusted;
uint32_t timesHospital;
uint32_t daysPassed;
uint32_t mmRainfall;
uint32_t insaneJumpMaxDistance;
uint32_t insaneJumpMaxHeight;
uint32_t insaneJumpMaxFlips;
uint32_t insangeJumpMaxRotation;
/*
* 0 none completed
* 1 insane stunt
* 2 perfect insane stunt
* 3 double insane stunt
* 4 perfect double insane stunt
* 5 triple insane stunt
* 6 perfect " " "
* 7 quadruple
* 8 perfect quadruple
*/
uint32_t bestStunt;
uint32_t uniqueStuntsFound;
uint32_t uniqueStuntsTotal;
uint32_t missionAttempts;
uint32_t missionsPassed;
uint32_t passengersDroppedOff;
uint32_t taxiRevenue;
uint32_t portlandPassed;
uint32_t stauntonPassed;
uint32_t shoresidePassed;
uint32_t bestTurismoTime;
float distanceWalked;
float distanceDriven;
uint32_t patriotPlaygroundTime;
uint32_t aRideInTheParkTime;
uint32_t grippedTime;
uint32_t multistoryMayhemTime;
uint32_t peopleSaved;
uint32_t criminalsKilled;
uint32_t highestParamedicLevel;
uint32_t firesExtinguished;
uint32_t longestDodoFlight;
uint32_t bombDefusalTime;
uint32_t rampagesPassed;
uint32_t totalRampages;
uint32_t totalMissions;
uint32_t fastestTime[16]; // not used
uint32_t highestScore[16];
uint32_t peopleKilledSinceCheckpoint; // ?
uint32_t peopleKilledSinceLastBustedOrWasted;
char lastMissionGXT[8];
struct GameStats {
uint32_t playerKills;
uint32_t otherKills;
uint32_t carsExploded;
uint32_t shotsHit;
uint32_t pedTypesKilled[23];
uint32_t helicoptersDestroyed;
uint32_t playerProgress;
uint32_t explosiveKgsUsed;
uint32_t bulletsFired;
uint32_t bulletsHit;
uint32_t carsCrushed;
uint32_t headshots;
uint32_t timesBusted;
uint32_t timesHospital;
uint32_t daysPassed;
uint32_t mmRainfall;
uint32_t insaneJumpMaxDistance;
uint32_t insaneJumpMaxHeight;
uint32_t insaneJumpMaxFlips;
uint32_t insangeJumpMaxRotation;
/*
* 0 none completed
* 1 insane stunt
* 2 perfect insane stunt
* 3 double insane stunt
* 4 perfect double insane stunt
* 5 triple insane stunt
* 6 perfect " " "
* 7 quadruple
* 8 perfect quadruple
*/
uint32_t bestStunt;
uint32_t uniqueStuntsFound;
uint32_t uniqueStuntsTotal;
uint32_t missionAttempts;
uint32_t missionsPassed;
uint32_t passengersDroppedOff;
uint32_t taxiRevenue;
uint32_t portlandPassed;
uint32_t stauntonPassed;
uint32_t shoresidePassed;
uint32_t bestTurismoTime;
float distanceWalked;
float distanceDriven;
uint32_t patriotPlaygroundTime;
uint32_t aRideInTheParkTime;
uint32_t grippedTime;
uint32_t multistoryMayhemTime;
uint32_t peopleSaved;
uint32_t criminalsKilled;
uint32_t highestParamedicLevel;
uint32_t firesExtinguished;
uint32_t longestDodoFlight;
uint32_t bombDefusalTime;
uint32_t rampagesPassed;
uint32_t totalRampages;
uint32_t totalMissions;
uint32_t fastestTime[16]; // not used
uint32_t highestScore[16];
uint32_t peopleKilledSinceCheckpoint; // ?
uint32_t peopleKilledSinceLastBustedOrWasted;
char lastMissionGXT[8];
GameStats ();
GameStats();
};
struct TextDisplayData
{
// This is set by the final display text command.
GameString text;
glm::vec2 position;
struct TextDisplayData {
// This is set by the final display text command.
GameString text;
glm::vec2 position;
glm::vec4 colourFG;
glm::vec4 colourBG;
glm::vec4 colourFG;
glm::vec4 colourBG;
};
/**
* Data about a blip
*/
struct BlipData
{
int id;
enum BlipType
{
Location = 0,
Vehicle = 1,
Pickup = 2,
Character = 3,
Instance = 4,
};
BlipType type;
GameObjectID target;
// If target is null then use coord
glm::vec3 coord;
std::string texture; // Texture for use in the radar
uint32_t colour = 0; // Color value (index or RGBA)
bool dimmed = false; // Color dimming if not in RGBA mode
struct BlipData {
int id;
uint16_t size = 3; // Only used if texture is empty
enum BlipType {
Location = 0,
Vehicle = 1,
Pickup = 2,
Character = 3,
Instance = 4,
};
BlipType type;
GameObjectID target;
// If target is null then use coord
glm::vec3 coord;
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)
{ }
std::string texture; // Texture for use in the radar
uint32_t colour = 0; // Color value (index or RGBA)
bool dimmed = false; // Color dimming if not in RGBA mode
int getScriptObjectID() const
{
return id;
}
uint16_t size = 3; // Only used if texture is empty
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) {
}
int getScriptObjectID() const {
return id;
}
};
/**
* Data for garages
*/
struct GarageInfo
{
enum /*GarageType*/ {
GARAGE_MISSION = 1,
GARAGE_BOMBSHOP1 = 2,
GARAGE_BOMBSHOP2 = 3,
GARAGE_BOMBSHOP3 = 4,
GARAGE_RESPRAY = 5,
GARAGE_INVALID = 6,
GARAGE_SPECIFIC_CARS_ONLY = 7, /* See Opcode 0x21B */
GARAGE_COLLECTCARS1 = 8, /* See Opcode 0x03D4 */
GARAGE_COLLECTCARS2 = 9,
GARAGE_COLLECTCARS3 = 10, /* Unused */
GARAGE_OPENFOREXIT = 11,
GARAGE_INVALID2 = 12,
GARAGE_CRUSHER = 13,
GARAGE_MISSION_KEEPCAR = 14,
GARAGE_FOR_SCRIPT = 15,
GARAGE_HIDEOUT_ONE = 16, /* Portland */
GARAGE_HIDEOUT_TWO = 17, /* Staunton */
GARAGE_HIDEOUT_THREE = 18, /* Shoreside */
GARAGE_FOR_SCRIPT2 = 19,
GARAGE_OPENS_FOR_SPECIFIC_CAR = 20,
GARAGE_OPENS_ONCE = 21
};
int id;
glm::vec3 min;
glm::vec3 max;
int type;
struct GarageInfo {
enum /*GarageType*/ {
GARAGE_MISSION = 1,
GARAGE_BOMBSHOP1 = 2,
GARAGE_BOMBSHOP2 = 3,
GARAGE_BOMBSHOP3 = 4,
GARAGE_RESPRAY = 5,
GARAGE_INVALID = 6,
GARAGE_SPECIFIC_CARS_ONLY = 7, /* See Opcode 0x21B */
GARAGE_COLLECTCARS1 = 8, /* See Opcode 0x03D4 */
GARAGE_COLLECTCARS2 = 9,
GARAGE_COLLECTCARS3 = 10, /* Unused */
GARAGE_OPENFOREXIT = 11,
GARAGE_INVALID2 = 12,
GARAGE_CRUSHER = 13,
GARAGE_MISSION_KEEPCAR = 14,
GARAGE_FOR_SCRIPT = 15,
GARAGE_HIDEOUT_ONE = 16, /* Portland */
GARAGE_HIDEOUT_TWO = 17, /* Staunton */
GARAGE_HIDEOUT_THREE = 18, /* Shoreside */
GARAGE_FOR_SCRIPT2 = 19,
GARAGE_OPENS_FOR_SPECIFIC_CAR = 20,
GARAGE_OPENS_ONCE = 21
};
int id;
glm::vec3 min;
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
{
return id;
}
int getScriptObjectID() const {
return id;
}
};
/**
* Gameplay state object that holds persistent state, and references runtime
* world state.
*/
class GameState
{
class GameState {
public:
/**
Basic Game State
*/
BasicState basic;
/**
Basic Game State
*/
BasicState basic;
/**
Player stats
*/
PlayerInfo playerInfo;
/**
Player stats
*/
PlayerInfo playerInfo;
/**
Game Stats
*/
GameStats gameStats;
/**
Game Stats
*/
GameStats gameStats;
/**
* Second since game was started
*/
float gameTime;
unsigned int currentProgress;
unsigned int maxProgress;
/**
* Second since game was started
*/
float gameTime;
unsigned int currentProgress;
unsigned int maxProgress;
unsigned int maxWantedLevel;
unsigned int maxWantedLevel;
GameObjectID playerObject;
GameObjectID playerObject;
/**
* @brief Stores a pointer to script global that stores the on-mission state.
*/
int32_t* scriptOnMissionFlag;
/** Objects created by the current mission */
std::vector<GameObject*> missionObjects;
bool overrideNextStart;
glm::vec4 nextRestartLocation;
/**
* @brief Stores a pointer to script global that stores the on-mission
* state.
*/
int32_t* scriptOnMissionFlag;
bool fadeOut;
float fadeStart;
float fadeTime;
bool fadeSound;
glm::u16vec3 fadeColour;
/** Objects created by the current mission */
std::vector<GameObject*> missionObjects;
std::string currentSplash;
bool overrideNextStart;
glm::vec4 nextRestartLocation;
bool skipCutscene;
bool isIntroPlaying;
CutsceneData* currentCutscene;
float cutsceneStartTime;
/** Flag for rendering cutscene letterbox */
bool isCinematic;
std::string lastMissionName;
/// Stores the "special" character and cutscene model indices.
std::map<unsigned short, std::string> specialCharacters;
std::map<unsigned short, std::string> specialModels;
bool fadeOut;
float fadeStart;
float fadeTime;
bool fadeSound;
glm::u16vec3 fadeColour;
/// Handles on screen text behaviour
ScreenText text;
std::string currentSplash;
TextDisplayData nextText;
/**
* Stores temporary, one-tick messages
*/
std::vector<TextDisplayData> texts;
bool skipCutscene;
bool isIntroPlaying;
CutsceneData* currentCutscene;
float cutsceneStartTime;
/** Flag for rendering cutscene letterbox */
bool isCinematic;
/** The camera near value currently set by the script */
float cameraNear;
bool cameraFixed;
glm::vec3 cameraPosition;
glm::quat cameraRotation;
std::string lastMissionName;
GameObjectID cameraTarget;
std::vector<VehicleGenerator> vehicleGenerators;
std::map<int, BlipData> radarBlips;
/// Stores the "special" character and cutscene model indices.
std::map<unsigned short, std::string> specialCharacters;
std::map<unsigned short, std::string> specialModels;
std::vector<GarageInfo> garages;
/// Handles on screen text behaviour
ScreenText text;
/**
* Bitsets for the car import / export list mission
*/
std::bitset<32> importExportPortland;
std::bitset<32> importExportShoreside;
std::bitset<32> importExportUnused;
TextDisplayData nextText;
/**
* Stores temporary, one-tick messages
*/
std::vector<TextDisplayData> texts;
/**
* State of the game input
*/
GameInputState input;
/** The camera near value currently set by the script */
float cameraNear;
bool cameraFixed;
glm::vec3 cameraPosition;
glm::quat cameraRotation;
/**
* World to use for this state, this isn't saved, just used at runtime
*/
GameWorld* world;
GameObjectID cameraTarget;
/**
* Script Machine associated with this state if it exists.
*/
ScriptMachine* script;
std::vector<VehicleGenerator> vehicleGenerators;
GameState();
std::map<int, BlipData> radarBlips;
/**
* Adds a blip to the state, returning it's ID.
*/
int addRadarBlip(BlipData& blip);
/**
* Removes a blip
*/
void removeBlip(int blip);
std::vector<GarageInfo> garages;
/**
* Bitsets for the car import / export list mission
*/
std::bitset<32> importExportPortland;
std::bitset<32> importExportShoreside;
std::bitset<32> importExportUnused;
/**
* State of the game input
*/
GameInputState input;
/**
* World to use for this state, this isn't saved, just used at runtime
*/
GameWorld* world;
/**
* Script Machine associated with this state if it exists.
*/
ScriptMachine* script;
GameState();
/**
* Adds a blip to the state, returning it's ID.
*/
int addRadarBlip(BlipData& blip);
/**
* Removes a blip
*/
void removeBlip(int blip);
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -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,323 +35,333 @@ 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
};
AreaIndicatorType type;
glm::vec3 position;
glm::vec3 radius;
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(Logger* log, WorkContext* work, GameData* dat);
~GameWorld();
~GameWorld();
Logger* logger;
Logger* logger;
/**
* Loads an IPL into the game.
* @param name The name of the IPL as it appears in the games' gta.dat
*/
bool placeItems(const std::string& name);
/**
* Loads an IPL into the game.
* @param name The name of the IPL as it appears in the games' gta.dat
*/
bool placeItems(const std::string& name);
/**
* @brief createTraffic spawn transitory peds and vehicles
* @param viewCamera The camera to create traffic near
*
* The position and frustum of the passed in camera is used to determine
* the radius where traffic can be spawned, and the frustum is used to avoid
* spawning traffic in view of the player.
*/
void createTraffic(const ViewCamera& viewCamera);
/**
* @brief createTraffic spawn transitory peds and vehicles
* @param viewCamera The camera to create traffic near
*
* The position and frustum of the passed in camera is used to determine
* the radius where traffic can be spawned, and the frustum is used to avoid
* spawning traffic in view of the player.
*/
void createTraffic(const ViewCamera& viewCamera);
/**
* @brief cleanupTraffic Cleans up traffic too far away from the given
* camera
* @param viewCamera
*/
void cleanupTraffic(const ViewCamera& viewCamera);
/**
* @brief cleanupTraffic Cleans up traffic too far away from the given camera
* @param viewCamera
*/
void cleanupTraffic(const ViewCamera& viewCamera);
/**
* Creates an instance
*/
InstanceObject* createInstance(const uint16_t id, const glm::vec3& pos,
const glm::quat& rot = glm::quat());
/**
* Creates an instance
*/
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());
/**
* @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());
/**
* Creates a vehicle
*/
VehicleObject *createVehicle(const uint16_t id, const glm::vec3& pos, const glm::quat& rot = glm::quat(), GameObjectID gid = 0);
/**
* Creates a vehicle
*/
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);
/**
* Creates a pedestrian.
*/
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);
/**
* Creates a player
*/
CharacterObject* createPlayer(const glm::vec3& pos,
const glm::quat& rot = glm::quat(),
GameObjectID gid = 0);
/**
* Creates a pickup
*/
PickupObject* createPickup(const glm::vec3& pos, int id, int type);
/**
* Creates a pickup
*/
PickupObject* createPickup(const glm::vec3& pos, int id, int type);
/**
* Destroys an existing Object
*/
void destroyObject(GameObject* object);
/**
* Destroys an existing Object
*/
void destroyObject(GameObject* object);
/**
* @brief Put an object on the deletion queue.
*/
void destroyObjectQueued(GameObject* object);
/**
* @brief Put an object on the deletion queue.
*/
void destroyObjectQueued(GameObject* object);
/**
* @brief Destroys all objects on the destruction queue.
*/
void destroyQueuedObjects();
/**
* @brief Destroys all objects on the destruction queue.
*/
void destroyQueuedObjects();
/**
* Performs a weapon scan against things in the world
*/
void doWeaponScan(const WeaponScan &scan );
/**
* Performs a weapon scan against things in the world
*/
void doWeaponScan(const WeaponScan& scan);
/**
* Allocates a new VisualFX of the given type
*/
VisualFX* createEffect(VisualFX::EffectType type);
/**
* Immediately destoys the given effect
*/
void destroyEffect(VisualFX* effect);
/**
* Allocates a new VisualFX of the given type
*/
VisualFX* createEffect(VisualFX::EffectType type);
/**
* Returns the current hour
*/
int getHour();
/**
* Returns the current minute
*/
int getMinute();
/**
* Immediately destoys the given effect
*/
void destroyEffect(VisualFX* effect);
/**
* Modifies the game time and handles the circular nature of clock numbers
* Supports negative numbers
*/
void offsetGameTime(int minutes);
/**
* Returns the current hour
*/
int getHour();
glm::vec3 getGroundAtPosition(const glm::vec3& pos) const;
/**
* Returns the current minute
*/
int getMinute();
float getGameTime() const;
/**
* Modifies the game time and handles the circular nature of clock numbers
* Supports negative numbers
*/
void offsetGameTime(int minutes);
/**
* @brief getInventoryItem
* @param weaponId The Weapon ID (inventory slot) of the weapon to fetch
* @return Instance of the weapon
*/
InventoryItem* getInventoryItem(uint16_t weaponId) const;
glm::vec3 getGroundAtPosition(const glm::vec3& pos) const;
/**
* Game data
*/
GameData* data;
float getGameTime() const;
/**
* Gameplay state
*/
GameState* state;
/**
* State of playing sounds
*/
SoundManager sound;
/**
* @brief getInventoryItem
* @param weaponId The Weapon ID (inventory slot) of the weapon to fetch
* @return Instance of the weapon
*/
InventoryItem* getInventoryItem(uint16_t weaponId) const;
/**
* Chase state
*/
ChaseCoordinator chase;
/**
* Game data
*/
GameData* data;
/**
* Each object type is allocated from a pool. This object helps manage
* the individual pools.
*/
struct ObjectPool
{
std::map<GameObjectID, GameObject*> objects;
/**
* Allocates the game object a GameObjectID and inserts it into
* the pool
*/
void insert(GameObject* object);
/**
* Gameplay state
*/
GameState* state;
/**
* Removes a game object from this pool
*/
void remove(GameObject* object);
/**
* State of playing sounds
*/
SoundManager sound;
/**
* Finds a game object if it exists in this pool
*/
GameObject* find(GameObjectID id) const;
};
/**
* Chase state
*/
ChaseCoordinator chase;
/**
* Stores all game objects
*/
std::vector<GameObject*> allObjects;
/**
* Each object type is allocated from a pool. This object helps manage
* the individual pools.
*/
struct ObjectPool {
std::map<GameObjectID, GameObject*> objects;
ObjectPool pedestrianPool;
ObjectPool instancePool;
ObjectPool vehiclePool;
ObjectPool pickupPool;
ObjectPool cutscenePool;
ObjectPool projectilePool;
/**
* Allocates the game object a GameObjectID and inserts it into
* the pool
*/
void insert(GameObject* object);
ObjectPool& getTypeObjectPool(GameObject* object);
/**
* Removes a game object from this pool
*/
void remove(GameObject* object);
std::vector<PlayerController*> players;
/**
* Finds a game object if it exists in this pool
*/
GameObject* find(GameObjectID id) const;
};
/**
* @brief getBlipTarget
* @param blip
* @return The targetted object of the given blip
*/
GameObject *getBlipTarget(const BlipData &blip) const;
/**
* Stores all game objects
*/
std::vector<GameObject*> allObjects;
/**
* Map of Model Names to Instances
*/
std::map<std::string, InstanceObject*> modelInstances;
ObjectPool pedestrianPool;
ObjectPool instancePool;
ObjectPool vehiclePool;
ObjectPool pickupPool;
ObjectPool cutscenePool;
ObjectPool projectilePool;
/**
* AI Graph
*/
AIGraph aigraph;
/**
* Visual Effects
* @todo Consider using lighter handing mechanism
*/
std::vector<VisualFX*> effects;
ObjectPool& getTypeObjectPool(GameObject* object);
/**
* Randomness Engine
*/
std::default_random_engine randomEngine;
/**
* Bullet
*/
btDefaultCollisionConfiguration* collisionConfig;
btCollisionDispatcher* collisionDispatcher;
btBroadphaseInterface* broadphase;
btSequentialImpulseConstraintSolver* solver;
btDiscreteDynamicsWorld* dynamicsWorld;
std::vector<PlayerController*> players;
/**
* @brief physicsNearCallback
* Used to implement uprooting and other physics oddities.
*/
static bool ContactProcessedCallback(btManifoldPoint& mp, void* body0, void* body1);
/**
* @brief getBlipTarget
* @param blip
* @return The targetted object of the given blip
*/
GameObject* getBlipTarget(const BlipData& blip) const;
/**
* @brief PhysicsTickCallback updates object each physics tick.
* @param physWorld
* @param timeStep
*/
static void PhysicsTickCallback(btDynamicsWorld* physWorld, btScalar timeStep);
/**
* Map of Model Names to Instances
*/
std::map<std::string, InstanceObject*> modelInstances;
/**
* Work related
*/
WorkContext* _work;
/**
* AI Graph
*/
AIGraph aigraph;
/**
* @brief Loads and starts the named cutscene.
* @param name
*/
void loadCutscene(const std::string& name);
void startCutscene();
void clearCutscene();
bool isCutsceneDone();
/**
* Visual Effects
* @todo Consider using lighter handing mechanism
*/
std::vector<VisualFX*> effects;
std::string cutsceneAudio;
bool cutsceneAudioLoaded;
std::string missionAudio;
/**
* Randomness Engine
*/
std::default_random_engine randomEngine;
/**
* @brief loads a model into a special character slot.
*/
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 drawAreaIndicator(AreaIndicatorInfo::AreaIndicatorType type, glm::vec3 position, glm::vec3 radius);
const std::vector<AreaIndicatorInfo>& getAreaIndicators() const { return areaIndicators; }
void clearTickData();
void setPaused(bool pause);
bool isPaused() const;
/**
* Bullet
*/
btDefaultCollisionConfiguration* collisionConfig;
btCollisionDispatcher* collisionDispatcher;
btBroadphaseInterface* broadphase;
btSequentialImpulseConstraintSolver* solver;
btDiscreteDynamicsWorld* dynamicsWorld;
/**
* Attempt to spawn a vehicle at a vehicle generator
*/
VehicleObject* tryToSpawnVehicle(VehicleGenerator& gen);
/**
* @brief physicsNearCallback
* Used to implement uprooting and other physics oddities.
*/
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);
/**
* Work related
*/
WorkContext* _work;
/**
* @brief Loads and starts the named cutscene.
* @param name
*/
void loadCutscene(const std::string& name);
void startCutscene();
void clearCutscene();
bool isCutsceneDone();
std::string cutsceneAudio;
bool cutsceneAudioLoaded;
std::string missionAudio;
/**
* @brief loads a model into a special character slot.
*/
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 drawAreaIndicator(AreaIndicatorInfo::AreaIndicatorType type,
glm::vec3 position, glm::vec3 radius);
const std::vector<AreaIndicatorInfo>& getAreaIndicators() const {
return areaIndicators;
}
void clearTickData();
void setPaused(bool pause);
bool isPaused() const;
/**
* Attempt to spawn a vehicle at a vehicle generator
*/
VehicleObject* tryToSpawnVehicle(VehicleGenerator& gen);
private:
/**
* @brief Used by objects to delete themselves during updates.
*/
std::set<GameObject*> deletionQueue;
/**
* @brief Used by objects to delete themselves during updates.
*/
std::set<GameObject*> deletionQueue;
std::vector<AreaIndicatorInfo> areaIndicators;
std::vector<AreaIndicatorInfo> areaIndicators;
/**
* Inventory Item instances
*/
std::vector<InventoryItem*> inventoryItems;
/**
* Inventory Item instances
*/
std::vector<InventoryItem*> inventoryItems;
/**
* Flag for pausing the simulation
*/
bool paused;
/**
* Flag for pausing the simulation
*/
bool paused;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -12,42 +12,39 @@
class GameWorld;
class ScriptMachine;
struct SaveGameInfo
{
std::string savePath;
bool valid;
BasicState basicState;
struct SaveGameInfo {
std::string savePath;
bool valid;
BasicState basicState;
};
/**
* 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
*/
static void writeGame(GameState& state, const std::string& file);
/**
* Writes the entire game state to a file format that closely approximates
* the format used in GTA III
*/
static void writeGame(GameState& state, const std::string& file);
/**
* Loads an entire Game State from a file, using a format similar to the
* format used by GTA III.
*
* It assumes that the state already has a world and script that have been
* initalized to the same state as the game being loaded.
* @return status, false if failure occured.
*/
static bool loadGame(GameState& state, const std::string& file);
/**
* Loads an entire Game State from a file, using a format similar to the
* format used by GTA III.
*
* It assumes that the state already has a world and script that have been
* initalized to the same state as the game being loaded.
* @return status, false if failure occured.
*/
static bool loadGame(GameState& state, const std::string& file);
static bool getSaveInfo(const std::string& file, BasicState* outState);
static bool getSaveInfo(const std::string& file, BasicState* outState);
/**
* Returns save game information for all found saves
*/
static std::vector<SaveGameInfo> getAllSaveGameInfo();
/**
* Returns save game information for all found saves
*/
static std::vector<SaveGameInfo> getAllSaveGameInfo();
};
#endif

View File

@ -1,197 +1,168 @@
#include <engine/ScreenText.hpp>
void ScreenText::tick(float dt)
{
int millis = dt * 1000;
void ScreenText::tick(float dt) {
int millis = dt * 1000;
// Remove all the immedate text
m_textQueues[static_cast<size_t>(ScreenTextType::Immediate)].clear();
// 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();)
{
auto& big = m_textQueues[t][i];
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
{
++i;
}
}
}
big.displayedMS += millis;
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)
// Horizontally: Centered
// Vertically: Baseline at y = 252 (from top)
// Size: 25 Pixel high letters ('S', 'l')
case 1:
return {str,
{320.f, 252.f},
1,
50,
{2, 0, 0, 0},
{58, 119, 133},
1,
durationMS,
0,
600,
id};
// Color: Blue
// Font: Pricedown
// Style: Italic (lowercase only)
// Horizontally: Centered
// Vertically: Baseline at y = 252 (from top)
// Size: 25 Pixel high letters ('S', 'l')
case 1:
return {
str,
{320.f, 252.f},
1,
50,
{ 2, 0, 0, 0},
{58, 119, 133},
1,
durationMS,
0,
600,
id
};
// Color: Yellow/Gold
// Font: Pricedown
// Style: Italic (lowercase only)
// Horizontally: Right at x = 620 (from left)
// Vertically: Baseline at y = 380 (from top)
// Size: 22 Pixel high letters ('S', 'l')
case 2:
return {str,
{620.f, 380.f},
1,
30,
{2, 3, 0, 0},
{214, 171, 9},
2,
durationMS,
0,
600,
id};
// Color: Yellow/Gold
// Font: Pricedown
// Style: Italic (lowercase only)
// Horizontally: Right at x = 620 (from left)
// Vertically: Baseline at y = 380 (from top)
// Size: 22 Pixel high letters ('S', 'l')
case 2:
return {
str,
{620.f, 380.f},
1,
30,
{ 2, 3, 0, 0},
{214, 171, 9},
2,
durationMS,
0,
600,
id
};
// Color: Light brown
// Font: Pricedown
// Style: Italic (lowercase only)
// Horizontally: Right at x = 620 (from left)
// Vertically: Baseline at y = 427 (from top)
// Size: 28 Pixel high letters ('S', 'l')
case 3:
return {str,
{320.f, 400.f},
1,
50,
{5, 5, 0, 0},
{169, 123, 88}, /// @todo verify
1,
durationMS,
0,
600,
id};
// Color: Light brown
// Font: Pricedown
// Style: Italic (lowercase only)
// Horizontally: Right at x = 620 (from left)
// Vertically: Baseline at y = 427 (from top)
// Size: 28 Pixel high letters ('S', 'l')
case 3:
return {
str,
{320.f, 400.f},
1,
50,
{ 5, 5, 0, 0},
{169, 123, 88}, /// @todo verify
1,
durationMS,
0,
600,
id
};
// Color: Blue
// Font: Arial
// Style: Italic
// Horizontally: Centered
// Vertically: Baseline at y = 176 (from top)
// Size: 20 Pixel high letters ('S', 'l')
case 4:
case 5:
return {str,
{320.f, 176.f},
2,
50,
((style == 4) ? glm::u8vec4({2, 2, 0, 0})
: glm::u8vec4({-2, -2, 0, 0})),
{90, 115, 150}, /// @todo verify
1,
durationMS,
0,
600,
id};
// Color: Blue
// Font: Arial
// Style: Italic
// Horizontally: Centered
// Vertically: Baseline at y = 176 (from top)
// Size: 20 Pixel high letters ('S', 'l')
case 4:
case 5:
return {
str,
{320.f, 176.f},
2,
50,
((style == 4) ? glm::u8vec4({ 2, 2, 0, 0}) : glm::u8vec4({ -2, -2, 0, 0 })),
{90, 115, 150}, /// @todo verify
1,
durationMS,
0,
600,
id
};
// Color: Brown
// Font: Arial
// Style: Italic
// Horizontally: Centered
// Vertically: Baseline at y = 240 (from top)
// Size: 16 Pixel high letters ('S', 'l')
case 6:
return {str,
{320.f, 240.f},
2,
50,
{2, 2, 0, 0},
{152, 89, 39},
1,
durationMS,
0,
600,
id};
// Color: Brown
// Font: Arial
// Style: Italic
// Horizontally: Centered
// Vertically: Baseline at y = 240 (from top)
// Size: 16 Pixel high letters ('S', 'l')
case 6:
return {
str,
{320.f, 240.f},
2,
50,
{ 2, 2, 0, 0},
{152, 89, 39},
1,
durationMS,
0,
600,
id
};
default:
RW_ERROR("Unhandled text style");
break;
}
default:
RW_ERROR("Unhandled text style");
break;
}
return {
GameStringUtil::fromString("Error, style " + std::to_string(style)),
{320.f, 400.f},
2,
50,
{20, 20, 0, 0},
{20, 20, 200},
1,
durationMS,
0,
600,
id
};
return {GameStringUtil::fromString("Error, style " + std::to_string(style)),
{320.f, 400.f},
2,
50,
{20, 20, 0, 0},
{20, 20, 200},
1,
durationMS,
0,
600,
id};
}
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,
{320.f, 420.f},
2,
18,
{1, 0, 0, 0},
{255, 255, 255},
1,
durationMS,
0,
50,
id
};
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,
{320.f, 420.f},
2,
18,
{1, 0, 0, 0},
{255, 255, 255},
1,
durationMS,
0,
50,
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};
}

View File

@ -1,71 +1,69 @@
#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
{
/// Big text will be rendered according to the proscribed style.
/// Adding a 2nd big text will cause the first to terminate.
Big = 0,
/// See Big, will wait for any Big text to finish.
BigLowPriority = 1,
/// Will be cleared by the clear help opcode
Help = 2,
/// Automatically cleared after each tick, for generic text.
Immediate = 3,
/// High priority cutscene text
HighPriority = 4,
///
_Count = 5
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,
/// See Big, will wait for any Big text to finish.
BigLowPriority = 1,
/// Will be cleared by the clear help opcode
Help = 2,
/// Automatically cleared after each tick, for generic text.
Immediate = 3,
/// High priority cutscene text
HighPriority = 4,
///
_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
{
/// After processing numbers
GameString text;
/// in the virtual 640x480 screen space
glm::vec2 position;
/// Font number
int font;
/// Font size
int size;
/// Background colour (or, if a == 0, shadow offset)
glm::u8vec4 colourBG;
/// Foreground colour
glm::u8vec3 colourFG;
/// Alignment (left = 0, center = 1, right = 2)
unsigned char alignment;
/// Onscreen duration
int durationMS;
/// The amount of time onscreen so far
int displayedMS;
/// Wrap width
int wrapX;
/// ID used to reference the text.
GameStringKey id;
struct ScreenTextEntry {
/// After processing numbers
GameString text;
/// in the virtual 640x480 screen space
glm::vec2 position;
/// Font number
int font;
/// Font size
int size;
/// Background colour (or, if a == 0, shadow offset)
glm::u8vec4 colourBG;
/// Foreground colour
glm::u8vec3 colourFG;
/// Alignment (left = 0, center = 1, right = 2)
unsigned char alignment;
/// Onscreen duration
int durationMS;
/// The amount of time onscreen so far
int displayedMS;
/// Wrap width
int wrapX;
/// ID used to reference the text.
GameStringKey id;
static ScreenTextEntry makeBig(const GameStringKey& id,
const GameString& str,
int style,
int durationMS);
static ScreenTextEntry makeBig(const GameStringKey& id,
const GameString& str, int style,
int durationMS);
static ScreenTextEntry makeHighPriority(const GameStringKey& id,
const GameString& str,
int durationMS);
static ScreenTextEntry makeHighPriority(const GameStringKey& id,
const GameString& str,
int durationMS);
static ScreenTextEntry makeHelp(const GameStringKey& id,
const GameString& str);
static ScreenTextEntry makeHelp(const GameStringKey& id,
const GameString& str);
};
/**
@ -88,74 +86,69 @@ 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>;
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
///
void tick(float dt);
///
/// \brief tick Apply display and fading rules to the text
/// \param dt
///
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...));
}
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...));
}
template <ScreenTextType Q>
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>
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");
m_textQueues[static_cast<size_t>(Q)].clear();
}
template <ScreenTextType Q>
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");
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());
}
template <ScreenTextType Q>
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()
);
}
const EntryQueues& getAllText() const {
return m_textQueues;
}
const EntryQueues& getAllText() const
{
return m_textQueues;
}
template<class...Args>
static GameString format(GameString format, Args&&...args)
{
static auto kReplacementMarker = GameStringUtil::fromString("~1~");
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())
{
format = format.substr(0, x) + vals[val++] + format.substr(x + 3);
}
return format;
}
template <class... Args>
static GameString format(GameString format, Args&&... args) {
static auto kReplacementMarker = GameStringUtil::fromString("~1~");
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()) {
format = format.substr(0, x) + vals[val++] + format.substr(x + 3);
}
return format;
}
private:
EntryQueues m_textQueues;
EntryQueues m_textQueues;
};
#endif