Merge git://github.com/EQEmu/Server into Development

This commit is contained in:
KayenEQ 2014-09-26 06:54:53 -04:00
commit 9f3a0a3f95
21 changed files with 1136 additions and 1223 deletions

View File

@ -289,6 +289,7 @@ ADD_DEFINITIONS(-DLOG_LEVEL_DEBUG=${EQEMU_LOG_LEVEL_DEBUG})
ADD_DEFINITIONS(-DLOG_LEVEL_QUEST=${EQEMU_LOG_LEVEL_QUEST})
ADD_DEFINITIONS(-DLOG_LEVEL_COMMANDS=${EQEMU_LOG_LEVEL_COMMANDS})
ADD_DEFINITIONS(-DLOG_LEVEL_CRASH=${EQEMU_LOG_LEVEL_CRASH})
ADD_DEFINITIONS(-DGLM_FORCE_RADIANS)
IF(EQEMU_STREAM_RETRANSMIT_ACKED_PACKETS)
ADD_DEFINITIONS(-DRETRANSMIT_ACKED_PACKETS=true)

View File

@ -387,3 +387,26 @@ float EQHtoFloat(int d)
{
return(360.0f - float((d * 360) >> 11));
}
// returns a swapped-bit value for use in client translator and inventory functions
uint32 SwapBits21and22(uint32 mask)
{
static const uint32 BIT21 = 1 << 21;
static const uint32 BIT22 = 1 << 22;
static const uint32 SWAPBITS = (BIT21 | BIT22);
if ((bool)(mask & BIT21) != (bool)(mask & BIT22))
mask ^= SWAPBITS;
return mask;
}
// returns an unset bit 22 value for use in client translators
uint32 Catch22(uint32 mask)
{
static const uint32 KEEPBITS = ~(1 << 22);
mask &= KEEPBITS;
return mask;
}

View File

@ -102,6 +102,8 @@ int FloatToEQ13(float d);
int NewFloatToEQ13(float d);
int FloatToEQ19(float d);
int FloatToEQH(float d);
uint32 SwapBits21and22(uint32 mask);
uint32 Catch22(uint32 mask);
// macro to catch fp errors (provided by noudness)
#define FCMP(a,b) (fabs(a-b) < FLT_EPSILON)

View File

@ -131,22 +131,6 @@ static inline uint32 Client62ToServerCorpseSlot(uint32 Client62Corpse) {
// reserved
}
*/
/*
static inline uint32 RemovePowerSourceBit(uint32 slots) { // shouldn't need to add one..just grab the actual server reference, if so...
static const uint32 BIT21 = 1 << 21;
static const uint32 BIT22 = 1 << 22;
static const uint32 KEEPBITS = ~(BIT21 | BIT22);
bool wearammo = slots & BIT22;
slots &= KEEPBITS;
if (wearammo)
slots |= BIT21;
return slots;
}
*/
EAT_ENCODE(OP_ZoneServerReady)

View File

@ -1,36 +1,35 @@
//list of packets we need to encode on the way out:
// out-going packets that require an ENCODE translation:
E(OP_Action)
E(OP_BazaarSearch)
E(OP_BecomeTrader)
E(OP_CharInventory)
E(OP_DeleteSpawn)
E(OP_GuildMemberLevelUpdate)
E(OP_GuildMemberList)
E(OP_Illusion)
E(OP_ItemLinkResponse)
E(OP_ItemPacket)
E(OP_LeadershipExpUpdate)
E(OP_NewSpawn)
E(OP_OnLevelMessage)
E(OP_PetBuffWindow)
E(OP_PlayerProfile)
E(OP_ReadBook)
E(OP_RespondAA)
E(OP_SendAATable)
E(OP_SendCharInfo)
E(OP_LeadershipExpUpdate)
E(OP_PlayerProfile)
E(OP_NewSpawn)
E(OP_ZoneSpawns)
E(OP_ZoneEntry)
E(OP_ItemPacket)
E(OP_ItemLinkResponse)
E(OP_CharInventory)
E(OP_GuildMemberList)
E(OP_ZoneServerReady)
E(OP_GuildMemberLevelUpdate)
E(OP_ReadBook)
E(OP_Illusion)
E(OP_Track)
E(OP_BazaarSearch)
E(OP_RespondAA)
E(OP_DeleteSpawn)
E(OP_WearChange)
E(OP_Action)
E(OP_BecomeTrader)
E(OP_PetBuffWindow)
E(OP_OnLevelMessage)
//list of packets we need to decode on the way in:
D(OP_SetServerFilter)
E(OP_ZoneEntry)
E(OP_ZoneServerReady)
E(OP_ZoneSpawns)
// incoming packets that require a DECODE translation:
D(OP_CharacterCreate)
D(OP_ItemLinkClick)
D(OP_WhoAllRequest)
D(OP_ReadBook)
D(OP_FaceChange)
D(OP_ItemLinkClick)
D(OP_ReadBook)
D(OP_SetServerFilter)
D(OP_WearChange)
D(OP_WhoAllRequest)
#undef E
#undef D

View File

@ -1,162 +1,160 @@
//list of packets we need to encode on the way out:
E(OP_SendCharInfo)
E(OP_ZoneServerInfo)
E(OP_SendAATable)
E(OP_PlayerProfile)
E(OP_ZoneEntry)
E(OP_CharInventory)
E(OP_NewZone)
E(OP_SpawnDoor)
E(OP_GroundSpawn)
E(OP_SendZonepoints)
E(OP_NewSpawn)
E(OP_ZoneSpawns)
E(OP_ItemLinkResponse)
E(OP_ItemPacket)
E(OP_GuildMemberList)
E(OP_Illusion)
E(OP_ManaChange)
E(OP_ClientUpdate)
E(OP_LeadershipExpUpdate)
E(OP_ExpansionInfo)
E(OP_LogServer)
E(OP_Damage)
E(OP_Buff)
// out-going packets that require an ENCODE translation:
E(OP_Action)
E(OP_Consider)
E(OP_CancelTrade)
E(OP_ShopPlayerSell)
E(OP_DeleteItem)
E(OP_ItemVerifyReply)
E(OP_DeleteCharge)
E(OP_MoveItem)
//E(OP_OpenNewTasksWindow)
E(OP_BazaarSearch)
E(OP_Trader)
E(OP_TraderBuy)
E(OP_LootItem)
E(OP_TributeItem)
E(OP_SomeItemPacketMaybe)
E(OP_ReadBook)
E(OP_Stun)
E(OP_ZonePlayerToBind)
E(OP_AdventureMerchantSell)
E(OP_RaidUpdate)
E(OP_RaidJoin)
E(OP_VetRewardsAvaliable)
E(OP_InspectRequest)
E(OP_GroupInvite)
E(OP_GroupFollow)
E(OP_GroupFollow2)
E(OP_GroupUpdate)
E(OP_GroupCancelInvite)
E(OP_WhoAllResponse)
E(OP_Track)
E(OP_ShopPlayerBuy)
E(OP_PetBuffWindow)
E(OP_OnLevelMessage)
E(OP_Barter)
E(OP_AltCurrency)
E(OP_AltCurrencySell)
E(OP_Animation)
E(OP_ApplyPoison)
E(OP_Barter)
E(OP_BazaarSearch)
E(OP_BeginCast)
E(OP_BlockedBuffs)
E(OP_Buff)
E(OP_BuffCreate)
E(OP_CancelTrade)
E(OP_CastSpell)
E(OP_ChannelMessage)
E(OP_GuildsList)
E(OP_CharInventory)
E(OP_ClickObjectAction)
E(OP_ClientUpdate)
E(OP_Consider)
E(OP_Damage)
E(OP_DeleteCharge)
E(OP_DeleteItem)
E(OP_DeleteSpawn)
E(OP_DisciplineUpdate)
E(OP_DzCompass)
E(OP_DzExpeditionEndsWarning)
E(OP_DzExpeditionInfo)
E(OP_DzCompass)
E(OP_DzMemberList)
E(OP_DzExpeditionList)
E(OP_DzLeaderStatus)
E(OP_DzJoinExpeditionConfirm)
E(OP_TargetBuffs)
E(OP_BuffCreate)
E(OP_SpawnAppearance)
E(OP_RespondAA)
E(OP_DisciplineUpdate)
E(OP_AltCurrencySell)
E(OP_AltCurrency)
E(OP_RequestClientZoneChange)
E(OP_ZoneChange)
E(OP_WearChange)
E(OP_ShopRequest)
E(OP_CastSpell)
E(OP_InterruptCast)
E(OP_SendMembership)
E(OP_Animation)
E(OP_HPUpdate)
E(OP_BlockedBuffs)
E(OP_RemoveBlockedBuffs)
E(OP_DeleteSpawn)
E(OP_ClickObjectAction)
E(OP_RecipeAutoCombine)
E(OP_GMTrainSkillConfirm)
E(OP_SkillUpdate)
E(OP_TributeInfo)
E(OP_TaskHistoryReply)
E(OP_TaskDescription)
E(OP_SetGuildRank)
E(OP_MercenaryDataUpdate)
E(OP_MercenaryDataResponse)
E(OP_GuildMemberUpdate)
E(OP_DzLeaderStatus)
E(OP_DzMemberList)
E(OP_ExpansionInfo)
E(OP_GMLastName)
E(OP_BeginCast)
E(OP_GMTrainSkillConfirm)
E(OP_GroundSpawn)
E(OP_GroupCancelInvite)
E(OP_GroupFollow)
E(OP_GroupFollow2)
E(OP_GroupInvite)
E(OP_GroupUpdate)
E(OP_GuildMemberList)
E(OP_GuildMemberUpdate)
E(OP_GuildsList)
E(OP_HPUpdate)
E(OP_Illusion)
E(OP_InspectRequest)
E(OP_InterruptCast)
E(OP_ItemLinkResponse)
E(OP_ItemPacket)
E(OP_ItemVerifyReply)
E(OP_LeadershipExpUpdate)
E(OP_LogServer)
E(OP_LootItem)
E(OP_ManaChange)
E(OP_MercenaryDataResponse)
E(OP_MercenaryDataUpdate)
E(OP_MoveItem)
E(OP_NewSpawn)
E(OP_NewZone)
E(OP_OnLevelMessage)
//E(OP_OpenNewTasksWindow)
E(OP_PetBuffWindow)
E(OP_PlayerProfile)
E(OP_RaidJoin)
E(OP_RaidUpdate)
E(OP_ReadBook)
E(OP_RecipeAutoCombine)
E(OP_RemoveBlockedBuffs)
E(OP_RequestClientZoneChange)
E(OP_RespondAA)
E(OP_RezzRequest)
//list of packets we need to decode on the way in:
D(OP_SetServerFilter)
D(OP_CharacterCreate)
D(OP_ItemLinkClick)
D(OP_ConsiderCorpse)
D(OP_Consider)
D(OP_ClientUpdate)
D(OP_MoveItem)
D(OP_WhoAllRequest)
E(OP_SendAATable)
E(OP_SendCharInfo)
E(OP_SendMembership)
E(OP_SendZonepoints)
E(OP_SetGuildRank)
E(OP_ShopPlayerBuy)
E(OP_ShopPlayerSell)
E(OP_ShopRequest)
E(OP_SkillUpdate)
E(OP_SomeItemPacketMaybe)
E(OP_SpawnAppearance)
E(OP_SpawnDoor)
E(OP_Stun)
E(OP_TargetBuffs)
E(OP_TaskDescription)
E(OP_TaskHistoryReply)
E(OP_Track)
E(OP_Trader)
E(OP_TraderBuy)
E(OP_TributeInfo)
E(OP_TributeItem)
E(OP_VetRewardsAvaliable)
E(OP_WearChange)
E(OP_WhoAllResponse)
E(OP_ZoneChange)
E(OP_ZoneEntry)
E(OP_ZonePlayerToBind)
E(OP_ZoneServerInfo)
E(OP_ZoneSpawns)
// incoming packets that require a DECODE translation:
D(OP_AdventureMerchantSell)
D(OP_AltCurrencySell)
D(OP_AltCurrencySellSelection)
D(OP_ApplyPoison)
D(OP_AugmentInfo)
D(OP_AugmentItem)
D(OP_BazaarSearch)
D(OP_BlockedBuffs)
D(OP_Buff)
D(OP_ShopPlayerSell)
D(OP_Consume)
D(OP_BuffRemoveRequest)
D(OP_CastSpell)
D(OP_Save)
D(OP_ItemVerifyRequest)
D(OP_GroupInvite)
D(OP_GroupInvite2)
D(OP_ChannelMessage)
D(OP_CharacterCreate)
D(OP_ClientUpdate)
D(OP_Consider)
D(OP_ConsiderCorpse)
D(OP_Consume)
D(OP_Damage)
D(OP_DeleteItem)
D(OP_EnvDamage)
D(OP_FaceChange)
D(OP_FindPersonRequest)
D(OP_GMLastName)
D(OP_GroupCancelInvite)
D(OP_GroupDisband)
D(OP_GroupFollow)
D(OP_GroupFollow2)
D(OP_GroupDisband)
D(OP_GroupCancelInvite)
D(OP_FindPersonRequest)
D(OP_TraderBuy)
D(OP_LootItem)
D(OP_TributeItem)
D(OP_ReadBook)
D(OP_AugmentInfo)
D(OP_FaceChange)
D(OP_AdventureMerchantSell)
D(OP_TradeSkillCombine)
D(OP_RaidInvite)
D(OP_InspectRequest)
D(OP_ShopPlayerBuy)
D(OP_BazaarSearch)
D(OP_LoadSpellSet)
D(OP_ApplyPoison)
D(OP_Damage)
D(OP_EnvDamage)
D(OP_ChannelMessage)
D(OP_DeleteItem)
D(OP_AugmentItem)
D(OP_PetCommands)
D(OP_BuffRemoveRequest)
D(OP_AltCurrencySellSelection)
D(OP_AltCurrencySell)
D(OP_ZoneChange)
D(OP_ZoneEntry)
D(OP_ShopRequest)
D(OP_BlockedBuffs)
D(OP_RemoveBlockedBuffs)
D(OP_RecipeAutoCombine)
D(OP_GroupInvite)
D(OP_GroupInvite2)
D(OP_GuildDemote)
D(OP_GuildRemove)
D(OP_GuildStatus)
D(OP_Trader)
D(OP_GMLastName)
D(OP_InspectRequest)
D(OP_ItemLinkClick)
D(OP_ItemVerifyRequest)
D(OP_LoadSpellSet)
D(OP_LootItem)
D(OP_MoveItem)
D(OP_PetCommands)
D(OP_RaidInvite)
D(OP_ReadBook)
D(OP_RecipeAutoCombine)
D(OP_RemoveBlockedBuffs)
D(OP_RezzAnswer)
D(OP_Save)
D(OP_SetServerFilter)
D(OP_ShopPlayerBuy)
D(OP_ShopPlayerSell)
D(OP_ShopRequest)
D(OP_Trader)
D(OP_TraderBuy)
D(OP_TradeSkillCombine)
D(OP_TributeItem)
D(OP_WhoAllRequest)
D(OP_ZoneChange)
D(OP_ZoneEntry)
#undef E
#undef D

