Organize dScripts (#814)

* Organize dScripts

whitespace

Remove parent scope

Remove parent scope from initial setter

Remove debug

Remove helper programs

* Fix NtImagimeterVisibility script

Co-authored-by: aronwk-aaron <aronwk.aaron@gmail.com>
This commit is contained in:
David Markowitz
2022-11-03 10:57:54 -07:00
committed by GitHub
parent b974eed8f5
commit 8d37d9b681
567 changed files with 886 additions and 252 deletions

View File

@@ -0,0 +1,23 @@
#include "BankInteractServer.h"
#include "GameMessages.h"
void BankInteractServer::OnUse(Entity* self, Entity* user) {
AMFArrayValue args;
AMFStringValue* bank = new AMFStringValue();
bank->SetStringValue("bank");
args.InsertValue("state", bank);
GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "pushGameState", &args);
}
void BankInteractServer::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1,
int32_t param2, int32_t param3) {
if (args == "ToggleBank") {
AMFArrayValue args;
args.InsertValue("visible", new AMFFalseValue());
GameMessages::SendUIMessageServerToSingleClient(sender, sender->GetSystemAddress(), "ToggleBank", &args);
GameMessages::SendNotifyClientObject(self->GetObjectID(), u"CloseBank", 0, 0, LWOOBJID_EMPTY, "", sender->GetSystemAddress());
}
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include "CppScripts.h"
class BankInteractServer : public CppScripts::Script
{
public:
void OnUse(Entity* self, Entity* user) override;
void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2,
int32_t param3) override;
};

View File

@@ -0,0 +1,30 @@
#include "BaseInteractDropLootServer.h"
#include "Loot.h"
#include "GameMessages.h"
void BaseInteractDropLootServer::OnUse(Entity* self, Entity* user) {
BaseUse(self, user);
}
void BaseInteractDropLootServer::BaseUse(Entity* self, Entity* user) {
auto cooldownTime = self->GetVar<float>(u"cooldownTime");
if (cooldownTime == 0) cooldownTime = 5;
uint32_t lootMatrix = self->GetVar<int32_t>(u"UseLootMatrix");
if (lootMatrix == 0) lootMatrix = self->GetVar<int32_t>(u"smashable_loot_matrix");
if (lootMatrix == 0) lootMatrix = 715;
auto useSound = self->GetVar<std::string>(u"sound1");
if (!useSound.empty()) {
GameMessages::SendPlayNDAudioEmitter(self, user->GetSystemAddress(), useSound);
}
self->SetNetworkVar(u"bInUse", true);
LootGenerator::Instance().DropLoot(user, self, lootMatrix, 0, 0);
self->AddCallbackTimer(cooldownTime, [this, self]() {
self->SetNetworkVar(u"bInUse", false);
});
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include "CppScripts.h"
class BaseInteractDropLootServer : public CppScripts::Script
{
public:
virtual void OnUse(Entity* self, Entity* user) override;
void BaseUse(Entity* self, Entity* user);
};

View File

@@ -0,0 +1,15 @@
#include "Binoculars.h"
#include "Character.h"
#include "GameMessages.h"
#include "Game.h"
#include "dServer.h"
void Binoculars::OnUse(Entity* self, Entity* user) {
const auto number = self->GetVarAsString(u"number");
int32_t flag = std::stoi(std::to_string(Game::server->GetZoneID()).substr(0, 2) + number);
if (user->GetCharacter()->GetPlayerFlag(flag) == false) {
user->GetCharacter()->SetPlayerFlag(flag, true);
GameMessages::SendFireEventClientSide(self->GetObjectID(), user->GetSystemAddress(), u"achieve", LWOOBJID_EMPTY, 0, -1, LWOOBJID_EMPTY);
}
}

View File

@@ -0,0 +1,7 @@
#pragma once
#include "CppScripts.h"
class Binoculars : public CppScripts::Script {
public:
void OnUse(Entity* self, Entity* user);
};

View File

@@ -0,0 +1,28 @@
set(DSCRIPTS_SOURCES_02_SERVER_MAP_GENERAL
"BankInteractServer.cpp"
"BaseInteractDropLootServer.cpp"
"Binoculars.cpp"
"ExplodingAsset.cpp"
"ForceVolumeServer.cpp"
"GrowingFlower.cpp"
"ImaginationBackpackHealServer.cpp"
"InvalidScript.cpp"
"MailBoxServer.cpp"
"NjRailSwitch.cpp"
"PetDigServer.cpp"
"PropertyDevice.cpp"
"PropertyPlatform.cpp"
"QbEnemyStunner.cpp"
"QbSpawner.cpp"
"StoryBoxInteractServer.cpp"
"TokenConsoleServer.cpp"
"TouchMissionUpdateServer.cpp"
"WishingWellServer.cpp")
add_subdirectory(Ninjago)
foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_GENERAL_NINJAGO})
set(DSCRIPTS_SOURCES_02_SERVER_MAP_GENERAL ${DSCRIPTS_SOURCES_02_SERVER_MAP_GENERAL} "Ninjago/${file}")
endforeach()
set(DSCRIPTS_SOURCES_02_SERVER_MAP_GENERAL ${DSCRIPTS_SOURCES_02_SERVER_MAP_GENERAL} PARENT_SCOPE)

View File

