2023-12-29 01:11:19 +00:00
# include "ActivityComponent.h"
2021-12-05 17:54:36 +00:00
# include "GameMessages.h"
# include "CDClientManager.h"
# include "MissionComponent.h"
# include "Character.h"
# include "dZoneManager.h"
# include "ZoneInstanceManager.h"
# include "Game.h"
2023-10-21 23:31:55 +00:00
# include "Logger.h"
2024-01-05 12:33:52 +00:00
# include "WorldPackets.h"
2021-12-05 17:54:36 +00:00
# include "EntityManager.h"
# include "ChatPackets.h"
# include "Player.h"
2023-09-21 01:06:28 +00:00
# include "BitStreamUtils.h"
2021-12-05 17:54:36 +00:00
# include "dServer.h"
# include "GeneralUtils.h"
# include "dZoneManager.h"
# include "dConfig.h"
2022-12-18 15:46:04 +00:00
# include "InventoryComponent.h"
2021-12-24 00:25:52 +00:00
# include "DestroyableComponent.h"
2023-01-07 05:17:05 +00:00
# include "Loot.h"
2021-12-05 17:54:36 +00:00
# include "eMissionTaskType.h"
2023-05-02 22:39:21 +00:00
# include "eMatchUpdate.h"
2023-05-03 21:38:32 +00:00
# include "eConnectionType.h"
# include "eChatInternalMessageType.h"
2021-12-05 17:54:36 +00:00
2023-03-17 14:36:21 +00:00
# include "CDCurrencyTableTable.h"
# include "CDActivityRewardsTable.h"
# include "CDActivitiesTable.h"
2023-05-08 09:38:08 +00:00
# include "LeaderboardManager.h"
2023-03-17 14:36:21 +00:00
2023-12-29 01:11:19 +00:00
ActivityComponent : : ActivityComponent ( Entity * parent , int32_t activityID ) : Component ( parent ) {
2024-01-07 13:43:53 +00:00
/*
* 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 .
*/
2021-12-05 17:54:36 +00:00
2024-01-07 13:43:53 +00:00
m_ActivityID = activityID ;
LoadActivityData ( activityID ) ;
if ( m_Parent - > HasVar ( u " activityID " ) ) {
m_ActivityID = parent - > GetVar < int32_t > ( u " activityID " ) ;
LoadActivityData ( m_ActivityID ) ;
2021-12-05 17:54:36 +00:00
}
2021-12-24 00:25:52 +00:00
auto * destroyableComponent = m_Parent - > GetComponent < DestroyableComponent > ( ) ;
if ( destroyableComponent ) {
2024-01-11 04:57:41 +00:00
// First lookup the loot matrix id for this component id.
2023-03-17 14:36:21 +00:00
CDActivityRewardsTable * activityRewardsTable = CDClientManager : : Instance ( ) . GetTable < CDActivityRewardsTable > ( ) ;
2021-12-24 00:25:52 +00:00
std : : vector < CDActivityRewards > activityRewards = activityRewardsTable - > Query ( [ = ] ( CDActivityRewards entry ) { return ( entry . LootMatrixIndex = = destroyableComponent - > GetLootMatrixID ( ) ) ; } ) ;
uint32_t startingLMI = 0 ;
2024-01-11 04:57:41 +00:00
// If we have one, set the starting loot matrix id to that.
2021-12-24 00:25:52 +00:00
if ( activityRewards . size ( ) > 0 ) {
startingLMI = activityRewards [ 0 ] . LootMatrixIndex ;
}
if ( startingLMI > 0 ) {
2024-01-11 04:57:41 +00:00
// 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.
2021-12-24 00:25:52 +00:00
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 } ) ;
}
}
}
}
2021-12-05 17:54:36 +00:00
}
2024-01-07 13:43:53 +00:00
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 ) ;
}
}
}
}
2021-12-05 17:54:36 +00:00
2023-12-29 01:11:19 +00:00
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 ) ;
}
2021-12-05 17:54:36 +00:00
}
}
2023-12-29 01:11:19 +00:00
if ( ! bIsInitialUpdate ) m_DirtyActivityInfo = false ;
2021-12-05 17:54:36 +00:00
}
}
2023-12-29 01:11:19 +00:00
void ActivityComponent : : ReloadConfig ( ) {
2023-03-17 14:36:21 +00:00
CDActivitiesTable * activitiesTable = CDClientManager : : Instance ( ) . GetTable < CDActivitiesTable > ( ) ;
2024-01-02 07:53:00 +00:00
std : : vector < CDActivities > activities = activitiesTable - > Query ( [ this ] ( CDActivities entry ) { return ( entry . ActivityID = = m_ActivityID ) ; } ) ;
2022-12-04 22:25:58 +00:00
for ( auto activity : activities ) {
auto mapID = m_ActivityInfo . instanceMapID ;
2023-12-29 01:11:19 +00:00
if ( static_cast < Leaderboard : : Type > ( activity . leaderboardType ) = = Leaderboard : : Type : : Racing & & Game : : config - > GetValue ( " solo_racing " ) = = " 1 " ) {
2022-12-04 22:25:58 +00:00
m_ActivityInfo . minTeamSize = 1 ;
m_ActivityInfo . minTeams = 1 ;
} else {
m_ActivityInfo . minTeamSize = activity . minTeamSize ;
m_ActivityInfo . minTeams = activity . minTeams ;
}
}
}
2023-12-29 01:11:19 +00:00
void ActivityComponent : : HandleMessageBoxResponse ( Entity * player , const std : : string & id ) {
2021-12-05 17:54:36 +00:00
if ( id = = " LobbyExit " ) {
PlayerLeave ( player - > GetObjectID ( ) ) ;
} else if ( id = = " PlayButton " ) {
PlayerJoin ( player ) ;
}
}
2023-12-29 01:11:19 +00:00
void ActivityComponent : : PlayerJoin ( Entity * player ) {
2023-12-31 06:14:58 +00:00
if ( PlayerIsInQueue ( player ) ) return ;
2021-12-05 17:54:36 +00:00
// 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 ) ;
}
}
2023-12-29 01:11:19 +00:00
void ActivityComponent : : PlayerJoinLobby ( Entity * player ) {
2023-03-04 07:16:37 +00:00
if ( ! m_Parent - > HasComponent ( eReplicaComponentType : : QUICK_BUILD ) )
2021-12-05 17:54:36 +00:00
GameMessages : : SendMatchResponse ( player , player - > GetSystemAddress ( ) , 0 ) ; // tell the client they joined a lobby
LobbyPlayer * newLobbyPlayer = new LobbyPlayer ( ) ;
newLobbyPlayer - > entityID = player - > GetObjectID ( ) ;
Lobby * playerLobby = nullptr ;
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
auto * character = player - > GetCharacter ( ) ;
if ( character ! = nullptr )
2023-07-17 22:55:33 +00:00
character - > SetLastNonInstanceZoneID ( Game : : zoneManager - > GetZone ( ) - > GetWorldID ( ) ) ;
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
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 ;
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
// 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 ( ) ) + " \n playerName=0: " + player - > GetCharacter ( ) - > GetName ( ) ;
for ( LobbyPlayer * joinedPlayer : lobby - > players ) {
auto * entity = joinedPlayer - > GetEntity ( ) ;
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
if ( entity = = nullptr ) {
continue ;
}
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
std : : string matchUpdate = " player=9: " + std : : to_string ( entity - > GetObjectID ( ) ) + " \n playerName=0: " + entity - > GetCharacter ( ) - > GetName ( ) ;
2023-05-02 22:39:21 +00:00
GameMessages : : SendMatchUpdate ( player , player - > GetSystemAddress ( ) , matchUpdate , eMatchUpdate : : PLAYER_ADDED ) ;
2021-12-05 17:54:36 +00:00
PlayerReady ( entity , joinedPlayer - > ready ) ;
2023-05-02 22:39:21 +00:00
GameMessages : : SendMatchUpdate ( entity , entity - > GetSystemAddress ( ) , matchUpdateJoined , eMatchUpdate : : PLAYER_ADDED ) ;
2021-12-05 17:54:36 +00:00
}
}
}
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
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 ) ;
}
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
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 ) ;
2023-05-02 22:39:21 +00:00
GameMessages : : SendMatchUpdate ( player , player - > GetSystemAddress ( ) , matchTimerUpdate , eMatchUpdate : : PHASE_WAIT_READY ) ;
2021-12-05 17:54:36 +00:00
}
}
2023-12-29 01:11:19 +00:00
void ActivityComponent : : PlayerLeave ( LWOOBJID playerID ) {
2021-12-05 17:54:36 +00:00
// 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 ;
2023-05-02 22:39:21 +00:00
GameMessages : : SendMatchUpdate ( entity , entity - > GetSystemAddress ( ) , matchUpdateLeft , eMatchUpdate : : PLAYER_REMOVED ) ;
2021-12-05 17:54:36 +00:00
}
delete lobby - > players [ i ] ;
lobby - > players [ i ] = nullptr ;
lobby - > players . erase ( lobby - > players . begin ( ) + i ) ;
2022-07-25 02:26:51 +00:00
2021-12-05 17:54:36 +00:00
return ;
}
}
}
}
2023-12-29 01:11:19 +00:00
void ActivityComponent : : Update ( float deltaTime ) {
2022-12-20 21:20:44 +00:00
std : : vector < Lobby * > lobbiesToRemove { } ;
2021-12-05 17:54:36 +00:00
// 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 ;
}
}
2022-12-20 21:20:44 +00:00
if ( lobby - > players . empty ( ) ) {
lobbiesToRemove . push_back ( lobby ) ;
continue ;
}
2021-12-05 17:54:36 +00:00
// 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 ) ;
2023-05-02 22:39:21 +00:00
GameMessages : : SendMatchUpdate ( entity , entity - > GetSystemAddress ( ) , matchTimerUpdate , eMatchUpdate : : PHASE_WAIT_READY ) ;
2021-12-05 17:54:36 +00:00
}
}
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 ;
2023-05-02 22:39:21 +00:00
GameMessages : : SendMatchUpdate ( entity , entity - > GetSystemAddress ( ) , matchTimerUpdate , eMatchUpdate : : PHASE_WAIT_START ) ;
2021-12-05 17:54:36 +00:00
}
}
// The timer has elapsed, start the instance
if ( lobby - > timer < = 0.0f ) {
2023-10-21 23:31:55 +00:00
LOG ( " Setting up instance. " ) ;
2021-12-05 17:54:36 +00:00
ActivityInstance * instance = NewInstance ( ) ;
LoadPlayersIntoInstance ( instance , lobby - > players ) ;
instance - > StartZone ( ) ;
2022-12-20 21:20:44 +00:00
lobbiesToRemove . push_back ( lobby ) ;
2021-12-05 17:54:36 +00:00
}
}
2022-12-20 21:20:44 +00:00
while ( ! lobbiesToRemove . empty ( ) ) {
RemoveLobby ( lobbiesToRemove . front ( ) ) ;
lobbiesToRemove . erase ( lobbiesToRemove . begin ( ) ) ;
}
2021-12-05 17:54:36 +00:00
}
2023-12-29 01:11:19 +00:00
void ActivityComponent : : RemoveLobby ( Lobby * lobby ) {
2021-12-05 17:54:36 +00:00
for ( int i = 0 ; i < m_Queue . size ( ) ; + + i ) {
if ( m_Queue [ i ] = = lobby ) {
m_Queue . erase ( m_Queue . begin ( ) + i ) ;
return ;
}
}
}
2023-12-29 01:11:19 +00:00
bool ActivityComponent : : HasLobby ( ) const {
2021-12-05 17:54:36 +00:00
// 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 ( ) ;
}
2023-12-29 01:11:19 +00:00
bool ActivityComponent : : PlayerIsInQueue ( Entity * player ) {
2021-12-05 17:54:36 +00:00
for ( Lobby * lobby : m_Queue ) {
for ( LobbyPlayer * lobbyPlayer : lobby - > players ) {
if ( player - > GetObjectID ( ) = = lobbyPlayer - > entityID ) return true ;
}
}
return false ;
}
2023-12-29 01:11:19 +00:00
bool ActivityComponent : : IsPlayedBy ( Entity * player ) const {
2021-12-05 17:54:36 +00:00
for ( const auto * instance : this - > m_Instances ) {
for ( const auto * instancePlayer : instance - > GetParticipants ( ) ) {
if ( instancePlayer ! = nullptr & & instancePlayer - > GetObjectID ( ) = = player - > GetObjectID ( ) )
return true ;
}
}
return false ;
}
2023-12-29 01:11:19 +00:00
bool ActivityComponent : : IsPlayedBy ( LWOOBJID playerID ) const {
2021-12-05 17:54:36 +00:00
for ( const auto * instance : this - > m_Instances ) {
for ( const auto * instancePlayer : instance - > GetParticipants ( ) ) {
if ( instancePlayer ! = nullptr & & instancePlayer - > GetObjectID ( ) = = playerID )
return true ;
}
}
return false ;
}
2023-12-29 01:11:19 +00:00
bool ActivityComponent : : TakeCost ( Entity * player ) const {
2021-12-05 17:54:36 +00:00
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 ;
}
2023-12-29 01:11:19 +00:00
void ActivityComponent : : PlayerReady ( Entity * player , bool bReady ) {
2021-12-05 17:54:36 +00:00
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 ( ) ) ;
2023-05-02 22:39:21 +00:00
eMatchUpdate readyStatus = eMatchUpdate : : PLAYER_READY ;
if ( ! bReady ) readyStatus = eMatchUpdate : : PLAYER_NOT_READY ;
2021-12-05 17:54:36 +00:00
for ( LobbyPlayer * otherPlayer : lobby - > players ) {
auto * entity = otherPlayer - > GetEntity ( ) ;
if ( entity = = nullptr )
continue ;
GameMessages : : SendMatchUpdate ( entity , entity - > GetSystemAddress ( ) , matchReadyUpdate , readyStatus ) ;
}
}
}
}
}
2023-12-29 01:11:19 +00:00
ActivityInstance * ActivityComponent : : NewInstance ( ) {
2021-12-05 17:54:36 +00:00
auto * instance = new ActivityInstance ( m_Parent , m_ActivityInfo ) ;
m_Instances . push_back ( instance ) ;
return instance ;
}
2023-12-29 01:11:19 +00:00
void ActivityComponent : : LoadPlayersIntoInstance ( ActivityInstance * instance , const std : : vector < LobbyPlayer * > & lobby ) const {
2021-12-05 17:54:36 +00:00
for ( LobbyPlayer * player : lobby ) {
auto * entity = player - > GetEntity ( ) ;
if ( entity = = nullptr | | ! TakeCost ( entity ) ) {
continue ;
}
instance - > AddParticipant ( entity ) ;
}
}
2023-12-29 01:11:19 +00:00
const std : : vector < ActivityInstance * > & ActivityComponent : : GetInstances ( ) const {
2021-12-05 17:54:36 +00:00
return m_Instances ;
}
2023-12-29 01:11:19 +00:00
ActivityInstance * ActivityComponent : : GetInstance ( const LWOOBJID playerID ) {
2021-12-05 17:54:36 +00:00
for ( const auto * instance : GetInstances ( ) ) {
for ( const auto * participant : instance - > GetParticipants ( ) ) {
if ( participant - > GetObjectID ( ) = = playerID )
return const_cast < ActivityInstance * > ( instance ) ;
}
}
return nullptr ;
}
2023-12-29 01:11:19 +00:00
void ActivityComponent : : ClearInstances ( ) {
2021-12-05 17:54:36 +00:00
for ( ActivityInstance * instance : m_Instances ) {
delete instance ;
}
m_Instances . clear ( ) ;
}
2023-12-29 01:11:19 +00:00
ActivityPlayer * ActivityComponent : : GetActivityPlayerData ( LWOOBJID playerID ) {
2021-12-05 17:54:36 +00:00
for ( auto * activityData : m_ActivityPlayers ) {
if ( activityData - > playerID = = playerID ) {
return activityData ;
}
}
return nullptr ;
}
2023-12-29 01:11:19 +00:00
void ActivityComponent : : RemoveActivityPlayerData ( LWOOBJID playerID ) {
2021-12-05 17:54:36 +00:00
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 ) ;
2023-12-29 01:11:19 +00:00
m_DirtyActivityInfo = true ;
2023-07-15 20:56:33 +00:00
Game : : entityManager - > SerializeEntity ( m_Parent ) ;
2021-12-05 17:54:36 +00:00
return ;
}
}
}
2023-12-29 01:11:19 +00:00
ActivityPlayer * ActivityComponent : : AddActivityPlayerData ( LWOOBJID playerID ) {
2021-12-05 17:54:36 +00:00
auto * data = GetActivityPlayerData ( playerID ) ;
if ( data ! = nullptr )
return data ;
m_ActivityPlayers . push_back ( new ActivityPlayer { playerID , { } } ) ;
2023-12-29 01:11:19 +00:00
m_DirtyActivityInfo = true ;
2023-07-15 20:56:33 +00:00
Game : : entityManager - > SerializeEntity ( m_Parent ) ;
2021-12-05 17:54:36 +00:00
return GetActivityPlayerData ( playerID ) ;
}
2023-12-29 01:11:19 +00:00
float_t ActivityComponent : : GetActivityValue ( LWOOBJID playerID , uint32_t index ) {
2021-12-05 17:54:36 +00:00
auto value = - 1.0f ;
auto * data = GetActivityPlayerData ( playerID ) ;
if ( data ! = nullptr ) {
2023-12-28 04:18:20 +00:00
value = data - > values [ std : : min ( index , static_cast < uint32_t > ( 9 ) ) ] ;
2021-12-05 17:54:36 +00:00
}
return value ;
}
2023-12-29 01:11:19 +00:00
void ActivityComponent : : SetActivityValue ( LWOOBJID playerID , uint32_t index , float_t value ) {
2021-12-05 17:54:36 +00:00
auto * data = AddActivityPlayerData ( playerID ) ;
if ( data ! = nullptr ) {
2023-12-28 04:18:20 +00:00
data - > values [ std : : min ( index , static_cast < uint32_t > ( 9 ) ) ] = value ;
2021-12-05 17:54:36 +00:00
}
2023-12-29 01:11:19 +00:00
m_DirtyActivityInfo = true ;
2023-07-15 20:56:33 +00:00
Game : : entityManager - > SerializeEntity ( m_Parent ) ;
2021-12-05 17:54:36 +00:00
}
2023-12-29 01:11:19 +00:00
void ActivityComponent : : PlayerRemove ( LWOOBJID playerID ) {
2021-12-05 17:54:36 +00:00
for ( auto * instance : GetInstances ( ) ) {
auto participants = instance - > GetParticipants ( ) ;
for ( const auto * participant : participants ) {
if ( participant ! = nullptr & & participant - > GetObjectID ( ) = = playerID ) {
instance - > RemoveParticipant ( participant ) ;
RemoveActivityPlayerData ( playerID ) ;
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
// 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 ] ;
2022-05-27 20:25:57 +00:00
LWOZONEID zoneId = LWOZONEID ( m_ActivityInfo . instanceMapID , 0 , leader - > GetCharacter ( ) - > GetPropertyCloneID ( ) ) ;
2021-12-05 17:54:36 +00:00
2022-05-27 20:25:57 +00:00
// only make a team if we have more than one participant
if ( participants . size ( ) > 1 ) {
CBITSTREAM ;
2023-09-21 01:06:28 +00:00
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : CHAT_INTERNAL , eChatInternalMessageType : : CREATE_TEAM ) ;
2021-12-05 17:54:36 +00:00
2022-05-27 20:25:57 +00:00
bitStream . Write ( leader - > GetObjectID ( ) ) ;
bitStream . Write ( m_Participants . size ( ) ) ;
2021-12-05 17:54:36 +00:00
2022-05-27 20:25:57 +00:00
for ( const auto & participant : m_Participants ) {
bitStream . Write ( participant ) ;
}
2021-12-05 17:54:36 +00:00
2022-05-27 20:25:57 +00:00
bitStream . Write ( zoneId ) ;
2021-12-05 17:54:36 +00:00
2022-05-27 20:25:57 +00:00
Game : : chatServer - > Send ( & bitStream , SYSTEM_PRIORITY , RELIABLE , 0 , Game : : chatSysAddr , false ) ;
}
2021-12-05 17:54:36 +00:00
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 ) {
2023-07-15 20:56:33 +00:00
auto * player = Game : : entityManager - > GetEntity ( objid ) ;
2021-12-05 17:54:36 +00:00
if ( player = = nullptr )
return ;
2023-10-21 23:31:55 +00:00
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 ) ;
2021-12-05 17:54:36 +00:00
if ( player - > GetCharacter ( ) ) {
player - > GetCharacter ( ) - > SetZoneID ( zoneID ) ;
player - > GetCharacter ( ) - > SetZoneInstance ( zoneInstance ) ;
player - > GetCharacter ( ) - > SetZoneClone ( zoneClone ) ;
}
WorldPackets : : SendTransferToWorld ( player - > GetSystemAddress ( ) , serverIP , serverPort , mythranShift ) ;
return ;
} ) ;
}
2022-07-25 02:26:51 +00:00
2021-12-05 17:54:36 +00:00
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
2023-03-17 14:36:21 +00:00
auto * activityRewardsTable = CDClientManager : : Instance ( ) . GetTable < CDActivityRewardsTable > ( ) ;
2024-01-02 07:53:00 +00:00
std : : vector < CDActivityRewards > activityRewards = activityRewardsTable - > Query ( [ this ] ( CDActivityRewards entry ) { return ( entry . objectTemplate = = m_ActivityInfo . ActivityID ) ; } ) ;
2021-12-05 17:54:36 +00:00
if ( ! activityRewards . empty ( ) ) {
uint32_t minCoins = 0 ;
uint32_t maxCoins = 0 ;
2023-03-17 14:36:21 +00:00
auto * currencyTableTable = CDClientManager : : Instance ( ) . GetTable < CDCurrencyTableTable > ( ) ;
2021-12-05 17:54:36 +00:00
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 ;
}
2023-10-09 20:33:22 +00:00
Loot : : DropLoot ( participant , m_Parent , activityRewards [ 0 ] . LootMatrixIndex , minCoins , maxCoins ) ;
2021-12-05 17:54:36 +00:00
}
}
std : : vector < Entity * > ActivityInstance : : GetParticipants ( ) const {
std : : vector < Entity * > entities ;
entities . reserve ( m_Participants . size ( ) ) ;
for ( const auto & id : m_Participants ) {
2023-07-15 20:56:33 +00:00
auto * entity = Game : : entityManager - > GetEntity ( id ) ;
2021-12-05 17:54:36 +00:00
if ( entity ! = nullptr )
entities . push_back ( entity ) ;
}
2022-07-25 02:26:51 +00:00
2021-12-05 17:54:36 +00:00
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 {
2023-07-15 20:56:33 +00:00
return Game : : entityManager - > GetEntity ( entityID ) ;
2021-12-05 17:54:36 +00:00
}