mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-11-26 07:27:18 +00:00
f0b6ad89d9
* SystemAddress and destructor * move respawn logic to character comp Tested that respawn pos and rot can be set as per previously by crossing a respawn point and smashing to see if I would respawn at the new place. * Move loot cheat checking * Remove GetParentUser overload Tested completing missions control behaviors collecting life crate completing a bunch of missions using macros loading into worlds brick-by-brick placing models digging the x spot in gnarled forest can still ban and mute players cheat detection is still doing its thing flags are still set (checked with flag 45) claim codes still work (created new char, checked the lego club mail was there) * Move player constructor logic Its now at the bottom of Entity constructor. Time to remove Player * Remove Player class Removes the Player class. Tested that I can still login and see another player in Venture Explorer and logging out a few times still works as well as smashing enemies * store ptr * Update SlashCommandHandler.cpp
606 lines
20 KiB
C++
606 lines
20 KiB
C++
#include "ActivityComponent.h"
|
|
#include "GameMessages.h"
|
|
#include "CDClientManager.h"
|
|
#include "MissionComponent.h"
|
|
#include "Character.h"
|
|
#include "dZoneManager.h"
|
|
#include "ZoneInstanceManager.h"
|
|
#include "Game.h"
|
|
#include "Logger.h"
|
|
#include "WorldPackets.h"
|
|
#include "EntityManager.h"
|
|
#include "ChatPackets.h"
|
|
#include "BitStreamUtils.h"
|
|
#include "dServer.h"
|
|
#include "GeneralUtils.h"
|
|
#include "dZoneManager.h"
|
|
#include "dConfig.h"
|
|
#include "InventoryComponent.h"
|
|
#include "DestroyableComponent.h"
|
|
#include "Loot.h"
|
|
#include "eMissionTaskType.h"
|
|
#include "eMatchUpdate.h"
|
|
#include "eConnectionType.h"
|
|
#include "eChatInternalMessageType.h"
|
|
|
|
#include "CDCurrencyTableTable.h"
|
|
#include "CDActivityRewardsTable.h"
|
|
#include "CDActivitiesTable.h"
|
|
#include "LeaderboardManager.h"
|
|
|
|
ActivityComponent::ActivityComponent(Entity* parent, int32_t activityID) : Component(parent) {
|
|
/*
|
|
* This is precisely what the client does functionally
|
|
* Use the component id as the default activity id and load its data from the database
|
|
* if activityID is specified and if that column exists in the activities table, update the activity info with that data.
|
|
*/
|
|
|
|
m_ActivityID = activityID;
|
|
LoadActivityData(activityID);
|
|
if (m_Parent->HasVar(u"activityID")) {
|
|
m_ActivityID = parent->GetVar<int32_t>(u"activityID");
|
|
LoadActivityData(m_ActivityID);
|
|
}
|
|
|
|
auto* destroyableComponent = m_Parent->GetComponent<DestroyableComponent>();
|
|
|
|
if (destroyableComponent) {
|
|
// First lookup the loot matrix id for this component id.
|
|
CDActivityRewardsTable* activityRewardsTable = CDClientManager::Instance().GetTable<CDActivityRewardsTable>();
|
|
std::vector<CDActivityRewards> activityRewards = activityRewardsTable->Query([=](CDActivityRewards entry) {return (entry.LootMatrixIndex == destroyableComponent->GetLootMatrixID()); });
|
|
|
|
uint32_t startingLMI = 0;
|
|
|
|
// If we have one, set the starting loot matrix id to that.
|
|
if (activityRewards.size() > 0) {
|
|
startingLMI = activityRewards[0].LootMatrixIndex;
|
|
}
|
|
|
|
if (startingLMI > 0) {
|
|
// We may have more than 1 loot matrix index to use depending ont the size of the team that is looting the activity.
|
|
// So this logic will get the rest of the loot matrix indices for this activity.
|
|
|
|
std::vector<CDActivityRewards> objectTemplateActivities = activityRewardsTable->Query([=](CDActivityRewards entry) {return (activityRewards[0].objectTemplate == entry.objectTemplate); });
|
|
for (const auto& item : objectTemplateActivities) {
|
|
if (item.activityRating > 0 && item.activityRating < 5) {
|
|
m_ActivityLootMatrices.insert({ item.activityRating, item.LootMatrixIndex });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
void ActivityComponent::LoadActivityData(const int32_t activityId) {
|
|
CDActivitiesTable* activitiesTable = CDClientManager::Instance().GetTable<CDActivitiesTable>();
|
|
std::vector<CDActivities> activities = activitiesTable->Query([activityId](CDActivities entry) {return (entry.ActivityID == activityId); });
|
|
|
|
bool soloRacing = Game::config->GetValue("solo_racing") == "1";
|
|
for (CDActivities activity : activities) {
|
|
m_ActivityInfo = activity;
|
|
if (static_cast<Leaderboard::Type>(activity.leaderboardType) == Leaderboard::Type::Racing && soloRacing) {
|
|
m_ActivityInfo.minTeamSize = 1;
|
|
m_ActivityInfo.minTeams = 1;
|
|
}
|
|
if (m_ActivityInfo.instanceMapID == -1) {
|
|
const auto& transferOverride = m_Parent->GetVarAsString(u"transferZoneID");
|
|
if (!transferOverride.empty()) {
|
|
GeneralUtils::TryParse(transferOverride, m_ActivityInfo.instanceMapID);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ActivityComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
|
outBitStream->Write(m_DirtyActivityInfo);
|
|
if (m_DirtyActivityInfo) {
|
|
outBitStream->Write<uint32_t>(m_ActivityPlayers.size());
|
|
if (!m_ActivityPlayers.empty()) {
|
|
for (const auto& activityPlayer : m_ActivityPlayers) {
|
|
outBitStream->Write<LWOOBJID>(activityPlayer->playerID);
|
|
for (const auto& activityValue : activityPlayer->values) {
|
|
outBitStream->Write<float_t>(activityValue);
|
|
}
|
|
}
|
|
}
|
|
if (!bIsInitialUpdate) m_DirtyActivityInfo = false;
|
|
}
|
|
}
|
|
|
|
void ActivityComponent::ReloadConfig() {
|
|
CDActivitiesTable* activitiesTable = CDClientManager::Instance().GetTable<CDActivitiesTable>();
|
|
std::vector<CDActivities> activities = activitiesTable->Query([this](CDActivities entry) {return (entry.ActivityID == m_ActivityID); });
|
|
for (auto activity : activities) {
|
|
auto mapID = m_ActivityInfo.instanceMapID;
|
|
if (static_cast<Leaderboard::Type>(activity.leaderboardType) == Leaderboard::Type::Racing && Game::config->GetValue("solo_racing") == "1") {
|
|
m_ActivityInfo.minTeamSize = 1;
|
|
m_ActivityInfo.minTeams = 1;
|
|
} else {
|
|
m_ActivityInfo.minTeamSize = activity.minTeamSize;
|
|
m_ActivityInfo.minTeams = activity.minTeams;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ActivityComponent::HandleMessageBoxResponse(Entity* player, const std::string& id) {
|
|
if (id == "LobbyExit") {
|
|
PlayerLeave(player->GetObjectID());
|
|
} else if (id == "PlayButton") {
|
|
PlayerJoin(player);
|
|
}
|
|
}
|
|
|
|
void ActivityComponent::PlayerJoin(Entity* player) {
|
|
if (PlayerIsInQueue(player)) return;
|
|
// If we have a lobby, queue the player and allow others to join, otherwise spin up an instance on the spot
|
|
if (HasLobby()) {
|
|
PlayerJoinLobby(player);
|
|
} else if (!IsPlayedBy(player)) {
|
|
auto* instance = NewInstance();
|
|
instance->AddParticipant(player);
|
|
}
|
|
}
|
|
|
|
void ActivityComponent::PlayerJoinLobby(Entity* player) {
|
|
if (!m_Parent->HasComponent(eReplicaComponentType::QUICK_BUILD))
|
|
GameMessages::SendMatchResponse(player, player->GetSystemAddress(), 0); // tell the client they joined a lobby
|
|
LobbyPlayer* newLobbyPlayer = new LobbyPlayer();
|
|
newLobbyPlayer->entityID = player->GetObjectID();
|
|
Lobby* playerLobby = nullptr;
|
|
|
|
auto* character = player->GetCharacter();
|
|
if (character != nullptr)
|
|
character->SetLastNonInstanceZoneID(Game::zoneManager->GetZone()->GetWorldID());
|
|
|
|
for (Lobby* lobby : m_Queue) {
|
|
if (lobby->players.size() < m_ActivityInfo.maxTeamSize || m_ActivityInfo.maxTeamSize == 1 && lobby->players.size() < m_ActivityInfo.maxTeams) {
|
|
// If an empty slot in an existing lobby is found
|
|
lobby->players.push_back(newLobbyPlayer);
|
|
playerLobby = lobby;
|
|
|
|
// Update the joining player on players already in the lobby, and update players already in the lobby on the joining player
|
|
std::string matchUpdateJoined = "player=9:" + std::to_string(player->GetObjectID()) + "\nplayerName=0:" + player->GetCharacter()->GetName();
|
|
for (LobbyPlayer* joinedPlayer : lobby->players) {
|
|
auto* entity = joinedPlayer->GetEntity();
|
|
|
|
if (entity == nullptr) {
|
|
continue;
|
|
}
|
|
|
|
std::string matchUpdate = "player=9:" + std::to_string(entity->GetObjectID()) + "\nplayerName=0:" + entity->GetCharacter()->GetName();
|
|
GameMessages::SendMatchUpdate(player, player->GetSystemAddress(), matchUpdate, eMatchUpdate::PLAYER_ADDED);
|
|
PlayerReady(entity, joinedPlayer->ready);
|
|
GameMessages::SendMatchUpdate(entity, entity->GetSystemAddress(), matchUpdateJoined, eMatchUpdate::PLAYER_ADDED);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!playerLobby) {
|
|
// If all lobbies are full
|
|
playerLobby = new Lobby();
|
|
playerLobby->players.push_back(newLobbyPlayer);
|
|
playerLobby->timer = m_ActivityInfo.waitTime / 1000;
|
|
m_Queue.push_back(playerLobby);
|
|
}
|
|
|
|
if (m_ActivityInfo.maxTeamSize != 1 && playerLobby->players.size() >= m_ActivityInfo.minTeamSize || m_ActivityInfo.maxTeamSize == 1 && playerLobby->players.size() >= m_ActivityInfo.minTeams) {
|
|
// Update the joining player on the match timer
|
|
std::string matchTimerUpdate = "time=3:" + std::to_string(playerLobby->timer);
|
|
GameMessages::SendMatchUpdate(player, player->GetSystemAddress(), matchTimerUpdate, eMatchUpdate::PHASE_WAIT_READY);
|
|
}
|
|
}
|
|
|
|
void ActivityComponent::PlayerLeave(LWOOBJID playerID) {
|
|
|
|
// Removes the player from a lobby and notifies the others, not applicable for non-lobby instances
|
|
for (Lobby* lobby : m_Queue) {
|
|
for (int i = 0; i < lobby->players.size(); ++i) {
|
|
if (lobby->players[i]->entityID == playerID) {
|
|
std::string matchUpdateLeft = "player=9:" + std::to_string(playerID);
|
|
for (LobbyPlayer* lobbyPlayer : lobby->players) {
|
|
auto* entity = lobbyPlayer->GetEntity();
|
|
if (entity == nullptr)
|
|
continue;
|
|
|
|
GameMessages::SendMatchUpdate(entity, entity->GetSystemAddress(), matchUpdateLeft, eMatchUpdate::PLAYER_REMOVED);
|
|
}
|
|
|
|
delete lobby->players[i];
|
|
lobby->players[i] = nullptr;
|
|
lobby->players.erase(lobby->players.begin() + i);
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ActivityComponent::Update(float deltaTime) {
|
|
std::vector<Lobby*> lobbiesToRemove{};
|
|
// Ticks all the lobbies, not applicable for non-instance activities
|
|
for (Lobby* lobby : m_Queue) {
|
|
for (LobbyPlayer* player : lobby->players) {
|
|
auto* entity = player->GetEntity();
|
|
if (entity == nullptr) {
|
|
PlayerLeave(player->entityID);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (lobby->players.empty()) {
|
|
lobbiesToRemove.push_back(lobby);
|
|
continue;
|
|
}
|
|
|
|
// Update the match time for all players
|
|
if (m_ActivityInfo.maxTeamSize != 1 && lobby->players.size() >= m_ActivityInfo.minTeamSize
|
|
|| m_ActivityInfo.maxTeamSize == 1 && lobby->players.size() >= m_ActivityInfo.minTeams) {
|
|
if (lobby->timer == m_ActivityInfo.waitTime / 1000) {
|
|
for (LobbyPlayer* joinedPlayer : lobby->players) {
|
|
auto* entity = joinedPlayer->GetEntity();
|
|
|
|
if (entity == nullptr)
|
|
continue;
|
|
|
|
std::string matchTimerUpdate = "time=3:" + std::to_string(lobby->timer);
|
|
GameMessages::SendMatchUpdate(entity, entity->GetSystemAddress(), matchTimerUpdate, eMatchUpdate::PHASE_WAIT_READY);
|
|
}
|
|
}
|
|
|
|
lobby->timer -= deltaTime;
|
|
}
|
|
|
|
bool lobbyReady = true;
|
|
for (LobbyPlayer* player : lobby->players) {
|
|
if (player->ready) continue;
|
|
lobbyReady = false;
|
|
}
|
|
|
|
// If everyone's ready, jump the timer
|
|
if (lobbyReady && lobby->timer > m_ActivityInfo.startDelay / 1000) {
|
|
lobby->timer = m_ActivityInfo.startDelay / 1000;
|
|
|
|
// Update players in lobby on switch to start delay
|
|
std::string matchTimerUpdate = "time=3:" + std::to_string(lobby->timer);
|
|
for (LobbyPlayer* player : lobby->players) {
|
|
auto* entity = player->GetEntity();
|
|
|
|
if (entity == nullptr)
|
|
continue;
|
|
|
|
GameMessages::SendMatchUpdate(entity, entity->GetSystemAddress(), matchTimerUpdate, eMatchUpdate::PHASE_WAIT_START);
|
|
}
|
|
}
|
|
|
|
// The timer has elapsed, start the instance
|
|
if (lobby->timer <= 0.0f) {
|
|
LOG("Setting up instance.");
|
|
ActivityInstance* instance = NewInstance();
|
|
LoadPlayersIntoInstance(instance, lobby->players);
|
|
instance->StartZone();
|
|
lobbiesToRemove.push_back(lobby);
|
|
}
|
|
}
|
|
|
|
while (!lobbiesToRemove.empty()) {
|
|
RemoveLobby(lobbiesToRemove.front());
|
|
lobbiesToRemove.erase(lobbiesToRemove.begin());
|
|
}
|
|
}
|
|
|
|
void ActivityComponent::RemoveLobby(Lobby* lobby) {
|
|
for (int i = 0; i < m_Queue.size(); ++i) {
|
|
if (m_Queue[i] == lobby) {
|
|
m_Queue.erase(m_Queue.begin() + i);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool ActivityComponent::HasLobby() const {
|
|
// If the player is not in the world he has to be, create a lobby for the transfer
|
|
return m_ActivityInfo.instanceMapID != UINT_MAX && m_ActivityInfo.instanceMapID != Game::server->GetZoneID();
|
|
}
|
|
|
|
bool ActivityComponent::PlayerIsInQueue(Entity* player) {
|
|
for (Lobby* lobby : m_Queue) {
|
|
for (LobbyPlayer* lobbyPlayer : lobby->players) {
|
|
if (player->GetObjectID() == lobbyPlayer->entityID) return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ActivityComponent::IsPlayedBy(Entity* player) const {
|
|
for (const auto* instance : this->m_Instances) {
|
|
for (const auto* instancePlayer : instance->GetParticipants()) {
|
|
if (instancePlayer != nullptr && instancePlayer->GetObjectID() == player->GetObjectID())
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ActivityComponent::IsPlayedBy(LWOOBJID playerID) const {
|
|
for (const auto* instance : this->m_Instances) {
|
|
for (const auto* instancePlayer : instance->GetParticipants()) {
|
|
if (instancePlayer != nullptr && instancePlayer->GetObjectID() == playerID)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ActivityComponent::TakeCost(Entity* player) const {
|
|
if (m_ActivityInfo.optionalCostLOT <= 0 || m_ActivityInfo.optionalCostCount <= 0)
|
|
return true;
|
|
|
|
auto* inventoryComponent = player->GetComponent<InventoryComponent>();
|
|
if (inventoryComponent == nullptr)
|
|
return false;
|
|
|
|
if (inventoryComponent->GetLotCount(m_ActivityInfo.optionalCostLOT) < m_ActivityInfo.optionalCostCount)
|
|
return false;
|
|
|
|
inventoryComponent->RemoveItem(m_ActivityInfo.optionalCostLOT, m_ActivityInfo.optionalCostCount);
|
|
|
|
return true;
|
|
}
|
|
|
|
void ActivityComponent::PlayerReady(Entity* player, bool bReady) {
|
|
for (Lobby* lobby : m_Queue) {
|
|
for (LobbyPlayer* lobbyPlayer : lobby->players) {
|
|
if (lobbyPlayer->entityID == player->GetObjectID()) {
|
|
|
|
lobbyPlayer->ready = bReady;
|
|
|
|
// Update players in lobby on player being ready
|
|
std::string matchReadyUpdate = "player=9:" + std::to_string(player->GetObjectID());
|
|
eMatchUpdate readyStatus = eMatchUpdate::PLAYER_READY;
|
|
if (!bReady) readyStatus = eMatchUpdate::PLAYER_NOT_READY;
|
|
for (LobbyPlayer* otherPlayer : lobby->players) {
|
|
auto* entity = otherPlayer->GetEntity();
|
|
if (entity == nullptr)
|
|
continue;
|
|
|
|
GameMessages::SendMatchUpdate(entity, entity->GetSystemAddress(), matchReadyUpdate, readyStatus);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ActivityInstance* ActivityComponent::NewInstance() {
|
|
auto* instance = new ActivityInstance(m_Parent, m_ActivityInfo);
|
|
m_Instances.push_back(instance);
|
|
return instance;
|
|
}
|
|
|
|
void ActivityComponent::LoadPlayersIntoInstance(ActivityInstance* instance, const std::vector<LobbyPlayer*>& lobby) const {
|
|
for (LobbyPlayer* player : lobby) {
|
|
auto* entity = player->GetEntity();
|
|
if (entity == nullptr || !TakeCost(entity)) {
|
|
continue;
|
|
}
|
|
|
|
instance->AddParticipant(entity);
|
|
}
|
|
}
|
|
|
|
const std::vector<ActivityInstance*>& ActivityComponent::GetInstances() const {
|
|
return m_Instances;
|
|
}
|
|
|
|
ActivityInstance* ActivityComponent::GetInstance(const LWOOBJID playerID) {
|
|
for (const auto* instance : GetInstances()) {
|
|
for (const auto* participant : instance->GetParticipants()) {
|
|
if (participant->GetObjectID() == playerID)
|
|
return const_cast<ActivityInstance*>(instance);
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void ActivityComponent::ClearInstances() {
|
|
for (ActivityInstance* instance : m_Instances) {
|
|
delete instance;
|
|
}
|
|
m_Instances.clear();
|
|
}
|
|
|
|
ActivityPlayer* ActivityComponent::GetActivityPlayerData(LWOOBJID playerID) {
|
|
for (auto* activityData : m_ActivityPlayers) {
|
|
if (activityData->playerID == playerID) {
|
|
return activityData;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void ActivityComponent::RemoveActivityPlayerData(LWOOBJID playerID) {
|
|
for (size_t i = 0; i < m_ActivityPlayers.size(); i++) {
|
|
if (m_ActivityPlayers[i]->playerID == playerID) {
|
|
delete m_ActivityPlayers[i];
|
|
m_ActivityPlayers[i] = nullptr;
|
|
|
|
m_ActivityPlayers.erase(m_ActivityPlayers.begin() + i);
|
|
m_DirtyActivityInfo = true;
|
|
Game::entityManager->SerializeEntity(m_Parent);
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
ActivityPlayer* ActivityComponent::AddActivityPlayerData(LWOOBJID playerID) {
|
|
auto* data = GetActivityPlayerData(playerID);
|
|
if (data != nullptr)
|
|
return data;
|
|
|
|
m_ActivityPlayers.push_back(new ActivityPlayer{ playerID, {} });
|
|
m_DirtyActivityInfo = true;
|
|
Game::entityManager->SerializeEntity(m_Parent);
|
|
|
|
return GetActivityPlayerData(playerID);
|
|
}
|
|
|
|
float_t ActivityComponent::GetActivityValue(LWOOBJID playerID, uint32_t index) {
|
|
auto value = -1.0f;
|
|
|
|
auto* data = GetActivityPlayerData(playerID);
|
|
if (data != nullptr) {
|
|
value = data->values[std::min(index, static_cast<uint32_t>(9))];
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
void ActivityComponent::SetActivityValue(LWOOBJID playerID, uint32_t index, float_t value) {
|
|
auto* data = AddActivityPlayerData(playerID);
|
|
if (data != nullptr) {
|
|
data->values[std::min(index, static_cast<uint32_t>(9))] = value;
|
|
}
|
|
m_DirtyActivityInfo = true;
|
|
Game::entityManager->SerializeEntity(m_Parent);
|
|
}
|
|
|
|
void ActivityComponent::PlayerRemove(LWOOBJID playerID) {
|
|
for (auto* instance : GetInstances()) {
|
|
auto participants = instance->GetParticipants();
|
|
for (const auto* participant : participants) {
|
|
if (participant != nullptr && participant->GetObjectID() == playerID) {
|
|
instance->RemoveParticipant(participant);
|
|
RemoveActivityPlayerData(playerID);
|
|
|
|
// If the instance is empty after the delete of the participant, delete the instance too
|
|
if (instance->GetParticipants().empty()) {
|
|
m_Instances.erase(std::find(m_Instances.begin(), m_Instances.end(), instance));
|
|
delete instance;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ActivityInstance::StartZone() {
|
|
if (m_Participants.empty())
|
|
return;
|
|
|
|
const auto& participants = GetParticipants();
|
|
if (participants.empty())
|
|
return;
|
|
|
|
auto* leader = participants[0];
|
|
LWOZONEID zoneId = LWOZONEID(m_ActivityInfo.instanceMapID, 0, leader->GetCharacter()->GetPropertyCloneID());
|
|
|
|
// only make a team if we have more than one participant
|
|
if (participants.size() > 1) {
|
|
CBITSTREAM;
|
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::CREATE_TEAM);
|
|
|
|
bitStream.Write(leader->GetObjectID());
|
|
bitStream.Write(m_Participants.size());
|
|
|
|
for (const auto& participant : m_Participants) {
|
|
bitStream.Write(participant);
|
|
}
|
|
|
|
bitStream.Write(zoneId);
|
|
|
|
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
|
|
}
|
|
|
|
const auto cloneId = GeneralUtils::GenerateRandomNumber<uint32_t>(1, UINT32_MAX);
|
|
for (Entity* player : participants) {
|
|
const auto objid = player->GetObjectID();
|
|
ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, m_ActivityInfo.instanceMapID, cloneId, false, [objid](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) {
|
|
|
|
auto* player = Game::entityManager->GetEntity(objid);
|
|
if (player == nullptr)
|
|
return;
|
|
|
|
LOG("Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", player->GetCharacter()->GetName().c_str(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort);
|
|
if (player->GetCharacter()) {
|
|
player->GetCharacter()->SetZoneID(zoneID);
|
|
player->GetCharacter()->SetZoneInstance(zoneInstance);
|
|
player->GetCharacter()->SetZoneClone(zoneClone);
|
|
}
|
|
|
|
WorldPackets::SendTransferToWorld(player->GetSystemAddress(), serverIP, serverPort, mythranShift);
|
|
return;
|
|
});
|
|
}
|
|
|
|
m_NextZoneCloneID++;
|
|
}
|
|
|
|
void ActivityInstance::RewardParticipant(Entity* participant) {
|
|
auto* missionComponent = participant->GetComponent<MissionComponent>();
|
|
if (missionComponent) {
|
|
missionComponent->Progress(eMissionTaskType::ACTIVITY, m_ActivityInfo.ActivityID);
|
|
}
|
|
|
|
// First, get the activity data
|
|
auto* activityRewardsTable = CDClientManager::Instance().GetTable<CDActivityRewardsTable>();
|
|
std::vector<CDActivityRewards> activityRewards = activityRewardsTable->Query([this](CDActivityRewards entry) { return (entry.objectTemplate == m_ActivityInfo.ActivityID); });
|
|
|
|
if (!activityRewards.empty()) {
|
|
uint32_t minCoins = 0;
|
|
uint32_t maxCoins = 0;
|
|
|
|
auto* currencyTableTable = CDClientManager::Instance().GetTable<CDCurrencyTableTable>();
|
|
std::vector<CDCurrencyTable> currencyTable = currencyTableTable->Query([=](CDCurrencyTable entry) { return (entry.currencyIndex == activityRewards[0].CurrencyIndex && entry.npcminlevel == 1); });
|
|
|
|
if (!currencyTable.empty()) {
|
|
minCoins = currencyTable[0].minvalue;
|
|
maxCoins = currencyTable[0].maxvalue;
|
|
}
|
|
|
|
Loot::DropLoot(participant, m_Parent, activityRewards[0].LootMatrixIndex, minCoins, maxCoins);
|
|
}
|
|
}
|
|
|
|
std::vector<Entity*> ActivityInstance::GetParticipants() const {
|
|
std::vector<Entity*> entities;
|
|
entities.reserve(m_Participants.size());
|
|
|
|
for (const auto& id : m_Participants) {
|
|
auto* entity = Game::entityManager->GetEntity(id);
|
|
if (entity != nullptr)
|
|
entities.push_back(entity);
|
|
}
|
|
|
|
return entities;
|
|
}
|
|
|
|
void ActivityInstance::AddParticipant(Entity* participant) {
|
|
const auto id = participant->GetObjectID();
|
|
if (std::count(m_Participants.begin(), m_Participants.end(), id))
|
|
return;
|
|
|
|
m_Participants.push_back(id);
|
|
}
|
|
|
|
void ActivityInstance::RemoveParticipant(const Entity* participant) {
|
|
const auto loadedParticipant = std::find(m_Participants.begin(), m_Participants.end(), participant->GetObjectID());
|
|
if (loadedParticipant != m_Participants.end()) {
|
|
m_Participants.erase(loadedParticipant);
|
|
}
|
|
}
|
|
|
|
uint32_t ActivityInstance::GetScore() const {
|
|
return score;
|
|
}
|
|
|
|
void ActivityInstance::SetScore(uint32_t score) {
|
|
this->score = score;
|
|
}
|
|
|
|
Entity* LobbyPlayer::GetEntity() const {
|
|
return Game::entityManager->GetEntity(entityID);
|
|
}
|