@@ -0,0 +1,109 @@
#include "ExplodingAsset.h"
#include "DestroyableComponent.h"
#include "GameMessages.h"
#include "MissionComponent.h"
#include "SkillComponent.h"
//TODO: this has to be updated so that you only get killed if you're in a certain radius.
//And so that all entities in a certain radius are killed, not just the attacker.
void ExplodingAsset::OnStartup(Entity* self) {
self->SetProximityRadius(20.0f, "outRadius");
self->SetVar<int32_t>(u"playersNearChest", 0);
self->SetProximityRadius(10.0f, "crateHitters");
}
void ExplodingAsset::OnHit(Entity* self, Entity* attacker) {
std::vector<Entity*> entities;
entities.push_back(attacker);
if (!self->GetBoolean(u"bIsHit")) {
for (Entity* en : entities) {
if (en->GetObjectID() == attacker->GetObjectID()) {
if (Vector3::DistanceSquared(en->GetPosition(), self->GetPosition()) > 10 * 10) continue;
auto* destroyable = en->GetComponent<DestroyableComponent>();
if (destroyable == nullptr) {
continue;
}
destroyable->Smash(attacker->GetObjectID());
}
}
}
attacker = attacker->GetOwner();
self->SetBoolean(u"bIsHit", true);
self->SetOwnerOverride(attacker->GetObjectID());
GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(self, u"camshake", self->GetObjectID(), 16);
auto* skillComponent = self->GetComponent<SkillComponent>();
if (skillComponent != nullptr) {
skillComponent->CalculateBehavior(147, 4721, LWOOBJID_EMPTY, true);
}
const auto missionID = self->GetVar<int32_t>(u"missionID");
auto achievementIDs = self->GetVar<std::u16string>(u"achieveID");
// Progress all scripted missions related to this asset
auto* missionComponent = attacker->GetComponent<MissionComponent>();
if (missionComponent != nullptr) {
if (missionID != 0) {
missionComponent->ForceProgressValue(missionID,
static_cast<uint32_t>(MissionTaskType::MISSION_TASK_TYPE_SCRIPT),
self->GetLOT(), false);
}
if (!achievementIDs.empty()) {
for (const auto& achievementID : GeneralUtils::SplitString(achievementIDs, u'_')) {
missionComponent->ForceProgressValue(std::stoi(GeneralUtils::UTF16ToWTF8(achievementID)),
static_cast<uint32_t>(MissionTaskType::MISSION_TASK_TYPE_SCRIPT),
self->GetLOT());
}
}
}
self->ScheduleKillAfterUpdate();
}
void ExplodingAsset::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) {
/*
if msg.objId:BelongsToFaction{factionID = 1}.bIsInFaction then
if (msg.status == "ENTER") then
self:PlayAnimation{ animationID = "bounce" }
self:PlayFXEffect{ name = "bouncin", effectType = "anim" }
self:SetVar("playersNearChest", (self:GetVar("playersNearChest") + 1 ))
elseif (msg.status == "LEAVE") then
self:SetVar("playersNearChest", (self:GetVar("playersNearChest") - 1 ))
if self:GetVar("playersNearChest") < 1 then
self:PlayAnimation{ animationID = "idle" }
self:StopFXEffect{ name = "bouncin" }
self:SetVar("playersNearChest", 0)
end
end
end
*/
auto* destuctableComponent = entering->GetComponent<DestroyableComponent>();
if (destuctableComponent == nullptr) return;
const auto& factions = destuctableComponent->GetFactionIDs();
if (!std::count(factions.begin(), factions.end(), 1)) return;
if (status == "ENTER") {
GameMessages::SendPlayAnimation(self, u"bounce");
GameMessages::SendPlayFXEffect(self, -1, u"anim", "bouncin", LWOOBJID_EMPTY, 1, 1, true);
self->SetVar(u"playersNearChest", self->GetVar<int32_t>(u"playersNearChest") + 1);
} else if (status == "LEAVE") {
self->SetVar(u"playersNearChest", self->GetVar<int32_t>(u"playersNearChest") - 1);
if (self->GetVar<int32_t>(u"playersNearChest") < 1) {
GameMessages::SendPlayAnimation(self, u"idle");
GameMessages::SendStopFXEffect(self, true, "bouncin");
self->SetVar<int32_t>(u"playersNearChest", 0);
}
}
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include "CppScripts.h"
class ExplodingAsset : public CppScripts::Script
{
public:
void OnStartup(Entity* self);
void OnHit(Entity* self, Entity* attacker);
void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status);
};

View File

@@ -0,0 +1,21 @@
#include "ForceVolumeServer.h"
#include "PhantomPhysicsComponent.h"
#include "EntityManager.h"
void ForceVolumeServer::OnStartup(Entity* self) {
auto* phantomPhysicsComponent = self->GetComponent<PhantomPhysicsComponent>();
if (phantomPhysicsComponent == nullptr) return;
const auto forceAmount = self->GetVar<float>(u"ForceAmt");
const auto forceX = self->GetVar<float>(u"ForceX");
const auto forceY = self->GetVar<float>(u"ForceY");
const auto forceZ = self->GetVar<float>(u"ForceZ");
phantomPhysicsComponent->SetEffectType(0); // PUSH
phantomPhysicsComponent->SetDirectionalMultiplier(forceAmount);
phantomPhysicsComponent->SetDirection({ forceX, forceY, forceZ });
phantomPhysicsComponent->SetPhysicsEffectActive(true);
EntityManager::Instance()->SerializeEntity(self);
}

View File

@@ -0,0 +1,8 @@
#pragma once
#include "CppScripts.h"
class ForceVolumeServer : public CppScripts::Script
{
public:
void OnStartup(Entity* self) override;
};

View File

@@ -0,0 +1,35 @@
#include "GrowingFlower.h"
#include "MissionComponent.h"
void GrowingFlower::OnSkillEventFired(Entity* self, Entity* target, const std::string& message) {
if (!self->GetVar<bool>(u"blooming") && (message == "waterspray" || message == "shovelgrow")) {
self->SetVar<bool>(u"blooming", true);
self->SetNetworkVar(u"blooming", true);
self->AddTimer("FlowerDie", GrowingFlower::aliveTime);
const auto mission1 = self->GetVar<int32_t>(u"missionID");
const auto mission2 = self->GetVar<int32_t>(u"missionID2");
LootGenerator::Instance().DropActivityLoot(target, self, self->GetLOT(), 0);
auto* missionComponent = target->GetComponent<MissionComponent>();
if (missionComponent != nullptr) {
for (const auto mission : achievementIDs)
missionComponent->ForceProgressTaskType(mission, static_cast<uint32_t>(MissionTaskType::MISSION_TASK_TYPE_SCRIPT), 1);
if (mission1 && missionComponent->GetMissionState(mission1) == MissionState::MISSION_STATE_ACTIVE)
missionComponent->ForceProgressTaskType(mission1, static_cast<uint32_t>(MissionTaskType::MISSION_TASK_TYPE_SCRIPT), 1);
if (mission2 && missionComponent->GetMissionState(mission2) == MissionState::MISSION_STATE_ACTIVE)
missionComponent->ForceProgressTaskType(mission2, static_cast<uint32_t>(MissionTaskType::MISSION_TASK_TYPE_SCRIPT), 1);
}
}
}
void GrowingFlower::OnTimerDone(Entity* self, std::string message) {
if (message == "FlowerDie") {
self->Smash();
}
}
const std::vector<uint32_t> GrowingFlower::achievementIDs = { 143, 152, 153, 1409, 1507, 1544, 1581, 1845 };