View File

@ -1,117 +1,115 @@
//list of packets we need to encode on the way out:
E(OP_SendCharInfo)
E(OP_ZoneServerInfo)
E(OP_SendAATable)
E(OP_PlayerProfile)
E(OP_ZoneEntry)
E(OP_CharInventory)
E(OP_NewZone)
E(OP_SpawnDoor)
E(OP_GroundSpawn)
E(OP_SendZonepoints)
E(OP_NewSpawn)
E(OP_ZoneSpawns)
E(OP_ItemLinkResponse)
E(OP_ItemPacket)
E(OP_GuildMemberList)
E(OP_Illusion)
E(OP_ManaChange)
E(OP_ClientUpdate)
E(OP_LeadershipExpUpdate)
E(OP_ExpansionInfo)
E(OP_LogServer)
E(OP_Damage)
E(OP_Buff)
// out-going packets that require an ENCODE translation:
E(OP_Action)
E(OP_Consider)
E(OP_CancelTrade)
E(OP_ShopPlayerSell)
E(OP_DeleteItem)
E(OP_ItemVerifyReply)
E(OP_DeleteCharge)
E(OP_MoveItem)
E(OP_OpenNewTasksWindow)
E(OP_BazaarSearch)
E(OP_Trader)
E(OP_TraderBuy)
E(OP_LootItem)
E(OP_TributeItem)
E(OP_SomeItemPacketMaybe)
E(OP_ReadBook)
E(OP_Stun)
E(OP_ZonePlayerToBind)
E(OP_AdventureMerchantSell)
E(OP_RaidUpdate)
E(OP_RaidJoin)
E(OP_VetRewardsAvaliable)
E(OP_InspectRequest)
E(OP_GroupInvite)
E(OP_GroupFollow)
E(OP_GroupFollow2)
E(OP_GroupUpdate)
E(OP_GroupCancelInvite)
E(OP_WhoAllResponse)
E(OP_Track)
E(OP_ShopPlayerBuy)
E(OP_PetBuffWindow)
E(OP_OnLevelMessage)
E(OP_Barter)
E(OP_AltCurrencySell)
E(OP_ApplyPoison)
E(OP_Barter)
E(OP_BazaarSearch)
E(OP_Buff)
E(OP_CancelTrade)
E(OP_CharInventory)
E(OP_ClientUpdate)
E(OP_Consider)
E(OP_Damage)
E(OP_DeleteCharge)
E(OP_DeleteItem)
E(OP_DzCompass)
E(OP_DzExpeditionEndsWarning)
E(OP_DzExpeditionInfo)
E(OP_DzCompass)
E(OP_DzMemberList)
E(OP_DzExpeditionList)
E(OP_DzLeaderStatus)
E(OP_DzJoinExpeditionConfirm)
E(OP_TargetBuffs)
E(OP_AltCurrencySell)
E(OP_WearChange)
E(OP_DzLeaderStatus)
E(OP_DzMemberList)
E(OP_ExpansionInfo)
E(OP_GroundSpawn)
E(OP_GroupCancelInvite)
E(OP_GroupFollow)
E(OP_GroupFollow2)
E(OP_GroupInvite)
E(OP_GroupUpdate)
E(OP_GuildMemberList)
E(OP_Illusion)
E(OP_InspectRequest)
E(OP_ItemLinkResponse)
E(OP_ItemPacket)
E(OP_ItemVerifyReply)
E(OP_LeadershipExpUpdate)
E(OP_LogServer)
E(OP_LootItem)
E(OP_ManaChange)
E(OP_MercenaryDataResponse)
E(OP_MercenaryDataUpdate)
//list of packets we need to decode on the way in:
D(OP_SetServerFilter)
D(OP_CharacterCreate)
D(OP_ItemLinkClick)
D(OP_ConsiderCorpse)
D(OP_Consider)
D(OP_ClientUpdate)
D(OP_MoveItem)
D(OP_WhoAllRequest)
E(OP_MoveItem)
E(OP_NewSpawn)
E(OP_NewZone)
E(OP_OnLevelMessage)
E(OP_OpenNewTasksWindow)
E(OP_PetBuffWindow)
E(OP_PlayerProfile)
E(OP_RaidJoin)
E(OP_RaidUpdate)
E(OP_ReadBook)
E(OP_SendAATable)
E(OP_SendCharInfo)
E(OP_SendZonepoints)
E(OP_ShopPlayerBuy)
E(OP_ShopPlayerSell)
E(OP_SomeItemPacketMaybe)
E(OP_SpawnDoor)
E(OP_Stun)
E(OP_TargetBuffs)
E(OP_Track)
E(OP_Trader)
E(OP_TraderBuy)
E(OP_TributeItem)
E(OP_VetRewardsAvaliable)
E(OP_WearChange)
E(OP_WhoAllResponse)
E(OP_ZoneEntry)
E(OP_ZonePlayerToBind)
E(OP_ZoneServerInfo)
E(OP_ZoneSpawns)
// incoming packets that require a DECODE translation:
D(OP_AdventureMerchantSell)
D(OP_AltCurrencySell)
D(OP_AltCurrencySellSelection)
D(OP_ApplyPoison)
D(OP_AugmentInfo)
D(OP_AugmentItem)
D(OP_BazaarSearch)
D(OP_Buff)
D(OP_ShopPlayerSell)
D(OP_Consume)
D(OP_Bug)
D(OP_CastSpell)
D(OP_Save)
D(OP_ItemVerifyRequest)
D(OP_GroupInvite)
D(OP_GroupInvite2)
D(OP_CharacterCreate)
D(OP_ClientUpdate)
D(OP_Consider)
D(OP_ConsiderCorpse)
D(OP_Consume)
D(OP_DeleteItem)
D(OP_FaceChange)
D(OP_FindPersonRequest)
D(OP_GroupCancelInvite)
D(OP_GroupDisband)
D(OP_GroupFollow)
D(OP_GroupFollow2)
D(OP_GroupDisband)
D(OP_GroupCancelInvite)
D(OP_FindPersonRequest)
D(OP_TraderBuy)
D(OP_LootItem)
D(OP_TributeItem)
D(OP_ReadBook)
D(OP_AugmentInfo)
D(OP_FaceChange)
D(OP_AdventureMerchantSell)
D(OP_TradeSkillCombine)
D(OP_RaidInvite)
D(OP_GroupInvite)
D(OP_GroupInvite2)
D(OP_InspectRequest)
D(OP_WearChange)
D(OP_ShopPlayerBuy)
D(OP_BazaarSearch)
D(OP_ItemLinkClick)
D(OP_ItemVerifyRequest)
D(OP_LoadSpellSet)
D(OP_ApplyPoison)
D(OP_DeleteItem)
D(OP_AugmentItem)
D(OP_Bug)
D(OP_AltCurrencySellSelection)
D(OP_AltCurrencySell)
D(OP_LootItem)
D(OP_MoveItem)
D(OP_RaidInvite)
D(OP_ReadBook)
D(OP_Save)
D(OP_SetServerFilter)
D(OP_ShopPlayerBuy)
D(OP_ShopPlayerSell)
D(OP_TraderBuy)
D(OP_TradeSkillCombine)
D(OP_TributeItem)
D(OP_WearChange)
D(OP_WhoAllRequest)
#undef E
#undef D

View File

@ -1,100 +1,98 @@
//list of packets we need to encode on the way out:
E(OP_SendCharInfo)
E(OP_ZoneServerInfo)
E(OP_SendAATable)
E(OP_PlayerProfile)
E(OP_ZoneEntry)
E(OP_CharInventory)
E(OP_NewZone)
E(OP_SpawnDoor)
E(OP_GroundSpawn)
E(OP_SendZonepoints)
E(OP_NewSpawn)
E(OP_ZoneSpawns)
E(OP_ItemLinkResponse)
E(OP_ItemPacket)
E(OP_GuildMemberList)
E(OP_Illusion)
E(OP_ManaChange)
E(OP_ClientUpdate)
E(OP_LeadershipExpUpdate)
E(OP_ExpansionInfo)
E(OP_LogServer)
E(OP_Damage)
E(OP_Buff)
// out-going packets that require an ENCODE translation:
E(OP_Action)
E(OP_Consider)
E(OP_CancelTrade)
E(OP_ShopPlayerSell)
E(OP_DeleteItem)
E(OP_ItemVerifyReply)
E(OP_DeleteCharge)
E(OP_MoveItem)
E(OP_OpenNewTasksWindow)
E(OP_BazaarSearch)
E(OP_Trader)
E(OP_TraderBuy)
E(OP_LootItem)
E(OP_TributeItem)
E(OP_SomeItemPacketMaybe)
E(OP_ReadBook)
E(OP_Stun)
E(OP_ZonePlayerToBind)
E(OP_AdventureMerchantSell)
E(OP_RaidUpdate)
E(OP_RaidJoin)
E(OP_VetRewardsAvaliable)
E(OP_InspectRequest)
E(OP_Track)
E(OP_DeleteSpawn)
E(OP_AltCurrencySell)
E(OP_ApplyPoison)
E(OP_BazaarSearch)
E(OP_BecomeTrader)
E(OP_Buff)
E(OP_CancelTrade)
E(OP_CharInventory)
E(OP_ClientUpdate)
E(OP_Consider)
E(OP_Damage)
E(OP_DeleteCharge)
E(OP_DeleteItem)
E(OP_DeleteSpawn)
E(OP_DzCompass)
E(OP_DzExpeditionEndsWarning)
E(OP_DzExpeditionInfo)
E(OP_DzCompass)
E(OP_DzMemberList)
E(OP_DzExpeditionList)
E(OP_DzLeaderStatus)
E(OP_DzJoinExpeditionConfirm)
E(OP_BecomeTrader)
E(OP_PetBuffWindow)
E(OP_DzLeaderStatus)
E(OP_DzMemberList)
E(OP_ExpansionInfo)
E(OP_GroundSpawn)
E(OP_GuildMemberList)
E(OP_Illusion)
E(OP_InspectRequest)
E(OP_ItemLinkResponse)
E(OP_ItemPacket)
E(OP_ItemVerifyReply)
E(OP_LeadershipExpUpdate)
E(OP_LogServer)
E(OP_LootItem)
E(OP_ManaChange)
E(OP_MoveItem)
E(OP_NewSpawn)
E(OP_NewZone)
E(OP_OnLevelMessage)
E(OP_AltCurrencySell)
E(OP_OpenNewTasksWindow)
E(OP_PetBuffWindow)
E(OP_PlayerProfile)
E(OP_RaidJoin)
E(OP_RaidUpdate)
E(OP_ReadBook)
E(OP_SendAATable)
E(OP_SendCharInfo)
E(OP_SendZonepoints)
E(OP_ShopPlayerSell)
E(OP_SomeItemPacketMaybe)
E(OP_SpawnDoor)
E(OP_Stun)
E(OP_Track)
E(OP_Trader)
E(OP_TraderBuy)
E(OP_TributeItem)
E(OP_VetRewardsAvaliable)
E(OP_WearChange)
//list of packets we need to decode on the way in:
D(OP_SetServerFilter)
D(OP_CharacterCreate)
D(OP_ItemLinkClick)
D(OP_ConsiderCorpse)
D(OP_Consider)
D(OP_ClientUpdate)
D(OP_MoveItem)
D(OP_WhoAllRequest)
E(OP_ZoneEntry)
E(OP_ZonePlayerToBind)
E(OP_ZoneServerInfo)
E(OP_ZoneSpawns)
// incoming packets that require a DECODE translation:
D(OP_AdventureMerchantSell)
D(OP_AltCurrencySell)
D(OP_AltCurrencySellSelection)
D(OP_ApplyPoison)
D(OP_AugmentInfo)
D(OP_AugmentItem)
D(OP_Buff)
D(OP_ShopPlayerSell)
D(OP_Consume)
D(OP_CastSpell)
D(OP_Save)
D(OP_ItemVerifyRequest)
D(OP_CharacterCreate)
D(OP_ClientUpdate)
D(OP_Consider)
D(OP_ConsiderCorpse)
D(OP_Consume)
D(OP_DeleteItem)
D(OP_FaceChange)
D(OP_FindPersonRequest)
D(OP_GroupFollow)
D(OP_GroupFollow2)
D(OP_FindPersonRequest)
D(OP_TraderBuy)
D(OP_LootItem)
D(OP_TributeItem)
D(OP_ReadBook)
D(OP_AugmentInfo)
D(OP_FaceChange)
D(OP_AdventureMerchantSell)
D(OP_TradeSkillCombine)
D(OP_RaidInvite)
D(OP_InspectRequest)
D(OP_ItemLinkClick)
D(OP_ItemVerifyRequest)
D(OP_LootItem)
D(OP_MoveItem)
D(OP_RaidInvite)
D(OP_ReadBook)
D(OP_Save)
D(OP_SetServerFilter)
D(OP_ShopPlayerSell)
D(OP_TraderBuy)
D(OP_TradeSkillCombine)
D(OP_TributeItem)
D(OP_WearChange)
D(OP_ApplyPoison)
D(OP_DeleteItem)
D(OP_AugmentItem)
D(OP_AltCurrencySellSelection)
D(OP_AltCurrencySell)
D(OP_WhoAllRequest)
#undef E
#undef D

