mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-22 02:12:45 +01:00
commit
2b096eb228
@ -61,6 +61,8 @@ set(RWENGINE_SOURCES
|
||||
src/engine/GameState.hpp
|
||||
src/engine/GameWorld.cpp
|
||||
src/engine/GameWorld.hpp
|
||||
src/engine/GarageController.cpp
|
||||
src/engine/GarageController.hpp
|
||||
src/engine/SaveGame.cpp
|
||||
src/engine/SaveGame.hpp
|
||||
src/engine/ScreenText.cpp
|
||||
|
@ -1,11 +1,12 @@
|
||||
#ifndef _RWENGINE_MODELDATA_HPP_
|
||||
#define _RWENGINE_MODELDATA_HPP_
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <glm/glm.hpp>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@ -114,6 +115,20 @@ private:
|
||||
using ModelInfoTable =
|
||||
std::unordered_map<ModelID, std::unique_ptr<BaseModelInfo>>;
|
||||
|
||||
const static std::unordered_set<std::string> doorModels = {
|
||||
"oddjgaragdoor", "bombdoor", "door_bombshop",
|
||||
"vheistlocdoor", "door2_garage", "ind_slidedoor",
|
||||
"bankjobdoor", "door_jmsgrage", "jamesgrge_kb",
|
||||
"door_sfehousegrge", "shedgaragedoor", "door4_garage",
|
||||
"door_col_compnd_01", "door_col_compnd_02", "door_col_compnd_03",
|
||||
"door_col_compnd_04", "door_col_compnd_05", "impex_door",
|
||||
"SalvGarage", "door3_garage", "leveldoor2",
|
||||
"double_garage_dr", "amcogaragedoor", "towergaragedoor1",
|
||||
"towergaragedoor2", "towergaragedoor3", "plysve_gragedoor",
|
||||
"impexpsubgrgdoor", "Sub_sprayshopdoor", "ind_plyrwoor",
|
||||
"8ballsuburbandoor", "crushercrush", "crushertop",
|
||||
};
|
||||
|
||||
/**
|
||||
* Model data for simple types
|
||||
*
|
||||
@ -249,6 +264,10 @@ public:
|
||||
return related_;
|
||||
}
|
||||
|
||||
static bool isDoorModel(std::string m) {
|
||||
return doorModels.find(m) != doorModels.end();
|
||||
}
|
||||
|
||||
private:
|
||||
ClumpPtr model_;
|
||||
std::array<AtomicPtr, 3> atomics_;
|
||||
@ -301,7 +320,6 @@ private:
|
||||
ClumpPtr model_ = nullptr;
|
||||
};
|
||||
|
||||
|
||||
enum class ComponentRuleType {
|
||||
Any = 1,
|
||||
RainOnly = 2,
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <data/VehicleGenerator.hpp>
|
||||
#include <engine/GameData.hpp>
|
||||
#include <engine/GameInputState.hpp>
|
||||
|
||||
#include <engine/GameWorld.hpp>
|
||||
#include <engine/ScreenText.hpp>
|
||||
#include <objects/ObjectTypes.hpp>
|
||||
@ -208,40 +209,49 @@ struct BlipData {
|
||||
}
|
||||
};
|
||||
|
||||
enum class GarageType {
|
||||
Mission = 1,
|
||||
BombShop1 = 2,
|
||||
BombShop2 = 3,
|
||||
BombShop3 = 4,
|
||||
Respray = 5,
|
||||
CollectCars1 = 8,
|
||||
CollectCars2 = 9,
|
||||
MissionForCarToComeOut = 11,
|
||||
Crusher = 13,
|
||||
MissionKeepCar = 14,
|
||||
Hideout1 = 16,
|
||||
Hideout2 = 17,
|
||||
Hideout3 = 18,
|
||||
MissionToOpenAndClose = 19,
|
||||
MissionForSpecificCar = 20,
|
||||
MissionKeepCarAndRemainClosed = 21,
|
||||
};
|
||||
|
||||
enum class GarageState { Closed, Closing, Opening, Opened };
|
||||
|
||||
/**
|
||||
* 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
|
||||
};
|
||||
GarageType type;
|
||||
|
||||
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_) {
|
||||
GameObject* target;
|
||||
|
||||
GarageState state;
|
||||
|
||||
GarageInfo(int id_, const glm::vec3 min_, const glm::vec3 max_,
|
||||
GarageType type_)
|
||||
: type(type_)
|
||||
, id(id_)
|
||||
, min(min_)
|
||||
, max(max_)
|
||||
, target(nullptr)
|
||||
, state(GarageState::Closed) {
|
||||
}
|
||||
|
||||
int getScriptObjectID() const {
|
||||
|
@ -371,6 +371,79 @@ PickupObject* GameWorld::createPickup(const glm::vec3& pos, int id, int type) {
|
||||
return pickup;
|
||||
}
|
||||
|
||||
GarageInfo* GameWorld::createGarage(const glm::vec3 coord0,
|
||||
const glm::vec3 coord1, const int type) {
|
||||
glm::vec3 min;
|
||||
glm::vec3 max;
|
||||
glm::vec3 midpoint;
|
||||
|
||||
min.x = std::min(coord0.x, coord1.x);
|
||||
min.y = std::min(coord0.y, coord1.y);
|
||||
min.z = std::min(coord0.z, coord1.z);
|
||||
|
||||
max.x = std::max(coord0.x, coord1.x);
|
||||
max.y = std::max(coord0.y, coord1.y);
|
||||
max.z = std::max(coord0.z, coord1.z);
|
||||
|
||||
midpoint.x = (min.x + max.x) / 2;
|
||||
midpoint.y = (min.y + max.y) / 2;
|
||||
midpoint.z = (min.z + max.z) / 2;
|
||||
|
||||
// Find door object for this garage
|
||||
InstanceObject* door = nullptr;
|
||||
|
||||
for (auto p : instancePool.objects) {
|
||||
auto o = p.second;
|
||||
if (!o->getModel()) continue;
|
||||
if (!SimpleModelInfo::isDoorModel(
|
||||
o->getModelInfo<BaseModelInfo>()->name))
|
||||
continue;
|
||||
|
||||
// Is this how the game finds door object?
|
||||
if (glm::distance(midpoint, o->getPosition()) < 20.f) {
|
||||
door = static_cast<InstanceObject*>(o);
|
||||
}
|
||||
}
|
||||
|
||||
// Create garage
|
||||
int id = state->garages.size();
|
||||
GarageInfo* info =
|
||||
new GarageInfo{id, min, max, static_cast<GarageType>(type)};
|
||||
state->garages.push_back(*info);
|
||||
|
||||
switch (static_cast<GarageType>(type)) {
|
||||
case GarageType::Mission:
|
||||
case GarageType::CollectCars1:
|
||||
case GarageType::CollectCars2:
|
||||
case GarageType::MissionForCarToComeOut:
|
||||
case GarageType::MissionKeepCar:
|
||||
case GarageType::Hideout1:
|
||||
case GarageType::Hideout2:
|
||||
case GarageType::Hideout3:
|
||||
case GarageType::MissionToOpenAndClose:
|
||||
case GarageType::MissionForSpecificCar:
|
||||
case GarageType::MissionKeepCarAndRemainClosed: {
|
||||
info->state = GarageState::Closed;
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::BombShop1:
|
||||
case GarageType::BombShop2:
|
||||
case GarageType::BombShop3:
|
||||
case GarageType::Respray:
|
||||
case GarageType::Crusher: {
|
||||
info->state = GarageState::Opened;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Create controller
|
||||
garageControllers.push_back(
|
||||
std::make_unique<GarageController>(GarageController(this, info, door)));
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void GameWorld::ObjectPool::insert(GameObject* object) {
|
||||
if (object->getGameObjectID() == 0) {
|
||||
// Find the lowest free GameObjectID.
|
||||
|
@ -17,7 +17,9 @@
|
||||
#include <ai/AIGraphNode.hpp>
|
||||
#include <audio/SoundManager.hpp>
|
||||
|
||||
#include <engine/GarageController.hpp>
|
||||
#include <objects/ObjectTypes.hpp>
|
||||
|
||||
#include <render/VisualFX.hpp>
|
||||
|
||||
#include <data/Chase.hpp>
|
||||
@ -32,6 +34,7 @@ class btSequentialImpulseConstraintSolver;
|
||||
struct btDbvtBroadphase;
|
||||
|
||||
class GameState;
|
||||
class GarageController;
|
||||
|
||||
class PlayerController;
|
||||
class Logger;
|
||||
@ -142,6 +145,12 @@ public:
|
||||
*/
|
||||
PickupObject* createPickup(const glm::vec3& pos, int id, int type);
|
||||
|
||||
/**
|
||||
* Creates a garage
|
||||
*/
|
||||
GarageInfo* createGarage(const glm::vec3 coord0, const glm::vec3 coord1,
|
||||
const int type);
|
||||
|
||||
/**
|
||||
* Destroys an existing Object
|
||||
*/
|
||||
@ -255,6 +264,8 @@ public:
|
||||
|
||||
std::vector<PlayerController*> players;
|
||||
|
||||
std::vector<std::unique_ptr<GarageController>> garageControllers;
|
||||
|
||||
/**
|
||||
* @brief getBlipTarget
|
||||
* @param blip
|
||||
|
702
rwengine/src/engine/GarageController.cpp
Normal file
702
rwengine/src/engine/GarageController.cpp
Normal file
@ -0,0 +1,702 @@
|
||||
#include "GarageController.hpp"
|
||||
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
#include "dynamics/CollisionInstance.hpp"
|
||||
|
||||
#include "ai/PlayerController.hpp"
|
||||
|
||||
#include "engine/GameState.hpp"
|
||||
|
||||
#include "objects/CharacterObject.hpp"
|
||||
#include "objects/GameObject.hpp"
|
||||
#include "objects/InstanceObject.hpp"
|
||||
#include "objects/VehicleObject.hpp"
|
||||
|
||||
GarageController::GarageController(GameWorld* engine, GarageInfo* info,
|
||||
InstanceObject* door)
|
||||
|
||||
: swingType(false)
|
||||
, needsToUpdate(false)
|
||||
, fraction(0.f)
|
||||
, step(0.5f)
|
||||
, doorHeight(4.0f)
|
||||
, engine(engine)
|
||||
, garageInfo(info)
|
||||
, doorObject(door) {
|
||||
if (doorObject) {
|
||||
startPosition = doorObject->getPosition();
|
||||
startRotation = doorObject->getRotation();
|
||||
}
|
||||
if (garageInfo) {
|
||||
if (garageInfo->state == GarageState::Closed) {
|
||||
fraction = 0.f;
|
||||
} else {
|
||||
fraction = 1.f;
|
||||
}
|
||||
}
|
||||
|
||||
// @todo set door height according to model size
|
||||
|
||||
updateDoor();
|
||||
}
|
||||
|
||||
GarageController::~GarageController() {
|
||||
}
|
||||
|
||||
float GarageController::getDistanceToGarage(glm::vec3 point) {
|
||||
float dx = std::max(
|
||||
{garageInfo->min.x - point.x, 0.f, point.x - garageInfo->max.x});
|
||||
float dy = std::max(
|
||||
{garageInfo->min.y - point.y, 0.f, point.y - garageInfo->max.y});
|
||||
|
||||
// Seems like original game ignores z axis, bug or feature?
|
||||
// float dz = std::max(
|
||||
// {garageInfo->min.z - point.z, 0.f, point.z - garageInfo->max.z});
|
||||
|
||||
// return std::sqrt(dx * dx + dy * dy + dz * dz);
|
||||
|
||||
return std::sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
bool GarageController::isObjectInsideGarage(GameObject* object) {
|
||||
// This is not that trivial, we need to check if full vehicle body is inside
|
||||
auto p = object->getPosition();
|
||||
|
||||
if (p.x >= (garageInfo->min.x) && p.y >= (garageInfo->min.y) &&
|
||||
p.z >= (garageInfo->min.z) && p.x <= (garageInfo->max.x) &&
|
||||
p.y <= (garageInfo->max.y) && p.z <= (garageInfo->max.z)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GarageController::shouldClose() {
|
||||
auto controller = engine->players.at(0);
|
||||
auto plyChar = controller->getCharacter();
|
||||
auto playerPosition = plyChar->getPosition();
|
||||
auto playerVehicle = plyChar->getCurrentVehicle();
|
||||
bool playerIsInVehicle = playerVehicle != nullptr;
|
||||
|
||||
switch (garageInfo->type) {
|
||||
case GarageType::Mission: {
|
||||
if (!isObjectInsideGarage(static_cast<GameObject*>(plyChar)) &&
|
||||
isObjectInsideGarage(garageInfo->target)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::BombShop1:
|
||||
case GarageType::BombShop2:
|
||||
case GarageType::BombShop3:
|
||||
case GarageType::Respray: {
|
||||
if (playerIsInVehicle) {
|
||||
if (isObjectInsideGarage(
|
||||
static_cast<GameObject*>(playerVehicle)) &&
|
||||
playerVehicle->isStopped()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::CollectCars1:
|
||||
case GarageType::CollectCars2: {
|
||||
if (playerIsInVehicle) {
|
||||
if (isObjectInsideGarage(
|
||||
static_cast<GameObject*>(playerVehicle))) {
|
||||
if (playerVehicle->getLifetime() !=
|
||||
GameObject::MissionLifetime) {
|
||||
return true;
|
||||
} else {
|
||||
// @todo show message "come back when youre not busy"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::MissionForCarToComeOut: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::Crusher: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::MissionKeepCar: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::Hideout1:
|
||||
case GarageType::Hideout2:
|
||||
case GarageType::Hideout3: {
|
||||
// Not sure about these values
|
||||
if ((!playerIsInVehicle &&
|
||||
getDistanceToGarage(playerPosition) >= 5.f) ||
|
||||
(playerIsInVehicle &&
|
||||
getDistanceToGarage(playerPosition) >= 10.f)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::MissionToOpenAndClose: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::MissionForSpecificCar: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::MissionKeepCarAndRemainClosed: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GarageController::shouldOpen() {
|
||||
auto controller = engine->players.at(0);
|
||||
auto plyChar = controller->getCharacter();
|
||||
auto playerPosition = plyChar->getPosition();
|
||||
auto playerVehicle = plyChar->getCurrentVehicle();
|
||||
bool playerIsInVehicle = playerVehicle != nullptr;
|
||||
|
||||
switch (garageInfo->type) {
|
||||
case GarageType::Mission: {
|
||||
// Not sure about these values
|
||||
if (playerIsInVehicle &&
|
||||
getDistanceToGarage(playerPosition) < 8.f &&
|
||||
playerVehicle == garageInfo->target) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::BombShop1:
|
||||
case GarageType::BombShop2:
|
||||
case GarageType::BombShop3:
|
||||
case GarageType::Respray: {
|
||||
if (garageTimer < engine->getGameTime()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::CollectCars1:
|
||||
case GarageType::CollectCars2: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::MissionForCarToComeOut: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::Crusher: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::MissionKeepCar: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::Hideout1:
|
||||
case GarageType::Hideout2:
|
||||
case GarageType::Hideout3: {
|
||||
// Not sure about these values
|
||||
if ((!playerIsInVehicle &&
|
||||
getDistanceToGarage(playerPosition) < 5.f) ||
|
||||
(playerIsInVehicle &&
|
||||
getDistanceToGarage(playerPosition) < 10.f)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::MissionToOpenAndClose: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::MissionForSpecificCar: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::MissionKeepCarAndRemainClosed: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GarageController::shouldStopClosing() {
|
||||
auto controller = engine->players.at(0);
|
||||
auto plyChar = controller->getCharacter();
|
||||
auto playerPosition = plyChar->getPosition();
|
||||
auto playerVehicle = plyChar->getCurrentVehicle();
|
||||
bool playerIsInVehicle = playerVehicle != nullptr;
|
||||
|
||||
switch (garageInfo->type) {
|
||||
case GarageType::Mission:
|
||||
case GarageType::BombShop1:
|
||||
case GarageType::BombShop2:
|
||||
case GarageType::BombShop3:
|
||||
case GarageType::Respray:
|
||||
case GarageType::CollectCars1:
|
||||
case GarageType::CollectCars2: {
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::MissionForCarToComeOut: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::Crusher: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::MissionKeepCar: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::Hideout1:
|
||||
case GarageType::Hideout2:
|
||||
case GarageType::Hideout3: {
|
||||
// Not sure about these values
|
||||
if ((!playerIsInVehicle &&
|
||||
getDistanceToGarage(playerPosition) < 5.f) ||
|
||||
(playerIsInVehicle &&
|
||||
getDistanceToGarage(playerPosition) < 10.f)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::MissionToOpenAndClose: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::MissionForSpecificCar: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::MissionKeepCarAndRemainClosed: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GarageController::shouldStopOpening() {
|
||||
auto controller = engine->players.at(0);
|
||||
auto plyChar = controller->getCharacter();
|
||||
auto playerPosition = plyChar->getPosition();
|
||||
auto playerVehicle = plyChar->getCurrentVehicle();
|
||||
bool playerIsInVehicle = playerVehicle != nullptr;
|
||||
|
||||
switch (garageInfo->type) {
|
||||
case GarageType::Mission:
|
||||
case GarageType::BombShop1:
|
||||
case GarageType::BombShop2:
|
||||
case GarageType::BombShop3:
|
||||
case GarageType::Respray:
|
||||
case GarageType::CollectCars1:
|
||||
case GarageType::CollectCars2: {
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::MissionForCarToComeOut: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::Crusher: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::MissionKeepCar: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::Hideout1:
|
||||
case GarageType::Hideout2:
|
||||
case GarageType::Hideout3: {
|
||||
// Not sure about these values
|
||||
if ((!playerIsInVehicle &&
|
||||
getDistanceToGarage(playerPosition) >= 5.f) ||
|
||||
(playerIsInVehicle &&
|
||||
getDistanceToGarage(playerPosition) >= 10.f)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::MissionToOpenAndClose: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::MissionForSpecificCar: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case GarageType::MissionKeepCarAndRemainClosed: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void GarageController::doOnOpenEvent() {
|
||||
auto controller = engine->players.at(0);
|
||||
auto plyChar = controller->getCharacter();
|
||||
auto playerPosition = plyChar->getPosition();
|
||||
auto playerVehicle = plyChar->getCurrentVehicle();
|
||||
bool playerIsInVehicle = playerVehicle != nullptr;
|
||||
|
||||
switch (garageInfo->type) {
|
||||
case GarageType::Mission: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::BombShop1: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::BombShop2: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::BombShop3: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::Respray: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::CollectCars1:
|
||||
case GarageType::CollectCars2: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::MissionForCarToComeOut: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::Crusher: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::MissionKeepCar: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::Hideout1:
|
||||
case GarageType::Hideout2:
|
||||
case GarageType::Hideout3: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::MissionToOpenAndClose: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::MissionForSpecificCar: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::MissionKeepCarAndRemainClosed: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GarageController::doOnCloseEvent() {
|
||||
auto controller = engine->players.at(0);
|
||||
auto plyChar = controller->getCharacter();
|
||||
auto playerPosition = plyChar->getPosition();
|
||||
auto playerVehicle = plyChar->getCurrentVehicle();
|
||||
bool playerIsInVehicle = playerVehicle != nullptr;
|
||||
|
||||
switch (garageInfo->type) {
|
||||
case GarageType::Mission: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::BombShop1:
|
||||
case GarageType::BombShop2:
|
||||
case GarageType::BombShop3: {
|
||||
// Find out real value
|
||||
garageTimer = engine->getGameTime() + 1.5f;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::Respray: {
|
||||
// Find out real value
|
||||
garageTimer = engine->getGameTime() + 2.f;
|
||||
playerVehicle->setHealth(1000.f);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::CollectCars1:
|
||||
case GarageType::CollectCars2: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::MissionForCarToComeOut: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::Crusher: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::MissionKeepCar: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::Hideout1:
|
||||
case GarageType::Hideout2:
|
||||
case GarageType::Hideout3: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::MissionToOpenAndClose: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::MissionForSpecificCar: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::MissionKeepCarAndRemainClosed: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GarageController::doOnStartOpeningEvent() {
|
||||
auto controller = engine->players.at(0);
|
||||
auto plyChar = controller->getCharacter();
|
||||
auto playerPosition = plyChar->getPosition();
|
||||
auto playerVehicle = plyChar->getCurrentVehicle();
|
||||
bool playerIsInVehicle = playerVehicle != nullptr;
|
||||
|
||||
switch (garageInfo->type) {
|
||||
case GarageType::Mission:
|
||||
case GarageType::CollectCars1:
|
||||
case GarageType::CollectCars2: {
|
||||
controller->setInputEnabled(true);
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::BombShop1:
|
||||
case GarageType::BombShop2:
|
||||
case GarageType::BombShop3:
|
||||
case GarageType::Respray: {
|
||||
controller->setInputEnabled(true);
|
||||
playerVehicle->setHandbraking(false);
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::MissionForCarToComeOut: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::Crusher: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::MissionKeepCar: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::Hideout1:
|
||||
case GarageType::Hideout2:
|
||||
case GarageType::Hideout3: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::MissionToOpenAndClose: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::MissionForSpecificCar: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::MissionKeepCarAndRemainClosed: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GarageController::doOnStartClosingEvent() {
|
||||
auto controller = engine->players.at(0);
|
||||
auto plyChar = controller->getCharacter();
|
||||
auto playerPosition = plyChar->getPosition();
|
||||
auto playerVehicle = plyChar->getCurrentVehicle();
|
||||
bool playerIsInVehicle = playerVehicle != nullptr;
|
||||
|
||||
switch (garageInfo->type) {
|
||||
case GarageType::Mission:
|
||||
case GarageType::CollectCars1:
|
||||
case GarageType::CollectCars2: {
|
||||
controller->setInputEnabled(false);
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::BombShop1:
|
||||
case GarageType::BombShop2:
|
||||
case GarageType::BombShop3:
|
||||
case GarageType::Respray: {
|
||||
controller->setInputEnabled(false);
|
||||
playerVehicle->setHandbraking(true);
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::MissionForCarToComeOut: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::Crusher: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::MissionKeepCar: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::MissionToOpenAndClose: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::MissionForSpecificCar: {
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageType::MissionKeepCarAndRemainClosed: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GarageController::tick(float dt) {
|
||||
if (!garageInfo) return;
|
||||
if (!doorObject) return;
|
||||
|
||||
needsToUpdate = false;
|
||||
|
||||
switch (garageInfo->state) {
|
||||
case GarageState::Opened: {
|
||||
if (shouldClose()) {
|
||||
garageInfo->state = GarageState::Closing;
|
||||
doOnStartClosingEvent();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageState::Closed: {
|
||||
if (shouldOpen()) {
|
||||
garageInfo->state = GarageState::Opening;
|
||||
doOnStartOpeningEvent();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageState::Opening: {
|
||||
if (shouldStopOpening()) {
|
||||
garageInfo->state = GarageState::Closing;
|
||||
} else {
|
||||
fraction += dt * step;
|
||||
|
||||
if (fraction >= 1.0f) {
|
||||
garageInfo->state = GarageState::Opened;
|
||||
fraction = 1.f;
|
||||
doOnOpenEvent();
|
||||
}
|
||||
|
||||
needsToUpdate = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case GarageState::Closing: {
|
||||
if (shouldStopClosing()) {
|
||||
garageInfo->state = GarageState::Opening;
|
||||
} else {
|
||||
fraction -= dt * step;
|
||||
|
||||
if (fraction <= 0.f) {
|
||||
garageInfo->state = GarageState::Closed;
|
||||
fraction = 0.f;
|
||||
doOnCloseEvent();
|
||||
}
|
||||
|
||||
needsToUpdate = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (needsToUpdate) {
|
||||
updateDoor();
|
||||
}
|
||||
}
|
||||
|
||||
void GarageController::updateDoor() {
|
||||
if (swingType) {
|
||||
// @todo incomplete
|
||||
doorObject->setRotation(
|
||||
glm::angleAxis(fraction * 1.57079632679f, glm::vec3(0, 1, 0)));
|
||||
} else {
|
||||
doorObject->setPosition(startPosition +
|
||||
glm::vec3(0.f, 0.f, fraction * doorHeight));
|
||||
}
|
||||
}
|
59
rwengine/src/engine/GarageController.hpp
Normal file
59
rwengine/src/engine/GarageController.hpp
Normal file
@ -0,0 +1,59 @@
|
||||
#ifndef _RWENGINE_GARAGECONTROLLER_HPP_
|
||||
#define _RWENGINE_GARAGECONTROLLER_HPP_
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <rw/defines.hpp>
|
||||
|
||||
class PlayerController;
|
||||
|
||||
struct GarageInfo;
|
||||
|
||||
class GameWorld;
|
||||
|
||||
class CharacterObject;
|
||||
class InstanceObject;
|
||||
class GameObject;
|
||||
|
||||
class GarageController {
|
||||
private:
|
||||
float garageTimer = 0.f;
|
||||
|
||||
bool swingType;
|
||||
|
||||
glm::vec3 startPosition;
|
||||
glm::quat startRotation;
|
||||
|
||||
bool needsToUpdate;
|
||||
|
||||
float fraction;
|
||||
float step;
|
||||
float doorHeight;
|
||||
|
||||
float getDistanceToGarage(glm::vec3 point);
|
||||
bool isObjectInsideGarage(GameObject* object);
|
||||
|
||||
bool shouldOpen();
|
||||
bool shouldClose();
|
||||
bool shouldStopOpening();
|
||||
bool shouldStopClosing();
|
||||
|
||||
void doOnOpenEvent();
|
||||
void doOnCloseEvent();
|
||||
void doOnStartOpeningEvent();
|
||||
void doOnStartClosingEvent();
|
||||
|
||||
void updateDoor();
|
||||
|
||||
public:
|
||||
GameWorld* engine;
|
||||
GarageInfo* garageInfo;
|
||||
InstanceObject* doorObject;
|
||||
|
||||
GarageController(GameWorld* engine, GarageInfo* info, InstanceObject* door);
|
||||
~GarageController();
|
||||
|
||||
void tick(float dt);
|
||||
};
|
||||
|
||||
#endif
|
@ -1263,7 +1263,7 @@ bool SaveGame::loadGame(GameState& state, const std::string& file) {
|
||||
auto& garage = garages[g];
|
||||
state.garages.emplace_back(
|
||||
(int)g, glm::vec3(garage.x1, garage.y1, garage.z1),
|
||||
glm::vec3(garage.x2, garage.y2, garage.z2), garage.type);
|
||||
glm::vec3(garage.x2, garage.y2, garage.z2), static_cast<GarageType>(garage.type));
|
||||
}
|
||||
for (auto &c : garageData.cars) {
|
||||
if (c.modelId == 0) continue;
|
||||
|
@ -48,6 +48,10 @@ InstanceObject::InstanceObject(GameWorld* engine, const glm::vec3& pos,
|
||||
engine->aigraph.createPathNodes(position, rot, path);
|
||||
}
|
||||
}
|
||||
|
||||
if (SimpleModelInfo::isDoorModel(modelinfo->name)) {
|
||||
setStatic(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6094,17 +6094,10 @@ void opcode_0218(const ScriptArguments& args, const ScriptString gxtEntry, const
|
||||
@arg arg7
|
||||
@arg garage
|
||||
*/
|
||||
void opcode_0219(const ScriptArguments& args, ScriptVec3 coord0, ScriptVec3 coord1, const ScriptInt arg7, ScriptGarage& garage) {
|
||||
auto& garages = args.getState()->garages;
|
||||
int id = garages.size();
|
||||
auto info= GarageInfo {
|
||||
id,
|
||||
coord0,
|
||||
coord1,
|
||||
arg7
|
||||
};
|
||||
garages.push_back(info);
|
||||
garage = &info;
|
||||
void opcode_0219(const ScriptArguments& args, ScriptVec3 coord0,
|
||||
ScriptVec3 coord1, const ScriptInt type,
|
||||
ScriptGarage& garage) {
|
||||
garage = args.getWorld()->createGarage(coord0, coord1, type);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -8188,6 +8181,7 @@ void opcode_02fa(const ScriptArguments& args, const ScriptGarage garage0, const
|
||||
@arg arg10
|
||||
*/
|
||||
void opcode_02fb(const ScriptArguments& args, const ScriptFloat arg1, const ScriptFloat arg2, const ScriptFloat arg3, const ScriptFloat arg4, const ScriptFloat arg5, const ScriptFloat arg6, const ScriptFloat arg7, const ScriptFloat arg8, const ScriptFloat arg9, const ScriptFloat arg10) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x02fb);
|
||||
RW_UNUSED(arg1);
|
||||
RW_UNUSED(arg2);
|
||||
RW_UNUSED(arg3);
|
||||
@ -8198,29 +8192,6 @@ void opcode_02fb(const ScriptArguments& args, const ScriptFloat arg1, const Scri
|
||||
RW_UNUSED(arg8);
|
||||
RW_UNUSED(arg9);
|
||||
RW_UNUSED(arg10);
|
||||
glm::vec2 crane_location(args[0].real, args[1].real);
|
||||
glm::vec2 park_min(args[2].real, args[3].real);
|
||||
glm::vec2 park_max(args[4].real, args[5].real);
|
||||
glm::vec3 crusher_position(args[6].real, args[7].real, args[8].real);
|
||||
float crusher_heading = args[9].real;
|
||||
|
||||
RW_UNIMPLEMENTED("create_crusher_crane is incomplete");
|
||||
/// @todo check how to store all parameters and how to create the actual crusher
|
||||
RW_UNUSED(crane_location);
|
||||
RW_UNUSED(crusher_position);
|
||||
/// @todo check how the savegame stores the heading value etc.
|
||||
RW_UNUSED(crusher_heading);
|
||||
|
||||
// NOTE: These values come from a savegame from the original game
|
||||
glm::vec3 min(park_min, -1.f);
|
||||
glm::vec3 max(park_max, 3.5f);
|
||||
int garageType = GarageInfo::GARAGE_CRUSHER;
|
||||
|
||||
// NOTE: This instruction also creates or controls a garage
|
||||
/// @todo find out if this creates a garage or if it just controls garage[0]
|
||||
args.getWorld()->state->garages.push_back({
|
||||
0, min, max, garageType
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -8917,7 +8888,7 @@ void opcode_0327(const ScriptArguments& args, ScriptVec2 coord0, ScriptVec2 coor
|
||||
@arg garage Handle
|
||||
*/
|
||||
bool opcode_0329(const ScriptArguments& args, const ScriptGarage garage) {
|
||||
if (garage->type != GarageInfo::GARAGE_RESPRAY) {
|
||||
if (garage->type != GarageType::Respray) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -11334,15 +11305,16 @@ bool opcode_03d4(const ScriptArguments& args, const ScriptGarage garage, const S
|
||||
RW_CHECK(entryIndex >= 0, "Entry index too low");
|
||||
RW_CHECK(entryIndex < 32, "Entry index too high");
|
||||
|
||||
if (garage->type == GarageInfo::GARAGE_COLLECTCARS1) {
|
||||
// @todo reimplement
|
||||
if (garage->type == GarageType::CollectCars1) {
|
||||
return args.getState()->importExportPortland[entryIndex];
|
||||
}
|
||||
if (garage->type == GarageInfo::GARAGE_COLLECTCARS2) {
|
||||
if (garage->type == GarageType::CollectCars2) {
|
||||
return args.getState()->importExportShoreside[entryIndex];
|
||||
}
|
||||
if (garage->type == GarageInfo::GARAGE_COLLECTCARS3) {
|
||||
return args.getState()->importExportUnused[entryIndex];
|
||||
}
|
||||
// if (garage->type == GarageType::CollectCars3) {
|
||||
// return args.getState()->importExportUnused[entryIndex];
|
||||
// }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -26,10 +26,14 @@
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
const std::map<GameRenderer::SpecialModel, std::pair<std::string,std::string>> kSpecialModels = {
|
||||
{GameRenderer::ZoneCylinderA, std::pair<std::string,std::string>("zonecyla.dff", "particle")},
|
||||
{GameRenderer::ZoneCylinderB, std::pair<std::string,std::string>("zonecylb.dff", "particle")},
|
||||
{GameRenderer::Arrow, std::pair<std::string,std::string>("arrow.dff", "")}};
|
||||
const std::map<GameRenderer::SpecialModel, std::pair<std::string, std::string>>
|
||||
kSpecialModels = {
|
||||
{GameRenderer::ZoneCylinderA,
|
||||
std::pair<std::string, std::string>("zonecyla.dff", "particle")},
|
||||
{GameRenderer::ZoneCylinderB,
|
||||
std::pair<std::string, std::string>("zonecylb.dff", "particle")},
|
||||
{GameRenderer::Arrow,
|
||||
std::pair<std::string, std::string>("arrow.dff", "")}};
|
||||
|
||||
namespace {
|
||||
constexpr float kMaxPhysicsSubSteps = 2;
|
||||
@ -523,6 +527,10 @@ void RWGame::tick(float dt) {
|
||||
object->tick(dt);
|
||||
}
|
||||
|
||||
for (auto& gc : world->garageControllers) {
|
||||
gc->tick(dt);
|
||||
}
|
||||
|
||||
world->destroyQueuedObjects();
|
||||
|
||||
state.text.tick(dt);
|
||||
|
Loading…
Reference in New Issue
Block a user