View File

@@ -0,0 +1,11 @@
#pragma once
#include "CppScripts.h"
class GrowingFlower : public CppScripts::Script {
public:
void OnSkillEventFired(Entity* self, Entity* target, const std::string& message) override;
void OnTimerDone(Entity* self, std::string message) override;
private:
static const std::vector<uint32_t> achievementIDs;
constexpr static const float aliveTime = 16.0f;
};

View File

@@ -0,0 +1,20 @@
#include "ImaginationBackpackHealServer.h"
#include "GameMessages.h"
#include "MissionComponent.h"
void ImaginationBackpackHealServer::OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) {
if (message == "CastImaginationBackpack") {
auto healMission = self->GetVar<int32_t>(u"FXOffMis");
if (healMission == 0)
healMission = self->GetVar<int32_t>(u"FXOnMis");
if (healMission == 0)
return;
auto* missionComponent = caster->GetComponent<MissionComponent>();
if (missionComponent != nullptr && missionComponent->GetMissionState(healMission) == MissionState::MISSION_STATE_ACTIVE) {
missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, self->GetLOT());
GameMessages::SendNotifyClientObject(self->GetObjectID(), u"ClearMaelstrom", 0, 0,
caster->GetObjectID(), "", caster->GetSystemAddress());
}
}
}

View File

@@ -0,0 +1,6 @@
#pragma once
#include "CppScripts.h"
class ImaginationBackpackHealServer : public CppScripts::Script {
void OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) override;
};

View File

@@ -0,0 +1 @@
#include "InvalidScript.h"

View File

@@ -0,0 +1,6 @@
#pragma once
#include "CppScripts.h"
class InvalidScript : public CppScripts::Script
{
};

View File

@@ -0,0 +1,19 @@
#include "MailBoxServer.h"
#include "AMFFormat.h"
#include "GameMessages.h"
void MailBoxServer::OnUse(Entity* self, Entity* user) {
AMFStringValue* value = new AMFStringValue();
value->SetStringValue("Mail");
AMFArrayValue args;
args.InsertValue("state", value);
GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "pushGameState", &args);
}
void MailBoxServer::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) {
if (args == "toggleMail") {
AMFArrayValue args;
args.InsertValue("visible", new AMFFalseValue());
GameMessages::SendUIMessageServerToSingleClient(sender, sender->GetSystemAddress(), "ToggleMail", &args);
}
}

View File

@@ -0,0 +1,16 @@
#pragma once
#include "CppScripts.h"
class MailBoxServer : public CppScripts::Script {
public:
/**
* When a mailbox is interacted with, this method updates the player game state
* to be in a mailbox.
*
* @param self The object that owns this script.
* @param user The user that interacted with this Entity.
*/
void OnUse(Entity* self, Entity* user) override;
void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override;
};

View File

@@ -0,0 +1,6 @@
set(DSCRIPTS_SOURCES_02_SERVER_MAP_GENERAL_NINJAGO
"NjRailActivatorsServer.cpp"
"NjRailPostServer.cpp"
"NjIceRailActivator.cpp"
"NjhubLavaPlayerDeathTrigger.cpp"
PARENT_SCOPE)

View File