View File

@ -133,22 +133,6 @@ static inline uint32 TitaniumToServerCorpseSlot(uint32 TitaniumCorpse) {
// reserved
}
*/
/*
static inline uint32 RemovePowerSourceBit(uint32 slots) { // shouldn't need to add one..just grab the actual server reference, if so...
static const uint32 BIT21 = 1 << 21;
static const uint32 BIT22 = 1 << 22;
static const uint32 KEEPBITS = ~(BIT21 | BIT22);
bool wearammo = slots & BIT22;
slots &= KEEPBITS;
if (wearammo)
slots |= BIT21;
return slots;
}
*/
EAT_ENCODE(OP_ZoneServerReady)

View File

@ -1,53 +1,52 @@
//list of packets we need to encode on the way out:
E(OP_SendCharInfo)
E(OP_SendAATable)
E(OP_LeadershipExpUpdate)
E(OP_PlayerProfile)
E(OP_NewSpawn)
E(OP_ZoneSpawns)
E(OP_ZoneEntry)
E(OP_CharInventory)
E(OP_ItemLinkResponse)
E(OP_ItemPacket)
// out-going packets that require an ENCODE translation:
E(OP_Action)
E(OP_BazaarSearch)
E(OP_GuildMemberList)
E(OP_ZoneServerReady)
E(OP_GuildMemberLevelUpdate)
E(OP_Trader)
E(OP_TraderBuy)
E(OP_ReadBook)
E(OP_Illusion)
E(OP_VetRewardsAvaliable)
E(OP_InspectRequest)
E(OP_InspectAnswer)
E(OP_Track)
E(OP_RespondAA)
E(OP_BecomeTrader)
E(OP_CharInventory)
E(OP_DeleteSpawn)
E(OP_WearChange)
E(OP_DzCompass)
E(OP_DzExpeditionEndsWarning)
E(OP_DzExpeditionInfo)
E(OP_DzCompass)
E(OP_DzMemberList)
E(OP_DzExpeditionList)
E(OP_DzLeaderStatus)
E(OP_DzJoinExpeditionConfirm)
E(OP_Action)
E(OP_BecomeTrader)
E(OP_PetBuffWindow)
E(OP_OnLevelMessage)
E(OP_DzLeaderStatus)
E(OP_DzMemberList)
E(OP_GuildMemberLevelUpdate)
E(OP_GuildMemberList)
E(OP_Illusion)
E(OP_InspectAnswer)
E(OP_InspectRequest)
E(OP_ItemLinkResponse)
E(OP_ItemPacket)
E(OP_LeadershipExpUpdate)
E(OP_LFGuild)
//list of packets we need to decode on the way in:
D(OP_SetServerFilter)
E(OP_OnLevelMessage)
E(OP_PetBuffWindow)
E(OP_PlayerProfile)
E(OP_NewSpawn)
E(OP_ReadBook)
E(OP_RespondAA)
E(OP_SendCharInfo)
E(OP_SendAATable)
E(OP_Track)
E(OP_Trader)
E(OP_TraderBuy)
E(OP_VetRewardsAvaliable)
E(OP_WearChange)
E(OP_ZoneEntry)
E(OP_ZoneServerReady)
E(OP_ZoneSpawns)
// incoming packets that require a DECODE translation:
D(OP_CharacterCreate)
D(OP_ItemLinkClick)
D(OP_TraderBuy)
D(OP_WhoAllRequest)
D(OP_ReadBook)
D(OP_FaceChange)
D(OP_InspectRequest)
D(OP_InspectAnswer)
D(OP_WearChange)
D(OP_InspectRequest)
D(OP_ItemLinkClick)
D(OP_LFGuild)
D(OP_ReadBook)
D(OP_SetServerFilter)
D(OP_TraderBuy)
D(OP_WearChange)
D(OP_WhoAllRequest)
#undef E
#undef D

View File

@ -1,128 +1,126 @@
//list of packets we need to encode on the way out:
E(OP_SendCharInfo)
E(OP_ZoneServerInfo)
E(OP_SendAATable)
E(OP_PlayerProfile)
E(OP_ZoneEntry)
E(OP_CharInventory)
E(OP_NewZone)
E(OP_SpawnDoor)
E(OP_GroundSpawn)
E(OP_SendZonepoints)
E(OP_NewSpawn)
E(OP_ZoneSpawns)
E(OP_ItemLinkResponse)
E(OP_ItemPacket)
E(OP_GuildMemberList)
E(OP_Illusion)
E(OP_ManaChange)
E(OP_ClientUpdate)
E(OP_LeadershipExpUpdate)
E(OP_ExpansionInfo)
E(OP_LogServer)
E(OP_Damage)
E(OP_Buff)
// out-going packets that require an ENCODE translation:
E(OP_Action)
E(OP_Consider)
E(OP_CancelTrade)
E(OP_ShopPlayerSell)
E(OP_DeleteItem)
E(OP_ItemVerifyReply)
E(OP_DeleteCharge)
E(OP_MoveItem)
E(OP_OpenNewTasksWindow)
E(OP_BazaarSearch)
E(OP_Trader)
E(OP_TraderBuy)
E(OP_LootItem)
E(OP_TributeItem)
E(OP_SomeItemPacketMaybe)
E(OP_ReadBook)
E(OP_Stun)
E(OP_ZonePlayerToBind)
E(OP_AdventureMerchantSell)
E(OP_RaidUpdate)
E(OP_RaidJoin)
E(OP_VetRewardsAvaliable)
E(OP_InspectRequest)
E(OP_GroupInvite)
E(OP_GroupFollow)
E(OP_GroupFollow2)
E(OP_GroupUpdate)
E(OP_GroupCancelInvite)
E(OP_WhoAllResponse)
E(OP_Track)
E(OP_ShopPlayerBuy)
E(OP_PetBuffWindow)
E(OP_OnLevelMessage)
E(OP_Barter)
E(OP_AltCurrency)
E(OP_AltCurrencySell)
E(OP_ApplyPoison)
E(OP_Barter)
E(OP_BazaarSearch)
E(OP_Buff)
E(OP_BuffCreate)
E(OP_CancelTrade)
E(OP_ChannelMessage)
E(OP_GuildsList)
E(OP_CharInventory)
E(OP_ClientUpdate)
E(OP_Consider)
E(OP_Damage)
E(OP_DeleteCharge)
E(OP_DeleteItem)
E(OP_DisciplineUpdate)
E(OP_DzCompass)
E(OP_DzExpeditionEndsWarning)
E(OP_DzExpeditionInfo)
E(OP_DzCompass)
E(OP_DzMemberList)
E(OP_DzExpeditionList)
E(OP_DzLeaderStatus)
E(OP_DzJoinExpeditionConfirm)
E(OP_TargetBuffs)
E(OP_BuffCreate)
E(OP_SpawnAppearance)
E(OP_RespondAA)
E(OP_DisciplineUpdate)
E(OP_AltCurrencySell)
E(OP_AltCurrency)
E(OP_WearChange)
E(OP_DzLeaderStatus)
E(OP_DzMemberList)
E(OP_ExpansionInfo)
E(OP_GroundSpawn)
E(OP_GroupCancelInvite)
E(OP_GroupFollow)
E(OP_GroupFollow2)
E(OP_GroupInvite)
E(OP_GroupUpdate)
E(OP_GuildMemberList)
E(OP_GuildsList)
E(OP_Illusion)
E(OP_InspectRequest)
E(OP_ItemLinkResponse)
E(OP_ItemPacket)
E(OP_ItemVerifyReply)
E(OP_LeadershipExpUpdate)
E(OP_LogServer)
E(OP_LootItem)
E(OP_ManaChange)
E(OP_MercenaryDataResponse)
E(OP_MercenaryDataUpdate)
//list of packets we need to decode on the way in:
D(OP_SetServerFilter)
D(OP_CharacterCreate)
D(OP_ItemLinkClick)
D(OP_ConsiderCorpse)
D(OP_Consider)
D(OP_ClientUpdate)
D(OP_MoveItem)
D(OP_WhoAllRequest)
E(OP_MoveItem)
E(OP_NewSpawn)
E(OP_NewZone)
E(OP_OnLevelMessage)
E(OP_OpenNewTasksWindow)
E(OP_PetBuffWindow)
E(OP_PlayerProfile)
E(OP_RaidJoin)
E(OP_RaidUpdate)
E(OP_ReadBook)
E(OP_RespondAA)
E(OP_SendAATable)
E(OP_SendCharInfo)
E(OP_SendZonepoints)
E(OP_ShopPlayerBuy)
E(OP_ShopPlayerSell)
E(OP_SomeItemPacketMaybe)
E(OP_SpawnAppearance)
E(OP_SpawnDoor)
E(OP_Stun)
E(OP_TargetBuffs)
E(OP_Track)
E(OP_Trader)
E(OP_TraderBuy)
E(OP_TributeItem)
E(OP_VetRewardsAvaliable)
E(OP_WearChange)
E(OP_WhoAllResponse)
E(OP_ZoneEntry)
E(OP_ZonePlayerToBind)
E(OP_ZoneServerInfo)
E(OP_ZoneSpawns)
// incoming packets that require a DECODE translation:
D(OP_AdventureMerchantSell)
D(OP_AltCurrencySell)
D(OP_AltCurrencySellSelection)
D(OP_ApplyPoison)
D(OP_AugmentInfo)
D(OP_AugmentItem)
D(OP_BazaarSearch)
D(OP_Buff)
D(OP_ShopPlayerSell)
D(OP_Consume)
D(OP_BuffRemoveRequest)
D(OP_CastSpell)
D(OP_Save)
D(OP_ItemVerifyRequest)
D(OP_GroupInvite)
D(OP_GroupInvite2)
D(OP_ChannelMessage)
D(OP_CharacterCreate)
D(OP_ClientUpdate)
D(OP_Consider)
D(OP_ConsiderCorpse)
D(OP_Consume)
D(OP_Damage)
D(OP_DeleteItem)
D(OP_EnvDamage)
D(OP_FaceChange)
D(OP_FindPersonRequest)
D(OP_GroupCancelInvite)
D(OP_GroupDisband)
D(OP_GroupFollow)
D(OP_GroupFollow2)
D(OP_GroupDisband)
D(OP_GroupCancelInvite)
D(OP_FindPersonRequest)
D(OP_TraderBuy)
D(OP_LootItem)
D(OP_TributeItem)
D(OP_ReadBook)
D(OP_AugmentInfo)
D(OP_FaceChange)
D(OP_AdventureMerchantSell)
D(OP_TradeSkillCombine)
D(OP_RaidInvite)
D(OP_GroupInvite)
D(OP_GroupInvite2)
D(OP_InspectRequest)
D(OP_WearChange)
D(OP_ShopPlayerBuy)
D(OP_BazaarSearch)
D(OP_ItemLinkClick)
D(OP_ItemVerifyRequest)
D(OP_LoadSpellSet)
D(OP_ApplyPoison)
D(OP_Damage)
D(OP_EnvDamage)
D(OP_ChannelMessage)
D(OP_DeleteItem)
D(OP_AugmentItem)
D(OP_LootItem)
D(OP_MoveItem)
D(OP_PetCommands)
D(OP_BuffRemoveRequest)
D(OP_AltCurrencySellSelection)
D(OP_AltCurrencySell)
D(OP_RaidInvite)
D(OP_ReadBook)
D(OP_Save)
D(OP_SetServerFilter)
D(OP_ShopPlayerBuy)
D(OP_ShopPlayerSell)
D(OP_TraderBuy)
D(OP_TradeSkillCombine)
D(OP_TributeItem)
D(OP_WearChange)
D(OP_WhoAllRequest)
#undef E
#undef D

