1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-11-22 02:12:45 +01:00

Merge pull request #480 from husho/garages

[Ready] Garages
This commit is contained in:
Daniel Evans 2018-05-24 17:35:40 +01:00 committed by GitHub
commit 2b096eb228
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 932 additions and 73 deletions

View File

@ -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

View File

@ -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,

View File

@ -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 {

View File

@ -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.

View File

@ -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

View 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));
}
}

View 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

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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;
}

View File

@ -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);