@@ -0,0 +1,25 @@
#include "NjIceRailActivator.h"
#include "EntityManager.h"
#include "GameMessages.h"
void NjIceRailActivator::OnPlayerRailArrived(Entity* self, Entity* sender, const std::u16string& pathName,
int32_t waypoint) {
const auto breakPoint = self->GetVar<int32_t>(BreakpointVariable);
if (breakPoint == waypoint) {
const auto& blockGroup = self->GetVar<std::u16string>(BlockGroupVariable);
for (auto* block : EntityManager::Instance()->GetEntitiesInGroup(GeneralUtils::UTF16ToWTF8(blockGroup))) {
GameMessages::SendPlayAnimation(block, u"explode");
const auto blockID = block->GetObjectID();
self->AddCallbackTimer(1.0f, [self, blockID]() {
auto* block = EntityManager::Instance()->GetEntity(blockID);
if (block != nullptr) {
block->Kill(self);
}
});
}
}
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include "NjRailActivatorsServer.h"
class NjIceRailActivator : public NjRailActivatorsServer {
void OnPlayerRailArrived(Entity* self, Entity* sender, const std::u16string& pathName, int32_t waypoint) override;
private:
std::u16string BreakpointVariable = u"BreakPoint";
std::u16string BlockGroupVariable = u"BlockGroup";
std::u16string IceBlockVariable = u"IceBlock";
};

View File

@@ -0,0 +1,16 @@
#include "NjRailActivatorsServer.h"
#include "RebuildComponent.h"
#include "Character.h"
void NjRailActivatorsServer::OnUse(Entity* self, Entity* user) {
const auto flag = self->GetVar<int32_t>(u"RailFlagNum");
auto* rebuildComponent = self->GetComponent<RebuildComponent>();
// Only allow use if this is not a quick build or the quick build is built
if (rebuildComponent == nullptr || rebuildComponent->GetState() == REBUILD_COMPLETED) {
auto* character = user->GetCharacter();
if (character != nullptr) {
character->SetPlayerFlag(flag, true);
}
}
}

View File

@@ -0,0 +1,6 @@
#pragma once
#include "NjRailPostServer.h"
class NjRailActivatorsServer : public NjRailPostServer {
void OnUse(Entity* self, Entity* user) override;
};

View File

@@ -0,0 +1,51 @@
#include "NjRailPostServer.h"
#include "RebuildComponent.h"
#include "EntityManager.h"
void NjRailPostServer::OnStartup(Entity* self) {
auto* rebuildComponent = self->GetComponent<RebuildComponent>();
if (rebuildComponent != nullptr) {
self->SetNetworkVar<bool>(NetworkNotActiveVariable, true);
}
}
void NjRailPostServer::OnNotifyObject(Entity* self, Entity* sender, const std::string& name, int32_t param1,
int32_t param2) {
if (name == "PostRebuilt") {
self->SetNetworkVar<bool>(NetworkNotActiveVariable, false);
} else if (name == "PostDied") {
self->SetNetworkVar<bool>(NetworkNotActiveVariable, true);
}
}
void NjRailPostServer::OnRebuildNotifyState(Entity* self, eRebuildState state) {
if (state == REBUILD_COMPLETED) {
auto* relatedRail = GetRelatedRail(self);
if (relatedRail == nullptr)
return;
relatedRail->NotifyObject(self, "PostRebuilt");
if (self->GetVar<bool>(NotActiveVariable))
return;
self->SetNetworkVar(NetworkNotActiveVariable, false);
} else if (state == REBUILD_RESETTING) {
auto* relatedRail = GetRelatedRail(self);
if (relatedRail == nullptr)
return;
relatedRail->NotifyObject(self, "PostDied");
}
}
Entity* NjRailPostServer::GetRelatedRail(Entity* self) {
const auto& railGroup = self->GetVar<std::u16string>(RailGroupVariable);
if (!railGroup.empty()) {
for (auto* entity : EntityManager::Instance()->GetEntitiesInGroup(GeneralUtils::UTF16ToWTF8(railGroup))) {
return entity;
}
}
return nullptr;
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include "CppScripts.h"
class NjRailPostServer : public CppScripts::Script {
void OnStartup(Entity* self) override;
void OnNotifyObject(Entity* self, Entity* sender, const std::string& name, int32_t param1, int32_t param2) override;
void OnRebuildNotifyState(Entity* self, eRebuildState state) override;
private:
Entity* GetRelatedRail(Entity* self);
const std::u16string NetworkNotActiveVariable = u"NetworkNotActive";
const std::u16string NotActiveVariable = u"NotActive";
const std::u16string RailGroupVariable = u"RailGroup";
};

View File

@@ -0,0 +1,9 @@
#include "NjhubLavaPlayerDeathTrigger.h"
#include "Entity.h"
void NjhubLavaPlayerDeathTrigger::OnCollisionPhantom(Entity* self, Entity* target) {
if (!target->IsPlayer())
return;
target->Smash(self->GetObjectID(), VIOLENT, u"drown");
}

View File

@@ -0,0 +1,6 @@
#pragma once
#include "CppScripts.h"
class NjhubLavaPlayerDeathTrigger : public CppScripts::Script {
void OnCollisionPhantom(Entity* self, Entity* target) override;
};

View File

@@ -0,0 +1,12 @@
#include "NjRailSwitch.h"
#include "GameMessages.h"
void NjRailSwitch::OnUse(Entity* self, Entity* user) {
// const auto path = self->GetVar<std::u16string>(u"rail_path");
// const auto pathStart = self->GetVar<uint32_t>(u"rail_path_start");
// const auto pathGoForward = self->GetVar<bool>(u"rail_path_direction");
// const auto cinematicName = self->GetVar<std::u16string>(u"cinematic");
//
// GameMessages::SendSetRailMovement(self->GetObjectID(), pathGoForward, path, pathStart, user->GetSystemAddress());
// GameMessages::SendPlayCinematic(self->GetObjectID(), cinematicName, user->GetSystemAddress());
}

View File

@@ -0,0 +1,6 @@
#pragma once
#include "CppScripts.h"
class NjRailSwitch : public CppScripts::Script {
void OnUse(Entity* self, Entity* user) override;
};

View File

@@ -0,0 +1,234 @@
#include "dZoneManager.h"
#include "PetDigServer.h"
#include "MissionComponent.h"
#include "EntityManager.h"
#include "Character.h"
#include "PetComponent.h"
std::vector<LWOOBJID> PetDigServer::treasures{};
const DigInfo PetDigServer::defaultDigInfo = DigInfo{ 3495, -1, -1, false, false, false, false };
/**
* Summary of all the special treasure behaviors, indexed by their lot
*/
const std::map<LOT, DigInfo> PetDigServer::digInfoMap{
// Regular treasures
{3495, defaultDigInfo},
// Pet cove treasure
{7612, DigInfo { 7612, -1, -1, false, false, false, false }},
// Gnarled Forest flag treasure
{7410, DigInfo { 7410, -1, -1, false, true, false, false }},
// Gnarled Forest crab treasure
{9308, DigInfo { 9308, 7694, -1, false, false, false, false }},
// Avant Gardens mission treasure
{9307, DigInfo { 9307, -1, -1, false, true, false, true }},
// Avant Gardens bouncer treasure
{7559, DigInfo { 7559, -1, -1, false, false, true, false }},
// Crux Prime dragon treasure
{13098, DigInfo { 13098, 13067, 1298, false, false, false, false }},
// Bone treasure (can only be digged using the dragon)
{12192, DigInfo { 12192, -1, -1, true, false, false, false }},
};
void PetDigServer::OnStartup(Entity* self) {
treasures.push_back(self->GetObjectID());
const auto digInfoIterator = digInfoMap.find(self->GetLOT());
const auto digInfo = digInfoIterator != digInfoMap.end() ? digInfoIterator->second : defaultDigInfo;
// Reset any bouncers that might've been created by the previous dig
if (digInfo.bouncer) {
auto bounceNumber = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"BouncerNumber"));
auto bouncerSpawners = dZoneManager::Instance()->GetSpawnersByName("PetBouncer" + bounceNumber);
auto switchSpawners = dZoneManager::Instance()->GetSpawnersByName("PetBouncerSwitch" + bounceNumber);
for (auto* bouncerSpawner : bouncerSpawners) {
for (auto* bouncer : bouncerSpawner->m_Info.nodes)
bouncerSpawner->Deactivate();
bouncerSpawner->Reset();
}
for (auto* switchSpawner : switchSpawners) {
switchSpawner->Deactivate();
switchSpawner->Reset();
}
}
}
void PetDigServer::OnDie(Entity* self, Entity* killer) {
const auto iterator = std::find(treasures.begin(), treasures.end(), self->GetObjectID());
if (iterator != treasures.end()) {
treasures.erase(iterator);
}
auto* owner = killer->GetOwner();
const auto digInfoIterator = digInfoMap.find(self->GetLOT());
const auto digInfo = digInfoIterator != digInfoMap.end() ? digInfoIterator->second : defaultDigInfo;
if (digInfo.spawnLot >= 0) {
PetDigServer::SpawnPet(self, owner, digInfo);
} else if (digInfo.builderOnly) {
// Some treasures may only be retrieved by the player that built the diggable
auto builder = self->GetVar<LWOOBJID>(u"builder"); // Set by the pet dig build script
if (builder != owner->GetObjectID())
return;
} else if (digInfo.xBuild) {
PetDigServer::HandleXBuildDig(self, owner, killer);
return;
} else if (digInfo.bouncer) {
PetDigServer::HandleBouncerDig(self, owner);
}
PetDigServer::ProgressPetDigMissions(owner, self);
self->SetNetworkVar<bool>(u"treasure_dug", true);
// TODO: Reset other pets
// Handles smashing leftovers (edge case for the AG X)
auto* xObject = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"X"));
if (xObject != nullptr) {
xObject->Smash(xObject->GetObjectID(), VIOLENT);
}
}
void PetDigServer::HandleXBuildDig(const Entity* self, Entity* owner, Entity* pet) {
auto playerID = self->GetVar<LWOOBJID>(u"builder");
if (playerID == LWOOBJID_EMPTY || playerID != owner->GetObjectID())
return;
auto* playerEntity = EntityManager::Instance()->GetEntity(playerID);
if (!playerEntity || !playerEntity->GetParentUser() || !playerEntity->GetParentUser()->GetLastUsedChar())
return;
auto* player = playerEntity->GetCharacter();
const auto groupID = self->GetVar<std::u16string>(u"groupID");
auto playerFlag = 0;
// The flag that the player dug up
if (groupID == u"Flag1") {
playerFlag = 61;
} else if (groupID == u"Flag2") {
playerFlag = 62;
} else if (groupID == u"Flag3") {
playerFlag = 63;
}
// If the player doesn't have the flag yet
if (playerFlag != 0 && !player->GetPlayerFlag(playerFlag)) {
auto* petComponent = pet->GetComponent<PetComponent>();
if (petComponent != nullptr) {
// TODO: Pet state = 9 ??
}
// Shows the flag object to the player
player->SetPlayerFlag(playerFlag, true);
}
auto* xObject = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"X"));
if (xObject != nullptr) {
xObject->Smash(xObject->GetObjectID(), VIOLENT);
}
}
void PetDigServer::HandleBouncerDig(const Entity* self, const Entity* owner) {
auto bounceNumber = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"BouncerNumber"));
auto bouncerSpawners = dZoneManager::Instance()->GetSpawnersByName("PetBouncer" + bounceNumber);
auto switchSpawners = dZoneManager::Instance()->GetSpawnersByName("PetBouncerSwitch" + bounceNumber);
for (auto* bouncerSpawner : bouncerSpawners) {
bouncerSpawner->Activate();
}
for (auto* switchSpawner : switchSpawners) {
switchSpawner->Activate();
}
}
/**
* Progresses the Can You Dig It mission and the Pet Excavator Achievement if the player has never completed it yet
* \param owner the owner that just made a pet dig something up
*/
void PetDigServer::ProgressPetDigMissions(const Entity* owner, const Entity* chest) {
auto* missionComponent = owner->GetComponent<MissionComponent>();
if (missionComponent != nullptr) {
// Can You Dig It progress
const auto digMissionState = missionComponent->GetMissionState(843);
if (digMissionState == MissionState::MISSION_STATE_ACTIVE) {
missionComponent->ForceProgress(843, 1216, 1);
}
// Pet Excavator progress
const auto excavatorMissionState = missionComponent->GetMissionState(505);
if (excavatorMissionState == MissionState::MISSION_STATE_ACTIVE) {
if (chest->HasVar(u"PetDig")) {
int32_t playerFlag = 1260 + chest->GetVarAs<int32_t>(u"PetDig");
Character* player = owner->GetCharacter();
// check if player flag is set
if (!player->GetPlayerFlag(playerFlag)) {
missionComponent->ForceProgress(505, 767, 1);
player->SetPlayerFlag(playerFlag, 1);
}
}
}
}
}
/**
* Some treasures spawn special pets, this handles that case
* \param owner the owner that just made a pet dig something up
* \param digInfo information regarding the treasure, will also contain info about the pet to spawn
*/
void PetDigServer::SpawnPet(Entity* self, const Entity* owner, const DigInfo digInfo) {
// Some treasures require a mission to be active
if (digInfo.requiredMission >= 0) {
auto* missionComponent = owner->GetComponent<MissionComponent>();
if (missionComponent != nullptr && missionComponent->GetMissionState(digInfo.requiredMission) < MissionState::MISSION_STATE_ACTIVE) {
return;
}
}
EntityInfo info{};
info.lot = digInfo.spawnLot;
info.pos = self->GetPosition();
info.rot = self->GetRotation();
info.spawnerID = self->GetSpawnerID();
info.settings = {
new LDFData<LWOOBJID>(u"tamer", owner->GetObjectID()),
new LDFData<std::string>(u"group", "pet" + std::to_string(owner->GetObjectID())),
new LDFData<std::string>(u"spawnAnim", "spawn-pet"),
new LDFData<float>(u"spawnTimer", 1.0)
};
auto* spawnedPet = EntityManager::Instance()->CreateEntity(info);
EntityManager::Instance()->ConstructEntity(spawnedPet);
}
Entity* PetDigServer::GetClosestTresure(NiPoint3 position) {
float closestDistance = 0;
Entity* closest = nullptr;
for (const auto tresureId : treasures) {
auto* tresure = EntityManager::Instance()->GetEntity(tresureId);
if (tresure == nullptr) continue;
float distance = Vector3::DistanceSquared(tresure->GetPosition(), position);
if (closest == nullptr || distance < closestDistance) {
closestDistance = distance;
closest = tresure;
}
}
return closest;
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include "CppScripts.h"
struct DigInfo {
LOT digLot; // The lot of the chest
LOT spawnLot; // Option lot of pet to spawn
int32_t requiredMission; // Optional mission required before pet can be spawned, if < 0 == don't use
bool specificPet; // This treasure requires a specific pet to be dug up
bool xBuild; // This treasure is retrieved from a buildable cross
bool bouncer; // This treasure spawns a bouncer
bool builderOnly; // Only the builder of this diggable may access the rewards, for example with crosses
};
class PetDigServer : public CppScripts::Script
{
public:
void OnStartup(Entity* self) override;
void OnDie(Entity* self, Entity* killer) override;
static Entity* GetClosestTresure(NiPoint3 position);
private:
static void ProgressPetDigMissions(const Entity* owner, const Entity* chest);
static void SpawnPet(Entity* self, const Entity* owner, DigInfo digInfo);
static void HandleXBuildDig(const Entity* self, Entity* owner, Entity* pet);
static void HandleBouncerDig(const Entity* self, const Entity* owner);
static std::vector<LWOOBJID> treasures;
static const DigInfo defaultDigInfo;
static const std::map<LOT, DigInfo> digInfoMap;
};

View File

@@ -0,0 +1,25 @@
#include "PropertyDevice.h"
#include "GameMessages.h"
#include "EntityManager.h"
#include "MissionComponent.h"
void PropertyDevice::OnStartup(Entity* self) {
auto* zoneControl = EntityManager::Instance()->GetZoneControlEntity();
if (zoneControl != nullptr) {
zoneControl->OnFireEventServerSide(self, "CheckForPropertyOwner");
}
}
void PropertyDevice::OnRebuildComplete(Entity* self, Entity* target) {
auto propertyOwnerID = self->GetNetworkVar<std::string>(m_PropertyOwnerVariable);
if (propertyOwnerID == std::to_string(LWOOBJID_EMPTY))
return;
auto* missionComponent = target->GetComponent<MissionComponent>();
if (missionComponent != nullptr) {
if (missionComponent->GetMissionState(m_PropertyMissionID) == MissionState::MISSION_STATE_ACTIVE) {
GameMessages::SendPlayFXEffect(self->GetObjectID(), 641, u"create", "callhome");
missionComponent->ForceProgress(m_PropertyMissionID, 1793, self->GetLOT());
}
}
}

View File

@@ -0,0 +1,9 @@
#pragma once
#include "CppScripts.h"
class PropertyDevice : public CppScripts::Script {
void OnStartup(Entity* self) override;
void OnRebuildComplete(Entity* self, Entity* target) override;
const std::u16string m_PropertyOwnerVariable = u"PropertyOwnerID";
const uint32_t m_PropertyMissionID = 1291;
};

View File

@@ -0,0 +1,32 @@
#include "PropertyPlatform.h"
#include "RebuildComponent.h"
#include "GameMessages.h"
void PropertyPlatform::OnRebuildComplete(Entity* self, Entity* target) {
// auto* movingPlatform = self->GetComponent<MovingPlatformComponent>();
// if (movingPlatform != nullptr) {
// movingPlatform->StopPathing();
// movingPlatform->SetNoAutoStart(true);
// }
GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0,
0, 0, MovementPlatformState::Stationary);
}
void PropertyPlatform::OnUse(Entity* self, Entity* user) {
auto* rebuildComponent = self->GetComponent<RebuildComponent>();
if (rebuildComponent != nullptr && rebuildComponent->GetState() == REBUILD_COMPLETED) {
// auto* movingPlatform = self->GetComponent<MovingPlatformComponent>();
// if (movingPlatform != nullptr) {
// movingPlatform->GotoWaypoint(1);
// }
GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0,
1, 1, MovementPlatformState::Moving);
self->AddCallbackTimer(movementDelay + effectDelay, [self, this]() {
self->SetNetworkVar<float_t>(u"startEffect", dieDelay);
self->AddCallbackTimer(dieDelay, [self]() {
self->Smash();
});
});
}
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include "CppScripts.h"
class PropertyPlatform : public CppScripts::Script {
public:
void OnUse(Entity* self, Entity* user) override;
void OnRebuildComplete(Entity* self, Entity* target) override;
private:
float_t movementDelay = 10.0f;
float_t effectDelay = 5.0f;
float_t dieDelay = 5.0f;
uint32_t desiredWaypoint = 1;
};