View File

@ -18,7 +18,7 @@
#include "types.h"
#include "skills.h"
bool EQEmu::IsTradeskill(uint32 skill)
bool EQEmu::IsTradeskill(SkillUseTypes skill)
{
switch (skill) {
case SkillFishing:
@ -38,3 +38,19 @@ bool EQEmu::IsTradeskill(uint32 skill)
return false;
}
}
bool EQEmu::IsSpecializedSkill(SkillUseTypes skill)
{
// this could be a simple if, but if this is more portable if any IDs change (probably won't)
// or any other specialized are added (also unlikely)
switch (skill) {
case SkillSpecializeAbjure:
case SkillSpecializeAlteration:
case SkillSpecializeConjuration:
case SkillSpecializeDivination:
case SkillSpecializeEvocation:
return true;
default:
return false;
}
}

View File

@ -262,7 +262,8 @@ typedef enum {
// for skill related helper functions
namespace EQEmu {
bool IsTradeskill(uint32 skill);
bool IsTradeskill(SkillUseTypes skill);
bool IsSpecializedSkill(SkillUseTypes skill);
}
#endif

View File

@ -15,6 +15,7 @@ SET(tests_headers
ipc_mutex_test.h
memory_mapped_file_test.h
string_util_test.h
skills_util_test.h
)
ADD_EXECUTABLE(tests ${tests_sources} ${tests_headers})

View File

@ -28,6 +28,7 @@
#include "hextoi_32_64_test.h"
#include "string_util_test.h"
#include "data_verification_test.h"
#include "skills_util_test.h"
int main() {
try {
@ -42,6 +43,7 @@ int main() {
tests.add(new hextoi_32_64_Test());
tests.add(new StringUtilTest());
tests.add(new DataVerificationTest());
tests.add(new SkillsUtilsTest());
tests.run(*output, true);
} catch(...) {
return -1;

48
tests/skills_util_test.h Normal file
View File

@ -0,0 +1,48 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __EQEMU_TESTS_SKILLS_UTILS_H
#define __EQEMU_TESTS_SKILLS_UTILS_H
#include "cppunit/cpptest.h"
#include "../common/skills.h"
class SkillsUtilsTest: public Test::Suite {
typedef void(SkillsUtilsTest::*TestFunction)(void);
public:
SkillsUtilsTest() {
TEST_ADD(SkillsUtilsTest::IsTradeskill);
TEST_ADD(SkillsUtilsTest::IsSpecializedSkill);
}
~SkillsUtilsTest() {
}
private:
void IsTradeskill() {
TEST_ASSERT(EQEmu::IsTradeskill(SkillPottery));
TEST_ASSERT(!EQEmu::IsTradeskill(SkillParry));
}
void IsSpecializedSkill() {
TEST_ASSERT(EQEmu::IsSpecializedSkill(SkillSpecializeConjuration));
TEST_ASSERT(!EQEmu::IsSpecializedSkill(SkillConjuration))
}
};
#endif

View File

@ -1794,10 +1794,10 @@ void Client::SetClassStartingSkills(PlayerProfile_Struct *pp)
{
for (uint32 i = 0; i <= HIGHEST_SKILL; ++i) {
if (pp->skills[i] == 0) {
if (i >= SkillSpecializeAbjure && i <= SkillSpecializeEvocation)
continue;
if (EQEmu::IsTradeskill(i) || i == SkillBegging)
// Skip specialized, tradeskills (fishing excluded), Alcohol Tolerance, and Bind Wound
if (EQEmu::IsSpecializedSkill((SkillUseTypes)i) ||
(EQEmu::IsTradeskill((SkillUseTypes)i) && i != SkillFishing) ||
i == SkillAlcoholTolerance || i == SkillBindWound)
continue;
pp->skills[i] = database.GetSkillCap(pp->class_, (SkillUseTypes)i, 1);

View File

@ -490,22 +490,36 @@ void EntityList::MobProcess()
#endif
auto it = mob_list.begin();
while (it != mob_list.end()) {
if (!it->second) {
uint16 id = it->first;
Mob *mob = it->second;
size_t sz = mob_list.size();
bool p_val = mob->Process();
size_t a_sz = mob_list.size();
if(a_sz > sz) {
//increased size can potentially screw with iterators so reset it to current value
//if buckets are re-orderered we may skip a process here and there but since
//process happens so often it shouldn't matter much
it = mob_list.find(id);
++it;
} else {
++it;
continue;
}
if (!it->second->Process()) {
Mob *mob = it->second;
uint16 tempid = it->first;
if (mob->IsNPC()) {
entity_list.RemoveNPC(mob->CastToNPC()->GetID());
} else if (mob->IsMerc()) {
entity_list.RemoveMerc(mob->CastToMerc()->GetID());
if(!p_val) {
if(mob->IsNPC()) {
entity_list.RemoveNPC(id);
}
else if(mob->IsMerc()) {
entity_list.RemoveMerc(id);
#ifdef BOTS
} else if (mob->IsBot()) {
entity_list.RemoveBot(mob->CastToBot()->GetID());
}
else if(mob->IsBot()) {
entity_list.RemoveBot(id);
#endif
} else {
}
else {
#ifdef _WINDOWS
struct in_addr in;
in.s_addr = mob->CastToClient()->GetIP();
@ -513,25 +527,19 @@ void EntityList::MobProcess()
#endif
zone->StartShutdownTimer();
Group *g = GetGroupByMob(mob);
if (g) {
if(g) {
LogFile->write(EQEMuLog::Error, "About to delete a client still in a group.");
g->DelMember(mob);
}
Raid *r = entity_list.GetRaidByClient(mob->CastToClient());
if (r) {
if(r) {
LogFile->write(EQEMuLog::Error, "About to delete a client still in a raid.");
r->MemberZoned(mob->CastToClient());
}
entity_list.RemoveClient(mob->GetID());
entity_list.RemoveClient(id);
}
if(entity_list.RemoveMob(tempid)) {
it = mob_list.begin();
} else {
++it;
}
} else {
++it;
entity_list.RemoveMob(id);
}
}
}

View File

@ -195,7 +195,7 @@ void Group::SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinu
if (members[i] != nullptr && members[i]->IsClient()) { // If Group Member is Client
Client *c = members[i]->CastToClient();
//I could not get MoneyOnCorpse to work, so we use this
c->AddMoneyToPP(cpsplit, spsplit, gpsplit, ppsplit, true);
c->AddMoneyToPP(cpsplit, spsplit, gpsplit, ppsplit, true);
c->Message(2, msg.c_str());
}
}
@ -969,31 +969,28 @@ void Group::TeleportGroup(Mob* sender, uint32 zoneID, uint16 instance_id, float
}
bool Group::LearnMembers() {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (database.RunQuery(query,MakeAnyLenString(&query, "SELECT name FROM group_id WHERE groupid=%lu", (unsigned long)GetID()),
errbuf,&result)){
safe_delete_array(query);
if(mysql_num_rows(result) < 1) { //could prolly be 2
mysql_free_result(result);
LogFile->write(EQEMuLog::Error, "Error getting group members for group %lu: %s", (unsigned long)GetID(), errbuf);
return(false);
}
int i = 0;
while((row = mysql_fetch_row(result))) {
if(!row[0])
continue;
members[i] = nullptr;
strn0cpy(membername[i], row[0], 64);
std::string query = StringFormat("SELECT name FROM group_id WHERE groupid = %lu", (unsigned long)GetID());
auto results = database.QueryDatabase(query);
if (!results.Success())
return false;
i++;
}
mysql_free_result(result);
if (results.RowCount() == 0) {
LogFile->write(EQEMuLog::Error, "Error getting group members for group %lu: %s", (unsigned long)GetID(), results.ErrorMessage().c_str());
return false;
}
int memberIndex = 0;
for(auto row = results.begin(); row != results.end(); ++row) {
if(!row[0])
continue;
members[memberIndex] = nullptr;
strn0cpy(membername[memberIndex], row[0], 64);
memberIndex++;
}
return(true);
return true;
}
void Group::VerifyGroup() {
@ -1077,7 +1074,7 @@ void Group::HealGroup(uint32 heal_amt, Mob* caster, int32 range)
if (!range)
range = 200;
float distance;
float range2 = range*range;
@ -1114,10 +1111,10 @@ void Group::BalanceHP(int32 penalty, int32 range, Mob* caster, int32 limit)
return;
if (!range)
range = 200;
range = 200;
int dmgtaken = 0, numMem = 0, dmgtaken_tmp = 0;
float distance;
float range2 = range*range;
@ -1164,16 +1161,16 @@ void Group::BalanceMana(int32 penalty, int32 range, Mob* caster, int32 limit)
return;
if (!range)
range = 200;
range = 200;
float distance;
float range2 = range*range;
int manataken = 0, numMem = 0, manataken_tmp = 0;
unsigned int gi = 0;
for(; gi < MAX_GROUP_MEMBERS; gi++)
{
if(members[gi] && (members[gi]->GetMaxMana() > 0)){
if(members[gi] && (members[gi]->GetMaxMana() > 0)){
distance = caster->DistNoRoot(*members[gi]);
if(distance <= range2){
@ -1341,15 +1338,12 @@ void Group::DelegateMainTank(const char *NewMainTankName, uint8 toggle)
}
if(updateDB) {
char errbuff[MYSQL_ERRMSG_SIZE];
char *Query = nullptr;
if (!database.RunQuery(Query, MakeAnyLenString(&Query, "UPDATE group_leaders SET maintank='%s' WHERE gid=%i LIMIT 1",
MainTankName.c_str(), GetID()), errbuff))
LogFile->write(EQEMuLog::Error, "Unable to set group main tank: %s\n", errbuff);
safe_delete_array(Query);
std::string query = StringFormat("UPDATE group_leaders SET maintank = '%s' WHERE gid = %i LIMIT 1",
MainTankName.c_str(), GetID());
auto results = database.QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Unable to set group main tank: %s\n", results.ErrorMessage().c_str());
}
}
@ -1390,15 +1384,13 @@ void Group::DelegateMainAssist(const char *NewMainAssistName, uint8 toggle)
}
if(updateDB) {
char errbuff[MYSQL_ERRMSG_SIZE];
char *Query = nullptr;
std::string query = StringFormat("UPDATE group_leaders SET assist = '%s' WHERE gid = %i LIMIT 1",
MainAssistName.c_str(), GetID());
auto results = database.QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Unable to set group main assist: %s\n", results.ErrorMessage().c_str());
if (!database.RunQuery(Query, MakeAnyLenString(&Query, "UPDATE group_leaders SET assist='%s' WHERE gid=%i LIMIT 1",
MainAssistName.c_str(), GetID()), errbuff))
LogFile->write(EQEMuLog::Error, "Unable to set group main assist: %s\n", errbuff);
safe_delete_array(Query);
}
}
@ -1439,15 +1431,13 @@ void Group::DelegatePuller(const char *NewPullerName, uint8 toggle)
}
if(updateDB) {
char errbuff[MYSQL_ERRMSG_SIZE];
char *Query = nullptr;
std::string query = StringFormat("UPDATE group_leaders SET puller = '%s' WHERE gid = %i LIMIT 1",
PullerName.c_str(), GetID());
auto results = database.QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Unable to set group main puller: %s\n", results.ErrorMessage().c_str());
if (!database.RunQuery(Query, MakeAnyLenString(&Query, "UPDATE group_leaders SET puller='%s' WHERE gid=%i LIMIT 1",
PullerName.c_str(), GetID()), errbuff))
LogFile->write(EQEMuLog::Error, "Unable to set group main puller: %s\n", errbuff);
safe_delete_array(Query);
}
}
@ -1593,15 +1583,11 @@ void Group::UnDelegateMainTank(const char *OldMainTankName, uint8 toggle)
// informing them of the change and update the group_leaders table.
//
if(OldMainTankName == MainTankName) {
char errbuff[MYSQL_ERRMSG_SIZE];
char *Query = 0;
if (!database.RunQuery(Query, MakeAnyLenString(&Query, "UPDATE group_leaders SET maintank='' WHERE gid=%i LIMIT 1",
GetID()), errbuff))
LogFile->write(EQEMuLog::Error, "Unable to clear group main tank: %s\n", errbuff);
safe_delete_array(Query);
std::string query = StringFormat("UPDATE group_leaders SET maintank = '' WHERE gid = %i LIMIT 1", GetID());
auto results = database.QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Unable to clear group main tank: %s\n", results.ErrorMessage().c_str());
if(!toggle) {
for(uint32 i = 0; i < MAX_GROUP_MEMBERS; ++i) {
@ -1647,15 +1633,10 @@ void Group::UnDelegateMainAssist(const char *OldMainAssistName, uint8 toggle)
safe_delete(outapp);
char errbuff[MYSQL_ERRMSG_SIZE];
char *Query = 0;
if (!database.RunQuery(Query, MakeAnyLenString(&Query, "UPDATE group_leaders SET assist='' WHERE gid=%i LIMIT 1",
GetID()), errbuff))
LogFile->write(EQEMuLog::Error, "Unable to clear group main assist: %s\n", errbuff);
safe_delete_array(Query);
std::string query = StringFormat("UPDATE group_leaders SET assist = '' WHERE gid = %i LIMIT 1", GetID());
auto results = database.QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Unable to clear group main assist: %s\n", results.ErrorMessage().c_str());
if(!toggle)
{
@ -1679,15 +1660,11 @@ void Group::UnDelegatePuller(const char *OldPullerName, uint8 toggle)
// informing them of the change and update the group_leaders table.
//
if(OldPullerName == PullerName) {
char errbuff[MYSQL_ERRMSG_SIZE];
char *Query = 0;
if (!database.RunQuery(Query, MakeAnyLenString(&Query, "UPDATE group_leaders SET puller='' WHERE gid=%i LIMIT 1",
GetID()), errbuff))
LogFile->write(EQEMuLog::Error, "Unable to clear group main puller: %s\n", errbuff);
safe_delete_array(Query);
std::string query = StringFormat("UPDATE group_leaders SET puller = '' WHERE gid = %i LIMIT 1", GetID());
auto results = database.QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Unable to clear group main puller: %s\n", results.ErrorMessage().c_str());
if(!toggle) {
for(uint32 i = 0; i < MAX_GROUP_MEMBERS; ++i) {
@ -1822,16 +1799,11 @@ void Group::DelegateMarkNPC(const char *NewNPCMarkerName)
if(members[i] && members[i]->IsClient())
NotifyMarkNPC(members[i]->CastToClient());
char errbuff[MYSQL_ERRMSG_SIZE];
char *Query = 0;
if (!database.RunQuery(Query, MakeAnyLenString(&Query, "UPDATE group_leaders SET marknpc='%s' WHERE gid=%i LIMIT 1",
NewNPCMarkerName, GetID()), errbuff))
LogFile->write(EQEMuLog::Error, "Unable to set group mark npc: %s\n", errbuff);
safe_delete_array(Query);
std::string query = StringFormat("UPDATE group_leaders SET marknpc = '%s' WHERE gid = %i LIMIT 1",
NewNPCMarkerName, GetID());
auto results = database.QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Unable to set group mark npc: %s\n", results.ErrorMessage().c_str());
}
void Group::NotifyMarkNPC(Client *c)
@ -1908,15 +1880,12 @@ void Group::UnDelegateMarkNPC(const char *OldNPCMarkerName)
NPCMarkerName.clear();
char errbuff[MYSQL_ERRMSG_SIZE];
char *Query = 0;
std::string query = StringFormat("UPDATE group_leaders SET marknpc = '' WHERE gid = %i LIMIT 1", GetID());
auto results = database.QueryDatabase(query);
if (!results.Success())
LogFile->write(EQEMuLog::Error, "Unable to clear group marknpc: %s\n", results.ErrorMessage().c_str());
if (!database.RunQuery(Query, MakeAnyLenString(&Query, "UPDATE group_leaders SET marknpc='' WHERE gid=%i LIMIT 1",
GetID()), errbuff))
LogFile->write(EQEMuLog::Error, "Unable to clear group marknpc: %s\n", errbuff);
safe_delete_array(Query);
}
void Group::SaveGroupLeaderAA()

View File

@ -172,7 +172,7 @@ void QuestManager::EndQuest() {
cur = QTimerList.erase(cur);
else
++cur;
}
}
run.owner->Depop();
}
quests_running_.pop();
@ -447,7 +447,7 @@ void QuestManager::settimer(const char *timer_name, int seconds) {
end = QTimerList.end();
while (cur != end) {
if(cur->mob && cur->mob == owner && cur->name == timer_name)
if(cur->mob && cur->mob == owner && cur->name == timer_name)
{
cur->Timer_.Enable();
cur->Timer_.Start(seconds * 1000, false);
@ -471,7 +471,7 @@ void QuestManager::settimerMS(const char *timer_name, int milliseconds) {
end = QTimerList.end();
while (cur != end) {
if(cur->mob && cur->mob == owner && cur->name == timer_name)
if(cur->mob && cur->mob == owner && cur->name == timer_name)
{
cur->Timer_.Enable();
cur->Timer_.Start(milliseconds, false);
@ -1310,7 +1310,7 @@ void QuestManager::setglobal(const char *varname, const char *newvalue, int opti
if (initiator && initiator->IsClient()){ // some events like waypoint and spawn don't have a player involved
qgCharid=initiator->CharacterID();
}
}
else {
qgCharid=-qgNpcid; // make char id negative npc id as a fudge
}
@ -1337,81 +1337,69 @@ void QuestManager::setglobal(const char *varname, const char *newvalue, int opti
/* Inserts global variable into quest_globals table */
int QuestManager::InsertQuestGlobal(int charid, int npcid, int zoneid, const char *varname, const char *varvalue, int duration) {
char *query = 0;
char errbuf[MYSQL_ERRMSG_SIZE];
// Make duration string either "unix_timestamp(now()) + xxx" or "NULL"
std::stringstream duration_ss;
if (duration == INT_MAX) {
duration_ss << "NULL";
}
else {
duration_ss << "unix_timestamp(now()) + " << duration;
}
std::string durationText = (duration == INT_MAX)? "NULL": StringFormat("unix_timestamp(now()) + %i", duration);
/*
NOTE: this should be escaping the contents of arglist
npcwise a malicious script can arbitrarily alter the DB
*/
uint32 last_id = 0;
if (!database.RunQuery(query, MakeAnyLenString(&query,
"REPLACE INTO quest_globals (charid, npcid, zoneid, name, value, expdate)"
"VALUES (%i, %i, %i, '%s', '%s', %s)",
charid, npcid, zoneid, varname, varvalue, duration_ss.str().c_str()
), errbuf, nullptr, nullptr, &last_id))
{
std::cerr << "setglobal error inserting " << varname << " : " << errbuf << std::endl;
}
safe_delete_array(query);
if(zone) {
/* Delete existing qglobal data and update zone processes */
ServerPacket* pack = new ServerPacket(ServerOP_QGlobalDelete, sizeof(ServerQGlobalDelete_Struct));
ServerQGlobalDelete_Struct *qgd = (ServerQGlobalDelete_Struct*)pack->pBuffer;
qgd->npc_id = npcid;
qgd->char_id = charid;
qgd->zone_id = zoneid;
qgd->from_zone_id = zone->GetZoneID();
qgd->from_instance_id = zone->GetInstanceID();
strcpy(qgd->name, varname);
std::string query = StringFormat("REPLACE INTO quest_globals "
"(charid, npcid, zoneid, name, value, expdate)"
"VALUES (%i, %i, %i, '%s', '%s', %s)",
charid, npcid, zoneid, varname, varvalue, durationText.c_str());
auto results = database.QueryDatabase(query);
if (!results.Success())
std::cerr << "setglobal error inserting " << varname << " : " << results.ErrorMessage() << std::endl;
entity_list.DeleteQGlobal(std::string((char*)qgd->name), qgd->npc_id, qgd->char_id, qgd->zone_id);
zone->DeleteQGlobal(std::string((char*)qgd->name), qgd->npc_id, qgd->char_id, qgd->zone_id);
if(!zone)
return 0;
worldserver.SendPacket(pack);
safe_delete(pack);
/* Delete existing qglobal data and update zone processes */
ServerPacket* pack = new ServerPacket(ServerOP_QGlobalDelete, sizeof(ServerQGlobalDelete_Struct));
ServerQGlobalDelete_Struct *qgd = (ServerQGlobalDelete_Struct*)pack->pBuffer;
qgd->npc_id = npcid;
qgd->char_id = charid;
qgd->zone_id = zoneid;
qgd->from_zone_id = zone->GetZoneID();
qgd->from_instance_id = zone->GetInstanceID();
strcpy(qgd->name, varname);
/* Create new qglobal data and update zone processes */
pack = new ServerPacket(ServerOP_QGlobalUpdate, sizeof(ServerQGlobalUpdate_Struct));
ServerQGlobalUpdate_Struct *qgu = (ServerQGlobalUpdate_Struct*)pack->pBuffer;
qgu->npc_id = npcid;
qgu->char_id = charid;
qgu->zone_id = zoneid;
if(duration == INT_MAX) {
qgu->expdate = 0xFFFFFFFF;
}
else {
qgu->expdate = Timer::GetTimeSeconds() + duration;
}
strcpy((char*)qgu->name, varname);
strn0cpy((char*)qgu->value, varvalue, 128);
qgu->id = last_id;
qgu->from_zone_id = zone->GetZoneID();
qgu->from_instance_id = zone->GetInstanceID();
entity_list.DeleteQGlobal(std::string((char*)qgd->name), qgd->npc_id, qgd->char_id, qgd->zone_id);
zone->DeleteQGlobal(std::string((char*)qgd->name), qgd->npc_id, qgd->char_id, qgd->zone_id);
QGlobal temp;
temp.npc_id = npcid;
temp.char_id = charid;
temp.zone_id = zoneid;
temp.expdate = qgu->expdate;
temp.name.assign(qgu->name);
temp.value.assign(qgu->value);
entity_list.UpdateQGlobal(qgu->id, temp);
zone->UpdateQGlobal(qgu->id, temp);
worldserver.SendPacket(pack);
safe_delete(pack);
worldserver.SendPacket(pack);
safe_delete(pack);
}
/* Create new qglobal data and update zone processes */
pack = new ServerPacket(ServerOP_QGlobalUpdate, sizeof(ServerQGlobalUpdate_Struct));
ServerQGlobalUpdate_Struct *qgu = (ServerQGlobalUpdate_Struct*)pack->pBuffer;
qgu->npc_id = npcid;
qgu->char_id = charid;
qgu->zone_id = zoneid;
qgu->expdate = (duration == INT_MAX)? 0xFFFFFFFF: Timer::GetTimeSeconds() + duration;
strcpy((char*)qgu->name, varname);
strn0cpy((char*)qgu->value, varvalue, 128);
qgu->id = results.LastInsertedID();
qgu->from_zone_id = zone->GetZoneID();
qgu->from_instance_id = zone->GetInstanceID();
QGlobal temp;
temp.npc_id = npcid;
temp.char_id = charid;
temp.zone_id = zoneid;
temp.expdate = qgu->expdate;
temp.name.assign(qgu->name);
temp.value.assign(qgu->value);
entity_list.UpdateQGlobal(qgu->id, temp);
zone->UpdateQGlobal(qgu->id, temp);
worldserver.SendPacket(pack);
safe_delete(pack);
return 0;
}
@ -1422,22 +1410,14 @@ void QuestManager::targlobal(const char *varname, const char *value, const char
void QuestManager::delglobal(const char *varname) {
QuestManagerCurrentQuestVars();
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
int qgZoneid=zone->GetZoneID();
int qgCharid=0;
int qgNpcid=owner->GetNPCTypeID();
if (initiator && initiator->IsClient()) // some events like waypoint and spawn don't have a player involved
{
qgCharid=initiator->CharacterID();
}
else {
if (initiator && initiator->IsClient()) // some events like waypoint and spawn don't have a player involved
qgCharid=initiator->CharacterID();
else
qgCharid=-qgNpcid; // make char id negative npc id as a fudge
}
/* QS: PlayerLogQGlobalUpdate */
if (RuleB(QueryServ, PlayerLogQGlobalUpdate) && qgCharid && qgCharid > 0 && initiator && initiator->IsClient()){
@ -1445,31 +1425,32 @@ void QuestManager::delglobal(const char *varname) {
QServ->PlayerLogEvent(Player_Log_QGlobal_Update, qgCharid, event_desc);
}
if (!database.RunQuery(query,
MakeAnyLenString(&query,
"DELETE FROM quest_globals WHERE name='%s'"
" && (npcid=0 || npcid=%i) && (charid=0 || charid=%i) && (zoneid=%i || zoneid=0)",
varname,qgNpcid,qgCharid,qgZoneid),errbuf))
{
std::cerr << "delglobal error deleting " << varname << " : " << errbuf << std::endl;
}
safe_delete_array(query);
std::string query = StringFormat("DELETE FROM quest_globals "
"WHERE name = '%s' "
"&& (npcid=0 || npcid=%i) "
"&& (charid=0 || charid=%i) "
"&& (zoneid=%i || zoneid=0)",
varname, qgNpcid, qgCharid, qgZoneid);
auto results = database.QueryDatabase(query);
if (!results.Success())
std::cerr << "delglobal error deleting " << varname << " : " << results.ErrorMessage() << std::endl;
if(zone) {
ServerPacket* pack = new ServerPacket(ServerOP_QGlobalDelete, sizeof(ServerQGlobalDelete_Struct));
ServerQGlobalDelete_Struct *qgu = (ServerQGlobalDelete_Struct*)pack->pBuffer;
if(!zone)
return;
qgu->npc_id = qgNpcid;
qgu->char_id = qgCharid;
qgu->zone_id = qgZoneid;
strcpy(qgu->name, varname);
ServerPacket* pack = new ServerPacket(ServerOP_QGlobalDelete, sizeof(ServerQGlobalDelete_Struct));
ServerQGlobalDelete_Struct *qgu = (ServerQGlobalDelete_Struct*)pack->pBuffer;
entity_list.DeleteQGlobal(std::string((char*)qgu->name), qgu->npc_id, qgu->char_id, qgu->zone_id);
zone->DeleteQGlobal(std::string((char*)qgu->name), qgu->npc_id, qgu->char_id, qgu->zone_id);
qgu->npc_id = qgNpcid;
qgu->char_id = qgCharid;
qgu->zone_id = qgZoneid;
strcpy(qgu->name, varname);
worldserver.SendPacket(pack);
safe_delete(pack);
}
entity_list.DeleteQGlobal(std::string((char*)qgu->name), qgu->npc_id, qgu->char_id, qgu->zone_id);
zone->DeleteQGlobal(std::string((char*)qgu->name), qgu->npc_id, qgu->char_id, qgu->zone_id);
worldserver.SendPacket(pack);
safe_delete(pack);
}
// Converts duration string to duration value (in seconds)
@ -1690,11 +1671,6 @@ void QuestManager::showgrid(int grid) {
if(initiator == nullptr)
return;
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
FindPerson_Point pt;
std::vector<FindPerson_Point> pts;
@ -1704,22 +1680,25 @@ void QuestManager::showgrid(int grid) {
pts.push_back(pt);
// Retrieve all waypoints for this grid
if(database.RunQuery(query,MakeAnyLenString(&query,"SELECT `x`,`y`,`z` FROM grid_entries WHERE `gridid`=%i AND `zoneid`=%i ORDER BY `number`",grid,zone->GetZoneID()),errbuf,&result)) {
while((row = mysql_fetch_row(result))) {
pt.x = atof(row[0]);
pt.y = atof(row[1]);
pt.z = atof(row[2]);
pts.push_back(pt);
}
mysql_free_result(result);
initiator->SendPathPacket(pts);
}
else // DB query error!
{
LogFile->write(EQEMuLog::Quest, "Error loading grid %d for showgrid(): %s", grid, errbuf);
std::string query = StringFormat("SELECT `x`,`y`,`z` FROM grid_entries "
"WHERE `gridid` = %i AND `zoneid` = %i "
"ORDER BY `number`", grid, zone->GetZoneID());
auto results = database.QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Quest, "Error loading grid %d for showgrid(): %s", grid, results.ErrorMessage().c_str());
return;
}
safe_delete_array(query);
}
for(auto row = results.begin(); row != results.end(); ++row) {
pt.x = atof(row[0]);
pt.y = atof(row[1]);
pt.z = atof(row[2]);
pts.push_back(pt);
}
initiator->SendPathPacket(pts);
}
//change the value of a spawn condition
@ -2295,19 +2274,19 @@ bool QuestManager::istaskappropriate(int task) {
}
void QuestManager::clearspawntimers() {
if(zone) {
//TODO: Dec 19, 2008, replace with code updated for current spawn timers.
LinkedListIterator<Spawn2*> iterator(zone->spawn2_list);
iterator.Reset();
while (iterator.MoreElements())
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
database.RunQuery(query, MakeAnyLenString(&query, "DELETE FROM respawn_times WHERE id=%lu AND "
"instance_id=%lu",(unsigned long)iterator.GetData()->GetID(), (unsigned long)zone->GetInstanceID()), errbuf);
safe_delete_array(query);
iterator.Advance();
}
if(!zone)
return;
//TODO: Dec 19, 2008, replace with code updated for current spawn timers.
LinkedListIterator<Spawn2*> iterator(zone->spawn2_list);
iterator.Reset();
while (iterator.MoreElements()) {
std::string query = StringFormat("DELETE FROM respawn_times "
"WHERE id = %lu AND instance_id = %lu",
(unsigned long)iterator.GetData()->GetID(),
(unsigned long)zone->GetInstanceID());
auto results = database.QueryDatabase(query);
iterator.Advance();
}
}
@ -2684,11 +2663,6 @@ void QuestManager::FlagInstanceByRaidLeader(uint32 zone, int16 version)
const char* QuestManager::saylink(char* Phrase, bool silent, const char* LinkName) {
QuestManagerCurrentQuestVars();
const char *ERR_MYSQLERROR = "Error in saylink phrase queries";
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
int sayid = 0;
int sz = strlen(Phrase);
@ -2696,42 +2670,26 @@ const char* QuestManager::saylink(char* Phrase, bool silent, const char* LinkNam
database.DoEscapeString(escaped_string, Phrase, sz);
// Query for an existing phrase and id in the saylink table
if(database.RunQuery(query,MakeAnyLenString(&query,"SELECT `id` FROM `saylink` WHERE `phrase` = '%s'", escaped_string),errbuf,&result))
std::string query = StringFormat("SELECT `id` FROM `saylink` WHERE `phrase` = '%s'", escaped_string);
auto results = database.QueryDatabase(query);
if(results.Success())
{
if (mysql_num_rows(result) >= 1)
{
while((row = mysql_fetch_row(result)))
{
if (results.RowCount() >= 1)
for (auto row = results.begin();row != results.end(); ++row)
sayid = atoi(row[0]);
}
mysql_free_result(result);
}
else // Add a new saylink entry to the database and query it again for the new sayid number
{
safe_delete_array(query);
query = StringFormat("INSERT INTO `saylink` (`phrase`) VALUES ('%s')", escaped_string);
results = database.QueryDatabase(query);
database.RunQuery(query,MakeAnyLenString(&query,"INSERT INTO `saylink` (`phrase`) VALUES ('%s')", escaped_string),errbuf);
safe_delete_array(query);
if(database.RunQuery(query,MakeAnyLenString(&query,"SELECT `id` FROM saylink WHERE `phrase` = '%s'", escaped_string),errbuf,&result))
{
if (mysql_num_rows(result) >= 1)
{
while((row = mysql_fetch_row(result)))
{
if(!results.Success())
LogFile->write(EQEMuLog::Error, "Error in saylink phrase queries", results.ErrorMessage().c_str());
else if (results.RowCount() >= 1)
for(auto row = results.begin(); row != results.end(); ++row)
sayid = atoi(row[0]);
}
mysql_free_result(result);
}
}
else
{
LogFile->write(EQEMuLog::Error, ERR_MYSQLERROR, errbuf);
}
safe_delete_array(query);
}
}
safe_delete_array(query);
safe_delete_array(escaped_string);
if(silent)
@ -2739,27 +2697,21 @@ const char* QuestManager::saylink(char* Phrase, bool silent, const char* LinkNam
else
sayid = sayid + 500000;
//Create the say link as an item link hash
char linktext[250];
//Create the say link as an item link hash
char linktext[250];
if(initiator)
{
if (initiator->GetClientVersion() >= EQClientRoF)
{
sprintf(linktext,"%c%06X%s%s%c",0x12,sayid,"0000000000000000000000000000000000000000000000000",LinkName,0x12);
}
else if (initiator->GetClientVersion() >= EQClientSoF)
{
sprintf(linktext,"%c%06X%s%s%c",0x12,sayid,"00000000000000000000000000000000000000000000",LinkName,0x12);
}
else
{
sprintf(linktext,"%c%06X%s%s%c",0x12,sayid,"000000000000000000000000000000000000000",LinkName,0x12);
}
}
else { // If no initiator, create an RoF saylink, since older clients handle RoF ones better than RoF handles older ones.
else // If no initiator, create an RoF saylink, since older clients handle RoF ones better than RoF handles older ones.
sprintf(linktext,"%c%06X%s%s%c",0x12,sayid,"0000000000000000000000000000000000000000000000000",LinkName,0x12);
}
strcpy(Phrase,linktext);
return Phrase;

View File

@ -133,7 +133,7 @@ void Trade::AddEntity(uint16 trade_slot_id, uint32 stack_size) {
client->Kick();
return;
}
SendItemData(inst, trade_slot_id);
_log(TRADING__HOLDER, "%s added item '%s' to trade slot %i", owner->GetName(), inst->GetItem()->Name, trade_slot_id);
@ -451,13 +451,13 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
mlog(TRADING__CLIENT, "Finishing trade with client %s", other->GetName());
this->AddMoneyToPP(other->trade->cp, other->trade->sp, other->trade->gp, other->trade->pp, true);
// step 0: pre-processing
// QS code
if (RuleB(QueryServ, PlayerLogTrades) && event_entry && event_details) {
qs_audit = (QSPlayerLogTrade_Struct*)event_entry;
qs_log = true;
if (finalizer) {
qs_audit->char2_id = this->character_id;
@ -506,7 +506,7 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
detail->aug_5 = inst->GetAugmentItemID(5);
event_details->push_back(detail);
if (finalizer)
qs_audit->char2_count += detail->charges;
else
@ -886,7 +886,7 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
if (baginst) {
const Item_Struct* bagitem = baginst->GetItem();
if (bagitem && (GetGM() || (bagitem->NoDrop != 0 && baginst->IsInstNoDrop() == false))) {
tradingWith->CastToNPC()->AddLootDrop(bagitem, &tradingWith->CastToNPC()->itemlist,
tradingWith->CastToNPC()->AddLootDrop(bagitem, &tradingWith->CastToNPC()->itemlist,
baginst->GetCharges(), 1, 127, true, true);
}
else if (RuleB(NPC, ReturnNonQuestNoDropItems)) {
@ -895,8 +895,8 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
}
}
}
tradingWith->CastToNPC()->AddLootDrop(item, &tradingWith->CastToNPC()->itemlist,
tradingWith->CastToNPC()->AddLootDrop(item, &tradingWith->CastToNPC()->itemlist,
inst->GetCharges(), 1, 127, true, true);
}
// Return NO DROP and Attuned items being handed into a non-quest NPC if the rule is true
@ -936,7 +936,7 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
if(tradingWith->GetAppearance() != eaDead) {
tradingWith->FaceTarget(this);
}
ItemInst *insts[4] = { 0 };
for(int i = EmuConstants::TRADE_BEGIN; i <= EmuConstants::TRADE_NPC_END; ++i) {
insts[i - EmuConstants::TRADE_BEGIN] = m_inv.PopItem(i);
@ -1468,18 +1468,16 @@ void Client::TradeRequestFailed(const EQApplicationPacket* app) {
}
static void BazaarAuditTrail(const char *Seller, const char *Buyer, const char *ItemName, int Quantity, int TotalCost, int TranType) {
static void BazaarAuditTrail(const char *seller, const char *buyer, const char *itemName, int quantity, int totalCost, int tranType) {
const char *AuditQuery="INSERT INTO `trader_audit` (`time`, `seller`, `buyer`, `itemname`, `quantity`, `totalcost`, `trantype`) "
"VALUES (NOW(), '%s', '%s', '%s', %i, %i, %i)";
std::string query = StringFormat("INSERT INTO `trader_audit` "
"(`time`, `seller`, `buyer`, `itemname`, `quantity`, `totalcost`, `trantype`) "
"VALUES (NOW(), '%s', '%s', '%s', %i, %i, %i)",
seller, buyer, itemName, quantity, totalCost, tranType);
auto results = database.QueryDatabase(query);
if(!results.Success())
_log(TRADING__CLIENT, "Audit write error: %s : %s", query.c_str(), results.ErrorMessage().c_str());
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
if(!database.RunQuery(query, MakeAnyLenString(&query, AuditQuery, Seller, Buyer, ItemName, Quantity, TotalCost, TranType), errbuf))
_log(TRADING__CLIENT, "Audit write error: %s : %s", query, errbuf);
safe_delete_array(query);
}
@ -1619,363 +1617,324 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicat
void Client::SendBazaarWelcome(){
char errbuf[MYSQL_ERRMSG_SIZE];
const std::string query = "SELECT COUNT(DISTINCT char_id), count(char_id) FROM trader";
auto results = database.QueryDatabase(query);
if (results.Success() && results.RowCount() == 1){
auto row = results.begin();
char* query = 0;
EQApplicationPacket* outapp = new EQApplicationPacket(OP_BazaarSearch, sizeof(BazaarWelcome_Struct));
MYSQL_RES *result;
memset(outapp->pBuffer,0,outapp->size);
MYSQL_ROW row;
BazaarWelcome_Struct* bws = (BazaarWelcome_Struct*)outapp->pBuffer;
if (database.RunQuery(query,MakeAnyLenString(&query, "select count(distinct char_id),count(char_id) from trader"),errbuf,&result)){
if(mysql_num_rows(result)==1){
bws->Beginning.Action = BazaarWelcome;
row = mysql_fetch_row(result);
bws->Traders = atoi(row[0]);
bws->Items = atoi(row[1]);
EQApplicationPacket* outapp = new EQApplicationPacket(OP_BazaarSearch, sizeof(BazaarWelcome_Struct));
QueuePacket(outapp);
memset(outapp->pBuffer,0,outapp->size);
safe_delete(outapp);
}
BazaarWelcome_Struct* bws = (BazaarWelcome_Struct*)outapp->pBuffer;
const std::string buyerCountQuery = "SELECT COUNT(DISTINCT charid) FROM buyer";
results = database.QueryDatabase(query);
if (!results.Success() || results.RowCount() != 1)
return;
bws->Beginning.Action = BazaarWelcome;
bws->Items = atoi(row[1]);
bws->Traders = atoi(row[0]);
QueuePacket(outapp);
safe_delete(outapp);
}
mysql_free_result(result);
}
safe_delete_array(query);
if (database.RunQuery(query,MakeAnyLenString(&query, "select count(distinct charid) from buyer"),errbuf,&result)){
if(mysql_num_rows(result)==1) {
row = mysql_fetch_row(result);
Message(10, "There are %i Buyers waiting to purchase your loot. Type /barter to search for them,"
" or use /buyer to set up your own Buy Lines.", atoi(row[0]));
}
mysql_free_result(result);
}
safe_delete_array(query);
auto row = results.begin();
Message(10, "There are %i Buyers waiting to purchase your loot. Type /barter to search for them, "
"or use /buyer to set up your own Buy Lines.", atoi(row[0]));
}
void Client::SendBazaarResults(uint32 TraderID, uint32 Class_, uint32 Race, uint32 ItemStat, uint32 Slot, uint32 Type,
char Name[64], uint32 MinPrice, uint32 MaxPrice) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* Query = 0;
std::string Search, Values;
MYSQL_RES *Result;
MYSQL_ROW Row;
char Tmp[100] = {0};
std::string searchValues = " COUNT(item_id), trader.*, items.name ";
std::string searchCriteria = " WHERE trader.item_id = items.id ";
Values.append("count(item_id),trader.*,items.name");
if(TraderID > 0) {
Client* trader = entity_list.GetClientByID(TraderID);
Search.append("where trader.item_id=items.id");
if(trader)
searchCriteria.append(StringFormat(" AND trader.char_id = %i", trader->CharacterID()));
}
if(TraderID > 0){
Client* Trader = entity_list.GetClientByID(TraderID);
if(MinPrice != 0)
searchCriteria.append(StringFormat(" AND trader.item_cost >= %i", MinPrice));
if(Trader){
sprintf(Tmp," and trader.char_id=%i",Trader->CharacterID());
Search.append(Tmp);
}
if(MaxPrice != 0)
searchCriteria.append(StringFormat(" AND trader.item_cost <= %i", MaxPrice));
if(strlen(Name) > 0) {
char *safeName = RemoveApostrophes(Name);
searchCriteria.append(StringFormat(" AND items.name LIKE '%%%s%%'", safeName));
safe_delete_array(safeName);
}
std::string SearchrResults;
if(MinPrice != 0){
sprintf(Tmp, " and trader.item_cost>=%i", MinPrice);
Search.append(Tmp);
}
if(MaxPrice != 0){
sprintf(Tmp, " and trader.item_cost<=%i", MaxPrice);
Search.append(Tmp);
}
if(strlen(Name) > 0){
char *SafeName = RemoveApostrophes(Name);
sprintf(Tmp, " and items.name like '%%%s%%'", SafeName);
safe_delete_array(SafeName);
Search.append(Tmp);
}
if(Class_ != 0xFFFFFFFF){
sprintf(Tmp, " and mid(reverse(bin(items.classes)),%i,1)=1", Class_);
Search.append(Tmp);
}
if(Race!=0xFFFFFFFF){
sprintf(Tmp, " and mid(reverse(bin(items.races)),%i,1)=1", Race);
Search.append(Tmp);
}
if(Slot!=0xFFFFFFFF){
sprintf(Tmp, " and mid(reverse(bin(items.slots)),%i,1)=1", Slot + 1);
Search.append(Tmp);
}
if(Type!=0xFFFFFFFF){
if(Class_ != 0xFFFFFFFF)
searchCriteria.append(StringFormat(" AND MID(REVERSE(BIN(items.classes)), %i, 1) = 1", Class_));
switch(Type){
if(Race != 0xFFFFFFFF)
searchCriteria.append(StringFormat(" AND MID(REVERSE(BIN(items.races)), %i, 1) = 1", Race));
case 0:
// 1H Slashing
Search.append(" and items.itemtype=0 and damage>0");
break;
case 31:
Search.append(" and items.itemclass=2");
break;
case 46:
Search.append(" and items.spellid>0 and items.spellid<65000");
break;
case 47:
Search.append(" and items.spellid=998");
break;
case 48:
Search.append(" and items.spellid>=1298 and items.spellid<=1307");
break;
case 49:
Search.append(" and items.focuseffect>0");
break;
default:
sprintf(Tmp, " and items.itemtype=%i", Type);
Search.append(Tmp);
}
}
if(Slot != 0xFFFFFFFF)
searchCriteria.append(StringFormat(" AND MID(REVERSE(BIN(items.slots)), %i, 1) = 1", Slot + 1));
switch(Type){
case 0xFFFFFFFF:
break;
case 0:
// 1H Slashing
searchCriteria.append(" AND items.itemtype = 0 AND damage > 0");
break;
case 31:
searchCriteria.append(" AND items.itemclass = 2");
break;
case 46:
searchCriteria.append(" AND items.spellid > 0 AND items.spellid < 65000");
break;
case 47:
searchCriteria.append(" AND items.spellid = 998");
break;
case 48:
searchCriteria.append(" AND items.spellid >= 1298 AND items.spellid <= 1307");
break;
case 49:
searchCriteria.append(" AND items.focuseffect > 0");
break;
default:
searchCriteria.append(StringFormat(" AND items.itemtype = %i", Type));
}
switch(ItemStat) {
case STAT_AC:
Search.append(" and items.ac>0");
Values.append(",items.ac");
searchCriteria.append(" AND items.ac > 0");
searchValues.append(", items.ac");
break;
case STAT_AGI:
Search.append(" and items.aagi>0");
Values.append(",items.aagi");
searchCriteria.append(" AND items.aagi > 0");
searchValues.append(", items.aagi");
break;
case STAT_CHA:
Search.append(" and items.acha>0");
Values.append(",items.acha");
searchCriteria.append(" AND items.acha > 0");
searchValues.append(", items.acha");
break;
case STAT_DEX:
Search.append(" and items.adex>0");
Values.append(",items.adex");
searchCriteria.append(" AND items.adex > 0");
searchValues.append(", items.adex");
break;
case STAT_INT:
Search.append(" and items.aint>0");
Values.append(",items.aint");
searchCriteria.append(" AND items.aint > 0");
searchValues.append(", items.aint");
break;
case STAT_STA:
Search.append(" and items.asta>0");
Values.append(",items.asta");
searchCriteria.append(" AND items.asta > 0");
searchValues.append(", items.asta");
break;
case STAT_STR:
Search.append(" and items.astr>0");
Values.append(",items.astr");
searchCriteria.append(" AND items.astr > 0");
searchValues.append(", items.astr");
break;
case STAT_WIS:
Search.append(" and items.awis>0");
Values.append(",items.awis");
searchCriteria.append(" AND items.awis > 0");
searchValues.append(", items.awis");
break;
case STAT_COLD:
Search.append(" and items.cr>0");
Values.append(",items.cr");
searchCriteria.append(" AND items.cr > 0");
searchValues.append(", items.cr");
break;
case STAT_DISEASE:
Search.append(" and items.dr>0");
Values.append(",items.dr");
searchCriteria.append(" AND items.dr > 0");
searchValues.append(", items.dr");
break;
case STAT_FIRE:
Search.append(" and items.fr>0");
Values.append(",items.fr");
searchCriteria.append(" AND items.fr > 0");
searchValues.append(", items.fr");
break;
case STAT_MAGIC:
Values.append(",items.mr");
Search.append(" and items.mr>0");
searchCriteria.append(" AND items.mr > 0");
searchValues.append(", items.mr");
break;
case STAT_POISON:
Search.append(" and items.pr>0");
Values.append(",items.pr");
searchCriteria.append(" AND items.pr > 0");
searchValues.append(", items.pr");
break;
case STAT_HP:
Search.append(" and items.hp>0");
Values.append(",items.hp");
searchCriteria.append(" AND items.hp > 0");
searchValues.append(", items.hp");
break;
case STAT_MANA:
Search.append(" and items.mana>0");
Values.append(",items.mana");
searchCriteria.append(" AND items.mana > 0");
searchValues.append(", items.mana");
break;
case STAT_ENDURANCE:
Search.append(" and items.endur>0");
Values.append(",items.endur");
searchCriteria.append(" AND items.endur > 0");
searchValues.append(", items.endur");
break;
case STAT_ATTACK:
Search.append(" and items.attack>0");
Values.append(",items.attack");
searchCriteria.append(" AND items.attack > 0");
searchValues.append(", items.attack");
break;
case STAT_HP_REGEN:
Search.append(" and items.regen>0");
Values.append(",items.regen");
searchCriteria.append(" AND items.regen > 0");
searchValues.append(", items.regen");
break;
case STAT_MANA_REGEN:
Search.append(" and items.manaregen>0");
Values.append(",items.manaregen");
searchCriteria.append(" AND items.manaregen > 0");
searchValues.append(", items.manaregen");
break;
case STAT_HASTE:
Search.append(" and items.haste>0");
Values.append(",items.haste");
searchCriteria.append(" AND items.haste > 0");
searchValues.append(", items.haste");
break;
case STAT_DAMAGE_SHIELD:
Search.append(" and items.damageshield>00");
Values.append(",items.damageshield");
searchCriteria.append(" AND items.damageshield > 0");
searchValues.append(", items.damageshield");
break;
default:
Values.append(",0");
searchValues.append(", 0");
break;
}
Values.append(",sum(charges), items.stackable ");
std::string query = StringFormat("SELECT %s, SUM(charges), items.stackable "
"FROM trader, items %s GROUP BY items.id, charges, char_id LIMIT %i",
searchValues.c_str(), searchCriteria.c_str(), RuleI(Bazaar, MaxSearchResults));
auto results = database.QueryDatabase(query);
if (!results.Success()) {
_log(TRADING__CLIENT, "Failed to retrieve Bazaar Search!! %s %s\n", query.c_str(), results.ErrorMessage().c_str());
return;
}
if (database.RunQuery(Query,MakeAnyLenString(&Query, "select %s from trader,items %s group by items.id,charges,char_id limit %i",
Values.c_str(),Search.c_str(), RuleI(Bazaar, MaxSearchResults)),errbuf,&Result)){
_log(TRADING__CLIENT, "SRCH: %s", query.c_str());
_log(TRADING__CLIENT, "SRCH: %s", Query);
safe_delete_array(Query);
int Size = 0;
uint32 ID = 0;
int Size = 0;
uint32 ID = 0;
if(mysql_num_rows(Result) == static_cast<unsigned long>(RuleI(Bazaar, MaxSearchResults)))
if (results.RowCount() == static_cast<unsigned long>(RuleI(Bazaar, MaxSearchResults)))
Message(15, "Your search reached the limit of %i results. Please narrow your search down by selecting more options.",
RuleI(Bazaar, MaxSearchResults));
if(mysql_num_rows(Result) == 0){
EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_BazaarSearch, sizeof(BazaarReturnDone_Struct));
BazaarReturnDone_Struct* brds = (BazaarReturnDone_Struct*)outapp2->pBuffer;
brds->TraderID = ID;
brds->Type = BazaarSearchDone;
brds->Unknown008 = 0xFFFFFFFF;
brds->Unknown012 = 0xFFFFFFFF;
brds->Unknown016 = 0xFFFFFFFF;
this->QueuePacket(outapp2);
_pkt(TRADING__PACKETS,outapp2);
safe_delete(outapp2);
mysql_free_result(Result);
return;
}
Size = mysql_num_rows(Result) * sizeof(BazaarSearchResults_Struct);
uchar *buffer = new uchar[Size];
uchar *bufptr = buffer;
memset(buffer, 0, Size);
int Action = BazaarSearchResults;
uint32 Cost = 0;
int32 SerialNumber = 0;
char Name[64] = {0};
int Count = 0;
uint32 StatValue=0;
while ((Row = mysql_fetch_row(Result))) {
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, Action);
Count = atoi(Row[0]);
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, Count);
SerialNumber = atoi(Row[3]);
VARSTRUCT_ENCODE_TYPE(int32, bufptr, SerialNumber);
Client* Trader2=entity_list.GetClientByCharID(atoi(Row[1]));
if(Trader2){
ID = Trader2->GetID();
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, ID);
}
else{
_log(TRADING__CLIENT, "Unable to find trader: %i\n",atoi(Row[1]));
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, 0);
}
Cost = atoi(Row[5]);
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, Cost);
StatValue = atoi(Row[8]);
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, StatValue);
bool Stackable = atoi(Row[10]);
if(Stackable) {
int Charges = atoi(Row[9]);
sprintf(Name, "%s(%i)", Row[7], Charges);
}
else
sprintf(Name,"%s(%i)",Row[7], Count);
memcpy(bufptr,&Name, strlen(Name));
bufptr += 64;
// Extra fields for SoD+
//
if(Trader2)
sprintf(Name, "%s", Trader2->GetName());
else
sprintf(Name, "Unknown");
memcpy(bufptr,&Name, strlen(Name));
bufptr += 64;
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, atoi(Row[1])); // ItemID
}
mysql_free_result(Result);
EQApplicationPacket* outapp = new EQApplicationPacket(OP_BazaarSearch, Size);
memcpy(outapp->pBuffer, buffer, Size);
this->QueuePacket(outapp);
_pkt(TRADING__PACKETS,outapp);
safe_delete(outapp);
safe_delete_array(buffer);
if(results.RowCount() == 0) {
EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_BazaarSearch, sizeof(BazaarReturnDone_Struct));
BazaarReturnDone_Struct* brds = (BazaarReturnDone_Struct*)outapp2->pBuffer;
brds->TraderID = ID;
brds->Type = BazaarSearchDone;
brds->Unknown008 = 0xFFFFFFFF;
brds->Unknown012 = 0xFFFFFFFF;
brds->Unknown016 = 0xFFFFFFFF;
this->QueuePacket(outapp2);
_pkt(TRADING__PACKETS,outapp2);
safe_delete(outapp2);
}
else{
_log(TRADING__CLIENT, "Failed to retrieve Bazaar Search!! %s %s\n", Query, errbuf);
safe_delete_array(Query);
return;
}
Size = results.RowCount() * sizeof(BazaarSearchResults_Struct);
uchar *buffer = new uchar[Size];
uchar *bufptr = buffer;
memset(buffer, 0, Size);
int Action = BazaarSearchResults;
uint32 Cost = 0;
int32 SerialNumber = 0;
char Name[64] = {0};
int Count = 0;
uint32 StatValue=0;
for (auto row = results.begin(); row != results.end(); ++row) {
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, Action);
Count = atoi(row[0]);
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, Count);
SerialNumber = atoi(row[3]);
VARSTRUCT_ENCODE_TYPE(int32, bufptr, SerialNumber);
Client* Trader2=entity_list.GetClientByCharID(atoi(row[1]));
if(Trader2){
ID = Trader2->GetID();
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, ID);
}
else{
_log(TRADING__CLIENT, "Unable to find trader: %i\n",atoi(row[1]));
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, 0);
}
Cost = atoi(row[5]);
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, Cost);
StatValue = atoi(row[8]);
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, StatValue);
bool Stackable = atoi(row[10]);
if(Stackable) {
int Charges = atoi(row[9]);
sprintf(Name, "%s(%i)", row[7], Charges);
}
else
sprintf(Name,"%s(%i)",row[7], Count);
memcpy(bufptr,&Name, strlen(Name));
bufptr += 64;
// Extra fields for SoD+
//
if(Trader2)
sprintf(Name, "%s", Trader2->GetName());
else
sprintf(Name, "Unknown");
memcpy(bufptr,&Name, strlen(Name));
bufptr += 64;
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, atoi(row[1])); // ItemID
}
EQApplicationPacket* outapp = new EQApplicationPacket(OP_BazaarSearch, Size);
memcpy(outapp->pBuffer, buffer, Size);
this->QueuePacket(outapp);
_pkt(TRADING__PACKETS,outapp);
safe_delete(outapp);
safe_delete_array(buffer);
EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_BazaarSearch, sizeof(BazaarReturnDone_Struct));
BazaarReturnDone_Struct* brds = (BazaarReturnDone_Struct*)outapp2->pBuffer;
brds->TraderID = ID;
brds->Type = BazaarSearchDone;
brds->Unknown008 = 0xFFFFFFFF;
brds->Unknown012 = 0xFFFFFFFF;
brds->Unknown016 = 0xFFFFFFFF;
this->QueuePacket(outapp2);
_pkt(TRADING__PACKETS,outapp2);
safe_delete(outapp2);
}
static void UpdateTraderCustomerItemsAdded(uint32 CustomerID, TraderCharges_Struct* gis, uint32 ItemID) {
@ -2297,103 +2256,92 @@ void Client::HandleTraderPriceUpdate(const EQApplicationPacket *app) {
}
void Client::SendBuyerResults(char* SearchString, uint32 SearchID) {
void Client::SendBuyerResults(char* searchString, uint32 searchID) {
// This method is called when a potential seller in the /barter window searches for matching buyers
//
_log(TRADING__BARTER, "Client::SendBuyerResults %s\n", SearchString);
_log(TRADING__BARTER, "Client::SendBuyerResults %s\n", searchString);
char errbuf[MYSQL_ERRMSG_SIZE];
char* Query = 0;
char ItemName[64];
std::string Search, Values;
MYSQL_RES *Result;
MYSQL_ROW Row;
char* escSearchString = new char[strlen(searchString) * 2 + 1];
database.DoEscapeString(escSearchString, searchString, strlen(searchString));
char*EscSearchString = new char[strlen(SearchString) * 2 + 1];
database.DoEscapeString(EscSearchString, SearchString, strlen(SearchString));
std::string query = StringFormat("SELECT * FROM buyer WHERE itemname LIKE '%%%s%%' ORDER BY charid LIMIT %i",
escSearchString, RuleI(Bazaar, MaxBarterSearchResults));
safe_delete_array(escSearchString);
auto results = database.QueryDatabase(query);
if (!results.Success()) {
_log(TRADING__CLIENT, "Failed to retrieve Barter Search!! %s %s\n", query.c_str(), results.ErrorMessage().c_str());
return;
}
if (database.RunQuery(Query,MakeAnyLenString(&Query, "select * from buyer where itemname like '%%%s%%' order by charid limit %i",
EscSearchString, RuleI(Bazaar, MaxBarterSearchResults)), errbuf, &Result)) {
int numberOfRows = results.RowCount();
int NumberOfRows = mysql_num_rows(Result);
if(numberOfRows == RuleI(Bazaar, MaxBarterSearchResults))
Message(15, "Your search found too many results; some are not displayed.");
else if(strlen(searchString) == 0)
Message(10, "There are %i Buy Lines.", numberOfRows);
else
Message(10, "There are %i Buy Lines that match the search string '%s'.", numberOfRows, searchString);
if(NumberOfRows == RuleI(Bazaar, MaxBarterSearchResults))
Message(15, "Your search found too many results; some are not displayed.");
else {
if(strlen(SearchString) == 0)
Message(10, "There are %i Buy Lines.", NumberOfRows);
else
Message(10, "There are %i Buy Lines that match the search string '%s'.",
NumberOfRows, SearchString);
if(numberOfRows == 0)
return;
uint32 lastCharID = 0;
Client *buyer = nullptr;
for (auto row = results.begin(); row != results.end(); ++row) {
char itemName[64];
uint32 charID = atoi(row[0]);
uint32 buySlot = atoi(row[1]);
uint32 itemID = atoi(row[2]);
strcpy(itemName, row[3]);
uint32 quantity = atoi(row[4]);
uint32 price = atoi(row[5]);
// Each item in the search results is sent as a single fixed length packet, although the position of
// the fields varies due to the use of variable length strings. The reason the packet is so big, is
// to allow item compensation, e.g. a buyer could offer to buy a Blade Of Carnage for 10000pp plus
// other items in exchange. Item compensation is not currently supported in EQEmu.
//
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Barter, 940);
char *buf = (char *)outapp->pBuffer;
const Item_Struct* item = database.GetItem(itemID);
if(!item)
continue;
// Save having to scan the client list when dealing with multiple buylines for the same Character.
if(charID != lastCharID) {
buyer = entity_list.GetClientByCharID(charID);
lastCharID = charID;
}
if(NumberOfRows == 0) {
mysql_free_result(Result);
safe_delete_array(Query);
return;
}
if(!buyer)
continue;
uint32 LastCharID = 0;
Client *Buyer = nullptr;
VARSTRUCT_ENCODE_TYPE(uint32, buf, Barter_BuyerSearchResults); // Command
VARSTRUCT_ENCODE_TYPE(uint32, buf, searchID); // Match up results with the request
VARSTRUCT_ENCODE_TYPE(uint32, buf, buySlot); // Slot in this Buyer's list
VARSTRUCT_ENCODE_TYPE(uint8, buf, 0x01); // Unknown - probably a flag field
VARSTRUCT_ENCODE_TYPE(uint32, buf, itemID); // ItemID
VARSTRUCT_ENCODE_STRING(buf, itemName); // Itemname
VARSTRUCT_ENCODE_TYPE(uint32, buf, item->Icon); // Icon
VARSTRUCT_ENCODE_TYPE(uint32, buf, quantity); // Quantity
VARSTRUCT_ENCODE_TYPE(uint8, buf, 0x01); // Unknown - probably a flag field
VARSTRUCT_ENCODE_TYPE(uint32, buf, price); // Price
VARSTRUCT_ENCODE_TYPE(uint32, buf, buyer->GetID()); // Entity ID
VARSTRUCT_ENCODE_TYPE(uint32, buf, 0); // Flag for + Items , probably ItemCount
VARSTRUCT_ENCODE_STRING(buf, buyer->GetName()); // Seller Name
while ((Row = mysql_fetch_row(Result))) {
_pkt(TRADING__BARTER, outapp);
uint32 CharID = atoi(Row[0]);
uint32 BuySlot = atoi(Row[1]);
uint32 ItemID = atoi(Row[2]);
strcpy(ItemName, Row[3]);
uint32 Quantity = atoi(Row[4]);
uint32 Price = atoi(Row[5]);
QueuePacket(outapp);
safe_delete(outapp);
}
// Each item in the search results is sent as a single fixed length packet, although the position of
// the fields varies due to the use of variable length strings. The reason the packet is so big, is
// to allow item compensation, e.g. a buyer could offer to buy a Blade Of Carnage for 10000pp plus
// other items in exchange. Item compensation is not currently supported in EQEmu.
//
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Barter, 940);
char *Buf = (char *)outapp->pBuffer;
const Item_Struct* item = database.GetItem(ItemID);
if(!item) continue;
// Save having to scan the client list when dealing with multiple buylines for the same Character.
if(CharID != LastCharID) {
Buyer = entity_list.GetClientByCharID(CharID);
LastCharID = CharID;
}
if(!Buyer) continue;
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Barter_BuyerSearchResults); // Command
VARSTRUCT_ENCODE_TYPE(uint32, Buf, SearchID); // Match up results with the request
VARSTRUCT_ENCODE_TYPE(uint32, Buf, BuySlot); // Slot in this Buyer's list
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 0x01); // Unknown - probably a flag field
VARSTRUCT_ENCODE_TYPE(uint32, Buf, ItemID); // ItemID
VARSTRUCT_ENCODE_STRING(Buf, ItemName); // Itemname
VARSTRUCT_ENCODE_TYPE(uint32, Buf, item->Icon); // Icon
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity); // Quantity
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 0x01); // Unknown - probably a flag field
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Price); // Price
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Buyer->GetID()); // Entity ID
VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0); // Flag for + Items , probably ItemCount
VARSTRUCT_ENCODE_STRING(Buf, Buyer->GetName()); // Seller Name
_pkt(TRADING__BARTER, outapp);
QueuePacket(outapp);
safe_delete(outapp);
}
mysql_free_result(Result);
}
else{
_log(TRADING__CLIENT, "Failed to retrieve Barter Search!! %s %s\n", Query, errbuf);
}
safe_delete_array(Query);
safe_delete_array(EscSearchString);
}
void Client::ShowBuyLines(const EQApplicationPacket *app) {
@ -2436,60 +2384,44 @@ void Client::ShowBuyLines(const EQApplicationPacket *app) {
safe_delete(outapp);
char errbuf[MYSQL_ERRMSG_SIZE];
char* Query = 0;
char ItemName[64];
std::string Search, Values;
MYSQL_RES *Result;
MYSQL_ROW Row;
std::string query = StringFormat("SELECT * FROM buyer WHERE charid = %i", Buyer->CharacterID());
auto results = database.QueryDatabase(query);
if (!results.Success() || results.RowCount() == 0)
return;
if (database.RunQuery(Query,MakeAnyLenString(&Query, "select * from buyer where charid = %i",
Buyer->CharacterID()),errbuf,&Result)){
for (auto row = results.begin(); row != results.end(); ++row) {
char ItemName[64];
uint32 BuySlot = atoi(row[1]);
uint32 ItemID = atoi(row[2]);
strcpy(ItemName, row[3]);
uint32 Quantity = atoi(row[4]);
uint32 Price = atoi(row[5]);
if(mysql_num_rows(Result) == 0) {
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Barter, 936);
safe_delete_array(Query);
char *Buf = (char *)outapp->pBuffer;
mysql_free_result(Result);
const Item_Struct* item = database.GetItem(ItemID);
return;
}
if(!item)
continue;
while ((Row = mysql_fetch_row(Result))) {
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Barter_BuyerInspectWindow);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, BuySlot);
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 1); // Flag
VARSTRUCT_ENCODE_TYPE(uint32, Buf, ItemID);
VARSTRUCT_ENCODE_STRING(Buf, ItemName);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, item->Icon);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity);
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 1); // Flag
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Price);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Buyer->GetID());
VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0);
VARSTRUCT_ENCODE_STRING(Buf, Buyer->GetName());
uint32 BuySlot = atoi(Row[1]);
uint32 ItemID = atoi(Row[2]);
strcpy(ItemName, Row[3]);
uint32 Quantity = atoi(Row[4]);
uint32 Price = atoi(Row[5]);
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Barter, 936);
char *Buf = (char *)outapp->pBuffer;
const Item_Struct* item = database.GetItem(ItemID);
if(!item) continue;
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Barter_BuyerInspectWindow);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, BuySlot);
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 1); // Flag
VARSTRUCT_ENCODE_TYPE(uint32, Buf, ItemID);
VARSTRUCT_ENCODE_STRING(Buf, ItemName);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, item->Icon);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity);
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 1); // Flag
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Price);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Buyer->GetID());
VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0);
VARSTRUCT_ENCODE_STRING(Buf, Buyer->GetName());
_pkt(TRADING__BARTER, outapp);
QueuePacket(outapp);
}
mysql_free_result(Result);
}
safe_delete_array(Query);
_pkt(TRADING__BARTER, outapp);
QueuePacket(outapp);
}
}
void Client::SellToBuyer(const EQApplicationPacket *app) {