From 363840396a7f44689c7039c2f45311bdc74f6166 Mon Sep 17 00:00:00 2001 From: husho Date: Fri, 1 Jun 2018 18:54:18 +0300 Subject: [PATCH] Implemented: Big'N'Veiny pickups --- rwengine/src/engine/GameState.hpp | 2 + rwengine/src/engine/GameWorld.cpp | 3 + rwengine/src/objects/PickupObject.cpp | 93 +++++---- rwengine/src/objects/PickupObject.hpp | 190 ++++++++++++++++-- .../src/script/modules/GTA3ModuleImpl.inl | 31 +-- 5 files changed, 259 insertions(+), 60 deletions(-) diff --git a/rwengine/src/engine/GameState.hpp b/rwengine/src/engine/GameState.hpp index 077cbe96..72e319a5 100644 --- a/rwengine/src/engine/GameState.hpp +++ b/rwengine/src/engine/GameState.hpp @@ -394,6 +394,8 @@ public: ScriptInt* scriptTimerVariable = nullptr; bool scriptTimerPaused = false; + int bigNVeinyPickupsCollected = 0; + /** The camera near value currently set by the script */ float cameraNear; bool cameraFixed; diff --git a/rwengine/src/engine/GameWorld.cpp b/rwengine/src/engine/GameWorld.cpp index 288ad22d..daa57a34 100644 --- a/rwengine/src/engine/GameWorld.cpp +++ b/rwengine/src/engine/GameWorld.cpp @@ -375,6 +375,9 @@ PickupObject* GameWorld::createPickup(const glm::vec3& pos, int id, int type) { pickup = new AdrenalinePickup(this, pos, modelInfo, pickuptype); } else if (modelInfo->name == "Money") { pickup = new MoneyPickup(this, pos, modelInfo, pickuptype, 0); + } else if (modelInfo->name == "donkeymag") { + pickup = new BigNVeinyPickup(this, pos, modelInfo, pickuptype); + pickup->setBehaviourFlags(PickupObject::BehaviourFlags::PickupInVehicle); } else { RW_UNIMPLEMENTED("Non-weapon pickups"); pickup = new PickupObject(this, pos, modelInfo, pickuptype); diff --git a/rwengine/src/objects/PickupObject.cpp b/rwengine/src/objects/PickupObject.cpp index 7aad4569..bdd52d7c 100644 --- a/rwengine/src/objects/PickupObject.cpp +++ b/rwengine/src/objects/PickupObject.cpp @@ -14,6 +14,7 @@ #include "engine/ScreenText.hpp" #include "objects/CharacterObject.hpp" #include "objects/PickupObject.hpp" +#include "objects/VehicleObject.hpp" uint32_t colours[14] = { 0xff0000, // bat, detonator, adrenaline @@ -22,7 +23,7 @@ uint32_t colours[14] = { 0xffff00, // shotgun 0xff00ff, // ak47 0x00ffff, // m16 - 0xff8000, // sniper + 0xff8000, // sniper, donkeymag 0x00ff80, // rocket 0x8000ff, // flame 0x80ff00, // molotov @@ -32,7 +33,7 @@ uint32_t colours[14] = { 0xffff00, // health, bonus }; -bool PickupObject::doesRespawn(PickupType type) { +bool PickupObject::defaultDoesRespawn(PickupType type) { switch (type) { case Once: case OnceTimeout: @@ -51,7 +52,7 @@ bool PickupObject::doesRespawn(PickupType type) { } } -float PickupObject::respawnTime(PickupType type) { +float PickupObject::defaultRespawnTime(PickupType type) { switch (type) { case InShop: return 5.f; @@ -63,7 +64,8 @@ float PickupObject::respawnTime(PickupType type) { } } -uint32_t PickupObject::behaviourFlags(PickupType type) { +PickupObject::BehaviourFlags PickupObject::defaultBehaviourFlags( + PickupType type) { switch (type) { case InShop: case OnStreet: @@ -78,12 +80,12 @@ uint32_t PickupObject::behaviourFlags(PickupType type) { case MineArmed: case NauticalMineInactive: case NauticalMineArmed: - return 0; + return None; case FloatingPackage: case FloatingPackageFloating: return PickupInVehicle; default: - return 0; + return None; } } @@ -118,7 +120,7 @@ PickupObject::PickupObject(GameWorld* world, const glm::vec3& position, m_colourId = 4; else if (modelinfo->name == "m16") m_colourId = 5; - else if (modelinfo->name == "sniper") + else if (modelinfo->name == "sniper" || modelinfo->name == "donkeymag") m_colourId = 6; else if (modelinfo->name == "rocket") m_colourId = 7; @@ -152,11 +154,9 @@ PickupObject::PickupObject(GameWorld* world, const glm::vec3& position, engine->data->findSlotTexture("particle", "coronaringa"); } - auto flags = behaviourFlags(m_type); - RW_UNUSED(flags); - - RW_CHECK((flags & PickupInVehicle) == 0, - "In Vehicle pickup not implemented yet"); + respawn = defaultDoesRespawn(m_type); + respawnTime = defaultRespawnTime(m_type); + behaviourFlags = defaultBehaviourFlags(m_type); setEnabled(true); setCollected(false); @@ -186,7 +186,7 @@ void PickupObject::tick(float dt) { if (!m_enabled) { // Check if our type of pickup respawns - if (doesRespawn(m_type)) { + if (doesRespawn()) { m_enableTimer -= dt; if (m_enableTimer <= 0.f) { setEnabled(true); @@ -210,7 +210,7 @@ void PickupObject::tick(float dt) { btBroadphasePairArray& pairArray = m_ghost->getOverlappingPairCache()->getOverlappingPairArray(); int numPairs = pairArray.size(); - auto flags = behaviourFlags(m_type); + auto flags = getBehaviourFlags(); for (int i = 0; i < numPairs; i++) { manifoldArray.clear(); @@ -229,11 +229,27 @@ void PickupObject::tick(float dt) { static_cast(object); if (character->isPlayer()) { - setCollected(onCharacterTouch(character)); + setCollected(onPlayerTouch()); setEnabled(!isCollected()); if (!m_enabled) { - m_enableTimer = respawnTime(m_type); + m_enableTimer = getRespawnTime(); + } + } + } + if ((flags & PickupInVehicle) == PickupInVehicle && + object->type() == Vehicle) { + VehicleObject* vehicle = + static_cast(object); + + if (vehicle->getOccupant(0) == + static_cast( + engine->getPlayer()->getCharacter())) { + setCollected(onPlayerVehicleTouch()); + setEnabled(!isCollected()); + + if (!m_enabled) { + m_enableTimer = getRespawnTime(); } } } @@ -261,7 +277,7 @@ ItemPickup::ItemPickup(GameWorld* world, const glm::vec3& position, : PickupObject(world, position, modelinfo, type), item(item) { } -bool ItemPickup::onCharacterTouch(CharacterObject* character) { +bool ItemPickup::onPlayerTouch() { auto totalRounds = 0; switch (item->modelID) { @@ -298,6 +314,8 @@ bool ItemPickup::onCharacterTouch(CharacterObject* character) { totalRounds /= 5; } + const auto& character = engine->getPlayer()->getCharacter(); + character->addToInventory(item->inventorySlot, totalRounds); return true; @@ -308,8 +326,7 @@ DummyPickup::DummyPickup(GameWorld* world, const glm::vec3& position, : PickupObject(world, position, modelinfo, type) { } -bool DummyPickup::onCharacterTouch(CharacterObject* character) { - RW_UNUSED(character); +bool DummyPickup::onPlayerTouch() { return true; } @@ -318,9 +335,7 @@ RampagePickup::RampagePickup(GameWorld* world, const glm::vec3& position, : PickupObject(world, position, modelinfo, type) { } -bool RampagePickup::onCharacterTouch(CharacterObject* character) { - RW_UNUSED(character); - +bool RampagePickup::onPlayerTouch() { if (engine->state->scriptOnMissionFlag == nullptr) { return false; } @@ -337,7 +352,9 @@ HealthPickup::HealthPickup(GameWorld* world, const glm::vec3& position, : PickupObject(world, position, modelinfo, type) { } -bool HealthPickup::onCharacterTouch(CharacterObject* character) { +bool HealthPickup::onPlayerTouch() { + const auto& character = engine->getPlayer()->getCharacter(); + if (character->getCurrentState().health >= 100.f) { return false; } @@ -352,7 +369,9 @@ ArmourPickup::ArmourPickup(GameWorld* world, const glm::vec3& position, : PickupObject(world, position, modelinfo, type) { } -bool ArmourPickup::onCharacterTouch(CharacterObject* character) { +bool ArmourPickup::onPlayerTouch() { + const auto& character = engine->getPlayer()->getCharacter(); + if (character->getCurrentState().armour >= 100.f) { return false; } @@ -368,10 +387,8 @@ CollectablePickup::CollectablePickup(GameWorld* world, : PickupObject(world, position, modelinfo, type) { } -bool CollectablePickup::onCharacterTouch(CharacterObject* character) { - RW_UNUSED(character); - - GameState* state = engine->state; +bool CollectablePickup::onPlayerTouch() { + const auto& state = engine->state; if (state->playerInfo.hiddenPackagesCollected == state->playerInfo.hiddenPackageCount) { @@ -408,9 +425,8 @@ AdrenalinePickup::AdrenalinePickup(GameWorld* world, const glm::vec3& position, : PickupObject(world, position, modelinfo, type) { } -bool AdrenalinePickup::onCharacterTouch(CharacterObject* character) { - static_cast(character->controller) - ->activateAdrenalineEffect(); +bool AdrenalinePickup::onPlayerTouch() { + engine->getPlayer()->activateAdrenalineEffect(); return true; } @@ -421,10 +437,19 @@ MoneyPickup::MoneyPickup(GameWorld* world, const glm::vec3& position, : PickupObject(world, position, modelinfo, type), money(money) { } -bool MoneyPickup::onCharacterTouch(CharacterObject* character) { - RW_UNUSED(character); - +bool MoneyPickup::onPlayerTouch() { engine->state->playerInfo.money += money; return true; } + +BigNVeinyPickup::BigNVeinyPickup(GameWorld* world, const glm::vec3& position, + BaseModelInfo* modelinfo, PickupType type) + : PickupObject(world, position, modelinfo, type) { +} + +bool BigNVeinyPickup::onPlayerVehicleTouch() { + engine->state->bigNVeinyPickupsCollected++; + + return true; +} \ No newline at end of file diff --git a/rwengine/src/objects/PickupObject.hpp b/rwengine/src/objects/PickupObject.hpp index 178508b1..8143a353 100644 --- a/rwengine/src/objects/PickupObject.hpp +++ b/rwengine/src/objects/PickupObject.hpp @@ -14,6 +14,7 @@ class btSphereShape; class BaseModelInfo; class GameWorld; class CharacterObject; +class VehicleObject; class VisualFX; /** @@ -38,11 +39,11 @@ public: FloatingPackageFloating = 13, OnStreetSlow = 14 }; - enum /*BehaviourFlags*/ { PickupOnFoot = 1, PickupInVehicle = 2 }; + enum BehaviourFlags { None = 0, PickupOnFoot = 1, PickupInVehicle = 2 }; - static bool doesRespawn(PickupType type); - static float respawnTime(PickupType type); - static uint32_t behaviourFlags(PickupType type); + static bool defaultDoesRespawn(PickupType type); + static float defaultRespawnTime(PickupType type); + static BehaviourFlags defaultBehaviourFlags(PickupType type); PickupObject(GameWorld* world, const glm::vec3& position, BaseModelInfo* modelinfo, PickupType type); @@ -55,8 +56,11 @@ public: void tick(float dt) override; - virtual bool onCharacterTouch(CharacterObject* character) { - RW_UNUSED(character); + virtual bool onPlayerTouch() { + return false; + } + + virtual bool onPlayerVehicleTouch() { return false; } @@ -81,6 +85,34 @@ public: return false; } + virtual bool isBigNVeinyPickup() const { + return false; + } + + bool doesRespawn() const { + return respawn; + } + + void setRespawn(bool r) { + respawn = r; + } + + float getRespawnTime() const { + return respawnTime; + } + + void setRespawnTime(float time) { + respawnTime = time; + } + + BehaviourFlags getBehaviourFlags() const { + return behaviourFlags; + } + + void setBehaviourFlags(BehaviourFlags flags) { + behaviourFlags = flags; + } + private: btPairCachingGhostObject* m_ghost; btSphereShape* m_shape; @@ -89,6 +121,9 @@ private: bool m_collected; VisualFX* m_corona; short m_colourId; + bool respawn; + float respawnTime; + BehaviourFlags behaviourFlags; PickupType m_type; }; @@ -107,7 +142,7 @@ public: ItemPickup(GameWorld* world, const glm::vec3& position, BaseModelInfo* modelinfo, PickupType type, WeaponData* item); - bool onCharacterTouch(CharacterObject* character) override; + bool onPlayerTouch() override; }; /** @@ -118,7 +153,7 @@ public: DummyPickup(GameWorld* world, const glm::vec3& position, BaseModelInfo* modelinfo, PickupType type); - bool onCharacterTouch(CharacterObject* character) override; + bool onPlayerTouch() override; }; /** @@ -133,7 +168,7 @@ public: return true; } - bool onCharacterTouch(CharacterObject* character) override; + bool onPlayerTouch() override; }; /** @@ -144,7 +179,7 @@ public: HealthPickup(GameWorld* world, const glm::vec3& position, BaseModelInfo* modelinfo, PickupType type); - bool onCharacterTouch(CharacterObject* character) override; + bool onPlayerTouch() override; }; /** @@ -155,7 +190,7 @@ public: ArmourPickup(GameWorld* world, const glm::vec3& position, BaseModelInfo* modelinfo, PickupType type); - bool onCharacterTouch(CharacterObject* character) override; + bool onPlayerTouch() override; }; /** @@ -166,7 +201,7 @@ public: CollectablePickup(GameWorld* world, const glm::vec3& position, BaseModelInfo* modelinfo, PickupType type); - bool onCharacterTouch(CharacterObject* character) override; + bool onPlayerTouch() override; }; /** @@ -177,7 +212,7 @@ public: AdrenalinePickup(GameWorld* world, const glm::vec3& position, BaseModelInfo* modelinfo, PickupType type); - bool onCharacterTouch(CharacterObject* character) override; + bool onPlayerTouch() override; }; /** @@ -194,7 +229,134 @@ public: money = m; }; - bool onCharacterTouch(CharacterObject* character) override; + bool onPlayerTouch() override; +}; + +const static std::array bigNVeinyPickupsLocations = { + glm::vec3(913.62219f, -155.13692f, 4.9699469f), + glm::vec3(913.92401f, -124.12943f, 4.9692569f), + glm::vec3(913.27899f, -93.524231f, 7.4325991f), + glm::vec3(912.60852f, -63.15905f, 7.4533591f), + glm::vec3(934.22144f, -42.049122f, 7.4511471f), + glm::vec3(958.88092f, -23.863735f, 7.4652338f), + glm::vec3(978.50812f, -0.78458798f, 5.13515f), + glm::vec3(1009.4175f, -2.1041219f, 2.4461579f), + glm::vec3(1040.6313f, -2.0793829f, 2.293175f), + glm::vec3(1070.7863f, -2.084095f, 2.2789791f), + glm::vec3(1100.5773f, -8.468729f, 5.3248072f), + glm::vec3(1119.9341f, -31.738031f, 7.1913071f), + glm::vec3(1122.1664f, -62.762737f, 7.4703908f), + glm::vec3(1122.814f, -93.650566f, 8.5577497f), + glm::vec3(1125.8253f, -124.26616f, 9.9803305f), + glm::vec3(1153.8727f, -135.47169f, 14.150617f), + glm::vec3(1184.0831f, -135.82845f, 14.973998f), + glm::vec3(1192.0432f, -164.57816f, 19.18627f), + glm::vec3(1192.7761f, -194.28871f, 24.799675f), + glm::vec3(1215.1527f, -215.0714f, 25.74975f), + glm::vec3(1245.79f, -215.39304f, 28.70726f), + glm::vec3(1276.2477f, -216.39485f, 33.71236f), + glm::vec3(1306.5535f, -216.71007f, 39.711472f), + glm::vec3(1335.0244f, -224.59329f, 46.474979f), + glm::vec3(1355.4879f, -246.27664f, 49.934841f), + glm::vec3(1362.6003f, -276.47064f, 49.96265f), + glm::vec3(1363.027f, -307.30847f, 49.969173f), + glm::vec3(1365.343f, -338.08609f, 49.967789f), + glm::vec3(1367.5957f, -368.01105f, 50.092304f), + glm::vec3(1368.2749f, -398.38049f, 50.061268f), + glm::vec3(1366.9034f, -429.98483f, 50.057545f), + glm::vec3(1356.8534f, -459.09259f, 50.035545f), + glm::vec3(1335.5819f, -481.13544f, 47.217903f), + glm::vec3(1306.7552f, -491.07443f, 40.202629f), + glm::vec3(1275.5978f, -491.33194f, 33.969223f), + glm::vec3(1244.702f, -491.46451f, 29.111021f), + glm::vec3(1213.2222f, -491.8754f, 25.771168f), + glm::vec3(1182.7729f, -492.19995f, 24.749964f), + glm::vec3(1152.6874f, -491.42221f, 21.70038f), + glm::vec3(1121.5352f, -491.94604f, 20.075182f), + glm::vec3(1090.7056f, -492.63751f, 17.585758f), + glm::vec3(1059.6008f, -491.65762f, 14.848632f), + glm::vec3(1029.113f, -489.66031f, 14.918498f), + glm::vec3(998.20679f, -486.78107f, 14.945688f), + glm::vec3(968.00555f, -484.91266f, 15.001229f), + glm::vec3(937.74939f, -492.09015f, 14.958629f), + glm::vec3(927.17352f, -520.97736f, 14.972308f), + glm::vec3(929.29749f, -552.08643f, 14.978855f), + glm::vec3(950.69525f, -574.47778f, 14.972788f), + glm::vec3(974.02826f, -593.56024f, 14.966445f), + glm::vec3(989.04779f, -620.12854f, 14.951016f), + glm::vec3(1014.1639f, -637.3905f, 14.966736f), + glm::vec3(1017.5961f, -667.3736f, 14.956415f), + glm::vec3(1041.9735f, -685.94391f, 15.003841f), + glm::vec3(1043.3064f, -716.11298f, 14.974236f), + glm::vec3(1043.5337f, -746.63855f, 14.96919f), + glm::vec3(1044.142f, -776.93823f, 14.965424f), + glm::vec3(1044.2657f, -807.29395f, 14.97171f), + glm::vec3(1017.0797f, -820.1076f, 14.975431f), + glm::vec3(986.23865f, -820.37103f, 14.972883f), + glm::vec3(956.10065f, -820.23291f, 14.981133f), + glm::vec3(925.86914f, -820.19049f, 14.976553f), + glm::vec3(897.69702f, -831.08734f, 14.962709f), + glm::vec3(868.06586f, -835.99237f, 14.970685f), + glm::vec3(836.93054f, -836.84387f, 14.965049f), + glm::vec3(811.63586f, -853.7915f, 15.067576f), + glm::vec3(811.46344f, -884.27368f, 12.247812f), + glm::vec3(811.60651f, -914.70959f, 9.2393751f), + glm::vec3(811.10425f, -945.16272f, 5.817255f), + glm::vec3(816.54584f, -975.64587f, 4.998558f), + glm::vec3(828.2951f, -1003.3685f, 5.0471172f), + glm::vec3(852.28839f, -1021.5963f, 4.9371028f), + glm::vec3(882.50067f, -1025.4459f, 5.14077f), + glm::vec3(912.84821f, -1026.7874f, 8.3415451f), + glm::vec3(943.68274f, -1026.6914f, 11.341879f), + glm::vec3(974.4129f, -1027.3682f, 14.410345f), + glm::vec3(1004.1079f, -1036.0778f, 14.92961f), + glm::vec3(1030.1144f, -1051.1224f, 14.850387f), + glm::vec3(1058.7585f, -1060.342f, 14.821624f), + glm::vec3(1087.7797f, -1068.3263f, 14.800561f), + glm::vec3(1099.8807f, -1095.656f, 11.877907f), + glm::vec3(1130.0005f, -1101.994f, 11.853914f), + glm::vec3(1160.3809f, -1101.6355f, 11.854824f), + glm::vec3(1191.8524f, -1102.1577f, 11.853843f), + glm::vec3(1223.3307f, -1102.7448f, 11.852233f), + glm::vec3(1253.564f, -1098.1045f, 11.853944f), + glm::vec3(1262.0203f, -1069.1785f, 14.8147f), + glm::vec3(1290.9998f, -1059.1882f, 14.816016f), + glm::vec3(1316.246f, -1041.0635f, 14.81109f), + glm::vec3(1331.7539f, -1013.835f, 14.81207f), + glm::vec3(1334.0579f, -983.55402f, 14.827253f), + glm::vec3(1323.2429f, -954.23083f, 14.954678f), + glm::vec3(1302.7495f, -932.21216f, 14.962917f), + glm::vec3(1317.418f, -905.89325f, 14.967506f), + glm::vec3(1337.9503f, -883.5025f, 14.969675f), + glm::vec3(1352.6929f, -855.96954f, 14.967854f), + glm::vec3(1357.2388f, -826.26971f, 14.97295f), + glm::vec3(1384.8668f, -812.47693f, 12.907736f), + glm::vec3(1410.8983f, -795.39056f, 12.052228f), + glm::vec3(1433.901f, -775.55811f, 11.96265f), + glm::vec3(1443.8615f, -746.92511f, 11.976114f), + glm::vec3(1457.7015f, -720.00903f, 11.971177f), + glm::vec3(1481.5685f, -701.30237f, 11.977908f), + glm::vec3(1511.4004f, -696.83295f, 11.972709f), + glm::vec3(1542.1796f, -695.61676f, 11.970441f), + glm::vec3(1570.3301f, -684.6239f, 11.969202f)}; + +/** + * @brief The BigNVeinyPickup class + */ +class BigNVeinyPickup : public PickupObject { +public: + BigNVeinyPickup(GameWorld* world, const glm::vec3& position, + BaseModelInfo* modelinfo, PickupType type); + + bool onPlayerVehicleTouch() override; + + bool isBigNVeinyPickup() const override { + return true; + } + + const static std::array& getBigNVeinyPickupsLocations() { + return bigNVeinyPickupsLocations; + } }; #endif diff --git a/rwengine/src/script/modules/GTA3ModuleImpl.inl b/rwengine/src/script/modules/GTA3ModuleImpl.inl index 406adf72..76e05460 100644 --- a/rwengine/src/script/modules/GTA3ModuleImpl.inl +++ b/rwengine/src/script/modules/GTA3ModuleImpl.inl @@ -7414,24 +7414,27 @@ void opcode_02c2(const ScriptArguments& args, const ScriptVehicle vehicle, Scrip @brief create_donkey_mags %1d% opcode 02c3 - @arg arg1 + @arg unused */ -void opcode_02c3(const ScriptArguments& args, const ScriptInt arg1) { - RW_UNIMPLEMENTED_OPCODE(0x02c3); - RW_UNUSED(arg1); - RW_UNUSED(args); +void opcode_02c3(const ScriptArguments& args, const ScriptInt unused) { + RW_UNUSED(unused); + args.getState()->bigNVeinyPickupsCollected = 0; + + for (auto& pos : BigNVeinyPickup::getBigNVeinyPickupsLocations()) { + args.getWorld()->createPickup( + pos, args.getWorld()->data->findModelObject("donkeymag"), + PickupObject::PickupType::OnStreet); + } } /** @brief %1d% = donkey_mags_picked_up opcode 02c5 - @arg arg1 + @arg collected */ -void opcode_02c5(const ScriptArguments& args, ScriptInt& arg1) { - RW_UNIMPLEMENTED_OPCODE(0x02c5); - RW_UNUSED(arg1); - RW_UNUSED(args); +void opcode_02c5(const ScriptArguments& args, ScriptInt& collected) { + collected = args.getState()->bigNVeinyPickupsCollected; } /** @@ -7440,8 +7443,12 @@ void opcode_02c5(const ScriptArguments& args, ScriptInt& arg1) { opcode 02c6 */ void opcode_02c6(const ScriptArguments& args) { - RW_UNIMPLEMENTED_OPCODE(0x02c6); - RW_UNUSED(args); + for (auto& p : args.getWorld()->pickupPool.objects) { + auto pickup = static_cast(p.second); + if (pickup->isBigNVeinyPickup()) { + script::destroyObject(args, pickup); + } + } } /**