View File

@@ -0,0 +1,65 @@
#include "QbEnemyStunner.h"
#include "SkillComponent.h"
#include "DestroyableComponent.h"
void QbEnemyStunner::OnRebuildComplete(Entity* self, Entity* target) {
auto* destroyable = self->GetComponent<DestroyableComponent>();
if (destroyable != nullptr) {
destroyable->SetFaction(115);
}
auto skillComponent = self->GetComponent<SkillComponent>();
if (!skillComponent) return;
// Get the skill IDs of this object.
CDObjectSkillsTable* skillsTable = CDClientManager::Instance()->GetTable<CDObjectSkillsTable>("ObjectSkills");
auto skills = skillsTable->Query([=](CDObjectSkills entry) {return (entry.objectTemplate == self->GetLOT()); });
std::map<uint32_t, uint32_t> skillBehaviorMap;
// For each skill, cast it with the associated behavior ID.
for (auto skill : skills) {
CDSkillBehaviorTable* skillBehaviorTable = CDClientManager::Instance()->GetTable<CDSkillBehaviorTable>("SkillBehavior");
CDSkillBehavior behaviorData = skillBehaviorTable->GetSkillByID(skill.skillID);
skillBehaviorMap.insert(std::make_pair(skill.skillID, behaviorData.behaviorID));
}
// If there are no skills found, insert a default skill to use.
if (skillBehaviorMap.size() == 0) {
skillBehaviorMap.insert(std::make_pair(499U, 6095U));
}
// Start all skills associated with the object next tick
self->AddTimer("TickTime", 0);
self->AddTimer("PlayEffect", 20);
self->SetVar<std::map<uint32_t, uint32_t>>(u"skillBehaviorMap", skillBehaviorMap);
}
void QbEnemyStunner::OnTimerDone(Entity* self, std::string timerName) {
if (timerName == "DieTime") {
self->Smash();
self->CancelAllTimers();
} else if (timerName == "PlayEffect") {
self->SetNetworkVar(u"startEffect", 5.0f, UNASSIGNED_SYSTEM_ADDRESS);
self->AddTimer("DieTime", 5.0f);
} else if (timerName == "TickTime") {
auto* skillComponent = self->GetComponent<SkillComponent>();
if (skillComponent != nullptr) {
auto skillBehaviorMap = self->GetVar<std::map<uint32_t, uint32_t>>(u"skillBehaviorMap");
if (skillBehaviorMap.size() == 0) {
// Should no skills have been found, default to the mermaid stunner
skillComponent->CalculateBehavior(499U, 6095U, LWOOBJID_EMPTY);
} else {
for (auto pair : skillBehaviorMap) {
skillComponent->CalculateBehavior(pair.first, pair.second, LWOOBJID_EMPTY);
}
}
}
self->AddTimer("TickTime", 1);
}
}

