mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-10-22 15:28:07 +00:00
Public release of the DLU server code!
Have fun!
This commit is contained in:
507
dScripts/NjMonastryBossInstance.cpp
Normal file
507
dScripts/NjMonastryBossInstance.cpp
Normal file
@@ -0,0 +1,507 @@
|
||||
#include <algorithm>
|
||||
#include "RebuildComponent.h"
|
||||
#include "NjMonastryBossInstance.h"
|
||||
#include "DestroyableComponent.h"
|
||||
#include "EntityManager.h"
|
||||
#include "GameMessages.h"
|
||||
#include "dZoneManager.h"
|
||||
#include "GameMessages.h"
|
||||
#include "BaseCombatAIComponent.h"
|
||||
#include "BuffComponent.h"
|
||||
#include "SkillComponent.h"
|
||||
#include "TeamManager.h"
|
||||
|
||||
// // // // // // //
|
||||
// Event handling //
|
||||
// // // // // // //
|
||||
|
||||
void NjMonastryBossInstance::OnStartup(Entity *self) {
|
||||
auto spawnerNames = std::vector { LedgeFrakjawSpawner, LowerFrakjawSpawner, BaseEnemiesSpawner + std::to_string(1),
|
||||
BaseEnemiesSpawner + std::to_string(2), BaseEnemiesSpawner + std::to_string(3),
|
||||
BaseEnemiesSpawner + std::to_string(4), CounterweightSpawner };
|
||||
|
||||
// Add a notification request for all the spawned entities, corresponds to notifySpawnedObjectLoaded
|
||||
for (const auto& spawnerName : spawnerNames) {
|
||||
for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(spawnerName)) {
|
||||
spawner->AddEntitySpawnedCallback([self, this](Entity* entity) {
|
||||
const auto lot = entity->GetLOT();
|
||||
switch (lot) {
|
||||
case LedgedFrakjawLOT:
|
||||
NjMonastryBossInstance::HandleLedgedFrakjawSpawned(self, entity);
|
||||
return;
|
||||
case CounterWeightLOT:
|
||||
NjMonastryBossInstance::HandleCounterWeightSpawned(self, entity);
|
||||
return;
|
||||
case LowerFrakjawLOT:
|
||||
NjMonastryBossInstance::HandleLowerFrakjawSpawned(self, entity);
|
||||
return;
|
||||
default:
|
||||
NjMonastryBossInstance::HandleWaveEnemySpawned(self, entity);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NjMonastryBossInstance::OnPlayerLoaded(Entity *self, Entity *player) {
|
||||
ActivityTimerStop(self, WaitingForPlayersTimer);
|
||||
|
||||
// Join the player in the activity and charge for joining
|
||||
UpdatePlayer(self, player->GetObjectID());
|
||||
TakeActivityCost(self, player->GetObjectID());
|
||||
|
||||
// Buff the player
|
||||
auto* destroyableComponent = player->GetComponent<DestroyableComponent>();
|
||||
if (destroyableComponent != nullptr) {
|
||||
destroyableComponent->SetHealth((int32_t) destroyableComponent->GetMaxHealth());
|
||||
destroyableComponent->SetArmor((int32_t) destroyableComponent->GetMaxArmor());
|
||||
destroyableComponent->SetImagination((int32_t) destroyableComponent->GetMaxImagination());
|
||||
}
|
||||
|
||||
// Track the player ID
|
||||
auto totalPlayersLoaded = self->GetVar<std::vector<LWOOBJID>>(TotalPlayersLoadedVariable);
|
||||
if (totalPlayersLoaded.empty() || std::find(totalPlayersLoaded.begin(), totalPlayersLoaded.end(), player->GetObjectID()) != totalPlayersLoaded.end()) {
|
||||
totalPlayersLoaded.push_back(player->GetObjectID());
|
||||
}
|
||||
|
||||
// Properly position the player
|
||||
self->SetVar<std::vector<LWOOBJID>>(TotalPlayersLoadedVariable, totalPlayersLoaded);
|
||||
TeleportPlayer(player, totalPlayersLoaded.size());
|
||||
|
||||
// Large teams face a tougher challenge
|
||||
if (totalPlayersLoaded.size() > 2)
|
||||
self->SetVar<bool>(LargeTeamVariable, true);
|
||||
|
||||
// Start the game if all players in the team have loaded
|
||||
auto* team = TeamManager::Instance()->GetTeam(player->GetObjectID());
|
||||
if (team == nullptr || totalPlayersLoaded.size() >= team->members.size()) {
|
||||
StartFight(self);
|
||||
return;
|
||||
}
|
||||
|
||||
self->AddCallbackTimer(0.0f, [self, player]() {
|
||||
if (player != nullptr) {
|
||||
// If we don't have enough players yet, wait for the others to load and notify the client to play a cool cinematic
|
||||
GameMessages::SendNotifyClientObject(self->GetObjectID(), u"PlayerLoaded", 0, 0,
|
||||
player->GetObjectID(), "", player->GetSystemAddress());
|
||||
}
|
||||
});
|
||||
|
||||
ActivityTimerStart(self, WaitingForPlayersTimer, 45.0f, 45.0f);
|
||||
}
|
||||
|
||||
void NjMonastryBossInstance::OnPlayerExit(Entity *self, Entity *player) {
|
||||
UpdatePlayer(self, player->GetObjectID(), true);
|
||||
GameMessages::SendNotifyClientObject(self->GetObjectID(), u"PlayerLeft", 0, 0,
|
||||
player->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS);
|
||||
}
|
||||
|
||||
void NjMonastryBossInstance::OnActivityTimerDone(Entity *self, const std::string &name) {
|
||||
auto split = GeneralUtils::SplitString(name, TimerSplitChar);
|
||||
auto timerName = split[0];
|
||||
auto objectID = split.size() > 1 ? (LWOOBJID) std::stol(split[1]) : LWOOBJID_EMPTY;
|
||||
|
||||
if (timerName == WaitingForPlayersTimer) {
|
||||
StartFight(self);
|
||||
} else if (timerName == SpawnNextWaveTimer) {
|
||||
auto* frakjaw = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(LedgeFrakjawVariable));
|
||||
if (frakjaw != nullptr) {
|
||||
SummonWave(self, frakjaw);
|
||||
}
|
||||
} else if (timerName == SpawnWaveTimer) {
|
||||
auto wave = self->GetVar<uint32_t>(WaveNumberVariable);
|
||||
self->SetVar<uint32_t>(WaveNumberVariable, wave + 1);
|
||||
self->SetVar<uint32_t>(TotalAliveInWaveVariable, 0);
|
||||
|
||||
if (wave < m_Waves.size()) {
|
||||
auto waves = m_Waves.at(wave);
|
||||
auto counter = 0;
|
||||
|
||||
for (const auto& waveEnemy : waves) {
|
||||
const auto numberToSpawn = self->GetVar<bool>(LargeTeamVariable)
|
||||
? waveEnemy.largeNumber : waveEnemy.smallNumber;
|
||||
|
||||
auto spawnIndex = counter % 4 + 1;
|
||||
SpawnOnNetwork(self, waveEnemy.lot, numberToSpawn, BaseEnemiesSpawner + std::to_string(spawnIndex));
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
} else if (timerName + TimerSplitChar == UnstunTimer) {
|
||||
auto* entity = EntityManager::Instance()->GetEntity(objectID);
|
||||
if (entity != nullptr) {
|
||||
auto* combatAI = entity->GetComponent<BaseCombatAIComponent>();
|
||||
if (combatAI != nullptr) {
|
||||
combatAI->SetDisabled(false);
|
||||
}
|
||||
}
|
||||
} else if (timerName == SpawnCounterWeightTimer) {
|
||||
auto spawners = dZoneManager::Instance()->GetSpawnersByName(CounterweightSpawner);
|
||||
if (!spawners.empty()) {
|
||||
// Spawn the counter weight at a specific waypoint, there's one for each round
|
||||
auto* spawner = spawners.front();
|
||||
|
||||
spawner->Spawn({
|
||||
spawner->m_Info.nodes.at((self->GetVar<uint32_t>(WaveNumberVariable) - 1) % 3)
|
||||
}, true);
|
||||
}
|
||||
} else if (timerName == LowerFrakjawCamTimer) {
|
||||
// Destroy the frakjaw on the ledge
|
||||
auto* ledgeFrakjaw = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(LedgeFrakjawVariable));
|
||||
if (ledgeFrakjaw != nullptr) {
|
||||
ledgeFrakjaw->Kill();
|
||||
}
|
||||
|
||||
ActivityTimerStart(self, SpawnLowerFrakjawTimer, 1.0f, 1.0f);
|
||||
GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0,
|
||||
LWOOBJID_EMPTY, BottomFrakSpawn, UNASSIGNED_SYSTEM_ADDRESS);
|
||||
} else if (timerName == SpawnLowerFrakjawTimer) {
|
||||
auto spawners = dZoneManager::Instance()->GetSpawnersByName(LowerFrakjawSpawner);
|
||||
if (!spawners.empty()) {
|
||||
auto* spawner = spawners.front();
|
||||
spawner->Activate();
|
||||
}
|
||||
} else if (timerName == SpawnRailTimer) {
|
||||
GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0,
|
||||
LWOOBJID_EMPTY, FireRailSpawn, UNASSIGNED_SYSTEM_ADDRESS);
|
||||
|
||||
auto spawners = dZoneManager::Instance()->GetSpawnersByName(FireRailSpawner);
|
||||
if (!spawners.empty()) {
|
||||
auto* spawner = spawners.front();
|
||||
spawner->Activate();
|
||||
}
|
||||
} else if (timerName + TimerSplitChar == FrakjawSpawnInTimer) {
|
||||
auto* lowerFrakjaw = EntityManager::Instance()->GetEntity(objectID);
|
||||
if (lowerFrakjaw != nullptr) {
|
||||
LowerFrakjawSummon(self, lowerFrakjaw);
|
||||
}
|
||||
} else if (timerName == WaveOverTimer) {
|
||||
WaveOver(self);
|
||||
} else if (timerName == FightOverTimer) {
|
||||
FightOver(self);
|
||||
}
|
||||
}
|
||||
|
||||
// // // // // // // //
|
||||
// Custom functions //
|
||||
// // // // // // // //
|
||||
|
||||
void NjMonastryBossInstance::StartFight(Entity *self) {
|
||||
if (self->GetVar<bool>(FightStartedVariable))
|
||||
return;
|
||||
|
||||
self->SetVar<bool>(FightStartedVariable, true);
|
||||
|
||||
// Activate the frakjaw spawner
|
||||
for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(LedgeFrakjawSpawner)) {
|
||||
spawner->Activate();
|
||||
}
|
||||
}
|
||||
|
||||
void NjMonastryBossInstance::HandleLedgedFrakjawSpawned(Entity *self, Entity *ledgedFrakjaw) {
|
||||
self->SetVar<LWOOBJID>(LedgeFrakjawVariable, ledgedFrakjaw->GetObjectID());
|
||||
SummonWave(self, ledgedFrakjaw);
|
||||
}
|
||||
|
||||
void NjMonastryBossInstance::HandleCounterWeightSpawned(Entity *self, Entity *counterWeight) {
|
||||
auto* rebuildComponent = counterWeight->GetComponent<RebuildComponent>();
|
||||
if (rebuildComponent != nullptr) {
|
||||
rebuildComponent->AddRebuildStateCallback([this, self, counterWeight](eRebuildState state) {
|
||||
|
||||
switch (state) {
|
||||
case REBUILD_BUILDING:
|
||||
GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification,
|
||||
0, 0, counterWeight->GetObjectID(),
|
||||
BaseCounterweightQB + std::to_string(self->GetVar<uint32_t>(WaveNumberVariable)),
|
||||
UNASSIGNED_SYSTEM_ADDRESS);
|
||||
return;
|
||||
case REBUILD_INCOMPLETE:
|
||||
GameMessages::SendNotifyClientObject(self->GetObjectID(), EndCinematicNotification,
|
||||
0, 0, LWOOBJID_EMPTY,"",
|
||||
UNASSIGNED_SYSTEM_ADDRESS);
|
||||
return;
|
||||
case REBUILD_RESETTING:
|
||||
ActivityTimerStart(self, SpawnCounterWeightTimer, 0.0f, 0.0f);
|
||||
return;
|
||||
case REBUILD_COMPLETED: {
|
||||
// TODO: Move the platform?
|
||||
|
||||
// The counterweight is actually a moving platform and we should listen to the last waypoint event here
|
||||
// 0.5f is a rough estimate of that path, though, and results in less needed logic
|
||||
self->AddCallbackTimer(0.5f, [this, self, counterWeight]() {
|
||||
if (counterWeight != nullptr) {
|
||||
counterWeight->Kill();
|
||||
}
|
||||
|
||||
auto* frakjaw = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(LedgeFrakjawVariable));
|
||||
if (frakjaw == nullptr) {
|
||||
GameMessages::SendNotifyClientObject(self->GetObjectID(), u"LedgeFrakjawDead", 0,
|
||||
0, LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS);
|
||||
return;
|
||||
}
|
||||
|
||||
auto* skillComponent = frakjaw->GetComponent<SkillComponent>();
|
||||
if (skillComponent != nullptr) {
|
||||
skillComponent->CalculateBehavior(1635, 39097, frakjaw->GetObjectID(), true, false);
|
||||
}
|
||||
|
||||
GameMessages::SendPlayAnimation(frakjaw, StunnedAnimation);
|
||||
GameMessages::SendPlayNDAudioEmitter(frakjaw, UNASSIGNED_SYSTEM_ADDRESS, CounterSmashAudio);
|
||||
|
||||
// Before wave 4 we should lower frakjaw from the ledge
|
||||
if (self->GetVar<uint32_t>(WaveNumberVariable) == 3) {
|
||||
LowerFrakjaw(self, frakjaw);
|
||||
return;
|
||||
}
|
||||
|
||||
ActivityTimerStart(self, SpawnNextWaveTimer, 2.0f, 2.0f);
|
||||
});
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void NjMonastryBossInstance::HandleLowerFrakjawSpawned(Entity *self, Entity *lowerFrakjaw) {
|
||||
GameMessages::SendPlayAnimation(lowerFrakjaw, TeleportInAnimation);
|
||||
self->SetVar<LWOOBJID>(LowerFrakjawVariable, lowerFrakjaw->GetObjectID());
|
||||
|
||||
auto* combatAI = lowerFrakjaw->GetComponent<BaseCombatAIComponent>();
|
||||
if (combatAI != nullptr) {
|
||||
combatAI->SetDisabled(true);
|
||||
}
|
||||
|
||||
auto* destroyableComponent = lowerFrakjaw->GetComponent<DestroyableComponent>();
|
||||
if (destroyableComponent != nullptr) {
|
||||
destroyableComponent->AddOnHitCallback([this, self, lowerFrakjaw](Entity* attacker) {
|
||||
NjMonastryBossInstance::HandleLowerFrakjawHit(self, lowerFrakjaw, attacker);
|
||||
});
|
||||
}
|
||||
|
||||
lowerFrakjaw->AddDieCallback([this, self, lowerFrakjaw]() {
|
||||
NjMonastryBossInstance::HandleLowerFrakjawDied(self, lowerFrakjaw);
|
||||
});
|
||||
|
||||
GameMessages::SendNotifyClientObject(self->GetObjectID(), u"LedgeFrakjawDead", 0, 0,
|
||||
LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS);
|
||||
|
||||
if (self->GetVar<bool>(LargeTeamVariable)) {
|
||||
// Double frakjaws health for large teams
|
||||
if (destroyableComponent != nullptr) {
|
||||
const auto doubleHealth = destroyableComponent->GetHealth() * 2;
|
||||
destroyableComponent->SetHealth(doubleHealth);
|
||||
destroyableComponent->SetMaxHealth((float_t) doubleHealth);
|
||||
}
|
||||
|
||||
ActivityTimerStart(self, FrakjawSpawnInTimer + std::to_string(lowerFrakjaw->GetObjectID()),
|
||||
2.0f, 2.0f);
|
||||
ActivityTimerStart(self, UnstunTimer + std::to_string(lowerFrakjaw->GetObjectID()),
|
||||
7.0f, 7.0f);
|
||||
} else {
|
||||
ActivityTimerStart(self, UnstunTimer + std::to_string(lowerFrakjaw->GetObjectID()),
|
||||
5.0f, 5.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void NjMonastryBossInstance::HandleLowerFrakjawHit(Entity *self, Entity *lowerFrakjaw, Entity *attacker) {
|
||||
auto* destroyableComponent = lowerFrakjaw->GetComponent<DestroyableComponent>();
|
||||
if (destroyableComponent == nullptr)
|
||||
return;
|
||||
|
||||
// Progress the fight to the last wave if frakjaw has less than 50% of his health left
|
||||
if (destroyableComponent->GetHealth() <= (uint32_t) destroyableComponent->GetMaxHealth() / 2 && !self->GetVar<bool>(OnLastWaveVarbiale)) {
|
||||
self->SetVar<bool>(OnLastWaveVarbiale, true);
|
||||
|
||||
// Stun frakjaw during the cinematic
|
||||
auto* combatAI = lowerFrakjaw->GetComponent<BaseCombatAIComponent>();
|
||||
if (combatAI != nullptr) {
|
||||
combatAI->SetDisabled(true);
|
||||
}
|
||||
ActivityTimerStart(self, UnstunTimer + std::to_string(lowerFrakjaw->GetObjectID()), 5.0f, 5.0f);
|
||||
|
||||
const auto trashMobsAlive = self->GetVar<std::vector<LWOOBJID>>(TrashMobsAliveVariable);
|
||||
std::vector<LWOOBJID> newTrashMobs = {};
|
||||
|
||||
for (const auto& trashMobID : trashMobsAlive) {
|
||||
auto* trashMob = EntityManager::Instance()->GetEntity(trashMobID);
|
||||
if (trashMob != nullptr) {
|
||||
newTrashMobs.push_back(trashMobID);
|
||||
|
||||
// Stun all the enemies until the cinematic is over
|
||||
auto* trashMobCombatAI = trashMob->GetComponent<BaseCombatAIComponent>();
|
||||
if (trashMobCombatAI != nullptr) {
|
||||
trashMobCombatAI->SetDisabled(true);
|
||||
}
|
||||
ActivityTimerStart(self, UnstunTimer + std::to_string(trashMobID), 5.0f, 5.0f);
|
||||
}
|
||||
}
|
||||
|
||||
self->SetVar<std::vector<LWOOBJID>>(TrashMobsAliveVariable, newTrashMobs);
|
||||
|
||||
LowerFrakjawSummon(self, lowerFrakjaw);
|
||||
RemovePoison(self);
|
||||
}
|
||||
}
|
||||
|
||||
void NjMonastryBossInstance::HandleLowerFrakjawDied(Entity *self, Entity *lowerFrakjaw) {
|
||||
ActivityTimerStart(self, FightOverTimer, 2.0f, 2.0f);
|
||||
}
|
||||
|
||||
void NjMonastryBossInstance::HandleWaveEnemySpawned(Entity *self, Entity *waveEnemy) {
|
||||
waveEnemy->AddDieCallback([this, self, waveEnemy]() {
|
||||
NjMonastryBossInstance::HandleWaveEnemyDied(self, waveEnemy);
|
||||
});
|
||||
|
||||
auto waveEnemies = self->GetVar<std::vector<LWOOBJID>>(TrashMobsAliveVariable);
|
||||
waveEnemies.push_back(waveEnemy->GetObjectID());
|
||||
self->SetVar<std::vector<LWOOBJID>>(TrashMobsAliveVariable, waveEnemies);
|
||||
|
||||
auto* combatAI = waveEnemy->GetComponent<BaseCombatAIComponent>();
|
||||
if (combatAI != nullptr) {
|
||||
combatAI->SetDisabled(true);
|
||||
ActivityTimerStart(self, UnstunTimer + std::to_string(waveEnemy->GetObjectID()), 3.0f, 3.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void NjMonastryBossInstance::HandleWaveEnemyDied(Entity *self, Entity* waveEnemy) {
|
||||
auto waveEnemies = self->GetVar<std::vector<LWOOBJID>>(TrashMobsAliveVariable);
|
||||
waveEnemies.erase(std::remove(waveEnemies.begin(), waveEnemies.end(), waveEnemy->GetObjectID()), waveEnemies.end());
|
||||
self->SetVar<std::vector<LWOOBJID>>(TrashMobsAliveVariable, waveEnemies);
|
||||
|
||||
if (waveEnemies.empty()) {
|
||||
ActivityTimerStart(self, WaveOverTimer, 2.0f, 2.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void NjMonastryBossInstance::TeleportPlayer(Entity *player, uint32_t position) {
|
||||
for (const auto* spawnPoint : EntityManager::Instance()->GetEntitiesInGroup("SpawnPoint" + std::to_string(position))) {
|
||||
GameMessages::SendTeleport(player->GetObjectID(), spawnPoint->GetPosition(), spawnPoint->GetRotation(),
|
||||
player->GetSystemAddress(), true);
|
||||
}
|
||||
}
|
||||
|
||||
void NjMonastryBossInstance::SummonWave(Entity* self, Entity* frakjaw) {
|
||||
GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, LWOOBJID_EMPTY,
|
||||
LedgeFrakSummon, UNASSIGNED_SYSTEM_ADDRESS);
|
||||
GameMessages::SendPlayAnimation(frakjaw, SummonAnimation);
|
||||
|
||||
// Stop the music for the first, fourth and fifth wave
|
||||
const auto wave = self->GetVar<uint32_t>(WaveNumberVariable);
|
||||
if (wave >= 1 || wave < (m_Waves.size() - 1)) {
|
||||
GameMessages::SendNotifyClientObject(self->GetObjectID(), StopMusicNotification, 0, 0,
|
||||
LWOOBJID_EMPTY, AudioWaveAudio + std::to_string(wave - 1),
|
||||
UNASSIGNED_SYSTEM_ADDRESS);
|
||||
}
|
||||
|
||||
// After frakjaw moves down the music stays the same
|
||||
if (wave < (m_Waves.size() - 1)) {
|
||||
GameMessages::SendNotifyClientObject(self->GetObjectID(), StartMusicNotification, 0, 0,
|
||||
LWOOBJID_EMPTY, AudioWaveAudio + std::to_string(wave),
|
||||
UNASSIGNED_SYSTEM_ADDRESS);
|
||||
}
|
||||
|
||||
ActivityTimerStart(self, SpawnWaveTimer, 4.0f, 4.0f);
|
||||
}
|
||||
|
||||
void NjMonastryBossInstance::LowerFrakjawSummon(Entity *self, Entity *frakjaw) {
|
||||
GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0,
|
||||
LWOOBJID_EMPTY, BottomFrakSummon, UNASSIGNED_SYSTEM_ADDRESS);
|
||||
ActivityTimerStart(self, SpawnWaveTimer, 2.0f, 2.0f);
|
||||
GameMessages::SendPlayAnimation(frakjaw, SummonAnimation);
|
||||
}
|
||||
|
||||
void NjMonastryBossInstance::RemovePoison(Entity *self) {
|
||||
const auto& totalPlayer = self->GetVar<std::vector<LWOOBJID>>(TotalPlayersLoadedVariable);
|
||||
for (const auto& playerID : totalPlayer) {
|
||||
|
||||
auto* player = EntityManager::Instance()->GetEntity(playerID);
|
||||
if (player != nullptr) {
|
||||
|
||||
auto* buffComponent = player->GetComponent<BuffComponent>();
|
||||
if (buffComponent != nullptr) {
|
||||
buffComponent->RemoveBuff(PoisonBuff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NjMonastryBossInstance::LowerFrakjaw(Entity *self, Entity* frakjaw) {
|
||||
GameMessages::SendPlayAnimation(frakjaw, TeleportOutAnimation);
|
||||
ActivityTimerStart(self, LowerFrakjawCamTimer, 2.0f, 2.0f);
|
||||
|
||||
GameMessages::SendNotifyClientObject(frakjaw->GetObjectID(), StopMusicNotification, 0, 0,
|
||||
LWOOBJID_EMPTY, AudioWaveAudio + std::to_string(m_Waves.size() - 3), UNASSIGNED_SYSTEM_ADDRESS);
|
||||
GameMessages::SendNotifyClientObject(frakjaw->GetObjectID(), StartMusicNotification, 0, 0,
|
||||
LWOOBJID_EMPTY, AudioWaveAudio + std::to_string(m_Waves.size() - 2), UNASSIGNED_SYSTEM_ADDRESS);
|
||||
}
|
||||
|
||||
void NjMonastryBossInstance::SpawnOnNetwork(Entity* self, const LOT& toSpawn, const uint32_t& numberToSpawn, const std::string& spawnerName) {
|
||||
auto spawners = dZoneManager::Instance()->GetSpawnersByName(spawnerName);
|
||||
if (spawners.empty() || numberToSpawn <= 0)
|
||||
return;
|
||||
|
||||
auto* spawner = spawners.front();
|
||||
|
||||
// Spawn the lot N times
|
||||
spawner->SetSpawnLot(toSpawn);
|
||||
for (auto i = 0; i < numberToSpawn; i++)
|
||||
spawner->Spawn({ spawner->m_Info.nodes.at(i % spawner->m_Info.nodes.size()) }, true);
|
||||
}
|
||||
|
||||
void NjMonastryBossInstance::WaveOver(Entity *self) {
|
||||
auto wave = self->GetVar<uint32_t>(WaveNumberVariable);
|
||||
if (wave >= m_Waves.size() - 1)
|
||||
return;
|
||||
|
||||
GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0,
|
||||
LWOOBJID_EMPTY, BaseCounterweightSpawn + std::to_string(wave),
|
||||
UNASSIGNED_SYSTEM_ADDRESS);
|
||||
ActivityTimerStart(self, SpawnCounterWeightTimer, 1.5f, 1.5f);
|
||||
RemovePoison(self);
|
||||
}
|
||||
|
||||
void NjMonastryBossInstance::FightOver(Entity *self) {
|
||||
GameMessages::SendNotifyClientObject(self->GetObjectID(), u"GroundFrakjawDead", 0, 0,
|
||||
LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS);
|
||||
|
||||
// Remove all the enemies from the battlefield
|
||||
for (auto i = 1; i < 5; i++) {
|
||||
auto spawners = dZoneManager::Instance()->GetSpawnersByName(BaseEnemiesSpawner + std::to_string(i));
|
||||
if (!spawners.empty()) {
|
||||
auto* spawner = spawners.front();
|
||||
spawner->Deactivate();
|
||||
spawner->Reset();
|
||||
}
|
||||
}
|
||||
|
||||
RemovePoison(self);
|
||||
ActivityTimerStart(self, SpawnRailTimer, 1.5f, 1.5f);
|
||||
|
||||
// Set the music to play the victory music
|
||||
GameMessages::SendNotifyClientObject(self->GetObjectID(), StopMusicNotification, 0, 0,
|
||||
LWOOBJID_EMPTY, AudioWaveAudio + std::to_string(m_Waves.size() - 2),
|
||||
UNASSIGNED_SYSTEM_ADDRESS);
|
||||
GameMessages::SendNotifyClientObject(self->GetObjectID(), FlashMusicNotification, 0, 0,
|
||||
LWOOBJID_EMPTY, "Monastery_Frakjaw_Battle_Win", UNASSIGNED_SYSTEM_ADDRESS);
|
||||
GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0,
|
||||
LWOOBJID_EMPTY, TreasureChestSpawning, UNASSIGNED_SYSTEM_ADDRESS);
|
||||
|
||||
auto treasureChests = EntityManager::Instance()->GetEntitiesInGroup(ChestSpawnpointGroup);
|
||||
for (auto* treasureChest : treasureChests) {
|
||||
auto info = EntityInfo {};
|
||||
|
||||
info.lot = ChestLOT;
|
||||
info.pos = treasureChest->GetPosition();
|
||||
info.rot = treasureChest->GetRotation();
|
||||
info.spawnerID = self->GetObjectID();
|
||||
info.settings = {
|
||||
new LDFData<LWOOBJID>(u"parent_tag", self->GetObjectID())
|
||||
};
|
||||
|
||||
// Finally spawn a treasure chest at the correct spawn point
|
||||
auto* chestObject = EntityManager::Instance()->CreateEntity(info);
|
||||
EntityManager::Instance()->ConstructEntity(chestObject);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user