mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-23 19:02:39 +01:00
Garages continuation
This commit is contained in:
parent
10ef3448aa
commit
92d2a614b7
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,3 +5,4 @@ documentation/
|
||||
*swp
|
||||
*.user*
|
||||
.DS_Store
|
||||
.vscode/
|
||||
|
@ -61,8 +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/Garage.cpp
|
||||
src/engine/Garage.hpp
|
||||
src/engine/Payphone.cpp
|
||||
src/engine/Payphone.hpp
|
||||
src/engine/SaveGame.cpp
|
||||
|
@ -211,56 +211,6 @@ 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 {
|
||||
GarageType type;
|
||||
|
||||
int id;
|
||||
glm::vec3 min;
|
||||
glm::vec3 max;
|
||||
|
||||
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 {
|
||||
return id;
|
||||
}
|
||||
};
|
||||
|
||||
enum class HudFlash {
|
||||
Disabled = -1,
|
||||
FlashArmor = 3,
|
||||
@ -406,8 +356,6 @@ public:
|
||||
|
||||
std::map<int, BlipData> radarBlips;
|
||||
|
||||
std::vector<GarageInfo> garages;
|
||||
|
||||
/**
|
||||
* Bitsets for the car import / export list mission
|
||||
*/
|
||||
|
@ -386,77 +386,11 @@ 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;
|
||||
Garage* GameWorld::createGarage(const glm::vec3 coord0, const glm::vec3 coord1,
|
||||
Garage::Type type) {
|
||||
const int id = garages.size();
|
||||
garages.emplace_back(std::make_unique<Garage>(this, id, coord0, coord1, type));
|
||||
return garages.back().get();
|
||||
}
|
||||
|
||||
Payphone* GameWorld::createPayphone(const glm::vec2 coord) {
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include <ai/AIGraphNode.hpp>
|
||||
#include <audio/SoundManager.hpp>
|
||||
|
||||
#include <engine/GarageController.hpp>
|
||||
#include <engine/Garage.hpp>
|
||||
#include <engine/Payphone.hpp>
|
||||
#include <objects/ObjectTypes.hpp>
|
||||
|
||||
@ -35,7 +35,7 @@ class btSequentialImpulseConstraintSolver;
|
||||
struct btDbvtBroadphase;
|
||||
|
||||
class GameState;
|
||||
class GarageController;
|
||||
class Garage;
|
||||
class Payphone;
|
||||
|
||||
class PlayerController;
|
||||
@ -150,8 +150,8 @@ public:
|
||||
/**
|
||||
* Creates a garage
|
||||
*/
|
||||
GarageInfo* createGarage(const glm::vec3 coord0, const glm::vec3 coord1,
|
||||
const int type);
|
||||
Garage* createGarage(const glm::vec3 coord0, const glm::vec3 coord1,
|
||||
Garage::Type type);
|
||||
|
||||
/**
|
||||
* Creates a payphone
|
||||
@ -271,7 +271,7 @@ public:
|
||||
|
||||
std::vector<PlayerController*> players;
|
||||
|
||||
std::vector<std::unique_ptr<GarageController>> garageControllers;
|
||||
std::vector<std::unique_ptr<Garage>> garages;
|
||||
|
||||
std::vector<std::unique_ptr<Payphone>> payphones;
|
||||
|
||||
|
886
rwengine/src/engine/Garage.cpp
Normal file
886
rwengine/src/engine/Garage.cpp
Normal file
@ -0,0 +1,886 @@
|
||||
#include "Garage.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"
|
||||
|
||||
Garage::Garage(GameWorld* engine_, const int id_, const glm::vec3 coord0,
|
||||
const glm::vec3 coord1, const Type type_)
|
||||
: engine(engine_), id(id_), type(type_) {
|
||||
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);
|
||||
|
||||
glm::vec2 midpoint;
|
||||
midpoint.x = (min.x + max.x) / 2;
|
||||
midpoint.y = (min.y + max.y) / 2;
|
||||
|
||||
// Find door objects for this garage
|
||||
for (const auto p : engine->instancePool.objects) {
|
||||
const auto inst = static_cast<InstanceObject*>(p.second);
|
||||
|
||||
if (!inst->getModel()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!SimpleModelInfo::isDoorModel(
|
||||
inst->getModelInfo<BaseModelInfo>()->name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto instPos = inst->getPosition();
|
||||
const auto xDist = std::abs(instPos.x - midpoint.x);
|
||||
const auto yDist = std::abs(instPos.y - midpoint.y);
|
||||
|
||||
if (xDist < 20.f && yDist < 20.f) {
|
||||
if (!doorObject) {
|
||||
doorObject = inst;
|
||||
continue;
|
||||
} else {
|
||||
secondDoorObject = inst;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (doorObject) {
|
||||
startPosition = doorObject->getPosition();
|
||||
|
||||
// Setup door height based on model's bounding box
|
||||
auto doorModel = doorObject->getModelInfo<BaseModelInfo>();
|
||||
auto collision = doorModel->getCollision();
|
||||
// Original behavior - game actually subtracts 0.1f
|
||||
doorHeight =
|
||||
collision->boundingBox.max.z - collision->boundingBox.min.z - 0.1f;
|
||||
}
|
||||
|
||||
if (secondDoorObject) {
|
||||
startPositionSecondDoor = secondDoorObject->getPosition();
|
||||
}
|
||||
|
||||
step /= doorHeight;
|
||||
|
||||
switch (type) {
|
||||
case Garage::Type::Mission:
|
||||
case Garage::Type::CollectCars1:
|
||||
case Garage::Type::CollectCars2:
|
||||
case Garage::Type::MissionForCarToComeOut:
|
||||
case Garage::Type::MissionKeepCar:
|
||||
case Garage::Type::Hideout1:
|
||||
case Garage::Type::Hideout2:
|
||||
case Garage::Type::Hideout3:
|
||||
case Garage::Type::MissionToOpenAndClose:
|
||||
case Garage::Type::MissionForSpecificCar:
|
||||
case Garage::Type::MissionKeepCarAndRemainClosed: {
|
||||
state = State::Closed;
|
||||
break;
|
||||
}
|
||||
|
||||
case Garage::Type::BombShop1:
|
||||
case Garage::Type::BombShop2:
|
||||
case Garage::Type::BombShop3:
|
||||
case Garage::Type::Respray:
|
||||
case Garage::Type::Crusher: {
|
||||
state = State::Opened;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (state == State::Closed) {
|
||||
fraction = 0.f;
|
||||
} else {
|
||||
fraction = 1.f;
|
||||
}
|
||||
|
||||
if (doorObject) {
|
||||
updateDoor();
|
||||
}
|
||||
}
|
||||
|
||||
void Garage::makeDoorSwing() {
|
||||
// This is permanent, you can't restore it
|
||||
// back to non swing just like in original game
|
||||
// Values are from original game
|
||||
if (!swingType) {
|
||||
swingType = true;
|
||||
doorHeight /= 2.0f;
|
||||
doorHeight -= 0.1f;
|
||||
}
|
||||
}
|
||||
|
||||
bool Garage::isTargetInsideGarage() const {
|
||||
return state == State::Closed && isObjectInsideGarage(target);
|
||||
}
|
||||
|
||||
void Garage::activate() {
|
||||
active = true;
|
||||
|
||||
if (type == Type::MissionForCarToComeOut && state == State::Closed) {
|
||||
state = State::Opening;
|
||||
}
|
||||
}
|
||||
|
||||
void Garage::deactivate() {
|
||||
active = false;
|
||||
}
|
||||
|
||||
void Garage::open() {
|
||||
if (state == State::Closed || state == State::Closing) {
|
||||
state = State::Opening;
|
||||
}
|
||||
}
|
||||
|
||||
void Garage::close() {
|
||||
if (state == State::Opened || state == State::Opening) {
|
||||
state = State::Closing;
|
||||
}
|
||||
}
|
||||
|
||||
float Garage::getDistanceToGarage(const glm::vec3 point) {
|
||||
// Seems like original game ignores z axis
|
||||
float dx = std::max({min.x - point.x, 0.f, point.x - max.x});
|
||||
float dy = std::max({min.y - point.y, 0.f, point.y - max.y});
|
||||
|
||||
return std::sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
bool Garage::isObjectInsideGarage(GameObject* object) const {
|
||||
auto p = object->getPosition();
|
||||
|
||||
// Do basic check first
|
||||
if (p.x < min.x) return false;
|
||||
if (p.y < min.y) return false;
|
||||
if (p.z < min.z) return false;
|
||||
if (p.x > max.x) return false;
|
||||
if (p.y > max.y) return false;
|
||||
if (p.z > max.z) return false;
|
||||
|
||||
// Now check if all collision spheres are inside
|
||||
// garage's bounding box
|
||||
auto objectModel = object->getModelInfo<BaseModelInfo>();
|
||||
auto collision = objectModel->getCollision();
|
||||
// Peds don't have collisions currently?
|
||||
if (collision) {
|
||||
for (auto& sphere : collision->spheres) {
|
||||
auto c = p + sphere.center;
|
||||
auto r = sphere.radius;
|
||||
if (c.x + r < min.x) return false;
|
||||
if (c.y + r < min.y) return false;
|
||||
if (c.z + r < min.z) return false;
|
||||
if (c.x - r > max.x) return false;
|
||||
if (c.y - r > max.y) return false;
|
||||
if (c.z - r > max.z) return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Garage::shouldClose() {
|
||||
auto player = engine->getPlayer();
|
||||
auto plyChar = player->getCharacter();
|
||||
auto playerPosition = plyChar->getPosition();
|
||||
auto playerVehicle = plyChar->getCurrentVehicle();
|
||||
bool playerIsInVehicle = playerVehicle != nullptr;
|
||||
|
||||
switch (type) {
|
||||
case Type::Mission: {
|
||||
if (!isObjectInsideGarage(static_cast<GameObject*>(plyChar)) &&
|
||||
isObjectInsideGarage(target) && !playerIsInVehicle &&
|
||||
getDistanceToGarage(playerPosition) >= 2.f) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::BombShop1:
|
||||
case Type::BombShop2:
|
||||
case Type::BombShop3: {
|
||||
if (playerIsInVehicle) {
|
||||
if (isObjectInsideGarage(
|
||||
static_cast<GameObject*>(playerVehicle)) &&
|
||||
playerVehicle->isStopped()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::Respray: {
|
||||
if (playerIsInVehicle) {
|
||||
if (isObjectInsideGarage(
|
||||
static_cast<GameObject*>(playerVehicle)) &&
|
||||
playerVehicle->isStopped() && !resprayDone) {
|
||||
return true;
|
||||
} else if (!isObjectInsideGarage(
|
||||
static_cast<GameObject*>(playerVehicle)) &&
|
||||
getDistanceToGarage(playerVehicle->getPosition()) >=
|
||||
2.f &&
|
||||
resprayDone) {
|
||||
resprayDone = false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::CollectCars1:
|
||||
case Type::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 Type::MissionForCarToComeOut: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::Crusher: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::MissionKeepCar: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::Hideout1:
|
||||
case Type::Hideout2:
|
||||
case Type::Hideout3: {
|
||||
// Not sure about these values
|
||||
if ((!playerIsInVehicle &&
|
||||
getDistanceToGarage(playerPosition) >= 5.f) ||
|
||||
(playerIsInVehicle &&
|
||||
getDistanceToGarage(playerPosition) >= 10.f)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::MissionToOpenAndClose: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::MissionForSpecificCar: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::MissionKeepCarAndRemainClosed: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
default: { return false; }
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Garage::shouldOpen() {
|
||||
auto player = engine->getPlayer();
|
||||
auto plyChar = player->getCharacter();
|
||||
auto playerPosition = plyChar->getPosition();
|
||||
auto playerVehicle = plyChar->getCurrentVehicle();
|
||||
bool playerIsInVehicle = playerVehicle != nullptr;
|
||||
|
||||
switch (type) {
|
||||
case Type::Mission: {
|
||||
// Not sure about these values
|
||||
if (playerIsInVehicle &&
|
||||
getDistanceToGarage(playerPosition) < 8.f &&
|
||||
playerVehicle == target) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::BombShop1:
|
||||
case Type::BombShop2:
|
||||
case Type::BombShop3:
|
||||
case Type::Respray: {
|
||||
if (garageTimer < engine->getGameTime()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::CollectCars1:
|
||||
case Type::CollectCars2: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::MissionForCarToComeOut: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::Crusher: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::MissionKeepCar: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::Hideout1:
|
||||
case Type::Hideout2:
|
||||
case Type::Hideout3: {
|
||||
// Not sure about these values
|
||||
if ((!playerIsInVehicle &&
|
||||
getDistanceToGarage(playerPosition) < 5.f) ||
|
||||
(playerIsInVehicle &&
|
||||
getDistanceToGarage(playerPosition) < 10.f)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::MissionToOpenAndClose: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::MissionForSpecificCar: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::MissionKeepCarAndRemainClosed: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
default: { return false; }
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Garage::shouldStopClosing() {
|
||||
auto player = engine->getPlayer();
|
||||
auto plyChar = player->getCharacter();
|
||||
auto playerPosition = plyChar->getPosition();
|
||||
auto playerVehicle = plyChar->getCurrentVehicle();
|
||||
bool playerIsInVehicle = playerVehicle != nullptr;
|
||||
|
||||
switch (type) {
|
||||
case Type::Mission:
|
||||
case Type::BombShop1:
|
||||
case Type::BombShop2:
|
||||
case Type::BombShop3:
|
||||
case Type::Respray:
|
||||
case Type::CollectCars1:
|
||||
case Type::CollectCars2: {
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::MissionForCarToComeOut: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::Crusher: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::MissionKeepCar: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::Hideout1:
|
||||
case Type::Hideout2:
|
||||
case Type::Hideout3: {
|
||||
// Not sure about these values
|
||||
if ((!playerIsInVehicle &&
|
||||
getDistanceToGarage(playerPosition) < 5.f) ||
|
||||
(playerIsInVehicle &&
|
||||
getDistanceToGarage(playerPosition) < 10.f)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::MissionToOpenAndClose: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::MissionForSpecificCar: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::MissionKeepCarAndRemainClosed: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
default: { return false; }
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Garage::shouldStopOpening() {
|
||||
auto player = engine->getPlayer();
|
||||
auto plyChar = player->getCharacter();
|
||||
auto playerPosition = plyChar->getPosition();
|
||||
auto playerVehicle = plyChar->getCurrentVehicle();
|
||||
bool playerIsInVehicle = playerVehicle != nullptr;
|
||||
|
||||
switch (type) {
|
||||
case Type::Mission:
|
||||
case Type::BombShop1:
|
||||
case Type::BombShop2:
|
||||
case Type::BombShop3:
|
||||
case Type::Respray:
|
||||
case Type::CollectCars1:
|
||||
case Type::CollectCars2: {
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::MissionForCarToComeOut: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::Crusher: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::MissionKeepCar: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::Hideout1:
|
||||
case Type::Hideout2:
|
||||
case Type::Hideout3: {
|
||||
// Not sure about these values
|
||||
if ((!playerIsInVehicle &&
|
||||
getDistanceToGarage(playerPosition) >= 5.f) ||
|
||||
(playerIsInVehicle &&
|
||||
getDistanceToGarage(playerPosition) >= 10.f)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::MissionToOpenAndClose: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::MissionForSpecificCar: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
case Type::MissionKeepCarAndRemainClosed: {
|
||||
// @todo unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
default: { return false; }
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Garage::doOnOpenEvent() {
|
||||
auto player = engine->getPlayer();
|
||||
auto plyChar = player->getCharacter();
|
||||
auto playerPosition = plyChar->getPosition();
|
||||
auto playerVehicle = plyChar->getCurrentVehicle();
|
||||
bool playerIsInVehicle = playerVehicle != nullptr;
|
||||
RW_UNUSED(playerPosition);
|
||||
RW_UNUSED(playerIsInVehicle);
|
||||
|
||||
switch (type) {
|
||||
case Type::Mission: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::BombShop1: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::BombShop2: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::BombShop3: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::Respray: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::CollectCars1:
|
||||
case Type::CollectCars2: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::MissionForCarToComeOut: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::Crusher: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::MissionKeepCar: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::Hideout1:
|
||||
case Type::Hideout2:
|
||||
case Type::Hideout3: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::MissionToOpenAndClose: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::MissionForSpecificCar: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::MissionKeepCarAndRemainClosed: {
|
||||
break;
|
||||
}
|
||||
|
||||
default: { break; }
|
||||
}
|
||||
}
|
||||
|
||||
void Garage::doOnCloseEvent() {
|
||||
auto player = engine->getPlayer();
|
||||
auto plyChar = player->getCharacter();
|
||||
auto playerPosition = plyChar->getPosition();
|
||||
auto playerVehicle = plyChar->getCurrentVehicle();
|
||||
bool playerIsInVehicle = playerVehicle != nullptr;
|
||||
RW_UNUSED(playerPosition);
|
||||
RW_UNUSED(playerIsInVehicle);
|
||||
|
||||
switch (type) {
|
||||
case Type::Mission: {
|
||||
player->setInputEnabled(true);
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::BombShop1:
|
||||
case Type::BombShop2:
|
||||
case Type::BombShop3: {
|
||||
// Find out real value
|
||||
garageTimer = engine->getGameTime() + 1.5f;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::Respray: {
|
||||
// Find out real value
|
||||
garageTimer = engine->getGameTime() + 2.f;
|
||||
playerVehicle->setHealth(1000.f);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::CollectCars1:
|
||||
case Type::CollectCars2: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::MissionForCarToComeOut: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::Crusher: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::MissionKeepCar: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::Hideout1:
|
||||
case Type::Hideout2:
|
||||
case Type::Hideout3: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::MissionToOpenAndClose: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::MissionForSpecificCar: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::MissionKeepCarAndRemainClosed: {
|
||||
break;
|
||||
}
|
||||
|
||||
default: { break; }
|
||||
}
|
||||
}
|
||||
|
||||
void Garage::doOnStartOpeningEvent() {
|
||||
auto player = engine->getPlayer();
|
||||
auto plyChar = player->getCharacter();
|
||||
auto playerPosition = plyChar->getPosition();
|
||||
auto playerVehicle = plyChar->getCurrentVehicle();
|
||||
bool playerIsInVehicle = playerVehicle != nullptr;
|
||||
RW_UNUSED(playerPosition);
|
||||
RW_UNUSED(playerIsInVehicle);
|
||||
|
||||
switch (type) {
|
||||
case Type::Mission: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::CollectCars1:
|
||||
case Type::CollectCars2: {
|
||||
player->setInputEnabled(true);
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::BombShop1:
|
||||
case Type::BombShop2:
|
||||
case Type::BombShop3: {
|
||||
player->setInputEnabled(true);
|
||||
playerVehicle->setHandbraking(false);
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::Respray: {
|
||||
player->setInputEnabled(true);
|
||||
playerVehicle->setHandbraking(false);
|
||||
resprayDone = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::MissionForCarToComeOut: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::Crusher: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::MissionKeepCar: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::Hideout1:
|
||||
case Type::Hideout2:
|
||||
case Type::Hideout3: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::MissionToOpenAndClose: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::MissionForSpecificCar: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::MissionKeepCarAndRemainClosed: {
|
||||
break;
|
||||
}
|
||||
|
||||
default: { break; }
|
||||
}
|
||||
}
|
||||
|
||||
void Garage::doOnStartClosingEvent() {
|
||||
auto player = engine->getPlayer();
|
||||
auto plyChar = player->getCharacter();
|
||||
auto playerPosition = plyChar->getPosition();
|
||||
auto playerVehicle = plyChar->getCurrentVehicle();
|
||||
bool playerIsInVehicle = playerVehicle != nullptr;
|
||||
RW_UNUSED(playerPosition);
|
||||
RW_UNUSED(playerIsInVehicle);
|
||||
|
||||
switch (type) {
|
||||
case Type::Mission:
|
||||
case Type::CollectCars1:
|
||||
case Type::CollectCars2: {
|
||||
player->setInputEnabled(false);
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::BombShop1:
|
||||
case Type::BombShop2:
|
||||
case Type::BombShop3:
|
||||
case Type::Respray: {
|
||||
player->setInputEnabled(false);
|
||||
playerVehicle->setHandbraking(true);
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::MissionForCarToComeOut: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::Crusher: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::MissionKeepCar: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::MissionToOpenAndClose: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::MissionForSpecificCar: {
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::MissionKeepCarAndRemainClosed: {
|
||||
break;
|
||||
}
|
||||
|
||||
default: { break; }
|
||||
}
|
||||
}
|
||||
|
||||
void Garage::tick(float dt) {
|
||||
if (!doorObject) {
|
||||
return;
|
||||
}
|
||||
if (!active) {
|
||||
return;
|
||||
}
|
||||
|
||||
needsToUpdate = false;
|
||||
|
||||
switch (state) {
|
||||
case State::Opened: {
|
||||
if (shouldClose()) {
|
||||
state = State::Closing;
|
||||
doOnStartClosingEvent();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case State::Closed: {
|
||||
if (shouldOpen()) {
|
||||
state = State::Opening;
|
||||
doOnStartOpeningEvent();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case State::Opening: {
|
||||
if (shouldStopOpening()) {
|
||||
state = State::Closing;
|
||||
} else {
|
||||
fraction += dt * step;
|
||||
|
||||
if (fraction >= 1.0f) {
|
||||
state = State::Opened;
|
||||
fraction = 1.f;
|
||||
doOnOpenEvent();
|
||||
}
|
||||
|
||||
needsToUpdate = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case State::Closing: {
|
||||
if (shouldStopClosing()) {
|
||||
state = State::Opening;
|
||||
} else {
|
||||
fraction -= dt * step;
|
||||
|
||||
if (fraction <= 0.f) {
|
||||
state = State::Closed;
|
||||
fraction = 0.f;
|
||||
doOnCloseEvent();
|
||||
}
|
||||
|
||||
needsToUpdate = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: { break; }
|
||||
}
|
||||
|
||||
if (needsToUpdate) {
|
||||
updateDoor();
|
||||
}
|
||||
}
|
||||
|
||||
void Garage::updateDoor() {
|
||||
if (swingType) {
|
||||
doorObject->setRotation(glm::angleAxis(fraction * glm::radians(90.f),
|
||||
glm::vec3(0.f, 1.f, 0.f)));
|
||||
|
||||
if (secondDoorObject) {
|
||||
secondDoorObject->setRotation(glm::angleAxis(
|
||||
fraction * glm::radians(90.f), glm::vec3(0.f, 1.f, 0.f)));
|
||||
}
|
||||
}
|
||||
|
||||
doorObject->setPosition(startPosition +
|
||||
glm::vec3(0.f, 0.f, fraction * doorHeight));
|
||||
|
||||
if (secondDoorObject) {
|
||||
secondDoorObject->setPosition(
|
||||
startPositionSecondDoor +
|
||||
glm::vec3(0.f, 0.f, fraction * doorHeight));
|
||||
}
|
||||
}
|
112
rwengine/src/engine/Garage.hpp
Normal file
112
rwengine/src/engine/Garage.hpp
Normal file
@ -0,0 +1,112 @@
|
||||
#ifndef _RWENGINE_Garage_HPP_
|
||||
#define _RWENGINE_Garage_HPP_
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <rw/defines.hpp>
|
||||
|
||||
class PlayerController;
|
||||
|
||||
class GameWorld;
|
||||
|
||||
class CharacterObject;
|
||||
class InstanceObject;
|
||||
class GameObject;
|
||||
|
||||
class Garage {
|
||||
private:
|
||||
InstanceObject* doorObject = nullptr;
|
||||
InstanceObject* secondDoorObject = nullptr;
|
||||
|
||||
bool active = true;
|
||||
|
||||
float garageTimer = 0.f;
|
||||
|
||||
bool swingType = false;
|
||||
|
||||
glm::vec3 startPosition;
|
||||
glm::vec3 startPositionSecondDoor;
|
||||
|
||||
bool needsToUpdate = false;
|
||||
|
||||
float fraction = 0.f;
|
||||
float step = 3.f; // this should be adjusted somehow
|
||||
// to look similar to original game
|
||||
float doorHeight = 4.f;
|
||||
|
||||
float getDistanceToGarage(glm::vec3 point);
|
||||
|
||||
bool shouldOpen();
|
||||
bool shouldClose();
|
||||
bool shouldStopOpening();
|
||||
bool shouldStopClosing();
|
||||
|
||||
void doOnOpenEvent();
|
||||
void doOnCloseEvent();
|
||||
void doOnStartOpeningEvent();
|
||||
void doOnStartClosingEvent();
|
||||
|
||||
void updateDoor();
|
||||
|
||||
public:
|
||||
// Garage types are from original game
|
||||
enum class Type {
|
||||
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 State { Closed, Closing, Opening, Opened };
|
||||
|
||||
GameWorld* engine;
|
||||
int id;
|
||||
|
||||
int getScriptObjectID() const {
|
||||
return id;
|
||||
}
|
||||
|
||||
glm::vec3 min;
|
||||
glm::vec3 max;
|
||||
|
||||
Type type;
|
||||
|
||||
GameObject* target = nullptr;
|
||||
// @todo use model type
|
||||
int targetModel = 0;
|
||||
|
||||
State state = State::Closed;
|
||||
|
||||
bool resprayDone = false;
|
||||
|
||||
Garage(GameWorld* engine_, const int id_, const glm::vec3 coord0,
|
||||
const glm::vec3 coord1, const Type type_);
|
||||
~Garage() = default;
|
||||
|
||||
void makeDoorSwing();
|
||||
|
||||
bool isObjectInsideGarage(GameObject* object) const;
|
||||
bool isTargetInsideGarage() const;
|
||||
|
||||
void activate();
|
||||
void deactivate();
|
||||
|
||||
void open();
|
||||
void close();
|
||||
|
||||
void tick(float dt);
|
||||
};
|
||||
|
||||
#endif
|
@ -1,702 +0,0 @@
|
||||
#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));
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
#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
|
@ -1264,9 +1264,9 @@ bool SaveGame::loadGame(GameState& state, const std::string& file) {
|
||||
// http://gtaforums.com/topic/758692-gta-iii-save-file-documentation/
|
||||
for (size_t g = 0; g < garageData.garageCount; ++g) {
|
||||
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), static_cast<GarageType>(garage.type));
|
||||
state.world->createGarage(glm::vec3(garage.x1, garage.y1, garage.z1),
|
||||
glm::vec3(garage.x2, garage.y2, garage.z2),
|
||||
static_cast<Garage::Type>(garage.type));
|
||||
}
|
||||
for (auto &c : garageData.cars) {
|
||||
if (c.modelId == 0) continue;
|
||||
|
@ -140,7 +140,7 @@ void do_unpacked_call(Tret (*const& func)(Targs...),
|
||||
const ScriptArguments& args) {
|
||||
script_bind::binder<Tret, Targs...>::call(func, args);
|
||||
}
|
||||
}
|
||||
} // namespace script_bind
|
||||
|
||||
/**
|
||||
* Interface for a collection of functions that can be exported to a game script
|
||||
@ -154,8 +154,7 @@ void do_unpacked_call(Tret (*const& func)(Targs...),
|
||||
class ScriptModule {
|
||||
public:
|
||||
template <class String>
|
||||
ScriptModule(String&& _name)
|
||||
: name(std::forward<String>(_name)) {
|
||||
ScriptModule(String&& _name) : name(std::forward<String>(_name)) {
|
||||
}
|
||||
|
||||
const std::string& getName() const {
|
||||
|
@ -10,8 +10,8 @@
|
||||
#include "objects/InstanceObject.hpp"
|
||||
#include "objects/PickupObject.hpp"
|
||||
#include "objects/VehicleObject.hpp"
|
||||
#include "script/ScriptMachine.hpp"
|
||||
#include "script/SCMFile.hpp"
|
||||
#include "script/ScriptMachine.hpp"
|
||||
|
||||
GameState* ScriptArguments::getState() const {
|
||||
return getVM()->getState();
|
||||
@ -47,6 +47,12 @@ GameObject* ScriptArguments::getPlayerCharacter(unsigned int player) const {
|
||||
return controller->getCharacter();
|
||||
}
|
||||
|
||||
// @todo figure out original cast
|
||||
template <>
|
||||
ScriptGarageType ScriptArguments::getParameter<ScriptGarageType>(unsigned int arg) const {
|
||||
return static_cast<Garage::Type>(getParameters().at(arg).integerValue());
|
||||
}
|
||||
|
||||
template <>
|
||||
GameObject* ScriptArguments::getObject<PlayerController>(
|
||||
unsigned int arg) const {
|
||||
@ -208,14 +214,14 @@ ScriptObjectType<VehicleGenerator> ScriptArguments::getScriptObject(
|
||||
return {param.handleValue(), generator};
|
||||
}
|
||||
template <>
|
||||
ScriptObjectType<GarageInfo> ScriptArguments::getScriptObject(
|
||||
ScriptObjectType<Garage> ScriptArguments::getScriptObject(
|
||||
unsigned int arg) const {
|
||||
auto& param = (*this)[arg];
|
||||
RW_CHECK(param.isLvalue(), "Non lvalue passed as object");
|
||||
auto& garages = getWorld()->state->garages;
|
||||
GarageInfo* garage = nullptr;
|
||||
auto& garages = getWorld()->garages;
|
||||
Garage* garage = nullptr;
|
||||
if (size_t(*param.handleValue()) < garages.size()) {
|
||||
garage = &garages[*param.handleValue()];
|
||||
garage = garages[*param.handleValue()].get();
|
||||
}
|
||||
return {param.handleValue(), garage};
|
||||
}
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
#include <rw/defines.hpp>
|
||||
|
||||
#include "engine/Garage.hpp"
|
||||
|
||||
class CharacterObject;
|
||||
class CutsceneObject;
|
||||
class GameObject;
|
||||
@ -24,6 +26,7 @@ struct SCMThread;
|
||||
class GameState;
|
||||
class GameWorld;
|
||||
class Payphone;
|
||||
class Garage;
|
||||
|
||||
typedef uint16_t SCMOpcode;
|
||||
typedef char SCMByte;
|
||||
@ -98,14 +101,13 @@ using ScriptPlayer = ScriptObjectType<PlayerController>;
|
||||
using ScriptVehicle = ScriptObjectType<VehicleObject>;
|
||||
using ScriptCharacter = ScriptObjectType<CharacterObject>;
|
||||
using ScriptPickup = ScriptObjectType<PickupObject>;
|
||||
using ScriptGarage = ScriptObjectType<Garage>;
|
||||
|
||||
struct VehicleGenerator;
|
||||
struct BlipData;
|
||||
struct GarageInfo;
|
||||
|
||||
using ScriptVehicleGenerator = ScriptObjectType<VehicleGenerator>;
|
||||
using ScriptBlip = ScriptObjectType<BlipData>;
|
||||
using ScriptGarage = ScriptObjectType<GarageInfo>;
|
||||
using ScriptPayphone = ScriptObjectType<Payphone>;
|
||||
|
||||
/// @todo replace these with real types for sounds etc.
|
||||
@ -159,7 +161,7 @@ using ScriptParticle = int;
|
||||
using ScriptTempact = int;
|
||||
using ScriptSoundType = int;
|
||||
using ScriptPickupType = int;
|
||||
using ScriptGarageType = int;
|
||||
using ScriptGarageType = Garage::Type;
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// Script Bytecode Types
|
||||
@ -345,7 +347,7 @@ template <>
|
||||
ScriptObjectType<VehicleGenerator> ScriptArguments::getScriptObject(
|
||||
unsigned int arg) const;
|
||||
template <>
|
||||
ScriptObjectType<GarageInfo> ScriptArguments::getScriptObject(
|
||||
ScriptObjectType<Garage> ScriptArguments::getScriptObject(
|
||||
unsigned int arg) const;
|
||||
|
||||
typedef std::function<void(const ScriptArguments&)> ScriptFunction;
|
||||
|
@ -6103,8 +6103,8 @@ 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 type,
|
||||
void opcode_0219(const ScriptArguments& args, const ScriptVec3 coord0,
|
||||
const ScriptVec3 coord1, const ScriptGarageType type,
|
||||
ScriptGarage& garage) {
|
||||
garage = args.getWorld()->createGarage(coord0, coord1, type);
|
||||
}
|
||||
@ -6117,10 +6117,8 @@ void opcode_0219(const ScriptArguments& args, ScriptVec3 coord0,
|
||||
@arg vehicle Car/vehicle
|
||||
*/
|
||||
void opcode_021b(const ScriptArguments& args, const ScriptGarage garage, const ScriptVehicle vehicle) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x021b);
|
||||
RW_UNUSED(garage);
|
||||
RW_UNUSED(vehicle);
|
||||
RW_UNUSED(args);
|
||||
garage->target = vehicle.get();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -6130,16 +6128,8 @@ void opcode_021b(const ScriptArguments& args, const ScriptGarage garage, const S
|
||||
@arg garage
|
||||
*/
|
||||
bool opcode_021c(const ScriptArguments& args, const ScriptGarage garage) {
|
||||
auto& objects = args.getWorld()->vehiclePool.objects;
|
||||
for(auto& v : objects) {
|
||||
// @todo if this car only accepts mission cars we probably have to filter here / only check for one specific car
|
||||
auto vp = v.second->getPosition();
|
||||
if (vp.x >= garage->min.x && vp.y >= garage->min.y && vp.z >= garage->min.z &&
|
||||
vp.x <= garage->max.x && vp.y <= garage->max.y && vp.z <= garage->max.z) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
RW_UNUSED(args);
|
||||
return garage->isTargetInsideGarage();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -6843,9 +6833,8 @@ void opcode_0298(const ScriptArguments& args, const ScriptModelID model0, Script
|
||||
@arg garage
|
||||
*/
|
||||
void opcode_0299(const ScriptArguments& args, const ScriptGarage garage) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x0299);
|
||||
RW_UNUSED(garage);
|
||||
RW_UNUSED(args);
|
||||
garage->activate();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -7342,9 +7331,8 @@ bool opcode_02b8(const ScriptArguments& args, const ScriptPlayer player, ScriptV
|
||||
@arg garage
|
||||
*/
|
||||
void opcode_02b9(const ScriptArguments& args, const ScriptGarage garage) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x02b9);
|
||||
RW_UNUSED(garage);
|
||||
RW_UNUSED(args);
|
||||
garage->deactivate();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -8163,11 +8151,9 @@ void opcode_02f9(const ScriptArguments& args, const ScriptVehicle vehicle, Scrip
|
||||
@arg garage0
|
||||
@arg garage1
|
||||
*/
|
||||
void opcode_02fa(const ScriptArguments& args, const ScriptGarage garage0, const ScriptGarageType garage1) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x02fa);
|
||||
RW_UNUSED(garage0);
|
||||
RW_UNUSED(garage1);
|
||||
void opcode_02fa(const ScriptArguments& args, const ScriptGarage garage, const ScriptGarageType garageType) {
|
||||
RW_UNUSED(args);
|
||||
garage->type = garageType;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -8894,18 +8880,8 @@ 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 != GarageType::Respray) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto playerobj = args.getWorld()->pedestrianPool.find(args.getState()->playerObject);
|
||||
auto pp = playerobj->getPosition();
|
||||
if (pp.x >= garage->min.x && pp.y >= garage->min.y && pp.z >= garage->min.z &&
|
||||
pp.x <= garage->max.x && pp.y <= garage->max.y && pp.z <= garage->max.z) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
RW_UNUSED(args);
|
||||
return garage->resprayDone;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -9584,9 +9560,8 @@ void opcode_035f(const ScriptArguments& args, const ScriptCharacter character, c
|
||||
@arg garage
|
||||
*/
|
||||
void opcode_0360(const ScriptArguments& args, const ScriptGarage garage) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x0360);
|
||||
RW_UNUSED(garage);
|
||||
RW_UNUSED(args);
|
||||
garage->open();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -9596,9 +9571,8 @@ void opcode_0360(const ScriptArguments& args, const ScriptGarage garage) {
|
||||
@arg garage
|
||||
*/
|
||||
void opcode_0361(const ScriptArguments& args, const ScriptGarage garage) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x0361);
|
||||
RW_UNUSED(garage);
|
||||
RW_UNUSED(args);
|
||||
garage->close();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -10698,12 +10672,11 @@ void opcode_03a4(const ScriptArguments& args, const ScriptString name) {
|
||||
@arg garage1
|
||||
@arg model
|
||||
*/
|
||||
void opcode_03a5(const ScriptArguments& args, const ScriptGarage garage0, const ScriptGarageType garage1, const ScriptModelID model) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x03a5);
|
||||
RW_UNUSED(garage0);
|
||||
RW_UNUSED(garage1);
|
||||
RW_UNUSED(model);
|
||||
void opcode_03a5(const ScriptArguments& args, const ScriptGarage garage, const ScriptGarageType garageType, const ScriptModelID model) {
|
||||
RW_UNUSED(args);
|
||||
garage->type = garageType;
|
||||
garage->targetModel = model;
|
||||
garage->state = Garage::State::Closed;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -10826,10 +10799,8 @@ bool opcode_03b0(const ScriptArguments& args, const ScriptGarage garage) {
|
||||
@arg garage
|
||||
*/
|
||||
bool opcode_03b1(const ScriptArguments& args, const ScriptGarage garage) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x03b1);
|
||||
RW_UNUSED(garage);
|
||||
RW_UNUSED(args);
|
||||
return false;
|
||||
return garage->state == Garage::State::Closed;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -10964,12 +10935,11 @@ void opcode_03ba(const ScriptArguments& args, ScriptVec3 coord0, ScriptVec3 coor
|
||||
@brief set_garage %1d% door_type_to_swing_open
|
||||
|
||||
opcode 03bb
|
||||
@arg garage
|
||||
@arg garage
|
||||
*/
|
||||
void opcode_03bb(const ScriptArguments& args, const ScriptGarage garage) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x03bb);
|
||||
RW_UNUSED(garage);
|
||||
RW_UNUSED(args);
|
||||
garage->makeDoorSwing();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -11302,21 +11272,18 @@ void opcode_03d3(const ScriptArguments& args, ScriptVec3 coord, ScriptFloat& xCo
|
||||
@arg garage Handle
|
||||
@arg arg2
|
||||
*/
|
||||
bool opcode_03d4(const ScriptArguments& args, const ScriptGarage garage, const ScriptInt arg2) {
|
||||
int entryIndex = arg2;
|
||||
bool opcode_03d4(const ScriptArguments& args, const ScriptGarage garage, const ScriptInt index) {
|
||||
int entryIndex = index;
|
||||
RW_CHECK(entryIndex >= 0, "Entry index too low");
|
||||
RW_CHECK(entryIndex < 32, "Entry index too high");
|
||||
|
||||
// @todo reimplement
|
||||
if (garage->type == GarageType::CollectCars1) {
|
||||
return args.getState()->importExportPortland[entryIndex];
|
||||
if (garage->type == Garage::Type::CollectCars1) {
|
||||
return args.getState()->importExportPortland[entryIndex];
|
||||
}
|
||||
if (garage->type == GarageType::CollectCars2) {
|
||||
return args.getState()->importExportShoreside[entryIndex];
|
||||
if (garage->type == Garage::Type::CollectCars2) {
|
||||
return args.getState()->importExportShoreside[entryIndex];
|
||||
}
|
||||
// if (garage->type == GarageType::CollectCars3) {
|
||||
// return args.getState()->importExportUnused[entryIndex];
|
||||
// }
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -12179,18 +12146,7 @@ void opcode_0421(const ScriptArguments& args, const ScriptBoolean arg1) {
|
||||
*/
|
||||
bool opcode_0422(const ScriptArguments& args, const ScriptGarage garage, const ScriptVehicle vehicle) {
|
||||
RW_UNUSED(args);
|
||||
/// @todo move to garage code
|
||||
|
||||
if (vehicle) {
|
||||
/// @todo if this car only accepts mission cars we probably have to filter here / only check for one specific car
|
||||
auto vp = vehicle->getPosition();
|
||||
if(vp.x >= garage->min.x && vp.y >= garage->min.y && vp.z >= garage->min.z &&
|
||||
vp.x <= garage->max.x && vp.y <= garage->max.y && vp.z <= garage->max.z) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return garage->isObjectInsideGarage(vehicle.get());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -537,8 +537,8 @@ void RWGame::tick(float dt) {
|
||||
object->tick(dt);
|
||||
}
|
||||
|
||||
for (auto& gc : world->garageControllers) {
|
||||
gc->tick(dt);
|
||||
for (auto& g : world->garages) {
|
||||
g->tick(dt);
|
||||
}
|
||||
|
||||
for (auto& p : world->payphones) {
|
||||
@ -717,11 +717,11 @@ void RWGame::renderDebugPaths(float time) {
|
||||
}
|
||||
|
||||
// Draw Garage bounds
|
||||
for (const auto& garage : state.garages) {
|
||||
for (const auto& garage : world->garages) {
|
||||
btVector3 minColor(1.f, 0.f, 0.f);
|
||||
btVector3 maxColor(0.f, 1.f, 0.f);
|
||||
btVector3 min(garage.min.x, garage.min.y, garage.min.z);
|
||||
btVector3 max(garage.max.x, garage.max.y, garage.max.z);
|
||||
btVector3 min(garage->min.x, garage->min.y, garage->min.z);
|
||||
btVector3 max(garage->max.x, garage->max.y, garage->max.z);
|
||||
debug.drawLine(min, min + btVector3(0.5f, 0.f, 0.f), minColor);
|
||||
debug.drawLine(min, min + btVector3(0.f, 0.5f, 0.f), minColor);
|
||||
debug.drawLine(min, min + btVector3(0.f, 0.f, 0.5f), minColor);
|
||||
|
@ -16,6 +16,7 @@ set(TESTS
|
||||
FileIndex
|
||||
GameData
|
||||
GameWorld
|
||||
Garage
|
||||
Input
|
||||
Items
|
||||
Lifetime
|
||||
|
18
tests/test_Garage.cpp
Normal file
18
tests/test_Garage.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <engine/Garage.hpp>
|
||||
#include "test_Globals.hpp"
|
||||
#if RW_TEST_WITH_DATA
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(GarageTests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_garage_interaction) {
|
||||
{
|
||||
auto garage = Global::get().e->createGarage(
|
||||
{0.f, 0.f, 0.f}, {3.f, 3.f, 3.f}, Garage::Type::Respray);
|
||||
BOOST_REQUIRE(garage != nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user