View File

@@ -0,0 +1,9 @@
#pragma once
#include "CppScripts.h"
class QbEnemyStunner : public CppScripts::Script
{
public:
void OnRebuildComplete(Entity* self, Entity* target) override;
void OnTimerDone(Entity* self, std::string timerName) override;
};

View File

@@ -0,0 +1,136 @@
#include "QbSpawner.h"
#include "BaseCombatAIComponent.h"
#include "MovementAIComponent.h"
void QbSpawner::OnStartup(Entity* self) {
auto mobNum = self->GetVar<int>(u"mobNum");
auto spawnDist = self->GetVar<float>(u"spawnDist");
auto mobTemplate = self->GetVar<LWOOBJID>(u"mobTemplate");
auto spawnTime = self->GetVar<float>(u"spawnTime");
if (!mobNum) self->SetVar<int>(u"mobNum", m_DefaultMobNum);
if (!spawnDist) self->SetVar<float>(u"spawnDist", m_DefaultSpawnDist);
if (!mobTemplate) self->SetVar<LWOOBJID>(u"mobTemplate", m_DefaultMobTemplate);
if (!spawnTime) self->SetVar<float>(u"spawnTime", m_DefaultSpawnTime);
// go ahead and setup the mob table here
std::vector<LWOOBJID> mobTable;
mobTable.assign(self->GetVar<int>(u"mobNum"), LWOOBJID_EMPTY);
self->SetVar<std::vector<LWOOBJID>>(u"mobTable", mobTable);
}
void QbSpawner::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) {
auto gateObjID = sender->GetObjectID();
if (!gateObjID) return;
if (args == "spawnMobs") {
self->SetVar(u"gateObj", gateObjID);
auto spawnTime = self->GetVar<float>(u"spawnTime");
self->AddTimer("SpawnMobEnemies", spawnTime);
}
}
void QbSpawner::OnTimerDone(Entity* self, std::string timerName) {
if (timerName == "SpawnMobEnemies") {
auto mobTable = self->GetVar<std::vector<LWOOBJID>>(u"mobTable");
auto spawnDist = self->GetVar<float>(u"spawnDist");
auto mobTemplate = self->GetVar<LWOOBJID>(u"mobTemplate");
auto gateObjID = self->GetVar<LWOOBJID>(u"gateObj");
if (!gateObjID) return;
auto* gate = EntityManager::Instance()->GetEntity(gateObjID);
if (!gate) return;
auto oPos = gate->GetPosition();
auto oDir = gate->GetRotation().GetForwardVector();
NiPoint3 newPos(
oPos.x + (oDir.x * spawnDist),
oPos.y,
oPos.z + (oDir.z * spawnDist)
);
auto newRot = NiQuaternion::LookAt(newPos, oPos);
for (int i = 0; i < mobTable.size(); i++) {
int posOffset = -10;
if (mobTable[i] == LWOOBJID_EMPTY) {
posOffset = posOffset + 5 * i;
auto newOffset = newPos;
newOffset.z = newOffset.z + posOffset;
EntityInfo info{};
info.lot = mobTemplate;
info.pos = newOffset;
info.rot = newRot;
info.spawnerID = self->GetObjectID();
info.spawnerNodeID = 0;
info.settings = {
new LDFData<bool>(u"no_timed_spawn", true),
new LDFData<float>(u"aggroRadius", 70),
new LDFData<float>(u"softtetherRadius", 80),
new LDFData<float>(u"tetherRadius", 90),
new LDFData<float>(u"wanderRadius", 5),
new LDFData<int>(u"mobTableLoc", i)
};
auto* child = EntityManager::Instance()->CreateEntity(info, nullptr, self);
EntityManager::Instance()->ConstructEntity(child);
OnChildLoaded(self, child);
} else {
auto* mob = EntityManager::Instance()->GetEntity(mobTable[i]);
AggroTargetObject(self, mob);
}
}
}
}
void QbSpawner::OnChildLoaded(Entity* self, Entity* child) {
auto mobTable = self->GetVar<std::vector<LWOOBJID>>(u"mobTable");
auto tableLoc = child->GetVar<int>(u"mobTableLoc");
mobTable[tableLoc] = child->GetObjectID();
self->SetVar<std::vector<LWOOBJID>>(u"mobTable", mobTable);
AggroTargetObject(self, child);
const auto selfID = self->GetObjectID();
child->AddDieCallback([this, selfID, child]() {
auto* self = EntityManager::Instance()->GetEntity(selfID);
OnChildRemoved(self, child);
}
);
}
void QbSpawner::OnChildRemoved(Entity* self, Entity* child) {
auto mobTable = self->GetVar<std::vector<LWOOBJID>>(u"mobTable");
auto tableLoc = child->GetVar<int>(u"mobTableLoc");
mobTable[tableLoc] = LWOOBJID_EMPTY;
self->SetVar<std::vector<LWOOBJID>>(u"mobTable", mobTable);
}
void QbSpawner::AggroTargetObject(Entity* self, Entity* enemy) {
auto* baseCombatAIComponent = enemy->GetComponent<BaseCombatAIComponent>();
if (!baseCombatAIComponent) return;
auto gateObjID = self->GetVar<LWOOBJID>(u"gateObj");
if (gateObjID) {
auto* gate = EntityManager::Instance()->GetEntity(gateObjID);
if (gate) {
auto* movementAIComponent = enemy->GetComponent<MovementAIComponent>();
if (movementAIComponent) movementAIComponent->SetDestination(gate->GetPosition());
baseCombatAIComponent->Taunt(gateObjID, 1000);
}
}
auto playerObjID = self->GetVar<LWOOBJID>(u"player");
if (playerObjID) {
baseCombatAIComponent->Taunt(playerObjID, 100);
}
}

