From 5c1dbbd8b60d17517a44ccf6683cb3d15e9b76f5 Mon Sep 17 00:00:00 2001 From: husho Date: Fri, 18 May 2018 11:49:02 +0300 Subject: [PATCH] Added pickups --- rwengine/CMakeLists.txt | 2 - rwengine/src/ai/PlayerController.cpp | 20 ++ rwengine/src/ai/PlayerController.hpp | 9 + rwengine/src/engine/GameWorld.cpp | 17 +- rwengine/src/engine/ScreenText.cpp | 17 +- rwengine/src/engine/ScreenText.hpp | 7 +- rwengine/src/objects/CharacterObject.cpp | 8 + rwengine/src/objects/ItemPickup.cpp | 53 ---- rwengine/src/objects/ItemPickup.hpp | 26 -- rwengine/src/objects/PickupObject.cpp | 259 ++++++++++++++++-- rwengine/src/objects/PickupObject.hpp | 116 +++++++- .../src/script/modules/GTA3ModuleImpl.inl | 38 ++- rwgame/states/IngameState.cpp | 46 +++- tests/test_Pickup.cpp | 4 +- 14 files changed, 480 insertions(+), 142 deletions(-) delete mode 100644 rwengine/src/objects/ItemPickup.cpp delete mode 100644 rwengine/src/objects/ItemPickup.hpp diff --git a/rwengine/CMakeLists.txt b/rwengine/CMakeLists.txt index 3e26782b..ec2b1bf4 100644 --- a/rwengine/CMakeLists.txt +++ b/rwengine/CMakeLists.txt @@ -94,8 +94,6 @@ set(RWENGINE_SOURCES src/objects/GameObject.hpp src/objects/InstanceObject.cpp src/objects/InstanceObject.hpp - src/objects/ItemPickup.cpp - src/objects/ItemPickup.hpp src/objects/ObjectTypes.hpp src/objects/PickupObject.cpp src/objects/PickupObject.hpp diff --git a/rwengine/src/ai/PlayerController.cpp b/rwengine/src/ai/PlayerController.cpp index d87a165e..67e1cedd 100644 --- a/rwengine/src/ai/PlayerController.cpp +++ b/rwengine/src/ai/PlayerController.cpp @@ -277,6 +277,17 @@ void PlayerController::restartLogic() { void PlayerController::update(float dt) { restartLogic(); + + GameWorld* world = character->engine; + GameState* state = character->engine->state; + + if (adrenalineEffect) { + if (world->getGameTime() > adrenalineEffectTime) { + state->basic.timeScale = 1.f; + adrenalineEffect = false; + } + } + CharacterController::update(dt); } @@ -289,3 +300,12 @@ void PlayerController::jump() { setNextActivity(std::make_unique()); } } + +void PlayerController::activateAdrenalineEffect() { + GameWorld* world = character->engine; + GameState* state = character->engine->state; + + adrenalineEffect = true; + adrenalineEffectTime = world->getGameTime() + 20.f; + state->basic.timeScale = 0.3f; +} \ No newline at end of file diff --git a/rwengine/src/ai/PlayerController.hpp b/rwengine/src/ai/PlayerController.hpp index 551c6458..305f842f 100644 --- a/rwengine/src/ai/PlayerController.hpp +++ b/rwengine/src/ai/PlayerController.hpp @@ -14,6 +14,9 @@ class PlayerController : public CharacterController { bool missionRestartRequired; + bool adrenalineEffect; + float adrenalineEffectTime; + bool _enabled; enum RestartState { @@ -59,6 +62,12 @@ public: glm::vec3 getTargetPosition() override; + bool isAdrenalineActive() { + return adrenalineEffect; + }; + + void activateAdrenalineEffect(); + void jump(); /** diff --git a/rwengine/src/engine/GameWorld.cpp b/rwengine/src/engine/GameWorld.cpp index 4273714a..5384e8e5 100644 --- a/rwengine/src/engine/GameWorld.cpp +++ b/rwengine/src/engine/GameWorld.cpp @@ -26,7 +26,7 @@ #include "objects/CharacterObject.hpp" #include "objects/CutsceneObject.hpp" #include "objects/InstanceObject.hpp" -#include "objects/ItemPickup.hpp" +#include "objects/PickupObject.hpp" #include "objects/VehicleObject.hpp" #include "render/ViewCamera.hpp" @@ -360,6 +360,21 @@ PickupObject* GameWorld::createPickup(const glm::vec3& pos, int id, int type) { // If nothing, create a generic pickup instead of an item pickup if (it != data->weaponData.end()) { pickup = new ItemPickup(this, pos, modelInfo, pickuptype, it->get()); + } else if (modelInfo->name == "info" || modelInfo->name == "briefcase" || + modelInfo->name == "floatpackge1") { + pickup = new DummyPickup(this, pos, modelInfo, pickuptype); + } else if (modelInfo->name == "killfrenzy") { + pickup = new RampagePickup(this, pos, modelInfo, pickuptype); + } else if (modelInfo->name == "health") { + pickup = new HealthPickup(this, pos, modelInfo, pickuptype); + } else if (modelInfo->name == "bodyarmour") { + pickup = new ArmourPickup(this, pos, modelInfo, pickuptype); + } else if (modelInfo->name == "package1") { + pickup = new CollectablePickup(this, pos, modelInfo, pickuptype); + } else if (modelInfo->name == "adrenaline") { + pickup = new AdrenalinePickup(this, pos, modelInfo, pickuptype); + } else if (modelInfo->name == "Money") { + pickup = new MoneyPickup(this, pos, modelInfo, pickuptype, 0); } else { RW_UNIMPLEMENTED("Non-weapon pickups"); pickup = new PickupObject(this, pos, modelInfo, pickuptype); diff --git a/rwengine/src/engine/ScreenText.cpp b/rwengine/src/engine/ScreenText.cpp index 3eb069dc..19c75405 100644 --- a/rwengine/src/engine/ScreenText.cpp +++ b/rwengine/src/engine/ScreenText.cpp @@ -8,7 +8,7 @@ void ScreenText::tick(float dt) { // Remove all the immedate text m_textQueues[static_cast(ScreenTextType::Immediate)].clear(); - for (auto &textQueue : m_textQueues) { + for (auto& textQueue : m_textQueues) { for (unsigned int i = 0; i < textQueue.size();) { auto& big = textQueue[i]; @@ -168,3 +168,18 @@ ScreenTextEntry ScreenTextEntry::makeHelp(const GameStringKey& id, return {str, {20.f, 20.f}, 2, 18, {0, 0, 0, 255}, {255, 255, 255}, 0, 5000, 0, 35, id}; } + +ScreenTextEntry ScreenTextEntry::makeHiddenPackageText(const GameStringKey& id, + const GameString& str) { + return {str, + {318.f, 138.f}, + 2, + 33, + {2, 2, 0, 0}, + {0x59, 0x73, 0x96}, + 1, + 5000, + 0, + 600, + id}; +} diff --git a/rwengine/src/engine/ScreenText.hpp b/rwengine/src/engine/ScreenText.hpp index fb6e4c00..0cd8c33d 100644 --- a/rwengine/src/engine/ScreenText.hpp +++ b/rwengine/src/engine/ScreenText.hpp @@ -22,8 +22,10 @@ enum class ScreenTextType { Immediate = 3, /// High priority cutscene text HighPriority = 4, + + HiddenPackageText = 5, /// - _Count = 5 + _Count = 6 }; constexpr unsigned int ScreenTypeTextCount = static_cast(ScreenTextType::_Count); @@ -67,6 +69,9 @@ struct ScreenTextEntry { static ScreenTextEntry makeHelp(const GameStringKey& id, const GameString& str); + + static ScreenTextEntry makeHiddenPackageText(const GameStringKey& id, + const GameString& str); }; /** diff --git a/rwengine/src/objects/CharacterObject.cpp b/rwengine/src/objects/CharacterObject.cpp index c276716f..1e7fc6a7 100644 --- a/rwengine/src/objects/CharacterObject.cpp +++ b/rwengine/src/objects/CharacterObject.cpp @@ -12,6 +12,7 @@ #include #include "ai/CharacterController.hpp" +#include "ai/PlayerController.hpp" #include "engine/Animator.hpp" #include "engine/GameData.hpp" #include "engine/GameState.hpp" @@ -197,6 +198,13 @@ glm::vec3 CharacterObject::updateMovementAnimation(float dt) { } } + if (controller) { + if (static_cast(controller)->isAdrenalineActive() && + movementAnimation == animations->animation(AnimCycle::WalkStart)) { + animationSpeed *= 2; + } + } + // Check if we need to change the animation or change speed if (animator->getAnimation(AnimIndexMovement) != movementAnimation) { animator->playAnimation(AnimIndexMovement, movementAnimation, diff --git a/rwengine/src/objects/ItemPickup.cpp b/rwengine/src/objects/ItemPickup.cpp deleted file mode 100644 index 574eef75..00000000 --- a/rwengine/src/objects/ItemPickup.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "objects/ItemPickup.hpp" - -#include "data/WeaponData.hpp" -#include "objects/CharacterObject.hpp" -#include "objects/PickupObject.hpp" - -ItemPickup::ItemPickup(GameWorld *world, const glm::vec3 &position, - BaseModelInfo *modelinfo, PickupType type, - WeaponData *item) - : PickupObject(world, position, modelinfo, type), item(item) { -} - -bool ItemPickup::onCharacterTouch(CharacterObject *character) { - auto totalRounds = 0; - - switch (item->modelID) { - case 173: /* Pistol */ - totalRounds = 45; - break; - case 178: /* Uzi */ - totalRounds = 125; - break; - case 176: /* Shotgun */ - totalRounds = 25; - break; - case 170: /* Grenade */ - totalRounds = 5; - break; - case 174: /* Molotov */ - totalRounds = 5; - break; - case 181: /* Flame thrower */ - totalRounds = 25; - break; - case 171: /* AK */ - totalRounds = 150; - break; - case 180: /* M16 */ - totalRounds = 300; - break; - case 177: /* Sniper Rifle */ - totalRounds = 25; - break; - } - - if (getPickupType() == OnStreet || getPickupType() == OnStreetSlow) { - totalRounds /= 5; - } - - character->addToInventory(item->inventorySlot, totalRounds); - - return true; -} diff --git a/rwengine/src/objects/ItemPickup.hpp b/rwengine/src/objects/ItemPickup.hpp deleted file mode 100644 index ebb56a34..00000000 --- a/rwengine/src/objects/ItemPickup.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef _RWENGINE_ITEMPICKUP_HPP_ -#define _RWENGINE_ITEMPICKUP_HPP_ - -#include - -#include - -class BaseModelInfo; -class CharacterObject; -class GameWorld; -struct WeaponData; - -/** - * @brief The ItemPickup class - * Inserts an item into a characters inventory on pickup. - */ -class ItemPickup : public PickupObject { - WeaponData* item; -public: - ItemPickup(GameWorld* world, const glm::vec3& position, - BaseModelInfo* modelinfo, PickupType type, WeaponData* item); - - bool onCharacterTouch(CharacterObject* character) override; -}; - -#endif diff --git a/rwengine/src/objects/PickupObject.cpp b/rwengine/src/objects/PickupObject.cpp index c3401ea5..7aad4569 100644 --- a/rwengine/src/objects/PickupObject.cpp +++ b/rwengine/src/objects/PickupObject.cpp @@ -2,29 +2,34 @@ #include -#include #include +#include #include +#include "ai/PlayerController.hpp" +#include "data/WeaponData.hpp" #include "engine/GameData.hpp" +#include "engine/GameState.hpp" #include "engine/GameWorld.hpp" +#include "engine/ScreenText.hpp" #include "objects/CharacterObject.hpp" +#include "objects/PickupObject.hpp" uint32_t colours[14] = { - 0xff0000, // bat, detonator, adrenaline - 0x00ff00, // pistol - 0x8080ff, // uzi - 0xffff00, // shotgun - 0xff00ff, // ak47 - 0x00ffff, // m16 - 0xff8000, // sniper - 0x00ff80, // rocket - 0x8000ff, // flame - 0x80ff00, // molotov - 0xffffff, // grenade - 0x80ff80, // bodyarmour, bribe - 0x0000ff, // info, killfrenzy - 0xffff00 // health, bonus + 0xff0000, // bat, detonator, adrenaline + 0x00ff00, // pistol + 0x8080ff, // uzi + 0xffff00, // shotgun + 0xff00ff, // ak47 + 0x00ffff, // m16 + 0xff8000, // sniper + 0x00ff80, // rocket + 0x8000ff, // flame + 0x80ff00, // molotov + 0xffffff, // grenade. package1, floatpackge1 + 0x80ff80, // bodyarmour, bribe + 0x0000ff, // info, killfrenzy + 0xffff00, // health, bonus }; bool PickupObject::doesRespawn(PickupType type) { @@ -84,7 +89,7 @@ uint32_t PickupObject::behaviourFlags(PickupType type) { PickupObject::PickupObject(GameWorld* world, const glm::vec3& position, BaseModelInfo* modelinfo, PickupType type) - : GameObject(world, position, glm::quat{1.0f,0.0f,0.0f,0.0f}, modelinfo) + : GameObject(world, position, glm::quat{1.0f, 0.0f, 0.0f, 0.0f}, modelinfo) , m_ghost(nullptr) , m_shape(nullptr) , m_enabled(false) @@ -121,7 +126,8 @@ PickupObject::PickupObject(GameWorld* world, const glm::vec3& position, m_colourId = 8; else if (modelinfo->name == "molotov") m_colourId = 9; - else if (modelinfo->name == "grenade") + else if (modelinfo->name == "grenade" || modelinfo->name == "package1" || + modelinfo->name == "floatpackge1") m_colourId = 10; else if (modelinfo->name == "bodyarmour" || modelinfo->name == "bribe") m_colourId = 11; @@ -134,7 +140,17 @@ PickupObject::PickupObject(GameWorld* world, const glm::vec3& position, m_corona->particle.position = getPosition(); m_corona->particle.direction = glm::vec3(0.f, 0.f, 1.f); m_corona->particle.orientation = VisualFX::ParticleData::Camera; - m_corona->particle.texture = engine->data->findSlotTexture("particle", "coronaringa"); + + // @todo float package should float on the water + if (m_type == FloatingPackage) { + // verify offset and texture? + m_corona->particle.position += glm::vec3(0.f, 0.f, 0.7f); + m_corona->particle.texture = + engine->data->findSlotTexture("particle", "coronastar"); + } else { + m_corona->particle.texture = + engine->data->findSlotTexture("particle", "coronaringa"); + } auto flags = behaviourFlags(m_type); RW_UNUSED(flags); @@ -143,6 +159,7 @@ PickupObject::PickupObject(GameWorld* world, const glm::vec3& position, "In Vehicle pickup not implemented yet"); setEnabled(true); + setCollected(false); } PickupObject::~PickupObject() { @@ -156,27 +173,36 @@ PickupObject::~PickupObject() { } void PickupObject::tick(float dt) { + if (isRampage()) { + if (engine->state->scriptOnMissionFlag != nullptr) { + if (*(engine->state->scriptOnMissionFlag) != 0 && isEnabled()) { + setEnabled(false); + } else if (*(engine->state->scriptOnMissionFlag) == 0 && + !isEnabled()) { + setEnabled(true); + } + } + } + if (!m_enabled) { // Check if our type of pickup respawns if (doesRespawn(m_type)) { m_enableTimer -= dt; if (m_enableTimer <= 0.f) { setEnabled(true); - m_collected = false; + setCollected(false); } } } float time = engine->getGameTime(); float colourValue = 0.5f * (std::sin(time * 3.0664064f) * 0.3f + 0.3f); - uint32_t *colour = &colours[m_colourId]; + uint32_t* colour = &colours[m_colourId]; float red = (*colour >> 16) & 0xFF; float green = (*colour >> 8) & 0xFF; float blue = *colour & 0xFF; - m_corona->particle.colour = glm::vec4(red / 255.f, - green / 255.f, - blue / 255.f, - 1.f) * colourValue; + m_corona->particle.colour = + glm::vec4(red / 255.f, green / 255.f, blue / 255.f, 1.f) * colourValue; if (m_enabled) { // Sort out interactions with things that may or may not be players. @@ -201,11 +227,14 @@ void PickupObject::tick(float dt) { object->type() == Character) { CharacterObject* character = static_cast(object); - m_collected = onCharacterTouch(character); - setEnabled(!m_collected); - if (!m_enabled) { - m_enableTimer = respawnTime(m_type); + if (character->isPlayer()) { + setCollected(onCharacterTouch(character)); + setEnabled(!isCollected()); + + if (!m_enabled) { + m_enableTimer = respawnTime(m_type); + } } } } @@ -225,3 +254,177 @@ void PickupObject::setEnabled(bool enabled) { m_enabled = enabled; } + +ItemPickup::ItemPickup(GameWorld* world, const glm::vec3& position, + BaseModelInfo* modelinfo, PickupType type, + WeaponData* item) + : PickupObject(world, position, modelinfo, type), item(item) { +} + +bool ItemPickup::onCharacterTouch(CharacterObject* character) { + auto totalRounds = 0; + + switch (item->modelID) { + case 173: /* Pistol */ + totalRounds = 45; + break; + case 178: /* Uzi */ + totalRounds = 125; + break; + case 176: /* Shotgun */ + totalRounds = 25; + break; + case 170: /* Grenade */ + totalRounds = 5; + break; + case 174: /* Molotov */ + totalRounds = 5; + break; + case 181: /* Flame thrower */ + totalRounds = 25; + break; + case 171: /* AK */ + totalRounds = 150; + break; + case 180: /* M16 */ + totalRounds = 300; + break; + case 177: /* Sniper Rifle */ + totalRounds = 25; + break; + } + + if (getPickupType() == OnStreet || getPickupType() == OnStreetSlow) { + totalRounds /= 5; + } + + character->addToInventory(item->inventorySlot, totalRounds); + + return true; +} + +DummyPickup::DummyPickup(GameWorld* world, const glm::vec3& position, + BaseModelInfo* modelinfo, PickupType type) + : PickupObject(world, position, modelinfo, type) { +} + +bool DummyPickup::onCharacterTouch(CharacterObject* character) { + RW_UNUSED(character); + return true; +} + +RampagePickup::RampagePickup(GameWorld* world, const glm::vec3& position, + BaseModelInfo* modelinfo, PickupType type) + : PickupObject(world, position, modelinfo, type) { +} + +bool RampagePickup::onCharacterTouch(CharacterObject* character) { + RW_UNUSED(character); + + if (engine->state->scriptOnMissionFlag == nullptr) { + return false; + } + + if (*(engine->state->scriptOnMissionFlag) != 0) { + return false; + } + + return true; +} + +HealthPickup::HealthPickup(GameWorld* world, const glm::vec3& position, + BaseModelInfo* modelinfo, PickupType type) + : PickupObject(world, position, modelinfo, type) { +} + +bool HealthPickup::onCharacterTouch(CharacterObject* character) { + if (character->getCurrentState().health >= 100.f) { + return false; + } + + character->getCurrentState().health = 100.f; + + return true; +} + +ArmourPickup::ArmourPickup(GameWorld* world, const glm::vec3& position, + BaseModelInfo* modelinfo, PickupType type) + : PickupObject(world, position, modelinfo, type) { +} + +bool ArmourPickup::onCharacterTouch(CharacterObject* character) { + if (character->getCurrentState().armour >= 100.f) { + return false; + } + + character->getCurrentState().armour = 100.f; + + return true; +} + +CollectablePickup::CollectablePickup(GameWorld* world, + const glm::vec3& position, + BaseModelInfo* modelinfo, PickupType type) + : PickupObject(world, position, modelinfo, type) { +} + +bool CollectablePickup::onCharacterTouch(CharacterObject* character) { + RW_UNUSED(character); + + GameState* state = engine->state; + + if (state->playerInfo.hiddenPackagesCollected == + state->playerInfo.hiddenPackageCount) { + state->playerInfo.money += 1000000; + + const auto gxtEntry = "CO_ALL"; + + state->text.addText( + ScreenTextEntry::makeHiddenPackageText( + gxtEntry, engine->data->texts.text(gxtEntry))); + + } else { + state->playerInfo.hiddenPackagesCollected++; + state->playerInfo.money += 1000; + + const auto gxtEntry = "CO_ONE"; + + auto text = ScreenText::format( + engine->data->texts.text(gxtEntry), + GameStringUtil::fromString( + std::to_string(state->playerInfo.hiddenPackagesCollected)), + GameStringUtil::fromString( + std::to_string(state->playerInfo.hiddenPackageCount))); + + state->text.addText( + ScreenTextEntry::makeHiddenPackageText(gxtEntry, text)); + } + + return true; +} + +AdrenalinePickup::AdrenalinePickup(GameWorld* world, const glm::vec3& position, + BaseModelInfo* modelinfo, PickupType type) + : PickupObject(world, position, modelinfo, type) { +} + +bool AdrenalinePickup::onCharacterTouch(CharacterObject* character) { + static_cast(character->controller) + ->activateAdrenalineEffect(); + + return true; +} + +MoneyPickup::MoneyPickup(GameWorld* world, const glm::vec3& position, + BaseModelInfo* modelinfo, PickupType type, + uint32_t money) + : PickupObject(world, position, modelinfo, type), money(money) { +} + +bool MoneyPickup::onCharacterTouch(CharacterObject* character) { + RW_UNUSED(character); + + engine->state->playerInfo.money += money; + + return true; +} diff --git a/rwengine/src/objects/PickupObject.hpp b/rwengine/src/objects/PickupObject.hpp index 13bc1f42..178508b1 100644 --- a/rwengine/src/objects/PickupObject.hpp +++ b/rwengine/src/objects/PickupObject.hpp @@ -44,8 +44,8 @@ public: static float respawnTime(PickupType type); static uint32_t behaviourFlags(PickupType type); - PickupObject(GameWorld* world, const glm::vec3& position, BaseModelInfo *modelinfo, - PickupType type); + PickupObject(GameWorld* world, const glm::vec3& position, + BaseModelInfo* modelinfo, PickupType type); ~PickupObject() override; @@ -69,10 +69,18 @@ public: return m_collected; } + void setCollected(bool collected) { + m_collected = collected; + } + PickupType getPickupType() const { return m_type; } + virtual bool isRampage() const { + return false; + } + private: btPairCachingGhostObject* m_ghost; btSphereShape* m_shape; @@ -85,4 +93,108 @@ private: PickupType m_type; }; +/** + * @brief The ItemPickup class + * Inserts an item into a characters inventory on pickup. + */ + +struct WeaponData; + +class ItemPickup : public PickupObject { + WeaponData* item; + +public: + ItemPickup(GameWorld* world, const glm::vec3& position, + BaseModelInfo* modelinfo, PickupType type, WeaponData* item); + + bool onCharacterTouch(CharacterObject* character) override; +}; + +/** + * @brief The DummyPickup class + */ +class DummyPickup : public PickupObject { +public: + DummyPickup(GameWorld* world, const glm::vec3& position, + BaseModelInfo* modelinfo, PickupType type); + + bool onCharacterTouch(CharacterObject* character) override; +}; + +/** + * @brief The RampagePickup class + */ +class RampagePickup : public PickupObject { +public: + RampagePickup(GameWorld* world, const glm::vec3& position, + BaseModelInfo* modelinfo, PickupType type); + + bool isRampage() const override { + return true; + } + + bool onCharacterTouch(CharacterObject* character) override; +}; + +/** + * @brief The HealthPickup class + */ +class HealthPickup : public PickupObject { +public: + HealthPickup(GameWorld* world, const glm::vec3& position, + BaseModelInfo* modelinfo, PickupType type); + + bool onCharacterTouch(CharacterObject* character) override; +}; + +/** + * @brief The ArmourPickup class + */ +class ArmourPickup : public PickupObject { +public: + ArmourPickup(GameWorld* world, const glm::vec3& position, + BaseModelInfo* modelinfo, PickupType type); + + bool onCharacterTouch(CharacterObject* character) override; +}; + +/** + * @brief The CollectablePickup class + */ +class CollectablePickup : public PickupObject { +public: + CollectablePickup(GameWorld* world, const glm::vec3& position, + BaseModelInfo* modelinfo, PickupType type); + + bool onCharacterTouch(CharacterObject* character) override; +}; + +/** + * @brief The AdrenalinePickup class + */ +class AdrenalinePickup : public PickupObject { +public: + AdrenalinePickup(GameWorld* world, const glm::vec3& position, + BaseModelInfo* modelinfo, PickupType type); + + bool onCharacterTouch(CharacterObject* character) override; +}; + +/** + * @brief The MoneyPickup class + */ +class MoneyPickup : public PickupObject { + uint32_t money; + +public: + MoneyPickup(GameWorld* world, const glm::vec3& position, + BaseModelInfo* modelinfo, PickupType type, uint32_t money); + + void setMoney(uint32_t m) { + money = m; + }; + + bool onCharacterTouch(CharacterObject* character) override; +}; + #endif diff --git a/rwengine/src/script/modules/GTA3ModuleImpl.inl b/rwengine/src/script/modules/GTA3ModuleImpl.inl index e5fb739b..0928f805 100644 --- a/rwengine/src/script/modules/GTA3ModuleImpl.inl +++ b/rwengine/src/script/modules/GTA3ModuleImpl.inl @@ -6049,10 +6049,12 @@ void opcode_0213(const ScriptArguments& args, const ScriptModel model, const Scr bool opcode_0214(const ScriptArguments& args, const ScriptPickup pickup) { RW_UNUSED(args); RW_CHECK(pickup != nullptr, "Pickup is null"); - if (! pickup) { - return false; + if (!pickup) { + return false; } - return pickup->isCollected(); + bool collected = pickup->isCollected(); + pickup->setCollected(false); + return collected; } /** @@ -7843,17 +7845,14 @@ bool opcode_02e0(const ScriptArguments& args, const ScriptCharacter character) { @arg arg1 @arg arg2 @arg arg3 - @arg arg4 + @arg money @arg pickup */ -void opcode_02e1(const ScriptArguments& args, const ScriptFloat arg1, const ScriptFloat arg2, const ScriptFloat arg3, const ScriptInt arg4, ScriptPickup& pickup) { - RW_UNIMPLEMENTED_OPCODE(0x02e1); - RW_UNUSED(arg1); - RW_UNUSED(arg2); - RW_UNUSED(arg3); - RW_UNUSED(arg4); - RW_UNUSED(pickup); - RW_UNUSED(args); +void opcode_02e1(const ScriptArguments& args, ScriptVec3 coord, const ScriptInt money, ScriptPickup& pickup) { + coord = script::getGround(args, coord); + PickupObject* pickupObj = args.getWorld()->createPickup(coord, args.getWorld()->data->findModelObject("Money"), PickupObject::PickupType::Money); + static_cast(pickupObj)->setMoney(money); + pickup = pickupObj; } /** @@ -8001,9 +8000,8 @@ void opcode_02eb(const ScriptArguments& args) { @arg coord Coordinates */ void opcode_02ec(const ScriptArguments& args, ScriptVec3 coord) { - RW_UNIMPLEMENTED_OPCODE(0x02ec); - RW_UNUSED(coord); - RW_UNUSED(args); + coord = script::getGround(args, coord); + args.getWorld()->createPickup(coord, args.getWorld()->data->findModelObject("package1"), PickupObject::PickupType::Collectable); } /** @@ -9577,13 +9575,9 @@ void opcode_035a(const ScriptArguments& args, ScriptFloat& arg1, ScriptFloat& ar @arg arg3 @arg pickup */ -void opcode_035b(const ScriptArguments& args, const ScriptFloat arg1, const ScriptFloat arg2, const ScriptFloat arg3, ScriptPickup& pickup) { - RW_UNIMPLEMENTED_OPCODE(0x035b); - RW_UNUSED(arg1); - RW_UNUSED(arg2); - RW_UNUSED(arg3); - RW_UNUSED(pickup); - RW_UNUSED(args); +void opcode_035b(const ScriptArguments& args, ScriptVec3 coord, ScriptPickup& pickup) { + coord = script::getGround(args, coord); + pickup = args.getWorld()->createPickup(coord, args.getWorld()->data->findModelObject("floatpackge1"), PickupObject::PickupType::FloatingPackage); } /** diff --git a/rwgame/states/IngameState.cpp b/rwgame/states/IngameState.cpp index 1c90a3d7..7f39e450 100644 --- a/rwgame/states/IngameState.cpp +++ b/rwgame/states/IngameState.cpp @@ -5,21 +5,21 @@ #include "RWGame.hpp" #include -#include #include +#include #include #include #include #include #include #include -#include +#include #include #include