mirror of
https://github.com/rwengine/openrw.git
synced 2024-09-02 16:49:46 +02:00
parent
81781a53ed
commit
6d04746222
@ -63,6 +63,8 @@ set(RWENGINE_SOURCES
|
||||
src/engine/GameWorld.hpp
|
||||
src/engine/GarageController.cpp
|
||||
src/engine/GarageController.hpp
|
||||
src/engine/Payphone.cpp
|
||||
src/engine/Payphone.hpp
|
||||
src/engine/SaveGame.cpp
|
||||
src/engine/SaveGame.hpp
|
||||
src/engine/ScreenText.cpp
|
||||
|
@ -4,18 +4,22 @@
|
||||
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include "engine/Animator.hpp"
|
||||
#include "engine/GameState.hpp"
|
||||
#include "engine/GameWorld.hpp"
|
||||
#include "objects/CharacterObject.hpp"
|
||||
#include "objects/GameObject.hpp"
|
||||
#include "objects/VehicleObject.hpp"
|
||||
|
||||
class Animator;
|
||||
|
||||
PlayerController::PlayerController()
|
||||
: CharacterController()
|
||||
, lastRotation(glm::vec3(0.f, 0.f, 0.f))
|
||||
, missionRestartRequired(false)
|
||||
, _enabled(true)
|
||||
, restartState(Alive) {
|
||||
, restartState(Alive)
|
||||
, payphoneState(Left) {
|
||||
}
|
||||
|
||||
void PlayerController::setInputEnabled(bool enabled) {
|
||||
@ -275,6 +279,42 @@ void PlayerController::restartLogic() {
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerController::pickUpPayphone() {
|
||||
payphoneState = PayphoneState::PickingUp;
|
||||
|
||||
character->animator->playAnimation(
|
||||
AnimIndexMovement, character->animations->animation(AnimCycle::PhoneIn),
|
||||
1.f, false);
|
||||
}
|
||||
|
||||
void PlayerController::hangUpPayphone() {
|
||||
payphoneState = PayphoneState::HangingUp;
|
||||
|
||||
character->animator->playAnimation(
|
||||
AnimIndexMovement,
|
||||
character->animations->animation(AnimCycle::PhoneOut), 1.f, false);
|
||||
}
|
||||
|
||||
void PlayerController::talkOnPayphone() {
|
||||
payphoneState = PayphoneState::Talking;
|
||||
}
|
||||
|
||||
void PlayerController::leavePayphone() {
|
||||
payphoneState = Left;
|
||||
}
|
||||
|
||||
bool PlayerController::isPickingUpPayphone() const {
|
||||
return payphoneState == PayphoneState::PickingUp;
|
||||
}
|
||||
|
||||
bool PlayerController::isHangingUpPayphone() const {
|
||||
return payphoneState == PayphoneState::HangingUp;
|
||||
}
|
||||
|
||||
bool PlayerController::isTalkingOnPayphone() const {
|
||||
return payphoneState == PayphoneState::Talking;
|
||||
}
|
||||
|
||||
void PlayerController::update(float dt) {
|
||||
restartLogic();
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
class PlayerController : public CharacterController {
|
||||
private:
|
||||
glm::quat cameraRotation{1.0f, 0.0f, 0.0f, 0.0f};
|
||||
|
||||
glm::vec3 direction{};
|
||||
@ -26,6 +27,13 @@ class PlayerController : public CharacterController {
|
||||
FadingIn,
|
||||
} restartState;
|
||||
|
||||
enum PayphoneState {
|
||||
Left,
|
||||
Talking,
|
||||
PickingUp,
|
||||
HangingUp,
|
||||
} payphoneState;
|
||||
|
||||
// handles player respawn logic
|
||||
void restartLogic();
|
||||
|
||||
@ -58,6 +66,22 @@ public:
|
||||
// @todo not implemented yet
|
||||
bool isBusted() const;
|
||||
|
||||
// Play payphone pick up anim
|
||||
void pickUpPayphone();
|
||||
// Play payphone hang up anim
|
||||
void hangUpPayphone();
|
||||
// Play talking on payphone anim
|
||||
void talkOnPayphone();
|
||||
// Reset any payphone anim
|
||||
void leavePayphone();
|
||||
|
||||
// Is payphone pick up anim playing
|
||||
bool isPickingUpPayphone() const;
|
||||
// Is payphone hang up anim playing
|
||||
bool isHangingUpPayphone() const;
|
||||
// Is talking on payphone anim playing
|
||||
bool isTalkingOnPayphone() const;
|
||||
|
||||
void update(float dt) override;
|
||||
|
||||
glm::vec3 getTargetPosition() override;
|
||||
|
@ -459,6 +459,12 @@ GarageInfo* GameWorld::createGarage(const glm::vec3 coord0,
|
||||
return info;
|
||||
}
|
||||
|
||||
Payphone* GameWorld::createPayphone(const glm::vec2 coord) {
|
||||
int id = payphones.size();
|
||||
payphones.emplace_back(make_unique<Payphone>(this, id, coord));
|
||||
return payphones.back().get();
|
||||
}
|
||||
|
||||
void GameWorld::ObjectPool::insert(GameObject* object) {
|
||||
if (object->getGameObjectID() == 0) {
|
||||
// Find the lowest free GameObjectID.
|
||||
@ -1031,4 +1037,4 @@ PlayerController* GameWorld::getPlayer() {
|
||||
return static_cast<PlayerController*>(controller);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <audio/SoundManager.hpp>
|
||||
|
||||
#include <engine/GarageController.hpp>
|
||||
#include <engine/Payphone.hpp>
|
||||
#include <objects/ObjectTypes.hpp>
|
||||
|
||||
#include <render/VisualFX.hpp>
|
||||
@ -35,6 +36,7 @@ struct btDbvtBroadphase;
|
||||
|
||||
class GameState;
|
||||
class GarageController;
|
||||
class Payphone;
|
||||
|
||||
class PlayerController;
|
||||
class Logger;
|
||||
@ -151,6 +153,11 @@ public:
|
||||
GarageInfo* createGarage(const glm::vec3 coord0, const glm::vec3 coord1,
|
||||
const int type);
|
||||
|
||||
/**
|
||||
* Creates a payphone
|
||||
*/
|
||||
Payphone* createPayphone(const glm::vec2 coord);
|
||||
|
||||
/**
|
||||
* Destroys an existing Object
|
||||
*/
|
||||
@ -266,6 +273,8 @@ public:
|
||||
|
||||
std::vector<std::unique_ptr<GarageController>> garageControllers;
|
||||
|
||||
std::vector<std::unique_ptr<Payphone>> payphones;
|
||||
|
||||
/**
|
||||
* @brief getBlipTarget
|
||||
* @param blip
|
||||
|
127
rwengine/src/engine/Payphone.cpp
Normal file
127
rwengine/src/engine/Payphone.cpp
Normal file
@ -0,0 +1,127 @@
|
||||
#include "engine/Payphone.hpp"
|
||||
|
||||
#include <rw/defines.hpp>
|
||||
|
||||
#include "ai/PlayerController.hpp"
|
||||
|
||||
#include "engine/GameState.hpp"
|
||||
#include "engine/GameWorld.hpp"
|
||||
|
||||
#include "objects/CharacterObject.hpp"
|
||||
#include "objects/GameObject.hpp"
|
||||
#include "objects/InstanceObject.hpp"
|
||||
|
||||
Payphone::Payphone(GameWorld* engine_, const int id_, const glm::vec2 coord)
|
||||
: engine(engine_), id(id_) {
|
||||
// Find payphone object, original game does this differently
|
||||
for (const auto& p : engine->instancePool.objects) {
|
||||
auto o = p.second;
|
||||
if (!o->getModel()) {
|
||||
continue;
|
||||
}
|
||||
if (o->getModelInfo<BaseModelInfo>()->name != "phonebooth1") {
|
||||
continue;
|
||||
}
|
||||
if (glm::distance(coord, glm::vec2(o->getPosition())) < 2.f) {
|
||||
object = static_cast<InstanceObject*>(o);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
message.clear();
|
||||
|
||||
if (object) {
|
||||
position = object->getPosition();
|
||||
}
|
||||
}
|
||||
|
||||
void Payphone::enable() {
|
||||
state = State::Ringing;
|
||||
}
|
||||
|
||||
void Payphone::disable() {
|
||||
state = State::Idle;
|
||||
}
|
||||
|
||||
bool Payphone::isTalking() const {
|
||||
return state == State::Talking;
|
||||
}
|
||||
|
||||
void Payphone::setMessageAndStartRinging(const std::string& m) {
|
||||
state = State::Ringing;
|
||||
message = m;
|
||||
}
|
||||
|
||||
void Payphone::tick(float dt) {
|
||||
RW_UNUSED(dt);
|
||||
|
||||
switch (state) {
|
||||
case State::Idle: {
|
||||
break;
|
||||
}
|
||||
|
||||
case State::Ringing: {
|
||||
if (glm::distance(
|
||||
position,
|
||||
engine->getPlayer()->getCharacter()->getPosition()) < 1.f) {
|
||||
state = State::PickingUp;
|
||||
|
||||
engine->getPlayer()->pickUpPayphone();
|
||||
|
||||
engine->state->isCinematic = true;
|
||||
engine->getPlayer()->prepareForCutscene();
|
||||
|
||||
engine->getPlayer()->getCharacter()->setHeading(glm::degrees(
|
||||
glm::atan(position.x, position.y) + glm::half_pi<float>()));
|
||||
}
|
||||
|
||||
// @todo Do wiggle animation
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case State::PickingUp: {
|
||||
if (!engine->getPlayer()->isPickingUpPayphone()) {
|
||||
state = State::Talking;
|
||||
|
||||
if (!message.empty()) {
|
||||
const auto& text =
|
||||
ScreenText::format(engine->data->texts.text(message));
|
||||
|
||||
engine->state->text.clear<ScreenTextType::HighPriority>();
|
||||
engine->state->text.addText<ScreenTextType::HighPriority>(
|
||||
ScreenTextEntry::makeHighPriority(message, text, 3000));
|
||||
|
||||
message.clear();
|
||||
}
|
||||
|
||||
callTimer = engine->getGameTime() + 3.f;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case State::Talking: {
|
||||
if (callTimer <= engine->getGameTime()) {
|
||||
state = State::HangingUp;
|
||||
|
||||
engine->getPlayer()->hangUpPayphone();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case State::HangingUp: {
|
||||
if (!engine->getPlayer()->isHangingUpPayphone()) {
|
||||
state = State::Idle;
|
||||
|
||||
engine->state->isCinematic = false;
|
||||
engine->getPlayer()->freeFromCutscene();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: { break; }
|
||||
}
|
||||
}
|
49
rwengine/src/engine/Payphone.hpp
Normal file
49
rwengine/src/engine/Payphone.hpp
Normal file
@ -0,0 +1,49 @@
|
||||
#ifndef _RWENGINE_PAYPHONE_HPP_
|
||||
#define _RWENGINE_PAYPHONE_HPP_
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <string>
|
||||
|
||||
class PlayerController;
|
||||
|
||||
class GameWorld;
|
||||
class GameState;
|
||||
|
||||
class GameObject;
|
||||
class InstanceObject;
|
||||
class CharacterObject;
|
||||
|
||||
class Payphone {
|
||||
private:
|
||||
InstanceObject* object;
|
||||
glm::vec3 position;
|
||||
GameWorld* engine;
|
||||
float callTimer = 0.f;
|
||||
std::string message;
|
||||
|
||||
public:
|
||||
enum class State { Idle, Ringing, PickingUp, Talking, HangingUp };
|
||||
|
||||
State state = State::Idle;
|
||||
|
||||
int id;
|
||||
|
||||
int getScriptObjectID() const {
|
||||
return id;
|
||||
}
|
||||
|
||||
Payphone(GameWorld* engine_, const int id_, const glm::vec2 coord);
|
||||
~Payphone() = default;
|
||||
|
||||
// Makes a payphone ring
|
||||
void enable();
|
||||
// Disables ringing
|
||||
void disable();
|
||||
// Is currently used by player
|
||||
bool isTalking() const;
|
||||
// Sets a message and makes a payphone ring
|
||||
void setMessageAndStartRinging(const std::string& m);
|
||||
void tick(float dt);
|
||||
};
|
||||
|
||||
#endif
|
@ -328,11 +328,11 @@ struct Block7Data {
|
||||
};
|
||||
|
||||
struct Block8Data {
|
||||
BlockDword numPhones;
|
||||
BlockDword numActivePhones;
|
||||
BlockDword numPayphones;
|
||||
BlockDword numActivePayphones;
|
||||
};
|
||||
|
||||
struct Block8Phone {
|
||||
struct Block8Payphone {
|
||||
glm::vec3 position{};
|
||||
BlockDword messagePtr[6];
|
||||
BlockDword messageEndTime;
|
||||
@ -815,25 +815,23 @@ bool SaveGame::loadGame(GameState& state, const std::string& file) {
|
||||
#endif
|
||||
|
||||
// Block 8
|
||||
BlockSize phoneBlockSize;
|
||||
BLOCK_HEADER(phoneBlockSize)
|
||||
BlockDword phoneDataSize;
|
||||
READ_VALUE(phoneDataSize)
|
||||
BlockSize payphoneBlockSize;
|
||||
BLOCK_HEADER(payphoneBlockSize)
|
||||
BlockDword payphoneDataSize;
|
||||
READ_VALUE(payphoneDataSize)
|
||||
|
||||
Block8Data phoneData;
|
||||
READ_VALUE(phoneData);
|
||||
std::vector<Block8Phone> phones(phoneData.numPhones);
|
||||
for (size_t p = 0; p < phoneData.numPhones; ++p) {
|
||||
Block8Phone& phone = phones[p];
|
||||
READ_VALUE(phone)
|
||||
Block8Data payphoneData;
|
||||
READ_VALUE(payphoneData);
|
||||
std::vector<Block8Payphone> payphones(payphoneData.numPayphones);
|
||||
for (auto& payphone : payphones) {
|
||||
READ_VALUE(payphone)
|
||||
}
|
||||
|
||||
#if RW_DEBUG
|
||||
std::cout << "Phones: " << phoneData.numPhones << std::endl;
|
||||
for (size_t p = 0; p < phoneData.numPhones; ++p) {
|
||||
Block8Phone& phone = phones[p];
|
||||
std::cout << " " << uint16_t(phone.state) << " " << phone.position.x
|
||||
<< " " << phone.position.y << " " << phone.position.z
|
||||
std::cout << "Payphones: " << payphoneData.numPayphones << std::endl;
|
||||
for (const auto& payphone : payphones) {
|
||||
std::cout << " " << uint16_t(payphone.state) << " " << payphone.position.x
|
||||
<< " " << payphone.position.y << " " << payphone.position.z
|
||||
<< std::endl;
|
||||
}
|
||||
#endif
|
||||
@ -1257,6 +1255,11 @@ bool SaveGame::loadGame(GameState& state, const std::string& file) {
|
||||
}
|
||||
}
|
||||
|
||||
// @todo restore properly
|
||||
for (const auto& payphone : payphones) {
|
||||
state.world->createPayphone(glm::vec2(payphone.position));
|
||||
}
|
||||
|
||||
// TODO restore garage data
|
||||
// http://gtaforums.com/topic/758692-gta-iii-save-file-documentation/
|
||||
for (size_t g = 0; g < garageData.garageCount; ++g) {
|
||||
|
@ -122,6 +122,32 @@ void CharacterObject::destroyActor() {
|
||||
glm::vec3 CharacterObject::updateMovementAnimation(float dt) {
|
||||
glm::vec3 animTranslate{};
|
||||
|
||||
if (controller) {
|
||||
auto c = static_cast<PlayerController*>(controller);
|
||||
|
||||
if (c->isTalkingOnPayphone()) {
|
||||
animator->playAnimation(
|
||||
AnimIndexMovement,
|
||||
animations->animation(AnimCycle::PhoneTalk), 1.f,
|
||||
true);
|
||||
return glm::vec3();
|
||||
}
|
||||
if (c->isPickingUpPayphone()) {
|
||||
if (animator->isCompleted(AnimIndexMovement)) {
|
||||
c->talkOnPayphone();
|
||||
} else {
|
||||
return glm::vec3();
|
||||
}
|
||||
}
|
||||
if (c->isHangingUpPayphone()) {
|
||||
if (animator->isCompleted(AnimIndexMovement)) {
|
||||
c->leavePayphone();
|
||||
} else {
|
||||
return glm::vec3();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (motionBlockedByActivity) {
|
||||
// Clear any residual motion animation
|
||||
animator->playAnimation(AnimIndexMovement, nullptr, 1.f, false);
|
||||
@ -584,8 +610,8 @@ void CharacterObject::resetToAINode() {
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterObject::playActivityAnimation(const AnimationPtr& animation, bool repeat,
|
||||
bool blocked) {
|
||||
void CharacterObject::playActivityAnimation(const AnimationPtr& animation,
|
||||
bool repeat, bool blocked) {
|
||||
RW_CHECK(animator != nullptr, "No Animator");
|
||||
animator->playAnimation(AnimIndexAction, animation, 1.f, repeat);
|
||||
motionBlockedByActivity = blocked;
|
||||
|
@ -220,6 +220,17 @@ ScriptObjectType<GarageInfo> ScriptArguments::getScriptObject(
|
||||
return {param.handleValue(), garage};
|
||||
}
|
||||
template <>
|
||||
ScriptObjectType<Payphone> ScriptArguments::getScriptObject(
|
||||
unsigned int arg) const {
|
||||
auto& param = (*this)[arg];
|
||||
RW_CHECK(param.isLvalue(), "Non lvalue passed as object");
|
||||
auto index = *param.handleValue();
|
||||
RW_CHECK(index >= 0, "Object index is negative");
|
||||
auto& payphones = getWorld()->payphones;
|
||||
auto payphone = payphones.at(size_t(index)).get();
|
||||
return {param.handleValue(), payphone};
|
||||
}
|
||||
template <>
|
||||
ScriptObjectType<BlipData> ScriptArguments::getScriptObject(
|
||||
unsigned int arg) const {
|
||||
auto& param = (*this)[arg];
|
||||
|
@ -23,6 +23,7 @@ class ScriptModule;
|
||||
struct SCMThread;
|
||||
class GameState;
|
||||
class GameWorld;
|
||||
class Payphone;
|
||||
|
||||
typedef uint16_t SCMOpcode;
|
||||
typedef char SCMByte;
|
||||
@ -105,10 +106,10 @@ 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.
|
||||
using ScriptSound = ScriptObjectType<int>;
|
||||
using ScriptPhone = ScriptObjectType<int>;
|
||||
using ScriptFire = ScriptObjectType<int>;
|
||||
using ScriptSphere = ScriptObjectType<int>;
|
||||
|
||||
@ -338,6 +339,9 @@ template <>
|
||||
ScriptObjectType<BlipData> ScriptArguments::getScriptObject(
|
||||
unsigned int arg) const;
|
||||
template <>
|
||||
ScriptObjectType<Payphone> ScriptArguments::getScriptObject(
|
||||
unsigned int arg) const;
|
||||
template <>
|
||||
ScriptObjectType<VehicleGenerator> ScriptArguments::getScriptObject(
|
||||
unsigned int arg) const;
|
||||
template <>
|
||||
|
@ -6604,70 +6604,64 @@ void opcode_0249(const ScriptArguments& args, const ScriptModel model) {
|
||||
}
|
||||
|
||||
/**
|
||||
@brief %3d% = create_phone_at %1d% %2d%
|
||||
@brief %3d% = create_payphone_at %1d% %2d%
|
||||
|
||||
opcode 024a
|
||||
@arg coord Coordinates
|
||||
@arg phone Handle
|
||||
@arg payphone Handle
|
||||
*/
|
||||
void opcode_024a(const ScriptArguments& args, ScriptVec2 coord, ScriptPhone& phone) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x024a);
|
||||
RW_UNUSED(coord);
|
||||
RW_UNUSED(phone);
|
||||
RW_UNUSED(args);
|
||||
void opcode_024a(const ScriptArguments& args, const ScriptVec2 coord, ScriptPayphone& payphone) {
|
||||
payphone = args.getWorld()->createPayphone(coord);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief text_phone_repeatedly %1d% %2g%
|
||||
@brief text_payphone_repeatedly %1d% %2g%
|
||||
|
||||
opcode 024b
|
||||
@arg phone
|
||||
@arg payphone
|
||||
@arg arg2
|
||||
*/
|
||||
void opcode_024b(const ScriptArguments& args, const ScriptPhone phone, const ScriptString arg2) {
|
||||
void opcode_024b(const ScriptArguments& args, const ScriptPayphone payphone, const ScriptString arg2) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x024b);
|
||||
RW_UNUSED(phone);
|
||||
RW_UNUSED(payphone);
|
||||
RW_UNUSED(arg2);
|
||||
RW_UNUSED(args);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief text_phone %1d% %2g%
|
||||
@brief text_payphone %1d% %2g%
|
||||
|
||||
opcode 024c
|
||||
@arg phone
|
||||
@arg arg2
|
||||
@arg payphone
|
||||
@arg text
|
||||
*/
|
||||
void opcode_024c(const ScriptArguments& args, const ScriptPhone phone, const ScriptString arg2) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x024c);
|
||||
RW_UNUSED(phone);
|
||||
RW_UNUSED(arg2);
|
||||
void opcode_024c(const ScriptArguments& args, const ScriptPayphone payphone, const ScriptString text) {
|
||||
RW_UNUSED(args);
|
||||
payphone->setMessageAndStartRinging(text);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief phone_text_been_displayed %1d%
|
||||
@brief payphone_text_been_displayed %1d%
|
||||
|
||||
opcode 024d
|
||||
@arg phone
|
||||
@arg payphone
|
||||
*/
|
||||
bool opcode_024d(const ScriptArguments& args, const ScriptPhone phone) {
|
||||
bool opcode_024d(const ScriptArguments& args, const ScriptPayphone payphone) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x024d);
|
||||
RW_UNUSED(phone);
|
||||
RW_UNUSED(payphone);
|
||||
RW_UNUSED(args);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief disable_phone %1d%
|
||||
@brief disable_payphone %1d%
|
||||
|
||||
opcode 024e
|
||||
@arg phone
|
||||
@arg payphone
|
||||
*/
|
||||
void opcode_024e(const ScriptArguments& args, const ScriptPhone phone) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x024e);
|
||||
RW_UNUSED(phone);
|
||||
void opcode_024e(const ScriptArguments& args, const ScriptPayphone payphone) {
|
||||
RW_UNUSED(args);
|
||||
payphone->disable();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -9955,49 +9949,49 @@ void opcode_0377(const ScriptArguments& args, const ScriptCharacter character) {
|
||||
}
|
||||
|
||||
/**
|
||||
@brief text_phone_1string_repeatedly %1d% %2g% %3g%
|
||||
@brief text_payphone_1string_repeatedly %1d% %2g% %3g%
|
||||
|
||||
opcode 0378
|
||||
@arg phone
|
||||
@arg payphone
|
||||
@arg arg2
|
||||
@arg arg3
|
||||
*/
|
||||
void opcode_0378(const ScriptArguments& args, const ScriptPhone phone, const ScriptString arg2, const ScriptString arg3) {
|
||||
void opcode_0378(const ScriptArguments& args, const ScriptPayphone payphone, const ScriptString arg2, const ScriptString arg3) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x0378);
|
||||
RW_UNUSED(phone);
|
||||
RW_UNUSED(payphone);
|
||||
RW_UNUSED(arg2);
|
||||
RW_UNUSED(arg3);
|
||||
RW_UNUSED(args);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief text_phone_1string %1d% %2g% %3g%
|
||||
@brief text_payphone_1string %1d% %2g% %3g%
|
||||
|
||||
opcode 0379
|
||||
@arg phone
|
||||
@arg payphone
|
||||
@arg arg2
|
||||
@arg arg3
|
||||
*/
|
||||
void opcode_0379(const ScriptArguments& args, const ScriptPhone phone, const ScriptString arg2, const ScriptString arg3) {
|
||||
void opcode_0379(const ScriptArguments& args, const ScriptPayphone payphone, const ScriptString arg2, const ScriptString arg3) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x0379);
|
||||
RW_UNUSED(phone);
|
||||
RW_UNUSED(payphone);
|
||||
RW_UNUSED(arg2);
|
||||
RW_UNUSED(arg3);
|
||||
RW_UNUSED(args);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief text_phone_2strings_repeatedly %1d% %2g% %3g% %4g%
|
||||
@brief text_payphone_2strings_repeatedly %1d% %2g% %3g% %4g%
|
||||
|
||||
opcode 037a
|
||||
@arg phone
|
||||
@arg payphone
|
||||
@arg arg2
|
||||
@arg arg3
|
||||
@arg arg4
|
||||
*/
|
||||
void opcode_037a(const ScriptArguments& args, const ScriptPhone phone, const ScriptString arg2, const ScriptString arg3, const ScriptString arg4) {
|
||||
void opcode_037a(const ScriptArguments& args, const ScriptPayphone payphone, const ScriptString arg2, const ScriptString arg3, const ScriptString arg4) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x037a);
|
||||
RW_UNUSED(phone);
|
||||
RW_UNUSED(payphone);
|
||||
RW_UNUSED(arg2);
|
||||
RW_UNUSED(arg3);
|
||||
RW_UNUSED(arg4);
|
||||
@ -10005,17 +9999,17 @@ void opcode_037a(const ScriptArguments& args, const ScriptPhone phone, const Scr
|
||||
}
|
||||
|
||||
/**
|
||||
@brief text_phone_2strings %1d% %2g% %3g% %4g%
|
||||
@brief text_payphone_2strings %1d% %2g% %3g% %4g%
|
||||
|
||||
opcode 037b
|
||||
@arg phone
|
||||
@arg payphone
|
||||
@arg arg2
|
||||
@arg arg3
|
||||
@arg arg4
|
||||
*/
|
||||
void opcode_037b(const ScriptArguments& args, const ScriptPhone phone, const ScriptString arg2, const ScriptString arg3, const ScriptString arg4) {
|
||||
void opcode_037b(const ScriptArguments& args, const ScriptPayphone payphone, const ScriptString arg2, const ScriptString arg3, const ScriptString arg4) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x037b);
|
||||
RW_UNUSED(phone);
|
||||
RW_UNUSED(payphone);
|
||||
RW_UNUSED(arg2);
|
||||
RW_UNUSED(arg3);
|
||||
RW_UNUSED(arg4);
|
||||
@ -10023,18 +10017,18 @@ void opcode_037b(const ScriptArguments& args, const ScriptPhone phone, const Scr
|
||||
}
|
||||
|
||||
/**
|
||||
@brief text_phone_3strings_repeatedly %1d% %2g% %3g% %4g% %5g%
|
||||
@brief text_payphone_3strings_repeatedly %1d% %2g% %3g% %4g% %5g%
|
||||
|
||||
opcode 037c
|
||||
@arg phone
|
||||
@arg payphone
|
||||
@arg arg2
|
||||
@arg arg3
|
||||
@arg arg4
|
||||
@arg arg5
|
||||
*/
|
||||
void opcode_037c(const ScriptArguments& args, const ScriptPhone phone, const ScriptString arg2, const ScriptString arg3, const ScriptString arg4, const ScriptString arg5) {
|
||||
void opcode_037c(const ScriptArguments& args, const ScriptPayphone payphone, const ScriptString arg2, const ScriptString arg3, const ScriptString arg4, const ScriptString arg5) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x037c);
|
||||
RW_UNUSED(phone);
|
||||
RW_UNUSED(payphone);
|
||||
RW_UNUSED(arg2);
|
||||
RW_UNUSED(arg3);
|
||||
RW_UNUSED(arg4);
|
||||
@ -10043,18 +10037,18 @@ void opcode_037c(const ScriptArguments& args, const ScriptPhone phone, const Scr
|
||||
}
|
||||
|
||||
/**
|
||||
@brief text_phone_3strings %1d% %2g% %3g% %4g% %5g%
|
||||
@brief text_payphone_3strings %1d% %2g% %3g% %4g% %5g%
|
||||
|
||||
opcode 037d
|
||||
@arg phone
|
||||
@arg payphone
|
||||
@arg arg2
|
||||
@arg arg3
|
||||
@arg arg4
|
||||
@arg arg5
|
||||
*/
|
||||
void opcode_037d(const ScriptArguments& args, const ScriptPhone phone, const ScriptString arg2, const ScriptString arg3, const ScriptString arg4, const ScriptString arg5) {
|
||||
void opcode_037d(const ScriptArguments& args, const ScriptPayphone payphone, const ScriptString arg2, const ScriptString arg3, const ScriptString arg4, const ScriptString arg5) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x037d);
|
||||
RW_UNUSED(phone);
|
||||
RW_UNUSED(payphone);
|
||||
RW_UNUSED(arg2);
|
||||
RW_UNUSED(arg3);
|
||||
RW_UNUSED(arg4);
|
||||
@ -10165,19 +10159,19 @@ void opcode_0385(const ScriptArguments& args, const ScriptString gxtEntry0, cons
|
||||
}
|
||||
|
||||
/**
|
||||
@brief text_phone_4strings_repeatedly %1d% %2g% %3g% %4g% %5g% %6g%
|
||||
@brief text_payphone_4strings_repeatedly %1d% %2g% %3g% %4g% %5g% %6g%
|
||||
|
||||
opcode 0386
|
||||
@arg phone
|
||||
@arg payphone
|
||||
@arg arg2
|
||||
@arg arg3
|
||||
@arg arg4
|
||||
@arg arg5
|
||||
@arg arg6
|
||||
*/
|
||||
void opcode_0386(const ScriptArguments& args, const ScriptPhone phone, const ScriptString arg2, const ScriptString arg3, const ScriptString arg4, const ScriptString arg5, const ScriptString arg6) {
|
||||
void opcode_0386(const ScriptArguments& args, const ScriptPayphone payphone, const ScriptString arg2, const ScriptString arg3, const ScriptString arg4, const ScriptString arg5, const ScriptString arg6) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x0386);
|
||||
RW_UNUSED(phone);
|
||||
RW_UNUSED(payphone);
|
||||
RW_UNUSED(arg2);
|
||||
RW_UNUSED(arg3);
|
||||
RW_UNUSED(arg4);
|
||||
@ -10187,19 +10181,19 @@ void opcode_0386(const ScriptArguments& args, const ScriptPhone phone, const Scr
|
||||
}
|
||||
|
||||
/**
|
||||
@brief text_phone_4strings %1d% %2g% %3g% %4g% %5g% %6g%
|
||||
@brief text_payphone_4strings %1d% %2g% %3g% %4g% %5g% %6g%
|
||||
|
||||
opcode 0387
|
||||
@arg phone
|
||||
@arg payphone
|
||||
@arg arg2
|
||||
@arg arg3
|
||||
@arg arg4
|
||||
@arg arg5
|
||||
@arg arg6
|
||||
*/
|
||||
void opcode_0387(const ScriptArguments& args, const ScriptPhone phone, const ScriptString arg2, const ScriptString arg3, const ScriptString arg4, const ScriptString arg5, const ScriptString arg6) {
|
||||
void opcode_0387(const ScriptArguments& args, const ScriptPayphone payphone, const ScriptString arg2, const ScriptString arg3, const ScriptString arg4, const ScriptString arg5, const ScriptString arg6) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x0387);
|
||||
RW_UNUSED(phone);
|
||||
RW_UNUSED(payphone);
|
||||
RW_UNUSED(arg2);
|
||||
RW_UNUSED(arg3);
|
||||
RW_UNUSED(arg4);
|
||||
@ -10209,10 +10203,10 @@ void opcode_0387(const ScriptArguments& args, const ScriptPhone phone, const Scr
|
||||
}
|
||||
|
||||
/**
|
||||
@brief text_phone_5strings_repeatedly %1d% %2g% %3g% %4g% %5g% %6g% %7g%
|
||||
@brief text_payphone_5strings_repeatedly %1d% %2g% %3g% %4g% %5g% %6g% %7g%
|
||||
|
||||
opcode 0388
|
||||
@arg phone
|
||||
@arg payphone
|
||||
@arg arg2
|
||||
@arg arg3
|
||||
@arg arg4
|
||||
@ -10220,9 +10214,9 @@ void opcode_0387(const ScriptArguments& args, const ScriptPhone phone, const Scr
|
||||
@arg arg6
|
||||
@arg arg7
|
||||
*/
|
||||
void opcode_0388(const ScriptArguments& args, const ScriptPhone phone, const ScriptString arg2, const ScriptString arg3, const ScriptString arg4, const ScriptString arg5, const ScriptString arg6, const ScriptString arg7) {
|
||||
void opcode_0388(const ScriptArguments& args, const ScriptPayphone payphone, const ScriptString arg2, const ScriptString arg3, const ScriptString arg4, const ScriptString arg5, const ScriptString arg6, const ScriptString arg7) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x0388);
|
||||
RW_UNUSED(phone);
|
||||
RW_UNUSED(payphone);
|
||||
RW_UNUSED(arg2);
|
||||
RW_UNUSED(arg3);
|
||||
RW_UNUSED(arg4);
|
||||
@ -10233,10 +10227,10 @@ void opcode_0388(const ScriptArguments& args, const ScriptPhone phone, const Scr
|
||||
}
|
||||
|
||||
/**
|
||||
@brief text_phone_5strings %1d% %2g% %3g% %4g% %5g% %6g% %7g%
|
||||
@brief text_payphone_5strings %1d% %2g% %3g% %4g% %5g% %6g% %7g%
|
||||
|
||||
opcode 0389
|
||||
@arg phone
|
||||
@arg payphone
|
||||
@arg arg2
|
||||
@arg arg3
|
||||
@arg arg4
|
||||
@ -10244,9 +10238,9 @@ void opcode_0388(const ScriptArguments& args, const ScriptPhone phone, const Scr
|
||||
@arg arg6
|
||||
@arg arg7
|
||||
*/
|
||||
void opcode_0389(const ScriptArguments& args, const ScriptPhone phone, const ScriptString arg2, const ScriptString arg3, const ScriptString arg4, const ScriptString arg5, const ScriptString arg6, const ScriptString arg7) {
|
||||
void opcode_0389(const ScriptArguments& args, const ScriptPayphone payphone, const ScriptString arg2, const ScriptString arg3, const ScriptString arg4, const ScriptString arg5, const ScriptString arg6, const ScriptString arg7) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x0389);
|
||||
RW_UNUSED(phone);
|
||||
RW_UNUSED(payphone);
|
||||
RW_UNUSED(arg2);
|
||||
RW_UNUSED(arg3);
|
||||
RW_UNUSED(arg4);
|
||||
@ -11028,16 +11022,14 @@ void opcode_03c1(const ScriptArguments& args, const ScriptPlayer player, ScriptV
|
||||
}
|
||||
|
||||
/**
|
||||
@brief phone %1d% answered
|
||||
@brief payphone %1d% answered
|
||||
|
||||
opcode 03c2
|
||||
@arg phone
|
||||
@arg payphone
|
||||
*/
|
||||
bool opcode_03c2(const ScriptArguments& args, const ScriptPhone phone) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x03c2);
|
||||
RW_UNUSED(phone);
|
||||
bool opcode_03c2(const ScriptArguments& args, const ScriptPayphone payphone) {
|
||||
RW_UNUSED(args);
|
||||
return false;
|
||||
return payphone->isTalking();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -11819,15 +11811,14 @@ void opcode_0404(const ScriptArguments& args) {
|
||||
}
|
||||
|
||||
/**
|
||||
@brief enable_phone %1d%
|
||||
@brief enable_payphone %1d%
|
||||
|
||||
opcode 0405
|
||||
@arg phone Handle
|
||||
@arg payphone Handle
|
||||
*/
|
||||
void opcode_0405(const ScriptArguments& args, const ScriptPhone phone) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x0405);
|
||||
RW_UNUSED(phone);
|
||||
void opcode_0405(const ScriptArguments& args, const ScriptPayphone payphone) {
|
||||
RW_UNUSED(args);
|
||||
payphone->enable();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -12586,16 +12577,15 @@ void opcode_0446(const ScriptArguments& args, const ScriptCharacter character, c
|
||||
}
|
||||
|
||||
/**
|
||||
@brief is_player_lifting_a_phone %1d%
|
||||
@brief is_player_lifting_a_payphone %1d%
|
||||
|
||||
opcode 0447
|
||||
@arg player Player
|
||||
*/
|
||||
bool opcode_0447(const ScriptArguments& args, const ScriptPlayer player) {
|
||||
RW_UNIMPLEMENTED_OPCODE(0x0447);
|
||||
RW_UNUSED(player);
|
||||
RW_UNUSED(args);
|
||||
return false;
|
||||
return player->isPickingUpPayphone() || player->isTalkingOnPayphone() ||
|
||||
player->isHangingUpPayphone();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -545,6 +545,10 @@ void RWGame::tick(float dt) {
|
||||
gc->tick(dt);
|
||||
}
|
||||
|
||||
for (auto& p : world->payphones) {
|
||||
p->tick(dt);
|
||||
}
|
||||
|
||||
world->destroyQueuedObjects();
|
||||
|
||||
state.text.tick(dt);
|
||||
|
@ -25,6 +25,7 @@ set(TESTS
|
||||
Menu
|
||||
Object
|
||||
ObjectData
|
||||
Payphone
|
||||
Pickup
|
||||
Renderer
|
||||
RWBStream
|
||||
|
72
tests/test_Payphone.cpp
Normal file
72
tests/test_Payphone.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <ai/PlayerController.hpp>
|
||||
#include <engine/GameWorld.hpp>
|
||||
#include <engine/Payphone.hpp>
|
||||
#include <objects/CharacterObject.hpp>
|
||||
#include <objects/GameObject.hpp>
|
||||
#include <objects/InstanceObject.hpp>
|
||||
#include "test_Globals.hpp"
|
||||
#if RW_TEST_WITH_DATA
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(PayphoneTests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_payphone_interaction) {
|
||||
{
|
||||
const auto playerID = 7777;
|
||||
auto character = Global::get().e->createPlayer(
|
||||
{0.f, 0.f, 0.f}, {1.f, 0.f, 0.f, 0.f}, playerID);
|
||||
BOOST_REQUIRE(character != nullptr);
|
||||
|
||||
Global::get().e->state->playerObject = playerID;
|
||||
|
||||
// phonebooth1 from ipl file
|
||||
const auto modelID = 1335;
|
||||
auto payphoneObj = Global::get().e->createInstance(
|
||||
modelID, {1.f, 0.f, 0.f}, {1.f, 0.f, 0.f, 0.f});
|
||||
BOOST_REQUIRE(payphoneObj != nullptr);
|
||||
|
||||
auto payphone = Global::get().e->createPayphone({1.f, 0.f});
|
||||
BOOST_REQUIRE(payphone != nullptr);
|
||||
payphone->setMessageAndStartRinging("");
|
||||
|
||||
auto dt = 0.016f;
|
||||
Global::get().e->state->gameTime += dt;
|
||||
character->tick(dt);
|
||||
payphone->tick(dt);
|
||||
|
||||
BOOST_CHECK(!Global::get().e->getPlayer()->isPickingUpPayphone());
|
||||
|
||||
character->setPosition(character->getPosition() + glm::vec3{0.001f, 0.f, 0.f});
|
||||
|
||||
dt = 0.016f;
|
||||
Global::get().e->state->gameTime += dt;
|
||||
// character->tick(dt);
|
||||
payphone->tick(dt);
|
||||
|
||||
BOOST_CHECK(Global::get().e->getPlayer()->isPickingUpPayphone());
|
||||
BOOST_CHECK(!payphone->isTalking());
|
||||
|
||||
dt = 10.f;
|
||||
Global::get().e->state->gameTime += dt;
|
||||
character->tick(dt);
|
||||
payphone->tick(dt);
|
||||
|
||||
BOOST_CHECK(Global::get().e->getPlayer()->isTalkingOnPayphone());
|
||||
BOOST_CHECK(payphone->isTalking());
|
||||
|
||||
dt = 3.f;
|
||||
Global::get().e->state->gameTime += dt;
|
||||
character->tick(dt);
|
||||
payphone->tick(dt);
|
||||
|
||||
BOOST_CHECK(Global::get().e->getPlayer()->isHangingUpPayphone());
|
||||
BOOST_CHECK(!payphone->isTalking());
|
||||
|
||||
Global::get().e->destroyObject(payphoneObj);
|
||||
Global::get().e->destroyObject(character);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user