View File

@@ -0,0 +1,17 @@
#pragma once
#include "CppScripts.h"
class QbSpawner : public CppScripts::Script {
public:
void OnStartup(Entity* self) override;
void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override;
void OnTimerDone(Entity* self, std::string timerName) override;
void OnChildLoaded(Entity* self, Entity* child);
void OnChildRemoved(Entity* self, Entity* child);
void AggroTargetObject(Entity* self, Entity* enemy);
private:
const int m_DefaultMobNum = 3;
const float m_DefaultSpawnDist = 25.0;
const LWOOBJID m_DefaultMobTemplate = 4712;
const float m_DefaultSpawnTime = 2.0;
};

View File

@@ -0,0 +1,48 @@
#include "StoryBoxInteractServer.h"
#include "Character.h"
#include "GameMessages.h"
#include "dServer.h"
#include "AMFFormat.h"
void StoryBoxInteractServer::OnUse(Entity* self, Entity* user) {
if (self->GetVar<bool>(u"hasCustomText")) {
const auto& customText = self->GetVar<std::string>(u"customText");
{
AMFArrayValue args;
auto* state = new AMFStringValue();
state->SetStringValue("Story");
args.InsertValue("state", state);
GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "pushGameState", &args);
}
user->AddCallbackTimer(0.1f, [user, customText]() {
AMFArrayValue args;
auto* text = new AMFStringValue();
text->SetStringValue(customText);
args.InsertValue("visible", new AMFTrueValue());
args.InsertValue("text", text);
GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "ToggleStoryBox", &args);
});
return;
}
const auto storyText = self->GetVarAsString(u"storyText");
int32_t boxFlag = self->GetVar<int32_t>(u"altFlagID");
if (boxFlag <= 0) {
boxFlag = (10000 + Game::server->GetZoneID() + std::stoi(storyText.substr(storyText.length() - 2)));
}
if (user->GetCharacter()->GetPlayerFlag(boxFlag) == false) {
user->GetCharacter()->SetPlayerFlag(boxFlag, true);
GameMessages::SendFireEventClientSide(self->GetObjectID(), user->GetSystemAddress(), u"achieve", LWOOBJID_EMPTY, 0, -1, LWOOBJID_EMPTY);
}
}

