mirror of
https://github.com/rwengine/openrw.git
synced 2024-09-15 15:02:34 +02:00
Initial Save + Load implementation
* Fix VM Global Addressing * Modify VM structures to simplify storage * Add explicit GameWorld::createPlayer() method * Move gameTime to GameState for storage * Add SaveGame class for reading + writing * New Dependancy: cereal
This commit is contained in:
parent
d6eaf6e1f9
commit
91065b6af4
@ -74,7 +74,7 @@ struct VehicleGenerator
|
|||||||
struct BlipData
|
struct BlipData
|
||||||
{
|
{
|
||||||
int id;
|
int id;
|
||||||
GameObject* target;
|
GameObjectID target;
|
||||||
// If target is null then use coord
|
// If target is null then use coord
|
||||||
glm::vec3 coord;
|
glm::vec3 coord;
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ struct BlipData
|
|||||||
DisplayMode display;
|
DisplayMode display;
|
||||||
|
|
||||||
BlipData()
|
BlipData()
|
||||||
: id(-1), target(nullptr), display(Show)
|
: id(-1), target(0), display(Show)
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -102,6 +102,10 @@ struct BlipData
|
|||||||
*/
|
*/
|
||||||
struct GameState
|
struct GameState
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Second since game was started
|
||||||
|
*/
|
||||||
|
float gameTime;
|
||||||
unsigned int currentProgress;
|
unsigned int currentProgress;
|
||||||
unsigned int maxProgress;
|
unsigned int maxProgress;
|
||||||
unsigned int numMissions;
|
unsigned int numMissions;
|
||||||
@ -110,7 +114,6 @@ struct GameState
|
|||||||
unsigned int numUniqueJumps;
|
unsigned int numUniqueJumps;
|
||||||
unsigned int numRampages;
|
unsigned int numRampages;
|
||||||
unsigned int maxWantedLevel;
|
unsigned int maxWantedLevel;
|
||||||
PlayerController* player;
|
|
||||||
GameObjectID playerObject;
|
GameObjectID playerObject;
|
||||||
|
|
||||||
unsigned int currentWeather;
|
unsigned int currentWeather;
|
||||||
|
@ -89,12 +89,17 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Creates a vehicle
|
* Creates a vehicle
|
||||||
*/
|
*/
|
||||||
VehicleObject *createVehicle(const uint16_t id, const glm::vec3& pos, const glm::quat& rot = glm::quat());
|
VehicleObject *createVehicle(const uint16_t id, const glm::vec3& pos, const glm::quat& rot = glm::quat(), GameObjectID gid = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a pedestrian.
|
* Creates a pedestrian.
|
||||||
*/
|
*/
|
||||||
CharacterObject* createPedestrian(const uint16_t id, const glm::vec3& pos, const glm::quat& rot = glm::quat());
|
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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts the given game object into the world.
|
* Inserts the given game object into the world.
|
||||||
@ -147,12 +152,9 @@ public:
|
|||||||
int getMinute();
|
int getMinute();
|
||||||
|
|
||||||
glm::vec3 getGroundAtPosition(const glm::vec3& pos) const;
|
glm::vec3 getGroundAtPosition(const glm::vec3& pos) const;
|
||||||
|
|
||||||
/**
|
float getGameTime() const;
|
||||||
* Game Clock
|
|
||||||
*/
|
|
||||||
float gameTime;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Game data
|
* Game data
|
||||||
*/
|
*/
|
||||||
|
33
rwengine/include/engine/SaveGame.hpp
Normal file
33
rwengine/include/engine/SaveGame.hpp
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef _SAVEGAME_HPP_
|
||||||
|
#define _SAVEGAME_HPP_
|
||||||
|
|
||||||
|
#include <engine/RWTypes.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct GameState;
|
||||||
|
class GameWorld;
|
||||||
|
class ScriptMachine;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads and Writes GameStates to disk, restoring the required state information
|
||||||
|
*/
|
||||||
|
class SaveGame
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static void writeState(GameState& state, const std::string& file);
|
||||||
|
|
||||||
|
static bool loadState(GameState& state, const std::string& file);
|
||||||
|
|
||||||
|
static void writeScript(ScriptMachine& sm, const std::string& file);
|
||||||
|
|
||||||
|
static bool loadScript(ScriptMachine&, const std::string& file);
|
||||||
|
|
||||||
|
static void writeObjects(GameWorld& world, const std::string& file);
|
||||||
|
|
||||||
|
static bool loadObjects(GameWorld& world, const std::string& file);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -59,7 +59,7 @@ public:
|
|||||||
bool visible;
|
bool visible;
|
||||||
|
|
||||||
GameObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, ModelRef model)
|
GameObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, ModelRef model)
|
||||||
: _lastPosition(pos), _lastRotation(rot), objectID(-1), position(pos), rotation(rot),
|
: _lastPosition(pos), _lastRotation(rot), objectID(0), position(pos), rotation(rot),
|
||||||
model(model), engine(engine), animator(nullptr), skeleton(nullptr), mHealth(0.f),
|
model(model), engine(engine), animator(nullptr), skeleton(nullptr), mHealth(0.f),
|
||||||
inWater(false), _lastHeight(std::numeric_limits<float>::max()), visible(true),
|
inWater(false), _lastHeight(std::numeric_limits<float>::max()), visible(true),
|
||||||
lifetime(GameObject::UnknownLifetime)
|
lifetime(GameObject::UnknownLifetime)
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
@ -16,6 +17,7 @@
|
|||||||
* Changing this will break saves.
|
* Changing this will break saves.
|
||||||
*/
|
*/
|
||||||
#define SCM_VARIABLE_SIZE 4
|
#define SCM_VARIABLE_SIZE 4
|
||||||
|
#define SCM_STACK_DEPTH 32
|
||||||
|
|
||||||
class GameState;
|
class GameState;
|
||||||
|
|
||||||
@ -111,7 +113,7 @@ struct SCMThread
|
|||||||
{
|
{
|
||||||
typedef unsigned int pc_t;
|
typedef unsigned int pc_t;
|
||||||
|
|
||||||
std::string name;
|
char name[17];
|
||||||
pc_t baseAddress;
|
pc_t baseAddress;
|
||||||
pc_t programCounter;
|
pc_t programCounter;
|
||||||
|
|
||||||
@ -122,13 +124,14 @@ struct SCMThread
|
|||||||
|
|
||||||
/** Number of MS until the thread should be waked (-1 = yeilded) */
|
/** Number of MS until the thread should be waked (-1 = yeilded) */
|
||||||
int wakeCounter;
|
int wakeCounter;
|
||||||
SCMByte locals[SCM_THREAD_LOCAL_SIZE * (SCM_VARIABLE_SIZE)];
|
std::array<SCMByte, SCM_THREAD_LOCAL_SIZE * (SCM_VARIABLE_SIZE)> locals;
|
||||||
bool isMission;
|
bool isMission;
|
||||||
|
|
||||||
bool finished;
|
bool finished;
|
||||||
|
|
||||||
|
unsigned int stackDepth;
|
||||||
/// Stores the return-addresses for calls.
|
/// Stores the return-addresses for calls.
|
||||||
std::stack<pc_t> calls;
|
std::array<pc_t, SCM_STACK_DEPTH> calls;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -176,6 +179,7 @@ public:
|
|||||||
std::vector<SCMThread>& getThreads() { return _activeThreads; }
|
std::vector<SCMThread>& getThreads() { return _activeThreads; }
|
||||||
|
|
||||||
SCMByte* getGlobals();
|
SCMByte* getGlobals();
|
||||||
|
std::vector<SCMByte>& getGlobalData() { return globalData; }
|
||||||
|
|
||||||
GameState* getState() const { return state; }
|
GameState* getState() const { return state; }
|
||||||
|
|
||||||
@ -215,7 +219,7 @@ private:
|
|||||||
|
|
||||||
void executeThread(SCMThread& t, int msPassed);
|
void executeThread(SCMThread& t, int msPassed);
|
||||||
|
|
||||||
SCMByte* _globals;
|
std::vector<SCMByte> globalData;
|
||||||
|
|
||||||
BreakpointHandler bpHandler;
|
BreakpointHandler bpHandler;
|
||||||
std::set<SCMThread::pc_t> breakpoints;
|
std::set<SCMThread::pc_t> breakpoints;
|
||||||
|
@ -593,7 +593,7 @@ int GameData::getWaterIndexAt(const glm::vec3 &ws) const
|
|||||||
|
|
||||||
float GameData::getWaveHeightAt(const glm::vec3 &ws) const
|
float GameData::getWaveHeightAt(const glm::vec3 &ws) const
|
||||||
{
|
{
|
||||||
return (1+sin(engine->gameTime + (ws.x + ws.y) * WATER_SCALE)) * WATER_HEIGHT;
|
return (1+sin(engine->getGameTime() + (ws.x + ws.y) * WATER_SCALE)) * WATER_HEIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameData::isValidGameDirectory(const std::string& path)
|
bool GameData::isValidGameDirectory(const std::string& path)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <engine/GameState.hpp>
|
#include <engine/GameState.hpp>
|
||||||
|
|
||||||
GameState::GameState() :
|
GameState::GameState() :
|
||||||
|
gameTime(0.f),
|
||||||
currentProgress(0),
|
currentProgress(0),
|
||||||
maxProgress(1),
|
maxProgress(1),
|
||||||
numMissions(0),
|
numMissions(0),
|
||||||
@ -9,7 +10,6 @@ numHiddenPackagesDiscovered(0),
|
|||||||
numUniqueJumps(0),
|
numUniqueJumps(0),
|
||||||
numRampages(0),
|
numRampages(0),
|
||||||
maxWantedLevel(0),
|
maxWantedLevel(0),
|
||||||
player(nullptr),
|
|
||||||
currentWeather(0),
|
currentWeather(0),
|
||||||
scriptOnMissionFlag(nullptr),
|
scriptOnMissionFlag(nullptr),
|
||||||
fadeOut(true),
|
fadeOut(true),
|
||||||
|
@ -76,7 +76,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
GameWorld::GameWorld(Logger* log, WorkContext* work, GameData* dat)
|
GameWorld::GameWorld(Logger* log, WorkContext* work, GameData* dat)
|
||||||
: logger(log), gameTime(0.f), data(dat), randomEngine(rand()),
|
: logger(log), data(dat), randomEngine(rand()),
|
||||||
_work( work ), cutsceneAudio(nullptr), missionAudio(nullptr),
|
_work( work ), cutsceneAudio(nullptr), missionAudio(nullptr),
|
||||||
paused(false)
|
paused(false)
|
||||||
{
|
{
|
||||||
@ -277,7 +277,11 @@ CutsceneObject *GameWorld::createCutsceneObject(const uint16_t id, const glm::ve
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( id == 0 ) {
|
if( id == 0 ) {
|
||||||
modelname = state->player->getCharacter()->model->name;
|
auto playerobj = findObject(state->playerObject);
|
||||||
|
if( playerobj )
|
||||||
|
{
|
||||||
|
modelname = playerobj->model->name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the relevant data is loaded.
|
// Ensure the relevant data is loaded.
|
||||||
@ -308,7 +312,7 @@ CutsceneObject *GameWorld::createCutsceneObject(const uint16_t id, const glm::ve
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
VehicleObject *GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos, const glm::quat& rot)
|
VehicleObject *GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos, const glm::quat& rot, GameObjectID gid)
|
||||||
{
|
{
|
||||||
auto vti = data->findObjectType<VehicleData>(id);
|
auto vti = data->findObjectType<VehicleData>(id);
|
||||||
if( vti ) {
|
if( vti ) {
|
||||||
@ -365,6 +369,7 @@ VehicleObject *GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos,
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto vehicle = new VehicleObject{ this, pos, rot, m, vti, info->second, prim, sec };
|
auto vehicle = new VehicleObject{ this, pos, rot, m, vti, info->second, prim, sec };
|
||||||
|
vehicle->setGameObjectID(gid);
|
||||||
|
|
||||||
insertObject( vehicle );
|
insertObject( vehicle );
|
||||||
|
|
||||||
@ -373,7 +378,7 @@ VehicleObject *GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
CharacterObject* GameWorld::createPedestrian(const uint16_t id, const glm::vec3 &pos, const glm::quat& rot)
|
CharacterObject* GameWorld::createPedestrian(const uint16_t id, const glm::vec3& pos, const glm::quat& rot, GameObjectID gid)
|
||||||
{
|
{
|
||||||
auto pt = data->findObjectType<CharacterData>(id);
|
auto pt = data->findObjectType<CharacterData>(id);
|
||||||
if( pt ) {
|
if( pt ) {
|
||||||
@ -405,6 +410,7 @@ CharacterObject* GameWorld::createPedestrian(const uint16_t id, const glm::vec3
|
|||||||
|
|
||||||
if(m && m->resource) {
|
if(m && m->resource) {
|
||||||
auto ped = new CharacterObject( this, pos, rot, m, pt );
|
auto ped = new CharacterObject( this, pos, rot, m, pt );
|
||||||
|
ped->setGameObjectID(gid);
|
||||||
insertObject(ped);
|
insertObject(ped);
|
||||||
characters.insert(ped);
|
characters.insert(ped);
|
||||||
new DefaultAIController(ped);
|
new DefaultAIController(ped);
|
||||||
@ -414,17 +420,48 @@ CharacterObject* GameWorld::createPedestrian(const uint16_t id, const glm::vec3
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CharacterObject* GameWorld::createPlayer(const glm::vec3& pos, const glm::quat& rot, GameObjectID gid)
|
||||||
|
{
|
||||||
|
// Player object ID is hardcoded to 0.
|
||||||
|
auto pt = data->findObjectType<CharacterData>(0);
|
||||||
|
if( pt ) {
|
||||||
|
// Model name is also hardcoded.
|
||||||
|
std::string modelname = "player";
|
||||||
|
std::string texturename = "player";
|
||||||
|
|
||||||
|
// Ensure the relevant data is loaded.
|
||||||
|
data->loadDFF(modelname + ".dff");
|
||||||
|
data->loadTXD(texturename + ".txd");
|
||||||
|
|
||||||
|
ModelRef m = data->models[modelname];
|
||||||
|
|
||||||
|
if(m && m->resource) {
|
||||||
|
auto ped = new CharacterObject( this, pos, rot, m, nullptr );
|
||||||
|
ped->setGameObjectID(gid);
|
||||||
|
ped->setLifetime(GameObject::PlayerLifetime);
|
||||||
|
insertObject(ped);
|
||||||
|
characters.insert(ped);
|
||||||
|
new PlayerController(ped);
|
||||||
|
return ped;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void GameWorld::insertObject(GameObject* object)
|
void GameWorld::insertObject(GameObject* object)
|
||||||
{
|
{
|
||||||
// Find the lowest free GameObjectID.
|
if( object->getGameObjectID() == 0 )
|
||||||
GameObjectID availID = 1;
|
|
||||||
for( auto& p : objects )
|
|
||||||
{
|
{
|
||||||
if( p.first == availID ) availID++;
|
// Find the lowest free GameObjectID.
|
||||||
}
|
GameObjectID availID = 1;
|
||||||
|
for( auto& p : objects )
|
||||||
|
{
|
||||||
|
if( p.first == availID ) availID++;
|
||||||
|
}
|
||||||
|
|
||||||
object->setGameObjectID( availID );
|
object->setGameObjectID( availID );
|
||||||
objects[availID] = object;
|
}
|
||||||
|
objects[object->getGameObjectID()] = object;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameObject* GameWorld::findObject(GameObjectID id) const
|
GameObject* GameWorld::findObject(GameObjectID id) const
|
||||||
@ -582,6 +619,11 @@ glm::vec3 GameWorld::getGroundAtPosition(const glm::vec3 &pos) const
|
|||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float GameWorld::getGameTime() const
|
||||||
|
{
|
||||||
|
return state->gameTime;
|
||||||
|
}
|
||||||
|
|
||||||
void handleVehicleResponse(GameObject* object, btManifoldPoint& mp, bool isA)
|
void handleVehicleResponse(GameObject* object, btManifoldPoint& mp, bool isA)
|
||||||
{
|
{
|
||||||
bool isVehicle = object->type() == GameObject::Vehicle;
|
bool isVehicle = object->type() == GameObject::Vehicle;
|
||||||
@ -720,7 +762,7 @@ void GameWorld::loadCutscene(const std::string &name)
|
|||||||
|
|
||||||
void GameWorld::startCutscene()
|
void GameWorld::startCutscene()
|
||||||
{
|
{
|
||||||
state->cutsceneStartTime = gameTime;
|
state->cutsceneStartTime = getGameTime();
|
||||||
state->skipCutscene = false;
|
state->skipCutscene = false;
|
||||||
if( cutsceneAudio ) {
|
if( cutsceneAudio ) {
|
||||||
cutsceneAudio->play();
|
cutsceneAudio->play();
|
||||||
@ -752,7 +794,7 @@ void GameWorld::clearCutscene()
|
|||||||
bool GameWorld::isCutsceneDone()
|
bool GameWorld::isCutsceneDone()
|
||||||
{
|
{
|
||||||
if( state->currentCutscene ) {
|
if( state->currentCutscene ) {
|
||||||
float time = gameTime - state->cutsceneStartTime;
|
float time = getGameTime() - state->cutsceneStartTime;
|
||||||
if( state->skipCutscene ) {
|
if( state->skipCutscene ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
315
rwengine/src/engine/SaveGame.cpp
Normal file
315
rwengine/src/engine/SaveGame.cpp
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
#include <engine/SaveGame.hpp>
|
||||||
|
#include <engine/GameState.hpp>
|
||||||
|
#include <engine/GameWorld.hpp>
|
||||||
|
#include <objects/GameObject.hpp>
|
||||||
|
#include <objects/VehicleObject.hpp>
|
||||||
|
#include <objects/CharacterObject.hpp>
|
||||||
|
#include <script/ScriptMachine.hpp>
|
||||||
|
#include <script/SCMFile.hpp>
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <cereal/cereal.hpp>
|
||||||
|
#include <cereal/archives/json.hpp>
|
||||||
|
#include <cereal/types/vector.hpp>
|
||||||
|
#include <cereal/types/array.hpp>
|
||||||
|
#include <cereal/types/map.hpp>
|
||||||
|
|
||||||
|
namespace cereal
|
||||||
|
{
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive& archive,
|
||||||
|
glm::vec3& s)
|
||||||
|
{
|
||||||
|
archive(s.x, s.y, s.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive& archive,
|
||||||
|
glm::vec4& s)
|
||||||
|
{
|
||||||
|
archive(s.x, s.y, s.z, s.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive& archive,
|
||||||
|
glm::u16vec3& s)
|
||||||
|
{
|
||||||
|
archive(s.x, s.y, s.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive& archive,
|
||||||
|
glm::quat& s)
|
||||||
|
{
|
||||||
|
archive(s.x, s.y, s.z, s.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive& archive,
|
||||||
|
OnscreenText& t)
|
||||||
|
{
|
||||||
|
archive(
|
||||||
|
t.id,
|
||||||
|
t.osTextString,
|
||||||
|
t.osTextStart,
|
||||||
|
t.osTextTime,
|
||||||
|
t.osTextStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive& archive,
|
||||||
|
VehicleGenerator& s)
|
||||||
|
{
|
||||||
|
archive(
|
||||||
|
s.position,
|
||||||
|
s.heading,
|
||||||
|
s.vehicleID,
|
||||||
|
s.colourFG,
|
||||||
|
s.colourBG,
|
||||||
|
s.alwaysSpawn,
|
||||||
|
s.alarmThreshold,
|
||||||
|
s.lockedThreshold,
|
||||||
|
s.minDelay,
|
||||||
|
s.maxDelay,
|
||||||
|
s.lastSpawnTime,
|
||||||
|
s.remainingSpawns);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive& archive,
|
||||||
|
BlipData& s)
|
||||||
|
{
|
||||||
|
archive(
|
||||||
|
s.id,
|
||||||
|
s.target,
|
||||||
|
s.coord,
|
||||||
|
s.texture,
|
||||||
|
s.display);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive& archive,
|
||||||
|
GameState& s)
|
||||||
|
{
|
||||||
|
archive(
|
||||||
|
s.gameTime,
|
||||||
|
s.currentProgress,
|
||||||
|
s.maxProgress,
|
||||||
|
s.numMissions,
|
||||||
|
s.numHiddenPackages,
|
||||||
|
s.numHiddenPackagesDiscovered,
|
||||||
|
s.numUniqueJumps,
|
||||||
|
s.numRampages,
|
||||||
|
s.maxWantedLevel,
|
||||||
|
s.playerObject,
|
||||||
|
s.currentWeather,
|
||||||
|
s.missionObjects,
|
||||||
|
s.overrideNextStart,
|
||||||
|
s.nextRestartLocation,
|
||||||
|
s.fadeOut,
|
||||||
|
s.fadeStart,
|
||||||
|
s.fadeTime,
|
||||||
|
s.fadeSound,
|
||||||
|
s.fadeColour,
|
||||||
|
s.currentSplash,
|
||||||
|
s.skipCutscene,
|
||||||
|
s.isIntroPlaying,
|
||||||
|
s.isCinematic,
|
||||||
|
s.hour,
|
||||||
|
s.minute,
|
||||||
|
s.lastMissionName,
|
||||||
|
s.specialCharacters,
|
||||||
|
s.specialModels,
|
||||||
|
s.text,
|
||||||
|
s.cameraNear,
|
||||||
|
s.cameraFixed,
|
||||||
|
s.cameraPosition,
|
||||||
|
s.cameraRotation,
|
||||||
|
s.cameraTarget,
|
||||||
|
s.vehicleGenerators,
|
||||||
|
s.radarBlips);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive& archive,
|
||||||
|
SCMThread& s)
|
||||||
|
{
|
||||||
|
archive(
|
||||||
|
s.name,
|
||||||
|
s.baseAddress,
|
||||||
|
s.programCounter,
|
||||||
|
s.conditionCount,
|
||||||
|
s.conditionResult,
|
||||||
|
s.conditionMask,
|
||||||
|
s.conditionAND,
|
||||||
|
s.wakeCounter,
|
||||||
|
s.locals,
|
||||||
|
s.isMission,
|
||||||
|
s.finished,
|
||||||
|
s.stackDepth,
|
||||||
|
s.calls);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive& archive,
|
||||||
|
ScriptMachine& s)
|
||||||
|
{
|
||||||
|
archive(
|
||||||
|
s.getThreads(),
|
||||||
|
s.getGlobalData());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveGame::writeState(GameState& state, const std::string& file)
|
||||||
|
{
|
||||||
|
std::ofstream os(file.c_str());
|
||||||
|
|
||||||
|
{
|
||||||
|
cereal::JSONOutputArchive oa(os);
|
||||||
|
|
||||||
|
oa(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SaveGame::loadState(GameState& state, const std::string& file)
|
||||||
|
{
|
||||||
|
std::ifstream is(file.c_str());
|
||||||
|
|
||||||
|
{
|
||||||
|
cereal::JSONInputArchive ia(is);
|
||||||
|
|
||||||
|
ia(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveGame::writeScript(ScriptMachine& sm, const std::string& file)
|
||||||
|
{
|
||||||
|
std::ofstream os(file.c_str());
|
||||||
|
|
||||||
|
{
|
||||||
|
cereal::JSONOutputArchive oa(os);
|
||||||
|
|
||||||
|
oa(sm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SaveGame::loadScript(ScriptMachine& sm, const std::string& file)
|
||||||
|
{
|
||||||
|
std::ifstream is(file.c_str());
|
||||||
|
|
||||||
|
{
|
||||||
|
cereal::JSONInputArchive ia(is);
|
||||||
|
|
||||||
|
ia(sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveGame::writeObjects(GameWorld& world, const std::string& file)
|
||||||
|
{
|
||||||
|
std::ofstream os(file.c_str());
|
||||||
|
|
||||||
|
{
|
||||||
|
cereal::JSONOutputArchive oa(os);
|
||||||
|
|
||||||
|
std::vector<GameObject*> writeable;
|
||||||
|
for( auto& p : world.objects )
|
||||||
|
{
|
||||||
|
switch( p.second->type() )
|
||||||
|
{
|
||||||
|
case GameObject::Vehicle:
|
||||||
|
case GameObject::Character:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if( p.second->getLifetime() == GameObject::TrafficLifetime )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
writeable.push_back(p.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write object count.
|
||||||
|
oa(writeable.size());
|
||||||
|
for( GameObject* saved : writeable )
|
||||||
|
{
|
||||||
|
oa(saved->getGameObjectID());
|
||||||
|
oa(saved->type());
|
||||||
|
oa(saved->getLifetime());
|
||||||
|
oa(saved->getPosition());
|
||||||
|
oa(saved->getRotation());
|
||||||
|
switch( saved->type() )
|
||||||
|
{
|
||||||
|
case GameObject::Vehicle:
|
||||||
|
{
|
||||||
|
auto vehicle = static_cast<VehicleObject*>(saved);
|
||||||
|
oa(vehicle->vehicle->ID);
|
||||||
|
} break;
|
||||||
|
case GameObject::Character:
|
||||||
|
{
|
||||||
|
auto character = static_cast<CharacterObject*>(saved);
|
||||||
|
oa(character->ped->ID);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool SaveGame::loadObjects(GameWorld& world, const std::string& file)
|
||||||
|
{
|
||||||
|
std::ifstream is(file.c_str());
|
||||||
|
|
||||||
|
{
|
||||||
|
cereal::JSONInputArchive ia(is);
|
||||||
|
|
||||||
|
std::size_t num;
|
||||||
|
ia(num);
|
||||||
|
for(int i = 0; i < num; i++)
|
||||||
|
{
|
||||||
|
GameObjectID gameID;
|
||||||
|
GameObject::Type type;
|
||||||
|
GameObject::ObjectLifetime lifetime;
|
||||||
|
glm::vec3 translation;
|
||||||
|
glm::quat orientation;
|
||||||
|
|
||||||
|
ia(gameID);
|
||||||
|
ia(type);
|
||||||
|
ia(lifetime);
|
||||||
|
ia(translation);
|
||||||
|
ia(orientation);
|
||||||
|
|
||||||
|
switch( type )
|
||||||
|
{
|
||||||
|
case GameObject::Vehicle:
|
||||||
|
{
|
||||||
|
ObjectID id;
|
||||||
|
ia(id);
|
||||||
|
auto vehicle = world.createVehicle(id, translation, orientation, gameID);
|
||||||
|
vehicle->setLifetime(lifetime);
|
||||||
|
} break;
|
||||||
|
case GameObject::Character:
|
||||||
|
{
|
||||||
|
ObjectID id;
|
||||||
|
ia(id);
|
||||||
|
CharacterObject* character;
|
||||||
|
if( lifetime == GameObject::PlayerLifetime )
|
||||||
|
{
|
||||||
|
character = world.createPlayer(translation, orientation, gameID);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
character = world.createPedestrian(id, translation, orientation, gameID);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
@ -105,7 +105,7 @@ void WeaponItem::fireProjectile()
|
|||||||
// Work out the velocity multiplier as a function of how long the player
|
// Work out the velocity multiplier as a function of how long the player
|
||||||
// Was holding down the fire button. If _fireStop < 0.f then the player
|
// Was holding down the fire button. If _fireStop < 0.f then the player
|
||||||
// is still holding the button down.
|
// is still holding the button down.
|
||||||
float throwTime = _character->engine->gameTime - _fireStart;
|
float throwTime = _character->engine->getGameTime() - _fireStart;
|
||||||
float forceFactor = throwTime;
|
float forceFactor = throwTime;
|
||||||
if( _fireStop > 0.f ) {
|
if( _fireStop > 0.f ) {
|
||||||
forceFactor = _fireStop - _fireStart;
|
forceFactor = _fireStop - _fireStart;
|
||||||
@ -128,14 +128,14 @@ void WeaponItem::primary(bool active)
|
|||||||
{
|
{
|
||||||
_firing = active;
|
_firing = active;
|
||||||
if( active ) {
|
if( active ) {
|
||||||
_fireStart = _character->engine->gameTime;
|
_fireStart = _character->engine->getGameTime();
|
||||||
_fireStop = -1.f;
|
_fireStop = -1.f;
|
||||||
|
|
||||||
// ShootWeapon will call ::fire() on us at the appropriate time.
|
// ShootWeapon will call ::fire() on us at the appropriate time.
|
||||||
_character->controller->setNextActivity(new Activities::ShootWeapon(this));
|
_character->controller->setNextActivity(new Activities::ShootWeapon(this));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_fireStop = _character->engine->gameTime;
|
_fireStop = _character->engine->getGameTime();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ void ProjectileObject::explode()
|
|||||||
auto explosion = engine->createEffect(VisualFX::Particle);
|
auto explosion = engine->createEffect(VisualFX::Particle);
|
||||||
explosion->particle.size = glm::vec2(exp_size);
|
explosion->particle.size = glm::vec2(exp_size);
|
||||||
explosion->particle.texture = tex;
|
explosion->particle.texture = tex;
|
||||||
explosion->particle.starttime = engine->gameTime;
|
explosion->particle.starttime = engine->getGameTime();
|
||||||
explosion->particle.lifetime = 0.5f;
|
explosion->particle.lifetime = 0.5f;
|
||||||
explosion->particle.orientation = VisualFX::ParticleData::Camera;
|
explosion->particle.orientation = VisualFX::ParticleData::Camera;
|
||||||
explosion->particle.colour = glm::vec4(1.0f);
|
explosion->particle.colour = glm::vec4(1.0f);
|
||||||
|
@ -388,16 +388,20 @@ void GameRenderer::renderWorld(GameWorld* world, const ViewCamera &camera, float
|
|||||||
{
|
{
|
||||||
glm::mat4 model;
|
glm::mat4 model;
|
||||||
|
|
||||||
if( blip.second.target )
|
if( blip.second.target > 0 )
|
||||||
{
|
{
|
||||||
model = blip.second.target->getTimeAdjustedTransform( _renderAlpha );
|
auto object = world->findObject(blip.second.target);
|
||||||
|
if( object )
|
||||||
|
{
|
||||||
|
model = object->getTimeAdjustedTransform( _renderAlpha );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
model = glm::translate( model, blip.second.coord );
|
model = glm::translate( model, blip.second.coord );
|
||||||
}
|
}
|
||||||
|
|
||||||
float a = world->gameTime * glm::pi<float>();
|
float a = world->getGameTime() * glm::pi<float>();
|
||||||
model = glm::translate( model, glm::vec3(0.f, 0.f, 2.5f + glm::sin( a ) * 0.5f) );
|
model = glm::translate( model, glm::vec3(0.f, 0.f, 2.5f + glm::sin( a ) * 0.5f) );
|
||||||
model = glm::rotate( model, a, glm::vec3(0.f, 0.f, 1.f) );
|
model = glm::rotate( model, a, glm::vec3(0.f, 0.f, 1.f) );
|
||||||
model = glm::scale( model, glm::vec3(1.5f, 1.5f, 1.5f) );
|
model = glm::scale( model, glm::vec3(1.5f, 1.5f, 1.5f) );
|
||||||
@ -470,7 +474,7 @@ void GameRenderer::renderWorld(GameWorld* world, const ViewCamera &camera, float
|
|||||||
renderLetterbox();
|
renderLetterbox();
|
||||||
}
|
}
|
||||||
|
|
||||||
float fadeTimer = world->gameTime - world->state->fadeStart;
|
float fadeTimer = world->getGameTime() - world->state->fadeStart;
|
||||||
if( fadeTimer < world->state->fadeTime || !world->state->fadeOut ) {
|
if( fadeTimer < world->state->fadeTime || !world->state->fadeOut ) {
|
||||||
glUseProgram(ssRectProgram);
|
glUseProgram(ssRectProgram);
|
||||||
glUniform2f(ssRectOffset, 0.f, 0.f);
|
glUniform2f(ssRectOffset, 0.f, 0.f);
|
||||||
@ -706,7 +710,7 @@ void GameRenderer::renderPickup(PickupObject *pickup)
|
|||||||
if( ! pickup->isEnabled() ) return;
|
if( ! pickup->isEnabled() ) return;
|
||||||
|
|
||||||
glm::mat4 modelMatrix = glm::translate(glm::mat4(), pickup->getPosition());
|
glm::mat4 modelMatrix = glm::translate(glm::mat4(), pickup->getPosition());
|
||||||
modelMatrix = glm::rotate(modelMatrix, _renderWorld->gameTime, glm::vec3(0.f, 0.f, 1.f));
|
modelMatrix = glm::rotate(modelMatrix, _renderWorld->getGameTime(), glm::vec3(0.f, 0.f, 1.f));
|
||||||
|
|
||||||
auto odata = data->findObjectType<ObjectData>(pickup->getModelID());
|
auto odata = data->findObjectType<ObjectData>(pickup->getModelID());
|
||||||
|
|
||||||
@ -938,7 +942,7 @@ void GameRenderer::renderAreaIndicator(const AreaIndicatorInfo* info)
|
|||||||
{
|
{
|
||||||
glm::mat4 m(1.f);
|
glm::mat4 m(1.f);
|
||||||
m = glm::translate(m, info->position);
|
m = glm::translate(m, info->position);
|
||||||
glm::vec3 scale = info->radius + 0.15f * glm::sin(_renderWorld->gameTime * 5.f);
|
glm::vec3 scale = info->radius + 0.15f * glm::sin(_renderWorld->getGameTime() * 5.f);
|
||||||
|
|
||||||
Renderer::DrawParameters dp;
|
Renderer::DrawParameters dp;
|
||||||
dp.textures = {data->findTexture("cloud1")->getName()};
|
dp.textures = {data->findTexture("cloud1")->getName()};
|
||||||
@ -954,7 +958,7 @@ void GameRenderer::renderAreaIndicator(const AreaIndicatorInfo* info)
|
|||||||
glm::vec3 final = scale * glm::pow(0.9f, i + 1.0f);
|
glm::vec3 final = scale * glm::pow(0.9f, i + 1.0f);
|
||||||
mt = glm::scale(mt, glm::vec3(final.x, final.y, 1.0f + i * 0.1f));
|
mt = glm::scale(mt, glm::vec3(final.x, final.y, 1.0f + i * 0.1f));
|
||||||
int reverse = (i % 2 ? 1 : -1);
|
int reverse = (i % 2 ? 1 : -1);
|
||||||
mt = glm::rotate(mt, reverse * _renderWorld->gameTime * 0.5f, glm::vec3(0.f, 0.f, 1.f) );
|
mt = glm::rotate(mt, reverse * _renderWorld->getGameTime() * 0.5f, glm::vec3(0.f, 0.f, 1.f) );
|
||||||
|
|
||||||
renderer->drawArrays(mt, &cylinderBuffer, dp);
|
renderer->drawArrays(mt, &cylinderBuffer, dp);
|
||||||
}
|
}
|
||||||
|
@ -149,20 +149,24 @@ void MapRenderer::draw(GameWorld* world, const MapInfo& mi)
|
|||||||
for(auto& blip : world->state->radarBlips)
|
for(auto& blip : world->state->radarBlips)
|
||||||
{
|
{
|
||||||
glm::vec2 blippos( blip.second.coord );
|
glm::vec2 blippos( blip.second.coord );
|
||||||
if( blip.second.target )
|
if( blip.second.target > 0 )
|
||||||
{
|
{
|
||||||
blippos = glm::vec2( blip.second.target->getPosition() );
|
auto object = world->findObject(blip.second.target);
|
||||||
|
if( object )
|
||||||
|
{
|
||||||
|
blippos = glm::vec2( object->getPosition() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
drawBlip(blippos, model, mi, "");
|
drawBlip(blippos, model, mi, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the player blip
|
// Draw the player blip
|
||||||
auto player = world->state->player;
|
auto player = world->findObject(world->state->playerObject);
|
||||||
if( player )
|
if( player )
|
||||||
{
|
{
|
||||||
glm::vec2 plyblip(player->getCharacter()->getPosition());
|
glm::vec2 plyblip(player->getPosition());
|
||||||
float hdg = glm::roll(player->getCharacter()->getRotation());
|
float hdg = glm::roll(player->getRotation());
|
||||||
drawBlip(plyblip, model, mi, "radar_centre", hdg);
|
drawBlip(plyblip, model, mi, "radar_centre", hdg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ void WaterRenderer::render(GameRenderer* renderer, GameWorld* world)
|
|||||||
buffers[0] = GL_COLOR_ATTACHMENT0;
|
buffers[0] = GL_COLOR_ATTACHMENT0;
|
||||||
glDrawBuffers(1, buffers);
|
glDrawBuffers(1, buffers);
|
||||||
|
|
||||||
r->setUniform(waterProg, "time", world->gameTime);
|
r->setUniform(waterProg, "time", world->getGameTime());
|
||||||
r->setUniform(waterProg, "waveParams", glm::vec2(WATER_SCALE, WATER_HEIGHT));
|
r->setUniform(waterProg, "waveParams", glm::vec2(WATER_SCALE, WATER_HEIGHT));
|
||||||
auto ivp = glm::inverse(r->getSceneData().projection * r->getSceneData().view);
|
auto ivp = glm::inverse(r->getSceneData().projection * r->getSceneData().view);
|
||||||
r->setUniform(waterProg, "inverseVP", ivp);
|
r->setUniform(waterProg, "inverseVP", ivp);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <engine/GameState.hpp>
|
#include <engine/GameState.hpp>
|
||||||
#include <engine/GameWorld.hpp>
|
#include <engine/GameWorld.hpp>
|
||||||
#include <core/Logger.hpp>
|
#include <core/Logger.hpp>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
#if SCM_DEBUG_INSTRUCTIONS
|
#if SCM_DEBUG_INSTRUCTIONS
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -89,7 +90,7 @@ void ScriptMachine::executeThread(SCMThread &t, int msPassed)
|
|||||||
break;
|
break;
|
||||||
case TGlobal: {
|
case TGlobal: {
|
||||||
auto v = _file->read<std::uint16_t>(t.programCounter);
|
auto v = _file->read<std::uint16_t>(t.programCounter);
|
||||||
parameters.back().globalPtr = _globals + v; //* SCM_VARIABLE_SIZE;
|
parameters.back().globalPtr = globalData.data() + v; //* SCM_VARIABLE_SIZE;
|
||||||
if( v >= _file->getGlobalsSize() )
|
if( v >= _file->getGlobalsSize() )
|
||||||
{
|
{
|
||||||
state->world->logger->error("SCM", "Global Out of bounds! "+ std::to_string(v) + " " + std::to_string(_file->getGlobalsSize()));
|
state->world->logger->error("SCM", "Global Out of bounds! "+ std::to_string(v) + " " + std::to_string(_file->getGlobalsSize()));
|
||||||
@ -99,7 +100,7 @@ void ScriptMachine::executeThread(SCMThread &t, int msPassed)
|
|||||||
break;
|
break;
|
||||||
case TLocal: {
|
case TLocal: {
|
||||||
auto v = _file->read<std::uint16_t>(t.programCounter);
|
auto v = _file->read<std::uint16_t>(t.programCounter);
|
||||||
parameters.back().globalPtr = t.locals + v * SCM_VARIABLE_SIZE;
|
parameters.back().globalPtr = t.locals.data() + v * SCM_VARIABLE_SIZE;
|
||||||
if( v >= SCM_THREAD_LOCAL_SIZE )
|
if( v >= SCM_THREAD_LOCAL_SIZE )
|
||||||
{
|
{
|
||||||
state->world->logger->error("SCM", "Local Out of bounds!");
|
state->world->logger->error("SCM", "Local Out of bounds!");
|
||||||
@ -176,9 +177,9 @@ void ScriptMachine::executeThread(SCMThread &t, int msPassed)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SCMOpcodeParameter p;
|
SCMOpcodeParameter p;
|
||||||
p.globalPtr = (t.locals + 16 * sizeof ( SCMByte ) * 4);
|
p.globalPtr = (t.locals.data() + 16 * sizeof ( SCMByte ) * 4);
|
||||||
*p.globalInteger += msPassed;
|
*p.globalInteger += msPassed;
|
||||||
p.globalPtr = (t.locals + 17 * sizeof ( SCMByte ) * 4);
|
p.globalPtr = (t.locals.data() + 17 * sizeof ( SCMByte ) * 4);
|
||||||
*p.globalInteger += msPassed;
|
*p.globalInteger += msPassed;
|
||||||
|
|
||||||
if( t.wakeCounter == -1 ) {
|
if( t.wakeCounter == -1 ) {
|
||||||
@ -189,12 +190,11 @@ void ScriptMachine::executeThread(SCMThread &t, int msPassed)
|
|||||||
ScriptMachine::ScriptMachine(GameState* _state, SCMFile *file, SCMOpcodes *ops)
|
ScriptMachine::ScriptMachine(GameState* _state, SCMFile *file, SCMOpcodes *ops)
|
||||||
: _file(file), _ops(ops), state(_state)
|
: _file(file), _ops(ops), state(_state)
|
||||||
{
|
{
|
||||||
startThread(0);
|
|
||||||
auto globals = _file->getGlobalsSize();
|
auto globals = _file->getGlobalsSize();
|
||||||
_globals = new SCMByte[globals];
|
globalData.resize(globals);
|
||||||
for(int i = 0; i < globals; ++i)
|
for(int i = 0; i < globals; ++i)
|
||||||
{
|
{
|
||||||
_globals[i] = 0;
|
globalData[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,7 +202,6 @@ ScriptMachine::~ScriptMachine()
|
|||||||
{
|
{
|
||||||
delete _file;
|
delete _file;
|
||||||
delete _ops;
|
delete _ops;
|
||||||
delete[] _globals;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptMachine::startThread(SCMThread::pc_t start, bool mission)
|
void ScriptMachine::startThread(SCMThread::pc_t start, bool mission)
|
||||||
@ -211,7 +210,7 @@ void ScriptMachine::startThread(SCMThread::pc_t start, bool mission)
|
|||||||
for(int i = 0; i < SCM_THREAD_LOCAL_SIZE * SCM_VARIABLE_SIZE; ++i) {
|
for(int i = 0; i < SCM_THREAD_LOCAL_SIZE * SCM_VARIABLE_SIZE; ++i) {
|
||||||
t.locals[i] = 0;
|
t.locals[i] = 0;
|
||||||
}
|
}
|
||||||
t.name = "THREAD";
|
strncpy(t.name, "THREAD", 16);
|
||||||
t.conditionResult = false;
|
t.conditionResult = false;
|
||||||
t.conditionCount = 0;
|
t.conditionCount = 0;
|
||||||
t.conditionAND = false;
|
t.conditionAND = false;
|
||||||
@ -220,12 +219,13 @@ void ScriptMachine::startThread(SCMThread::pc_t start, bool mission)
|
|||||||
t.wakeCounter = 0;
|
t.wakeCounter = 0;
|
||||||
t.isMission = mission;
|
t.isMission = mission;
|
||||||
t.finished = false;
|
t.finished = false;
|
||||||
|
t.stackDepth = 0;
|
||||||
_activeThreads.push_back(t);
|
_activeThreads.push_back(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
SCMByte *ScriptMachine::getGlobals()
|
SCMByte *ScriptMachine::getGlobals()
|
||||||
{
|
{
|
||||||
return _file->data() + _file->getGlobalSection();
|
return globalData.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptMachine::execute(float dt)
|
void ScriptMachine::execute(float dt)
|
||||||
|
@ -33,7 +33,7 @@ void game_print_big(const ScriptArguments& args)
|
|||||||
args.getWorld()->state->text.push_back({
|
args.getWorld()->state->text.push_back({
|
||||||
id,
|
id,
|
||||||
str,
|
str,
|
||||||
args.getWorld()->gameTime,
|
args.getWorld()->getGameTime(),
|
||||||
args[1].integer / 1000.f,
|
args[1].integer / 1000.f,
|
||||||
style
|
style
|
||||||
});
|
});
|
||||||
@ -47,7 +47,7 @@ void game_print_now(const ScriptArguments& args)
|
|||||||
args.getWorld()->state->text.push_back({
|
args.getWorld()->state->text.push_back({
|
||||||
id,
|
id,
|
||||||
str,
|
str,
|
||||||
args.getWorld()->gameTime,
|
args.getWorld()->getGameTime(),
|
||||||
args[1].integer / 1000.f,
|
args[1].integer / 1000.f,
|
||||||
0
|
0
|
||||||
});
|
});
|
||||||
@ -225,7 +225,7 @@ void game_fade_screen(const ScriptArguments& args)
|
|||||||
{
|
{
|
||||||
args.getWorld()->state->fadeTime = args[0].integer / 1000.f;
|
args.getWorld()->state->fadeTime = args[0].integer / 1000.f;
|
||||||
args.getWorld()->state->fadeOut = !!args[1].integer;
|
args.getWorld()->state->fadeOut = !!args[1].integer;
|
||||||
args.getWorld()->state->fadeStart = args.getWorld()->gameTime;
|
args.getWorld()->state->fadeStart = args.getWorld()->getGameTime();
|
||||||
}
|
}
|
||||||
bool game_screen_fading(const ScriptArguments& args)
|
bool game_screen_fading(const ScriptArguments& args)
|
||||||
{
|
{
|
||||||
@ -233,7 +233,7 @@ bool game_screen_fading(const ScriptArguments& args)
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return args.getWorld()->gameTime <
|
return args.getWorld()->getGameTime() <
|
||||||
args.getWorld()->state->fadeStart + args.getWorld()->state->fadeTime;
|
args.getWorld()->state->fadeStart + args.getWorld()->state->fadeTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,7 +258,7 @@ void game_link_mission_flag(const ScriptArguments& args)
|
|||||||
void game_add_vehicle_blip(const ScriptArguments& args)
|
void game_add_vehicle_blip(const ScriptArguments& args)
|
||||||
{
|
{
|
||||||
BlipData data;
|
BlipData data;
|
||||||
data.target = args.getGameObject(0);
|
data.target = args.getGameObject(0)->getGameObjectID();
|
||||||
data.texture = "";
|
data.texture = "";
|
||||||
*args[1].globalInteger = args.getWorld()->state->addRadarBlip(data);
|
*args[1].globalInteger = args.getWorld()->state->addRadarBlip(data);
|
||||||
}
|
}
|
||||||
@ -266,7 +266,7 @@ void game_add_vehicle_blip(const ScriptArguments& args)
|
|||||||
void game_add_character_blip(const ScriptArguments& args)
|
void game_add_character_blip(const ScriptArguments& args)
|
||||||
{
|
{
|
||||||
BlipData data;
|
BlipData data;
|
||||||
data.target = args.getGameObject(0);
|
data.target = args.getGameObject(0)->getGameObjectID();
|
||||||
data.texture = "";
|
data.texture = "";
|
||||||
*args[1].globalInteger = args.getWorld()->state->addRadarBlip(data);
|
*args[1].globalInteger = args.getWorld()->state->addRadarBlip(data);
|
||||||
}
|
}
|
||||||
@ -274,7 +274,7 @@ void game_add_character_blip(const ScriptArguments& args)
|
|||||||
void game_add_pickup_blip(const ScriptArguments& args)
|
void game_add_pickup_blip(const ScriptArguments& args)
|
||||||
{
|
{
|
||||||
BlipData data;
|
BlipData data;
|
||||||
data.target = args.getGameObject(0);
|
data.target = args.getGameObject(0)->getGameObjectID();
|
||||||
data.texture = "";
|
data.texture = "";
|
||||||
*args[1].globalInteger = args.getWorld()->state->addRadarBlip(data);
|
*args[1].globalInteger = args.getWorld()->state->addRadarBlip(data);
|
||||||
}
|
}
|
||||||
@ -283,7 +283,7 @@ void game_add_pickup_blip(const ScriptArguments& args)
|
|||||||
void game_add_location_blip(const ScriptArguments& args)
|
void game_add_location_blip(const ScriptArguments& args)
|
||||||
{
|
{
|
||||||
BlipData data;
|
BlipData data;
|
||||||
data.target = nullptr;
|
data.target = 0;
|
||||||
data.coord = glm::vec3(args[0].real, args[1].real, args[2].real);
|
data.coord = glm::vec3(args[0].real, args[1].real, args[2].real);
|
||||||
data.texture = "";
|
data.texture = "";
|
||||||
*args[3].globalInteger = args.getWorld()->state->addRadarBlip(data);
|
*args[3].globalInteger = args.getWorld()->state->addRadarBlip(data);
|
||||||
@ -322,7 +322,7 @@ void game_set_weather(const ScriptArguments& args)
|
|||||||
|
|
||||||
void game_get_runtime(const ScriptArguments& args)
|
void game_get_runtime(const ScriptArguments& args)
|
||||||
{
|
{
|
||||||
*args[0].globalInteger = args.getWorld()->gameTime * 1000;
|
*args[0].globalInteger = args.getWorld()->getGameTime() * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
void game_print_big_with_number(const ScriptArguments& args)
|
void game_print_big_with_number(const ScriptArguments& args)
|
||||||
@ -338,7 +338,7 @@ void game_print_big_with_number(const ScriptArguments& args)
|
|||||||
args.getWorld()->state->text.push_back({
|
args.getWorld()->state->text.push_back({
|
||||||
id,
|
id,
|
||||||
str,
|
str,
|
||||||
args.getWorld()->gameTime,
|
args.getWorld()->getGameTime(),
|
||||||
args[2].integer / 1000.f,
|
args[2].integer / 1000.f,
|
||||||
style
|
style
|
||||||
});
|
});
|
||||||
@ -442,20 +442,21 @@ void game_restart_critical_mission(const ScriptArguments& args)
|
|||||||
// Reset player state.
|
// Reset player state.
|
||||||
glm::vec3 position(args[0].real, args[1].real, args[2].real + 1.f);
|
glm::vec3 position(args[0].real, args[1].real, args[2].real + 1.f);
|
||||||
|
|
||||||
auto controller = args.getWorld()->state->player;
|
auto object = args.getWorld()->findObject(args.getState()->playerObject);
|
||||||
|
auto player = static_cast<CharacterObject*>(object);
|
||||||
|
|
||||||
glm::vec3 spawnMagic( 0.f, 0.f, 1.f );
|
glm::vec3 spawnMagic( 0.f, 0.f, 1.f );
|
||||||
|
|
||||||
controller->getCharacter()->setPosition(position + spawnMagic);
|
player->setPosition(position + spawnMagic);
|
||||||
|
|
||||||
controller->getCharacter()->setHeading( args[3].real );
|
player->setHeading( args[3].real );
|
||||||
|
|
||||||
/// @todo find a nicer way to implement warping out of vehicles.
|
/// @todo find a nicer way to implement warping out of vehicles.
|
||||||
auto cv = controller->getCharacter()->getCurrentVehicle();
|
auto cv = player->getCurrentVehicle();
|
||||||
if ( cv != nullptr )
|
if ( cv != nullptr )
|
||||||
{
|
{
|
||||||
cv->setOccupant( controller->getCharacter()->getCurrentSeat(), nullptr );
|
cv->setOccupant( player->getCurrentSeat(), nullptr );
|
||||||
controller->getCharacter()->setCurrentVehicle(nullptr, 0);
|
player->setCurrentVehicle(nullptr, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -514,7 +515,7 @@ void game_add_contact_blip(const ScriptArguments& args)
|
|||||||
|
|
||||||
BlipData bd;
|
BlipData bd;
|
||||||
bd.coord = c;
|
bd.coord = c;
|
||||||
bd.target = nullptr;
|
bd.target = 0;
|
||||||
bd.texture = spriteName;
|
bd.texture = spriteName;
|
||||||
|
|
||||||
*args[4].globalInteger = args.getWorld()->state->addRadarBlip(bd);
|
*args[4].globalInteger = args.getWorld()->state->addRadarBlip(bd);
|
||||||
@ -534,7 +535,7 @@ void game_add_sprite_blip(const ScriptArguments& args)
|
|||||||
|
|
||||||
BlipData bd;
|
BlipData bd;
|
||||||
bd.coord = c;
|
bd.coord = c;
|
||||||
bd.target = nullptr;
|
bd.target = 0;
|
||||||
bd.texture = spriteName;
|
bd.texture = spriteName;
|
||||||
|
|
||||||
*args[4].globalInteger = args.getWorld()->state->addRadarBlip(bd);
|
*args[4].globalInteger = args.getWorld()->state->addRadarBlip(bd);
|
||||||
@ -578,7 +579,7 @@ void game_start_cutscene(const ScriptArguments& args)
|
|||||||
}
|
}
|
||||||
void game_get_cutscene_time(const ScriptArguments& args)
|
void game_get_cutscene_time(const ScriptArguments& args)
|
||||||
{
|
{
|
||||||
float time = args.getWorld()->gameTime - args.getWorld()->state->cutsceneStartTime;
|
float time = args.getWorld()->getGameTime() - args.getWorld()->state->cutsceneStartTime;
|
||||||
if( args.getWorld()->state->skipCutscene )
|
if( args.getWorld()->state->skipCutscene )
|
||||||
{
|
{
|
||||||
*args[0].globalInteger = args.getWorld()->state->currentCutscene->tracks.duration * 1000;
|
*args[0].globalInteger = args.getWorld()->state->currentCutscene->tracks.duration * 1000;
|
||||||
@ -591,7 +592,7 @@ void game_get_cutscene_time(const ScriptArguments& args)
|
|||||||
bool game_cutscene_finished(const ScriptArguments& args)
|
bool game_cutscene_finished(const ScriptArguments& args)
|
||||||
{
|
{
|
||||||
if( args.getWorld()->state->currentCutscene ) {
|
if( args.getWorld()->state->currentCutscene ) {
|
||||||
float time = args.getWorld()->gameTime - args.getWorld()->state->cutsceneStartTime;
|
float time = args.getWorld()->getGameTime() - args.getWorld()->state->cutsceneStartTime;
|
||||||
if( args.getWorld()->state->skipCutscene ) {
|
if( args.getWorld()->state->skipCutscene ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -803,7 +804,7 @@ void game_display_help(const ScriptArguments& args)
|
|||||||
args.getWorld()->state->text.push_back({
|
args.getWorld()->state->text.push_back({
|
||||||
id,
|
id,
|
||||||
str,
|
str,
|
||||||
args.getWorld()->gameTime,
|
args.getWorld()->getGameTime(),
|
||||||
2.5f,
|
2.5f,
|
||||||
style
|
style
|
||||||
});
|
});
|
||||||
@ -818,6 +819,10 @@ void game_clear_help(const ScriptArguments& args)
|
|||||||
{
|
{
|
||||||
texts.erase(texts.begin() + i);
|
texts.erase(texts.begin() + i);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,8 +38,7 @@ void game_create_player(const ScriptArguments& args)
|
|||||||
position = args.getWorld()->getGroundAtPosition(position);
|
position = args.getWorld()->getGroundAtPosition(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pc = args.getWorld()->createPedestrian(1, position + spawnMagic);
|
auto pc = args.getWorld()->createPlayer(position + spawnMagic);
|
||||||
args.getState()->player = new PlayerController(pc);
|
|
||||||
args.getState()->playerObject = pc->getGameObjectID();
|
args.getState()->playerObject = pc->getGameObjectID();
|
||||||
|
|
||||||
*args[4].globalInteger = pc->getGameObjectID();
|
*args[4].globalInteger = pc->getGameObjectID();
|
||||||
@ -922,11 +921,14 @@ void game_change_nearest_model(const ScriptArguments& args)
|
|||||||
bool game_rotate_object(const ScriptArguments& args)
|
bool game_rotate_object(const ScriptArguments& args)
|
||||||
{
|
{
|
||||||
auto object = args.getGameObject(0);
|
auto object = args.getGameObject(0);
|
||||||
float start = args[1].real;
|
if( object )
|
||||||
float finish = args[2].real;
|
{
|
||||||
|
float start = args[1].real;
|
||||||
// @todo INTERPOLATE instead of just setting the heading.
|
float finish = args[2].real;
|
||||||
object->setHeading(finish);
|
|
||||||
|
// @todo INTERPOLATE instead of just setting the heading.
|
||||||
|
object->setHeading(finish);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <script/SCMFile.hpp>
|
#include <script/SCMFile.hpp>
|
||||||
#include <engine/GameWorld.hpp>
|
#include <engine/GameWorld.hpp>
|
||||||
#include <engine/GameState.hpp>
|
#include <engine/GameState.hpp>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
SCMThread::pc_t localizeLabel(SCMThread* t, int label)
|
SCMThread::pc_t localizeLabel(SCMThread* t, int label)
|
||||||
{
|
{
|
||||||
@ -107,14 +108,13 @@ void vm_halt_thread(const ScriptArguments& args)
|
|||||||
|
|
||||||
void vm_call(const ScriptArguments& args)
|
void vm_call(const ScriptArguments& args)
|
||||||
{
|
{
|
||||||
args.getThread()->calls.push(args.getThread()->programCounter);
|
args.getThread()->calls[args.getThread()->stackDepth++] = args.getThread()->programCounter;
|
||||||
args.getThread()->programCounter = localizeLabel(args.getThread(), args[0].integer);
|
args.getThread()->programCounter = localizeLabel(args.getThread(), args[0].integer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vm_return(const ScriptArguments& args)
|
void vm_return(const ScriptArguments& args)
|
||||||
{
|
{
|
||||||
args.getThread()->programCounter = args.getThread()->calls.top();
|
args.getThread()->programCounter = args.getThread()->calls[--args.getThread()->stackDepth];
|
||||||
args.getThread()->calls.pop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vm_dec_global_int_by_global(const ScriptArguments& args)
|
void vm_dec_global_int_by_global(const ScriptArguments& args)
|
||||||
@ -161,8 +161,11 @@ void vm_mission_over(const ScriptArguments& args)
|
|||||||
{
|
{
|
||||||
for( auto oid : args.getState()->missionObjects )
|
for( auto oid : args.getState()->missionObjects )
|
||||||
{
|
{
|
||||||
auto obj = args.getWorld()->objects[oid];
|
auto obj = args.getWorld()->findObject(oid);
|
||||||
args.getWorld()->destroyObjectQueued(obj);
|
if( obj )
|
||||||
|
{
|
||||||
|
args.getWorld()->destroyObjectQueued(obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
args.getState()->missionObjects.clear();
|
args.getState()->missionObjects.clear();
|
||||||
@ -172,7 +175,7 @@ void vm_mission_over(const ScriptArguments& args)
|
|||||||
|
|
||||||
void vm_name_thread(const ScriptArguments& args)
|
void vm_name_thread(const ScriptArguments& args)
|
||||||
{
|
{
|
||||||
args.getThread()->name = args[0].string;
|
strncpy(args.getThread()->name, args[0].string, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vm_start_mission(const ScriptArguments& args)
|
void vm_start_mission(const ScriptArguments& args)
|
||||||
|
49
rwengine/tests/test_SaveGame.cpp
Normal file
49
rwengine/tests/test_SaveGame.cpp
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include <engine/GameState.hpp>
|
||||||
|
#include <engine/SaveGame.hpp>
|
||||||
|
#include <test_globals.hpp>
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE(SaveGameTests)
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_write_state)
|
||||||
|
{
|
||||||
|
GameState state;
|
||||||
|
|
||||||
|
// Set some test data
|
||||||
|
state.world = nullptr;
|
||||||
|
state.currentProgress = 10;
|
||||||
|
state.maxProgress = 124;
|
||||||
|
state.numMissions = 12;
|
||||||
|
state.numHiddenPackages = 34;
|
||||||
|
state.numHiddenPackagesDiscovered = 11;
|
||||||
|
state.numUniqueJumps = 14;
|
||||||
|
state.numRampages = 7;
|
||||||
|
state.maxWantedLevel = 5;
|
||||||
|
state.currentWeather = 9;
|
||||||
|
state.overrideNextStart = true;
|
||||||
|
state.hour = 13;
|
||||||
|
state.minute = 32;
|
||||||
|
|
||||||
|
// This may break due to cwd issues
|
||||||
|
SaveGame::writeState(state, "test_savestate.sav");
|
||||||
|
|
||||||
|
GameState loaded;
|
||||||
|
loaded.world = nullptr;
|
||||||
|
|
||||||
|
BOOST_REQUIRE( SaveGame::loadState(loaded, "test_savestate.sav") );
|
||||||
|
BOOST_CHECK( loaded.world == nullptr );
|
||||||
|
BOOST_CHECK_EQUAL( loaded.currentProgress, state.currentProgress );
|
||||||
|
BOOST_CHECK_EQUAL( loaded.maxProgress, state.maxProgress );
|
||||||
|
BOOST_CHECK_EQUAL( loaded.numMissions, state.numMissions );
|
||||||
|
BOOST_CHECK_EQUAL( loaded.numHiddenPackages, state.numHiddenPackages );
|
||||||
|
BOOST_CHECK_EQUAL( loaded.numHiddenPackagesDiscovered, state.numHiddenPackagesDiscovered );
|
||||||
|
BOOST_CHECK_EQUAL( loaded.numUniqueJumps, state.numUniqueJumps );
|
||||||
|
BOOST_CHECK_EQUAL( loaded.numRampages, state.numRampages );
|
||||||
|
BOOST_CHECK_EQUAL( loaded.maxWantedLevel, state.maxWantedLevel );
|
||||||
|
BOOST_CHECK_EQUAL( loaded.currentWeather, state.currentWeather );
|
||||||
|
BOOST_CHECK_EQUAL( loaded.overrideNextStart, state.overrideNextStart );
|
||||||
|
BOOST_CHECK_EQUAL( loaded.hour, state.hour );
|
||||||
|
BOOST_CHECK_EQUAL( loaded.minute, state.minute );
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include <objects/GameObject.hpp>
|
#include <objects/GameObject.hpp>
|
||||||
#include <engine/GameState.hpp>
|
#include <engine/GameState.hpp>
|
||||||
|
#include <engine/SaveGame.hpp>
|
||||||
#include <engine/GameWorld.hpp>
|
#include <engine/GameWorld.hpp>
|
||||||
#include <render/GameRenderer.hpp>
|
#include <render/GameRenderer.hpp>
|
||||||
#include <render/DebugDraw.hpp>
|
#include <render/DebugDraw.hpp>
|
||||||
@ -124,12 +125,10 @@ RWGame::RWGame(const std::string& gamepath, int argc, char* argv[])
|
|||||||
data->loadTXD(name + ".txd");
|
data->loadTXD(name + ".txd");
|
||||||
}
|
}
|
||||||
|
|
||||||
newGame();
|
|
||||||
|
|
||||||
auto loading = new LoadingState(this);
|
auto loading = new LoadingState(this);
|
||||||
if( newgame )
|
if( newgame )
|
||||||
{
|
{
|
||||||
loading->setNextState(new IngameState(this,test));
|
loading->setNextState(new IngameState(this,true,test));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -164,13 +163,60 @@ void RWGame::newGame()
|
|||||||
// Associate the new world with the new state and vice versa
|
// Associate the new world with the new state and vice versa
|
||||||
state->world = world;
|
state->world = world;
|
||||||
world->state = state;
|
world->state = state;
|
||||||
|
|
||||||
|
for(std::map<std::string, std::string>::iterator it = world->data->iplLocations.begin();
|
||||||
|
it != world->data->iplLocations.end();
|
||||||
|
++it) {
|
||||||
|
world->data->loadZone(it->second);
|
||||||
|
world->placeItems(it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void RWGame::saveGame(const std::string& savename)
|
||||||
|
{
|
||||||
|
// Save games without a script don't make much sense at the moment
|
||||||
|
if( script )
|
||||||
|
{
|
||||||
|
SaveGame::writeScript(*script, savename+".script");
|
||||||
|
SaveGame::writeState(*state, savename+".state");
|
||||||
|
SaveGame::writeObjects(*world, savename+".world");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RWGame::loadGame(const std::string& savename)
|
||||||
|
{
|
||||||
|
delete state->world;
|
||||||
|
//delete state;
|
||||||
|
state = nullptr;
|
||||||
|
|
||||||
|
newGame();
|
||||||
|
|
||||||
|
startScript("data/main.scm");
|
||||||
|
|
||||||
|
if(! SaveGame::loadScript(*script, savename+".script") )
|
||||||
|
{
|
||||||
|
log.error("Game", "Failed to restore Script");
|
||||||
|
}
|
||||||
|
if(! SaveGame::loadState(*state, savename+".state") )
|
||||||
|
{
|
||||||
|
log.error("Game", "Failed to restore State");
|
||||||
|
}
|
||||||
|
if(! SaveGame::loadObjects(*world, savename+".world") )
|
||||||
|
{
|
||||||
|
log.error("Game", "Failed to restore World");
|
||||||
|
}
|
||||||
|
// TODO objects.
|
||||||
}
|
}
|
||||||
|
|
||||||
void RWGame::startScript(const std::string& name)
|
void RWGame::startScript(const std::string& name)
|
||||||
{
|
{
|
||||||
SCMFile* f = world->data->loadSCM(name);
|
SCMFile* f = world->data->loadSCM(name);
|
||||||
if( f ) {
|
if( f ) {
|
||||||
if( script ) delete script;
|
if( script )
|
||||||
|
{
|
||||||
|
delete script;
|
||||||
|
}
|
||||||
|
|
||||||
SCMOpcodes* opcodes = new SCMOpcodes;
|
SCMOpcodes* opcodes = new SCMOpcodes;
|
||||||
opcodes->modules.push_back(new VMModule);
|
opcodes->modules.push_back(new VMModule);
|
||||||
@ -206,6 +252,17 @@ void RWGame::startScript(const std::string& name)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PlayerController *RWGame::getPlayer()
|
||||||
|
{
|
||||||
|
auto object = world->findObject(state->playerObject);
|
||||||
|
if( object )
|
||||||
|
{
|
||||||
|
auto controller = static_cast<CharacterObject*>(object)->controller;
|
||||||
|
return static_cast<PlayerController*>(controller);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
int RWGame::run()
|
int RWGame::run()
|
||||||
{
|
{
|
||||||
clock.restart();
|
clock.restart();
|
||||||
@ -283,7 +340,7 @@ void RWGame::tick(float dt)
|
|||||||
|
|
||||||
static float clockAccumulator = 0.f;
|
static float clockAccumulator = 0.f;
|
||||||
if (inFocus && currState->shouldWorldUpdate() ) {
|
if (inFocus && currState->shouldWorldUpdate() ) {
|
||||||
world->gameTime += dt;
|
state->gameTime += dt;
|
||||||
|
|
||||||
clockAccumulator += dt;
|
clockAccumulator += dt;
|
||||||
while( clockAccumulator >= 1.f ) {
|
while( clockAccumulator >= 1.f ) {
|
||||||
@ -306,7 +363,7 @@ void RWGame::tick(float dt)
|
|||||||
{
|
{
|
||||||
auto& part = effect->particle;
|
auto& part = effect->particle;
|
||||||
if( part.lifetime < 0.f ) continue;
|
if( part.lifetime < 0.f ) continue;
|
||||||
if( world->gameTime >= part.starttime + part.lifetime )
|
if( world->getGameTime() >= part.starttime + part.lifetime )
|
||||||
{
|
{
|
||||||
world->destroyEffect( effect );
|
world->destroyEffect( effect );
|
||||||
--i;
|
--i;
|
||||||
@ -326,7 +383,7 @@ void RWGame::tick(float dt)
|
|||||||
for( int i = 0; i < state->text.size(); )
|
for( int i = 0; i < state->text.size(); )
|
||||||
{
|
{
|
||||||
auto& text = state->text[i];
|
auto& text = state->text[i];
|
||||||
if( world->gameTime > text.osTextStart + text.osTextTime )
|
if( world->getGameTime() > text.osTextStart + text.osTextTime )
|
||||||
{
|
{
|
||||||
state->text.erase(state->text.begin() + i);
|
state->text.erase(state->text.begin() + i);
|
||||||
}
|
}
|
||||||
@ -349,7 +406,7 @@ void RWGame::tick(float dt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( state->player )
|
if ( state->playerObject )
|
||||||
{
|
{
|
||||||
// Use the current camera position to spawn pedestrians.
|
// Use the current camera position to spawn pedestrians.
|
||||||
auto p = nextCam.position;
|
auto p = nextCam.position;
|
||||||
@ -377,7 +434,7 @@ void RWGame::render(float alpha, float time)
|
|||||||
if( state->currentCutscene != nullptr && state->cutsceneStartTime >= 0.f )
|
if( state->currentCutscene != nullptr && state->cutsceneStartTime >= 0.f )
|
||||||
{
|
{
|
||||||
auto cutscene = state->currentCutscene;
|
auto cutscene = state->currentCutscene;
|
||||||
float cutsceneTime = std::min(world->gameTime - state->cutsceneStartTime,
|
float cutsceneTime = std::min(world->getGameTime() - state->cutsceneStartTime,
|
||||||
cutscene->tracks.duration);
|
cutscene->tracks.duration);
|
||||||
cutsceneTime += GAME_TIMESTEP * alpha;
|
cutsceneTime += GAME_TIMESTEP * alpha;
|
||||||
glm::vec3 cameraPos = cutscene->tracks.getPositionAt(cutsceneTime),
|
glm::vec3 cameraPos = cutscene->tracks.getPositionAt(cutsceneTime),
|
||||||
@ -516,10 +573,13 @@ void RWGame::renderDebugStats(float time, Renderer::ProfileInfo& worldRenderTime
|
|||||||
|
|
||||||
ss << "P " << peds << " V " << cars << "\n";
|
ss << "P " << peds << " V " << cars << "\n";
|
||||||
|
|
||||||
if( state->player ) {
|
if( state->playerObject ) {
|
||||||
|
ss << "Player (" << state->playerObject << ")\n";
|
||||||
|
auto object = world->findObject(state->playerObject);
|
||||||
|
auto player = static_cast<CharacterObject*>(object)->controller;
|
||||||
ss << "Player Activity: ";
|
ss << "Player Activity: ";
|
||||||
if( state->player->getCurrentActivity() ) {
|
if( player->getCurrentActivity() ) {
|
||||||
ss << state->player->getCurrentActivity()->name();
|
ss << player->getCurrentActivity()->name();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ss << "Idle";
|
ss << "Idle";
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include <SFML/Graphics.hpp>
|
#include <SFML/Graphics.hpp>
|
||||||
|
|
||||||
|
class PlayerController;
|
||||||
class RWGame
|
class RWGame
|
||||||
{
|
{
|
||||||
Logger log;
|
Logger log;
|
||||||
@ -53,7 +54,12 @@ public:
|
|||||||
{
|
{
|
||||||
return world;
|
return world;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GameData* getGameData() const
|
||||||
|
{
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
GameRenderer* getRenderer() const
|
GameRenderer* getRenderer() const
|
||||||
{
|
{
|
||||||
return renderer;
|
return renderer;
|
||||||
@ -101,6 +107,12 @@ public:
|
|||||||
|
|
||||||
void startScript(const std::string& name);
|
void startScript(const std::string& name);
|
||||||
|
|
||||||
|
void saveGame(const std::string& savename);
|
||||||
|
void loadGame(const std::string& savename);
|
||||||
|
|
||||||
|
/** shortcut for getWorld()->state.player->getCharacter() */
|
||||||
|
PlayerController* getPlayer();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void tick(float dt);
|
void tick(float dt);
|
||||||
void render(float alpha, float dt);
|
void render(float alpha, float dt);
|
||||||
|
@ -7,19 +7,18 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <glm/gtx/string_cast.hpp>
|
#include <glm/gtx/string_cast.hpp>
|
||||||
|
|
||||||
void jumpCharacter(RWGame* game, CharacterController* controller, const glm::vec3& target)
|
void jumpCharacter(RWGame* game, CharacterObject* player, const glm::vec3& target)
|
||||||
{
|
{
|
||||||
glm::vec3 ground = game->getWorld()->getGroundAtPosition(target);
|
glm::vec3 ground = game->getWorld()->getGroundAtPosition(target);
|
||||||
if( controller )
|
if( player )
|
||||||
{
|
{
|
||||||
auto pl = controller->getCharacter();
|
if( player->getCurrentVehicle() )
|
||||||
if( pl->getCurrentVehicle() )
|
|
||||||
{
|
{
|
||||||
pl->getCurrentVehicle()->setPosition(ground + glm::vec3(0.f, 0.f, 1.f));
|
player->getCurrentVehicle()->setPosition(ground + glm::vec3(0.f, 0.f, 1.f));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pl->setPosition(ground + glm::vec3(0.f, 0.f, 1.f));
|
player->setPosition(ground + glm::vec3(0.f, 0.f, 1.f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -72,34 +71,40 @@ DebugState::DebugState(RWGame* game, const glm::vec3& vp, const glm::quat& vd)
|
|||||||
}, entryHeight));
|
}, entryHeight));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
m->addEntry(Menu::lambda("Quicksave", [=] {
|
||||||
|
game->saveGame("quicksave");
|
||||||
|
}, entryHeight));
|
||||||
|
m->addEntry(Menu::lambda("Quickload", [=] {
|
||||||
|
game->loadGame("quicksave");
|
||||||
|
}, entryHeight));
|
||||||
m->addEntry(Menu::lambda("Jump to Garage", [=] {
|
m->addEntry(Menu::lambda("Jump to Garage", [=] {
|
||||||
jumpCharacter(game, game->getWorld()->state->player, glm::vec3(270.f, -605.f, 40.f));
|
jumpCharacter(game, game->getPlayer()->getCharacter(), glm::vec3(270.f, -605.f, 40.f));
|
||||||
}, entryHeight));
|
}, entryHeight));
|
||||||
m->addEntry(Menu::lambda("Jump to Airport", [=] {
|
m->addEntry(Menu::lambda("Jump to Airport", [=] {
|
||||||
jumpCharacter(game, game->getWorld()->state->player, glm::vec3(-950.f, -980.f, 12.f));
|
jumpCharacter(game, game->getPlayer()->getCharacter(), glm::vec3(-950.f, -980.f, 12.f));
|
||||||
}, entryHeight));
|
}, entryHeight));
|
||||||
m->addEntry(Menu::lambda("Jump to Hideout", [=] {
|
m->addEntry(Menu::lambda("Jump to Hideout", [=] {
|
||||||
jumpCharacter(game, game->getWorld()->state->player, glm::vec3(875.0, -309.0, 100.0));
|
jumpCharacter(game, game->getPlayer()->getCharacter(), glm::vec3(875.0, -309.0, 100.0));
|
||||||
}, entryHeight));
|
}, entryHeight));
|
||||||
m->addEntry(Menu::lambda("Jump to Luigi's", [=] {
|
m->addEntry(Menu::lambda("Jump to Luigi's", [=] {
|
||||||
jumpCharacter(game, game->getWorld()->state->player, glm::vec3(902.75, -425.56, 100.0));
|
jumpCharacter(game, game->getPlayer()->getCharacter(), glm::vec3(902.75, -425.56, 100.0));
|
||||||
}, entryHeight));
|
}, entryHeight));
|
||||||
m->addEntry(Menu::lambda("Jump to Hospital", [=] {
|
m->addEntry(Menu::lambda("Jump to Hospital", [=] {
|
||||||
jumpCharacter(game, game->getWorld()->state->player, glm::vec3(1123.77, -569.15, 100.0));
|
jumpCharacter(game, game->getPlayer()->getCharacter(), glm::vec3(1123.77, -569.15, 100.0));
|
||||||
}, entryHeight));
|
}, entryHeight));
|
||||||
m->addEntry(Menu::lambda("Add Follower", [=] {
|
m->addEntry(Menu::lambda("Add Follower", [=] {
|
||||||
auto spawnPos = game->getWorld()->state->player->getCharacter()->getPosition();
|
auto spawnPos = game->getPlayer()->getCharacter()->getPosition();
|
||||||
spawnPos += game->getWorld()->state->player->getCharacter()->getRotation() * glm::vec3(-1.f, 0.f, 0.f);
|
spawnPos += game->getPlayer()->getCharacter()->getRotation() * glm::vec3(-1.f, 0.f, 0.f);
|
||||||
auto follower = game->getWorld()->createPedestrian(12, spawnPos);
|
auto follower = game->getWorld()->createPedestrian(12, spawnPos);
|
||||||
jumpCharacter(game, follower->controller, spawnPos);
|
jumpCharacter(game, follower, spawnPos);
|
||||||
follower->controller->setGoal(CharacterController::FollowLeader);
|
follower->controller->setGoal(CharacterController::FollowLeader);
|
||||||
follower->controller->setTargetCharacter(game->getWorld()->state->player->getCharacter());
|
follower->controller->setTargetCharacter(game->getPlayer()->getCharacter());
|
||||||
}, entryHeight));
|
}, entryHeight));
|
||||||
m->addEntry(Menu::lambda("Set Super Jump", [=] {
|
m->addEntry(Menu::lambda("Set Super Jump", [=] {
|
||||||
game->getWorld()->state->player->getCharacter()->setJumpSpeed(20.f);
|
game->getPlayer()->getCharacter()->setJumpSpeed(20.f);
|
||||||
}, entryHeight));
|
}, entryHeight));
|
||||||
m->addEntry(Menu::lambda("Set Normal Jump", [=] {
|
m->addEntry(Menu::lambda("Set Normal Jump", [=] {
|
||||||
game->getWorld()->state->player->getCharacter()->setJumpSpeed(CharacterObject::DefaultJumpSpeed);
|
game->getPlayer()->getCharacter()->setJumpSpeed(CharacterObject::DefaultJumpSpeed);
|
||||||
}, entryHeight));
|
}, entryHeight));
|
||||||
|
|
||||||
this->enterMenu(m);
|
this->enterMenu(m);
|
||||||
@ -237,7 +242,7 @@ void DebugState::handleEvent(const sf::Event &e)
|
|||||||
|
|
||||||
void DebugState::spawnVehicle(unsigned int id)
|
void DebugState::spawnVehicle(unsigned int id)
|
||||||
{
|
{
|
||||||
auto ch = getWorld()->state->player->getCharacter();
|
auto ch = game->getPlayer()->getCharacter();
|
||||||
if(! ch) return;
|
if(! ch) return;
|
||||||
|
|
||||||
glm::vec3 fwd = ch->rotation * glm::vec3(0.f, 1.f, 0.f);
|
glm::vec3 fwd = ch->rotation * glm::vec3(0.f, 1.f, 0.f);
|
||||||
|
@ -17,17 +17,17 @@
|
|||||||
|
|
||||||
#define AUTOLOOK_TIME 2.f
|
#define AUTOLOOK_TIME 2.f
|
||||||
|
|
||||||
IngameState::IngameState(RWGame* game, bool test)
|
IngameState::IngameState(RWGame* game, bool newgame, bool test)
|
||||||
: State(game), started(false), test(test), autolookTimer(0.f)
|
: State(game), started(false), newgame(newgame), test(test), autolookTimer(0.f)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void IngameState::startTest()
|
void IngameState::startTest()
|
||||||
{
|
{
|
||||||
auto playerChar = getWorld()->createPedestrian(1, {270.f, -605.f, 40.f});
|
auto playerChar = getWorld()->createPlayer({270.f, -605.f, 40.f});
|
||||||
auto player = new PlayerController(playerChar);
|
auto player = new PlayerController(playerChar);
|
||||||
|
|
||||||
getWorld()->state->player = player;
|
getWorld()->state->playerObject = playerChar->getGameObjectID();
|
||||||
|
|
||||||
/*auto bat = new WeaponItem(getWorld()->data.weaponData["ak47"]);
|
/*auto bat = new WeaponItem(getWorld()->data.weaponData["ak47"]);
|
||||||
_playerCharacter->addToInventory(bat);
|
_playerCharacter->addToInventory(bat);
|
||||||
@ -67,23 +67,22 @@ void IngameState::startTest()
|
|||||||
void IngameState::startGame()
|
void IngameState::startGame()
|
||||||
{
|
{
|
||||||
game->startScript("data/main.scm");
|
game->startScript("data/main.scm");
|
||||||
|
game->getScript()->startThread(0);
|
||||||
getWorld()->sound.playBackground( getWorld()->data->getDataPath() + "/audio/City.wav" );
|
getWorld()->sound.playBackground( getWorld()->data->getDataPath() + "/audio/City.wav" );
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerController *IngameState::getPlayer()
|
|
||||||
{
|
|
||||||
return getWorld()->state->player;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IngameState::enter()
|
void IngameState::enter()
|
||||||
{
|
{
|
||||||
if( ! started )
|
if( ! started )
|
||||||
{
|
{
|
||||||
if( test ) {
|
if( newgame )
|
||||||
startTest();
|
{
|
||||||
}
|
if( test ) {
|
||||||
else {
|
startTest();
|
||||||
startGame();
|
}
|
||||||
|
else {
|
||||||
|
startGame();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
started = true;
|
started = true;
|
||||||
}
|
}
|
||||||
@ -98,7 +97,7 @@ void IngameState::tick(float dt)
|
|||||||
{
|
{
|
||||||
autolookTimer = std::max(autolookTimer - dt, 0.f);
|
autolookTimer = std::max(autolookTimer - dt, 0.f);
|
||||||
|
|
||||||
auto player = getPlayer();
|
auto player = game->getPlayer();
|
||||||
if( player && player->isInputEnabled() )
|
if( player && player->isInputEnabled() )
|
||||||
{
|
{
|
||||||
float qpi = glm::half_pi<float>();
|
float qpi = glm::half_pi<float>();
|
||||||
@ -230,7 +229,7 @@ void IngameState::draw(GameRenderer* r)
|
|||||||
{
|
{
|
||||||
if( !getWorld()->state->isCinematic && getWorld()->isCutsceneDone() )
|
if( !getWorld()->state->isCinematic && getWorld()->isCutsceneDone() )
|
||||||
{
|
{
|
||||||
drawHUD(getPlayer(), getWorld(), r);
|
drawHUD(game->getPlayer(), getWorld(), r);
|
||||||
}
|
}
|
||||||
|
|
||||||
State::draw(r);
|
State::draw(r);
|
||||||
@ -238,7 +237,7 @@ void IngameState::draw(GameRenderer* r)
|
|||||||
|
|
||||||
void IngameState::handleEvent(const sf::Event &event)
|
void IngameState::handleEvent(const sf::Event &event)
|
||||||
{
|
{
|
||||||
auto player = getPlayer();
|
auto player = game->getPlayer();
|
||||||
|
|
||||||
switch(event.type) {
|
switch(event.type) {
|
||||||
case sf::Event::KeyPressed:
|
case sf::Event::KeyPressed:
|
||||||
|
@ -9,6 +9,7 @@ class IngameState : public State
|
|||||||
{
|
{
|
||||||
bool started;
|
bool started;
|
||||||
bool test;
|
bool test;
|
||||||
|
bool newgame;
|
||||||
ViewCamera _look;
|
ViewCamera _look;
|
||||||
/** Player input */
|
/** Player input */
|
||||||
glm::vec2 _lookAngles;
|
glm::vec2 _lookAngles;
|
||||||
@ -16,14 +17,11 @@ class IngameState : public State
|
|||||||
/** Timer to reset _lookAngles to forward in vehicles */
|
/** Timer to reset _lookAngles to forward in vehicles */
|
||||||
float autolookTimer;
|
float autolookTimer;
|
||||||
public:
|
public:
|
||||||
IngameState(RWGame* game, bool test = false);
|
IngameState(RWGame* game, bool newgame = true, bool test = false);
|
||||||
|
|
||||||
void startTest();
|
void startTest();
|
||||||
void startGame();
|
void startGame();
|
||||||
|
|
||||||
/** shortcut for getWorld()->state.player->getCharacter() */
|
|
||||||
PlayerController* getPlayer();
|
|
||||||
|
|
||||||
virtual void enter();
|
virtual void enter();
|
||||||
virtual void exit();
|
virtual void exit();
|
||||||
|
|
||||||
|
@ -9,23 +9,13 @@ LoadingState::LoadingState(RWGame* game)
|
|||||||
|
|
||||||
void LoadingState::enter()
|
void LoadingState::enter()
|
||||||
{
|
{
|
||||||
// Load all of the files waiting to be loaded.
|
// Load Item definitions
|
||||||
auto world = getWorld();
|
for( auto& def : game->getGameData()->ideLocations )
|
||||||
|
{
|
||||||
// Loade all of the IDEs.
|
game->getGameData()->loadObjects(def.second);
|
||||||
for(std::map<std::string, std::string>::iterator it = world->data->ideLocations.begin();
|
|
||||||
it != world->data->ideLocations.end();
|
|
||||||
++it) {
|
|
||||||
world->data->loadObjects(it->second);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load IPLs
|
game->newGame();
|
||||||
for(std::map<std::string, std::string>::iterator it = world->data->iplLocations.begin();
|
|
||||||
it != world->data->iplLocations.end();
|
|
||||||
++it) {
|
|
||||||
world->data->loadZone(it->second);
|
|
||||||
world->placeItems(it->second);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadingState::exit()
|
void LoadingState::exit()
|
||||||
|
@ -10,7 +10,11 @@ MenuState::MenuState(RWGame* game)
|
|||||||
Menu *m = new Menu(2);
|
Menu *m = new Menu(2);
|
||||||
m->offset = glm::vec2(200.f, 200.f);
|
m->offset = glm::vec2(200.f, 200.f);
|
||||||
m->addEntry(Menu::lambda("Start", [=] { StateManager::get().enter(new IngameState(game)); }));
|
m->addEntry(Menu::lambda("Start", [=] { StateManager::get().enter(new IngameState(game)); }));
|
||||||
m->addEntry(Menu::lambda("Test", [=] { StateManager::get().enter(new IngameState(game, true)); }));
|
m->addEntry(Menu::lambda("Resume", [=] {
|
||||||
|
StateManager::get().enter(new IngameState(game, false));
|
||||||
|
game->loadGame("quicksave");
|
||||||
|
}));
|
||||||
|
m->addEntry(Menu::lambda("Test", [=] { StateManager::get().enter(new IngameState(game, true, true)); }));
|
||||||
m->addEntry(Menu::lambda("Options", [] { std::cout << "Options" << std::endl; }));
|
m->addEntry(Menu::lambda("Options", [] { std::cout << "Options" << std::endl; }));
|
||||||
m->addEntry(Menu::lambda("Exit", [=] { getWindow().close(); }));
|
m->addEntry(Menu::lambda("Exit", [=] { getWindow().close(); }));
|
||||||
this->enterMenu(m);
|
this->enterMenu(m);
|
||||||
|
Loading…
Reference in New Issue
Block a user