From 15dc5feeb51884d8d09914447a78ff448221e8d4 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Tue, 17 Dec 2024 19:04:35 -0800 Subject: [PATCH] feat: start car races if you "equip" the car near the car pad; add more old ns scripts to ignore list (#1681) * brother * use some better logic * Implement spider boss msg script tested that the message now shows up when hitting the survival spider entrance area * add drag to start race feature --- dGame/dComponents/InventoryComponent.cpp | 25 ++++++++ dGame/dGameMessages/GameMessages.cpp | 73 +++++++++++++++--------- dGame/dGameMessages/GameMessages.h | 16 +++++- dScripts/CppScripts.cpp | 4 ++ dScripts/CppScripts.h | 2 +- dScripts/ai/AG/AgSpiderBossMessage.cpp | 3 +- dScripts/ai/GF/CMakeLists.txt | 1 + dScripts/ai/GF/GfRaceInstancer.cpp | 7 +++ dScripts/ai/GF/GfRaceInstancer.h | 11 ++++ 9 files changed, 110 insertions(+), 32 deletions(-) create mode 100644 dScripts/ai/GF/GfRaceInstancer.cpp create mode 100644 dScripts/ai/GF/GfRaceInstancer.h diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index 0bea9fe4..667956f6 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -31,6 +31,7 @@ #include "eStateChangeType.h" #include "eUseItemResponse.h" #include "Mail.h" +#include "ProximityMonitorComponent.h" #include "CDComponentsRegistryTable.h" #include "CDInventoryComponentTable.h" @@ -829,6 +830,30 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) { break; } + return; + } else if (item->GetLot() == 8092) { + // Trying to equip a car + const auto proximityObjects = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::PROXIMITY_MONITOR); + + // look for car instancers and check if we are in its setup range + for (auto* const entity : proximityObjects) { + if (!entity) continue; + + auto* proximityMonitorComponent = entity->GetComponent(); + if (!proximityMonitorComponent) continue; + + if (proximityMonitorComponent->IsInProximity("Interaction_Distance", m_Parent->GetObjectID())) { + // in the range of a car instancer + entity->OnUse(m_Parent); + GameMessages::UseItemOnClient itemMsg; + itemMsg.target = entity->GetObjectID(); + itemMsg.itemLOT = item->GetLot(); + itemMsg.itemToUse = item->GetId(); + itemMsg.playerId = m_Parent->GetObjectID(); + itemMsg.Send(m_Parent->GetSystemAddress()); + break; + } + } return; } diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index eea76fba..cc74436b 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -6342,36 +6342,57 @@ void GameMessages::SendUpdateInventoryUi(LWOOBJID objectId, const SystemAddress& SEND_PACKET; } -void GameMessages::DisplayTooltip::Send() const { - CBITSTREAM; - CMSGHEADER; +namespace GameMessages { + void GameMsg::Send(const SystemAddress& sysAddr) const { + CBITSTREAM; + CMSGHEADER; - bitStream.Write(target); - bitStream.Write(msgId); + bitStream.Write(target); // Who this message will be sent to on the (a) client + bitStream.Write(msgId); // the ID of this message - bitStream.Write(doOrDie); - bitStream.Write(noRepeat); - bitStream.Write(noRevive); - bitStream.Write(isPropertyTooltip); - bitStream.Write(show); - bitStream.Write(translate); - bitStream.Write(time); - bitStream.Write(id.size()); - bitStream.Write(id); + Serialize(bitStream); // write the message data - std::string toWrite; - for (const auto* item : localizeParams) { - toWrite += item->GetString() + "\n"; + // Send to everyone if someone sent unassigned system address, or to one specific client. + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) { + SEND_PACKET_BROADCAST; + } else { + SEND_PACKET; + } } - if (!toWrite.empty()) toWrite.pop_back(); - bitStream.Write(toWrite.size()); - bitStream.Write(GeneralUtils::ASCIIToUTF16(toWrite)); - if (!toWrite.empty()) bitStream.Write(0x00); // Null Terminator - bitStream.Write(imageName.size()); - bitStream.Write(imageName); - bitStream.Write(text.size()); - bitStream.Write(text); + void DisplayTooltip::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(doOrDie); + bitStream.Write(noRepeat); + bitStream.Write(noRevive); + bitStream.Write(isPropertyTooltip); + bitStream.Write(show); + bitStream.Write(translate); + bitStream.Write(time); + bitStream.Write(id.size()); + bitStream.Write(id); - SEND_PACKET; + std::string toWrite; + for (const auto* item : localizeParams) { + toWrite += item->GetString() + "\n"; + } + if (!toWrite.empty()) toWrite.pop_back(); + bitStream.Write(toWrite.size()); + bitStream.Write(GeneralUtils::ASCIIToUTF16(toWrite)); + if (!toWrite.empty()) bitStream.Write(0x00); // Null Terminator + + bitStream.Write(imageName.size()); + bitStream.Write(imageName); + bitStream.Write(text.size()); + bitStream.Write(text); + } + + void UseItemOnClient::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(itemLOT); + bitStream.Write(itemToUse); + bitStream.Write(itemType); + bitStream.Write(playerId); + bitStream.Write(targetPosition.x); + bitStream.Write(targetPosition.y); + bitStream.Write(targetPosition.z); + } } diff --git a/dGame/dGameMessages/GameMessages.h b/dGame/dGameMessages/GameMessages.h index 62d59a1d..f3833df1 100644 --- a/dGame/dGameMessages/GameMessages.h +++ b/dGame/dGameMessages/GameMessages.h @@ -52,10 +52,10 @@ namespace GameMessages { struct GameMsg { GameMsg(MessageType::Game gmId) : msgId{ gmId } {} virtual ~GameMsg() = default; - virtual void Send() const {} + void Send(const SystemAddress& sysAddr) const; + virtual void Serialize(RakNet::BitStream& bitStream) const {} MessageType::Game msgId; LWOOBJID target{ LWOOBJID_EMPTY }; - SystemAddress sysAddr{ UNASSIGNED_SYSTEM_ADDRESS }; }; class PropertyDataMessage; @@ -705,7 +705,17 @@ namespace GameMessages { std::vector localizeParams{}; std::u16string imageName{}; std::u16string text{}; - void Send() const override; + void Serialize(RakNet::BitStream& bitStream) const override; + }; + + struct UseItemOnClient : public GameMsg { + UseItemOnClient() : GameMsg(MessageType::Game::USE_ITEM_ON_CLIENT) {} + LWOOBJID playerId{}; + LWOOBJID itemToUse{}; + uint32_t itemType{}; + LOT itemLOT{}; + NiPoint3 targetPosition{}; + void Serialize(RakNet::BitStream& bitStream) const override; }; }; diff --git a/dScripts/CppScripts.cpp b/dScripts/CppScripts.cpp index 54328451..8b38e5ce 100644 --- a/dScripts/CppScripts.cpp +++ b/dScripts/CppScripts.cpp @@ -329,6 +329,7 @@ #include "WblRobotCitizen.h" #include "EnemyClearThreat.h" #include "AgSpiderBossMessage.h" +#include "GfRaceInstancer.h" #include #include @@ -690,6 +691,7 @@ namespace { {"scripts\\zone\\LUPs\\RobotCity Intro\\WBL_RCIntro_RobotCitizenYellow.lua", []() {return new WblRobotCitizen();}}, {"scripts\\02_server\\Map\\General\\L_ENEMY_CLEAR_THREAT.lua", []() {return new EnemyClearThreat();}}, {"scripts\\ai\\AG\\L_AG_SPIDER_BOSS_MESSAGE.lua", []() {return new AgSpiderBossMessage();}}, + {"scripts\\ai\\GF\\L_GF_RACE_INSTANCER.lua", []() {return new GfRaceInstancer();}}, }; @@ -703,6 +705,8 @@ namespace { "scripts\\zone\\AG\\L_ZONE_AG.lua", "scripts\\zone\\NS\\L_ZONE_NS.lua", "scripts\\zone\\GF\\L_ZONE_GF.lua", + "scripts\\ai\\AG\\CONCERT_STAGE.lua", + "scripts\\ai\\NS\\L_NS_CAR_MODULAR_BUILD.lua", // In our implementation, this is done in GameMessages.cpp }; }; diff --git a/dScripts/CppScripts.h b/dScripts/CppScripts.h index 8d3b3b5d..b0be7759 100644 --- a/dScripts/CppScripts.h +++ b/dScripts/CppScripts.h @@ -354,7 +354,7 @@ namespace CppScripts { * @param player the player to remove * @param canceled if it was done via the cancel button */ - virtual void OnRequestActivityExit(Entity* sender, LWOOBJID player, bool canceled){}; + virtual void OnRequestActivityExit(Entity* sender, LWOOBJID player, bool canceled) {}; }; Script* const GetScript(Entity* parent, const std::string& scriptName); diff --git a/dScripts/ai/AG/AgSpiderBossMessage.cpp b/dScripts/ai/AG/AgSpiderBossMessage.cpp index 6e6cc1b9..ea55384c 100644 --- a/dScripts/ai/AG/AgSpiderBossMessage.cpp +++ b/dScripts/ai/AG/AgSpiderBossMessage.cpp @@ -25,11 +25,10 @@ void AgSpiderBossMessage::MakeBox(Entity* self) const { if (!tgt) return; GameMessages::DisplayTooltip tooltip; tooltip.target = tgt->GetObjectID(); - tooltip.sysAddr = tgt->GetSystemAddress(); tooltip.show = true; tooltip.text = box.boxText; tooltip.time = box.boxTime * 1000; // to ms - tooltip.Send(); + tooltip.Send(tgt->GetSystemAddress()); } void AgSpiderBossMessage::OnCollisionPhantom(Entity* self, Entity* target) { diff --git a/dScripts/ai/GF/CMakeLists.txt b/dScripts/ai/GF/CMakeLists.txt index d28b04f1..b2670d2d 100644 --- a/dScripts/ai/GF/CMakeLists.txt +++ b/dScripts/ai/GF/CMakeLists.txt @@ -1,4 +1,5 @@ set(DSCRIPTS_SOURCES_AI_GF + "GfRaceInstancer.cpp" "GfCampfire.cpp" "GfOrgan.cpp" "GfBanana.cpp" diff --git a/dScripts/ai/GF/GfRaceInstancer.cpp b/dScripts/ai/GF/GfRaceInstancer.cpp new file mode 100644 index 00000000..45c86300 --- /dev/null +++ b/dScripts/ai/GF/GfRaceInstancer.cpp @@ -0,0 +1,7 @@ +#include "GfRaceInstancer.h" + +#include "Entity.h" + +void GfRaceInstancer::OnStartup(Entity* self) { + self->SetProximityRadius(self->HasVar(u"interaction_distance") ? self->GetVar(u"interaction_distance") : 16.0f, "Interaction_Distance"); +} diff --git a/dScripts/ai/GF/GfRaceInstancer.h b/dScripts/ai/GF/GfRaceInstancer.h new file mode 100644 index 00000000..7e3fe49c --- /dev/null +++ b/dScripts/ai/GF/GfRaceInstancer.h @@ -0,0 +1,11 @@ +#ifndef GFRACEINSTANCER_H +#define GFRACEINSTANCER_H + +#include "CppScripts.h" + +class GfRaceInstancer : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; +}; + +#endif //!GFRACEINSTANCER_H