View File

@@ -0,0 +1,7 @@
#pragma once
#include "CppScripts.h"
class StoryBoxInteractServer : public CppScripts::Script {
public:
void OnUse(Entity* self, Entity* user);
};

View File

@@ -0,0 +1,36 @@
#include "TokenConsoleServer.h"
#include "InventoryComponent.h"
#include "GameMessages.h"
#include "Character.h"
//2021-05-03 - max - added script, omitted some parts related to inheritance in lua which we don't need
void TokenConsoleServer::OnUse(Entity* self, Entity* user) {
auto* inv = static_cast<InventoryComponent*>(user->GetComponent(COMPONENT_TYPE_INVENTORY));
//make sure the user has the required amount of infected bricks
if (inv && inv->GetLotCount(6194) >= bricksToTake) {
//yeet the bricks
inv->RemoveItem(6194, bricksToTake);
//play sound
GameMessages::SendPlayNDAudioEmitter(self, user->GetSystemAddress(), "947d0d52-c7f8-4516-8dee-e1593a7fd1d1");
//figure out which faction the player belongs to:
auto character = user->GetCharacter();
if (!character) return;
// At this point the player has to be in a faction.
LOT tokenLOT = 0;
if (character->GetPlayerFlag(ePlayerFlags::VENTURE_FACTION)) //venture
tokenLOT = 8321;
else if (character->GetPlayerFlag(ePlayerFlags::ASSEMBLY_FACTION)) //assembly
tokenLOT = 8318;
else if (character->GetPlayerFlag(ePlayerFlags::PARADOX_FACTION)) //paradox
tokenLOT = 8320;
else if (character->GetPlayerFlag(ePlayerFlags::SENTINEL_FACTION)) //sentinel
tokenLOT = 8319;
inv->AddItem(tokenLOT, tokensToGive, eLootSourceType::LOOT_SOURCE_NONE);
}
GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID());
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include "CppScripts.h"
class TokenConsoleServer : public CppScripts::Script {
void OnUse(Entity* self, Entity* user) override;
private:
int bricksToTake = 25;
int tokensToGive = 5;
};

View File

@@ -0,0 +1,51 @@
#include "TouchMissionUpdateServer.h"
#include "Entity.h"
#include "GameMessages.h"
#include "MissionComponent.h"
void TouchMissionUpdateServer::OnStartup(Entity* self) {
self->SetProximityRadius(20, "touchCheck"); // Those does not have a collider for some reason?
}
void TouchMissionUpdateServer::OnCollisionPhantom(Entity* self, Entity* target) {
int32_t missionId = self->GetVar<int32_t>(u"TouchCompleteID");
if (missionId == 0) {
return;
}
auto* missionComponent = static_cast<MissionComponent*>(target->GetComponent(COMPONENT_TYPE_MISSION));
if (missionComponent == nullptr) {
return;
}
auto* mission = missionComponent->GetMission(missionId);
if (mission == nullptr) {
return;
}
const auto state = mission->GetMissionState();
if (state >= MissionState::MISSION_STATE_COMPLETE || mission->GetCompletions() > 1) {
return;
}
for (auto* task : mission->GetTasks()) {
if (!task->IsComplete()) {
task->Complete();
}
}
mission->CheckCompletion();
}
void TouchMissionUpdateServer::OnProximityUpdate(Entity* self, Entity* entering, const std::string name, const std::string status) {
if (name != "touchCheck" || status != "ENTER") {
return;
}
OnCollisionPhantom(self, entering);
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include "CppScripts.h"
class TouchMissionUpdateServer : public CppScripts::Script
{
public:
void OnStartup(Entity* self) override;
void OnCollisionPhantom(Entity* self, Entity* target) override;
void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override;
};

View File

@@ -0,0 +1,44 @@
#include "WishingWellServer.h"
#include "ScriptedActivityComponent.h"
#include "GameMessages.h"
void WishingWellServer::OnStartup(Entity* self) {
}
void WishingWellServer::OnUse(Entity* self, Entity* user) {
auto* scriptedActivity = self->GetComponent<ScriptedActivityComponent>();
if (!scriptedActivity->TakeCost(user)) {
return;
}
const auto audio = self->GetVar<std::string>(u"sound1");
if (!audio.empty()) {
GameMessages::SendPlayNDAudioEmitter(self, user->GetSystemAddress(), audio);
}
LootGenerator::Instance().DropActivityLoot(
user,
self,
static_cast<uint32_t>(scriptedActivity->GetActivityID()),
GeneralUtils::GenerateRandomNumber<int32_t>(1, 1000)
);
GameMessages::SendNotifyClientObject(self->GetObjectID(), u"StartCooldown", 0, 0, LWOOBJID_EMPTY, "", user->GetSystemAddress());
const auto userID = user->GetObjectID();
self->AddCallbackTimer(10, [self, userID]() {
auto* user = EntityManager::Instance()->GetEntity(userID);
if (user == nullptr) return;
GameMessages::SendNotifyClientObject(self->GetObjectID(), u"StopCooldown", 0, 0, LWOOBJID_EMPTY, "", user->GetSystemAddress());
});
GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID());
}
void WishingWellServer::OnTimerDone(Entity* self, std::string timerName) {
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include "CppScripts.h"
class WishingWellServer : public CppScripts::Script
{
public:
void OnStartup(Entity* self) override;
void OnUse(Entity* self, Entity* user) override;
void OnTimerDone(Entity* self, std::string timerName) override;
};