merge from upstream

This commit is contained in:
Arthur Ice 2014-08-28 15:49:16 -07:00
commit 0996570b78
90 changed files with 12579 additions and 3526 deletions

View File

@ -1,5 +1,70 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50) EQEMu Changelog (Started on Sept 24, 2003 15:50)
------------------------------------------------------- -------------------------------------------------------
== 08/26/2014 ==
Uleat: Implemented 'Smart' Player Trade transfers. Trades are processed by containers, stackables and then all remaining. QueryServ logs have been updated to match these transactions.
Note: QueryServ logs previously listed 'Items' on the main entry table. This indicated the number of slots affected and not the actual number of items.
This field now indicates the actual number of items transferred. For non-stackable, the value is '1' and stackable is the number of charges. A _detail_count
property has been added to both 'Trade' and 'Handin' structs to indicate the number of details recorded..though, not tracked..it could be added.
== 08/24/2014 ==
Uleat: Fix (attempted) for zone crashes related to zone shut-down. This change disables all Mob AI and disables/deletes all Mob timers once Zone::ShutDown() is called. More areas will be addressed as reports come in.
Note: Perl and Lua quests tested to work..please post any aberrant behavior. (I finally set my spell-check to US English...)
Akkadius: Character creation process crash fix and query cleanup
Akkadius: Created `character_lookup` table for applications that mirrors all `character_` table fields minus blob fields for application lookups
- A 2.4GB character_ table will take 7 seconds to query on a SSD versus .1s on the character_lookup table
- This also causes applications like Magelo to burst reads of the entire character table because of the blob fields that come with the reads, as much as 500-600MB/s even if a indexed id filter is provided
- This field is synchronized on player save and has 0.001s DB hit
- When we split out from the blob, ideally this table can be removed
- Required SQL: utils\sql\git\required\2014_08_24_character_lookup.sql
== 08/23/2014 ==
Akkadius: Changed zone process window title format, example: 'crushbone :: clients: 6 inst_id: 1 inst_ver: 0 :: port: 7015'
Akkadius: Most of the following changes are QueryServ related, fully implemented its original functionality to be able to offload
intensive or metric based logging to a remote server process that could exist on another server entirely
Akkadius: Implemented Player Event Logging Types (Go to table `qs_player_events`):
1 = Player_Log_Quest,
2 = Player_Log_Zoning,
3 = Player_Log_Deaths,
4 = Player_Log_Connect_State,
5 = Player_Log_Levels,
6 = Player_Log_Keyring_Addition,
7 = Player_Log_QGlobal_Update,
8 = Player_Log_Task_Updates,
9 = Player_Log_AA_Purchases,
10 = Player_Log_Trade_Skill_Events,
11 = Player_Log_Issued_Commands,
12 = Player_Log_Money_Transactions,
13 = Player_Log_Alternate_Currency_Transactions,
- All QueryServ logging will be implemented with a front end in EoC 2.0 very soon
- Architecture page: http://wiki.eqemulator.org/p?QueryServ_Architecture
Akkadius: Changed all QS Error related logging to 'QUERYSERV__ERROR'
Akkadius: (Natedog) (Crash Fix) Legacy MySQL bug revert for loading AA's COALESCE( from COALESCE (
Akkadius: Implemented Perl Quest objects (LUA still needed to be exported):
- quest::qs_send_query("MySQL query") - Will send a raw query to the QueryServ process, useful for custom logging
- quest::qs_player_event(char_id, event_desc); - Will process a quest type event to table `qs_player_events`
Akkadius: Added MySQL Tables
- `qs_player_aa_rate_hourly`
- `qs_player_events`
- Source table structures from:
- utils\sql\git\queryserv\required\08_23_2014_player_events_and_player_aa_rate_hourly
To get the complete QueryServ schema, source from here:
- utils\sql\git\queryserv\required\Complete_QueryServ_Table_Structures.sql
Akkadius: Added rules for each logging type, source rules here with them enabled by default:
- utils\sql\git\queryserv\required\Complete_QueryServ_Rules_Enabled.sql
Akkadius: Spawn related logging cleanup
Akkadius: General code cleanup
Akkadius: More to come for QueryServ
== 08/22/2014 ==
Uleat: Rework of Trade::FinishedTrade() and Trade::ResetTrade() to parse items a little more intelligently.
Trade window items are now sent to client inventory in this order:
- Bags
- Partial stack movements
- All remaining items
If any of these procedures cause any problems, please post them immediately.
== 08/20/2014 == == 08/20/2014 ==
Uleat: Rework of Trade::AddEntity() - function used to move items into the trade window. Now accepts argument for 'stack_size' and updates client properly. Uleat: Rework of Trade::AddEntity() - function used to move items into the trade window. Now accepts argument for 'stack_size' and updates client properly.
Note: I tested trade with Titanium:{SoF,SoD,UF,RoF} in both directions and no client generated an OP_MoveItem event for attempting to place a stackable Note: I tested trade with Titanium:{SoF,SoD,UF,RoF} in both directions and no client generated an OP_MoveItem event for attempting to place a stackable

View File

@ -81,8 +81,10 @@ void ExportSpells(SharedDatabase *db) {
line.push_back('^'); line.push_back('^');
} }
if(row[i] != nullptr) {
line += row[i]; line += row[i];
} }
}
fprintf(f, "%s\n", line.c_str()); fprintf(f, "%s\n", line.c_str());
} }
@ -180,8 +182,10 @@ void ExportBaseData(SharedDatabase *db) {
if(rowIndex != 0) if(rowIndex != 0)
line.push_back('^'); line.push_back('^');
if(row[rowIndex] != nullptr) {
line += row[rowIndex]; line += row[rowIndex];
} }
}
fprintf(f, "%s\n", line.c_str()); fprintf(f, "%s\n", line.c_str());
} }

View File

@ -93,6 +93,7 @@ SET(common_sources
) )
SET(common_headers SET(common_headers
any.h
base_packet.h base_packet.h
base_data.h base_data.h
bodytypes.h bodytypes.h

190
common/any.h Normal file
View File

@ -0,0 +1,190 @@
/*
* Boost Software License - Version 1.0 - August 17th, 2003
*
* Permission is hereby granted, free of charge, to any person or organization
* obtaining a copy of the software and accompanying documentation covered by
* this license (the "Software") to use, reproduce, display, distribute,
* execute, and transmit the Software, and to prepare derivative works of the
* Software, and to permit third-parties to whom the Software is furnished to
* do so, all subject to the following:
*
* The copyright notices in the Software and this entire statement, including
* the above license grant, this restriction and the following disclaimer,
* must be included in all copies of the Software, in whole or in part, and
* all derivative works of the Software, unless such copies or derivative
* works are solely in the form of machine-executable object code generated by
* a source language processor.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
// EQEmu::Any is a modified version of Boost::Any and as such retains the Boost licensing.
#ifndef EQEMU_COMMON_ANY_H
#define EQEMU_COMMON_ANY_H
#include <algorithm>
#include <typeinfo>
namespace EQEmu
{
class Any
{
public:
Any()
: content(nullptr)
{
}
template<typename ValueType>
Any(const ValueType &value)
: content(new Holder<ValueType>(value))
{
}
Any(const Any &other)
: content(other.content ? other.content->clone() : 0)
{
}
~Any()
{
if(content)
delete content;
}
Any& swap(Any &rhs)
{
std::swap(content, rhs.content);
return *this;
}
template<typename ValueType>
Any& operator=(const ValueType &rhs)
{
Any(rhs).swap(*this);
return *this;
}
Any& operator=(Any rhs)
{
rhs.swap(*this);
return *this;
}
bool empty() const
{
return !content;
}
const std::type_info& type() const
{
return content ? content->type() : typeid(void);
}
class Placeholder
{
public:
virtual ~Placeholder()
{
}
virtual const std::type_info& type() const = 0;
virtual Placeholder* clone() const = 0;
};
template<typename ValueType>
class Holder : public Placeholder
{
public:
Holder(const ValueType &value)
: held(value)
{
}
virtual const std::type_info& type() const
{
return typeid(ValueType);
}
virtual Placeholder* clone() const
{
return new Holder(held);
}
ValueType held;
private:
Holder& operator=(const Holder&);
};
private:
template<typename ValueType>
friend ValueType* any_cast(Any*);
template<typename ValueType>
friend ValueType* unsafe_any_cast(Any*);
Placeholder* content;
};
class bad_any_cast : public std::bad_cast
{
public:
virtual const char * what() const throw()
{
return "DBI::bad_any_cast: failed conversion using DBI::any_cast";
}
};
template<typename ValueType>
ValueType* any_cast(Any* operand)
{
return operand &&
operand->type() == typeid(ValueType) ? &static_cast<Any::Holder<ValueType>*>(operand->content)->held : nullptr;
}
template<typename ValueType>
inline const ValueType* any_cast(const Any* operand)
{
return any_cast<ValueType>(const_cast<Any*>(operand));
}
template<typename ValueType>
ValueType any_cast(Any& operand)
{
typedef typename std::remove_reference<ValueType>::type nonref;
nonref* result = any_cast<nonref>(&operand);
if(!result)
throw bad_any_cast();
return *result;
}
template<typename ValueType>
inline ValueType any_cast(const Any& operand)
{
typedef typename std::remove_reference<ValueType>::type nonref;
return any_cast<const nonref&>(const_cast<Any&>(operand));
}
template<typename ValueType>
inline ValueType* unsafe_any_cast(Any* operand)
{
return &static_cast<Any::Holder<ValueType>*>(operand->content)->held;
}
template<typename ValueType>
inline const ValueType* unsafe_any_cast(const Any* operand)
{
return unsafe_any_cast<ValueType>(const_cast<Any*>(operand));
}
}
#endif

View File

@ -161,6 +161,9 @@ uint32 Database::CheckLogin(const char* name, const char* password, int16* oStat
return 0; return 0;
} }
if(results.RowCount() == 0)
return 0;
auto row = results.begin(); auto row = results.begin();
uint32 id = atoi(row[0]); uint32 id = atoi(row[0]);
@ -608,10 +611,11 @@ bool Database::StoreCharacter(uint32 account_id, PlayerProfile_Struct* pp, Inven
for (int16 i=EmuConstants::EQUIPMENT_BEGIN; i<=EmuConstants::BANK_BAGS_END;) for (int16 i=EmuConstants::EQUIPMENT_BEGIN; i<=EmuConstants::BANK_BAGS_END;)
{ {
const ItemInst* newinv = inv->GetItem(i); const ItemInst* newinv = inv->GetItem(i);
if (!newinv) if (newinv)
{ {
invquery = StringFormat("INSERT INTO inventory SET charid=%0u, slotid=%0d, itemid=%0u, charges=%0d, color=%0u", invquery = StringFormat("INSERT INTO `inventory` (charid, slotid, itemid, charges, color) VALUES (%u, %i, %u, %i, %u)",
charid, i, newinv->GetItem()->ID, newinv->GetCharges(), newinv->GetColor()); charid, i, newinv->GetItem()->ID, newinv->GetCharges(), newinv->GetColor());
auto results = QueryDatabase(invquery); auto results = QueryDatabase(invquery);
if (!results.RowsAffected()) if (!results.RowsAffected())

View File

@ -654,6 +654,99 @@ int16 Inventory::FindFreeSlot(bool for_bag, bool try_cursor, uint8 min_size, boo
return INVALID_INDEX; return INVALID_INDEX;
} }
// This is a mix of HasSpaceForItem and FindFreeSlot..due to existing coding behavior, it was better to add a new helper function...
int16 Inventory::FindFreeSlotForTradeItem(const ItemInst* inst) {
// Do not arbitrarily use this function..it is designed for use with Client::ResetTrade() and Client::FinishTrade().
// If you have a need, use it..but, understand it is not a compatible replacement for Inventory::FindFreeSlot().
//
// I'll probably implement a bitmask in the new inventory system to avoid having to adjust stack bias -U
if (!inst || !inst->GetID())
return INVALID_INDEX;
// step 1: find room for bags (caller should really ask for slots for bags first to avoid sending them to cursor..and bag item loss)
if (inst->IsType(ItemClassContainer)) {
for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot)
if (!m_inv[free_slot])
return free_slot;
return MainCursor; // return cursor since bags do not stack and will not fit inside other bags..yet...)
}
// step 2: find partial room for stackables
if (inst->IsStackable()) {
for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot) {
const ItemInst* main_inst = m_inv[free_slot];
if (!main_inst)
continue;
if ((main_inst->GetID() == inst->GetID()) && (main_inst->GetCharges() < main_inst->GetItem()->StackSize))
return free_slot;
if (main_inst->IsType(ItemClassContainer)) { // if item-specific containers already have bad items, we won't fix it here...
for (uint8 free_bag_slot = SUB_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++free_bag_slot) {
const ItemInst* sub_inst = main_inst->GetItem(free_bag_slot);
if (!sub_inst)
continue;
if ((sub_inst->GetID() == inst->GetID()) && (sub_inst->GetCharges() < sub_inst->GetItem()->StackSize))
return Inventory::CalcSlotId(free_slot, free_bag_slot);
}
}
}
}
// step 3a: find room for container-specific items (ItemClassArrow)
if (inst->GetItem()->ItemType == ItemTypeArrow) {
for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot) {
const ItemInst* main_inst = m_inv[free_slot];
if (!main_inst || (main_inst->GetItem()->BagType != BagTypeQuiver) || !main_inst->IsType(ItemClassContainer))
continue;
for (uint8 free_bag_slot = SUB_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++free_bag_slot)
if (!main_inst->GetItem(free_bag_slot))
return Inventory::CalcSlotId(free_slot, free_bag_slot);
}
}
// step 3b: find room for container-specific items (ItemClassSmallThrowing)
if (inst->GetItem()->ItemType == ItemTypeSmallThrowing) {
for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot) {
const ItemInst* main_inst = m_inv[free_slot];
if (!main_inst || (main_inst->GetItem()->BagType != BagTypeBandolier) || !main_inst->IsType(ItemClassContainer))
continue;
for (uint8 free_bag_slot = SUB_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++free_bag_slot)
if (!main_inst->GetItem(free_bag_slot))
return Inventory::CalcSlotId(free_slot, free_bag_slot);
}
}
// step 4: just find an empty slot
for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot) {
const ItemInst* main_inst = m_inv[free_slot];
if (!main_inst)
return free_slot;
if (main_inst->IsType(ItemClassContainer)) {
if ((main_inst->GetItem()->BagSize < inst->GetItem()->Size) || (main_inst->GetItem()->BagType == BagTypeBandolier) || (main_inst->GetItem()->BagType == BagTypeQuiver))
continue;
for (uint8 free_bag_slot = SUB_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++free_bag_slot)
if (!main_inst->GetItem(free_bag_slot))
return Inventory::CalcSlotId(free_slot, free_bag_slot);
}
}
//return INVALID_INDEX; // everything else pushes to the cursor
return MainCursor;
}
// Opposite of below: Get parent bag slot_id from a slot inside of bag // Opposite of below: Get parent bag slot_id from a slot inside of bag
int16 Inventory::CalcSlotId(int16 slot_id) { int16 Inventory::CalcSlotId(int16 slot_id) {
int16 parent_slot_id = INVALID_INDEX; int16 parent_slot_id = INVALID_INDEX;

View File

@ -172,6 +172,7 @@ public:
// Locate an available inventory slot // Locate an available inventory slot
int16 FindFreeSlot(bool for_bag, bool try_cursor, uint8 min_size = 0, bool is_arrow = false); int16 FindFreeSlot(bool for_bag, bool try_cursor, uint8 min_size = 0, bool is_arrow = false);
int16 FindFreeSlotForTradeItem(const ItemInst* inst);
// Calculate slot_id for an item within a bag // Calculate slot_id for an item within a bag
static int16 CalcSlotId(int16 slot_id); // Calc parent bag's slot_id static int16 CalcSlotId(int16 slot_id); // Calc parent bag's slot_id

View File

@ -108,6 +108,7 @@ LOG_CATEGORY( FACTION )
LOG_CATEGORY( ZONE ) LOG_CATEGORY( ZONE )
LOG_TYPE( ZONE, GROUND_SPAWNS, DISABLED ) LOG_TYPE( ZONE, GROUND_SPAWNS, DISABLED )
LOG_TYPE( ZONE, SPAWNS, ENABLED)
LOG_TYPE( ZONE, INIT, ENABLED ) LOG_TYPE( ZONE, INIT, ENABLED )
LOG_TYPE( ZONE, INIT_ERR, ENABLED ) LOG_TYPE( ZONE, INIT_ERR, ENABLED )
LOG_TYPE( ZONE, WORLD, ENABLED ) LOG_TYPE( ZONE, WORLD, ENABLED )

View File

@ -40,7 +40,7 @@ public:
MySQLRequestResult& operator=(MySQLRequestResult&& other); MySQLRequestResult& operator=(MySQLRequestResult&& other);
bool Success() const { return m_Success;} bool Success() const { return m_Success;}
std::string ErrorMessage() const {return std::string(m_ErrorBuffer);} std::string ErrorMessage() const {return m_ErrorBuffer ? std::string(m_ErrorBuffer) : std::string("");}
uint32 ErrorNumber() const {return m_ErrorNumber;} uint32 ErrorNumber() const {return m_ErrorNumber;}
uint32 RowsAffected() const {return m_RowsAffected;} uint32 RowsAffected() const {return m_RowsAffected;}
uint32 RowCount() const {return m_RowCount;} uint32 RowCount() const {return m_RowCount;}

View File

@ -64,6 +64,5 @@ bool MySQLRequestRow::operator!=(const MySQLRequestRow& rhs)
char* MySQLRequestRow::operator[](int index) char* MySQLRequestRow::operator[](int index)
{ {
return m_MySQLRow[index]; return m_MySQLRow[index];
} }

View File

@ -558,14 +558,28 @@ RULE_INT ( Console, SessionTimeOut, 600000 ) // Amount of time in ms for the con
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY( QueryServ ) RULE_CATEGORY( QueryServ )
RULE_BOOL( QueryServ, PlayerChatLogging, false) // Logs Player Chat RULE_BOOL( QueryServ, PlayerLogChat, false) // Logs Player Chat
RULE_BOOL( QueryServ, PlayerLogTrades, false) // Logs Player Trades RULE_BOOL( QueryServ, PlayerLogTrades, false) // Logs Player Trades
RULE_BOOL( QueryServ, PlayerLogHandins, false) // Logs Player Handins RULE_BOOL( QueryServ, PlayerLogHandins, false) // Logs Player Handins
RULE_BOOL( QueryServ, PlayerLogNPCKills, false) // Logs Player NPC Kills RULE_BOOL( QueryServ, PlayerLogNPCKills, false) // Logs Player NPC Kills
RULE_BOOL( QueryServ, PlayerLogDeletes, false) // Logs Player Deletes RULE_BOOL( QueryServ, PlayerLogDeletes, false) // Logs Player Deletes
RULE_BOOL( QueryServ, PlayerLogMoves, false) // Logs Player Moves RULE_BOOL( QueryServ, PlayerLogMoves, false) // Logs Player Moves
RULE_BOOL( QueryServ, MerchantLogTransactions, false) // Logs Merchant Transactions RULE_BOOL( QueryServ, PlayerLogMerchantTransactions, false) // Logs Merchant Transactions
RULE_BOOL( QueryServ, PlayerLogPCCoordinates, false) // Logs Player Coordinates with certain events RULE_BOOL( QueryServ, PlayerLogPCCoordinates, false) // Logs Player Coordinates with certain events
RULE_BOOL( QueryServ, PlayerLogDropItem, false) // Logs Player Drop Item
RULE_BOOL( QueryServ, PlayerLogZone, false) // Logs Player Zone Events
RULE_BOOL( QueryServ, PlayerLogDeaths, false) // Logs Player Deaths
RULE_BOOL( QueryServ, PlayerLogConnectDisconnect, false) // Logs Player Connect Disconnect State
RULE_BOOL( QueryServ, PlayerLogLevels, false) // Logs Player Leveling/Deleveling
RULE_BOOL( QueryServ, PlayerLogAARate, false) // Logs Player AA Experience Rates
RULE_BOOL( QueryServ, PlayerLogQGlobalUpdate, false) // Logs Player QGlobal Updates
RULE_BOOL( QueryServ, PlayerLogTaskUpdates, false) // Logs Player Task Updates
RULE_BOOL( QueryServ, PlayerLogKeyringAddition, false) // Log PLayer Keyring additions
RULE_BOOL( QueryServ, PlayerLogAAPurchases, false) // Log Player AA Purchases
RULE_BOOL( QueryServ, PlayerLogTradeSkillEvents, false) // Log Player Tradeskill Transactions
RULE_BOOL( QueryServ, PlayerLogIssuedCommandes, false ) // Log Player Issued Commands
RULE_BOOL( QueryServ, PlayerLogMoneyTransactions, false) // Log Player Money Transaction/Splits
RULE_BOOL( QueryServ, PlayerLogAlternateCurrencyTransactions, false) // Log Ploayer Alternate Currency Transactions
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY( Inventory ) RULE_CATEGORY( Inventory )

View File

@ -184,8 +184,10 @@
#define ServerOP_QSPlayerLogNPCKills 0x4012 #define ServerOP_QSPlayerLogNPCKills 0x4012
#define ServerOP_QSPlayerLogDeletes 0x4013 #define ServerOP_QSPlayerLogDeletes 0x4013
#define ServerOP_QSPlayerLogMoves 0x4014 #define ServerOP_QSPlayerLogMoves 0x4014
#define ServerOP_QSMerchantLogTransactions 0x4015 #define ServerOP_QSPlayerLogMerchantTransactions 0x4015
#define ServerOP_QSSendQuery 0x4016
/* Query Serv Generic Packet Flag/Type Enumeration */
enum { QSG_LFGuild = 0 }; enum { QSG_LFGuild = 0 };
enum { QSG_LFGuild_PlayerMatches = 0, QSG_LFGuild_UpdatePlayerInfo, QSG_LFGuild_RequestPlayerInfo, QSG_LFGuild_UpdateGuildInfo, QSG_LFGuild_GuildMatches, enum { QSG_LFGuild_PlayerMatches = 0, QSG_LFGuild_UpdatePlayerInfo, QSG_LFGuild_RequestPlayerInfo, QSG_LFGuild_UpdateGuildInfo, QSG_LFGuild_GuildMatches,
QSG_LFGuild_RequestGuildInfo }; QSG_LFGuild_RequestGuildInfo };
@ -1116,6 +1118,7 @@ struct QSPlayerLogTrade_Struct {
uint32 char2_id; uint32 char2_id;
MoneyUpdate_Struct char2_money; MoneyUpdate_Struct char2_money;
uint16 char2_count; uint16 char2_count;
uint16 _detail_count;
QSTradeItems_Struct items[0]; QSTradeItems_Struct items[0];
}; };
@ -1139,6 +1142,7 @@ struct QSPlayerLogHandin_Struct {
uint32 npc_id; uint32 npc_id;
MoneyUpdate_Struct npc_money; MoneyUpdate_Struct npc_money;
uint16 npc_count; uint16 npc_count;
uint16 _detail_count;
QSHandinItems_Struct items[0]; QSHandinItems_Struct items[0];
}; };
@ -1219,6 +1223,10 @@ struct QSMerchantLogTransaction_Struct {
QSTransactionItems_Struct items[0]; QSTransactionItems_Struct items[0];
}; };
struct QSGeneralQuery_Struct {
char QueryString[0];
};
struct CZMessagePlayer_Struct { struct CZMessagePlayer_Struct {
uint32 Type; uint32 Type;
char CharName[64]; char CharName[64];

View File

@ -1632,6 +1632,13 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
int tempid = 0; int tempid = 0;
int counter = 0; int counter = 0;
if(result && mysql_field_count(getMySQL()) <= SPELL_LOAD_FIELD_COUNT) {
_log(SPELLS__LOAD_ERR, "Fatal error loading spells: Spell field count < SPELL_LOAD_FIELD_COUNT(%u)", SPELL_LOAD_FIELD_COUNT);
mysql_free_result(result);
return;
}
while (row = mysql_fetch_row(result)) { while (row = mysql_fetch_row(result)) {
tempid = atoi(row[0]); tempid = atoi(row[0]);
if(tempid >= max_spells) { if(tempid >= max_spells) {

View File

@ -621,6 +621,8 @@ typedef enum {
// number. note that the id field is counted as 0, this way the numbers // number. note that the id field is counted as 0, this way the numbers
// here match the numbers given to sep in the loading function net.cpp // here match the numbers given to sep in the loading function net.cpp
// //
#define SPELL_LOAD_FIELD_COUNT 231
struct SPDat_Spell_Struct struct SPDat_Spell_Struct
{ {
/* 000 */ int id; // not used /* 000 */ int id; // not used

View File

@ -57,6 +57,7 @@ const std::string vStringFormat(const char* format, va_list args)
va_copy(tmpargs,args); va_copy(tmpargs,args);
characters_used = vsnprintf(&output[0], output.capacity(), format, tmpargs); characters_used = vsnprintf(&output[0], output.capacity(), format, tmpargs);
va_end(tmpargs); va_end(tmpargs);
output.resize(characters_used);
if (characters_used < 0) { if (characters_used < 0) {
// We shouldn't have a format error by this point, but I can't imagine what error we // We shouldn't have a format error by this point, but I can't imagine what error we
@ -72,6 +73,8 @@ const std::string vStringFormat(const char* format, va_list args)
characters_used = vsnprintf(&output[0], output.capacity(), format, tmpargs); characters_used = vsnprintf(&output[0], output.capacity(), format, tmpargs);
va_end(tmpargs); va_end(tmpargs);
output.resize(characters_used);
if (characters_used < 0) { if (characters_used < 0) {
// We shouldn't have a format error by this point, but I can't imagine what error we // We shouldn't have a format error by this point, but I can't imagine what error we
// could have by this point. Still, return empty string; // could have by this point. Still, return empty string;
@ -380,6 +383,42 @@ std::string EscapeString(const std::string &s) {
return ret; return ret;
} }
std::string EscapeString(const char *src, size_t sz) {
std::string ret;
for(size_t i = 0; i < sz; ++i) {
char c = src[i];
switch(c) {
case '\x00':
ret += "\\x00";
break;
case '\n':
ret += "\\n";
break;
case '\r':
ret += "\\r";
break;
case '\\':
ret += "\\\\";
break;
case '\'':
ret += "\\'";
break;
case '\"':
ret += "\\\"";
break;
case '\x1a':
ret += "\\x1a";
break;
default:
ret.push_back(c);
break;
}
}
return ret;
}
bool isAlphaNumeric(const char *text) bool isAlphaNumeric(const char *text)
{ {
for (unsigned int charIndex=0; charIndex<strlen(text); charIndex++) { for (unsigned int charIndex=0; charIndex<strlen(text); charIndex++) {

View File

@ -26,6 +26,7 @@
const std::string vStringFormat(const char* format, va_list args); const std::string vStringFormat(const char* format, va_list args);
const std::string StringFormat(const char* format, ...); const std::string StringFormat(const char* format, ...);
std::string EscapeString(const std::string &s); std::string EscapeString(const std::string &s);
std::string EscapeString(const char *src, size_t sz);
const char *MakeLowerString(const char *source); const char *MakeLowerString(const char *source);

View File

@ -29,6 +29,7 @@
#include <ctype.h> #include <ctype.h>
#include <assert.h> #include <assert.h>
#include <map> #include <map>
#include <vector>
// Disgrace: for windows compile // Disgrace: for windows compile
#ifdef _WINDOWS #ifdef _WINDOWS
@ -96,41 +97,6 @@ Database::~Database()
{ {
} }
bool Database::GetVariable(const char* varname, char* varvalue, uint16 varvalue_len) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (!RunQuery(query,MakeAnyLenString(&query, "select `value` from `variables` where `varname`='%s'", varname), errbuf, &result)) {
_log(UCS__ERROR, "Unable to get message count from database. %s %s", query, errbuf);
safe_delete_array(query);
return false;
}
safe_delete_array(query);
if (mysql_num_rows(result) != 1) {
mysql_free_result(result);
return false;
}
row = mysql_fetch_row(result);
snprintf(varvalue, varvalue_len, "%s", row[0]);
mysql_free_result(result);
return true;
}
void Database::AddSpeech(const char* from, const char* to, const char* message, uint16 minstatus, uint32 guilddbid, uint8 type) { void Database::AddSpeech(const char* from, const char* to, const char* message, uint16 minstatus, uint32 guilddbid, uint8 type) {
char errbuf[MYSQL_ERRMSG_SIZE]; char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0; char* query = 0;
@ -143,8 +109,8 @@ void Database::AddSpeech(const char* from, const char* to, const char* message,
DoEscapeString(S3, message, strlen(message)); DoEscapeString(S3, message, strlen(message));
if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_player_speech` SET `from`='%s', `to`='%s', `message`='%s', `minstatus`='%i', `guilddbid`='%i', `type`='%i'", S1, S2, S3, minstatus, guilddbid, type), errbuf, 0, 0)) { if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_player_speech` SET `from`='%s', `to`='%s', `message`='%s', `minstatus`='%i', `guilddbid`='%i', `type`='%i'", S1, S2, S3, minstatus, guilddbid, type), errbuf, 0, 0)) {
_log(NET__WORLD, "Failed Speech Entry Insert: %s", errbuf); _log(QUERYSERV__ERROR, "Failed Speech Entry Insert: %s", errbuf);
_log(NET__WORLD, "%s", query); _log(QUERYSERV__ERROR, "%s", query);
} }
safe_delete_array(query); safe_delete_array(query);
@ -153,7 +119,7 @@ void Database::AddSpeech(const char* from, const char* to, const char* message,
safe_delete_array(S3); safe_delete_array(S3);
} }
void Database::LogPlayerTrade(QSPlayerLogTrade_Struct* QS, uint32 Items) { void Database::LogPlayerTrade(QSPlayerLogTrade_Struct* QS, uint32 DetailCount) {
char errbuf[MYSQL_ERRMSG_SIZE]; char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0; char* query = 0;
@ -164,27 +130,26 @@ void Database::LogPlayerTrade(QSPlayerLogTrade_Struct* QS, uint32 Items) {
QS->char1_id, QS->char1_money.platinum, QS->char1_money.gold, QS->char1_money.silver, QS->char1_money.copper, QS->char1_count, QS->char1_id, QS->char1_money.platinum, QS->char1_money.gold, QS->char1_money.silver, QS->char1_money.copper, QS->char1_count,
QS->char2_id, QS->char2_money.platinum, QS->char2_money.gold, QS->char2_money.silver, QS->char2_money.copper, QS->char2_count), QS->char2_id, QS->char2_money.platinum, QS->char2_money.gold, QS->char2_money.silver, QS->char2_money.copper, QS->char2_count),
errbuf, 0, 0, &lastid)) { errbuf, 0, 0, &lastid)) {
_log(NET__WORLD, "Failed Trade Log Record Insert: %s", errbuf); _log(QUERYSERV__ERROR, "Failed Trade Log Record Insert: %s", errbuf);
_log(NET__WORLD, "%s", query); _log(QUERYSERV__ERROR, "%s", query);
} }
if(Items > 0) { if(DetailCount > 0) {
for(int i = 0; i < Items; i++) { for(int i = 0; i < DetailCount; i++) {
if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_player_trade_record_entries` SET `event_id`='%i', " if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_player_trade_record_entries` SET `event_id`='%i', "
"`from_id`='%i', `from_slot`='%i', `to_id`='%i', `to_slot`='%i', `item_id`='%i', " "`from_id`='%i', `from_slot`='%i', `to_id`='%i', `to_slot`='%i', `item_id`='%i', "
"`charges`='%i', `aug_1`='%i', `aug_2`='%i', `aug_3`='%i', `aug_4`='%i', `aug_5`='%i'", "`charges`='%i', `aug_1`='%i', `aug_2`='%i', `aug_3`='%i', `aug_4`='%i', `aug_5`='%i'",
lastid, QS->items[i].from_id, QS->items[i].from_slot, QS->items[i].to_id, QS->items[i].to_slot, QS->items[i].item_id, lastid, QS->items[i].from_id, QS->items[i].from_slot, QS->items[i].to_id, QS->items[i].to_slot, QS->items[i].item_id,
QS->items[i].charges, QS->items[i].aug_1, QS->items[i].aug_2, QS->items[i].aug_3, QS->items[i].aug_4, QS->items[i].aug_5, QS->items[i].charges, QS->items[i].aug_1, QS->items[i].aug_2, QS->items[i].aug_3, QS->items[i].aug_4, QS->items[i].aug_5,
errbuf, 0, 0))) { errbuf, 0, 0))) {
_log(NET__WORLD, "Failed Trade Log Record Entry Insert: %s", errbuf); _log(QUERYSERV__ERROR, "Failed Trade Log Record Entry Insert: %s", errbuf);
_log(NET__WORLD, "%s", query); _log(QUERYSERV__ERROR, "%s", query);
} }
} }
} }
} }
void Database::LogPlayerHandin(QSPlayerLogHandin_Struct* QS, uint32 Items) { void Database::LogPlayerHandin(QSPlayerLogHandin_Struct* QS, uint32 DetailCount) {
char errbuf[MYSQL_ERRMSG_SIZE]; char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0; char* query = 0;
uint32 lastid = 0; uint32 lastid = 0;
@ -194,20 +159,20 @@ void Database::LogPlayerHandin(QSPlayerLogHandin_Struct* QS, uint32 Items) {
QS->quest_id, QS->char_id, QS->char_money.platinum, QS->char_money.gold, QS->char_money.silver, QS->char_money.copper, QS->char_count, QS->quest_id, QS->char_id, QS->char_money.platinum, QS->char_money.gold, QS->char_money.silver, QS->char_money.copper, QS->char_count,
QS->npc_id, QS->npc_money.platinum, QS->npc_money.gold, QS->npc_money.silver, QS->npc_money.copper, QS->npc_count), QS->npc_id, QS->npc_money.platinum, QS->npc_money.gold, QS->npc_money.silver, QS->npc_money.copper, QS->npc_count),
errbuf, 0, 0, &lastid)) { errbuf, 0, 0, &lastid)) {
_log(NET__WORLD, "Failed Handin Log Record Insert: %s", errbuf); _log(QUERYSERV__ERROR, "Failed Handin Log Record Insert: %s", errbuf);
_log(NET__WORLD, "%s", query); _log(QUERYSERV__ERROR, "%s", query);
} }
if(Items > 0) { if(DetailCount > 0) {
for(int i = 0; i < Items; i++) { for(int i = 0; i < DetailCount; i++) {
if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_player_handin_record_entries` SET `event_id`='%i', " if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_player_handin_record_entries` SET `event_id`='%i', "
"`action_type`='%s', `char_slot`='%i', `item_id`='%i', `charges`='%i', " "`action_type`='%s', `char_slot`='%i', `item_id`='%i', `charges`='%i', "
"`aug_1`='%i', `aug_2`='%i', `aug_3`='%i', `aug_4`='%i', `aug_5`='%i'", "`aug_1`='%i', `aug_2`='%i', `aug_3`='%i', `aug_4`='%i', `aug_5`='%i'",
lastid, QS->items[i].action_type, QS->items[i].char_slot, QS->items[i].item_id, QS->items[i].charges, lastid, QS->items[i].action_type, QS->items[i].char_slot, QS->items[i].item_id, QS->items[i].charges,
QS->items[i].aug_1, QS->items[i].aug_2, QS->items[i].aug_3, QS->items[i].aug_4, QS->items[i].aug_5, QS->items[i].aug_1, QS->items[i].aug_2, QS->items[i].aug_3, QS->items[i].aug_4, QS->items[i].aug_5,
errbuf, 0, 0))) { errbuf, 0, 0))) {
_log(NET__WORLD, "Failed Handin Log Record Entry Insert: %s", errbuf); _log(QUERYSERV__ERROR, "Failed Handin Log Record Entry Insert: %s", errbuf);
_log(NET__WORLD, "%s", query); _log(QUERYSERV__ERROR, "%s", query);
} }
} }
} }
@ -218,15 +183,15 @@ void Database::LogPlayerNPCKill(QSPlayerLogNPCKill_Struct* QS, uint32 Members){
char* query = 0; char* query = 0;
uint32 lastid = 0; uint32 lastid = 0;
if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_player_npc_kill_record` SET `npc_id`='%i', `type`='%i', `zone_id`='%i', `time`=NOW()", QS->s1.NPCID, QS->s1.Type, QS->s1.ZoneID), errbuf, 0, 0, &lastid)) { if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_player_npc_kill_record` SET `npc_id`='%i', `type`='%i', `zone_id`='%i', `time`=NOW()", QS->s1.NPCID, QS->s1.Type, QS->s1.ZoneID), errbuf, 0, 0, &lastid)) {
_log(NET__WORLD, "Failed NPC Kill Log Record Insert: %s", errbuf); _log(QUERYSERV__ERROR, "Failed NPC Kill Log Record Insert: %s", errbuf);
_log(NET__WORLD, "%s", query); _log(QUERYSERV__ERROR, "%s", query);
} }
if(Members > 0){ if(Members > 0){
for (int i = 0; i < Members; i++) { for (int i = 0; i < Members; i++) {
if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_player_npc_kill_record_entries` SET `event_id`='%i', `char_id`='%i'", lastid, QS->Chars[i].char_id, errbuf, 0, 0))) { if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_player_npc_kill_record_entries` SET `event_id`='%i', `char_id`='%i'", lastid, QS->Chars[i].char_id, errbuf, 0, 0))) {
_log(NET__WORLD, "Failed NPC Kill Log Entry Insert: %s", errbuf); _log(QUERYSERV__ERROR, "Failed NPC Kill Log Entry Insert: %s", errbuf);
_log(NET__WORLD, "%s", query); _log(QUERYSERV__ERROR, "%s", query);
} }
} }
} }
@ -241,8 +206,8 @@ void Database::LogPlayerDelete(QSPlayerLogDelete_Struct* QS, uint32 Items) {
"`char_id`='%i', `stack_size`='%i', `char_items`='%i'", "`char_id`='%i', `stack_size`='%i', `char_items`='%i'",
QS->char_id, QS->stack_size, QS->char_count, QS->char_count), QS->char_id, QS->stack_size, QS->char_count, QS->char_count),
errbuf, 0, 0, &lastid)) { errbuf, 0, 0, &lastid)) {
_log(NET__WORLD, "Failed Delete Log Record Insert: %s", errbuf); _log(QUERYSERV__ERROR, "Failed Delete Log Record Insert: %s", errbuf);
_log(NET__WORLD, "%s", query); _log(QUERYSERV__ERROR, "%s", query);
} }
if(Items > 0) { if(Items > 0) {
@ -253,15 +218,15 @@ void Database::LogPlayerDelete(QSPlayerLogDelete_Struct* QS, uint32 Items) {
lastid, QS->items[i].char_slot, QS->items[i].item_id, QS->items[i].charges, QS->items[i].aug_1, lastid, QS->items[i].char_slot, QS->items[i].item_id, QS->items[i].charges, QS->items[i].aug_1,
QS->items[i].aug_2, QS->items[i].aug_3, QS->items[i].aug_4, QS->items[i].aug_5, QS->items[i].aug_2, QS->items[i].aug_3, QS->items[i].aug_4, QS->items[i].aug_5,
errbuf, 0, 0))) { errbuf, 0, 0))) {
_log(NET__WORLD, "Failed Delete Log Record Entry Insert: %s", errbuf); _log(QUERYSERV__ERROR, "Failed Delete Log Record Entry Insert: %s", errbuf);
_log(NET__WORLD, "%s", query); _log(QUERYSERV__ERROR, "%s", query);
} }
} }
} }
} }
void Database::LogPlayerMove(QSPlayerLogMove_Struct* QS, uint32 Items) { void Database::LogPlayerMove(QSPlayerLogMove_Struct* QS, uint32 Items) {
/* These are item moves */
char errbuf[MYSQL_ERRMSG_SIZE]; char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0; char* query = 0;
uint32 lastid = 0; uint32 lastid = 0;
@ -269,10 +234,9 @@ void Database::LogPlayerMove(QSPlayerLogMove_Struct* QS, uint32 Items) {
"`char_id`='%i', `from_slot`='%i', `to_slot`='%i', `stack_size`='%i', `char_items`='%i', `postaction`='%i'", "`char_id`='%i', `from_slot`='%i', `to_slot`='%i', `stack_size`='%i', `char_items`='%i', `postaction`='%i'",
QS->char_id, QS->from_slot, QS->to_slot, QS->stack_size, QS->char_count, QS->postaction), QS->char_id, QS->from_slot, QS->to_slot, QS->stack_size, QS->char_count, QS->postaction),
errbuf, 0, 0, &lastid)) { errbuf, 0, 0, &lastid)) {
_log(NET__WORLD, "Failed Move Log Record Insert: %s", errbuf); _log(QUERYSERV__ERROR, "Failed Move Log Record Insert: %s", errbuf);
_log(NET__WORLD, "%s", query); _log(QUERYSERV__ERROR, "%s", query);
} }
if(Items > 0) { if(Items > 0) {
for(int i = 0; i < Items; i++) { for(int i = 0; i < Items; i++) {
if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_player_move_record_entries` SET `event_id`='%i', " if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_player_move_record_entries` SET `event_id`='%i', "
@ -281,16 +245,15 @@ void Database::LogPlayerMove(QSPlayerLogMove_Struct* QS, uint32 Items) {
QS->items[i].from_slot, QS->items[i].to_slot, QS->items[i].item_id, QS->items[i].charges, QS->items[i].from_slot, QS->items[i].to_slot, QS->items[i].item_id, QS->items[i].charges,
QS->items[i].aug_1, QS->items[i].aug_2, QS->items[i].aug_3, QS->items[i].aug_4, QS->items[i].aug_5, QS->items[i].aug_1, QS->items[i].aug_2, QS->items[i].aug_3, QS->items[i].aug_4, QS->items[i].aug_5,
errbuf, 0, 0))) { errbuf, 0, 0))) {
_log(NET__WORLD, "Failed Move Log Record Entry Insert: %s", errbuf); _log(QUERYSERV__ERROR, "Failed Move Log Record Entry Insert: %s", errbuf);
_log(NET__WORLD, "%s", query); _log(QUERYSERV__ERROR, "%s", query);
} }
} }
} }
} }
void Database::LogMerchantTransaction(QSMerchantLogTransaction_Struct* QS, uint32 Items) { void Database::LogMerchantTransaction(QSMerchantLogTransaction_Struct* QS, uint32 Items) {
// Merchant transactions are from the perspective of the merchant, not the player -U /* Merchant transactions are from the perspective of the merchant, not the player -U */
char errbuf[MYSQL_ERRMSG_SIZE]; char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0; char* query = 0;
uint32 lastid = 0; uint32 lastid = 0;
@ -300,8 +263,8 @@ void Database::LogMerchantTransaction(QSMerchantLogTransaction_Struct* QS, uint3
QS->zone_id, QS->merchant_id, QS->merchant_money.platinum, QS->merchant_money.gold, QS->merchant_money.silver, QS->merchant_money.copper, QS->merchant_count, QS->zone_id, QS->merchant_id, QS->merchant_money.platinum, QS->merchant_money.gold, QS->merchant_money.silver, QS->merchant_money.copper, QS->merchant_count,
QS->char_id, QS->char_money.platinum, QS->char_money.gold, QS->char_money.silver, QS->char_money.copper, QS->char_count), QS->char_id, QS->char_money.platinum, QS->char_money.gold, QS->char_money.silver, QS->char_money.copper, QS->char_count),
errbuf, 0, 0, &lastid)) { errbuf, 0, 0, &lastid)) {
_log(NET__WORLD, "Failed Transaction Log Record Insert: %s", errbuf); _log(QUERYSERV__ERROR, "Failed Transaction Log Record Insert: %s", errbuf);
_log(NET__WORLD, "%s", query); _log(QUERYSERV__ERROR, "%s", query);
} }
if(Items > 0) { if(Items > 0) {
@ -312,10 +275,29 @@ void Database::LogMerchantTransaction(QSMerchantLogTransaction_Struct* QS, uint3
lastid, QS->items[i].char_slot, QS->items[i].item_id, QS->items[i].charges, QS->items[i].aug_1, lastid, QS->items[i].char_slot, QS->items[i].item_id, QS->items[i].charges, QS->items[i].aug_1,
QS->items[i].aug_2, QS->items[i].aug_3, QS->items[i].aug_4, QS->items[i].aug_5, QS->items[i].aug_2, QS->items[i].aug_3, QS->items[i].aug_4, QS->items[i].aug_5,
errbuf, 0, 0))) { errbuf, 0, 0))) {
_log(NET__WORLD, "Failed Transaction Log Record Entry Insert: %s", errbuf); _log(QUERYSERV__ERROR, "Failed Transaction Log Record Entry Insert: %s", errbuf);
_log(NET__WORLD, "%s", query); _log(QUERYSERV__ERROR, "%s", query);
} }
} }
} }
safe_delete_array(query);
} }
void Database::GeneralQueryReceive(ServerPacket *pack) {
/*
These are general queries passed from anywhere in zone instead of packing structures and breaking them down again and again
*/
char *Query = nullptr;
Query = new char[pack->ReadUInt32() + 1];
pack->ReadString(Query);
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
uint32 lastid = 0;
if (!RunQuery(query, MakeAnyLenString(&query, Query), errbuf, 0, 0, &lastid)) {
_log(QUERYSERV__ERROR, "Failed Delete Log Record Insert: %s", errbuf);
_log(QUERYSERV__ERROR, "%s", query);
}
safe_delete_array(query);
safe_delete(pack);
safe_delete(Query);
}

View File

@ -42,14 +42,14 @@ public:
bool Connect(const char* host, const char* user, const char* passwd, const char* database,uint32 port); bool Connect(const char* host, const char* user, const char* passwd, const char* database,uint32 port);
~Database(); ~Database();
bool GetVariable(const char* varname, char* varvalue, uint16 varvalue_len);
void AddSpeech(const char* from, const char* to, const char* message, uint16 minstatus, uint32 guilddbid, uint8 type); void AddSpeech(const char* from, const char* to, const char* message, uint16 minstatus, uint32 guilddbid, uint8 type);
void LogPlayerTrade(QSPlayerLogTrade_Struct* QS, uint32 Items); void LogPlayerTrade(QSPlayerLogTrade_Struct* QS, uint32 DetailCount);
void LogPlayerHandin(QSPlayerLogHandin_Struct* QS, uint32 Items); void LogPlayerHandin(QSPlayerLogHandin_Struct* QS, uint32 DetailCount);
void LogPlayerNPCKill(QSPlayerLogNPCKill_Struct* QS, uint32 Members); void LogPlayerNPCKill(QSPlayerLogNPCKill_Struct* QS, uint32 Members);
void LogPlayerDelete(QSPlayerLogDelete_Struct* QS, uint32 Items); void LogPlayerDelete(QSPlayerLogDelete_Struct* QS, uint32 Items);
void LogPlayerMove(QSPlayerLogMove_Struct* QS, uint32 Items); void LogPlayerMove(QSPlayerLogMove_Struct* QS, uint32 Items);
void LogMerchantTransaction(QSMerchantLogTransaction_Struct* QS, uint32 Items); void LogMerchantTransaction(QSMerchantLogTransaction_Struct* QS, uint32 Items);
void GeneralQueryReceive(ServerPacket *pack);
protected: protected:
void HandleMysqlError(uint32 errnum); void HandleMysqlError(uint32 errnum);
private: private:

View File

@ -33,24 +33,15 @@
volatile bool RunLoops = true; volatile bool RunLoops = true;
uint32 MailMessagesSent = 0;
uint32 ChatMessagesSent = 0;
TimeoutManager timeout_manager; TimeoutManager timeout_manager;
Database database; Database database;
LFGuildManager lfguildmanager; LFGuildManager lfguildmanager;
std::string WorldShortName; std::string WorldShortName;
const queryservconfig *Config; const queryservconfig *Config;
WorldServer *worldserver = 0; WorldServer *worldserver = 0;
void CatchSignal(int sig_num) { void CatchSignal(int sig_num) {
RunLoops = false; RunLoops = false;
if(worldserver) if(worldserver)
worldserver->Disconnect(); worldserver->Disconnect();
} }
@ -58,31 +49,31 @@ void CatchSignal(int sig_num) {
int main() { int main() {
RegisterExecutablePlatform(ExePlatformQueryServ); RegisterExecutablePlatform(ExePlatformQueryServ);
set_exception_handler(); set_exception_handler();
Timer LFGuildExpireTimer(60000); Timer LFGuildExpireTimer(60000);
Timer InterserverTimer(INTERSERVER_TIMER); // does auto-reconnect Timer InterserverTimer(INTERSERVER_TIMER); // does auto-reconnect
/* Load XML from eqemu_config.xml
<qsdatabase>
<host>127.0.0.1</host>
<port>3306</port>
<username>user</username>
<password>password</password>
<db>dbname</db>
</qsdatabase>
*/
_log(QUERYSERV__INIT, "Starting EQEmu QueryServ."); _log(QUERYSERV__INIT, "Starting EQEmu QueryServ.");
if (!queryservconfig::LoadConfig()) { if (!queryservconfig::LoadConfig()) {
_log(QUERYSERV__INIT, "Loading server configuration failed."); _log(QUERYSERV__INIT, "Loading server configuration failed.");
return 1; return 1;
} }
Config = queryservconfig::get(); Config = queryservconfig::get();
if(!load_log_settings(Config->LogSettingsFile.c_str()))
_log(QUERYSERV__INIT, "Warning: Unable to read %s", Config->LogSettingsFile.c_str());
else
_log(QUERYSERV__INIT, "Log settings loaded from %s", Config->LogSettingsFile.c_str());
WorldShortName = Config->ShortName; WorldShortName = Config->ShortName;
_log(QUERYSERV__INIT, "Connecting to MySQL..."); _log(QUERYSERV__INIT, "Connecting to MySQL...");
/* MySQL Connection */
if (!database.Connect( if (!database.Connect(
Config->QSDatabaseHost.c_str(), Config->QSDatabaseHost.c_str(),
Config->QSDatabaseUsername.c_str(), Config->QSDatabaseUsername.c_str(),
@ -93,6 +84,12 @@ int main() {
return 1; return 1;
} }
/* Initialize Logging */
if (!load_log_settings(Config->LogSettingsFile.c_str()))
_log(QUERYSERV__INIT, "Warning: Unable to read %s", Config->LogSettingsFile.c_str());
else
_log(QUERYSERV__INIT, "Log settings loaded from %s", Config->LogSettingsFile.c_str());
if (signal(SIGINT, CatchSignal) == SIG_ERR) { if (signal(SIGINT, CatchSignal) == SIG_ERR) {
_log(QUERYSERV__ERROR, "Could not set signal handler"); _log(QUERYSERV__ERROR, "Could not set signal handler");
return 1; return 1;
@ -102,16 +99,15 @@ int main() {
return 1; return 1;
} }
/* Initial Connection to Worldserver */
worldserver = new WorldServer; worldserver = new WorldServer;
worldserver->Connect(); worldserver->Connect();
/* Load Looking For Guild Manager */
lfguildmanager.LoadDatabase(); lfguildmanager.LoadDatabase();
while(RunLoops) { while(RunLoops) {
Timer::SetCurrentTime(); Timer::SetCurrentTime();
if(LFGuildExpireTimer.Check()) if(LFGuildExpireTimer.Check())
lfguildmanager.ExpireEntries(); lfguildmanager.ExpireEntries();
@ -120,9 +116,7 @@ int main() {
worldserver->AsyncConnect(); worldserver->AsyncConnect();
} }
worldserver->Process(); worldserver->Process();
timeout_manager.CheckTimeouts(); timeout_manager.CheckTimeouts();
Sleep(100); Sleep(100);
} }
} }

View File

@ -57,121 +57,106 @@ void WorldServer::OnConnected()
void WorldServer::Process() void WorldServer::Process()
{ {
WorldConnection::Process(); WorldConnection::Process();
if (!Connected()) if (!Connected())
return; return;
ServerPacket *pack = 0; ServerPacket *pack = 0;
while((pack = tcpc.PopPacket())) while((pack = tcpc.PopPacket()))
{ {
_log(QUERYSERV__TRACE, "Received Opcode: %4X", pack->opcode); _log(QUERYSERV__TRACE, "Received Opcode: %4X", pack->opcode);
switch(pack->opcode) {
switch(pack->opcode)
{
case 0: { case 0: {
break; break;
} }
case ServerOP_KeepAlive: case ServerOP_KeepAlive: {
{
break; break;
} }
case ServerOP_Speech: case ServerOP_Speech: {
{
Server_Speech_Struct *SSS = (Server_Speech_Struct*)pack->pBuffer; Server_Speech_Struct *SSS = (Server_Speech_Struct*)pack->pBuffer;
std::string tmp1 = SSS->from; std::string tmp1 = SSS->from;
std::string tmp2 = SSS->to; std::string tmp2 = SSS->to;
database.AddSpeech(tmp1.c_str(), tmp2.c_str(), SSS->message, SSS->minstatus, SSS->guilddbid, SSS->type); database.AddSpeech(tmp1.c_str(), tmp2.c_str(), SSS->message, SSS->minstatus, SSS->guilddbid, SSS->type);
break; break;
} }
case ServerOP_QSPlayerLogTrades: case ServerOP_QSPlayerLogTrades: {
{
QSPlayerLogTrade_Struct *QS = (QSPlayerLogTrade_Struct*)pack->pBuffer; QSPlayerLogTrade_Struct *QS = (QSPlayerLogTrade_Struct*)pack->pBuffer;
uint32 Items = QS->char1_count + QS->char2_count; database.LogPlayerTrade(QS, QS->_detail_count);
database.LogPlayerTrade(QS, Items);
break; break;
} }
case ServerOP_QSPlayerLogHandins: case ServerOP_QSPlayerLogHandins: {
{
QSPlayerLogHandin_Struct *QS = (QSPlayerLogHandin_Struct*)pack->pBuffer; QSPlayerLogHandin_Struct *QS = (QSPlayerLogHandin_Struct*)pack->pBuffer;
uint32 Items = QS->char_count + QS->npc_count; database.LogPlayerHandin(QS, QS->_detail_count);
database.LogPlayerHandin(QS, Items);
break; break;
} }
case ServerOP_QSPlayerLogNPCKills: case ServerOP_QSPlayerLogNPCKills: {
{
QSPlayerLogNPCKill_Struct *QS = (QSPlayerLogNPCKill_Struct*)pack->pBuffer; QSPlayerLogNPCKill_Struct *QS = (QSPlayerLogNPCKill_Struct*)pack->pBuffer;
uint32 Members = pack->size - sizeof(QSPlayerLogNPCKill_Struct); uint32 Members = pack->size - sizeof(QSPlayerLogNPCKill_Struct);
if (Members > 0) Members = Members / sizeof(QSPlayerLogNPCKillsPlayers_Struct); if (Members > 0) Members = Members / sizeof(QSPlayerLogNPCKillsPlayers_Struct);
database.LogPlayerNPCKill(QS, Members); database.LogPlayerNPCKill(QS, Members);
break; break;
} }
case ServerOP_QSPlayerLogDeletes: case ServerOP_QSPlayerLogDeletes: {
{
QSPlayerLogDelete_Struct *QS = (QSPlayerLogDelete_Struct*)pack->pBuffer; QSPlayerLogDelete_Struct *QS = (QSPlayerLogDelete_Struct*)pack->pBuffer;
uint32 Items = QS->char_count; uint32 Items = QS->char_count;
database.LogPlayerDelete(QS, Items); database.LogPlayerDelete(QS, Items);
break; break;
} }
case ServerOP_QSPlayerLogMoves: case ServerOP_QSPlayerLogMoves: {
{
QSPlayerLogMove_Struct *QS = (QSPlayerLogMove_Struct*)pack->pBuffer; QSPlayerLogMove_Struct *QS = (QSPlayerLogMove_Struct*)pack->pBuffer;
uint32 Items = QS->char_count; uint32 Items = QS->char_count;
database.LogPlayerMove(QS, Items); database.LogPlayerMove(QS, Items);
break; break;
} }
case ServerOP_QSMerchantLogTransactions: case ServerOP_QSPlayerLogMerchantTransactions: {
{
QSMerchantLogTransaction_Struct *QS = (QSMerchantLogTransaction_Struct*)pack->pBuffer; QSMerchantLogTransaction_Struct *QS = (QSMerchantLogTransaction_Struct*)pack->pBuffer;
uint32 Items = QS->char_count + QS->merchant_count; uint32 Items = QS->char_count + QS->merchant_count;
database.LogMerchantTransaction(QS, Items); database.LogMerchantTransaction(QS, Items);
break; break;
} }
case ServerOP_QueryServGeneric: case ServerOP_QueryServGeneric: {
{ /*
// The purpose of ServerOP_QueryServerGeneric is so that we don't have to add code to world just to relay packets The purpose of ServerOP_QueryServerGeneric is so that we don't have to add code to world just to relay packets
// each time we add functionality to queryserv. each time we add functionality to queryserv.
//
// A ServerOP_QueryServGeneric packet has the following format: A ServerOP_QueryServGeneric packet has the following format:
//
// uint32 SourceZoneID uint32 SourceZoneID
// uint32 SourceInstanceID uint32 SourceInstanceID
// char OriginatingCharacterName[0] // Null terminated name of the character this packet came from. This could be just char OriginatingCharacterName[0]
// // an empty string if it has no meaning in the context of a particular packet. - Null terminated name of the character this packet came from. This could be just
// uint32 Type - an empty string if it has no meaning in the context of a particular packet.
// uint32 Type
// The 'Type' field is a 'sub-opcode'. A value of 0 is used for the LFGuild packets. The next feature to be added
// to queryserv would use 1, etc. The 'Type' field is a 'sub-opcode'. A value of 0 is used for the LFGuild packets. The next feature to be added
// to queryserv would use 1, etc.
// Obviously, any fields in the packet following the 'Type' will be unique to the particular type of packet. The
// 'Generic' in the name of this ServerOP code relates to the four header fields. Obviously, any fields in the packet following the 'Type' will be unique to the particular type of packet. The
'Generic' in the name of this ServerOP code relates to the four header fields.
*/
char From[64]; char From[64];
pack->SetReadPosition(8); pack->SetReadPosition(8);
pack->ReadString(From); pack->ReadString(From);
uint32 Type = pack->ReadUInt32(); uint32 Type = pack->ReadUInt32();
switch(Type) switch(Type) {
{ case QSG_LFGuild:{
case QSG_LFGuild:
{
lfguildmanager.HandlePacket(pack); lfguildmanager.HandlePacket(pack);
break; break;
} }
default: default:
_log(QUERYSERV__ERROR, "Received unhandled ServerOP_QueryServGeneric", Type); _log(QUERYSERV__ERROR, "Received unhandled ServerOP_QueryServGeneric", Type);
break; break;
} }
break; break;
} }
case ServerOP_QSSendQuery: {
/* Process all packets here */
database.GeneralQueryReceive(pack);
break;
}
} }
} }
safe_delete(pack); safe_delete(pack);
return; return;
} }

View File

@ -7,12 +7,13 @@ SET(tests_sources
) )
SET(tests_headers SET(tests_headers
atobool_test.h
fixed_memory_test.h fixed_memory_test.h
fixed_memory_variable_test.h fixed_memory_variable_test.h
hextoi_32_64_test.h
ipc_mutex_test.h ipc_mutex_test.h
memory_mapped_file_test.h memory_mapped_file_test.h
atobool_test.h string_util_test.h
hextoi_32_64_test.h
) )
ADD_EXECUTABLE(tests ${tests_sources} ${tests_headers}) ADD_EXECUTABLE(tests ${tests_sources} ${tests_headers})

View File

@ -26,6 +26,7 @@
#include "fixed_memory_variable_test.h" #include "fixed_memory_variable_test.h"
#include "atobool_test.h" #include "atobool_test.h"
#include "hextoi_32_64_test.h" #include "hextoi_32_64_test.h"
#include "string_util_test.h"
int main() { int main() {
try { try {
@ -38,6 +39,7 @@ int main() {
tests.add(new FixedMemoryVariableHashTest()); tests.add(new FixedMemoryVariableHashTest());
tests.add(new atoboolTest()); tests.add(new atoboolTest());
tests.add(new hextoi_32_64_Test()); tests.add(new hextoi_32_64_Test());
tests.add(new StringUtilTest());
tests.run(*output, true); tests.run(*output, true);
} catch(...) { } catch(...) {
return -1; return -1;

85
tests/string_util_test.h Normal file
View File

@ -0,0 +1,85 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2013 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_STRING_UTIL_H
#define __EQEMU_TESTS_STRING_UTIL_H
#include "cppunit/cpptest.h"
#include "../common/string_util.h"
class StringUtilTest : public Test::Suite {
typedef void(IPCMutexTest::*TestFunction)(void);
public:
StringUtilTest() {
TEST_ADD(StringUtilTest::StringFormatTest);
TEST_ADD(StringUtilTest::EscapeStringTest);
TEST_ADD(StringUtilTest::EscapeStringMemoryTest);
}
~StringUtilTest() {
}
private:
void StringFormatTest() {
const char* fmt = "Test: %c %d %4.2f";
char c = 'a';
int i = 2014;
float f = 3.1416;
auto s = StringFormat(fmt, c, i, f);
TEST_ASSERT_EQUALS(s.length(), 17);
TEST_ASSERT(s.compare("Test: a 2014 3.14") == 0);
}
void EscapeStringTest() {
std::string t;
t.resize(10);
t[0] = 'a';
t[1] = 'b';
t[2] = 'c';
t[3] = '\x00';
t[4] = '\n';
t[5] = '\r';
t[6] = '\\';
t[7] = '\'';
t[8] = '\"';
t[9] = '\x1a';
auto s = EscapeString(t);
TEST_ASSERT(s.compare("abc\\x00\\n\\r\\\\\\'\\\"\\x1a") == 0);
}
void EscapeStringMemoryTest() {
char t[10] = { 0 };
t[0] = 'a';
t[1] = 'b';
t[2] = 'c';
t[3] = '\x00';
t[4] = '\n';
t[5] = '\r';
t[6] = '\\';
t[7] = '\'';
t[8] = '\"';
t[9] = '\x1a';
auto s = EscapeString(t, 10);
TEST_ASSERT(s.compare("abc\\x00\\n\\r\\\\\\'\\\"\\x1a") == 0);
}
};
#endif

View File

@ -102,208 +102,143 @@ Database::~Database()
{ {
} }
void Database::GetAccountStatus(Client *c) { void Database::GetAccountStatus(Client *client) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (!RunQuery(query,MakeAnyLenString(&query, "select `status`, `hideme`, `karma`, `revoked` from `account` where `id`='%i' limit 1",
c->GetAccountID()),errbuf,&result)){
_log(UCS__ERROR, "Unable to get account status for character %s, error %s", c->GetName().c_str(), errbuf);
safe_delete_array(query);
std::string query = StringFormat("SELECT `status`, `hideme`, `karma`, `revoked` "
"FROM `account` WHERE `id` = '%i' LIMIT 1",
client->GetAccountID());
auto results = QueryDatabase(query);
if (!results.Success()) {
_log(UCS__ERROR, "Unable to get account status for character %s, error %s", client->GetName().c_str(), results.ErrorMessage().c_str());
return; return;
} }
_log(UCS__TRACE, "GetAccountStatus Query: %s", query);
safe_delete_array(query);
if(mysql_num_rows(result) != 1) _log(UCS__TRACE, "GetAccountStatus Query: %s", query.c_str());
if(results.RowCount() != 1)
{ {
_log(UCS__ERROR, "Error in GetAccountStatus"); _log(UCS__ERROR, "Error in GetAccountStatus");
mysql_free_result(result);
return; return;
} }
row = mysql_fetch_row(result); auto row = results.begin();
c->SetAccountStatus(atoi(row[0])); client->SetAccountStatus(atoi(row[0]));
c->SetHideMe(atoi(row[1]) != 0); client->SetHideMe(atoi(row[1]) != 0);
c->SetKarma(atoi(row[2])); client->SetKarma(atoi(row[2]));
c->SetRevoked((atoi(row[3])==1?true:false)); client->SetRevoked((atoi(row[3])==1?true:false));
_log(UCS__TRACE, "Set account status to %i, hideme to %i and karma to %i for %s", client->GetAccountStatus(), client->GetHideMe(), client->GetKarma(), client->GetName().c_str());
_log(UCS__TRACE, "Set account status to %i, hideme to %i and karma to %i for %s", c->GetAccountStatus(), c->GetHideMe(), c->GetKarma(), c->GetName().c_str());
mysql_free_result(result);
} }
int Database::FindAccount(const char *CharacterName, Client *c) { int Database::FindAccount(const char *characterName, Client *client) {
_log(UCS__TRACE, "FindAccount for character %s", CharacterName); _log(UCS__TRACE, "FindAccount for character %s", characterName);
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
c->ClearCharacters(); client->ClearCharacters();
std::string query = StringFormat("SELECT `id`, `account_id`, `level` "
if (!RunQuery(query,MakeAnyLenString(&query, "select `id`, `account_id`, `level` from `character_` where `name`='%s' limit 1", "FROM `character_` WHERE `name` = '%s' LIMIT 1",
CharacterName),errbuf,&result)) characterName);
{ auto results = QueryDatabase(query);
_log(UCS__ERROR, "FindAccount query failed: %s", query); if (!results.Success()) {
safe_delete_array(query); _log(UCS__ERROR, "FindAccount query failed: %s", query.c_str());
return -1; return -1;
} }
safe_delete_array(query);
if (mysql_num_rows(result) != 1) if (results.RowCount() != 1) {
{
_log(UCS__ERROR, "Bad result from query"); _log(UCS__ERROR, "Bad result from query");
mysql_free_result(result);
return -1; return -1;
} }
row = mysql_fetch_row(result); auto row = results.begin();
c->AddCharacter(atoi(row[0]), CharacterName, atoi(row[2])); client->AddCharacter(atoi(row[0]), characterName, atoi(row[2]));
int AccountID = atoi(row[1]);
mysql_free_result(result); int accountID = atoi(row[1]);
_log(UCS__TRACE, "Account ID for %s is %i", CharacterName, AccountID);
if (!RunQuery(query,MakeAnyLenString(&query, "select `id`, `name`, `level` from `character_` where `account_id`=%i and `name` !='%s'", _log(UCS__TRACE, "Account ID for %s is %i", characterName, accountID);
AccountID, CharacterName),errbuf,&result))
{
safe_delete_array(query);
return AccountID;
}
safe_delete_array(query);
for(unsigned int i = 0; i < mysql_num_rows(result); i++) query = StringFormat("SELECT `id`, `name`, `level` FROM `character_` "
{ "WHERE `account_id` = %i AND `name` != '%s'",
row = mysql_fetch_row(result); accountID, characterName);
c->AddCharacter(atoi(row[0]), row[1], atoi(row[2])); results = QueryDatabase(query);
} if (!results.Success())
mysql_free_result(result); return accountID;
return AccountID;
for (auto row = results.begin(); row != results.end(); ++row)
client->AddCharacter(atoi(row[0]), row[1], atoi(row[2]));
return accountID;
} }
bool Database::VerifyMailKey(std::string CharacterName, int IPAddress, std::string MailKey) { bool Database::VerifyMailKey(std::string characterName, int IPAddress, std::string MailKey) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (!RunQuery(query,MakeAnyLenString(&query, "select `mailkey` from `character_` where `name`='%s' limit 1",
CharacterName.c_str()),errbuf,&result)){
safe_delete_array(query);
_log(UCS__ERROR, "Error retrieving mailkey from database: %s", errbuf);
std::string query = StringFormat("SELECT `mailkey` FROM `character_` WHERE `name`='%s' LIMIT 1",
characterName.c_str());
auto results = QueryDatabase(query);
if (!results.Success()) {
_log(UCS__ERROR, "Error retrieving mailkey from database: %s", results.ErrorMessage().c_str());
return false; return false;
} }
safe_delete_array(query); auto row = results.begin();
row = mysql_fetch_row(result);
// The key is the client's IP address (expressed as 8 hex digits) and an 8 hex digit random string generated // The key is the client's IP address (expressed as 8 hex digits) and an 8 hex digit random string generated
// by world. // by world.
// //
char CombinedKey[17]; char combinedKey[17];
if(RuleB(Chat, EnableMailKeyIPVerification) == true) if(RuleB(Chat, EnableMailKeyIPVerification) == true)
sprintf(CombinedKey, "%08X%s", IPAddress, MailKey.c_str()); sprintf(combinedKey, "%08X%s", IPAddress, MailKey.c_str());
else else
sprintf(CombinedKey, "%s", MailKey.c_str()); sprintf(combinedKey, "%s", MailKey.c_str());
_log(UCS__TRACE, "DB key is [%s], Client key is [%s]", row[0], CombinedKey); _log(UCS__TRACE, "DB key is [%s], Client key is [%s]", row[0], combinedKey);
bool Valid = !strcmp(row[0], CombinedKey);
mysql_free_result(result);
return Valid;
return !strcmp(row[0], combinedKey);
} }
int Database::FindCharacter(const char *CharacterName) { int Database::FindCharacter(const char *characterName) {
char errbuf[MYSQL_ERRMSG_SIZE]; char *safeCharName = RemoveApostrophes(characterName);
char* query = 0; std::string query = StringFormat("SELECT `id` FROM `character_` WHERE `name`='%s' LIMIT 1", safeCharName);
MYSQL_RES *result; auto results = QueryDatabase(query);
MYSQL_ROW row; if (!results.Success()) {
_log(UCS__ERROR, "FindCharacter failed. %s %s", query.c_str(), results.ErrorMessage().c_str());
char *SafeCharName = RemoveApostrophes(CharacterName); safe_delete(safeCharName);
return -1;
if (!RunQuery(query,MakeAnyLenString(&query, "select `id` from `character_` where `name`='%s' limit 1", }
SafeCharName),errbuf,&result)){ safe_delete(safeCharName);
_log(UCS__ERROR, "FindCharacter failed. %s %s", query, errbuf);
safe_delete_array(query);
safe_delete_array(SafeCharName);
if (results.RowCount() != 1) {
_log(UCS__ERROR, "Bad result from FindCharacter query for character %s", characterName);
return -1; return -1;
} }
safe_delete_array(query); auto row = results.begin();
safe_delete_array(SafeCharName);
if (mysql_num_rows(result) != 1) { int characterID = atoi(row[0]);
_log(UCS__ERROR, "Bad result from FindCharacter query for character %s", CharacterName);
mysql_free_result(result);
return -1;
}
row = mysql_fetch_row(result);
int CharacterID = atoi(row[0]);
mysql_free_result(result);
return CharacterID;
return characterID;
} }
bool Database::GetVariable(const char* varname, char* varvalue, uint16 varvalue_len) { bool Database::GetVariable(const char* varname, char* varvalue, uint16 varvalue_len) {
char errbuf[MYSQL_ERRMSG_SIZE]; std::string query = StringFormat("SELECT `value` FROM `variables` WHERE `varname` = '%s'", varname);
char* query = 0; auto results = QueryDatabase(query);
MYSQL_RES *result; if (!results.Success()) {
MYSQL_ROW row; _log(UCS__ERROR, "Unable to get message count from database. %s %s", query.c_str(), results.ErrorMessage().c_str());
if (!RunQuery(query,MakeAnyLenString(&query, "select `value` from `variables` where `varname`='%s'", varname), errbuf, &result)) {
_log(UCS__ERROR, "Unable to get message count from database. %s %s", query, errbuf);
safe_delete_array(query);
return false; return false;
} }
safe_delete_array(query); if (results.RowCount() != 1)
if (mysql_num_rows(result) != 1) {
mysql_free_result(result);
return false; return false;
}
row = mysql_fetch_row(result); auto row = results.begin();
snprintf(varvalue, varvalue_len, "%s", row[0]); snprintf(varvalue, varvalue_len, "%s", row[0]);
mysql_free_result(result);
return true; return true;
} }
@ -311,302 +246,238 @@ bool Database::LoadChatChannels() {
_log(UCS__INIT, "Loading chat channels from the database."); _log(UCS__INIT, "Loading chat channels from the database.");
char errbuf[MYSQL_ERRMSG_SIZE]; const std::string query = "SELECT `name`, `owner`, `password`, `minstatus` FROM `chatchannels`";
char* query = 0; auto results = QueryDatabase(query);
MYSQL_RES *result; if (!results.Success()) {
MYSQL_ROW row; _log(UCS__ERROR, "Failed to load channels. %s %s", query.c_str(), results.ErrorMessage().c_str());
if (!RunQuery(query,MakeAnyLenString(&query, "select `name`,`owner`,`password`, `minstatus` from `chatchannels`"),errbuf,&result)){
_log(UCS__ERROR, "Failed to load channels. %s %s", query, errbuf);
safe_delete_array(query);
return false; return false;
} }
safe_delete_array(query); for (auto row = results.begin();row != results.end(); ++row) {
std::string channelName = row[0];
std::string channelOwner = row[1];
std::string channelPassword = row[2];
while((row = mysql_fetch_row(result))) { ChannelList->CreateChannel(channelName, channelOwner, channelPassword, true, atoi(row[3]));
std::string ChannelName = row[0];
std::string ChannelOwner = row[1];
std::string ChannelPassword = row[2];
ChannelList->CreateChannel(ChannelName, ChannelOwner, ChannelPassword, true, atoi(row[3]));
} }
mysql_free_result(result);
return true; return true;
} }
void Database::SetChannelPassword(std::string ChannelName, std::string Password) { void Database::SetChannelPassword(std::string channelName, std::string password) {
_log(UCS__TRACE, "Database::SetChannelPassword(%s, %s)", ChannelName.c_str(), Password.c_str()); _log(UCS__TRACE, "Database::SetChannelPassword(%s, %s)", channelName.c_str(), password.c_str());
char errbuf[MYSQL_ERRMSG_SIZE]; std::string query = StringFormat("UPDATE `chatchannels` SET `password` = '%s' WHERE `name` = '%s'",
char *query = 0; password.c_str(), channelName.c_str());
auto results = QueryDatabase(query);
if(!RunQuery(query, MakeAnyLenString(&query, "UPDATE `chatchannels` set `password`='%s' where `name`='%s'", Password.c_str(), if(!results.Success())
ChannelName.c_str()), errbuf)) { _log(UCS__ERROR, "Error updating password in database: %s, %s", query.c_str(), results.ErrorMessage().c_str());
_log(UCS__ERROR, "Error updating password in database: %s, %s", query, errbuf);
} }
safe_delete_array(query); void Database::SetChannelOwner(std::string channelName, std::string owner) {
}
void Database::SetChannelOwner(std::string ChannelName, std::string Owner) { _log(UCS__TRACE, "Database::SetChannelOwner(%s, %s)", channelName.c_str(), owner.c_str());
_log(UCS__TRACE, "Database::SetChannelOwner(%s, %s)", ChannelName.c_str(), Owner.c_str()); std::string query = StringFormat("UPDATE `chatchannels` SET `owner` = '%s' WHERE `name` = '%s'",
owner.c_str(), channelName.c_str());
char errbuf[MYSQL_ERRMSG_SIZE]; auto results = QueryDatabase(query);
char *query = 0; if(!results.Success())
_log(UCS__ERROR, "Error updating Owner in database: %s, %s", query.c_str(), results.ErrorMessage().c_str());
if(!RunQuery(query, MakeAnyLenString(&query, "UPDATE `chatchannels` set `owner`='%s' where `name`='%s'", Owner.c_str(),
ChannelName.c_str()), errbuf)) {
_log(UCS__ERROR, "Error updating Owner in database: %s, %s", query, errbuf);
} }
safe_delete_array(query); void Database::SendHeaders(Client *client) {
}
void Database::SendHeaders(Client *c) { int unknownField2 = 25015275;
int unknownField3 = 1;
int characterID = FindCharacter(client->MailBoxName().c_str());
int UnknownField2 = 25015275; _log(UCS__TRACE, "Sendheaders for %s, CharID is %i", client->MailBoxName().c_str(), characterID);
int UnknownField3 = 1;
int CharacterID = FindCharacter(c->MailBoxName().c_str()); if(characterID <= 0)
_log(UCS__TRACE, "Sendheaders for %s, CharID is %i", c->MailBoxName().c_str(), CharacterID);
if(CharacterID <= 0)
return; return;
std::string query = StringFormat("SELECT `msgid`,`timestamp`, `from`, `subject`, `status` "
char errbuf[MYSQL_ERRMSG_SIZE]; "FROM `mail` WHERE `charid`=%i", characterID);
char* query = 0; auto results = QueryDatabase(query);
MYSQL_RES *result; if (!results.Success())
MYSQL_ROW row;
if (!RunQuery(query,MakeAnyLenString(&query, "select `msgid`,`timestamp`,`from`,`subject`, `status` from `mail` "
"where `charid`=%i", CharacterID),errbuf,&result)){
safe_delete_array(query);
return; return;
}
safe_delete_array(query); char buffer[100];
char Buf[100]; int headerCountPacketLength = 0;
uint32 NumRows = mysql_num_rows(result); sprintf(buffer, "%i", client->GetMailBoxNumber());
headerCountPacketLength += (strlen(buffer) + 1);
int HeaderCountPacketLength = 0; sprintf(buffer, "%i", unknownField2);
headerCountPacketLength += (strlen(buffer) + 1);
sprintf(Buf, "%i", c->GetMailBoxNumber()); sprintf(buffer, "%i", unknownField3);
HeaderCountPacketLength += (strlen(Buf) + 1); headerCountPacketLength += (strlen(buffer) + 1);
sprintf(Buf, "%i", UnknownField2); sprintf(buffer, "%i", results.RowCount());
HeaderCountPacketLength += (strlen(Buf) + 1); headerCountPacketLength += (strlen(buffer) + 1);
sprintf(Buf, "%i", UnknownField3); EQApplicationPacket *outapp = new EQApplicationPacket(OP_MailHeaderCount, headerCountPacketLength);
HeaderCountPacketLength += (strlen(Buf) + 1);
sprintf(Buf, "%i", NumRows); char *packetBuffer = (char *)outapp->pBuffer;
HeaderCountPacketLength += (strlen(Buf) + 1);
EQApplicationPacket *outapp = new EQApplicationPacket(OP_MailHeaderCount, HeaderCountPacketLength); VARSTRUCT_ENCODE_INTSTRING(packetBuffer, client->GetMailBoxNumber());
VARSTRUCT_ENCODE_INTSTRING(packetBuffer, unknownField2);
char *PacketBuffer = (char *)outapp->pBuffer; VARSTRUCT_ENCODE_INTSTRING(packetBuffer, unknownField3);
VARSTRUCT_ENCODE_INTSTRING(packetBuffer, results.RowCount());
VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, c->GetMailBoxNumber());
VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, UnknownField2);
VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, UnknownField3);
VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, NumRows);
_pkt(UCS__PACKETS, outapp); _pkt(UCS__PACKETS, outapp);
c->QueuePacket(outapp); client->QueuePacket(outapp);
safe_delete(outapp); safe_delete(outapp);
int RowNum = 0; int rowIndex = 0;
for(auto row = results.begin(); row != results.end(); ++row, ++rowIndex) {
int headerPacketLength = 0;
while((row = mysql_fetch_row(result))) { sprintf(buffer, "%i", client->GetMailBoxNumber());
headerPacketLength += strlen(buffer) + 1;
sprintf(buffer, "%i", unknownField2);
headerPacketLength += strlen(buffer) + 1;
sprintf(buffer, "%i", rowIndex);
headerPacketLength += strlen(buffer) + 1;
headerPacketLength += strlen(row[0]) + 1;
headerPacketLength += strlen(row[1]) + 1;
headerPacketLength += strlen(row[4]) + 1;
headerPacketLength += GetMailPrefix().length() + strlen(row[2]) + 1;
headerPacketLength += strlen(row[3]) + 1;
int HeaderPacketLength = 0; outapp = new EQApplicationPacket(OP_MailHeader, headerPacketLength);
sprintf(Buf, "%i", c->GetMailBoxNumber()); packetBuffer = (char *)outapp->pBuffer;
HeaderPacketLength = HeaderPacketLength + strlen(Buf) + 1;
sprintf(Buf, "%i", UnknownField2);
HeaderPacketLength = HeaderPacketLength + strlen(Buf) + 1;
sprintf(Buf, "%i", RowNum);
HeaderPacketLength = HeaderPacketLength + strlen(Buf) + 1;
HeaderPacketLength = HeaderPacketLength + strlen(row[0]) + 1; VARSTRUCT_ENCODE_INTSTRING(packetBuffer, client->GetMailBoxNumber());
HeaderPacketLength = HeaderPacketLength + strlen(row[1]) + 1; VARSTRUCT_ENCODE_INTSTRING(packetBuffer, unknownField2);
HeaderPacketLength = HeaderPacketLength + strlen(row[4]) + 1; VARSTRUCT_ENCODE_INTSTRING(packetBuffer, rowIndex);
HeaderPacketLength = HeaderPacketLength + GetMailPrefix().length() + strlen(row[2]) + 1; VARSTRUCT_ENCODE_STRING(packetBuffer, row[0]);
HeaderPacketLength = HeaderPacketLength + strlen(row[3]) + 1; VARSTRUCT_ENCODE_STRING(packetBuffer, row[1]);
VARSTRUCT_ENCODE_STRING(packetBuffer, row[4]);
outapp = new EQApplicationPacket(OP_MailHeader, HeaderPacketLength); VARSTRUCT_ENCODE_STRING(packetBuffer, GetMailPrefix().c_str());
packetBuffer--;
PacketBuffer = (char *)outapp->pBuffer; VARSTRUCT_ENCODE_STRING(packetBuffer, row[2]);
VARSTRUCT_ENCODE_STRING(packetBuffer, row[3]);
VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, c->GetMailBoxNumber());
VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, UnknownField2);
VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, RowNum);
VARSTRUCT_ENCODE_STRING(PacketBuffer, row[0]);
VARSTRUCT_ENCODE_STRING(PacketBuffer, row[1]);
VARSTRUCT_ENCODE_STRING(PacketBuffer, row[4]);
VARSTRUCT_ENCODE_STRING(PacketBuffer, GetMailPrefix().c_str()); PacketBuffer--;
VARSTRUCT_ENCODE_STRING(PacketBuffer, row[2]);
VARSTRUCT_ENCODE_STRING(PacketBuffer, row[3]);
_pkt(UCS__PACKETS, outapp); _pkt(UCS__PACKETS, outapp);
c->QueuePacket(outapp); client->QueuePacket(outapp);
safe_delete(outapp); safe_delete(outapp);
RowNum++;
} }
mysql_free_result(result);
} }
void Database::SendBody(Client *c, int MessageNumber) { void Database::SendBody(Client *client, int messageNumber) {
int CharacterID = FindCharacter(c->MailBoxName().c_str()); int characterID = FindCharacter(client->MailBoxName().c_str());
_log(UCS__TRACE, "SendBody: MsgID %i, to %s, CharID is %i", MessageNumber, c->MailBoxName().c_str(), CharacterID); _log(UCS__TRACE, "SendBody: MsgID %i, to %s, CharID is %i", messageNumber, client->MailBoxName().c_str(), characterID);
if(CharacterID <= 0) if(characterID <= 0)
return; return;
char errbuf[MYSQL_ERRMSG_SIZE]; std::string query = StringFormat("SELECT `msgid`, `body`, `to` FROM `mail` "
char* query = 0; "WHERE `charid`=%i AND `msgid`=%i", characterID, messageNumber);
MYSQL_RES *result; auto results = QueryDatabase(query);
MYSQL_ROW row; if (!results.Success())
if (!RunQuery(query,MakeAnyLenString(&query, "select `msgid`, `body`, `to` from `mail` "
"where `charid`=%i and `msgid`=%i", CharacterID, MessageNumber), errbuf, &result)){
safe_delete_array(query);
return; return;
}
safe_delete_array(query);
if (mysql_num_rows(result) != 1) {
mysql_free_result(result);
if (results.RowCount() != 1)
return; return;
}
row = mysql_fetch_row(result); auto row = results.begin();
_log(UCS__TRACE, "Message: %i body (%i bytes)", MessageNumber, strlen(row[1])); _log(UCS__TRACE, "Message: %i body (%i bytes)", messageNumber, strlen(row[1]));
int PacketLength = 12 + strlen(row[0]) + strlen(row[1]) + strlen(row[2]); int packetLength = 12 + strlen(row[0]) + strlen(row[1]) + strlen(row[2]);
EQApplicationPacket *outapp = new EQApplicationPacket(OP_MailSendBody,PacketLength); EQApplicationPacket *outapp = new EQApplicationPacket(OP_MailSendBody,packetLength);
char *PacketBuffer = (char *)outapp->pBuffer; char *packetBuffer = (char *)outapp->pBuffer;
VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, c->GetMailBoxNumber()); VARSTRUCT_ENCODE_INTSTRING(packetBuffer, client->GetMailBoxNumber());
VARSTRUCT_ENCODE_STRING(PacketBuffer,row[0]); VARSTRUCT_ENCODE_STRING(packetBuffer,row[0]);
VARSTRUCT_ENCODE_STRING(PacketBuffer,row[1]); VARSTRUCT_ENCODE_STRING(packetBuffer,row[1]);
VARSTRUCT_ENCODE_STRING(PacketBuffer,"1"); VARSTRUCT_ENCODE_STRING(packetBuffer,"1");
VARSTRUCT_ENCODE_TYPE(uint8, PacketBuffer, 0); VARSTRUCT_ENCODE_TYPE(uint8, packetBuffer, 0);
VARSTRUCT_ENCODE_TYPE(uint8, PacketBuffer, 0x0a); VARSTRUCT_ENCODE_TYPE(uint8, packetBuffer, 0x0a);
VARSTRUCT_ENCODE_STRING(PacketBuffer, "TO:"); PacketBuffer--; VARSTRUCT_ENCODE_STRING(packetBuffer, "TO:");
VARSTRUCT_ENCODE_STRING(PacketBuffer, row[2]); PacketBuffer--; // Overwrite the null terminator packetBuffer--;
VARSTRUCT_ENCODE_TYPE(uint8, PacketBuffer, 0x0a); VARSTRUCT_ENCODE_STRING(packetBuffer, row[2]);
packetBuffer--; // Overwrite the null terminator
mysql_free_result(result); VARSTRUCT_ENCODE_TYPE(uint8, packetBuffer, 0x0a);
_pkt(UCS__PACKETS, outapp); _pkt(UCS__PACKETS, outapp);
c->QueuePacket(outapp); client->QueuePacket(outapp);
safe_delete(outapp); safe_delete(outapp);
} }
bool Database::SendMail(std::string Recipient, std::string From, std::string Subject, std::string Body, std::string RecipientsString) { bool Database::SendMail(std::string recipient, std::string from, std::string subject, std::string body, std::string recipientsString) {
int CharacterID; int characterID;
std::string characterName;
std::string CharacterName; auto lastPeriod = recipient.find_last_of(".");
//printf("Database::SendMail(%s, %s, %s)\n", Recipient.c_str(), From.c_str(), Subject.c_str()); if(lastPeriod == std::string::npos)
characterName = recipient;
std::string::size_type LastPeriod = Recipient.find_last_of(".");
if(LastPeriod == std::string::npos)
CharacterName = Recipient;
else else
CharacterName = Recipient.substr(LastPeriod+1); characterName = recipient.substr(lastPeriod+1);
CharacterName[0] = toupper(CharacterName[0]); characterName[0] = toupper(characterName[0]);
for(unsigned int i = 1; i < CharacterName.length(); i++) for(unsigned int i = 1; i < characterName.length(); i++)
CharacterName[i] = tolower(CharacterName[i]); characterName[i] = tolower(characterName[i]);
CharacterID = FindCharacter(CharacterName.c_str()); characterID = FindCharacter(characterName.c_str());
_log(UCS__TRACE, "SendMail: CharacterID for recipient %s is %i", CharacterName.c_str(), CharacterID); _log(UCS__TRACE, "SendMail: CharacterID for recipient %s is %i", characterName.c_str(), characterID);
if(CharacterID <= 0) return false; if(characterID <= 0)
return false;
char errbuf[MYSQL_ERRMSG_SIZE]; char *escSubject = new char[subject.length() * 2 + 1];
char* query = 0; char *escBody = new char[body.length() * 2 + 1];
char *EscSubject = new char[Subject.length() * 2 + 1]; DoEscapeString(escSubject, subject.c_str(), subject.length());
char *EscBody = new char[Body.length() * 2 + 1]; DoEscapeString(escBody, body.c_str(), body.length());
DoEscapeString(EscSubject, Subject.c_str(), Subject.length()); int now = time(nullptr); // time returns a 64 bit int on Windows at least, which vsnprintf doesn't like.
DoEscapeString(EscBody, Body.c_str(), Body.length());
const char *MailQuery="INSERT INTO `mail` (`charid`, `timestamp`, `from`, `subject`, `body`, `to`, `status`) "
"VALUES ('%i', %i, '%s', '%s', '%s', '%s', %i)";
uint32 LastMsgID;
int Now = time(nullptr); // time returns a 64 bit int on Windows at least, which vsnprintf doesn't like.
if(!RunQuery(query, MakeAnyLenString(&query, MailQuery, CharacterID, Now, From.c_str(), EscSubject, EscBody,
RecipientsString.c_str(), 1), errbuf, 0, 0, &LastMsgID)) {
_log(UCS__ERROR, "SendMail: Query %s failed with error %s", query, errbuf);
safe_delete_array(EscSubject);
safe_delete_array(EscBody);
safe_delete_array(query);
std::string query = StringFormat("INSERT INTO `mail` "
"(`charid`, `timestamp`, `from`, `subject`, `body`, `to`, `status`) "
"VALUES ('%i', %i, '%s', '%s', '%s', '%s', %i)",
characterID, now, from.c_str(), escSubject, escBody,
recipientsString.c_str(), 1);
safe_delete_array(escSubject);
safe_delete_array(escBody);
auto results = QueryDatabase(query);
if(!results.Success()) {
_log(UCS__ERROR, "SendMail: Query %s failed with error %s", query.c_str(), results.ErrorMessage().c_str());
return false; return false;
} }
_log(UCS__TRACE, "MessageID %i generated, from %s, to %s", LastMsgID, From.c_str(), Recipient.c_str()); _log(UCS__TRACE, "MessageID %i generated, from %s, to %s", results.LastInsertedID(), from.c_str(), recipient.c_str());
safe_delete_array(EscSubject);
safe_delete_array(EscBody);
safe_delete_array(query);
Client *c = CL->IsCharacterOnline(CharacterName); Client *client = CL->IsCharacterOnline(characterName);
if(c) { if(client) {
std::string FQN = GetMailPrefix() + From; std::string FQN = GetMailPrefix() + from;
client->SendNotification(client->GetMailBoxNumber(characterName), subject, FQN, results.LastInsertedID());
c->SendNotification(c->GetMailBoxNumber(CharacterName), Subject, FQN, LastMsgID);
} }
MailMessagesSent++; MailMessagesSent++;
@ -614,156 +485,122 @@ bool Database::SendMail(std::string Recipient, std::string From, std::string Sub
return true; return true;
} }
void Database::SetMessageStatus(int MessageNumber, int Status) { void Database::SetMessageStatus(int messageNumber, int status) {
_log(UCS__TRACE, "SetMessageStatus %i %i", MessageNumber, Status); _log(UCS__TRACE, "SetMessageStatus %i %i", messageNumber, status);
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(Status == 0)
RunQuery(query, MakeAnyLenString(&query, "delete from `mail` where `msgid`=%i", MessageNumber), errbuf);
else if (!RunQuery(query, MakeAnyLenString(&query, "update `mail` set `status`=%i where `msgid`=%i", Status, MessageNumber), errbuf)) {
_log(UCS__ERROR, "Error updating status %s, %s", query, errbuf);
if(status == 0) {
std::string query = StringFormat("DELETE FROM `mail` WHERE `msgid` = %i", messageNumber);
auto results = QueryDatabase(query);
return;
} }
safe_delete_array(query); std::string query = StringFormat("UPDATE `mail` SET `status` = %i WHERE `msgid`=%i", status, messageNumber);
auto results = QueryDatabase(query);
if (!results.Success())
_log(UCS__ERROR, "Error updating status %s, %s", query.c_str(), results.ErrorMessage().c_str());
} }
void Database::ExpireMail() { void Database::ExpireMail() {
_log(UCS__INIT, "Expiring mail..."); _log(UCS__INIT, "Expiring mail...");
char errbuf[MYSQL_ERRMSG_SIZE]; std::string query = "SELECT COUNT(*) FROM `mail`";
char* query = 0; auto results = QueryDatabase(query);
MYSQL_RES *result; if (!results.Success()) {
MYSQL_ROW row; _log(UCS__ERROR, "Unable to get message count from database. %s %s", query.c_str(), results.ErrorMessage().c_str());
uint32 AffectedRows;
if (!RunQuery(query,MakeAnyLenString(&query, "select COUNT(*) from `mail` "),errbuf,&result)){
_log(UCS__ERROR, "Unable to get message count from database. %s %s", query, errbuf);
safe_delete_array(query);
return; return;
} }
safe_delete_array(query);
row = mysql_fetch_row(result); auto row = results.begin();
_log(UCS__INIT, "There are %s messages in the database.", row[0]); _log(UCS__INIT, "There are %s messages in the database.", row[0]);
mysql_free_result(result);
// Expire Trash // Expire Trash
if(RuleI(Mail, ExpireTrash) >= 0) { if(RuleI(Mail, ExpireTrash) >= 0) {
if(RunQuery(query, MakeAnyLenString(&query, "delete from `mail` where `status`=4 and `timestamp` < %i", query = StringFormat("DELETE FROM `mail` WHERE `status`=4 AND `timestamp` < %i",
time(nullptr) - RuleI(Mail, ExpireTrash)), errbuf, 0, &AffectedRows)) { time(nullptr) - RuleI(Mail, ExpireTrash));
_log(UCS__INIT, "Expired %i trash messages.", AffectedRows); results = QueryDatabase(query);
} if(!results.Success())
else { _log(UCS__ERROR, "Error expiring trash messages, %s %s", query.c_str(), results.ErrorMessage().c_str());
_log(UCS__ERROR, "Error expiring trash messages, %s %s", query, errbuf); else
} _log(UCS__INIT, "Expired %i trash messages.", results.RowsAffected());
safe_delete_array(query);
} }
// Expire Read // Expire Read
if(RuleI(Mail, ExpireRead) >= 0) { if(RuleI(Mail, ExpireRead) >= 0) {
if(RunQuery(query, MakeAnyLenString(&query, "delete from `mail` where `status`=3 and `timestamp` < %i", query = StringFormat("DELETE FROM `mail` WHERE `status` = 3 AND `timestamp` < %i",
time(nullptr) - RuleI(Mail, ExpireRead)), errbuf, 0, &AffectedRows)) { time(nullptr) - RuleI(Mail, ExpireRead));
_log(UCS__INIT, "Expired %i read messages.", AffectedRows); results = QueryDatabase(query);
} if(!results.Success())
else { _log(UCS__INIT, "Expired %i read messages.", results.RowsAffected());
_log(UCS__ERROR, "Error expiring read messages, %s %s", query, errbuf); else
} _log(UCS__ERROR, "Error expiring read messages, %s %s", query.c_str(), results.ErrorMessage().c_str());
safe_delete_array(query);
} }
// Expire Unread // Expire Unread
if(RuleI(Mail, ExpireUnread) >= 0) { if(RuleI(Mail, ExpireUnread) >= 0) {
if(RunQuery(query, MakeAnyLenString(&query, "delete from `mail` where `status`=1 and `timestamp` < %i", query = StringFormat("DELETE FROM `mail` WHERE `status`=1 AND `timestamp` < %i",
time(nullptr) - RuleI(Mail, ExpireUnread)), errbuf, 0, &AffectedRows)) { time(nullptr) - RuleI(Mail, ExpireUnread));
_log(UCS__INIT, "Expired %i unread messages.", AffectedRows); results = QueryDatabase(query);
} if(!results.Success())
else { _log(UCS__INIT, "Expired %i unread messages.", results.RowsAffected());
_log(UCS__ERROR, "Error expiring unread messages, %s %s", query, errbuf);
}
safe_delete_array(query);
}
}
void Database::AddFriendOrIgnore(int CharID, int Type, std::string Name) {
const char *FriendsQuery="INSERT INTO `friends` (`charid`, `type`, `name`) VALUES ('%i', %i, '%s')";
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
if(!RunQuery(query, MakeAnyLenString(&query, FriendsQuery, CharID, Type, CapitaliseName(Name).c_str()), errbuf, 0, 0))
_log(UCS__ERROR, "Error adding friend/ignore, query was %s : %s", query, errbuf);
else else
_log(UCS__TRACE, "Wrote Friend/Ignore entry for charid %i, type %i, name %s to database.", _log(UCS__ERROR, "Error expiring unread messages, %s %s", query.c_str(), results.ErrorMessage().c_str());
CharID, Type, Name.c_str()); }
safe_delete_array(query);
} }
void Database::RemoveFriendOrIgnore(int CharID, int Type, std::string Name) { void Database::AddFriendOrIgnore(int charID, int type, std::string name) {
const char *FriendsQuery="DELETE FROM `friends` WHERE `charid`=%i AND `type`=%i and `name`='%s'"; std::string query = StringFormat("INSERT INTO `friends` (`charid`, `type`, `name`) "
"VALUES('%i', %i, '%s')",
char errbuf[MYSQL_ERRMSG_SIZE]; charID, type, CapitaliseName(name).c_str());
char* query = 0; auto results = QueryDatabase(query);
if(!results.Success())
if(!RunQuery(query, MakeAnyLenString(&query, FriendsQuery, CharID, Type, CapitaliseName(Name).c_str()), errbuf, 0, 0)) _log(UCS__ERROR, "Error adding friend/ignore, query was %s : %s", query.c_str(), results.ErrorMessage().c_str());
_log(UCS__ERROR, "Error removing friend/ignore, query was %s", query);
else else
_log(UCS__TRACE, "Removed Friend/Ignore entry for charid %i, type %i, name %s from database.", _log(UCS__TRACE, "Wrote Friend/Ignore entry for charid %i, type %i, name %s to database.", charID, type, name.c_str());
CharID, Type, Name.c_str());
safe_delete_array(query);
} }
void Database::GetFriendsAndIgnore(int CharID, std::vector<std::string> &Friends, std::vector<std::string> &Ignorees) { void Database::RemoveFriendOrIgnore(int charID, int type, std::string name) {
char errbuf[MYSQL_ERRMSG_SIZE]; std::string query = StringFormat("DELETE FROM `friends` WHERE `charid` = %i "
char* query = 0; "AND `type` = %i AND `name` = '%s'",
MYSQL_RES *result; charID, type, CapitaliseName(name).c_str());
MYSQL_ROW row; auto results = QueryDatabase(query);
if(!results.Success())
_log(UCS__ERROR, "Error removing friend/ignore, query was %s", query.c_str());
else
_log(UCS__TRACE, "Removed Friend/Ignore entry for charid %i, type %i, name %s from database.", charID, type, name.c_str());
const char *FriendsQuery="select `type`, `name` from `friends` WHERE `charid`=%i"; }
if (!RunQuery(query,MakeAnyLenString(&query, FriendsQuery, CharID),errbuf,&result)){ void Database::GetFriendsAndIgnore(int charID, std::vector<std::string> &friends, std::vector<std::string> &ignorees) {
_log(UCS__ERROR, "GetFriendsAndIgnore query error %s, %s", query, errbuf);
safe_delete_array(query);
std::string query = StringFormat("select `type`, `name` FROM `friends` WHERE `charid`=%i", charID);
auto results = QueryDatabase(query);
if (!results.Success()) {
_log(UCS__ERROR, "GetFriendsAndIgnore query error %s, %s", query.c_str(), results.ErrorMessage().c_str());
return; return;
} }
safe_delete_array(query);
while((row = mysql_fetch_row(result))) { for (auto row = results.begin(); row != results.end(); ++row) {
std::string name = row[1];
std::string Name = row[1];
if(atoi(row[0]) == 0) if(atoi(row[0]) == 0)
{ {
Ignorees.push_back(Name); ignorees.push_back(name);
_log(UCS__TRACE, "Added Ignoree from DB %s", Name.c_str()); _log(UCS__TRACE, "Added Ignoree from DB %s", name.c_str());
} continue;
else }
{
Friends.push_back(Name); friends.push_back(name);
_log(UCS__TRACE, "Added Friend from DB %s", Name.c_str()); _log(UCS__TRACE, "Added Friend from DB %s", name.c_str());
}
} }
mysql_free_result(result);
return;
} }

View File

@ -0,0 +1,23 @@
-- ----------------------------
-- Table structure for qs_player_events
-- ----------------------------
DROP TABLE IF EXISTS `qs_player_events`;
CREATE TABLE `qs_player_events` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`char_id` int(11) DEFAULT '0',
`event` int(11) unsigned DEFAULT '0',
`event_desc` varchar(255) DEFAULT NULL,
`time` int(11) unsigned DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
-- ----------------------------
-- Table structure for qs_player_aa_rate_hourly
-- ----------------------------
DROP TABLE IF EXISTS `qs_player_aa_rate_hourly`;
CREATE TABLE `qs_player_aa_rate_hourly` (
`char_id` int(11) NOT NULL DEFAULT '0',
`hour_time` int(11) NOT NULL,
`aa_count` varchar(11) DEFAULT NULL,
PRIMARY KEY (`char_id`,`hour_time`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

View File

@ -0,0 +1,45 @@
-- Disable Player Logging for All --
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogPCCoordinates', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogNPCKills', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogTrades', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogMerchantTransactions', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogDeletes', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogHandins', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogMoves', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogChat', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogKeyringAddition', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogAAPurchases', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogIssuedCommandes', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogMoneyTransactions', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogAlternateCurrencyTransactions', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogTradeSkillEvents', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogPCCoordinates', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogDropItem', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogMerchantTransactions', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogDeletes', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogHandins', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogMoves', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogNPCKills', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogTrades', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogQGlobalUpdate', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogTaskUpdates', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogDeaths', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogZone', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogConnectDisconnect', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogLevels', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogAARate', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogChat', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogDropItem', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogZone', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogDeaths', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogLevels', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogEXPRate', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogAARate', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogQGlobalUpdate', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogTaskUpdates', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogKeyringAddition', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogAAPurchases', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogTradeSkillEvents', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogIssuedCommandes', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogMoneyTransactions', 'false', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogAlternateCurrencyTransactions', 'false', '');

View File

@ -0,0 +1,45 @@
-- Enable Player Logging for All --
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogPCCoordinates', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogNPCKills', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogTrades', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogMerchantTransactions', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogDeletes', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogHandins', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogMoves', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogChat', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogKeyringAddition', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogAAPurchases', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogIssuedCommandes', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogMoneyTransactions', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogAlternateCurrencyTransactions', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogTradeSkillEvents', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogPCCoordinates', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogDropItem', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogMerchantTransactions', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogDeletes', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogHandins', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogMoves', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogNPCKills', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogTrades', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogQGlobalUpdate', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogTaskUpdates', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogDeaths', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogZone', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogConnectDisconnect', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogLevels', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (9, 'QueryServ:PlayerLogAARate', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogChat', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogDropItem', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogZone', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogDeaths', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogLevels', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogEXPRate', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogAARate', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogQGlobalUpdate', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogTaskUpdates', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogKeyringAddition', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogAAPurchases', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogTradeSkillEvents', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogIssuedCommandes', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogMoneyTransactions', 'true', '');
REPLACE INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (0, 'QueryServ:PlayerLogAlternateCurrencyTransactions', 'true', '');

View File

@ -0,0 +1,247 @@
-- QS Table Structures --
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for qs_merchant_transaction_record
-- ----------------------------
DROP TABLE IF EXISTS `qs_merchant_transaction_record`;
CREATE TABLE `qs_merchant_transaction_record` (
`transaction_id` int(11) NOT NULL AUTO_INCREMENT,
`time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
`zone_id` int(11) DEFAULT '0',
`merchant_id` int(11) DEFAULT '0',
`merchant_pp` int(11) DEFAULT '0',
`merchant_gp` int(11) DEFAULT '0',
`merchant_sp` int(11) DEFAULT '0',
`merchant_cp` int(11) DEFAULT '0',
`merchant_items` mediumint(7) DEFAULT '0',
`char_id` int(11) DEFAULT '0',
`char_pp` int(11) DEFAULT '0',
`char_gp` int(11) DEFAULT '0',
`char_sp` int(11) DEFAULT '0',
`char_cp` int(11) DEFAULT '0',
`char_items` mediumint(7) DEFAULT '0',
PRIMARY KEY (`transaction_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for qs_merchant_transaction_record_entries
-- ----------------------------
DROP TABLE IF EXISTS `qs_merchant_transaction_record_entries`;
CREATE TABLE `qs_merchant_transaction_record_entries` (
`event_id` int(11) DEFAULT '0',
`char_slot` mediumint(7) DEFAULT '0',
`item_id` int(11) DEFAULT '0',
`charges` mediumint(7) DEFAULT '0',
`aug_1` int(11) DEFAULT '0',
`aug_2` int(11) DEFAULT '0',
`aug_3` int(11) DEFAULT '0',
`aug_4` int(11) DEFAULT '0',
`aug_5` int(11) DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for qs_player_aa_rate_hourly
-- ----------------------------
DROP TABLE IF EXISTS `qs_player_aa_rate_hourly`;
CREATE TABLE `qs_player_aa_rate_hourly` (
`char_id` int(11) NOT NULL DEFAULT '0',
`hour_time` int(11) NOT NULL,
`aa_count` varchar(11) DEFAULT NULL,
PRIMARY KEY (`char_id`,`hour_time`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- ----------------------------
-- Table structure for qs_player_delete_record
-- ----------------------------
DROP TABLE IF EXISTS `qs_player_delete_record`;
CREATE TABLE `qs_player_delete_record` (
`delete_id` int(11) NOT NULL AUTO_INCREMENT,
`time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
`char_id` int(11) DEFAULT '0',
`stack_size` mediumint(7) DEFAULT '0',
`char_items` mediumint(7) DEFAULT '0',
PRIMARY KEY (`delete_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for qs_player_delete_record_entries
-- ----------------------------
DROP TABLE IF EXISTS `qs_player_delete_record_entries`;
CREATE TABLE `qs_player_delete_record_entries` (
`event_id` int(11) DEFAULT '0',
`char_slot` mediumint(7) DEFAULT '0',
`item_id` int(11) DEFAULT '0',
`charges` mediumint(7) DEFAULT '0',
`aug_1` int(11) DEFAULT '0',
`aug_2` int(11) DEFAULT '0',
`aug_3` int(11) DEFAULT '0',
`aug_4` int(11) DEFAULT '0',
`aug_5` int(11) DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for qs_player_events
-- ----------------------------
DROP TABLE IF EXISTS `qs_player_events`;
CREATE TABLE `qs_player_events` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`char_id` int(11) DEFAULT '0',
`event` int(11) unsigned DEFAULT '0',
`event_desc` varchar(255) DEFAULT NULL,
`time` int(11) unsigned DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
-- ----------------------------
-- Table structure for qs_player_handin_record
-- ----------------------------
DROP TABLE IF EXISTS `qs_player_handin_record`;
CREATE TABLE `qs_player_handin_record` (
`handin_id` int(11) NOT NULL AUTO_INCREMENT,
`time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
`quest_id` int(11) DEFAULT '0',
`char_id` int(11) DEFAULT '0',
`char_pp` int(11) DEFAULT '0',
`char_gp` int(11) DEFAULT '0',
`char_sp` int(11) DEFAULT '0',
`char_cp` int(11) DEFAULT '0',
`char_items` mediumint(7) DEFAULT '0',
`npc_id` int(11) DEFAULT '0',
`npc_pp` int(11) DEFAULT '0',
`npc_gp` int(11) DEFAULT '0',
`npc_sp` int(11) DEFAULT '0',
`npc_cp` int(11) DEFAULT '0',
`npc_items` mediumint(7) DEFAULT '0',
PRIMARY KEY (`handin_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for qs_player_handin_record_entries
-- ----------------------------
DROP TABLE IF EXISTS `qs_player_handin_record_entries`;
CREATE TABLE `qs_player_handin_record_entries` (
`event_id` int(11) DEFAULT '0',
`action_type` char(6) DEFAULT 'action',
`char_slot` mediumint(7) DEFAULT '0',
`item_id` int(11) DEFAULT '0',
`charges` mediumint(7) DEFAULT '0',
`aug_1` int(11) DEFAULT '0',
`aug_2` int(11) DEFAULT '0',
`aug_3` int(11) DEFAULT '0',
`aug_4` int(11) DEFAULT '0',
`aug_5` int(11) DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for qs_player_move_record
-- ----------------------------
DROP TABLE IF EXISTS `qs_player_move_record`;
CREATE TABLE `qs_player_move_record` (
`move_id` int(11) NOT NULL AUTO_INCREMENT,
`time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
`char_id` int(11) DEFAULT '0',
`from_slot` mediumint(7) DEFAULT '0',
`to_slot` mediumint(7) DEFAULT '0',
`stack_size` mediumint(7) DEFAULT '0',
`char_items` mediumint(7) DEFAULT '0',
`postaction` tinyint(1) DEFAULT '0',
PRIMARY KEY (`move_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for qs_player_move_record_entries
-- ----------------------------
DROP TABLE IF EXISTS `qs_player_move_record_entries`;
CREATE TABLE `qs_player_move_record_entries` (
`event_id` int(11) DEFAULT '0',
`from_slot` mediumint(7) DEFAULT '0',
`to_slot` mediumint(7) DEFAULT '0',
`item_id` int(11) DEFAULT '0',
`charges` mediumint(7) DEFAULT '0',
`aug_1` int(11) DEFAULT '0',
`aug_2` int(11) DEFAULT '0',
`aug_3` int(11) DEFAULT '0',
`aug_4` int(11) DEFAULT '0',
`aug_5` int(11) DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for qs_player_npc_kill_record
-- ----------------------------
DROP TABLE IF EXISTS `qs_player_npc_kill_record`;
CREATE TABLE `qs_player_npc_kill_record` (
`fight_id` int(11) NOT NULL AUTO_INCREMENT,
`npc_id` int(11) DEFAULT NULL,
`type` int(11) DEFAULT NULL,
`zone_id` int(11) DEFAULT NULL,
`time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`fight_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for qs_player_npc_kill_record_entries
-- ----------------------------
DROP TABLE IF EXISTS `qs_player_npc_kill_record_entries`;
CREATE TABLE `qs_player_npc_kill_record_entries` (
`event_id` int(11) DEFAULT '0',
`char_id` int(11) DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for qs_player_speech
-- ----------------------------
DROP TABLE IF EXISTS `qs_player_speech`;
CREATE TABLE `qs_player_speech` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`from` varchar(64) NOT NULL,
`to` varchar(64) NOT NULL,
`message` varchar(256) NOT NULL,
`minstatus` smallint(5) NOT NULL,
`guilddbid` int(11) NOT NULL,
`type` tinyint(3) NOT NULL,
`timerecorded` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for qs_player_trade_record
-- ----------------------------
DROP TABLE IF EXISTS `qs_player_trade_record`;
CREATE TABLE `qs_player_trade_record` (
`trade_id` int(11) NOT NULL AUTO_INCREMENT,
`time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
`char1_id` int(11) DEFAULT '0',
`char1_pp` int(11) DEFAULT '0',
`char1_gp` int(11) DEFAULT '0',
`char1_sp` int(11) DEFAULT '0',
`char1_cp` int(11) DEFAULT '0',
`char1_items` mediumint(7) DEFAULT '0',
`char2_id` int(11) DEFAULT '0',
`char2_pp` int(11) DEFAULT '0',
`char2_gp` int(11) DEFAULT '0',
`char2_sp` int(11) DEFAULT '0',
`char2_cp` int(11) DEFAULT '0',
`char2_items` mediumint(7) DEFAULT '0',
PRIMARY KEY (`trade_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for qs_player_trade_record_entries
-- ----------------------------
DROP TABLE IF EXISTS `qs_player_trade_record_entries`;
CREATE TABLE `qs_player_trade_record_entries` (
`event_id` int(11) DEFAULT '0',
`from_id` int(11) DEFAULT '0',
`from_slot` mediumint(7) DEFAULT '0',
`to_id` int(11) DEFAULT '0',
`to_slot` mediumint(7) DEFAULT '0',
`item_id` int(11) DEFAULT '0',
`charges` mediumint(7) DEFAULT '0',
`aug_1` int(11) DEFAULT '0',
`aug_2` int(11) DEFAULT '0',
`aug_3` int(11) DEFAULT '0',
`aug_4` int(11) DEFAULT '0',
`aug_5` int(11) DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

View File

@ -0,0 +1,33 @@
-- chracter_lookup table structure --
CREATE TABLE `character_lookup` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`account_id` int(11) NOT NULL DEFAULT '0',
`name` varchar(64) NOT NULL DEFAULT '',
`timelaston` int(11) unsigned DEFAULT '0',
`x` float NOT NULL DEFAULT '0',
`y` float NOT NULL DEFAULT '0',
`z` float NOT NULL DEFAULT '0',
`zonename` varchar(30) NOT NULL DEFAULT '',
`zoneid` smallint(6) NOT NULL DEFAULT '0',
`instanceid` smallint(5) unsigned NOT NULL DEFAULT '0',
`pktime` int(8) NOT NULL DEFAULT '0',
`groupid` int(10) unsigned NOT NULL DEFAULT '0',
`class` tinyint(4) NOT NULL DEFAULT '0',
`level` mediumint(8) unsigned NOT NULL DEFAULT '0',
`lfp` tinyint(1) unsigned NOT NULL DEFAULT '0',
`lfg` tinyint(1) unsigned NOT NULL DEFAULT '0',
`mailkey` char(16) NOT NULL,
`xtargets` tinyint(3) unsigned NOT NULL DEFAULT '5',
`firstlogon` tinyint(3) NOT NULL DEFAULT '0',
`inspectmessage` varchar(256) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`),
KEY `account_id` (`account_id`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
-- Initial population of the character_lookup table --
INSERT INTO `character_lookup` (id, account_id, `name`, timelaston, x, y, z, zonename, zoneid, instanceid, pktime, groupid, class, `level`, lfp, lfg, mailkey, xtargets, firstlogon, inspectmessage)
SELECT id, account_id, `name`, timelaston, x, y, z, zonename, zoneid, instanceid, pktime, groupid, class, `level`, lfp, lfg, mailkey, xtargets, firstlogon, inspectmessage
FROM `character_`;

View File

@ -1268,7 +1268,7 @@ bool ZoneServer::Process() {
UCSLink.SendPacket(pack); UCSLink.SendPacket(pack);
break; break;
} }
case ServerOP_QSSendQuery:
case ServerOP_QueryServGeneric: case ServerOP_QueryServGeneric:
case ServerOP_Speech: case ServerOP_Speech:
case ServerOP_QSPlayerLogTrades: case ServerOP_QSPlayerLogTrades:
@ -1296,7 +1296,7 @@ bool ZoneServer::Process() {
QSLink.SendPacket(pack); QSLink.SendPacket(pack);
break; break;
} }
case ServerOP_QSMerchantLogTransactions: case ServerOP_QSPlayerLogMerchantTransactions:
{ {
QSLink.SendPacket(pack); QSLink.SendPacket(pack);
break; break;

View File

@ -93,6 +93,7 @@ SET(zone_sources
petitions.cpp petitions.cpp
pets.cpp pets.cpp
qglobals.cpp qglobals.cpp
queryserv.cpp
questmgr.cpp questmgr.cpp
quest_parser_collection.cpp quest_parser_collection.cpp
raids.cpp raids.cpp
@ -184,6 +185,8 @@ SET(zone_headers
pets.h pets.h
qglobals.h qglobals.h
quest_interface.h quest_interface.h
queryserv.h
quest_interface.h
questmgr.h questmgr.h
quest_parser_collection.h quest_parser_collection.h
raid.h raid.h

View File

@ -38,6 +38,9 @@ Copyright (C) 2001-2004 EQEMu Development Team (http://eqemulator.net)
#include "../common/logsys.h" #include "../common/logsys.h"
#include "zonedb.h" #include "zonedb.h"
#include "string_ids.h" #include "string_ids.h"
#include "queryserv.h"
extern QueryServ* QServ;
//static data arrays, really not big enough to warrant shared mem. //static data arrays, really not big enough to warrant shared mem.
AA_DBAction AA_Actions[aaHighestID][MAX_AA_ACTION_RANKS]; //[aaid][rank] AA_DBAction AA_Actions[aaHighestID][MAX_AA_ACTION_RANKS]; //[aaid][rank]
@ -1059,11 +1062,29 @@ void Client::BuyAA(AA_Action* action)
//we are building these messages ourself instead of using the stringID to work around patch discrepencies //we are building these messages ourself instead of using the stringID to work around patch discrepencies
//these are AA_GAIN_ABILITY (410) & AA_IMPROVE (411), respectively, in both Titanium & SoF. not sure about 6.2 //these are AA_GAIN_ABILITY (410) & AA_IMPROVE (411), respectively, in both Titanium & SoF. not sure about 6.2
if(cur_level<1)
/* Initial purchase of an AA ability */
if (cur_level < 1){
Message(15, "You have gained the ability \"%s\" at a cost of %d ability %s.", aa2->name, real_cost, (real_cost>1) ? "points" : "point"); Message(15, "You have gained the ability \"%s\" at a cost of %d ability %s.", aa2->name, real_cost, (real_cost>1) ? "points" : "point");
else
/* QS: Player_Log_AA_Purchases */
if (RuleB(QueryServ, PlayerLogAAPurchases)){
std::string event_desc = StringFormat("Initial AA Purchase :: aa_name:%s aa_id:%i at cost:%i in zoneid:%i instid:%i", aa2->name, aa2->id, real_cost, this->GetZoneID(), this->GetInstanceID());
QServ->PlayerLogEvent(Player_Log_AA_Purchases, this->CharacterID(), event_desc);
}
}
/* Ranked purchase of an AA ability */
else{
Message(15, "You have improved %s %d at a cost of %d ability %s.", aa2->name, cur_level + 1, real_cost, (real_cost > 1) ? "points" : "point"); Message(15, "You have improved %s %d at a cost of %d ability %s.", aa2->name, cur_level + 1, real_cost, (real_cost > 1) ? "points" : "point");
/* QS: Player_Log_AA_Purchases */
if (RuleB(QueryServ, PlayerLogAAPurchases)){
std::string event_desc = StringFormat("Ranked AA Purchase :: aa_name:%s aa_id:%i at cost:%i in zoneid:%i instid:%i", aa2->name, aa2->id, real_cost, this->GetZoneID(), this->GetInstanceID());
QServ->PlayerLogEvent(Player_Log_AA_Purchases, this->CharacterID(), event_desc);
}
}
SendAAStats(); SendAAStats();

View File

@ -873,7 +873,34 @@ bool Mob::CombatRange(Mob* other)
if (size_mod > 10000) if (size_mod > 10000)
size_mod = size_mod / 7; size_mod = size_mod / 7;
if (DistNoRoot(*other) <= size_mod) float _DistNoRoot = DistNoRoot(*other);
if (GetSpecialAbility(NPC_CHASE_DISTANCE)){
bool DoLoSCheck = true;
float max_dist = static_cast<float>(GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 0));
float min_dist = static_cast<float>(GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 1));
if (GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 2));
DoLoSCheck = false; //Ignore line of sight check
if (max_dist == 1)
max_dist = 250.0f; //Default it to 250 if you forget to put a value
max_dist = max_dist * max_dist;
if (!min_dist)
min_dist = size_mod; //Default to melee range
else
min_dist = min_dist * min_dist;
if ((DoLoSCheck && CheckLastLosState()) && (_DistNoRoot >= min_dist && _DistNoRoot <= max_dist))
SetPseudoRoot(true);
else
SetPseudoRoot(false);
}
if (_DistNoRoot <= size_mod)
{ {
return true; return true;
} }
@ -887,6 +914,8 @@ bool Mob::CheckLosFN(Mob* other) {
if(other) if(other)
Result = CheckLosFN(other->GetX(), other->GetY(), other->GetZ(), other->GetSize()); Result = CheckLosFN(other->GetX(), other->GetY(), other->GetZ(), other->GetSize());
SetLastLosState(Result);
return Result; return Result;
} }

View File

@ -42,6 +42,9 @@
#include "quest_parser_collection.h" #include "quest_parser_collection.h"
#include "water_map.h" #include "water_map.h"
#include "worldserver.h" #include "worldserver.h"
#include "queryserv.h"
extern QueryServ* QServ;
extern WorldServer worldserver; extern WorldServer worldserver;
#ifdef _WINDOWS #ifdef _WINDOWS
@ -1455,14 +1458,14 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att
int exploss = 0; int exploss = 0;
mlog(COMBAT__HITS, "Fatal blow dealt by %s with %d damage, spell %d, skill %d", killerMob ? killerMob->GetName() : "Unknown", damage, spell, attack_skill); mlog(COMBAT__HITS, "Fatal blow dealt by %s with %d damage, spell %d, skill %d", killerMob ? killerMob->GetName() : "Unknown", damage, spell, attack_skill);
// /*
// #1: Send death packet to everyone #1: Send death packet to everyone
// */
uint8 killed_level = GetLevel(); uint8 killed_level = GetLevel();
SendLogoutPackets(); SendLogoutPackets();
//make our become corpse packet, and queue to ourself before OP_Death. /* Make self become corpse packet */
EQApplicationPacket app2(OP_BecomeCorpse, sizeof(BecomeCorpse_Struct)); EQApplicationPacket app2(OP_BecomeCorpse, sizeof(BecomeCorpse_Struct));
BecomeCorpse_Struct* bc = (BecomeCorpse_Struct*)app2.pBuffer; BecomeCorpse_Struct* bc = (BecomeCorpse_Struct*)app2.pBuffer;
bc->spawn_id = GetID(); bc->spawn_id = GetID();
@ -1471,7 +1474,7 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att
bc->z = GetZ(); bc->z = GetZ();
QueuePacket(&app2); QueuePacket(&app2);
// make death packet /* Make Death Packet */
EQApplicationPacket app(OP_Death, sizeof(Death_Struct)); EQApplicationPacket app(OP_Death, sizeof(Death_Struct));
Death_Struct* d = (Death_Struct*)app.pBuffer; Death_Struct* d = (Death_Struct*)app.pBuffer;
d->spawn_id = GetID(); d->spawn_id = GetID();
@ -1484,9 +1487,9 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att
app.priority = 6; app.priority = 6;
entity_list.QueueClients(this, &app); entity_list.QueueClients(this, &app);
// /*
// #2: figure out things that affect the player dying and mark them dead #2: figure out things that affect the player dying and mark them dead
// */
InterruptSpell(); InterruptSpell();
SetPet(0); SetPet(0);
@ -1541,9 +1544,9 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att
//remove ourself from all proximities //remove ourself from all proximities
ClearAllProximities(); ClearAllProximities();
// /*
// #3: exp loss and corpse generation #3: exp loss and corpse generation
// */
// figure out if they should lose exp // figure out if they should lose exp
if(RuleB(Character, UseDeathExpLossMult)){ if(RuleB(Character, UseDeathExpLossMult)){
@ -1659,27 +1662,21 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att
LeftCorpse = true; LeftCorpse = true;
} }
// if(!IsLD())//Todo: make it so an LDed client leaves corpse if its enabled
// MakeCorpse(exploss);
} else { } else {
BuffFadeDetrimental(); BuffFadeDetrimental();
} }
// /*
// Finally, send em home Finally, send em home
//
// we change the mob variables, not pp directly, because Save() will copy We change the mob variables, not pp directly, because Save() will copy
// from these and overwrite what we set in pp anyway from these and overwrite what we set in pp anyway
// */
if(LeftCorpse && (GetClientVersionBit() & BIT_SoFAndLater) && RuleB(Character, RespawnFromHover)) if(LeftCorpse && (GetClientVersionBit() & BIT_SoFAndLater) && RuleB(Character, RespawnFromHover))
{ {
ClearDraggedCorpses(); ClearDraggedCorpses();
RespawnFromHoverTimer.Start(RuleI(Character, RespawnFromHoverTimer) * 1000); RespawnFromHoverTimer.Start(RuleI(Character, RespawnFromHoverTimer) * 1000);
SendRespawnBinds(); SendRespawnBinds();
} }
else else
@ -1697,16 +1694,21 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att
r->MemberZoned(this); r->MemberZoned(this);
dead_timer.Start(5000, true); dead_timer.Start(5000, true);
m_pp.zone_id = m_pp.binds[0].zoneId; m_pp.zone_id = m_pp.binds[0].zoneId;
m_pp.zoneInstance = 0; m_pp.zoneInstance = 0;
database.MoveCharacterToZone(this->CharacterID(), database.GetZoneName(m_pp.zone_id)); database.MoveCharacterToZone(this->CharacterID(), database.GetZoneName(m_pp.zone_id));
Save(); Save();
GoToDeath(); GoToDeath();
} }
/* QS: PlayerLogDeaths */
if (RuleB(QueryServ, PlayerLogDeaths)){
const char * killer_name = "";
if (killerMob && killerMob->GetCleanName()){ killer_name = killerMob->GetCleanName(); }
std::string event_desc = StringFormat("Died in zoneid:%i instid:%i by '%s', spellid:%i, damage:%i", this->GetZoneID(), this->GetInstanceID(), killer_name, spell, damage);
QServ->PlayerLogEvent(Player_Log_Deaths, this->CharacterID(), event_desc);
}
parse->EventPlayer(EVENT_DEATH_COMPLETE, this, buffer, 0); parse->EventPlayer(EVENT_DEATH_COMPLETE, this, buffer, 0);
return true; return true;
} }

View File

@ -62,8 +62,9 @@ extern volatile bool RunLoops;
#include "client_logs.h" #include "client_logs.h"
#include "guild_mgr.h" #include "guild_mgr.h"
#include "quest_parser_collection.h" #include "quest_parser_collection.h"
#include "queryserv.h"
extern QueryServ* QServ;
extern EntityList entity_list; extern EntityList entity_list;
extern Zone* zone; extern Zone* zone;
extern volatile bool ZoneLoaded; extern volatile bool ZoneLoaded;
@ -629,6 +630,9 @@ bool Client::Save(uint8 iCommitNow) {
return false; return false;
} }
/* Mirror Character Data */
database.StoreCharacterLookup(this->CharacterID());
return true; return true;
} }
@ -805,8 +809,8 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
} }
} }
/* Logs Player Chat */
if(RuleB(QueryServ, PlayerChatLogging)) { if (RuleB(QueryServ, PlayerLogChat)) {
ServerPacket* pack = new ServerPacket(ServerOP_Speech, sizeof(Server_Speech_Struct) + strlen(message) + 1); ServerPacket* pack = new ServerPacket(ServerOP_Speech, sizeof(Server_Speech_Struct) + strlen(message) + 1);
Server_Speech_Struct* sem = (Server_Speech_Struct*) pack->pBuffer; Server_Speech_Struct* sem = (Server_Speech_Struct*) pack->pBuffer;
@ -841,7 +845,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
switch(chan_num) switch(chan_num)
{ {
case 0: { // GuildChat case 0: { /* Guild Chat */
if (!IsInAGuild()) if (!IsInAGuild())
Message_StringID(MT_DefaultText, GUILD_NOT_MEMBER2); //You are not a member of any guild. Message_StringID(MT_DefaultText, GUILD_NOT_MEMBER2); //You are not a member of any guild.
else if (!guild_mgr.CheckPermission(GuildID(), GuildRank(), GUILD_SPEAK)) else if (!guild_mgr.CheckPermission(GuildID(), GuildRank(), GUILD_SPEAK))
@ -850,7 +854,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
Message(0, "Error: World server disconnected"); Message(0, "Error: World server disconnected");
break; break;
} }
case 2: { // GroupChat case 2: { /* Group Chat */
Raid* raid = entity_list.GetRaidByClient(this); Raid* raid = entity_list.GetRaidByClient(this);
if(raid) { if(raid) {
raid->RaidGroupSay((const char*) message, this); raid->RaidGroupSay((const char*) message, this);
@ -863,14 +867,14 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
} }
break; break;
} }
case 15: { //raid say case 15: { /* Raid Say */
Raid* raid = entity_list.GetRaidByClient(this); Raid* raid = entity_list.GetRaidByClient(this);
if(raid){ if(raid){
raid->RaidSay((const char*) message, this); raid->RaidSay((const char*) message, this);
} }
break; break;
} }
case 3: { // Shout case 3: { /* Shout */
Mob *sender = this; Mob *sender = this;
if (GetPet() && GetPet()->FindType(SE_VoiceGraft)) if (GetPet() && GetPet()->FindType(SE_VoiceGraft))
sender = GetPet(); sender = GetPet();
@ -878,7 +882,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
entity_list.ChannelMessage(sender, chan_num, language, lang_skill, message); entity_list.ChannelMessage(sender, chan_num, language, lang_skill, message);
break; break;
} }
case 4: { // Auction case 4: { /* Auction */
if(RuleB(Chat, ServerWideAuction)) if(RuleB(Chat, ServerWideAuction))
{ {
if(!global_channel_timer.Check()) if(!global_channel_timer.Check())
@ -917,7 +921,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
} }
break; break;
} }
case 5: { // OOC case 5: { /* OOC */
if(RuleB(Chat, ServerWideOOC)) if(RuleB(Chat, ServerWideOOC))
{ {
if(!global_channel_timer.Check()) if(!global_channel_timer.Check())
@ -964,15 +968,15 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
} }
break; break;
} }
case 6: // Broadcast case 6: /* Broadcast */
case 11: { // GMSay case 11: { /* GM Say */
if (!(admin >= 80)) if (!(admin >= 80))
Message(0, "Error: Only GMs can use this channel"); Message(0, "Error: Only GMs can use this channel");
else if (!worldserver.SendChannelMessage(this, targetname, chan_num, 0, language, message)) else if (!worldserver.SendChannelMessage(this, targetname, chan_num, 0, language, message))
Message(0, "Error: World server disconnected"); Message(0, "Error: World server disconnected");
break; break;
} }
case 7: { // Tell case 7: { /* Tell */
if(!global_channel_timer.Check()) if(!global_channel_timer.Check())
{ {
if(strlen(targetname) == 0) if(strlen(targetname) == 0)
@ -1020,7 +1024,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
Message(0, "Error: World server disconnected"); Message(0, "Error: World server disconnected");
break; break;
} }
case 8: { // /say case 8: { /* Say */
if(message[0] == COMMAND_CHAR) { if(message[0] == COMMAND_CHAR) {
if(command_dispatch(this, message) == -2) { if(command_dispatch(this, message) == -2) {
if(parse->PlayerHasQuestSub(EVENT_COMMAND)) { if(parse->PlayerHasQuestSub(EVENT_COMMAND)) {
@ -4060,25 +4064,40 @@ void Client::KeyRingList()
bool Client::IsDiscovered(uint32 itemid) { bool Client::IsDiscovered(uint32 itemid) {
std::string query = StringFormat("SELECT count(*) FROM discovered_items WHERE item_id = '%lu'", itemid); char errbuf[MYSQL_ERRMSG_SIZE];
auto results = database.QueryDatabase(query); char *query = 0;
if (!results.Success()) { MYSQL_RES *result;
std::cerr << "Error in IsDiscovered query '" << query << "' " << results.ErrorMessage() << std::endl; MYSQL_ROW row;
return false;
if (database.RunQuery(query, MakeAnyLenString(&query, "SELECT count(*) FROM discovered_items WHERE item_id = '%lu'", itemid), errbuf, &result))
{
row = mysql_fetch_row(result);
if (atoi(row[0]))
{
mysql_free_result(result);
safe_delete_array(query);
return true;
} }
}
auto row = results.begin(); else
{
return atoi(row[0]) != 0; std::cerr << "Error in IsDiscovered query '" << query << "' " << errbuf << std::endl;
}
mysql_free_result(result);
safe_delete_array(query);
return false;
} }
void Client::DiscoverItem(uint32 itemid) { void Client::DiscoverItem(uint32 itemid) {
std::string query = StringFormat("INSERT INTO discovered_items SET " char errbuf[MYSQL_ERRMSG_SIZE];
"item_id = %lu, char_name = '%s', " char* query = 0;
"discovered_date = UNIX_TIMESTAMP(), account_status=%i", MYSQL_RES *result;
itemid, GetName(), Admin()); if (database.RunQuery(query,MakeAnyLenString(&query, "INSERT INTO discovered_items SET item_id=%lu, char_name='%s', discovered_date=UNIX_TIMESTAMP(), account_status=%i", itemid, GetName(), Admin()), errbuf, &result))
auto results = database.QueryDatabase(query); {
mysql_free_result(result);
}
safe_delete_array(query);
parse->EventPlayer(EVENT_DISCOVER_ITEM, this, "", itemid); parse->EventPlayer(EVENT_DISCOVER_ITEM, this, "", itemid);
} }
@ -5261,21 +5280,31 @@ const bool Client::IsMQExemptedArea(uint32 zoneID, float x, float y, float z) co
void Client::SendRewards() void Client::SendRewards()
{ {
std::vector<ClientReward> rewards; std::vector<ClientReward> rewards;
std::string query = StringFormat("SELECT reward_id, amount FROM " char errbuf[MYSQL_ERRMSG_SIZE];
"account_rewards WHERE account_id = %i " char* query = 0;
"ORDER BY reward_id", AccountID()); MYSQL_RES *result;
auto results = database.QueryDatabase(query); MYSQL_ROW row;
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in Client::SendRewards(): %s (%s)", query.c_str(), results.ErrorMessage().c_str());
return;
}
for (auto row = results.begin(); row != results.end(); ++row) { if(database.RunQuery(query,MakeAnyLenString(&query,"SELECT reward_id, amount FROM"
" account_rewards WHERE account_id=%i ORDER by reward_id", AccountID()),
errbuf,&result))
{
while((row = mysql_fetch_row(result)))
{
ClientReward cr; ClientReward cr;
cr.id = atoi(row[0]); cr.id = atoi(row[0]);
cr.amount = atoi(row[1]); cr.amount = atoi(row[1]);
rewards.push_back(cr); rewards.push_back(cr);
} }
mysql_free_result(result);
safe_delete_array(query);
}
else
{
LogFile->write(EQEMuLog::Error, "Error in Client::SendRewards(): %s (%s)", query, errbuf);
safe_delete_array(query);
return;
}
if(rewards.size() > 0) if(rewards.size() > 0)
{ {
@ -5336,54 +5365,88 @@ bool Client::TryReward(uint32 claim_id)
} }
if(free_slot == 0xFFFFFFFF) if(free_slot == 0xFFFFFFFF)
return false; {
std::string query = StringFormat("SELECT amount FROM account_rewards "
"WHERE account_id=%i AND reward_id=%i",
AccountID(), claim_id);
auto results = database.QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in Client::TryReward(): %s (%s)", query.c_str(), results.ErrorMessage().c_str());
return false; return false;
} }
if (results.RowCount() == 0) char errbuf[MYSQL_ERRMSG_SIZE];
return false; char* query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
uint32 amt = 0; uint32 amt = 0;
auto row = results.begin();
amt = atoi(row[0]); if(database.RunQuery(query,MakeAnyLenString(&query,"SELECT amount FROM"
" account_rewards WHERE account_id=%i AND reward_id=%i", AccountID(), claim_id),
if(amt == 0) errbuf,&result))
return false;
auto iter = zone->VeteranRewards.begin();
for (; iter != zone->VeteranRewards.end(); ++iter)
if((*iter).claim_id == claim_id)
break;
if(iter == zone->VeteranRewards.end())
return false;
if(amt == 1)
{ {
query = StringFormat("DELETE FROM account_rewards " row = mysql_fetch_row(result);
"WHERE account_id=%i AND reward_id=%i", if(row)
AccountID(), claim_id); {
results = database.QueryDatabase(query); amt = atoi(row[0]);
if(!results.ErrorMessage().c_str())
LogFile->write(EQEMuLog::Error, "Error in Client::TryReward(): %s (%s)", query.c_str(), results.ErrorMessage().c_str());
} }
else else
{ {
query = StringFormat("UPDATE account_rewards SET amount=(amount-1) " mysql_free_result(result);
"WHERE account_id=%i AND reward_id=%i", AccountID(), claim_id); safe_delete_array(query);
results = database.QueryDatabase(query); return false;
if(!results.Success()) }
LogFile->write(EQEMuLog::Error, "Error in Client::TryReward(): %s (%s)", query.c_str(), results.ErrorMessage().c_str()); mysql_free_result(result);
safe_delete_array(query);
}
else
{
LogFile->write(EQEMuLog::Error, "Error in Client::TryReward(): %s (%s)", query, errbuf);
safe_delete_array(query);
return false;
}
if(amt == 0)
{
return false;
}
std::list<InternalVeteranReward>::iterator iter = zone->VeteranRewards.begin();
while(iter != zone->VeteranRewards.end())
{
if((*iter).claim_id == claim_id)
{
break;
}
++iter;
}
if(iter == zone->VeteranRewards.end())
{
return false;
}
if(amt == 1)
{
if(!database.RunQuery(query,MakeAnyLenString(&query,"DELETE FROM"
" account_rewards WHERE account_id=%i AND reward_id=%i", AccountID(), claim_id),
errbuf))
{
LogFile->write(EQEMuLog::Error, "Error in Client::TryReward(): %s (%s)", query, errbuf);
safe_delete_array(query);
}
else
{
safe_delete_array(query);
}
}
else
{
if(!database.RunQuery(query,MakeAnyLenString(&query,"UPDATE account_rewards SET amount=(amount-1)"
" WHERE account_id=%i AND reward_id=%i", AccountID(), claim_id),
errbuf))
{
LogFile->write(EQEMuLog::Error, "Error in Client::TryReward(): %s (%s)", query, errbuf);
safe_delete_array(query);
}
else
{
safe_delete_array(query);
}
} }
InternalVeteranReward ivr = (*iter); InternalVeteranReward ivr = (*iter);
@ -6862,8 +6925,18 @@ void Client::SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount)
SendAlternateCurrencyValue(currency_id); SendAlternateCurrencyValue(currency_id);
} }
void Client::AddAlternateCurrencyValue(uint32 currency_id, int32 amount) void Client::AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 method)
{ {
/* Added via Quest, rest of the logging methods may be done inline due to information available in that area of the code */
if (method == 1){
/* QS: PlayerLogAlternateCurrencyTransactions :: Cursor to Item Storage */
if (RuleB(QueryServ, PlayerLogAlternateCurrencyTransactions)){
std::string event_desc = StringFormat("Added via Quest :: Cursor to Item :: alt_currency_id:%i amount:%i in zoneid:%i instid:%i", currency_id, this->GetZoneID(), this->GetInstanceID());
QServ->PlayerLogEvent(Player_Log_Alternate_Currency_Transactions, this->CharacterID(), event_desc);
}
}
if(amount == 0) { if(amount == 0) {
return; return;
} }
@ -7738,30 +7811,41 @@ void Client::SendFactionMessage(int32 tmpvalue, int32 faction_id, int32 totalval
void Client::LoadAccountFlags() void Client::LoadAccountFlags()
{ {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
accountflags.clear(); accountflags.clear();
MakeAnyLenString(&query, "SELECT p_flag, p_value FROM account_flags WHERE p_accid = '%d'", account_id);
std::string query = StringFormat("SELECT p_flag, p_value FROM account_flags WHERE p_accid = '%d'", account_id); if(database.RunQuery(query, strlen(query), errbuf, &result))
auto results = database.QueryDatabase(query); {
if (!results.Success()) { while(row = mysql_fetch_row(result))
std::cerr << "Error in LoadAccountFlags query '" << query << "' " << results.ErrorMessage() << std::endl; {
return;
}
for (auto row = results.begin(); row != results.end(); ++row) {
std::string fname(row[0]); std::string fname(row[0]);
std::string fval(row[1]); std::string fval(row[1]);
accountflags[fname] = fval; accountflags[fname] = fval;
} }
mysql_free_result(result);
}
else
{
std::cerr << "Error in LoadAccountFlags query '" << query << "' " << errbuf << std::endl;
}
safe_delete_array(query);
} }
void Client::SetAccountFlag(std::string flag, std::string val) void Client::SetAccountFlag(std::string flag, std::string val)
{ {
std::string query = StringFormat("REPLACE INTO account_flags (p_accid, p_flag, p_value) " char errbuf[MYSQL_ERRMSG_SIZE];
"VALUES( '%d', '%s', '%s')", account_id, flag.c_str(), val.c_str()); char *query = 0;
auto results = database.QueryDatabase(query);
if(!results.Success()) MakeAnyLenString(&query, "REPLACE INTO account_flags (p_accid, p_flag, p_value) VALUES( '%d', '%s', '%s')", account_id, flag.c_str(), val.c_str());
std::cerr << "Error in SetAccountFlags query '" << query << "' " << results.ErrorMessage() << std::endl; if(!database.RunQuery(query, strlen(query), errbuf))
{
std::cerr << "Error in SetAccountFlags query '" << query << "' " << errbuf << std::endl;
}
safe_delete_array(query);
accountflags[flag] = val; accountflags[flag] = val;
} }
@ -8170,21 +8254,29 @@ void Client::PlayMP3(const char* fname)
safe_delete(outapp); safe_delete(outapp);
} }
void Client::ExpeditionSay(const char *str, int expID) { void Client::ExpeditionSay(const char *str, int ExpID) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
std::string query = StringFormat("SELECT `player_name` FROM " if (!database.RunQuery(query,MakeAnyLenString(&query, "SELECT `player_name` FROM `cust_inst_players` WHERE `inst_id` = %i", ExpID),errbuf,&result)){
"`cust_inst_players` WHERE " safe_delete_array(query);
"`inst_id` = %i", expID);
auto results = database.QueryDatabase(query);
if (!results.Success())
return; return;
}
safe_delete_array(query);
if(result)
this->Message(14, "You say to the expedition, '%s'", str); this->Message(14, "You say to the expedition, '%s'", str);
for (auto row = results.begin(); row != results.end(); ++row) { while((row = mysql_fetch_row(result))) {
const char* charName = row[0]; const char* CharName = row[0];
if(strcmp(charName, this->GetCleanName()) != 0) if(strcmp(CharName, this->GetCleanName()) != 0)
worldserver.SendEmoteMessage(charName, 0, 0, 14, "%s says to the expedition, '%s'", this->GetCleanName(), str); worldserver.SendEmoteMessage(CharName, 0, 0, 14, "%s says to the expedition, '%s'", this->GetCleanName(), str);
// ChannelList->CreateChannel(ChannelName, ChannelOwner, ChannelPassword, true, atoi(row[3]));
} }
mysql_free_result(result);
} }

8232
zone/client.cpp.orig Normal file

File diff suppressed because it is too large Load Diff

View File

@ -268,7 +268,7 @@ public:
void TradeRequestFailed(const EQApplicationPacket* app); void TradeRequestFailed(const EQApplicationPacket* app);
void BuyTraderItem(TraderBuy_Struct* tbs,Client* trader,const EQApplicationPacket* app); void BuyTraderItem(TraderBuy_Struct* tbs,Client* trader,const EQApplicationPacket* app);
void TraderUpdate(uint16 slot_id,uint32 trader_id); void TraderUpdate(uint16 slot_id,uint32 trader_id);
void FinishTrade(Mob* with, ServerPacket* qspack = nullptr, bool finalizer = false); void FinishTrade(Mob* with, bool finalizer = false, void* event_entry = nullptr, std::list<void*>* event_details = nullptr);
void SendZonePoints(); void SendZonePoints();
void SendBuyerResults(char *SearchQuery, uint32 SearchID); void SendBuyerResults(char *SearchQuery, uint32 SearchID);
@ -1097,7 +1097,7 @@ public:
inline void ClearDraggedCorpses() { DraggedCorpses.clear(); } inline void ClearDraggedCorpses() { DraggedCorpses.clear(); }
void SendAltCurrencies(); void SendAltCurrencies();
void SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount); void SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount);
void AddAlternateCurrencyValue(uint32 currency_id, int32 amount); void AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 method = 0);
void SendAlternateCurrencyValues(); void SendAlternateCurrencyValues();
void SendAlternateCurrencyValue(uint32 currency_id, bool send_if_null = true); void SendAlternateCurrencyValue(uint32 currency_id, bool send_if_null = true);
uint32 GetAlternateCurrencyValue(uint32 currency_id) const; uint32 GetAlternateCurrencyValue(uint32 currency_id) const;

View File

@ -16,16 +16,16 @@
*/ */
#include "../common/debug.h" #include "../common/debug.h"
#include <iostream>
#include <iomanip>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <zlib.h>
#include <assert.h> #include <assert.h>
#include <sstream> #include <iomanip>
#include <iostream>
#include <math.h>
#include <set> #include <set>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <zlib.h>
#ifdef _WINDOWS #ifdef _WINDOWS
#define snprintf _snprintf #define snprintf _snprintf
@ -38,8 +38,6 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
#include "masterentity.h"
#include "zonedb.h"
#include "../common/packet_functions.h" #include "../common/packet_functions.h"
#include "../common/packet_dump.h" #include "../common/packet_dump.h"
#include "worldserver.h" #include "worldserver.h"
@ -59,17 +57,21 @@
#include "../common/faction.h" #include "../common/faction.h"
#include "../common/crc32.h" #include "../common/crc32.h"
#include "string_ids.h" #include "string_ids.h"
#include "map.h"
#include "titles.h" #include "titles.h"
#include "pets.h" #include "water_map.h"
#include "worldserver.h"
#include "zone.h"
#include "zone_config.h" #include "zone_config.h"
#include "guild_mgr.h" #include "guild_mgr.h"
#include "pathing.h" #include "pathing.h"
#include "water_map.h" #include "water_map.h"
#include "merc.h" #include "merc.h"
#include "pets.h"
#include "../common/zone_numbers.h" #include "../common/zone_numbers.h"
#include "quest_parser_collection.h" #include "quest_parser_collection.h"
#include "queryserv.h"
extern QueryServ* QServ;
extern Zone* zone; extern Zone* zone;
extern volatile bool ZoneLoaded; extern volatile bool ZoneLoaded;
extern WorldServer worldserver; extern WorldServer worldserver;
@ -431,7 +433,7 @@ int Client::HandlePacket(const EQApplicationPacket *app)
case CLIENT_CONNECTING: { case CLIENT_CONNECTING: {
if(ConnectingOpcodes.count(opcode) != 1) { if(ConnectingOpcodes.count(opcode) != 1) {
//Hate const cast but everything in lua needs to be non-const even if i make it non-mutable //Hate const cast but everything in lua needs to be non-const even if i make it non-mutable
std::vector<void*> args; std::vector<EQEmu::Any> args;
args.push_back(const_cast<EQApplicationPacket*>(app)); args.push_back(const_cast<EQApplicationPacket*>(app));
parse->EventPlayer(EVENT_UNHANDLED_OPCODE, this, "", 1, &args); parse->EventPlayer(EVENT_UNHANDLED_OPCODE, this, "", 1, &args);
@ -460,7 +462,7 @@ int Client::HandlePacket(const EQApplicationPacket *app)
ClientPacketProc p; ClientPacketProc p;
p = ConnectedOpcodes[opcode]; p = ConnectedOpcodes[opcode];
if(p == nullptr) { if(p == nullptr) {
std::vector<void*> args; std::vector<EQEmu::Any> args;
args.push_back(const_cast<EQApplicationPacket*>(app)); args.push_back(const_cast<EQApplicationPacket*>(app));
parse->EventPlayer(EVENT_UNHANDLED_OPCODE, this, "", 0, &args); parse->EventPlayer(EVENT_UNHANDLED_OPCODE, this, "", 0, &args);
@ -3135,6 +3137,7 @@ void Client::Handle_OP_ItemLinkClick(const EQApplicationPacket *app)
DumpPacket(app); DumpPacket(app);
return; return;
} }
DumpPacket(app); DumpPacket(app);
ItemViewRequest_Struct* ivrs = (ItemViewRequest_Struct*)app->pBuffer; ItemViewRequest_Struct* ivrs = (ItemViewRequest_Struct*)app->pBuffer;
@ -3154,30 +3157,24 @@ void Client::Handle_OP_ItemLinkClick(const EQApplicationPacket *app)
silentsaylink = true; silentsaylink = true;
} }
if (sayid && sayid > 0) if (sayid > 0)
{ {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
std::string query = StringFormat("SELECT `phrase` FROM saylink WHERE `id` = '%i'", sayid);
if(database.RunQuery(query,MakeAnyLenString(&query,"SELECT `phrase` FROM saylink WHERE `id` = '%i'", sayid),errbuf,&result)) auto results = database.QueryDatabase(query);
{ if (!results.Success()) {
if (mysql_num_rows(result) == 1)
{
row = mysql_fetch_row(result);
response = row[0];
}
mysql_free_result(result);
}
else
{
Message(13, "Error: The saylink (%s) was not found in the database.", response.c_str()); Message(13, "Error: The saylink (%s) was not found in the database.", response.c_str());
safe_delete_array(query);
return; return;
} }
safe_delete_array(query);
if (results.RowCount() != 1) {
Message(13, "Error: The saylink (%s) was not found in the database.", response.c_str());
return;
}
auto row = results.begin();
response = row[0];
} }
if((response).size() > 0) if((response).size() > 0)
@ -4860,6 +4857,7 @@ void Client::Handle_OP_TradeAcceptClick(const EQApplicationPacket *app)
{ {
Mob* with = trade->With(); Mob* with = trade->With();
trade->state = TradeAccepted; trade->state = TradeAccepted;
if (with && with->IsClient()) { if (with && with->IsClient()) {
//finish trade... //finish trade...
// Have both accepted? // Have both accepted?
@ -4870,6 +4868,7 @@ void Client::Handle_OP_TradeAcceptClick(const EQApplicationPacket *app)
other->trade->state = TradeCompleting; other->trade->state = TradeCompleting;
trade->state = TradeCompleting; trade->state = TradeCompleting;
// should we do this for NoDrop items as well?
if (CheckTradeLoreConflict(other) || other->CheckTradeLoreConflict(this)) { if (CheckTradeLoreConflict(other) || other->CheckTradeLoreConflict(this)) {
Message_StringID(13, TRADE_CANCEL_LORE); Message_StringID(13, TRADE_CANCEL_LORE);
other->Message_StringID(13, TRADE_CANCEL_LORE); other->Message_StringID(13, TRADE_CANCEL_LORE);
@ -4885,23 +4884,38 @@ void Client::Handle_OP_TradeAcceptClick(const EQApplicationPacket *app)
// start QS code // start QS code
if(RuleB(QueryServ, PlayerLogTrades)) { if(RuleB(QueryServ, PlayerLogTrades)) {
uint16 trade_count = 0; QSPlayerLogTrade_Struct event_entry;
std::list<void*> event_details;
// Item trade count for packet sizing memset(&event_entry, 0, sizeof(QSPlayerLogTrade_Struct));
for(int16 slot_id = EmuConstants::TRADE_BEGIN; slot_id <= EmuConstants::TRADE_END; slot_id++) {
if(other->GetInv().GetItem(slot_id)) { trade_count += other->GetInv().GetItem(slot_id)->GetTotalItemCount(); }
if(m_inv[slot_id]) { trade_count += m_inv[slot_id]->GetTotalItemCount(); }
}
ServerPacket* qspack = new ServerPacket(ServerOP_QSPlayerLogTrades, sizeof(QSPlayerLogTrade_Struct) + (sizeof(QSTradeItems_Struct) * trade_count));
// Perform actual trade // Perform actual trade
this->FinishTrade(other, qspack, true); this->FinishTrade(other, true, &event_entry, &event_details);
other->FinishTrade(this, qspack, false); other->FinishTrade(this, false, &event_entry, &event_details);
qspack->Deflate(); event_entry._detail_count = event_details.size();
if(worldserver.Connected()) { worldserver.SendPacket(qspack); }
safe_delete(qspack); ServerPacket* qs_pack = new ServerPacket(ServerOP_QSPlayerLogTrades, sizeof(QSPlayerLogTrade_Struct)+(sizeof(QSTradeItems_Struct)* event_entry._detail_count));
QSPlayerLogTrade_Struct* qs_buf = (QSPlayerLogTrade_Struct*)qs_pack->pBuffer;
memcpy(qs_buf, &event_entry, sizeof(QSPlayerLogTrade_Struct));
int offset = 0;
for (std::list<void*>::iterator iter = event_details.begin(); iter != event_details.end(); ++iter, ++offset) {
QSTradeItems_Struct* detail = reinterpret_cast<QSTradeItems_Struct*>(*iter);
qs_buf->items[offset] = *detail;
safe_delete(detail);
}
event_details.clear();
qs_pack->Deflate();
if(worldserver.Connected())
worldserver.SendPacket(qs_pack);
safe_delete(qs_pack);
// end QS code // end QS code
} }
else { else {
@ -4926,25 +4940,43 @@ void Client::Handle_OP_TradeAcceptClick(const EQApplicationPacket *app)
if(with->IsNPC()) { if(with->IsNPC()) {
// Audit trade to database for player trade stream // Audit trade to database for player trade stream
if(RuleB(QueryServ, PlayerLogHandins)) { if(RuleB(QueryServ, PlayerLogHandins)) {
uint16 handin_count = 0; QSPlayerLogHandin_Struct event_entry;
std::list<void*> event_details;
for(int16 slot_id = EmuConstants::TRADE_BEGIN; slot_id <= EmuConstants::TRADE_NPC_END; slot_id++) { memset(&event_entry, 0, sizeof(QSPlayerLogHandin_Struct));
if(m_inv[slot_id]) { handin_count += m_inv[slot_id]->GetTotalItemCount(); }
FinishTrade(with->CastToNPC(), false, &event_entry, &event_details);
event_entry._detail_count = event_details.size();
ServerPacket* qs_pack = new ServerPacket(ServerOP_QSPlayerLogHandins, sizeof(QSPlayerLogHandin_Struct)+(sizeof(QSHandinItems_Struct)* event_entry._detail_count));
QSPlayerLogHandin_Struct* qs_buf = (QSPlayerLogHandin_Struct*)qs_pack->pBuffer;
memcpy(qs_buf, &event_entry, sizeof(QSPlayerLogHandin_Struct));
int offset = 0;
for (std::list<void*>::iterator iter = event_details.begin(); iter != event_details.end(); ++iter, ++offset) {
QSHandinItems_Struct* detail = reinterpret_cast<QSHandinItems_Struct*>(*iter);
qs_buf->items[offset] = *detail;
safe_delete(detail);
} }
ServerPacket* qspack = new ServerPacket(ServerOP_QSPlayerLogHandins, sizeof(QSPlayerLogHandin_Struct) + (sizeof(QSHandinItems_Struct) * handin_count)); event_details.clear();
FinishTrade(with->CastToNPC(), qspack); qs_pack->Deflate();
qspack->Deflate(); if(worldserver.Connected())
if(worldserver.Connected()) { worldserver.SendPacket(qspack); } worldserver.SendPacket(qs_pack);
safe_delete(qspack);
safe_delete(qs_pack);
} }
else { else {
FinishTrade(with->CastToNPC()); FinishTrade(with->CastToNPC());
} }
} }
#ifdef BOTS #ifdef BOTS
// TODO: Log Bot trades
else if(with->IsBot()) else if(with->IsBot())
with->CastToBot()->FinishTrade(this, Bot::BotTradeClientNormal); with->CastToBot()->FinishTrade(this, Bot::BotTradeClientNormal);
#endif #endif
@ -5687,8 +5719,8 @@ void Client::Handle_OP_ShopPlayerBuy(const EQApplicationPacket *app)
safe_delete(outapp); safe_delete(outapp);
// start QS code // start QS code
if(RuleB(QueryServ, MerchantLogTransactions)) { if(RuleB(QueryServ, PlayerLogMerchantTransactions)) {
ServerPacket* qspack = new ServerPacket(ServerOP_QSMerchantLogTransactions, sizeof(QSMerchantLogTransaction_Struct) + sizeof(QSTransactionItems_Struct)); ServerPacket* qspack = new ServerPacket(ServerOP_QSPlayerLogMerchantTransactions, sizeof(QSMerchantLogTransaction_Struct) + sizeof(QSTransactionItems_Struct));
QSMerchantLogTransaction_Struct* qsaudit = (QSMerchantLogTransaction_Struct*)qspack->pBuffer; QSMerchantLogTransaction_Struct* qsaudit = (QSMerchantLogTransaction_Struct*)qspack->pBuffer;
qsaudit->zone_id = zone->GetZoneID(); qsaudit->zone_id = zone->GetZoneID();
@ -5823,8 +5855,8 @@ void Client::Handle_OP_ShopPlayerSell(const EQApplicationPacket *app)
} }
// start QS code // start QS code
if(RuleB(QueryServ, MerchantLogTransactions)) { if(RuleB(QueryServ, PlayerLogMerchantTransactions)) {
ServerPacket* qspack = new ServerPacket(ServerOP_QSMerchantLogTransactions, sizeof(QSMerchantLogTransaction_Struct) + sizeof(QSTransactionItems_Struct)); ServerPacket* qspack = new ServerPacket(ServerOP_QSPlayerLogMerchantTransactions, sizeof(QSMerchantLogTransaction_Struct) + sizeof(QSTransactionItems_Struct));
QSMerchantLogTransaction_Struct* qsaudit = (QSMerchantLogTransaction_Struct*)qspack->pBuffer; QSMerchantLogTransaction_Struct* qsaudit = (QSMerchantLogTransaction_Struct*)qspack->pBuffer;
qsaudit->zone_id = zone->GetZoneID(); qsaudit->zone_id = zone->GetZoneID();
@ -5984,7 +6016,7 @@ void Client::Handle_OP_ClickObject(const EQApplicationPacket *app)
object->HandleClick(this, click_object); object->HandleClick(this, click_object);
std::vector<void*> args; std::vector<EQEmu::Any> args;
args.push_back(object); args.push_back(object);
char buf[10]; char buf[10];
@ -6220,7 +6252,7 @@ void Client::Handle_OP_ClickDoor(const EQApplicationPacket *app)
char buf[20]; char buf[20];
snprintf(buf, 19, "%u", cd->doorid); snprintf(buf, 19, "%u", cd->doorid);
buf[19] = '\0'; buf[19] = '\0';
std::vector<void*> args; std::vector<EQEmu::Any> args;
args.push_back(currentdoor); args.push_back(currentdoor);
parse->EventPlayer(EVENT_CLICK_DOOR, this, buf, 0, &args); parse->EventPlayer(EVENT_CLICK_DOOR, this, buf, 0, &args);
@ -9180,8 +9212,7 @@ bool Client::FinishConnState2(DBAsyncWork* dbaw) {
if(!GetAA(aaPersistentMinion)) if(!GetAA(aaPersistentMinion))
memset(&m_suspendedminion, 0, sizeof(PetInfo)); memset(&m_suspendedminion, 0, sizeof(PetInfo));
//////////////////////////////////////////////////////////// /* Server Zone Entry Packet */
// Server Zone Entry Packet
outapp = new EQApplicationPacket(OP_ZoneEntry, sizeof(ServerZoneEntry_Struct)); outapp = new EQApplicationPacket(OP_ZoneEntry, sizeof(ServerZoneEntry_Struct));
ServerZoneEntry_Struct* sze = (ServerZoneEntry_Struct*)outapp->pBuffer; ServerZoneEntry_Struct* sze = (ServerZoneEntry_Struct*)outapp->pBuffer;
@ -9191,42 +9222,30 @@ bool Client::FinishConnState2(DBAsyncWork* dbaw) {
sze->player.spawn.z += 6; //arbitrary lift, seems to help spawning under zone. sze->player.spawn.z += 6; //arbitrary lift, seems to help spawning under zone.
outapp->priority = 6; outapp->priority = 6;
FastQueuePacket(&outapp); FastQueuePacket(&outapp);
//safe_delete(outapp);
//////////////////////////////////////////////////////////// /* Zone Spawns Packet */
// Zone Spawns Packet
entity_list.SendZoneSpawnsBulk(this); entity_list.SendZoneSpawnsBulk(this);
entity_list.SendZoneCorpsesBulk(this); entity_list.SendZoneCorpsesBulk(this);
entity_list.SendZonePVPUpdates(this); //hack until spawn struct is fixed. entity_list.SendZonePVPUpdates(this); //hack until spawn struct is fixed.
/* Time of Day packet */
////////////////////////////////////////////////////////////
// Time of Day packet
outapp = new EQApplicationPacket(OP_TimeOfDay, sizeof(TimeOfDay_Struct)); outapp = new EQApplicationPacket(OP_TimeOfDay, sizeof(TimeOfDay_Struct));
TimeOfDay_Struct* tod = (TimeOfDay_Struct*)outapp->pBuffer; TimeOfDay_Struct* tod = (TimeOfDay_Struct*)outapp->pBuffer;
zone->zone_time.getEQTimeOfDay(time(0), tod); zone->zone_time.getEQTimeOfDay(time(0), tod);
outapp->priority = 6; outapp->priority = 6;
FastQueuePacket(&outapp); FastQueuePacket(&outapp);
//safe_delete(outapp);
//I think this should happen earlier, not sure /* Tribute Packets */
/* if(GetHideMe())
SetHideMe(true); */
// Moved to Handle_Connect_OP_SendExpZonein();
////////////////////////////////////////////////////////////
// Tribute Packets
DoTributeUpdate(); DoTributeUpdate();
if(m_pp.tribute_active) { if(m_pp.tribute_active) {
//restart the tribute timer where we left off //restart the tribute timer where we left off
tribute_timer.Start(m_pp.tribute_time_remaining); tribute_timer.Start(m_pp.tribute_time_remaining);
} }
//////////////////////////////////////////////////////////// /*
// Character Inventory Packet Character Inventory Packet
//this is not quite where live sends inventory, they do it after tribute this is not quite where live sends inventory, they do it after tribute
*/
if (loaditems) { //dont load if a length error occurs if (loaditems) { //dont load if a length error occurs
BulkSendInventoryItems(); BulkSendInventoryItems();
@ -9241,9 +9260,7 @@ bool Client::FinishConnState2(DBAsyncWork* dbaw) {
} }
} }
/* Task Packets */
////////////////////////////////////////////////////////////
// Task Packets
LoadClientTaskState(); LoadClientTaskState();
if (GetClientVersion() >= EQClientRoF) if (GetClientVersion() >= EQClientRoF)
@ -9261,10 +9278,11 @@ bool Client::FinishConnState2(DBAsyncWork* dbaw) {
FastQueuePacket(&outapp); FastQueuePacket(&outapp);
} }
////////////////////////////////////// /*
// Weather Packet Weather Packet
// This shouldent be moved, this seems to be what the client This shouldent be moved, this seems to be what the client
// uses to advance to the next state (sending ReqNewZone) uses to advance to the next state (sending ReqNewZone)
*/
outapp = new EQApplicationPacket(OP_Weather, 12); outapp = new EQApplicationPacket(OP_Weather, 12);
Weather_Struct *ws = (Weather_Struct *) outapp->pBuffer; Weather_Struct *ws = (Weather_Struct *) outapp->pBuffer;
ws->val1 = 0x000000FF; ws->val1 = 0x000000FF;
@ -9279,16 +9297,6 @@ bool Client::FinishConnState2(DBAsyncWork* dbaw) {
QueuePacket(outapp); QueuePacket(outapp);
safe_delete(outapp); safe_delete(outapp);
//////////////////////////////////////
// Group Roles
//
//////////////////////////////////////
/*if(group){
group->NotifyMainTank(this, 1);
group->NotifyMainAssist(this, 1);
group->NotifyPuller(this, 1);
}*/
SetAttackTimer(); SetAttackTimer();
conn_state = ZoneInfoSent; conn_state = ZoneInfoSent;
@ -9296,9 +9304,8 @@ bool Client::FinishConnState2(DBAsyncWork* dbaw) {
return true; return true;
} }
// Finish client connecting state /* Finish client connecting state */
void Client::CompleteConnect() void Client::CompleteConnect() {
{
UpdateWho(); UpdateWho();
client_state = CLIENT_CONNECTED; client_state = CLIENT_CONNECTED;
@ -9311,7 +9318,7 @@ void Client::CompleteConnect()
EnteringMessages(this); EnteringMessages(this);
LoadZoneFlags(); LoadZoneFlags();
// Sets GM Flag if needed & Sends Petition Queue /* Sets GM Flag if needed & Sends Petition Queue */
UpdateAdmin(false); UpdateAdmin(false);
if (IsInAGuild()){ if (IsInAGuild()){
@ -9344,9 +9351,11 @@ void Client::CompleteConnect()
raid->LearnMembers(); raid->LearnMembers();
raid->VerifyRaid(); raid->VerifyRaid();
raid->GetRaidDetails(); raid->GetRaidDetails();
//only leader should get this; send to all for now till /*
//I figure out correct creation; can probably also send a no longer leader packet for non leaders Only leader should get this; send to all for now till
//but not important for now. I figure out correct creation; can probably also send a no longer leader packet for non leaders
but not important for now.
*/
raid->SendRaidCreate(this); raid->SendRaidCreate(this);
raid->SendMakeLeaderPacketTo(raid->leadername, this); raid->SendMakeLeaderPacketTo(raid->leadername, this);
raid->SendRaidAdd(GetName(), this); raid->SendRaidAdd(GetName(), this);
@ -9463,7 +9472,8 @@ void Client::CompleteConnect()
BuffFadeByEffect(SE_Levitate); BuffFadeByEffect(SE_Levitate);
Message(13, "You can't levitate in this zone."); Message(13, "You can't levitate in this zone.");
} }
}else{ }
else{
SendAppearancePacket(AT_Levitate, 2); SendAppearancePacket(AT_Levitate, 2);
} }
break; break;
@ -9499,10 +9509,10 @@ void Client::CompleteConnect()
} }
} }
//sends appearances for all mobs not doing anim_stand aka sitting, looting, playing dead /* Sends appearances for all mobs not doing anim_stand aka sitting, looting, playing dead */
entity_list.SendZoneAppearance(this); entity_list.SendZoneAppearance(this);
//sends the Nimbus particle effects (up to 3) for any mob using them /* Sends the Nimbus particle effects (up to 3) for any mob using them */
entity_list.SendNimbusEffects(this); entity_list.SendNimbusEffects(this);
entity_list.SendUntargetable(this); entity_list.SendUntargetable(this);
@ -9546,41 +9556,40 @@ void Client::CompleteConnect()
zone->weatherSend(); zone->weatherSend();
TotalKarma = database.GetKarma(AccountID()); TotalKarma = database.GetKarma(AccountID());
SendDisciplineTimers(); SendDisciplineTimers();
parse->EventPlayer(EVENT_ENTER_ZONE, this, "", 0); parse->EventPlayer(EVENT_ENTER_ZONE, this, "", 0);
//This sub event is for if a player logs in for the first time since entering world. /* This sub event is for if a player logs in for the first time since entering world. */
if(firstlogon == 1) if (firstlogon == 1){
parse->EventPlayer(EVENT_CONNECT, this, "", 0); parse->EventPlayer(EVENT_CONNECT, this, "", 0);
/* QS: PlayerLogConnectDisconnect */
if (RuleB(QueryServ, PlayerLogConnectDisconnect)){
std::string event_desc = StringFormat("Connect :: Logged into zoneid:%i instid:%i", this->GetZoneID(), this->GetInstanceID());
QServ->PlayerLogEvent(Player_Log_Connect_State, this->CharacterID(), event_desc);
}
}
if(zone) if(zone) {
{ if(zone->GetInstanceTimer()) {
if(zone->GetInstanceTimer())
{
uint32 ttime = zone->GetInstanceTimer()->GetRemainingTime(); uint32 ttime = zone->GetInstanceTimer()->GetRemainingTime();
uint32 day = (ttime/86400000); uint32 day = (ttime/86400000);
uint32 hour = (ttime/3600000)%24; uint32 hour = (ttime/3600000)%24;
uint32 minute = (ttime/60000)%60; uint32 minute = (ttime/60000)%60;
uint32 second = (ttime/1000)%60; uint32 second = (ttime/1000)%60;
if(day) if(day) {
{
Message(15, "%s(%u) will expire in %u days, %u hours, %u minutes, and %u seconds.", Message(15, "%s(%u) will expire in %u days, %u hours, %u minutes, and %u seconds.",
zone->GetLongName(), zone->GetInstanceID(), day, hour, minute, second); zone->GetLongName(), zone->GetInstanceID(), day, hour, minute, second);
} }
else if(hour) else if(hour) {
{
Message(15, "%s(%u) will expire in %u hours, %u minutes, and %u seconds.", Message(15, "%s(%u) will expire in %u hours, %u minutes, and %u seconds.",
zone->GetLongName(), zone->GetInstanceID(), hour, minute, second); zone->GetLongName(), zone->GetInstanceID(), hour, minute, second);
} }
else if(minute) else if(minute) {
{
Message(15, "%s(%u) will expire in %u minutes, and %u seconds.", Message(15, "%s(%u) will expire in %u minutes, and %u seconds.",
zone->GetLongName(), zone->GetInstanceID(), minute, second); zone->GetLongName(), zone->GetInstanceID(), minute, second);
} }
else else {
{
Message(15, "%s(%u) will expire in in %u seconds.", Message(15, "%s(%u) will expire in in %u seconds.",
zone->GetLongName(), zone->GetInstanceID(), second); zone->GetLongName(), zone->GetInstanceID(), second);
} }
@ -9603,8 +9612,7 @@ void Client::CompleteConnect()
if(GetClientVersion() >= EQClientSoD) if(GetClientVersion() >= EQClientSoD)
entity_list.SendFindableNPCList(this); entity_list.SendFindableNPCList(this);
if(IsInAGuild()) if(IsInAGuild()) {
{
SendGuildRanks(); SendGuildRanks();
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), zone->GetZoneID(), time(nullptr)); guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), zone->GetZoneID(), time(nullptr));
guild_mgr.RequestOnlineGuildMembers(this->CharacterID(), this->GuildID()); guild_mgr.RequestOnlineGuildMembers(this->CharacterID(), this->GuildID());
@ -9616,8 +9624,7 @@ void Client::CompleteConnect()
worldserver.SendPacket(pack); worldserver.SendPacket(pack);
delete pack; delete pack;
if(IsClient() && CastToClient()->GetClientVersionBit() & BIT_UnderfootAndLater) if(IsClient() && CastToClient()->GetClientVersionBit() & BIT_UnderfootAndLater) {
{
EQApplicationPacket *outapp = MakeBuffsPacket(false); EQApplicationPacket *outapp = MakeBuffsPacket(false);
CastToClient()->FastQueuePacket(&outapp); CastToClient()->FastQueuePacket(&outapp);
} }
@ -11433,92 +11440,68 @@ void Client::Handle_OP_SetStartCity(const EQApplicationPacket *app)
Message(15,"Your home city has already been set.", m_pp.binds[4].zoneId, database.GetZoneName(m_pp.binds[4].zoneId)); Message(15,"Your home city has already been set.", m_pp.binds[4].zoneId, database.GetZoneName(m_pp.binds[4].zoneId));
return; return;
} }
if (app->size < 1) { if (app->size < 1) {
LogFile->write(EQEMuLog::Error, "Wrong size: OP_SetStartCity, size=%i, expected %i", app->size, 1); LogFile->write(EQEMuLog::Error, "Wrong size: OP_SetStartCity, size=%i, expected %i", app->size, 1);
DumpPacket(app); DumpPacket(app);
return; return;
} }
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result = nullptr;
MYSQL_ROW row = 0;
float x(0),y(0),z(0); float x(0),y(0),z(0);
uint32 zoneid = 0; uint32 zoneid = 0;
uint32 startCity = (uint32)strtol((const char*)app->pBuffer, nullptr, 10);
uint32 StartCity = (uint32)strtol((const char*)app->pBuffer, nullptr, 10); std::string query = StringFormat("SELECT zone_id, bind_id, x, y, z FROM start_zones "
bool ValidCity = false;
database.RunQuery
(
query,
MakeAnyLenString
(
&query,
"SELECT zone_id, bind_id, x, y, z FROM start_zones "
"WHERE player_class=%i AND player_deity=%i AND player_race=%i", "WHERE player_class=%i AND player_deity=%i AND player_race=%i",
m_pp.class_, m_pp.class_, m_pp.deity, m_pp.race);
m_pp.deity, auto results = database.QueryDatabase(query);
m_pp.race if(!results.Success()) {
),
errbuf,
&result
);
safe_delete_array(query);
if(!result) {
LogFile->write(EQEMuLog::Error, "No valid start zones found for /setstartcity"); LogFile->write(EQEMuLog::Error, "No valid start zones found for /setstartcity");
return; return;
} }
while(row = mysql_fetch_row(result)) { bool validCity = false;
for (auto row = results.begin(); row != results.end(); ++row) {
if(atoi(row[1]) != 0) if(atoi(row[1]) != 0)
zoneid = atoi(row[1]); zoneid = atoi(row[1]);
else else
zoneid = atoi(row[0]); zoneid = atoi(row[0]);
if(zoneid == StartCity) { if(zoneid != startCity)
ValidCity = true; continue;
validCity = true;
x = atof(row[2]); x = atof(row[2]);
y = atof(row[3]); y = atof(row[3]);
z = atof(row[4]); z = atof(row[4]);
} }
if(validCity) {
Message(15,"Your home city has been set");
SetStartZone(startCity, x, y, z);
return;
} }
if(ValidCity) { query = StringFormat("SELECT zone_id, bind_id FROM start_zones "
Message(15,"Your home city has been set");
SetStartZone(StartCity, x, y, z);
}
else {
database.RunQuery
(
query,
MakeAnyLenString
(
&query,
"SELECT zone_id, bind_id FROM start_zones "
"WHERE player_class=%i AND player_deity=%i AND player_race=%i", "WHERE player_class=%i AND player_deity=%i AND player_race=%i",
m_pp.class_, m_pp.class_, m_pp.deity, m_pp.race);
m_pp.deity, results = database.QueryDatabase(query);
m_pp.race if (!results.Success())
), return;
errbuf,
&result
);
safe_delete_array(query);
Message(15,"Use \"/startcity #\" to choose a home city from the following list:"); Message(15,"Use \"/startcity #\" to choose a home city from the following list:");
char* name;
while(row = mysql_fetch_row(result)) { for (auto row = results.begin(); row != results.end(); ++row) {
if(atoi(row[1]) != 0) if(atoi(row[1]) != 0)
zoneid = atoi(row[1]); zoneid = atoi(row[1]);
else else
zoneid = atoi(row[0]); zoneid = atoi(row[0]);
char* name;
database.GetZoneLongName(database.GetZoneName(zoneid), &name); database.GetZoneLongName(database.GetZoneName(zoneid), &name);
Message(15,"%d - %s", zoneid, name); Message(15,"%d - %s", zoneid, name);
safe_delete_array(name);
}
} }
mysql_free_result(result);
} }
void Client::Handle_OP_Report(const EQApplicationPacket *app) void Client::Handle_OP_Report(const EQApplicationPacket *app)
@ -11625,7 +11608,7 @@ void Client::Handle_OP_GMSearchCorpse(const EQApplicationPacket *app)
// Could make this into a rule, although there is a hard limit since we are using a popup, of 4096 bytes that can // Could make this into a rule, although there is a hard limit since we are using a popup, of 4096 bytes that can
// be displayed in the window, including all the HTML formatting tags. // be displayed in the window, including all the HTML formatting tags.
// //
const int MaxResults = 10; const int maxResults = 10;
if(app->size < sizeof(GMSearchCorpse_Struct)) if(app->size < sizeof(GMSearchCorpse_Struct))
{ {
@ -11638,85 +11621,62 @@ void Client::Handle_OP_GMSearchCorpse(const EQApplicationPacket *app)
GMSearchCorpse_Struct *gmscs = (GMSearchCorpse_Struct *)app->pBuffer; GMSearchCorpse_Struct *gmscs = (GMSearchCorpse_Struct *)app->pBuffer;
gmscs->Name[63] = '\0'; gmscs->Name[63] = '\0';
char errbuf[MYSQL_ERRMSG_SIZE]; char *escSearchString = new char[129];
char* Query = 0; database.DoEscapeString(escSearchString, gmscs->Name, strlen(gmscs->Name));
MYSQL_RES *Result;
MYSQL_ROW Row;
char *EscSearchString = new char[129]; std::string query = StringFormat("SELECT charname, zoneid, x, y, z, timeofdeath, rezzed, IsBurried "
"FROM player_corpses WheRE charname LIKE '%%%s%%' ORDER BY charname LIMIT %i",
database.DoEscapeString(EscSearchString, gmscs->Name, strlen(gmscs->Name)); escSearchString, maxResults);
safe_delete_array(escSearchString);
if (database.RunQuery(Query, MakeAnyLenString(&Query, "select charname, zoneid, x, y, z, timeofdeath, rezzed, IsBurried from " auto results = database.QueryDatabase(query);
"player_corpses where charname like '%%%s%%' order by charname limit %i", if (!results.Success()) {
EscSearchString, MaxResults), errbuf, &Result)) Message(0, "Query failed: %s.", results.ErrorMessage().c_str());
{
int NumberOfRows = mysql_num_rows(Result);
if(NumberOfRows == MaxResults)
Message(clientMessageError, "Your search found too many results; some are not displayed.");
else {
Message(clientMessageYellow, "There are %i corpse(s) that match the search string '%s'.",
NumberOfRows, gmscs->Name);
}
if(NumberOfRows == 0)
{
mysql_free_result(Result);
safe_delete_array(Query);
return; return;
} }
char CharName[64], TimeOfDeath[20], Buffer[512]; if (results.RowCount() == 0)
return;
std::string PopupText = "<table><tr><td>Name</td><td>Zone</td><td>X</td><td>Y</td><td>Z</td><td>Date</td><td>" if(results.RowCount() == maxResults)
Message(clientMessageError, "Your search found too many results; some are not displayed.");
else
Message(clientMessageYellow, "There are %i corpse(s) that match the search string '%s'.", results.RowCount(), gmscs->Name);
char charName[64], timeOfDeath[20];
std::string popupText = "<table><tr><td>Name</td><td>Zone</td><td>X</td><td>Y</td><td>Z</td><td>Date</td><td>"
"Rezzed</td><td>Buried</td></tr><tr><td>&nbsp</td><td></td><td></td><td></td><td></td><td>" "Rezzed</td><td>Buried</td></tr><tr><td>&nbsp</td><td></td><td></td><td></td><td></td><td>"
"</td><td></td><td></td></tr>"; "</td><td></td><td></td></tr>";
for (auto row = results.begin(); row != results.end(); ++row) {
while ((Row = mysql_fetch_row(Result))) strn0cpy(charName, row[0], sizeof(charName));
{
strn0cpy(CharName, Row[0], sizeof(CharName)); uint32 ZoneID = atoi(row[1]);
float CorpseX = atof(row[2]);
float CorpseY = atof(row[3]);
float CorpseZ = atof(row[4]);
uint32 ZoneID = atoi(Row[1]); strn0cpy(timeOfDeath, row[5], sizeof(timeOfDeath));
float CorpseX = atof(Row[2]); bool corpseRezzed = atoi(row[6]);
float CorpseY = atof(Row[3]); bool corpseBuried = atoi(row[7]);
float CorpseZ = atof(Row[4]);
strn0cpy(TimeOfDeath, Row[5], sizeof(TimeOfDeath)); popupText += StringFormat("<tr><td>%s</td><td>%s</td><td>%8.0f</td><td>%8.0f</td><td>%8.0f</td><td>%s</td><td>%s</td><td>%s</td></tr>",
charName, StaticGetZoneName(ZoneID), CorpseX, CorpseY, CorpseZ, timeOfDeath,
corpseRezzed ? "Yes" : "No", corpseBuried ? "Yes" : "No");
bool CorpseRezzed = atoi(Row[6]); if(popupText.size() > 4000) {
bool CorpseBuried = atoi(Row[7]);
sprintf(Buffer, "<tr><td>%s</td><td>%s</td><td>%8.0f</td><td>%8.0f</td><td>%8.0f</td><td>%s</td><td>%s</td><td>%s</td></tr>",
CharName, StaticGetZoneName(ZoneID), CorpseX, CorpseY, CorpseZ, TimeOfDeath,
CorpseRezzed ? "Yes" : "No", CorpseBuried ? "Yes" : "No");
PopupText += Buffer;
if(PopupText.size() > 4000)
{
Message(clientMessageError, "Unable to display all the results."); Message(clientMessageError, "Unable to display all the results.");
break; break;
} }
} }
PopupText += "</table>"; popupText += "</table>";
mysql_free_result(Result); SendPopupToClient("Corpses", popupText.c_str());
SendPopupToClient("Corpses", PopupText.c_str());
}
else{
Message(0, "Query failed: %s.", errbuf);
}
safe_delete_array(Query);
safe_delete_array(EscSearchString);
} }
void Client::Handle_OP_GuildBank(const EQApplicationPacket *app) void Client::Handle_OP_GuildBank(const EQApplicationPacket *app)
@ -12749,6 +12709,12 @@ void Client::Handle_OP_AltCurrencyPurchase(const EQApplicationPacket *app) {
return; return;
} }
/* QS: PlayerLogAlternateCurrencyTransactions :: Merchant Purchase */
if (RuleB(QueryServ, PlayerLogAlternateCurrencyTransactions)){
std::string event_desc = StringFormat("Merchant Purchase :: Spent alt_currency_id:%i cost:%i for itemid:%i in zoneid:%i instid:%i", alt_cur_id, cost, item->ID, this->GetZoneID(), this->GetInstanceID());
QServ->PlayerLogEvent(Player_Log_Alternate_Currency_Transactions, this->CharacterID(), event_desc);
}
AddAlternateCurrencyValue(alt_cur_id, -((int32)cost)); AddAlternateCurrencyValue(alt_cur_id, -((int32)cost));
int16 charges = 1; int16 charges = 1;
if(item->MaxCharges != 0) if(item->MaxCharges != 0)
@ -12780,20 +12746,37 @@ void Client::Handle_OP_AltCurrencyReclaim(const EQApplicationPacket *app) {
return; return;
} }
if(reclaim->reclaim_flag == 1) { //item -> altcur /* Item to Currency Storage */
if(reclaim->reclaim_flag == 1) {
uint32 removed = NukeItem(item_id, invWhereWorn | invWherePersonal | invWhereCursor); uint32 removed = NukeItem(item_id, invWhereWorn | invWherePersonal | invWhereCursor);
if(removed > 0) { if(removed > 0) {
AddAlternateCurrencyValue(reclaim->currency_id, removed); AddAlternateCurrencyValue(reclaim->currency_id, removed);
/* QS: PlayerLogAlternateCurrencyTransactions :: Item to Currency */
if (RuleB(QueryServ, PlayerLogAlternateCurrencyTransactions)){
std::string event_desc = StringFormat("Reclaim :: Item to Currency :: alt_currency_id:%i amount:%i to currency tab in zoneid:%i instid:%i", reclaim->currency_id, removed, this->GetZoneID(), this->GetInstanceID());
QServ->PlayerLogEvent(Player_Log_Alternate_Currency_Transactions, this->CharacterID(), event_desc);
} }
} else { }
}
/* Cursor to Item storage */
else {
uint32 max_currency = GetAlternateCurrencyValue(reclaim->currency_id); uint32 max_currency = GetAlternateCurrencyValue(reclaim->currency_id);
/* If you input more than you have currency wise, just give the max of the currency you currently have */
if(reclaim->count > max_currency) { if(reclaim->count > max_currency) {
SummonItem(item_id, max_currency); SummonItem(item_id, max_currency);
SetAlternateCurrencyValue(reclaim->currency_id, 0); SetAlternateCurrencyValue(reclaim->currency_id, 0);
} else { }
else {
SummonItem(item_id, reclaim->count, 0, 0, 0, 0, 0, false, MainCursor); SummonItem(item_id, reclaim->count, 0, 0, 0, 0, 0, false, MainCursor);
AddAlternateCurrencyValue(reclaim->currency_id, -((int32)reclaim->count)); AddAlternateCurrencyValue(reclaim->currency_id, -((int32)reclaim->count));
} }
/* QS: PlayerLogAlternateCurrencyTransactions :: Cursor to Item Storage */
if (RuleB(QueryServ, PlayerLogAlternateCurrencyTransactions)){
std::string event_desc = StringFormat("Reclaim :: Cursor to Item :: alt_currency_id:%i amount:-%i in zoneid:%i instid:%i", reclaim->currency_id, reclaim->count, this->GetZoneID(), this->GetInstanceID());
QServ->PlayerLogEvent(Player_Log_Alternate_Currency_Transactions, this->CharacterID(), event_desc);
}
} }
} }
@ -12829,6 +12812,7 @@ void Client::Handle_OP_AltCurrencySell(const EQApplicationPacket *app) {
uint32 cost = 0; uint32 cost = 0;
uint32 current_currency = GetAlternateCurrencyValue(alt_cur_id); uint32 current_currency = GetAlternateCurrencyValue(alt_cur_id);
uint32 merchant_id = tar->MerchantType; uint32 merchant_id = tar->MerchantType;
uint32 npc_id = tar->GetNPCTypeID();
bool found = false; bool found = false;
std::list<MerchantList> merlist = zone->merchanttable[merchant_id]; std::list<MerchantList> merlist = zone->merchanttable[merchant_id];
std::list<MerchantList>::const_iterator itr; std::list<MerchantList>::const_iterator itr;
@ -12881,6 +12865,12 @@ void Client::Handle_OP_AltCurrencySell(const EQApplicationPacket *app) {
sell->cost = cost; sell->cost = cost;
/* QS: PlayerLogAlternateCurrencyTransactions :: Sold to Merchant*/
if (RuleB(QueryServ, PlayerLogAlternateCurrencyTransactions)){
std::string event_desc = StringFormat("Sold to Merchant :: itemid:%u npcid:%u alt_currency_id:%u cost:%u in zoneid:%u instid:%i", item->ID, npc_id, alt_cur_id, cost, this->GetZoneID(), this->GetInstanceID());
QServ->PlayerLogEvent(Player_Log_Alternate_Currency_Transactions, this->CharacterID(), event_desc);
}
FastQueuePacket(&outapp); FastQueuePacket(&outapp);
AddAlternateCurrencyValue(alt_cur_id, cost); AddAlternateCurrencyValue(alt_cur_id, cost);
Save(1); Save(1);

View File

@ -63,7 +63,9 @@
#include "guild_mgr.h" #include "guild_mgr.h"
#include <string> #include <string>
#include "quest_parser_collection.h" #include "quest_parser_collection.h"
#include "queryserv.h"
extern QueryServ* QServ;
extern Zone* zone; extern Zone* zone;
extern volatile bool ZoneLoaded; extern volatile bool ZoneLoaded;
extern WorldServer worldserver; extern WorldServer worldserver;
@ -770,38 +772,40 @@ bool Client::Process() {
return ret; return ret;
} }
//just a set of actions preformed all over in Client::Process /* Just a set of actions preformed all over in Client::Process */
void Client::OnDisconnect(bool hard_disconnect) { void Client::OnDisconnect(bool hard_disconnect) {
if(hard_disconnect) { if(hard_disconnect) {
LeaveGroup(); LeaveGroup();
Raid *MyRaid = entity_list.GetRaidByClient(this); Raid *MyRaid = entity_list.GetRaidByClient(this);
if (MyRaid) if (MyRaid)
MyRaid->MemberZoned(this); MyRaid->MemberZoned(this);
parse->EventPlayer(EVENT_DISCONNECT, this, "", 0); parse->EventPlayer(EVENT_DISCONNECT, this, "", 0);
/* QS: PlayerLogConnectDisconnect */
if (RuleB(QueryServ, PlayerLogConnectDisconnect)){
std::string event_desc = StringFormat("Disconnect :: in zoneid:%i instid:%i", this->GetZoneID(), this->GetInstanceID());
QServ->PlayerLogEvent(Player_Log_Connect_State, this->CharacterID(), event_desc);
}
} }
Mob *Other = trade->With(); Mob *Other = trade->With();
if(Other) {
if(Other)
{
mlog(TRADING__CLIENT, "Client disconnected during a trade. Returning their items."); mlog(TRADING__CLIENT, "Client disconnected during a trade. Returning their items.");
FinishTrade(this); FinishTrade(this);
if(Other->IsClient()) if(Other->IsClient())
Other->CastToClient()->FinishTrade(Other); Other->CastToClient()->FinishTrade(Other);
/* Reset both sides of the trade */
trade->Reset(); trade->Reset();
Other->trade->Reset(); Other->trade->Reset();
} }
database.SetFirstLogon(CharacterID(), 0); //We change firstlogon status regardless of if a player logs out to zone or not, because we only want to trigger it on their first login from world. database.SetFirstLogon(CharacterID(), 0); //We change firstlogon status regardless of if a player logs out to zone or not, because we only want to trigger it on their first login from world.
//remove ourself from all proximities /* Remove ourself from all proximities */
ClearAllProximities(); ClearAllProximities();
EQApplicationPacket *outapp = new EQApplicationPacket(OP_LogoutReply); EQApplicationPacket *outapp = new EQApplicationPacket(OP_LogoutReply);

View File

@ -62,8 +62,9 @@
#include "guild_mgr.h" #include "guild_mgr.h"
#include "titles.h" #include "titles.h"
#include "../common/patches/patches.h" #include "../common/patches/patches.h"
#include "queryserv.h"
// these should be in the headers... extern QueryServ* QServ;
extern WorldServer worldserver; extern WorldServer worldserver;
extern TaskManager *taskmanager; extern TaskManager *taskmanager;
void CatchSignal(int sig_num); void CatchSignal(int sig_num);
@ -588,6 +589,12 @@ int command_realdispatch(Client *c, const char *message)
return(-1); return(-1);
} }
/* QS: Player_Log_Issued_Commands */
if (RuleB(QueryServ, PlayerLogIssuedCommandes)){
std::string event_desc = StringFormat("Issued command :: '%s' in zoneid:%i instid:%i", message, c->GetZoneID(), c->GetInstanceID());
QServ->PlayerLogEvent(Player_Log_Issued_Commands, c->CharacterID(), event_desc);
}
#ifdef COMMANDS_LOGGING #ifdef COMMANDS_LOGGING
if(cur->access >= COMMANDS_LOGGING_MIN_STATUS) { if(cur->access >= COMMANDS_LOGGING_MIN_STATUS) {
LogFile->write(EQEMuLog::Commands, "%s (%s) used command: %s (target=%s)", c->GetName(), c->AccountName(), message, c->GetTarget()?c->GetTarget()->GetName():"NONE"); LogFile->write(EQEMuLog::Commands, "%s (%s) used command: %s (target=%s)", c->GetName(), c->AccountName(), message, c->GetTarget()?c->GetTarget()->GetName():"NONE");

View File

@ -127,7 +127,8 @@ enum {
FLEE_PERCENT = 37, FLEE_PERCENT = 37,
ALLOW_BENEFICIAL = 38, ALLOW_BENEFICIAL = 38,
DISABLE_MELEE = 39, DISABLE_MELEE = 39,
MAX_SPECIAL_ATTACK = 40 NPC_CHASE_DISTANCE = 40,
MAX_SPECIAL_ATTACK = 41
}; };
@ -526,7 +527,7 @@ public:
Mob* With(); Mob* With();
// Add item from cursor slot to trade bucket (automatically does bag data too) // Add item from cursor slot to trade bucket (automatically does bag data too)
void AddEntity(uint16 from_slot_id, uint16 trade_slot_id, uint32 stack_size); void AddEntity(uint16 trade_slot_id, uint32 stack_size);
// Audit trade // Audit trade
void LogTrade(); void LogTrade();

View File

@ -1164,7 +1164,7 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app)
strcpy(corpse_name, orgname); strcpy(corpse_name, orgname);
snprintf(buf, 87, "%d %d %s", inst->GetItem()->ID, inst->GetCharges(), EntityList::RemoveNumbers(corpse_name)); snprintf(buf, 87, "%d %d %s", inst->GetItem()->ID, inst->GetCharges(), EntityList::RemoveNumbers(corpse_name));
buf[87] = '\0'; buf[87] = '\0';
std::vector<void*> args; std::vector<EQEmu::Any> args;
args.push_back(inst); args.push_back(inst);
args.push_back(this); args.push_back(this);
parse->EventPlayer(EVENT_LOOT, client, buf, 0, &args); parse->EventPlayer(EVENT_LOOT, client, buf, 0, &args);

View File

@ -568,157 +568,137 @@ void Doors::DumpDoor(){
} }
int32 ZoneDatabase::GetDoorsCount(uint32* oMaxID, const char *zone_name, int16 version) { int32 ZoneDatabase::GetDoorsCount(uint32* oMaxID, const char *zone_name, int16 version) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result; std::string query = StringFormat("SELECT MAX(id), count(*) FROM doors "
MYSQL_ROW row; "WHERE zone = '%s' AND (version = %u OR version = -1)",
query = new char[256]; zone_name, version);
sprintf(query, "SELECT MAX(id), count(*) FROM doors WHERE zone='%s' AND (version=%u OR version=-1)", zone_name, version); auto results = QueryDatabase(query);
if (RunQuery(query, strlen(query), errbuf, &result)) { if (!results.Success()) {
safe_delete_array(query); std::cerr << "Error in GetDoorsCount query '" << query << "' " << results.ErrorMessage() << std::endl;
row = mysql_fetch_row(result); return -1;
if (row != nullptr && row[1] != 0) { }
int32 ret = atoi(row[1]);
if (oMaxID) { if (results.RowCount() != 1)
return -1;
auto row = results.begin();
if (!oMaxID)
return atoi(row[1]);
if (row[0]) if (row[0])
*oMaxID = atoi(row[0]); *oMaxID = atoi(row[0]);
else else
*oMaxID = 0; *oMaxID = 0;
}
mysql_free_result(result);
return ret;
}
mysql_free_result(result);
}
else {
std::cerr << "Error in GetDoorsCount query '" << query << "' " << errbuf << std::endl;
safe_delete_array(query);
return -1;
}
return -1; return atoi(row[1]);
} }
int32 ZoneDatabase::GetDoorsCountPlusOne(const char *zone_name, int16 version) { int32 ZoneDatabase::GetDoorsCountPlusOne(const char *zone_name, int16 version) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
uint32 oMaxID = 0;
MYSQL_RES *result; std::string query = StringFormat("SELECT MAX(id) FROM doors "
MYSQL_ROW row; "WHERE zone = '%s' AND version = %u", zone_name, version);
query = new char[256]; auto results = QueryDatabase(query);
sprintf(query, "SELECT MAX(id) FROM doors WHERE zone='%s' AND version=%u", zone_name, version); if (!results.Success()) {
if (RunQuery(query, strlen(query), errbuf, &result)) { std::cerr << "Error in GetDoorsCountPlusOne query '" << query << "' " << results.ErrorMessage() << std::endl;
safe_delete_array(query);
row = mysql_fetch_row(result);
if (row != nullptr && row[1] != 0) {
if (row[0])
oMaxID = atoi(row[0]) + 1;
else
oMaxID = 0;
mysql_free_result(result);
return oMaxID;
}
mysql_free_result(result);
}
else {
std::cerr << "Error in GetDoorsCountPlusOne query '" << query << "' " << errbuf << std::endl;
safe_delete_array(query);
return -1; return -1;
} }
if (results.RowCount() != 1)
return -1; return -1;
auto row = results.begin();
if (!row[0])
return 0;
return atoi(row[0]) + 1;
} }
int32 ZoneDatabase::GetDoorsDBCountPlusOne(const char *zone_name, int16 version) { int32 ZoneDatabase::GetDoorsDBCountPlusOne(const char *zone_name, int16 version) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
uint32 oMaxID = 0; uint32 oMaxID = 0;
MYSQL_RES *result; std::string query = StringFormat("SELECT MAX(doorid) FROM doors "
MYSQL_ROW row; "WHERE zone = '%s' AND (version = %u OR version = -1)",
query = new char[256]; zone_name, version);
sprintf(query, "SELECT MAX(doorid) FROM doors WHERE zone='%s' AND (version=%u OR version=-1)", zone_name, version); auto results = QueryDatabase(query);
if (RunQuery(query, strlen(query), errbuf, &result)) { if (!results.Success()) {
safe_delete_array(query); std::cerr << "Error in GetDoorsCountPlusOne query '" << query << "' " << results.ErrorMessage() << std::endl;
row = mysql_fetch_row(result);
if (row != nullptr && row[1] != 0) {
if (row[0])
oMaxID = atoi(row[0]) + 1;
else
oMaxID = 0;
mysql_free_result(result);
return oMaxID;
}
mysql_free_result(result);
}
else {
std::cerr << "Error in GetDoorsCountPlusOne query '" << query << "' " << errbuf << std::endl;
safe_delete_array(query);
return -1; return -1;
} }
if (results.RowCount() != 1)
return -1; return -1;
auto row = results.begin();
if (!row[0])
return 0;
return atoi(row[0]) + 1;
} }
bool ZoneDatabase::LoadDoors(int32 iDoorCount, Door *into, const char *zone_name, int16 version) { bool ZoneDatabase::LoadDoors(int32 iDoorCount, Door *into, const char *zone_name, int16 version) {
LogFile->write(EQEMuLog::Status, "Loading Doors from database..."); LogFile->write(EQEMuLog::Status, "Loading Doors from database...");
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
// Door tmpDoor; // Door tmpDoor;
MakeAnyLenString(&query, "SELECT id,doorid,zone,name,pos_x,pos_y,pos_z,heading," std::string query = StringFormat("SELECT id, doorid, zone, name, pos_x, pos_y, pos_z, heading, "
"opentype,guild,lockpick,keyitem,nokeyring,triggerdoor,triggertype,dest_zone,dest_instance,dest_x," "opentype, guild, lockpick, keyitem, nokeyring, triggerdoor, triggertype, "
"dest_y,dest_z,dest_heading,door_param,invert_state,incline,size,is_ldon_door,client_version_mask " "dest_zone, dest_instance, dest_x, dest_y, dest_z, dest_heading, "
"FROM doors WHERE zone='%s' AND (version=%u OR version=-1) ORDER BY doorid asc", zone_name, version); "door_param, invert_state, incline, size, is_ldon_door, client_version_mask "
if (RunQuery(query, strlen(query), errbuf, &result)) { "FROM doors WHERE zone = '%s' AND (version = %u OR version = -1) "
safe_delete_array(query); "ORDER BY doorid asc", zone_name, version);
int32 r; auto results = QueryDatabase(query);
for(r = 0; (row = mysql_fetch_row(result)); r++) { if (!results.Success()){
if(r >= iDoorCount) { std::cerr << "Error in DBLoadDoors query '" << query << "' " << results.ErrorMessage() << std::endl;
return false;
}
int32 rowIndex = 0;
for(auto row = results.begin(); row != results.end(); ++row, ++rowIndex) {
if(rowIndex >= iDoorCount) {
std::cerr << "Error, Door Count of " << iDoorCount << " exceeded." << std::endl; std::cerr << "Error, Door Count of " << iDoorCount << " exceeded." << std::endl;
break; break;
} }
memset(&into[r], 0, sizeof(Door));
into[r].db_id = atoi(row[0]); memset(&into[rowIndex], 0, sizeof(Door));
into[r].door_id = atoi(row[1]);
strn0cpy(into[r].zone_name,row[2],32); into[rowIndex].db_id = atoi(row[0]);
strn0cpy(into[r].door_name,row[3],32); into[rowIndex].door_id = atoi(row[1]);
into[r].pos_x = (float)atof(row[4]);
into[r].pos_y = (float)atof(row[5]); strn0cpy(into[rowIndex].zone_name,row[2],32);
into[r].pos_z = (float)atof(row[6]); strn0cpy(into[rowIndex].door_name,row[3],32);
into[r].heading = (float)atof(row[7]);
into[r].opentype = atoi(row[8]); into[rowIndex].pos_x = (float)atof(row[4]);
into[r].guild_id = atoi(row[9]); into[rowIndex].pos_y = (float)atof(row[5]);
into[r].lockpick = atoi(row[10]); into[rowIndex].pos_z = (float)atof(row[6]);
into[r].keyitem = atoi(row[11]); into[rowIndex].heading = (float)atof(row[7]);
into[r].nokeyring = atoi(row[12]); into[rowIndex].opentype = atoi(row[8]);
into[r].trigger_door = atoi(row[13]); into[rowIndex].guild_id = atoi(row[9]);
into[r].trigger_type = atoi(row[14]); into[rowIndex].lockpick = atoi(row[10]);
strn0cpy(into[r].dest_zone, row[15], 32); into[rowIndex].keyitem = atoi(row[11]);
into[r].dest_instance_id = atoi(row[16]); into[rowIndex].nokeyring = atoi(row[12]);
into[r].dest_x = (float) atof(row[17]); into[rowIndex].trigger_door = atoi(row[13]);
into[r].dest_y = (float) atof(row[18]); into[rowIndex].trigger_type = atoi(row[14]);
into[r].dest_z = (float) atof(row[19]);
into[r].dest_heading = (float) atof(row[20]); strn0cpy(into[rowIndex].dest_zone, row[15], 32);
into[r].door_param=atoi(row[21]);
into[r].invert_state=atoi(row[22]); into[rowIndex].dest_instance_id = atoi(row[16]);
into[r].incline=atoi(row[23]); into[rowIndex].dest_x = (float) atof(row[17]);
into[r].size=atoi(row[24]); into[rowIndex].dest_y = (float) atof(row[18]);
into[r].is_ldon_door=atoi(row[25]); into[rowIndex].dest_z = (float) atof(row[19]);
into[r].client_version_mask = (uint32)strtoul(row[26], nullptr, 10); into[rowIndex].dest_heading = (float) atof(row[20]);
} into[rowIndex].door_param=atoi(row[21]);
mysql_free_result(result); into[rowIndex].invert_state=atoi(row[22]);
} into[rowIndex].incline=atoi(row[23]);
else into[rowIndex].size=atoi(row[24]);
{ into[rowIndex].is_ldon_door=atoi(row[25]);
std::cerr << "Error in DBLoadDoors query '" << query << "' " << errbuf << std::endl; into[rowIndex].client_version_mask = (uint32)strtoul(row[26], nullptr, 10);
safe_delete_array(query);
return false;
} }
return true; return true;
} }

View File

@ -154,7 +154,7 @@ void PerlembParser::ReloadQuests() {
} }
int PerlembParser::EventCommon(QuestEventID event, uint32 objid, const char * data, NPC* npcmob, ItemInst* iteminst, Mob* mob, int PerlembParser::EventCommon(QuestEventID event, uint32 objid, const char * data, NPC* npcmob, ItemInst* iteminst, Mob* mob,
uint32 extradata, bool global, std::vector<void*> *extra_pointers) uint32 extradata, bool global, std::vector<EQEmu::Any> *extra_pointers)
{ {
if(!perl) if(!perl)
return 0; return 0;
@ -211,32 +211,32 @@ int PerlembParser::EventCommon(QuestEventID event, uint32 objid, const char * da
} }
int PerlembParser::EventNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, int PerlembParser::EventNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
return EventCommon(evt, npc->GetNPCTypeID(), data.c_str(), npc, nullptr, init, extra_data, false, extra_pointers); return EventCommon(evt, npc->GetNPCTypeID(), data.c_str(), npc, nullptr, init, extra_data, false, extra_pointers);
} }
int PerlembParser::EventGlobalNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, int PerlembParser::EventGlobalNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
return EventCommon(evt, npc->GetNPCTypeID(), data.c_str(), npc, nullptr, init, extra_data, true, extra_pointers); return EventCommon(evt, npc->GetNPCTypeID(), data.c_str(), npc, nullptr, init, extra_data, true, extra_pointers);
} }
int PerlembParser::EventPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data, int PerlembParser::EventPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
return EventCommon(evt, 0, data.c_str(), nullptr, nullptr, client, extra_data, false, extra_pointers); return EventCommon(evt, 0, data.c_str(), nullptr, nullptr, client, extra_data, false, extra_pointers);
} }
int PerlembParser::EventGlobalPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data, int PerlembParser::EventGlobalPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
return EventCommon(evt, 0, data.c_str(), nullptr, nullptr, client, extra_data, true, extra_pointers); return EventCommon(evt, 0, data.c_str(), nullptr, nullptr, client, extra_data, true, extra_pointers);
} }
int PerlembParser::EventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data, int PerlembParser::EventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
return EventCommon(evt, item->GetID(), nullptr, nullptr, item, client, extra_data, false, extra_pointers); return EventCommon(evt, item->GetID(), nullptr, nullptr, item, client, extra_data, false, extra_pointers);
} }
int PerlembParser::EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, int PerlembParser::EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
return EventCommon(evt, 0, itoa(spell_id), npc, nullptr, client, extra_data, false, extra_pointers); return EventCommon(evt, 0, itoa(spell_id), npc, nullptr, client, extra_data, false, extra_pointers);
} }
@ -1114,7 +1114,7 @@ void PerlembParser::ExportItemVariables(std::string &package_name, Mob *mob) {
#undef HASITEM_ISNULLITEM #undef HASITEM_ISNULLITEM
void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID event, uint32 objid, const char * data, void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID event, uint32 objid, const char * data,
NPC* npcmob, ItemInst* iteminst, Mob* mob, uint32 extradata, std::vector<void*> *extra_pointers) NPC* npcmob, ItemInst* iteminst, Mob* mob, uint32 extradata, std::vector<EQEmu::Any> *extra_pointers)
{ {
switch (event) { switch (event) {
case EVENT_SAY: { case EVENT_SAY: {
@ -1131,7 +1131,7 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
case EVENT_TRADE: { case EVENT_TRADE: {
if(extra_pointers) { if(extra_pointers) {
for(size_t i = 0; i < extra_pointers->size(); ++i) { for(size_t i = 0; i < extra_pointers->size(); ++i) {
ItemInst *inst = reinterpret_cast<ItemInst*>(extra_pointers->at(i)); ItemInst *inst = EQEmu::any_cast<ItemInst*>(extra_pointers->at(i));
std::string var_name = "item"; std::string var_name = "item";
var_name += std::to_string(static_cast<long long>(i + 1)); var_name += std::to_string(static_cast<long long>(i + 1));

View File

@ -45,17 +45,17 @@ public:
~PerlembParser(); ~PerlembParser();
virtual int EventNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, virtual int EventNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
virtual int EventGlobalNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, virtual int EventGlobalNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
virtual int EventPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data, virtual int EventPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
virtual int EventGlobalPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data, virtual int EventGlobalPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
virtual int EventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data, virtual int EventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
virtual int EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, virtual int EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
virtual bool HasQuestSub(uint32 npcid, QuestEventID evt); virtual bool HasQuestSub(uint32 npcid, QuestEventID evt);
virtual bool HasGlobalQuestSub(QuestEventID evt); virtual bool HasGlobalQuestSub(QuestEventID evt);
@ -86,7 +86,7 @@ private:
void ExportVarComplex(const char *pkgprefix, const char *varname, const char *value); void ExportVarComplex(const char *pkgprefix, const char *varname, const char *value);
int EventCommon(QuestEventID event, uint32 objid, const char * data, NPC* npcmob, ItemInst* iteminst, Mob* mob, int EventCommon(QuestEventID event, uint32 objid, const char * data, NPC* npcmob, ItemInst* iteminst, Mob* mob,
uint32 extradata, bool global, std::vector<void*> *extra_pointers); uint32 extradata, bool global, std::vector<EQEmu::Any> *extra_pointers);
int SendCommands(const char *pkgprefix, const char *event, uint32 npcid, Mob* other, Mob* mob, ItemInst *iteminst); int SendCommands(const char *pkgprefix, const char *event, uint32 npcid, Mob* other, Mob* mob, ItemInst *iteminst);
void MapFunctions(); void MapFunctions();
@ -103,7 +103,7 @@ private:
void ExportZoneVariables(std::string &package_name); void ExportZoneVariables(std::string &package_name);
void ExportItemVariables(std::string &package_name, Mob *mob); void ExportItemVariables(std::string &package_name, Mob *mob);
void ExportEventVariables(std::string &package_name, QuestEventID event, uint32 objid, const char * data, void ExportEventVariables(std::string &package_name, QuestEventID event, uint32 objid, const char * data,
NPC* npcmob, ItemInst* iteminst, Mob* mob, uint32 extradata, std::vector<void*> *extra_pointers); NPC* npcmob, ItemInst* iteminst, Mob* mob, uint32 extradata, std::vector<EQEmu::Any> *extra_pointers);
std::map<uint32, PerlQuestStatus> npc_quest_status_; std::map<uint32, PerlQuestStatus> npc_quest_status_;
PerlQuestStatus global_npc_quest_status_; PerlQuestStatus global_npc_quest_status_;

View File

@ -28,8 +28,10 @@
#include "embxs.h" #include "embxs.h"
#include "entity.h" #include "entity.h"
#include "zone.h" #include "zone.h"
#include "queryserv.h"
extern Zone* zone; extern Zone* zone;
extern QueryServ* QServ;
/* /*
@ -3370,6 +3372,36 @@ XS(XS__clear_npctype_cache)
XSRETURN_EMPTY; XSRETURN_EMPTY;
} }
XS(XS__qs_send_query);
XS(XS__qs_send_query)
{
dXSARGS;
if (items != 1){
Perl_croak(aTHX_ "Usage: qs_send_query(query)");
}
else{
// char *Query = (char *)SvPV_nolen(ST(0));
std::string Query = (std::string)SvPV_nolen(ST(0));
QServ->SendQuery(Query);
}
XSRETURN_EMPTY;
}
XS(XS__qs_player_event);
XS(XS__qs_player_event)
{
dXSARGS;
if (items != 2){
Perl_croak(aTHX_ "Usage: qs_player_event(char_id, event_desc)");
}
else{
int char_id = (int)SvIV(ST(0));
std::string event_desc = (std::string)SvPV_nolen(ST(1));
QServ->PlayerLogEvent(Player_Log_Quest, char_id, event_desc);
}
XSRETURN_EMPTY;
}
/* /*
This is the callback perl will look for to setup the This is the callback perl will look for to setup the
quest package's XSUBs quest package's XSUBs
@ -3591,6 +3623,8 @@ EXTERN_C XS(boot_quest)
newXS(strcpy(buf, "enablerecipe"), XS__enablerecipe, file); newXS(strcpy(buf, "enablerecipe"), XS__enablerecipe, file);
newXS(strcpy(buf, "disablerecipe"), XS__disablerecipe, file); newXS(strcpy(buf, "disablerecipe"), XS__disablerecipe, file);
newXS(strcpy(buf, "clear_npctype_cache"), XS__clear_npctype_cache, file); newXS(strcpy(buf, "clear_npctype_cache"), XS__clear_npctype_cache, file);
newXS(strcpy(buf, "qs_send_query"), XS__qs_send_query, file);
newXS(strcpy(buf, "qs_player_event"), XS__qs_player_event, file);
XSRETURN_YES; XSRETURN_YES;
} }

View File

@ -1476,7 +1476,7 @@ void EntityList::QueueClientsStatus(Mob *sender, const EQApplicationPacket *app,
void EntityList::DuelMessage(Mob *winner, Mob *loser, bool flee) void EntityList::DuelMessage(Mob *winner, Mob *loser, bool flee)
{ {
if (winner->GetLevelCon(winner->GetLevel(), loser->GetLevel()) > 2) { if (winner->GetLevelCon(winner->GetLevel(), loser->GetLevel()) > 2) {
std::vector<void*> args; std::vector<EQEmu::Any> args;
args.push_back(winner); args.push_back(winner);
args.push_back(loser); args.push_back(loser);
@ -1598,7 +1598,7 @@ Corpse *EntityList::GetCorpseByName(const char *name)
Spawn2 *EntityList::GetSpawnByID(uint32 id) Spawn2 *EntityList::GetSpawnByID(uint32 id)
{ {
if (!zone) if (!zone || !zone->IsLoaded())
return nullptr; return nullptr;
LinkedListIterator<Spawn2 *> iterator(zone->spawn2_list); LinkedListIterator<Spawn2 *> iterator(zone->spawn2_list);
@ -2847,7 +2847,7 @@ void EntityList::ClearFeignAggro(Mob *targ)
} }
if (targ->IsClient()) { if (targ->IsClient()) {
std::vector<void*> args; std::vector<EQEmu::Any> args;
args.push_back(it->second); args.push_back(it->second);
int i = parse->EventPlayer(EVENT_FEIGN_DEATH, targ->CastToClient(), "", 0, &args); int i = parse->EventPlayer(EVENT_FEIGN_DEATH, targ->CastToClient(), "", 0, &args);
if (i != 0) { if (i != 0) {
@ -3244,7 +3244,7 @@ void EntityList::ProcessMove(Client *c, float x, float y, float z)
if (evt.npc) { if (evt.npc) {
parse->EventNPC(evt.event_id, evt.npc, evt.client, "", 0); parse->EventNPC(evt.event_id, evt.npc, evt.client, "", 0);
} else { } else {
std::vector<void*> args; std::vector<EQEmu::Any> args;
args.push_back(&evt.area_id); args.push_back(&evt.area_id);
args.push_back(&evt.area_type); args.push_back(&evt.area_type);
parse->EventPlayer(evt.event_id, evt.client, "", 0, &args); parse->EventPlayer(evt.event_id, evt.client, "", 0, &args);
@ -3298,7 +3298,7 @@ void EntityList::ProcessMove(NPC *n, float x, float y, float z)
for (auto iter = events.begin(); iter != events.end(); ++iter) { for (auto iter = events.begin(); iter != events.end(); ++iter) {
quest_proximity_event& evt = (*iter); quest_proximity_event& evt = (*iter);
std::vector<void*> args; std::vector<EQEmu::Any> args;
args.push_back(&evt.area_id); args.push_back(&evt.area_id);
args.push_back(&evt.area_type); args.push_back(&evt.area_type);
parse->EventNPC(evt.event_id, evt.npc, evt.client, "", 0, &args); parse->EventNPC(evt.event_id, evt.npc, evt.client, "", 0, &args);
@ -4170,6 +4170,20 @@ void EntityList::SignalAllClients(uint32 data)
} }
} }
uint16 EntityList::GetClientCount(){
uint16 ClientCount = 0;
std::list<Client*> client_list;
entity_list.GetClientList(client_list);
std::list<Client*>::iterator iter = client_list.begin();
while (iter != client_list.end()) {
Client *entry = (*iter);
entry->GetCleanName();
ClientCount++;
iter++;
}
return ClientCount;
}
void EntityList::GetMobList(std::list<Mob *> &m_list) void EntityList::GetMobList(std::list<Mob *> &m_list)
{ {
m_list.clear(); m_list.clear();

View File

@ -398,6 +398,7 @@ public:
void UpdateFindableNPCState(NPC *n, bool Remove); void UpdateFindableNPCState(NPC *n, bool Remove);
void HideCorpses(Client *c, uint8 CurrentMode, uint8 NewMode); void HideCorpses(Client *c, uint8 CurrentMode, uint8 NewMode);
uint16 GetClientCount();
void GetMobList(std::list<Mob*> &m_list); void GetMobList(std::list<Mob*> &m_list);
void GetNPCList(std::list<NPC*> &n_list); void GetNPCList(std::list<NPC*> &n_list);
void GetMercList(std::list<Merc*> &n_list); void GetMercList(std::list<Merc*> &n_list);

View File

@ -22,6 +22,9 @@
#include "../common/string_util.h" #include "../common/string_util.h"
#include "../common/rulesys.h" #include "../common/rulesys.h"
#include "quest_parser_collection.h" #include "quest_parser_collection.h"
#include "queryserv.h"
extern QueryServ* QServ;
static uint32 MaxBankedGroupLeadershipPoints(int Level) static uint32 MaxBankedGroupLeadershipPoints(int Level)
@ -212,7 +215,6 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
return; // Must be invalid class/race return; // Must be invalid class/race
} }
if ((set_exp + set_aaxp) > (m_pp.exp+m_pp.expAA)) { if ((set_exp + set_aaxp) > (m_pp.exp+m_pp.expAA)) {
if (isrezzexp) if (isrezzexp)
this->Message_StringID(MT_Experience, REZ_REGAIN); this->Message_StringID(MT_Experience, REZ_REGAIN);
@ -288,6 +290,14 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
//Message(15, "You have gained %d skill points!!", m_pp.aapoints - last_unspentAA); //Message(15, "You have gained %d skill points!!", m_pp.aapoints - last_unspentAA);
char val1[20]={0}; char val1[20]={0};
Message_StringID(MT_Experience, GAIN_ABILITY_POINT,ConvertArray(m_pp.aapoints, val1),m_pp.aapoints == 1 ? "" : "(s)"); //You have gained an ability point! You now have %1 ability point%2. Message_StringID(MT_Experience, GAIN_ABILITY_POINT,ConvertArray(m_pp.aapoints, val1),m_pp.aapoints == 1 ? "" : "(s)"); //You have gained an ability point! You now have %1 ability point%2.
/* QS: PlayerLogAARate */
if (RuleB(QueryServ, PlayerLogAARate)){
int add_points = (m_pp.aapoints - last_unspentAA);
std::string query = StringFormat("INSERT INTO `qs_player_aa_rate_hourly` (char_id, aa_count, hour_time) VALUES (%i, %i, UNIX_TIMESTAMP() - MOD(UNIX_TIMESTAMP(), 3600)) ON DUPLICATE KEY UPDATE `aa_count` = `aa_count` + %i", this->CharacterID(), add_points, add_points);
QServ->SendQuery(query.c_str());
}
//Message(15, "You now have %d skill points available to spend.", m_pp.aapoints); //Message(15, "You now have %d skill points available to spend.", m_pp.aapoints);
} }
@ -299,12 +309,10 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
if(check_level > maxlevel) { if(check_level > maxlevel) {
check_level = maxlevel; check_level = maxlevel;
if(RuleB(Character, KeepLevelOverMax)) if(RuleB(Character, KeepLevelOverMax)) {
{
set_exp = GetEXPForLevel(GetLevel()+1); set_exp = GetEXPForLevel(GetLevel()+1);
} }
else else {
{
set_exp = GetEXPForLevel(maxlevel); set_exp = GetEXPForLevel(maxlevel);
} }
} }
@ -314,8 +322,7 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
if(MaxLevel){ if(MaxLevel){
if(GetLevel() >= MaxLevel){ if(GetLevel() >= MaxLevel){
uint32 expneeded = GetEXPForLevel(MaxLevel); uint32 expneeded = GetEXPForLevel(MaxLevel);
if(set_exp > expneeded) if(set_exp > expneeded) {
{
set_exp = expneeded; set_exp = expneeded;
} }
} }
@ -327,11 +334,11 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
if (GetLevel() == check_level-1){ if (GetLevel() == check_level-1){
Message_StringID(MT_Experience, GAIN_LEVEL,ConvertArray(check_level,val1)); Message_StringID(MT_Experience, GAIN_LEVEL,ConvertArray(check_level,val1));
SendLevelAppearance(); SendLevelAppearance();
//Message(15, "You have gained a level! Welcome to level %i!", check_level); /* Message(15, "You have gained a level! Welcome to level %i!", check_level); */
} }
if (GetLevel() == check_level){ if (GetLevel() == check_level){
Message_StringID(MT_Experience, LOSE_LEVEL,ConvertArray(check_level,val1)); Message_StringID(MT_Experience, LOSE_LEVEL,ConvertArray(check_level,val1));
//Message(15, "You lost a level! You are now level %i!", check_level); /* Message(15, "You lost a level! You are now level %i!", check_level); */
} }
else else
Message(15, "Welcome to level %i!", check_level); Message(15, "Welcome to level %i!", check_level);
@ -352,8 +359,7 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
//If were at max level then stop gaining experience if we make it to the cap //If were at max level then stop gaining experience if we make it to the cap
if(GetLevel() == maxlevel - 1){ if(GetLevel() == maxlevel - 1){
uint32 expneeded = GetEXPForLevel(maxlevel); uint32 expneeded = GetEXPForLevel(maxlevel);
if(set_exp > expneeded) if(set_exp > expneeded) {
{
set_exp = expneeded; set_exp = expneeded;
} }
} }
@ -405,15 +411,13 @@ void Client::SetLevel(uint8 set_level, bool command)
level = set_level; level = set_level;
if(IsRaidGrouped()) if(IsRaidGrouped()) {
{
Raid *r = this->GetRaid(); Raid *r = this->GetRaid();
if(r){ if(r){
r->UpdateLevel(GetName(), set_level); r->UpdateLevel(GetName(), set_level);
} }
} }
if(set_level > m_pp.level2) if(set_level > m_pp.level2) {
{
if(m_pp.level2 == 0) if(m_pp.level2 == 0)
m_pp.points += 5; m_pp.points += 5;
else else
@ -423,6 +427,18 @@ void Client::SetLevel(uint8 set_level, bool command)
} }
if(set_level > m_pp.level) { if(set_level > m_pp.level) {
parse->EventPlayer(EVENT_LEVEL_UP, this, "", 0); parse->EventPlayer(EVENT_LEVEL_UP, this, "", 0);
/* QS: PlayerLogLevels */
if (RuleB(QueryServ, PlayerLogLevels)){
std::string event_desc = StringFormat("Leveled UP :: to Level:%i from Level:%i in zoneid:%i instid:%i", set_level, m_pp.level, this->GetZoneID(), this->GetInstanceID());
QServ->PlayerLogEvent(Player_Log_Levels, this->CharacterID(), event_desc);
}
}
else if (set_level < m_pp.level){
/* QS: PlayerLogLevels */
if (RuleB(QueryServ, PlayerLogLevels)){
std::string event_desc = StringFormat("Leveled DOWN :: to Level:%i from Level:%i in zoneid:%i instid:%i", set_level, m_pp.level, this->GetZoneID(), this->GetInstanceID());
QServ->PlayerLogEvent(Player_Log_Levels, this->CharacterID(), event_desc);
}
} }
m_pp.level = set_level; m_pp.level = set_level;
@ -432,8 +448,7 @@ void Client::SetLevel(uint8 set_level, bool command)
lu->exp = 0; lu->exp = 0;
} }
else { else {
float tmpxp = (float) ( (float) m_pp.exp - GetEXPForLevel( GetLevel() )) / float tmpxp = (float) ( (float) m_pp.exp - GetEXPForLevel( GetLevel() )) / ( (float) GetEXPForLevel(GetLevel()+1) - GetEXPForLevel(GetLevel()));
( (float) GetEXPForLevel(GetLevel()+1) - GetEXPForLevel(GetLevel()));
lu->exp = (uint32)(330.0f * tmpxp); lu->exp = (uint32)(330.0f * tmpxp);
} }
QueuePacket(outapp); QueuePacket(outapp);
@ -443,14 +458,13 @@ void Client::SetLevel(uint8 set_level, bool command)
LogFile->write(EQEMuLog::Normal,"Setting Level for %s to %i", GetName(), set_level); LogFile->write(EQEMuLog::Normal,"Setting Level for %s to %i", GetName(), set_level);
CalcBonuses(); CalcBonuses();
if(!RuleB(Character, HealOnLevel))
{ if(!RuleB(Character, HealOnLevel)) {
int mhp = CalcMaxHP(); int mhp = CalcMaxHP();
if(GetHP() > mhp) if(GetHP() > mhp)
SetHP(mhp); SetHP(mhp);
} }
else else {
{
SetHP(CalcMaxHP()); // Why not, lets give them a free heal SetHP(CalcMaxHP()); // Why not, lets give them a free heal
} }
@ -458,8 +472,10 @@ void Client::SetLevel(uint8 set_level, bool command)
SendHPUpdate(); SendHPUpdate();
SetMana(CalcMaxMana()); SetMana(CalcMaxMana());
UpdateWho(); UpdateWho();
if(GetMerc()) if(GetMerc())
UpdateMercLevel(); UpdateMercLevel();
Save(); Save();
} }
@ -508,23 +524,13 @@ uint32 Client::GetEXPForLevel(uint16 check_level)
uint32 finalxp = uint32(base * mod); uint32 finalxp = uint32(base * mod);
finalxp = mod_client_xp_for_level(finalxp, check_level); finalxp = mod_client_xp_for_level(finalxp, check_level);
return(finalxp); return finalxp;
} }
void Client::AddLevelBasedExp(uint8 exp_percentage, uint8 max_level) { void Client::AddLevelBasedExp(uint8 exp_percentage, uint8 max_level) {
if (exp_percentage > 100) { exp_percentage = 100; }
if (exp_percentage > 100) if (!max_level || GetLevel() < max_level) { max_level = GetLevel(); }
{
exp_percentage = 100;
}
if (!max_level || GetLevel() < max_level)
{
max_level = GetLevel();
}
uint32 newexp = GetEXP() + ((GetEXPForLevel(max_level + 1) - GetEXPForLevel(max_level)) * exp_percentage / 100); uint32 newexp = GetEXP() + ((GetEXPForLevel(max_level + 1) - GetEXPForLevel(max_level)) * exp_percentage / 100);
SetEXP(newexp, GetAAXP()); SetEXP(newexp, GetAAXP());
} }
@ -666,22 +672,19 @@ void Client::SendLeadershipEXPUpdate() {
} }
uint32 Client::GetCharMaxLevelFromQGlobal() { uint32 Client::GetCharMaxLevelFromQGlobal() {
QGlobalCache *char_c = nullptr; QGlobalCache *char_c = nullptr;
char_c = this->GetQGlobals(); char_c = this->GetQGlobals();
std::list<QGlobal> globalMap; std::list<QGlobal> globalMap;
uint32 ntype = 0; uint32 ntype = 0;
if(char_c) if(char_c) {
{
QGlobalCache::Combine(globalMap, char_c->GetBucket(), ntype, this->CharacterID(), zone->GetZoneID()); QGlobalCache::Combine(globalMap, char_c->GetBucket(), ntype, this->CharacterID(), zone->GetZoneID());
} }
std::list<QGlobal>::iterator iter = globalMap.begin(); std::list<QGlobal>::iterator iter = globalMap.begin();
uint32 gcount = 0; uint32 gcount = 0;
while(iter != globalMap.end()) while(iter != globalMap.end()) {
{
if((*iter).name.compare("CharMaxLevel") == 0){ if((*iter).name.compare("CharMaxLevel") == 0){
return atoi((*iter).value.c_str()); return atoi((*iter).value.c_str());
} }
@ -689,5 +692,5 @@ uint32 Client::GetCharMaxLevelFromQGlobal() {
++gcount; ++gcount;
} }
return false; // Default is false return false;
} }

View File

@ -357,7 +357,7 @@ void Client::GoFish()
} }
} }
std::vector<void*> args; std::vector<EQEmu::Any> args;
args.push_back(inst); args.push_back(inst);
parse->EventPlayer(EVENT_FISH_SUCCESS, this, "", inst != nullptr ? inst->GetItem()->ID : 0, &args); parse->EventPlayer(EVENT_FISH_SUCCESS, this, "", inst != nullptr ? inst->GetItem()->ID : 0, &args);
} }
@ -471,7 +471,7 @@ void Client::ForageItem(bool guarantee) {
} }
} }
std::vector<void*> args; std::vector<EQEmu::Any> args;
args.push_back(inst); args.push_back(inst);
parse->EventPlayer(EVENT_FORAGE_SUCCESS, this, "", inst ? inst->GetItem()->ID : 0, &args); parse->EventPlayer(EVENT_FORAGE_SUCCESS, this, "", inst ? inst->GetItem()->ID : 0, &args);

View File

@ -196,7 +196,6 @@ void Group::SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinu
Client *c = members[i]->CastToClient(); Client *c = members[i]->CastToClient();
//I could not get MoneyOnCorpse to work, so we use this //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()); c->Message(2, msg.c_str());
} }
} }

View File

@ -644,104 +644,66 @@ GuildBankManager::~GuildBankManager()
} }
} }
bool GuildBankManager::Load(uint32 GuildID) bool GuildBankManager::Load(uint32 guildID)
{ {
const char *LoadQuery = "SELECT `area`, `slot`, `itemid`, `qty`, `donator`, `permissions`, `whofor` from `guild_bank` "
"WHERE `guildid` = %i";
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if(database.RunQuery(query, MakeAnyLenString(&query, LoadQuery, GuildID), errbuf, &result))
{
GuildBank *Bank = new GuildBank;
Bank->GuildID = GuildID;
for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i)
Bank->Items.MainArea[i].ItemID = 0;
for(int i = 0; i < GUILD_BANK_DEPOSIT_AREA_SIZE; ++i)
Bank->Items.DepositArea[i].ItemID = 0;
char Donator[64], WhoFor[64];
while((row = mysql_fetch_row(result)))
{
int Area = atoi(row[0]);
int Slot = atoi(row[1]);
int ItemID = atoi(row[2]);
int Qty = atoi(row[3]);
if(row[4])
strn0cpy(Donator, row[4], sizeof(Donator));
else
Donator[0] = '\0';
int Permissions = atoi(row[5]);
if(row[6])
strn0cpy(WhoFor, row[6], sizeof(WhoFor));
else
WhoFor[0] = '\0';
if(Area == GuildBankMainArea)
{
if((Slot >= 0) && (Slot < GUILD_BANK_MAIN_AREA_SIZE))
{
Bank->Items.MainArea[Slot].ItemID = ItemID;
Bank->Items.MainArea[Slot].Quantity = Qty;
strn0cpy(Bank->Items.MainArea[Slot].Donator, Donator, sizeof(Donator));
Bank->Items.MainArea[Slot].Permissions = Permissions;
strn0cpy(Bank->Items.MainArea[Slot].WhoFor, WhoFor, sizeof(WhoFor));
}
}
else
{
if((Slot >= 0 ) && (Slot < GUILD_BANK_DEPOSIT_AREA_SIZE))
{
Bank->Items.DepositArea[Slot].ItemID = ItemID;
Bank->Items.DepositArea[Slot].Quantity = Qty;
strn0cpy(Bank->Items.DepositArea[Slot].Donator, Donator, sizeof(Donator));
Bank->Items.DepositArea[Slot].Permissions = Permissions;
strn0cpy(Bank->Items.DepositArea[Slot].WhoFor, WhoFor, sizeof(WhoFor));
}
}
}
mysql_free_result(result);
safe_delete_array(query);
Banks.push_back(Bank);
}
else
{
_log(GUILDS__BANK_ERROR, "Error Loading guild bank: %s, %s", query, errbuf);
safe_delete_array(query);
std::string query = StringFormat("SELECT `area`, `slot`, `itemid`, `qty`, `donator`, `permissions`, `whofor` "
"FROM `guild_bank` WHERE `guildid` = %i", guildID);
auto results = database.QueryDatabase(query);
if(!results.Success()) {
_log(GUILDS__BANK_ERROR, "Error Loading guild bank: %s, %s", query.c_str(), results.ErrorMessage().c_str());
return false; return false;
} }
return true; GuildBank *bank = new GuildBank;
bank->GuildID = guildID;
for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i)
bank->Items.MainArea[i].ItemID = 0;
for(int i = 0; i < GUILD_BANK_DEPOSIT_AREA_SIZE; ++i)
bank->Items.DepositArea[i].ItemID = 0;
char donator[64], whoFor[64];
for (auto row = results.begin(); row != results.end(); ++row)
{
int area = atoi(row[0]);
int slot = atoi(row[1]);
int itemID = atoi(row[2]);
int qty = atoi(row[3]);
if(row[4])
strn0cpy(donator, row[4], sizeof(donator));
else
donator[0] = '\0';
int permissions = atoi(row[5]);
if(row[6])
strn0cpy(whoFor, row[6], sizeof(whoFor));
else
whoFor[0] = '\0';
if(slot < 0 ||
((area != GuildBankMainArea || slot >= GUILD_BANK_MAIN_AREA_SIZE) ||
(area == GuildBankMainArea || slot >= GUILD_BANK_DEPOSIT_AREA_SIZE)))
continue;
bank->Items.MainArea[slot].ItemID = itemID;
bank->Items.MainArea[slot].Quantity = qty;
strn0cpy(bank->Items.MainArea[slot].Donator, donator, sizeof(donator));
bank->Items.MainArea[slot].Permissions = permissions;
strn0cpy(bank->Items.MainArea[slot].WhoFor, whoFor, sizeof(whoFor));
}
Banks.push_back(bank);
return true;
} }
bool GuildBankManager::IsLoaded(uint32 GuildID) bool GuildBankManager::IsLoaded(uint32 GuildID)
@ -973,156 +935,127 @@ bool GuildBankManager::AddItem(uint32 GuildID, uint8 Area, uint32 ItemID, int32
return true; return true;
} }
int GuildBankManager::Promote(uint32 GuildID, int SlotID) int GuildBankManager::Promote(uint32 guildID, int slotID)
{ {
if((SlotID < 0) || (SlotID > (GUILD_BANK_DEPOSIT_AREA_SIZE - 1))) if((slotID < 0) || (slotID > (GUILD_BANK_DEPOSIT_AREA_SIZE - 1)))
return -1; return -1;
std::list<GuildBank*>::iterator Iterator = GetGuildBank(GuildID); auto iter = GetGuildBank(guildID);
if(Iterator == Banks.end()) if(iter == Banks.end())
{
return -1; return -1;
}
if((*Iterator)->Items.DepositArea[SlotID].ItemID == 0) if((*iter)->Items.DepositArea[slotID].ItemID == 0)
{
return -1; return -1;
}
int MainSlot = -1; int mainSlot = -1;
for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i) for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i)
if((*Iterator)->Items.MainArea[i].ItemID == 0) if((*iter)->Items.MainArea[i].ItemID == 0) {
{ mainSlot = i;
MainSlot = i;
break; break;
} }
if(MainSlot == -1) if(mainSlot == -1)
return -1; return -1;
(*iter)->Items.MainArea[mainSlot].ItemID = (*iter)->Items.DepositArea[slotID].ItemID;
(*iter)->Items.MainArea[mainSlot].Quantity = (*iter)->Items.DepositArea[slotID].Quantity;
(*iter)->Items.MainArea[mainSlot].Permissions = (*iter)->Items.DepositArea[slotID].Permissions;
(*Iterator)->Items.MainArea[MainSlot].ItemID = (*Iterator)->Items.DepositArea[SlotID].ItemID; strn0cpy((*iter)->Items.MainArea[mainSlot].Donator, (*iter)->Items.DepositArea[slotID].Donator, sizeof((*iter)->Items.MainArea[mainSlot].Donator));
strn0cpy((*iter)->Items.MainArea[mainSlot].WhoFor, (*iter)->Items.DepositArea[slotID].WhoFor, sizeof((*iter)->Items.MainArea[mainSlot].WhoFor));
(*Iterator)->Items.MainArea[MainSlot].Quantity = (*Iterator)->Items.DepositArea[SlotID].Quantity;
strn0cpy((*Iterator)->Items.MainArea[MainSlot].Donator, (*Iterator)->Items.DepositArea[SlotID].Donator, sizeof((*Iterator)->Items.MainArea[MainSlot].Donator));
(*Iterator)->Items.MainArea[MainSlot].Permissions = (*Iterator)->Items.DepositArea[SlotID].Permissions;
strn0cpy((*Iterator)->Items.MainArea[MainSlot].WhoFor, (*Iterator)->Items.DepositArea[SlotID].WhoFor, sizeof((*Iterator)->Items.MainArea[MainSlot].WhoFor));
const char *Query="UPDATE `guild_bank` SET `area` = 1, `slot` = %i WHERE `guildid` = %i AND `area` = 0 AND `slot` = %i LIMIT 1";
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
if(!database.RunQuery(query, MakeAnyLenString(&query, Query, MainSlot, GuildID, SlotID), errbuf))
{
_log(GUILDS__BANK_ERROR, "error promoting item: %s : %s", query, errbuf);
safe_delete_array(query);
std::string query = StringFormat("UPDATE `guild_bank` SET `area` = 1, `slot` = %i "
"WHERE `guildid` = %i AND `area` = 0 AND `slot` = %i "
"LIMIT 1", mainSlot, guildID, slotID);
auto results = database.QueryDatabase(query);
if (!results.Success()) {
_log(GUILDS__BANK_ERROR, "error promoting item: %s : %s", query.c_str(), results.ErrorMessage().c_str());
return -1; return -1;
} }
safe_delete_array(query); (*iter)->Items.DepositArea[slotID].ItemID = 0;
(*Iterator)->Items.DepositArea[SlotID].ItemID = 0; const Item_Struct *Item = database.GetItem((*iter)->Items.MainArea[mainSlot].ItemID);
const Item_Struct *Item = database.GetItem((*Iterator)->Items.MainArea[MainSlot].ItemID);
GuildBankItemUpdate_Struct gbius; GuildBankItemUpdate_Struct gbius;
if(!Item->Stackable) if(!Item->Stackable)
gbius.Init(GuildBankItemUpdate, 1, MainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon, 1, 0, 0, 0); gbius.Init(GuildBankItemUpdate, 1, mainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon, 1, 0, 0, 0);
else else
{ {
if((*Iterator)->Items.MainArea[MainSlot].Quantity == Item->StackSize) if((*iter)->Items.MainArea[mainSlot].Quantity == Item->StackSize)
gbius.Init(GuildBankItemUpdate, 1, MainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon, gbius.Init(GuildBankItemUpdate, 1, mainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon,
(*Iterator)->Items.MainArea[MainSlot].Quantity, 0, 0, 0); (*iter)->Items.MainArea[mainSlot].Quantity, 0, 0, 0);
else else
gbius.Init(GuildBankItemUpdate, 1, MainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon, gbius.Init(GuildBankItemUpdate, 1, mainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon,
(*Iterator)->Items.MainArea[MainSlot].Quantity, 0, 1, 0); (*iter)->Items.MainArea[mainSlot].Quantity, 0, 1, 0);
} }
strn0cpy(gbius.ItemName, Item->Name, sizeof(gbius.ItemName)); strn0cpy(gbius.ItemName, Item->Name, sizeof(gbius.ItemName));
entity_list.QueueClientsGuildBankItemUpdate(&gbius, GuildID); entity_list.QueueClientsGuildBankItemUpdate(&gbius, guildID);
gbius.Init(GuildBankItemUpdate, 1, SlotID, GuildBankDepositArea, 0, 0, 0, 0, 0, 0, 0); gbius.Init(GuildBankItemUpdate, 1, slotID, GuildBankDepositArea, 0, 0, 0, 0, 0, 0, 0);
entity_list.QueueClientsGuildBankItemUpdate(&gbius, GuildID); entity_list.QueueClientsGuildBankItemUpdate(&gbius, guildID);
return MainSlot; return mainSlot;
} }
void GuildBankManager::SetPermissions(uint32 GuildID, uint16 SlotID, uint32 Permissions, const char *MemberName) void GuildBankManager::SetPermissions(uint32 guildID, uint16 slotID, uint32 permissions, const char *memberName)
{ {
if((SlotID > (GUILD_BANK_MAIN_AREA_SIZE - 1))) if((slotID > (GUILD_BANK_MAIN_AREA_SIZE - 1)))
return; return;
std::list<GuildBank*>::iterator Iterator = GetGuildBank(GuildID); auto iter = GetGuildBank(guildID);
if(Iterator == Banks.end()) if(iter == Banks.end())
return;
if((*iter)->Items.MainArea[slotID].ItemID == 0)
return;
std::string query = StringFormat("UPDATE `guild_bank` SET `permissions` = %i, `whofor` = '%s' "
"WHERE `guildid` = %i AND `area` = 1 AND `slot` = %i LIMIT 1",
permissions, memberName, guildID, slotID);
auto results = database.QueryDatabase(query);
if(!results.Success())
{ {
_log(GUILDS__BANK_ERROR, "error changing permissions: %s : %s", query.c_str(), results.ErrorMessage().c_str());
return; return;
} }
if((*Iterator)->Items.MainArea[SlotID].ItemID == 0) (*iter)->Items.MainArea[slotID].Permissions = permissions;
{
return;
}
const char *Query="UPDATE `guild_bank` SET `permissions` = %i, `whofor` = '%s' WHERE `guildid` = %i AND `area` = 1 AND `slot` = %i LIMIT 1"; if(permissions == GuildBankSingleMember)
strn0cpy((*iter)->Items.MainArea[slotID].WhoFor, memberName, sizeof((*iter)->Items.MainArea[slotID].WhoFor));
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
if(!database.RunQuery(query, MakeAnyLenString(&query, Query, Permissions, MemberName, GuildID, SlotID), errbuf))
{
_log(GUILDS__BANK_ERROR, "error changing permissions: %s : %s", query, errbuf);
safe_delete_array(query);
return;
}
safe_delete_array(query);
(*Iterator)->Items.MainArea[SlotID].Permissions = Permissions;
if(Permissions == GuildBankSingleMember)
strn0cpy((*Iterator)->Items.MainArea[SlotID].WhoFor, MemberName, sizeof((*Iterator)->Items.MainArea[SlotID].WhoFor));
else else
(*Iterator)->Items.MainArea[SlotID].WhoFor[0] = '\0'; (*iter)->Items.MainArea[slotID].WhoFor[0] = '\0';
const Item_Struct *Item = database.GetItem((*iter)->Items.MainArea[slotID].ItemID);
const Item_Struct *Item = database.GetItem((*Iterator)->Items.MainArea[SlotID].ItemID);
GuildBankItemUpdate_Struct gbius; GuildBankItemUpdate_Struct gbius;
if(!Item->Stackable) if(!Item->Stackable)
gbius.Init(GuildBankItemUpdate, 1, SlotID, GuildBankMainArea, 1, Item->ID, Item->Icon, 1, (*Iterator)->Items.MainArea[SlotID].Permissions, 0, 0); gbius.Init(GuildBankItemUpdate, 1, slotID, GuildBankMainArea, 1, Item->ID, Item->Icon, 1, (*iter)->Items.MainArea[slotID].Permissions, 0, 0);
else else
{ {
if((*Iterator)->Items.MainArea[SlotID].Quantity == Item->StackSize) if((*iter)->Items.MainArea[slotID].Quantity == Item->StackSize)
gbius.Init(GuildBankItemUpdate, 1, SlotID, GuildBankMainArea, 1, Item->ID, Item->Icon, gbius.Init(GuildBankItemUpdate, 1, slotID, GuildBankMainArea, 1, Item->ID, Item->Icon,
(*Iterator)->Items.MainArea[SlotID].Quantity, (*Iterator)->Items.MainArea[SlotID].Permissions, 0, 0); (*iter)->Items.MainArea[slotID].Quantity, (*iter)->Items.MainArea[slotID].Permissions, 0, 0);
else else
gbius.Init(GuildBankItemUpdate, 1, SlotID, GuildBankMainArea, 1, Item->ID, Item->Icon, gbius.Init(GuildBankItemUpdate, 1, slotID, GuildBankMainArea, 1, Item->ID, Item->Icon,
(*Iterator)->Items.MainArea[SlotID].Quantity, (*Iterator)->Items.MainArea[SlotID].Permissions, 1, 0); (*iter)->Items.MainArea[slotID].Quantity, (*iter)->Items.MainArea[slotID].Permissions, 1, 0);
} }
strn0cpy(gbius.ItemName, Item->Name, sizeof(gbius.ItemName)); strn0cpy(gbius.ItemName, Item->Name, sizeof(gbius.ItemName));
strn0cpy(gbius.WhoFor, (*Iterator)->Items.MainArea[SlotID].WhoFor, sizeof(gbius.WhoFor)); strn0cpy(gbius.WhoFor, (*iter)->Items.MainArea[slotID].WhoFor, sizeof(gbius.WhoFor));
entity_list.QueueClientsGuildBankItemUpdate(&gbius, GuildID); entity_list.QueueClientsGuildBankItemUpdate(&gbius, guildID);
} }
ItemInst* GuildBankManager::GetItem(uint32 GuildID, uint16 Area, uint16 SlotID, uint32 Quantity) ItemInst* GuildBankManager::GetItem(uint32 GuildID, uint16 Area, uint16 SlotID, uint32 Quantity)
@ -1208,90 +1141,73 @@ std::list<GuildBank*>::iterator GuildBankManager::GetGuildBank(uint32 GuildID)
return Iterator; return Iterator;
} }
bool GuildBankManager::DeleteItem(uint32 GuildID, uint16 Area, uint16 SlotID, uint32 Quantity) bool GuildBankManager::DeleteItem(uint32 guildID, uint16 area, uint16 slotID, uint32 quantity)
{ {
std::list<GuildBank*>::iterator Iterator = GetGuildBank(GuildID); auto iter = GetGuildBank(guildID);
if(Iterator == Banks.end()) if(iter == Banks.end())
return false; return false;
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
GuildBankItem* BankArea = nullptr; GuildBankItem* BankArea = nullptr;
if(Area == GuildBankMainArea) if(area == GuildBankMainArea)
{ {
if(SlotID > (GUILD_BANK_MAIN_AREA_SIZE - 1)) if(slotID > (GUILD_BANK_MAIN_AREA_SIZE - 1))
return false; return false;
BankArea = &(*Iterator)->Items.MainArea[0]; BankArea = &(*iter)->Items.MainArea[0];
} } else {
else if(slotID > (GUILD_BANK_DEPOSIT_AREA_SIZE - 1))
{
if(SlotID > (GUILD_BANK_DEPOSIT_AREA_SIZE - 1))
return false; return false;
BankArea = &(*Iterator)->Items.DepositArea[0]; BankArea = &(*iter)->Items.DepositArea[0];
} }
bool deleted = true;
bool Deleted = true; const Item_Struct *Item = database.GetItem(BankArea[slotID].ItemID);
const Item_Struct *Item = database.GetItem(BankArea[SlotID].ItemID);
if(!Item->Stackable || (Quantity >= BankArea[SlotID].Quantity))
{
const char *Query = "DELETE from `guild_bank` where `guildid` = %i AND `area` = %i AND `slot` = %i LIMIT 1";
if(!database.RunQuery(query, MakeAnyLenString(&query, Query, GuildID, Area, SlotID), errbuf))
{
_log(GUILDS__BANK_ERROR, "Delete item failed. %s : %s", query, errbuf);
safe_delete_array(query);
if(!Item->Stackable || (quantity >= BankArea[slotID].Quantity)) {
std::string query = StringFormat("DELETE FROM `guild_bank` WHERE `guildid` = %i "
"AND `area` = %i AND `slot` = %i LIMIT 1",
guildID, area, slotID);
auto results = database.QueryDatabase(query);
if(!results.Success()) {
_log(GUILDS__BANK_ERROR, "Delete item failed. %s : %s", query.c_str(), results.ErrorMessage().c_str());
return false; return false;
} }
safe_delete_array(query); BankArea[slotID].ItemID = 0;
BankArea[SlotID].ItemID = 0;
}
else
{
const char *Query = "UPDATE `guild_bank` SET `qty` = %i where `guildid` = %i AND `area` = %i AND `slot` = %i LIMIT 1";
if(!database.RunQuery(query, MakeAnyLenString(&query, Query, BankArea[SlotID].Quantity - Quantity,
GuildID, Area, SlotID), errbuf))
{
_log(GUILDS__BANK_ERROR, "Update item failed. %s : %s", query, errbuf);
safe_delete_array(query);
} else {
std::string query = StringFormat("UPDATE `guild_bank` SET `qty` = %i WHERE `guildid` = %i "
"AND `area` = %i AND `slot` = %i LIMIT 1",
BankArea[slotID].Quantity - quantity, guildID, area, slotID);
auto results = database.QueryDatabase(query);
if(!results.Success()) {
_log(GUILDS__BANK_ERROR, "Update item failed. %s : %s", query.c_str(), results.ErrorMessage().c_str());
return false; return false;
} }
safe_delete_array(query); BankArea[slotID].Quantity -= quantity;
BankArea[SlotID].Quantity -= Quantity; deleted = false;
Deleted = false;
} }
GuildBankItemUpdate_Struct gbius; GuildBankItemUpdate_Struct gbius;
if(!Deleted) if(!deleted)
{ {
gbius.Init(GuildBankItemUpdate, 1, SlotID, Area, 1, Item->ID, Item->Icon, BankArea[SlotID].Quantity, BankArea[SlotID].Permissions, 1, 0); gbius.Init(GuildBankItemUpdate, 1, slotID, area, 1, Item->ID, Item->Icon, BankArea[slotID].Quantity, BankArea[slotID].Permissions, 1, 0);
strn0cpy(gbius.ItemName, Item->Name, sizeof(gbius.ItemName)); strn0cpy(gbius.ItemName, Item->Name, sizeof(gbius.ItemName));
strn0cpy(gbius.WhoFor, BankArea[SlotID].WhoFor, sizeof(gbius.WhoFor)); strn0cpy(gbius.WhoFor, BankArea[slotID].WhoFor, sizeof(gbius.WhoFor));
} }
else else
gbius.Init(GuildBankItemUpdate, 1, SlotID, Area, 0, 0, 0, 0, 0, 0, 0); gbius.Init(GuildBankItemUpdate, 1, slotID, area, 0, 0, 0, 0, 0, 0, 0);
entity_list.QueueClientsGuildBankItemUpdate(&gbius, GuildID); entity_list.QueueClientsGuildBankItemUpdate(&gbius, guildID);
return true; return true;
@ -1422,26 +1338,20 @@ bool GuildBankManager::SplitStack(uint32 GuildID, uint16 SlotID, uint32 Quantity
return true; return true;
} }
void GuildBankManager::UpdateItemQuantity(uint32 GuildID, uint16 Area, uint16 SlotID, uint32 Quantity) void GuildBankManager::UpdateItemQuantity(uint32 guildID, uint16 area, uint16 slotID, uint32 quantity)
{ {
// Helper method for MergeStacks. Assuming all passed parameters are valid. // Helper method for MergeStacks. Assuming all passed parameters are valid.
// //
char errbuf[MYSQL_ERRMSG_SIZE]; std::string query = StringFormat("UPDATE `guild_bank` SET `qty` = %i "
"WHERE `guildid` = %i AND `area` = %i "
char* query = 0; "AND `slot` = %i LIMIT 1",
quantity, guildID, area, slotID);
const char *Query = "UPDATE `guild_bank` SET `qty` = %i where `guildid` = %i AND `area` = %i AND `slot` = %i LIMIT 1"; auto results = database.QueryDatabase(query);
if(!results.Success()) {
if(!database.RunQuery(query, MakeAnyLenString(&query, Query, Quantity, GuildID, Area, SlotID), errbuf)) _log(GUILDS__BANK_ERROR, "Update item quantity failed. %s : %s", query.c_str(), results.ErrorMessage().c_str());
{
_log(GUILDS__BANK_ERROR, "Update item quantity failed. %s : %s", query, errbuf);
safe_delete_array(query);
return; return;
} }
safe_delete_array(query);
} }
bool GuildBankManager::AllowedToWithdraw(uint32 GuildID, uint16 Area, uint16 SlotID, const char *Name) bool GuildBankManager::AllowedToWithdraw(uint32 GuildID, uint16 Area, uint16 SlotID, const char *Name)

View File

@ -822,25 +822,24 @@ bool Client::PushItemOnCursor(const ItemInst& inst, bool client_update)
return database.SaveCursor(CharacterID(), s, e); return database.SaveCursor(CharacterID(), s, e);
} }
bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client_update) bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client_update) {
{
mlog(INVENTORY__SLOTS, "Putting item %s (%d) into slot %d", inst.GetItem()->Name, inst.GetItem()->ID, slot_id); mlog(INVENTORY__SLOTS, "Putting item %s (%d) into slot %d", inst.GetItem()->Name, inst.GetItem()->ID, slot_id);
if (slot_id == MainCursor) if (slot_id == MainCursor)
{
return PushItemOnCursor(inst, client_update); return PushItemOnCursor(inst, client_update);
}
else else
m_inv.PutItem(slot_id, inst); m_inv.PutItem(slot_id, inst);
if (client_update) { if (client_update)
SendItemPacket(slot_id, &inst, (slot_id == MainCursor) ? ItemPacketSummonItem : ItemPacketTrade); SendItemPacket(slot_id, &inst, ((slot_id == MainCursor) ? ItemPacketSummonItem : ItemPacketTrade));
}
if (slot_id == MainCursor) { if (slot_id == MainCursor) {
std::list<ItemInst*>::const_iterator s = m_inv.cursor_begin(), e = m_inv.cursor_end(); std::list<ItemInst*>::const_iterator s = m_inv.cursor_begin(), e = m_inv.cursor_end();
return database.SaveCursor(this->CharacterID(), s, e); return database.SaveCursor(this->CharacterID(), s, e);
} else }
else {
return database.SaveInventory(this->CharacterID(), &inst, slot_id); return database.SaveInventory(this->CharacterID(), &inst, slot_id);
}
CalcBonuses(); CalcBonuses();
} }
@ -1539,7 +1538,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
// Also sends trade information to other client of trade session // Also sends trade information to other client of trade session
if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit
trade->AddEntity(src_slot_id, dst_slot_id, move_in->number_in_stack); trade->AddEntity(dst_slot_id, move_in->number_in_stack);
return true; return true;
} else { } else {

View File

@ -1134,7 +1134,7 @@ void Lua_Client::Signal(uint32 id) {
void Lua_Client::AddAlternateCurrencyValue(uint32 currency, int amount) { void Lua_Client::AddAlternateCurrencyValue(uint32 currency, int amount) {
Lua_Safe_Call_Void(); Lua_Safe_Call_Void();
self->AddAlternateCurrencyValue(currency, amount); self->AddAlternateCurrencyValue(currency, amount, 1);
} }
void Lua_Client::SendWebLink(const char *site) { void Lua_Client::SendWebLink(const char *site) {

View File

@ -220,7 +220,7 @@ LuaParser::~LuaParser() {
} }
int LuaParser::EventNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, int LuaParser::EventNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
evt = ConvertLuaEvent(evt); evt = ConvertLuaEvent(evt);
if(evt >= _LargestEventID) { if(evt >= _LargestEventID) {
return 0; return 0;
@ -239,7 +239,7 @@ int LuaParser::EventNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data,
} }
int LuaParser::EventGlobalNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, int LuaParser::EventGlobalNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
evt = ConvertLuaEvent(evt); evt = ConvertLuaEvent(evt);
if(evt >= _LargestEventID) { if(evt >= _LargestEventID) {
return 0; return 0;
@ -257,7 +257,7 @@ int LuaParser::EventGlobalNPC(QuestEventID evt, NPC* npc, Mob *init, std::string
} }
int LuaParser::_EventNPC(std::string package_name, QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, int LuaParser::_EventNPC(std::string package_name, QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers, luabind::adl::object *l_func) { std::vector<EQEmu::Any> *extra_pointers, luabind::adl::object *l_func) {
const char *sub_name = LuaEvents[evt]; const char *sub_name = LuaEvents[evt];
int start = lua_gettop(L); int start = lua_gettop(L);
@ -316,7 +316,7 @@ int LuaParser::_EventNPC(std::string package_name, QuestEventID evt, NPC* npc, M
} }
int LuaParser::EventPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data, int LuaParser::EventPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
evt = ConvertLuaEvent(evt); evt = ConvertLuaEvent(evt);
if(evt >= _LargestEventID) { if(evt >= _LargestEventID) {
return 0; return 0;
@ -334,7 +334,7 @@ int LuaParser::EventPlayer(QuestEventID evt, Client *client, std::string data, u
} }
int LuaParser::EventGlobalPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data, int LuaParser::EventGlobalPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
evt = ConvertLuaEvent(evt); evt = ConvertLuaEvent(evt);
if(evt >= _LargestEventID) { if(evt >= _LargestEventID) {
return 0; return 0;
@ -352,7 +352,7 @@ int LuaParser::EventGlobalPlayer(QuestEventID evt, Client *client, std::string d
} }
int LuaParser::_EventPlayer(std::string package_name, QuestEventID evt, Client *client, std::string data, uint32 extra_data, int LuaParser::_EventPlayer(std::string package_name, QuestEventID evt, Client *client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers, luabind::adl::object *l_func) { std::vector<EQEmu::Any> *extra_pointers, luabind::adl::object *l_func) {
const char *sub_name = LuaEvents[evt]; const char *sub_name = LuaEvents[evt];
int start = lua_gettop(L); int start = lua_gettop(L);
@ -409,7 +409,7 @@ int LuaParser::_EventPlayer(std::string package_name, QuestEventID evt, Client *
} }
int LuaParser::EventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data, int LuaParser::EventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
evt = ConvertLuaEvent(evt); evt = ConvertLuaEvent(evt);
if(evt >= _LargestEventID) { if(evt >= _LargestEventID) {
return 0; return 0;
@ -429,7 +429,7 @@ int LuaParser::EventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *
} }
int LuaParser::_EventItem(std::string package_name, QuestEventID evt, Client *client, ItemInst *item, Mob *mob, int LuaParser::_EventItem(std::string package_name, QuestEventID evt, Client *client, ItemInst *item, Mob *mob,
std::string data, uint32 extra_data, std::vector<void*> *extra_pointers, luabind::adl::object *l_func) { std::string data, uint32 extra_data, std::vector<EQEmu::Any> *extra_pointers, luabind::adl::object *l_func) {
const char *sub_name = LuaEvents[evt]; const char *sub_name = LuaEvents[evt];
int start = lua_gettop(L); int start = lua_gettop(L);
@ -492,7 +492,7 @@ int LuaParser::_EventItem(std::string package_name, QuestEventID evt, Client *cl
} }
int LuaParser::EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, int LuaParser::EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
evt = ConvertLuaEvent(evt); evt = ConvertLuaEvent(evt);
if(evt >= _LargestEventID) { if(evt >= _LargestEventID) {
return 0; return 0;
@ -508,7 +508,7 @@ int LuaParser::EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spe
} }
int LuaParser::_EventSpell(std::string package_name, QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, int LuaParser::_EventSpell(std::string package_name, QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data,
std::vector<void*> *extra_pointers, luabind::adl::object *l_func) { std::vector<EQEmu::Any> *extra_pointers, luabind::adl::object *l_func) {
const char *sub_name = LuaEvents[evt]; const char *sub_name = LuaEvents[evt];
int start = lua_gettop(L); int start = lua_gettop(L);
@ -572,7 +572,7 @@ int LuaParser::_EventSpell(std::string package_name, QuestEventID evt, NPC* npc,
return 0; return 0;
} }
int LuaParser::EventEncounter(QuestEventID evt, std::string encounter_name, uint32 extra_data, std::vector<void*> *extra_pointers) { int LuaParser::EventEncounter(QuestEventID evt, std::string encounter_name, uint32 extra_data, std::vector<EQEmu::Any> *extra_pointers) {
evt = ConvertLuaEvent(evt); evt = ConvertLuaEvent(evt);
if(evt >= _LargestEventID) { if(evt >= _LargestEventID) {
return 0; return 0;
@ -588,7 +588,7 @@ int LuaParser::EventEncounter(QuestEventID evt, std::string encounter_name, uint
} }
int LuaParser::_EventEncounter(std::string package_name, QuestEventID evt, std::string encounter_name, uint32 extra_data, int LuaParser::_EventEncounter(std::string package_name, QuestEventID evt, std::string encounter_name, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
const char *sub_name = LuaEvents[evt]; const char *sub_name = LuaEvents[evt];
int start = lua_gettop(L); int start = lua_gettop(L);
@ -972,7 +972,7 @@ void LuaParser::MapFunctions(lua_State *L) {
} }
int LuaParser::DispatchEventNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, int LuaParser::DispatchEventNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
evt = ConvertLuaEvent(evt); evt = ConvertLuaEvent(evt);
if(evt >= _LargestEventID) { if(evt >= _LargestEventID) {
return 0; return 0;
@ -1018,7 +1018,7 @@ int LuaParser::DispatchEventNPC(QuestEventID evt, NPC* npc, Mob *init, std::stri
} }
int LuaParser::DispatchEventPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data, int LuaParser::DispatchEventPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
evt = ConvertLuaEvent(evt); evt = ConvertLuaEvent(evt);
if(evt >= _LargestEventID) { if(evt >= _LargestEventID) {
return 0; return 0;
@ -1047,7 +1047,7 @@ int LuaParser::DispatchEventPlayer(QuestEventID evt, Client *client, std::string
} }
int LuaParser::DispatchEventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data, int LuaParser::DispatchEventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
evt = ConvertLuaEvent(evt); evt = ConvertLuaEvent(evt);
if(evt >= _LargestEventID) { if(evt >= _LargestEventID) {
return 0; return 0;
@ -1093,7 +1093,7 @@ int LuaParser::DispatchEventItem(QuestEventID evt, Client *client, ItemInst *ite
} }
int LuaParser::DispatchEventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, int LuaParser::DispatchEventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
evt = ConvertLuaEvent(evt); evt = ConvertLuaEvent(evt);
if(evt >= _LargestEventID) { if(evt >= _LargestEventID) {
return 0; return 0;

View File

@ -28,19 +28,19 @@ public:
~LuaParser(); ~LuaParser();
virtual int EventNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, virtual int EventNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
virtual int EventGlobalNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, virtual int EventGlobalNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
virtual int EventPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data, virtual int EventPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
virtual int EventGlobalPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data, virtual int EventGlobalPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
virtual int EventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data, virtual int EventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
virtual int EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, virtual int EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
virtual int EventEncounter(QuestEventID evt, std::string encounter_name, uint32 extra_data, virtual int EventEncounter(QuestEventID evt, std::string encounter_name, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
virtual bool HasQuestSub(uint32 npc_id, QuestEventID evt); virtual bool HasQuestSub(uint32 npc_id, QuestEventID evt);
virtual bool HasGlobalQuestSub(QuestEventID evt); virtual bool HasGlobalQuestSub(QuestEventID evt);
@ -65,25 +65,25 @@ public:
virtual uint32 GetIdentifier() { return 0xb0712acc; } virtual uint32 GetIdentifier() { return 0xb0712acc; }
virtual int DispatchEventNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, virtual int DispatchEventNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
virtual int DispatchEventPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data, virtual int DispatchEventPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
virtual int DispatchEventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data, virtual int DispatchEventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
virtual int DispatchEventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, virtual int DispatchEventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
private: private:
int _EventNPC(std::string package_name, QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, int _EventNPC(std::string package_name, QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers, luabind::adl::object *l_func = nullptr); std::vector<EQEmu::Any> *extra_pointers, luabind::adl::object *l_func = nullptr);
int _EventPlayer(std::string package_name, QuestEventID evt, Client *client, std::string data, uint32 extra_data, int _EventPlayer(std::string package_name, QuestEventID evt, Client *client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers, luabind::adl::object *l_func = nullptr); std::vector<EQEmu::Any> *extra_pointers, luabind::adl::object *l_func = nullptr);
int _EventItem(std::string package_name, QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, int _EventItem(std::string package_name, QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data,
uint32 extra_data, std::vector<void*> *extra_pointers, luabind::adl::object *l_func = nullptr); uint32 extra_data, std::vector<EQEmu::Any> *extra_pointers, luabind::adl::object *l_func = nullptr);
int _EventSpell(std::string package_name, QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, int _EventSpell(std::string package_name, QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data,
std::vector<void*> *extra_pointers, luabind::adl::object *l_func = nullptr); std::vector<EQEmu::Any> *extra_pointers, luabind::adl::object *l_func = nullptr);
int _EventEncounter(std::string package_name, QuestEventID evt, std::string encounter_name, uint32 extra_data, int _EventEncounter(std::string package_name, QuestEventID evt, std::string encounter_name, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void LoadScript(std::string filename, std::string package_name); void LoadScript(std::string filename, std::string package_name);
bool HasFunction(std::string function, std::string package_name); bool HasFunction(std::string function, std::string package_name);

View File

@ -27,7 +27,7 @@
//NPC //NPC
void handle_npc_event_say(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_event_say(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
npc->DoQuestPause(init); npc->DoQuestPause(init);
Lua_Client l_client(reinterpret_cast<Client*>(init)); Lua_Client l_client(reinterpret_cast<Client*>(init));
@ -43,7 +43,7 @@ void handle_npc_event_say(QuestInterface *parse, lua_State* L, NPC* npc, Mob *in
} }
void handle_npc_event_trade(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_event_trade(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Lua_Client l_client(reinterpret_cast<Client*>(init)); Lua_Client l_client(reinterpret_cast<Client*>(init));
luabind::adl::object l_client_o = luabind::adl::object(L, l_client); luabind::adl::object l_client_o = luabind::adl::object(L, l_client);
l_client_o.push(L); l_client_o.push(L);
@ -56,7 +56,7 @@ void handle_npc_event_trade(QuestInterface *parse, lua_State* L, NPC* npc, Mob *
if(extra_pointers) { if(extra_pointers) {
for(size_t i = 0; i < extra_pointers->size(); ++i) { for(size_t i = 0; i < extra_pointers->size(); ++i) {
std::string prefix = "item" + std::to_string(static_cast<long long>(i + 1)); std::string prefix = "item" + std::to_string(static_cast<long long>(i + 1));
Lua_ItemInst l_inst = reinterpret_cast<ItemInst*>(extra_pointers->at(i)); Lua_ItemInst l_inst = EQEmu::any_cast<ItemInst*>(extra_pointers->at(i));
luabind::adl::object l_inst_o = luabind::adl::object(L, l_inst); luabind::adl::object l_inst_o = luabind::adl::object(L, l_inst);
l_inst_o.push(L); l_inst_o.push(L);
@ -79,7 +79,7 @@ void handle_npc_event_trade(QuestInterface *parse, lua_State* L, NPC* npc, Mob *
} }
void handle_npc_event_hp(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_event_hp(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
if(extra_data == 1) { if(extra_data == 1) {
lua_pushinteger(L, -1); lua_pushinteger(L, -1);
lua_setfield(L, -2, "hp_event"); lua_setfield(L, -2, "hp_event");
@ -96,7 +96,7 @@ void handle_npc_event_hp(QuestInterface *parse, lua_State* L, NPC* npc, Mob *ini
} }
void handle_npc_single_mob(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_single_mob(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Lua_Mob l_mob(init); Lua_Mob l_mob(init);
luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob);
l_mob_o.push(L); l_mob_o.push(L);
@ -104,7 +104,7 @@ void handle_npc_single_mob(QuestInterface *parse, lua_State* L, NPC* npc, Mob *i
} }
void handle_npc_single_client(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_single_client(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Lua_Client l_client(reinterpret_cast<Client*>(init)); Lua_Client l_client(reinterpret_cast<Client*>(init));
luabind::adl::object l_client_o = luabind::adl::object(L, l_client); luabind::adl::object l_client_o = luabind::adl::object(L, l_client);
l_client_o.push(L); l_client_o.push(L);
@ -112,7 +112,7 @@ void handle_npc_single_client(QuestInterface *parse, lua_State* L, NPC* npc, Mob
} }
void handle_npc_single_npc(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_single_npc(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Lua_NPC l_npc(reinterpret_cast<NPC*>(init)); Lua_NPC l_npc(reinterpret_cast<NPC*>(init));
luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc); luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc);
l_npc_o.push(L); l_npc_o.push(L);
@ -120,7 +120,7 @@ void handle_npc_single_npc(QuestInterface *parse, lua_State* L, NPC* npc, Mob *i
} }
void handle_npc_task_accepted(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_task_accepted(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Lua_Client l_client(reinterpret_cast<Client*>(init)); Lua_Client l_client(reinterpret_cast<Client*>(init));
luabind::adl::object l_client_o = luabind::adl::object(L, l_client); luabind::adl::object l_client_o = luabind::adl::object(L, l_client);
l_client_o.push(L); l_client_o.push(L);
@ -131,7 +131,7 @@ void handle_npc_task_accepted(QuestInterface *parse, lua_State* L, NPC* npc, Mob
} }
void handle_npc_popup(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_popup(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Lua_Mob l_mob(init); Lua_Mob l_mob(init);
luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob);
l_mob_o.push(L); l_mob_o.push(L);
@ -142,7 +142,7 @@ void handle_npc_popup(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init,
} }
void handle_npc_waypoint(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_waypoint(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Lua_Mob l_mob(init); Lua_Mob l_mob(init);
luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob);
l_mob_o.push(L); l_mob_o.push(L);
@ -153,7 +153,7 @@ void handle_npc_waypoint(QuestInterface *parse, lua_State* L, NPC* npc, Mob *ini
} }
void handle_npc_hate(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_hate(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Lua_Mob l_mob(init); Lua_Mob l_mob(init);
luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob);
l_mob_o.push(L); l_mob_o.push(L);
@ -165,19 +165,19 @@ void handle_npc_hate(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, s
void handle_npc_signal(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_signal(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
lua_pushinteger(L, std::stoi(data)); lua_pushinteger(L, std::stoi(data));
lua_setfield(L, -2, "signal"); lua_setfield(L, -2, "signal");
} }
void handle_npc_timer(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_timer(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
lua_pushstring(L, data.c_str()); lua_pushstring(L, data.c_str());
lua_setfield(L, -2, "timer"); lua_setfield(L, -2, "timer");
} }
void handle_npc_death(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_death(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Lua_Mob l_mob(init); Lua_Mob l_mob(init);
luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob);
l_mob_o.push(L); l_mob_o.push(L);
@ -205,7 +205,7 @@ void handle_npc_death(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init,
} }
void handle_npc_cast(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_cast(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
int spell_id = std::stoi(data); int spell_id = std::stoi(data);
if(IsValidSpell(spell_id)) { if(IsValidSpell(spell_id)) {
Lua_Spell l_spell(&spells[spell_id]); Lua_Spell l_spell(&spells[spell_id]);
@ -221,21 +221,21 @@ void handle_npc_cast(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, s
} }
void handle_npc_area(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_area(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
lua_pushinteger(L, *reinterpret_cast<int*>(extra_pointers->at(0))); lua_pushinteger(L, *EQEmu::any_cast<int*>(extra_pointers->at(0)));
lua_setfield(L, -2, "area_id"); lua_setfield(L, -2, "area_id");
lua_pushinteger(L, *reinterpret_cast<int*>(extra_pointers->at(1))); lua_pushinteger(L, *EQEmu::any_cast<int*>(extra_pointers->at(1)));
lua_setfield(L, -2, "area_type"); lua_setfield(L, -2, "area_type");
} }
void handle_npc_null(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_null(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
} }
//Player //Player
void handle_player_say(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_say(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
lua_pushstring(L, data.c_str()); lua_pushstring(L, data.c_str());
lua_setfield(L, -2, "message"); lua_setfield(L, -2, "message");
@ -244,7 +244,7 @@ void handle_player_say(QuestInterface *parse, lua_State* L, Client* client, std:
} }
void handle_player_death(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_death(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Seperator sep(data.c_str()); Seperator sep(data.c_str());
Mob *o = entity_list.GetMobID(std::stoi(sep.arg[0])); Mob *o = entity_list.GetMobID(std::stoi(sep.arg[0]));
@ -274,13 +274,13 @@ void handle_player_death(QuestInterface *parse, lua_State* L, Client* client, st
} }
void handle_player_timer(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_timer(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
lua_pushstring(L, data.c_str()); lua_pushstring(L, data.c_str());
lua_setfield(L, -2, "timer"); lua_setfield(L, -2, "timer");
} }
void handle_player_discover_item(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_discover_item(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
const Item_Struct *item = database.GetItem(extra_data); const Item_Struct *item = database.GetItem(extra_data);
if(item) { if(item) {
Lua_Item l_item(item); Lua_Item l_item(item);
@ -296,51 +296,51 @@ void handle_player_discover_item(QuestInterface *parse, lua_State* L, Client* cl
} }
void handle_player_fish_forage_success(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_fish_forage_success(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Lua_ItemInst l_item(reinterpret_cast<ItemInst*>(extra_pointers->at(0))); Lua_ItemInst l_item(EQEmu::any_cast<ItemInst*>(extra_pointers->at(0)));
luabind::adl::object l_item_o = luabind::adl::object(L, l_item); luabind::adl::object l_item_o = luabind::adl::object(L, l_item);
l_item_o.push(L); l_item_o.push(L);
lua_setfield(L, -2, "item"); lua_setfield(L, -2, "item");
} }
void handle_player_click_object(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_click_object(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Lua_Object l_object(reinterpret_cast<Object*>(extra_pointers->at(0))); Lua_Object l_object(EQEmu::any_cast<Object*>(extra_pointers->at(0)));
luabind::adl::object l_object_o = luabind::adl::object(L, l_object); luabind::adl::object l_object_o = luabind::adl::object(L, l_object);
l_object_o.push(L); l_object_o.push(L);
lua_setfield(L, -2, "object"); lua_setfield(L, -2, "object");
} }
void handle_player_click_door(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_click_door(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Lua_Door l_door(reinterpret_cast<Doors*>(extra_pointers->at(0))); Lua_Door l_door(EQEmu::any_cast<Doors*>(extra_pointers->at(0)));
luabind::adl::object l_door_o = luabind::adl::object(L, l_door); luabind::adl::object l_door_o = luabind::adl::object(L, l_door);
l_door_o.push(L); l_door_o.push(L);
lua_setfield(L, -2, "door"); lua_setfield(L, -2, "door");
} }
void handle_player_signal(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_signal(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
lua_pushinteger(L, std::stoi(data)); lua_pushinteger(L, std::stoi(data));
lua_setfield(L, -2, "signal"); lua_setfield(L, -2, "signal");
} }
void handle_player_popup_response(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_popup_response(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
lua_pushinteger(L, std::stoi(data)); lua_pushinteger(L, std::stoi(data));
lua_setfield(L, -2, "popup_id"); lua_setfield(L, -2, "popup_id");
} }
void handle_player_pick_up(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_pick_up(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Lua_ItemInst l_item(reinterpret_cast<ItemInst*>(extra_pointers->at(0))); Lua_ItemInst l_item(EQEmu::any_cast<ItemInst*>(extra_pointers->at(0)));
luabind::adl::object l_item_o = luabind::adl::object(L, l_item); luabind::adl::object l_item_o = luabind::adl::object(L, l_item);
l_item_o.push(L); l_item_o.push(L);
lua_setfield(L, -2, "item"); lua_setfield(L, -2, "item");
} }
void handle_player_cast(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_cast(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
int spell_id = std::stoi(data); int spell_id = std::stoi(data);
if(IsValidSpell(spell_id)) { if(IsValidSpell(spell_id)) {
Lua_Spell l_spell(&spells[spell_id]); Lua_Spell l_spell(&spells[spell_id]);
@ -356,48 +356,48 @@ void handle_player_cast(QuestInterface *parse, lua_State* L, Client* client, std
} }
void handle_player_task_fail(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_task_fail(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
lua_pushinteger(L, std::stoi(data)); lua_pushinteger(L, std::stoi(data));
lua_setfield(L, -2, "task_id"); lua_setfield(L, -2, "task_id");
} }
void handle_player_zone(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_zone(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
lua_pushinteger(L, std::stoi(data)); lua_pushinteger(L, std::stoi(data));
lua_setfield(L, -2, "zone_id"); lua_setfield(L, -2, "zone_id");
} }
void handle_player_duel_win(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_duel_win(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Lua_Client l_client(reinterpret_cast<Client*>(extra_pointers->at(1))); Lua_Client l_client(EQEmu::any_cast<Client*>(extra_pointers->at(1)));
luabind::adl::object l_client_o = luabind::adl::object(L, l_client); luabind::adl::object l_client_o = luabind::adl::object(L, l_client);
l_client_o.push(L); l_client_o.push(L);
lua_setfield(L, -2, "other"); lua_setfield(L, -2, "other");
} }
void handle_player_duel_loss(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_duel_loss(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Lua_Client l_client(reinterpret_cast<Client*>(extra_pointers->at(0))); Lua_Client l_client(EQEmu::any_cast<Client*>(extra_pointers->at(0)));
luabind::adl::object l_client_o = luabind::adl::object(L, l_client); luabind::adl::object l_client_o = luabind::adl::object(L, l_client);
l_client_o.push(L); l_client_o.push(L);
lua_setfield(L, -2, "other"); lua_setfield(L, -2, "other");
} }
void handle_player_loot(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_loot(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Lua_ItemInst l_item(reinterpret_cast<ItemInst*>(extra_pointers->at(0))); Lua_ItemInst l_item(EQEmu::any_cast<ItemInst*>(extra_pointers->at(0)));
luabind::adl::object l_item_o = luabind::adl::object(L, l_item); luabind::adl::object l_item_o = luabind::adl::object(L, l_item);
l_item_o.push(L); l_item_o.push(L);
lua_setfield(L, -2, "item"); lua_setfield(L, -2, "item");
Lua_Corpse l_corpse(reinterpret_cast<Corpse*>(extra_pointers->at(1))); Lua_Corpse l_corpse(EQEmu::any_cast<Corpse*>(extra_pointers->at(1)));
luabind::adl::object l_corpse_o = luabind::adl::object(L, l_corpse); luabind::adl::object l_corpse_o = luabind::adl::object(L, l_corpse);
l_corpse_o.push(L); l_corpse_o.push(L);
lua_setfield(L, -2, "corpse"); lua_setfield(L, -2, "corpse");
} }
void handle_player_task_stage_complete(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_task_stage_complete(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Seperator sep(data.c_str()); Seperator sep(data.c_str());
lua_pushinteger(L, std::stoi(sep.arg[0])); lua_pushinteger(L, std::stoi(sep.arg[0]));
lua_setfield(L, -2, "task_id"); lua_setfield(L, -2, "task_id");
@ -407,7 +407,7 @@ void handle_player_task_stage_complete(QuestInterface *parse, lua_State* L, Clie
} }
void handle_player_task_update(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_task_update(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Seperator sep(data.c_str()); Seperator sep(data.c_str());
lua_pushinteger(L, std::stoi(sep.arg[0])); lua_pushinteger(L, std::stoi(sep.arg[0]));
lua_setfield(L, -2, "count"); lua_setfield(L, -2, "count");
@ -420,7 +420,7 @@ void handle_player_task_update(QuestInterface *parse, lua_State* L, Client* clie
} }
void handle_player_command(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_command(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Seperator sep(data.c_str(), ' ', 10, 100, true); Seperator sep(data.c_str(), ' ', 10, 100, true);
std::string command(sep.arg[0] + 1); std::string command(sep.arg[0] + 1);
lua_pushstring(L, command.c_str()); lua_pushstring(L, command.c_str());
@ -439,7 +439,7 @@ void handle_player_command(QuestInterface *parse, lua_State* L, Client* client,
} }
void handle_player_combine(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_combine(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
lua_pushinteger(L, extra_data); lua_pushinteger(L, extra_data);
lua_setfield(L, -2, "recipe_id"); lua_setfield(L, -2, "recipe_id");
@ -448,24 +448,24 @@ void handle_player_combine(QuestInterface *parse, lua_State* L, Client* client,
} }
void handle_player_feign(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_feign(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Lua_NPC l_npc(reinterpret_cast<NPC*>(extra_pointers->at(0))); Lua_NPC l_npc(EQEmu::any_cast<NPC*>(extra_pointers->at(0)));
luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc); luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc);
l_npc_o.push(L); l_npc_o.push(L);
lua_setfield(L, -2, "other"); lua_setfield(L, -2, "other");
} }
void handle_player_area(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_area(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
lua_pushinteger(L, *reinterpret_cast<int*>(extra_pointers->at(0))); lua_pushinteger(L, *EQEmu::any_cast<int*>(extra_pointers->at(0)));
lua_setfield(L, -2, "area_id"); lua_setfield(L, -2, "area_id");
lua_pushinteger(L, *reinterpret_cast<int*>(extra_pointers->at(1))); lua_pushinteger(L, *EQEmu::any_cast<int*>(extra_pointers->at(1)));
lua_setfield(L, -2, "area_type"); lua_setfield(L, -2, "area_type");
} }
void handle_player_respawn(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_respawn(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
lua_pushinteger(L, std::stoi(data)); lua_pushinteger(L, std::stoi(data));
lua_setfield(L, -2, "option"); lua_setfield(L, -2, "option");
@ -474,8 +474,8 @@ void handle_player_respawn(QuestInterface *parse, lua_State* L, Client* client,
} }
void handle_player_packet(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_packet(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Lua_Packet l_packet(reinterpret_cast<EQApplicationPacket*>(extra_pointers->at(0))); Lua_Packet l_packet(EQEmu::any_cast<EQApplicationPacket*>(extra_pointers->at(0)));
luabind::adl::object l_packet_o = luabind::adl::object(L, l_packet); luabind::adl::object l_packet_o = luabind::adl::object(L, l_packet);
l_packet_o.push(L); l_packet_o.push(L);
lua_setfield(L, -2, "packet"); lua_setfield(L, -2, "packet");
@ -485,24 +485,24 @@ void handle_player_packet(QuestInterface *parse, lua_State* L, Client* client, s
} }
void handle_player_null(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_null(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
} }
//Item //Item
void handle_item_click(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data, void handle_item_click(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
lua_pushinteger(L, extra_data); lua_pushinteger(L, extra_data);
lua_setfield(L, -2, "slot_id"); lua_setfield(L, -2, "slot_id");
} }
void handle_item_timer(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data, void handle_item_timer(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
lua_pushstring(L, data.c_str()); lua_pushstring(L, data.c_str());
lua_setfield(L, -2, "timer"); lua_setfield(L, -2, "timer");
} }
void handle_item_proc(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data, void handle_item_proc(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Lua_Mob l_mob(mob); Lua_Mob l_mob(mob);
luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob);
@ -523,7 +523,7 @@ void handle_item_proc(QuestInterface *parse, lua_State* L, Client* client, ItemI
} }
void handle_item_loot(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data, void handle_item_loot(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
if(mob && mob->IsCorpse()) { if(mob && mob->IsCorpse()) {
Lua_Corpse l_corpse(mob->CastToCorpse()); Lua_Corpse l_corpse(mob->CastToCorpse());
luabind::adl::object l_corpse_o = luabind::adl::object(L, l_corpse); luabind::adl::object l_corpse_o = luabind::adl::object(L, l_corpse);
@ -538,14 +538,14 @@ void handle_item_loot(QuestInterface *parse, lua_State* L, Client* client, ItemI
} }
void handle_item_equip(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data, void handle_item_equip(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
lua_pushinteger(L, extra_data); lua_pushinteger(L, extra_data);
lua_setfield(L, -2, "slot_id"); lua_setfield(L, -2, "slot_id");
} }
void handle_item_augment(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data, void handle_item_augment(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Lua_ItemInst l_item(reinterpret_cast<ItemInst*>(extra_pointers->at(0))); Lua_ItemInst l_item(EQEmu::any_cast<ItemInst*>(extra_pointers->at(0)));
luabind::adl::object l_item_o = luabind::adl::object(L, l_item); luabind::adl::object l_item_o = luabind::adl::object(L, l_item);
l_item_o.push(L); l_item_o.push(L);
lua_setfield(L, -2, "aug"); lua_setfield(L, -2, "aug");
@ -555,8 +555,8 @@ void handle_item_augment(QuestInterface *parse, lua_State* L, Client* client, It
} }
void handle_item_augment_insert(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data, void handle_item_augment_insert(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Lua_ItemInst l_item(reinterpret_cast<ItemInst*>(extra_pointers->at(0))); Lua_ItemInst l_item(EQEmu::any_cast<ItemInst*>(extra_pointers->at(0)));
luabind::adl::object l_item_o = luabind::adl::object(L, l_item); luabind::adl::object l_item_o = luabind::adl::object(L, l_item);
l_item_o.push(L); l_item_o.push(L);
lua_setfield(L, -2, "item"); lua_setfield(L, -2, "item");
@ -566,8 +566,8 @@ void handle_item_augment_insert(QuestInterface *parse, lua_State* L, Client* cli
} }
void handle_item_augment_remove(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data, void handle_item_augment_remove(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
Lua_ItemInst l_item(reinterpret_cast<ItemInst*>(extra_pointers->at(0))); Lua_ItemInst l_item(EQEmu::any_cast<ItemInst*>(extra_pointers->at(0)));
luabind::adl::object l_item_o = luabind::adl::object(L, l_item); luabind::adl::object l_item_o = luabind::adl::object(L, l_item);
l_item_o.push(L); l_item_o.push(L);
lua_setfield(L, -2, "item"); lua_setfield(L, -2, "item");
@ -575,17 +575,17 @@ void handle_item_augment_remove(QuestInterface *parse, lua_State* L, Client* cli
lua_pushinteger(L, extra_data); lua_pushinteger(L, extra_data);
lua_setfield(L, -2, "slot_id"); lua_setfield(L, -2, "slot_id");
lua_pushboolean(L, *reinterpret_cast<bool*>(extra_pointers->at(1))); lua_pushboolean(L, *EQEmu::any_cast<bool*>(extra_pointers->at(1)));
lua_setfield(L, -2, "destroyed"); lua_setfield(L, -2, "destroyed");
} }
void handle_item_null(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data, void handle_item_null(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
} }
//Spell //Spell
void handle_spell_effect(QuestInterface *parse, lua_State* L, NPC* npc, Client* client, uint32 spell_id, uint32 extra_data, void handle_spell_effect(QuestInterface *parse, lua_State* L, NPC* npc, Client* client, uint32 spell_id, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
if(npc) { if(npc) {
Lua_Mob l_npc(npc); Lua_Mob l_npc(npc);
luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc); luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc);
@ -602,7 +602,7 @@ void handle_spell_effect(QuestInterface *parse, lua_State* L, NPC* npc, Client*
lua_setfield(L, -2, "target"); lua_setfield(L, -2, "target");
lua_pushinteger(L, *reinterpret_cast<int*>(extra_pointers->at(0))); lua_pushinteger(L, *EQEmu::any_cast<int*>(extra_pointers->at(0)));
lua_setfield(L, -2, "buff_slot"); lua_setfield(L, -2, "buff_slot");
lua_pushinteger(L, extra_data); lua_pushinteger(L, extra_data);
@ -610,7 +610,7 @@ void handle_spell_effect(QuestInterface *parse, lua_State* L, NPC* npc, Client*
} }
void handle_spell_tic(QuestInterface *parse, lua_State* L, NPC* npc, Client* client, uint32 spell_id, uint32 extra_data, void handle_spell_tic(QuestInterface *parse, lua_State* L, NPC* npc, Client* client, uint32 spell_id, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
if(npc) { if(npc) {
Lua_Mob l_npc(npc); Lua_Mob l_npc(npc);
luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc); luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc);
@ -627,13 +627,13 @@ void handle_spell_tic(QuestInterface *parse, lua_State* L, NPC* npc, Client* cli
lua_setfield(L, -2, "target"); lua_setfield(L, -2, "target");
lua_pushinteger(L, *reinterpret_cast<int*>(extra_pointers->at(0))); lua_pushinteger(L, *EQEmu::any_cast<int*>(extra_pointers->at(0)));
lua_setfield(L, -2, "tics_remaining"); lua_setfield(L, -2, "tics_remaining");
lua_pushinteger(L, *reinterpret_cast<uint8*>(extra_pointers->at(1))); lua_pushinteger(L, *EQEmu::any_cast<uint8*>(extra_pointers->at(1)));
lua_setfield(L, -2, "caster_level"); lua_setfield(L, -2, "caster_level");
lua_pushinteger(L, *reinterpret_cast<int*>(extra_pointers->at(2))); lua_pushinteger(L, *EQEmu::any_cast<int*>(extra_pointers->at(2)));
lua_setfield(L, -2, "buff_slot"); lua_setfield(L, -2, "buff_slot");
lua_pushinteger(L, extra_data); lua_pushinteger(L, extra_data);
@ -641,7 +641,7 @@ void handle_spell_tic(QuestInterface *parse, lua_State* L, NPC* npc, Client* cli
} }
void handle_spell_fade(QuestInterface *parse, lua_State* L, NPC* npc, Client* client, uint32 spell_id, uint32 extra_data, void handle_spell_fade(QuestInterface *parse, lua_State* L, NPC* npc, Client* client, uint32 spell_id, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
if(npc) { if(npc) {
Lua_Mob l_npc(npc); Lua_Mob l_npc(npc);
luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc); luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc);
@ -661,12 +661,12 @@ void handle_spell_fade(QuestInterface *parse, lua_State* L, NPC* npc, Client* cl
lua_pushinteger(L, extra_data); lua_pushinteger(L, extra_data);
lua_setfield(L, -2, "buff_slot"); lua_setfield(L, -2, "buff_slot");
lua_pushinteger(L, *reinterpret_cast<uint16*>(extra_pointers->at(0))); lua_pushinteger(L, *EQEmu::any_cast<uint16*>(extra_pointers->at(0)));
lua_setfield(L, -2, "caster_id"); lua_setfield(L, -2, "caster_id");
} }
void handle_translocate_finish(QuestInterface *parse, lua_State* L, NPC* npc, Client* client, uint32 spell_id, uint32 extra_data, void handle_translocate_finish(QuestInterface *parse, lua_State* L, NPC* npc, Client* client, uint32 spell_id, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
if(npc) { if(npc) {
Lua_Mob l_npc(npc); Lua_Mob l_npc(npc);
luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc); luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc);
@ -685,7 +685,7 @@ void handle_translocate_finish(QuestInterface *parse, lua_State* L, NPC* npc, Cl
} }
void handle_spell_null(QuestInterface *parse, lua_State* L, NPC* npc, Client* client, uint32 spell_id, uint32 extra_data, void handle_spell_null(QuestInterface *parse, lua_State* L, NPC* npc, Client* client, uint32 spell_id, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
} }
#endif #endif

View File

@ -2,128 +2,128 @@
#define _EQE_LUA_PARSER_EVENTS_H #define _EQE_LUA_PARSER_EVENTS_H
#ifdef LUA_EQEMU #ifdef LUA_EQEMU
typedef void(*NPCArgumentHandler)(QuestInterface*, lua_State*, NPC*, Mob*, std::string, uint32, std::vector<void*>*); typedef void(*NPCArgumentHandler)(QuestInterface*, lua_State*, NPC*, Mob*, std::string, uint32, std::vector<EQEmu::Any>*);
typedef void(*PlayerArgumentHandler)(QuestInterface*, lua_State*, Client*, std::string, uint32, std::vector<void*>*); typedef void(*PlayerArgumentHandler)(QuestInterface*, lua_State*, Client*, std::string, uint32, std::vector<EQEmu::Any>*);
typedef void(*ItemArgumentHandler)(QuestInterface*, lua_State*, Client*, ItemInst*, Mob*, std::string, uint32, std::vector<void*>*); typedef void(*ItemArgumentHandler)(QuestInterface*, lua_State*, Client*, ItemInst*, Mob*, std::string, uint32, std::vector<EQEmu::Any>*);
typedef void(*SpellArgumentHandler)(QuestInterface*, lua_State*, NPC*, Client*, uint32, uint32, std::vector<void*>*); typedef void(*SpellArgumentHandler)(QuestInterface*, lua_State*, NPC*, Client*, uint32, uint32, std::vector<EQEmu::Any>*);
//NPC //NPC
void handle_npc_event_say(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_event_say(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_npc_event_trade(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_event_trade(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_npc_event_hp(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_event_hp(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_npc_single_mob(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_single_mob(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_npc_single_client(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_single_client(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_npc_single_npc(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_single_npc(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_npc_task_accepted(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_task_accepted(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_npc_popup(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_popup(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_npc_waypoint(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_waypoint(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_npc_hate(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_hate(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_npc_signal(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_signal(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_npc_timer(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_timer(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_npc_death(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_death(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_npc_cast(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_cast(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_npc_area(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_area(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_npc_null(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_null(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
//Player //Player
void handle_player_say(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_say(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_player_death(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_death(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_player_timer(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_timer(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_player_discover_item(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_discover_item(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_player_fish_forage_success(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_fish_forage_success(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_player_click_object(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_click_object(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_player_click_door(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_click_door(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_player_signal(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_signal(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_player_popup_response(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_popup_response(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_player_pick_up(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_pick_up(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_player_cast(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_cast(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_player_task_fail(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_task_fail(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_player_zone(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_zone(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_player_duel_win(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_duel_win(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_player_duel_loss(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_duel_loss(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_player_loot(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_loot(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_player_task_stage_complete(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_task_stage_complete(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_player_task_update(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_task_update(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_player_command(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_command(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_player_combine(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_combine(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_player_feign(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_feign(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_player_area(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_area(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_player_respawn(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_respawn(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_player_packet(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_packet(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_player_null(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, void handle_player_null(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
//Item //Item
void handle_item_click(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data, void handle_item_click(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_item_timer(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data, void handle_item_timer(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_item_proc(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data, void handle_item_proc(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_item_loot(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data, void handle_item_loot(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_item_equip(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data, void handle_item_equip(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_item_augment(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data, void handle_item_augment(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_item_augment_insert(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data, void handle_item_augment_insert(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_item_augment_remove(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data, void handle_item_augment_remove(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_item_null(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data, void handle_item_null(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
//Spell //Spell
void handle_spell_effect(QuestInterface *parse, lua_State* L, NPC* npc, Client* client, uint32 spell_id, uint32 extra_data, void handle_spell_effect(QuestInterface *parse, lua_State* L, NPC* npc, Client* client, uint32 spell_id, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_spell_tic(QuestInterface *parse, lua_State* L, NPC* npc, Client* client, uint32 spell_id, uint32 extra_data, void handle_spell_tic(QuestInterface *parse, lua_State* L, NPC* npc, Client* client, uint32 spell_id, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_spell_fade(QuestInterface *parse, lua_State* L, NPC* npc, Client* client, uint32 spell_id, uint32 extra_data, void handle_spell_fade(QuestInterface *parse, lua_State* L, NPC* npc, Client* client, uint32 spell_id, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_translocate_finish(QuestInterface *parse, lua_State* L, NPC* npc, Client* client, uint32 spell_id, uint32 extra_data, void handle_translocate_finish(QuestInterface *parse, lua_State* L, NPC* npc, Client* client, uint32 spell_id, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void handle_spell_null(QuestInterface *parse, lua_State* L, NPC* npc, Client* client, uint32 spell_id, uint32 extra_data, void handle_spell_null(QuestInterface *parse, lua_State* L, NPC* npc, Client* client, uint32 spell_id, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
#endif #endif
#endif #endif

View File

@ -183,6 +183,7 @@ Mob::Mob(const char* in_name,
has_MGB = false; has_MGB = false;
has_ProjectIllusion = false; has_ProjectIllusion = false;
SpellPowerDistanceMod = 0; SpellPowerDistanceMod = 0;
last_los_check = false;
if(in_aa_title>0) if(in_aa_title>0)
aa_title = in_aa_title; aa_title = in_aa_title;
@ -341,6 +342,7 @@ Mob::Mob(const char* in_name,
viral_spells[i] = 0; viral_spells[i] = 0;
} }
pStandingPetOrder = SPO_Follow; pStandingPetOrder = SPO_Follow;
pseudo_rooted = false;
see_invis = in_see_invis; see_invis = in_see_invis;
see_invis_undead = in_see_invis_undead != 0; see_invis_undead = in_see_invis_undead != 0;

View File

@ -464,6 +464,8 @@ public:
bool CheckLosFN(float posX, float posY, float posZ, float mobSize); bool CheckLosFN(float posX, float posY, float posZ, float mobSize);
inline void SetChanged() { pLastChange = Timer::GetCurrentTime(); } inline void SetChanged() { pLastChange = Timer::GetCurrentTime(); }
inline const uint32 LastChange() const { return pLastChange; } inline const uint32 LastChange() const { return pLastChange; }
inline void SetLastLosState(bool value) { last_los_check = value; }
inline bool CheckLastLosState() const { return last_los_check; }
//Quest //Quest
void QuestReward(Client *c = nullptr, uint32 silver = 0, uint32 gold = 0, uint32 platinum = 0); void QuestReward(Client *c = nullptr, uint32 silver = 0, uint32 gold = 0, uint32 platinum = 0);
@ -752,7 +754,8 @@ public:
inline const bool IsRooted() const { return rooted || permarooted; } inline const bool IsRooted() const { return rooted || permarooted; }
inline const bool HasVirus() const { return has_virus; } inline const bool HasVirus() const { return has_virus; }
int GetSnaredAmount(); int GetSnaredAmount();
inline const bool IsPseudoRooted() const { return pseudo_rooted; }
inline void SetPseudoRoot(bool prState) { pseudo_rooted = prState; }
int GetCurWp() { return cur_wp; } int GetCurWp() { return cur_wp; }
@ -1119,6 +1122,8 @@ protected:
bool has_MGB; bool has_MGB;
bool has_ProjectIllusion; bool has_ProjectIllusion;
int16 SpellPowerDistanceMod; int16 SpellPowerDistanceMod;
bool last_los_check;
bool pseudo_rooted;
// Bind wound // Bind wound
Timer bindwound_timer; Timer bindwound_timer;

View File

@ -541,13 +541,40 @@ void NPC::AI_Start(uint32 iMoveDelay) {
void Mob::AI_Stop() { void Mob::AI_Stop() {
if (!IsAIControlled()) if (!IsAIControlled())
return; return;
pAIControlled = false; pAIControlled = false;
safe_delete(AIthink_timer); safe_delete(AIthink_timer);
safe_delete(AIwalking_timer); safe_delete(AIwalking_timer);
safe_delete(AImovement_timer); safe_delete(AImovement_timer);
safe_delete(AItarget_check_timer) safe_delete(AItarget_check_timer);
safe_delete(AIscanarea_timer); safe_delete(AIscanarea_timer);
safe_delete(AIfeignremember_timer); safe_delete(AIfeignremember_timer);
safe_delete(PathingLOSCheckTimer);
safe_delete(PathingRouteUpdateTimerShort);
safe_delete(PathingRouteUpdateTimerLong);
attack_timer.Disable();
attack_dw_timer.Disable();
ranged_timer.Disable();
tic_timer.Disable();
mana_timer.Disable();
spellend_timer.Disable();
projectile_timer.Disable();
rewind_timer.Disable();
bindwound_timer.Disable();
stunned_timer.Disable();
spun_timer.Disable();
bardsong_timer.Disable();
gravity_timer.Disable();
viral_timer.Disable();
flee_timer.Disable();
for (int sat = 0; sat < MAX_SPECIAL_ATTACK; ++sat) {
if (SpecialAbilities[sat].timer)
SpecialAbilities[sat].timer->Disable();
}
hate_list.Wipe(); hate_list.Wipe();
} }

View File

@ -48,6 +48,7 @@
#include "worldserver.h" #include "worldserver.h"
#include "net.h" #include "net.h"
#include "zone.h" #include "zone.h"
#include "queryserv.h"
#include "command.h" #include "command.h"
#include "zone_config.h" #include "zone_config.h"
#include "titles.h" #include "titles.h"
@ -98,6 +99,7 @@ npcDecayTimes_Struct npcCorpseDecayTimes[100];
TitleManager title_manager; TitleManager title_manager;
DBAsyncFinishedQueue MTdbafq; DBAsyncFinishedQueue MTdbafq;
DBAsync *dbasync = nullptr; DBAsync *dbasync = nullptr;
QueryServ *QServ = 0;
TaskManager *taskmanager = 0; TaskManager *taskmanager = 0;
QuestParserCollection *parse = 0; QuestParserCollection *parse = 0;
@ -114,6 +116,8 @@ int main(int argc, char** argv) {
const char *zone_name; const char *zone_name;
QServ = new QueryServ;
if(argc == 3) { if(argc == 3) {
worldserver.SetLauncherName(argv[2]); worldserver.SetLauncherName(argv[2]);
worldserver.SetLaunchedName(argv[1]); worldserver.SetLaunchedName(argv[1]);
@ -622,7 +626,7 @@ void LoadSpells(EQEmu::MemoryMappedFile **mmf) {
SPDAT_RECORDS = records; SPDAT_RECORDS = records;
} }
/* Update Window Title with relevant information */
void UpdateWindowTitle(char* iNewTitle) { void UpdateWindowTitle(char* iNewTitle) {
#ifdef _WINDOWS #ifdef _WINDOWS
char tmp[500]; char tmp[500];
@ -634,7 +638,7 @@ void UpdateWindowTitle(char* iNewTitle) {
#if defined(GOTFRAGS) || defined(_EQDEBUG) #if defined(GOTFRAGS) || defined(_EQDEBUG)
snprintf(tmp, sizeof(tmp), "%i: %s, %i clients, %i", ZoneConfig::get()->ZonePort, zone->GetShortName(), numclients, getpid()); snprintf(tmp, sizeof(tmp), "%i: %s, %i clients, %i", ZoneConfig::get()->ZonePort, zone->GetShortName(), numclients, getpid());
#else #else
snprintf(tmp, sizeof(tmp), "%i: %s, %i clients", ZoneConfig::get()->ZonePort, zone->GetShortName(), numclients); snprintf(tmp, sizeof(tmp), "%s :: clients: %i inst_id: %i inst_ver: %i :: port: %i", zone->GetShortName(), numclients, zone->GetInstanceID(), zone->GetInstanceVersion(), ZoneConfig::get()->ZonePort);
#endif #endif
} }
else { else {

View File

@ -1787,252 +1787,49 @@ void NPC::ModifyNPCStat(const char *identifier, const char *newValue)
{ {
std::string id = identifier; std::string id = identifier;
std::string val = newValue; std::string val = newValue;
for(int i = 0; i < id.length(); ++i) for(int i = 0; i < id.length(); ++i) {
{
id[i] = std::tolower(id[i]); id[i] = std::tolower(id[i]);
} }
if(id == "ac") if(id == "ac") { AC = atoi(val.c_str()); return; }
{ else if(id == "str") { STR = atoi(val.c_str()); return; }
AC = atoi(val.c_str()); else if(id == "sta") { STA = atoi(val.c_str()); return; }
return; else if(id == "agi") { AGI = atoi(val.c_str()); return; }
} else if(id == "dex") { DEX = atoi(val.c_str()); return; }
else if(id == "wis") { WIS = atoi(val.c_str()); CalcMaxMana(); return; }
if(id == "str") else if(id == "int" || id == "_int") { INT = atoi(val.c_str()); CalcMaxMana(); return; }
{ else if(id == "cha") { CHA = atoi(val.c_str()); return; }
STR = atoi(val.c_str()); else if(id == "max_hp") { base_hp = atoi(val.c_str()); CalcMaxHP(); if (cur_hp > max_hp) { cur_hp = max_hp; } return; }
return; else if(id == "max_mana") { npc_mana = atoi(val.c_str()); CalcMaxMana(); if (cur_mana > max_mana){ cur_mana = max_mana; } return; }
} else if(id == "mr") { MR = atoi(val.c_str()); return; }
else if(id == "fr") { FR = atoi(val.c_str()); return; }
if(id == "sta") else if(id == "cr") { CR = atoi(val.c_str()); return; }
{ else if(id == "pr") { PR = atoi(val.c_str()); return; }
STA = atoi(val.c_str()); else if(id == "dr") { DR = atoi(val.c_str()); return; }
return; else if(id == "PhR") { PhR = atoi(val.c_str()); return; }
} else if(id == "runspeed") { runspeed = (float)atof(val.c_str()); CalcBonuses(); return; }
else if(id == "special_attacks") { NPCSpecialAttacks(val.c_str(), 0, 1); return; }
if(id == "agi") else if(id == "attack_speed") { attack_speed = (float)atof(val.c_str()); CalcBonuses(); return; }
{ else if(id == "atk") { ATK = atoi(val.c_str()); return; }
AGI = atoi(val.c_str()); else if(id == "accuracy") { accuracy_rating = atoi(val.c_str()); return; }
return; else if(id == "avoidance") { avoidance_rating = atoi(val.c_str()); return; }
} else if(id == "trackable") { trackable = atoi(val.c_str()); return; }
else if(id == "min_hit") { min_dmg = atoi(val.c_str()); return; }
if(id == "dex") else if(id == "max_hit") { max_dmg = atoi(val.c_str()); return; }
{ else if(id == "attack_count") { attack_count = atoi(val.c_str()); return; }
DEX = atoi(val.c_str()); else if(id == "see_invis") { see_invis = atoi(val.c_str()); return; }
return; else if(id == "see_invis_undead") { see_invis_undead = atoi(val.c_str()); return; }
} else if(id == "see_hide") { see_hide = atoi(val.c_str()); return; }
else if(id == "see_improved_hide") { see_improved_hide = atoi(val.c_str()); return; }
if(id == "wis") else if(id == "hp_regen") { hp_regen = atoi(val.c_str()); return; }
{ else if(id == "mana_regen") { mana_regen = atoi(val.c_str()); return; }
WIS = atoi(val.c_str()); else if(id == "level") { SetLevel(atoi(val.c_str())); return; }
CalcMaxMana(); else if(id == "aggro") { pAggroRange = atof(val.c_str()); return; }
return; else if(id == "assist") { pAssistRange = atof(val.c_str()); return; }
} else if(id == "slow_mitigation") { slow_mitigation = atoi(val.c_str()); return; }
else if(id == "loottable_id") { loottable_id = atof(val.c_str()); return; }
if(id == "int" || id == "_int") else if(id == "healscale") { healscale = atof(val.c_str()); return; }
{ else if(id == "spellscale") { spellscale = atof(val.c_str()); return; }
INT = atoi(val.c_str());
CalcMaxMana();
return;
}
if(id == "cha")
{
CHA = atoi(val.c_str());
return;
}
if(id == "max_hp")
{
base_hp = atoi(val.c_str());
CalcMaxHP();
if(cur_hp > max_hp)
cur_hp = max_hp;
return;
}
if(id == "max_mana")
{
npc_mana = atoi(val.c_str());
CalcMaxMana();
if(cur_mana > max_mana)
cur_mana = max_mana;
return;
}
if(id == "mr")
{
MR = atoi(val.c_str());
return;
}
if(id == "fr")
{
FR = atoi(val.c_str());
return;
}
if(id == "cr")
{
CR = atoi(val.c_str());
return;
}
if(id == "pr")
{
PR = atoi(val.c_str());
return;
}
if(id == "dr")
{
DR = atoi(val.c_str());
return;
}
if(id == "PhR")
{
PhR = atoi(val.c_str());
return;
}
if(id == "runspeed")
{
runspeed = (float)atof(val.c_str());
CalcBonuses();
return;
}
if(id == "special_attacks")
{
//Added reset flag.
NPCSpecialAttacks(val.c_str(), 0, 1);
return;
}
if(id == "attack_speed")
{
attack_speed = (float)atof(val.c_str());
CalcBonuses();
return;
}
if(id == "atk")
{
ATK = atoi(val.c_str());
return;
}
if(id == "accuracy")
{
accuracy_rating = atoi(val.c_str());
return;
}
if(id == "avoidance")
{
avoidance_rating = atoi(val.c_str());
return;
}
if(id == "trackable")
{
trackable = atoi(val.c_str());
return;
}
if(id == "min_hit")
{
min_dmg = atoi(val.c_str());
return;
}
if(id == "max_hit")
{
max_dmg = atoi(val.c_str());
return;
}
if(id == "attack_count")
{
attack_count = atoi(val.c_str());
return;
}
if(id == "see_invis")
{
see_invis = atoi(val.c_str());
return;
}
if(id == "see_invis_undead")
{
see_invis_undead = atoi(val.c_str());
return;
}
if(id == "see_hide")
{
see_hide = atoi(val.c_str());
return;
}
if(id == "see_improved_hide")
{
see_improved_hide = atoi(val.c_str());
return;
}
if(id == "hp_regen")
{
hp_regen = atoi(val.c_str());
return;
}
if(id == "mana_regen")
{
mana_regen = atoi(val.c_str());
return;
}
if(id == "level")
{
SetLevel(atoi(val.c_str()));
return;
}
if(id == "aggro")
{
pAggroRange = atof(val.c_str());
return;
}
if(id == "assist")
{
pAssistRange = atof(val.c_str());
return;
}
if(id == "slow_mitigation")
{
slow_mitigation = atoi(val.c_str());
return;
}
if(id == "loottable_id")
{
loottable_id = atof(val.c_str());
return;
}
if(id == "healscale")
{
healscale = atof(val.c_str());
return;
}
if(id == "spellscale")
{
spellscale = atof(val.c_str());
return;
}
} }
void NPC::LevelScale() { void NPC::LevelScale() {

View File

@ -465,7 +465,7 @@ bool Object::HandleClick(Client* sender, const ClickObject_Struct* click_object)
char buf[10]; char buf[10];
snprintf(buf, 9, "%u", m_inst->GetItem()->ID); snprintf(buf, 9, "%u", m_inst->GetItem()->ID);
buf[9] = '\0'; buf[9] = '\0';
std::vector<void*> args; std::vector<EQEmu::Any> args;
args.push_back(m_inst); args.push_back(m_inst);
parse->EventPlayer(EVENT_PLAYER_PICKUP, sender, buf, 0, &args); parse->EventPlayer(EVENT_PLAYER_PICKUP, sender, buf, 0, &args);

View File

@ -1321,6 +1321,8 @@ XS(XS_Client_MovePCInstance)
_log(CLIENT__ERROR, "Perl(XS_Client_MovePCInstance) attempted to process an Unknown type reference"); _log(CLIENT__ERROR, "Perl(XS_Client_MovePCInstance) attempted to process an Unknown type reference");
Perl_croak(aTHX_ "THIS is not of type Client"); Perl_croak(aTHX_ "THIS is not of type Client");
Perl_croak(aTHX_ "THIS is not of type Client");
} }
} }
XSRETURN_EMPTY; XSRETURN_EMPTY;

View File

@ -300,8 +300,6 @@ void ZoneDatabase::RefreshPetitionsFromDB()
newpet->SetSentTime2(atol(row[13])); newpet->SetSentTime2(atol(row[13]));
newpet->SetGMText(row[14]); newpet->SetGMText(row[14]);
std::cout << "Petition " << row[0] << " pettime = " << newpet->GetSentTime() << std::endl;
if (atoi(row[12]) == 1) if (atoi(row[12]) == 1)
newpet->SetCheckedOut(true); newpet->SetCheckedOut(true);
else else

52
zone/queryserv.cpp Normal file
View File

@ -0,0 +1,52 @@
/* 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
*/
#include "../common/debug.h"
#include "../common/servertalk.h"
#include "../common/string_util.h"
#include "queryserv.h"
#include "worldserver.h"
#include "net.h"
#include <iostream>
extern WorldServer worldserver;
extern QueryServ* QServ;
QueryServ::QueryServ(){
}
QueryServ::~QueryServ(){
}
void QueryServ::SendQuery(std::string Query)
{
ServerPacket* pack = new ServerPacket(ServerOP_QSSendQuery, Query.length() + 5);
pack->WriteUInt32(Query.length()); /* Pack Query String Size so it can be dynamically broken out at queryserv */
pack->WriteString(Query.c_str()); /* Query */
worldserver.SendPacket(pack);
safe_delete(pack);
}
void QueryServ::PlayerLogEvent(int Event_Type, int Character_ID, std::string Event_Desc)
{
std::string query = StringFormat(
"INSERT INTO `qs_player_events` (event, char_id, event_desc, time) VALUES (%i, %i, '%s', UNIX_TIMESTAMP(now()))",
Event_Type, Character_ID, EscapeString(Event_Desc).c_str());
SendQuery(query);
}

35
zone/queryserv.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef QUERYSERV_ZONE_H
#define QUERYSERV_ZONE_H
/*
enum PlayerGenericLogEventTypes
These Enums are for the generic logging table that are not complex and require more advanced logic
*/
enum PlayerGenericLogEventTypes {
Player_Log_Quest = 1,
Player_Log_Zoning,
Player_Log_Deaths,
Player_Log_Connect_State,
Player_Log_Levels,
Player_Log_Keyring_Addition,
Player_Log_QGlobal_Update,
Player_Log_Task_Updates,
Player_Log_AA_Purchases,
Player_Log_Trade_Skill_Events,
Player_Log_Issued_Commands,
Player_Log_Money_Transactions,
Player_Log_Alternate_Currency_Transactions,
};
class QueryServ{
public:
QueryServ();
~QueryServ();
void SendQuery(std::string Query);
void PlayerLogEvent(int Event_Type, int Character_ID, std::string Event_Desc);
};
#endif /* QUERYSERV_ZONE_H */

View File

@ -20,6 +20,7 @@
#define _EQE_QUESTINTERFACE_H #define _EQE_QUESTINTERFACE_H
#include "../common/types.h" #include "../common/types.h"
#include "../common/any.h"
#include "event_codes.h" #include "event_codes.h"
class ItemInst; class ItemInst;
@ -29,19 +30,19 @@ class NPC;
class QuestInterface { class QuestInterface {
public: public:
virtual int EventNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, virtual int EventNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { return 0; } std::vector<EQEmu::Any> *extra_pointers) { return 0; }
virtual int EventGlobalNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, virtual int EventGlobalNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { return 0; } std::vector<EQEmu::Any> *extra_pointers) { return 0; }
virtual int EventPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data, virtual int EventPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { return 0; } std::vector<EQEmu::Any> *extra_pointers) { return 0; }
virtual int EventGlobalPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data, virtual int EventGlobalPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { return 0; } std::vector<EQEmu::Any> *extra_pointers) { return 0; }
virtual int EventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data, virtual int EventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { return 0; } std::vector<EQEmu::Any> *extra_pointers) { return 0; }
virtual int EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, virtual int EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data,
std::vector<void*> *extra_pointers) { return 0; } std::vector<EQEmu::Any> *extra_pointers) { return 0; }
virtual int EventEncounter(QuestEventID evt, std::string encounter_name, uint32 extra_data, virtual int EventEncounter(QuestEventID evt, std::string encounter_name, uint32 extra_data,
std::vector<void*> *extra_pointers) { return 0; } std::vector<EQEmu::Any> *extra_pointers) { return 0; }
virtual bool HasQuestSub(uint32 npcid, QuestEventID evt) { return false; } virtual bool HasQuestSub(uint32 npcid, QuestEventID evt) { return false; }
virtual bool HasGlobalQuestSub(QuestEventID evt) { return false; } virtual bool HasGlobalQuestSub(QuestEventID evt) { return false; }
@ -60,13 +61,13 @@ public:
virtual void LoadEncounterScript(std::string filename, std::string encounter_name) { } virtual void LoadEncounterScript(std::string filename, std::string encounter_name) { }
virtual int DispatchEventNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, virtual int DispatchEventNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { return 0; } std::vector<EQEmu::Any> *extra_pointers) { return 0; }
virtual int DispatchEventPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data, virtual int DispatchEventPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { return 0; } std::vector<EQEmu::Any> *extra_pointers) { return 0; }
virtual int DispatchEventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data, virtual int DispatchEventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { return 0; } std::vector<EQEmu::Any> *extra_pointers) { return 0; }
virtual int DispatchEventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, virtual int DispatchEventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data,
std::vector<void*> *extra_pointers) { return 0; } std::vector<EQEmu::Any> *extra_pointers) { return 0; }
virtual void AddVar(std::string name, std::string val) { } virtual void AddVar(std::string name, std::string val) { }
virtual std::string GetVar(std::string name) { return std::string(); } virtual std::string GetVar(std::string name) { return std::string(); }

View File

@ -234,7 +234,7 @@ bool QuestParserCollection::ItemHasQuestSub(ItemInst *itm, QuestEventID evt) {
} }
int QuestParserCollection::EventNPC(QuestEventID evt, NPC *npc, Mob *init, std::string data, uint32 extra_data, int QuestParserCollection::EventNPC(QuestEventID evt, NPC *npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
int rd = DispatchEventNPC(evt, npc, init, data, extra_data, extra_pointers); int rd = DispatchEventNPC(evt, npc, init, data, extra_data, extra_pointers);
int rl = EventNPCLocal(evt, npc, init, data, extra_data, extra_pointers); int rl = EventNPCLocal(evt, npc, init, data, extra_data, extra_pointers);
int rg = EventNPCGlobal(evt, npc, init, data, extra_data, extra_pointers); int rg = EventNPCGlobal(evt, npc, init, data, extra_data, extra_pointers);
@ -252,7 +252,7 @@ int QuestParserCollection::EventNPC(QuestEventID evt, NPC *npc, Mob *init, std::
} }
int QuestParserCollection::EventNPCLocal(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, int QuestParserCollection::EventNPCLocal(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
std::map<uint32, uint32>::iterator iter = _npc_quest_status.find(npc->GetNPCTypeID()); std::map<uint32, uint32>::iterator iter = _npc_quest_status.find(npc->GetNPCTypeID());
if(iter != _npc_quest_status.end()) { if(iter != _npc_quest_status.end()) {
//loaded or failed to load //loaded or failed to load
@ -275,7 +275,7 @@ int QuestParserCollection::EventNPCLocal(QuestEventID evt, NPC* npc, Mob *init,
} }
int QuestParserCollection::EventNPCGlobal(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, int QuestParserCollection::EventNPCGlobal(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
if(_global_npc_quest_status != QuestUnloaded && _global_npc_quest_status != QuestFailedToLoad) { if(_global_npc_quest_status != QuestUnloaded && _global_npc_quest_status != QuestFailedToLoad) {
std::map<uint32, QuestInterface*>::iterator qiter = _interfaces.find(_global_npc_quest_status); std::map<uint32, QuestInterface*>::iterator qiter = _interfaces.find(_global_npc_quest_status);
return qiter->second->EventGlobalNPC(evt, npc, init, data, extra_data, extra_pointers); return qiter->second->EventGlobalNPC(evt, npc, init, data, extra_data, extra_pointers);
@ -294,7 +294,7 @@ int QuestParserCollection::EventNPCGlobal(QuestEventID evt, NPC* npc, Mob *init,
} }
int QuestParserCollection::EventPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data, int QuestParserCollection::EventPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
int rd = DispatchEventPlayer(evt, client, data, extra_data, extra_pointers); int rd = DispatchEventPlayer(evt, client, data, extra_data, extra_pointers);
int rl = EventPlayerLocal(evt, client, data, extra_data, extra_pointers); int rl = EventPlayerLocal(evt, client, data, extra_data, extra_pointers);
int rg = EventPlayerGlobal(evt, client, data, extra_data, extra_pointers); int rg = EventPlayerGlobal(evt, client, data, extra_data, extra_pointers);
@ -312,7 +312,7 @@ int QuestParserCollection::EventPlayer(QuestEventID evt, Client *client, std::st
} }
int QuestParserCollection::EventPlayerLocal(QuestEventID evt, Client *client, std::string data, uint32 extra_data, int QuestParserCollection::EventPlayerLocal(QuestEventID evt, Client *client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
if(_player_quest_status == QuestUnloaded) { if(_player_quest_status == QuestUnloaded) {
std::string filename; std::string filename;
QuestInterface *qi = GetQIByPlayerQuest(filename); QuestInterface *qi = GetQIByPlayerQuest(filename);
@ -331,7 +331,7 @@ int QuestParserCollection::EventPlayerLocal(QuestEventID evt, Client *client, st
} }
int QuestParserCollection::EventPlayerGlobal(QuestEventID evt, Client *client, std::string data, uint32 extra_data, int QuestParserCollection::EventPlayerGlobal(QuestEventID evt, Client *client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
if(_global_player_quest_status == QuestUnloaded) { if(_global_player_quest_status == QuestUnloaded) {
std::string filename; std::string filename;
QuestInterface *qi = GetQIByGlobalPlayerQuest(filename); QuestInterface *qi = GetQIByGlobalPlayerQuest(filename);
@ -350,7 +350,7 @@ int QuestParserCollection::EventPlayerGlobal(QuestEventID evt, Client *client, s
} }
int QuestParserCollection::EventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data, int QuestParserCollection::EventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
std::string item_script; std::string item_script;
if(item->GetItem()->ScriptFileID != 0) { if(item->GetItem()->ScriptFileID != 0) {
item_script = "script_"; item_script = "script_";
@ -396,7 +396,7 @@ int QuestParserCollection::EventItem(QuestEventID evt, Client *client, ItemInst
} }
int QuestParserCollection::EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, int QuestParserCollection::EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
std::map<uint32, uint32>::iterator iter = _spell_quest_status.find(spell_id); std::map<uint32, uint32>::iterator iter = _spell_quest_status.find(spell_id);
if(iter != _spell_quest_status.end()) { if(iter != _spell_quest_status.end()) {
//loaded or failed to load //loaded or failed to load
@ -431,7 +431,7 @@ int QuestParserCollection::EventSpell(QuestEventID evt, NPC* npc, Client *client
} }
int QuestParserCollection::EventEncounter(QuestEventID evt, std::string encounter_name, uint32 extra_data, int QuestParserCollection::EventEncounter(QuestEventID evt, std::string encounter_name, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
auto iter = _encounter_quest_status.find(encounter_name); auto iter = _encounter_quest_status.find(encounter_name);
if(iter != _encounter_quest_status.end()) { if(iter != _encounter_quest_status.end()) {
//loaded or failed to load //loaded or failed to load
@ -600,8 +600,7 @@ QuestInterface *QuestParserCollection::GetQIByNPCQuest(uint32 npcid, std::string
} }
QuestInterface *QuestParserCollection::GetQIByPlayerQuest(std::string &filename) { QuestInterface *QuestParserCollection::GetQIByPlayerQuest(std::string &filename) {
if(!zone || !zone->IsLoaded())
if(!zone)
return nullptr; return nullptr;
//first look for /quests/zone/player_v[instance_version].ext (precedence) //first look for /quests/zone/player_v[instance_version].ext (precedence)
@ -975,7 +974,7 @@ void QuestParserCollection::GetErrors(std::list<std::string> &err) {
} }
int QuestParserCollection::DispatchEventNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, int QuestParserCollection::DispatchEventNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
int ret = 0; int ret = 0;
auto iter = _load_precedence.begin(); auto iter = _load_precedence.begin();
while(iter != _load_precedence.end()) { while(iter != _load_precedence.end()) {
@ -989,7 +988,7 @@ int QuestParserCollection::DispatchEventNPC(QuestEventID evt, NPC* npc, Mob *ini
} }
int QuestParserCollection::DispatchEventPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data, int QuestParserCollection::DispatchEventPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
int ret = 0; int ret = 0;
auto iter = _load_precedence.begin(); auto iter = _load_precedence.begin();
while(iter != _load_precedence.end()) { while(iter != _load_precedence.end()) {
@ -1003,7 +1002,7 @@ int QuestParserCollection::DispatchEventPlayer(QuestEventID evt, Client *client,
} }
int QuestParserCollection::DispatchEventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, int QuestParserCollection::DispatchEventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data,
uint32 extra_data, std::vector<void*> *extra_pointers) { uint32 extra_data, std::vector<EQEmu::Any> *extra_pointers) {
int ret = 0; int ret = 0;
auto iter = _load_precedence.begin(); auto iter = _load_precedence.begin();
while(iter != _load_precedence.end()) { while(iter != _load_precedence.end()) {
@ -1017,7 +1016,7 @@ int QuestParserCollection::DispatchEventItem(QuestEventID evt, Client *client, I
} }
int QuestParserCollection::DispatchEventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, int QuestParserCollection::DispatchEventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data,
std::vector<void*> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
int ret = 0; int ret = 0;
auto iter = _load_precedence.begin(); auto iter = _load_precedence.begin();
while(iter != _load_precedence.end()) { while(iter != _load_precedence.end()) {

View File

@ -51,15 +51,15 @@ public:
bool ItemHasQuestSub(ItemInst *itm, QuestEventID evt); bool ItemHasQuestSub(ItemInst *itm, QuestEventID evt);
int EventNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, int EventNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers = nullptr); std::vector<EQEmu::Any> *extra_pointers = nullptr);
int EventPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data, int EventPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers = nullptr); std::vector<EQEmu::Any> *extra_pointers = nullptr);
int EventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data, int EventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers = nullptr); std::vector<EQEmu::Any> *extra_pointers = nullptr);
int EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, int EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data,
std::vector<void*> *extra_pointers = nullptr); std::vector<EQEmu::Any> *extra_pointers = nullptr);
int EventEncounter(QuestEventID evt, std::string encounter_name, uint32 extra_data, int EventEncounter(QuestEventID evt, std::string encounter_name, uint32 extra_data,
std::vector<void*> *extra_pointers = nullptr); std::vector<EQEmu::Any> *extra_pointers = nullptr);
void GetErrors(std::list<std::string> &err); void GetErrors(std::list<std::string> &err);
@ -69,10 +69,10 @@ private:
bool PlayerHasQuestSubLocal(QuestEventID evt); bool PlayerHasQuestSubLocal(QuestEventID evt);
bool PlayerHasQuestSubGlobal(QuestEventID evt); bool PlayerHasQuestSubGlobal(QuestEventID evt);
int EventNPCLocal(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector<void*> *extra_pointers); int EventNPCLocal(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector<EQEmu::Any> *extra_pointers);
int EventNPCGlobal(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector<void*> *extra_pointers); int EventNPCGlobal(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector<EQEmu::Any> *extra_pointers);
int EventPlayerLocal(QuestEventID evt, Client *client, std::string data, uint32 extra_data, std::vector<void*> *extra_pointers); int EventPlayerLocal(QuestEventID evt, Client *client, std::string data, uint32 extra_data, std::vector<EQEmu::Any> *extra_pointers);
int EventPlayerGlobal(QuestEventID evt, Client *client, std::string data, uint32 extra_data, std::vector<void*> *extra_pointers); int EventPlayerGlobal(QuestEventID evt, Client *client, std::string data, uint32 extra_data, std::vector<EQEmu::Any> *extra_pointers);
QuestInterface *GetQIByNPCQuest(uint32 npcid, std::string &filename); QuestInterface *GetQIByNPCQuest(uint32 npcid, std::string &filename);
QuestInterface *GetQIByGlobalNPCQuest(std::string &filename); QuestInterface *GetQIByGlobalNPCQuest(std::string &filename);
@ -83,13 +83,13 @@ private:
QuestInterface *GetQIByEncounterQuest(std::string encounter_name, std::string &filename); QuestInterface *GetQIByEncounterQuest(std::string encounter_name, std::string &filename);
int DispatchEventNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, int DispatchEventNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
int DispatchEventPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data, int DispatchEventPlayer(QuestEventID evt, Client *client, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
int DispatchEventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data, int DispatchEventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
int DispatchEventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, int DispatchEventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data,
std::vector<void*> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
std::map<uint32, QuestInterface*> _interfaces; std::map<uint32, QuestInterface*> _interfaces;
std::map<uint32, std::string> _extensions; std::map<uint32, std::string> _extensions;

View File

@ -75,12 +75,12 @@ And then at then end of embparser.cpp, add:
#include "../common/rulesys.h" #include "../common/rulesys.h"
#include "qglobals.h" #include "qglobals.h"
#include "quest_parser_collection.h" #include "quest_parser_collection.h"
#include "queryserv.h"
#ifdef BOTS #ifdef BOTS
#include "bot.h" #include "bot.h"
#endif #endif
extern QueryServ* QServ;
extern Zone* zone; extern Zone* zone;
extern WorldServer worldserver; extern WorldServer worldserver;
extern EntityList entity_list; extern EntityList entity_list;
@ -173,7 +173,6 @@ void QuestManager::EndQuest() {
else else
++cur; ++cur;
} }
run.owner->Depop(); run.owner->Depop();
} }
quests_running_.pop(); quests_running_.pop();
@ -1306,21 +1305,17 @@ void QuestManager::setglobal(const char *varname, const char *newvalue, int opti
6 this all all 6 this all all
7 all all all 7 all all all
*/ */
if (initiator && initiator->IsClient()) // some events like waypoint and spawn don't have a player involved
{ if (initiator && initiator->IsClient()){ // some events like waypoint and spawn don't have a player involved
qgCharid=initiator->CharacterID(); qgCharid=initiator->CharacterID();
} }
else {
else
{
qgCharid=-qgNpcid; // make char id negative npc id as a fudge qgCharid=-qgNpcid; // make char id negative npc id as a fudge
} }
if (options < 0 || options > 7) if (options < 0 || options > 7) {
{
std::cerr << "Invalid options for global var " << varname << " using defaults" << std::endl; std::cerr << "Invalid options for global var " << varname << " using defaults" << std::endl;
} // default = 0 (only this npcid,player and zone) } // default = 0 (only this npcid,player and zone)
else else {
{
if (options & 1) if (options & 1)
qgNpcid=0; qgNpcid=0;
if (options & 2) if (options & 2)
@ -1330,30 +1325,32 @@ void QuestManager::setglobal(const char *varname, const char *newvalue, int opti
} }
InsertQuestGlobal(qgCharid, qgNpcid, qgZoneid, varname, newvalue, QGVarDuration(duration)); InsertQuestGlobal(qgCharid, qgNpcid, qgZoneid, varname, newvalue, QGVarDuration(duration));
/* QS: PlayerLogQGlobalUpdate */
if (RuleB(QueryServ, PlayerLogQGlobalUpdate) && qgCharid && qgCharid > 0 && initiator && initiator->IsClient()){
std::string event_desc = StringFormat("Update :: qglobal:%s to qvalue:%s zoneid:%i instid:%i", varname, newvalue, initiator->GetZoneID(), initiator->GetInstanceID());
QServ->PlayerLogEvent(Player_Log_QGlobal_Update, qgCharid, event_desc);
}
} }
/* Inserts global variable into quest_globals table */ /* Inserts global variable into quest_globals table */
int QuestManager::InsertQuestGlobal( int QuestManager::InsertQuestGlobal(int charid, int npcid, int zoneid, const char *varname, const char *varvalue, int duration) {
int charid, int npcid, int zoneid,
const char *varname, const char *varvalue,
int duration)
{
char *query = 0; char *query = 0;
char errbuf[MYSQL_ERRMSG_SIZE]; char errbuf[MYSQL_ERRMSG_SIZE];
// Make duration string either "unix_timestamp(now()) + xxx" or "NULL" // Make duration string either "unix_timestamp(now()) + xxx" or "NULL"
std::stringstream duration_ss; std::stringstream duration_ss;
if (duration == INT_MAX) if (duration == INT_MAX) {
{
duration_ss << "NULL"; duration_ss << "NULL";
} }
else else {
{
duration_ss << "unix_timestamp(now()) + " << duration; duration_ss << "unix_timestamp(now()) + " << duration;
} }
//NOTE: this should be escaping the contents of arglist /*
//npcwise a malicious script can arbitrarily alter the DB NOTE: this should be escaping the contents of arglist
npcwise a malicious script can arbitrarily alter the DB
*/
uint32 last_id = 0; uint32 last_id = 0;
if (!database.RunQuery(query, MakeAnyLenString(&query, if (!database.RunQuery(query, MakeAnyLenString(&query,
"REPLACE INTO quest_globals (charid, npcid, zoneid, name, value, expdate)" "REPLACE INTO quest_globals (charid, npcid, zoneid, name, value, expdate)"
@ -1365,9 +1362,8 @@ int QuestManager::InsertQuestGlobal(
} }
safe_delete_array(query); safe_delete_array(query);
if(zone) if(zone) {
{ /* Delete existing qglobal data and update zone processes */
//first delete our global
ServerPacket* pack = new ServerPacket(ServerOP_QGlobalDelete, sizeof(ServerQGlobalDelete_Struct)); ServerPacket* pack = new ServerPacket(ServerOP_QGlobalDelete, sizeof(ServerQGlobalDelete_Struct));
ServerQGlobalDelete_Struct *qgd = (ServerQGlobalDelete_Struct*)pack->pBuffer; ServerQGlobalDelete_Struct *qgd = (ServerQGlobalDelete_Struct*)pack->pBuffer;
qgd->npc_id = npcid; qgd->npc_id = npcid;
@ -1383,18 +1379,16 @@ int QuestManager::InsertQuestGlobal(
worldserver.SendPacket(pack); worldserver.SendPacket(pack);
safe_delete(pack); safe_delete(pack);
//then create a new one with the new id /* Create new qglobal data and update zone processes */
pack = new ServerPacket(ServerOP_QGlobalUpdate, sizeof(ServerQGlobalUpdate_Struct)); pack = new ServerPacket(ServerOP_QGlobalUpdate, sizeof(ServerQGlobalUpdate_Struct));
ServerQGlobalUpdate_Struct *qgu = (ServerQGlobalUpdate_Struct*)pack->pBuffer; ServerQGlobalUpdate_Struct *qgu = (ServerQGlobalUpdate_Struct*)pack->pBuffer;
qgu->npc_id = npcid; qgu->npc_id = npcid;
qgu->char_id = charid; qgu->char_id = charid;
qgu->zone_id = zoneid; qgu->zone_id = zoneid;
if(duration == INT_MAX) if(duration == INT_MAX) {
{
qgu->expdate = 0xFFFFFFFF; qgu->expdate = 0xFFFFFFFF;
} }
else else {
{
qgu->expdate = Timer::GetTimeSeconds() + duration; qgu->expdate = Timer::GetTimeSeconds() + duration;
} }
strcpy((char*)qgu->name, varname); strcpy((char*)qgu->name, varname);
@ -1420,8 +1414,7 @@ int QuestManager::InsertQuestGlobal(
return 0; return 0;
} }
void QuestManager::targlobal(const char *varname, const char *value, const char *duration, int qgNpcid, int qgCharid, int qgZoneid) void QuestManager::targlobal(const char *varname, const char *value, const char *duration, int qgNpcid, int qgCharid, int qgZoneid) {
{
InsertQuestGlobal(qgCharid, qgNpcid, qgZoneid, varname, value, QGVarDuration(duration)); InsertQuestGlobal(qgCharid, qgNpcid, qgZoneid, varname, value, QGVarDuration(duration));
} }
@ -1432,15 +1425,24 @@ void QuestManager::delglobal(const char *varname) {
int qgZoneid=zone->GetZoneID(); int qgZoneid=zone->GetZoneID();
int qgCharid=0; int qgCharid=0;
int qgNpcid=owner->GetNPCTypeID(); int qgNpcid=owner->GetNPCTypeID();
if (initiator && initiator->IsClient()) // some events like waypoint and spawn don't have a player involved if (initiator && initiator->IsClient()) // some events like waypoint and spawn don't have a player involved
{ {
qgCharid=initiator->CharacterID(); qgCharid=initiator->CharacterID();
} }
else else {
{
qgCharid=-qgNpcid; // make char id negative npc id as a fudge qgCharid=-qgNpcid; // make char id negative npc id as a fudge
} }
/* QS: PlayerLogQGlobalUpdate */
if (RuleB(QueryServ, PlayerLogQGlobalUpdate) && qgCharid && qgCharid > 0 && initiator && initiator->IsClient()){
std::string event_desc = StringFormat("Deleted :: qglobal:%s zoneid:%i instid:%i", varname, initiator->GetZoneID(), initiator->GetInstanceID());
QServ->PlayerLogEvent(Player_Log_QGlobal_Update, qgCharid, event_desc);
}
if (!database.RunQuery(query, if (!database.RunQuery(query,
MakeAnyLenString(&query, MakeAnyLenString(&query,
"DELETE FROM quest_globals WHERE name='%s'" "DELETE FROM quest_globals WHERE name='%s'"
@ -1451,8 +1453,7 @@ void QuestManager::delglobal(const char *varname) {
} }
safe_delete_array(query); safe_delete_array(query);
if(zone) if(zone) {
{
ServerPacket* pack = new ServerPacket(ServerOP_QGlobalDelete, sizeof(ServerQGlobalDelete_Struct)); ServerPacket* pack = new ServerPacket(ServerOP_QGlobalDelete, sizeof(ServerQGlobalDelete_Struct));
ServerQGlobalDelete_Struct *qgu = (ServerQGlobalDelete_Struct*)pack->pBuffer; ServerQGlobalDelete_Struct *qgu = (ServerQGlobalDelete_Struct*)pack->pBuffer;
@ -1701,17 +1702,14 @@ void QuestManager::showgrid(int grid) {
pts.push_back(pt); pts.push_back(pt);
// Retrieve all waypoints for this grid // 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)) 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))) {
while((row = mysql_fetch_row(result)))
{
pt.x = atof(row[0]); pt.x = atof(row[0]);
pt.y = atof(row[1]); pt.y = atof(row[1]);
pt.z = atof(row[2]); pt.z = atof(row[2]);
pts.push_back(pt); pts.push_back(pt);
} }
mysql_free_result(result); mysql_free_result(result);
initiator->SendPathPacket(pts); initiator->SendPathPacket(pts);
} }
else // DB query error! else // DB query error!

View File

@ -354,97 +354,87 @@ void Spawn2::DeathReset(bool realdeath)
} }
bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList<Spawn2*> &spawn2_list, int16 version, uint32 repopdelay) { bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList<Spawn2*> &spawn2_list, int16 version, uint32 repopdelay) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
const char *zone_name = database.GetZoneName(zoneid); const char *zone_name = database.GetZoneName(zoneid);
std::string query = StringFormat("SELECT id, spawngroupID, x, y, z, heading, "
"respawntime, variance, pathgrid, _condition, "
"cond_value, enabled, animation FROM spawn2 "
"WHERE zone = '%s' AND version = %u",
zone_name, version);
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in PopulateZoneLists query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return false;
}
MakeAnyLenString(&query, "SELECT id, spawngroupID, x, y, z, heading, respawntime, variance, pathgrid, _condition, cond_value, enabled, animation FROM spawn2 WHERE zone='%s' AND version=%u", zone_name, version); for (auto row = results.begin(); row != results.end(); ++row) {
if (RunQuery(query, strlen(query), errbuf, &result))
{
safe_delete_array(query);
while((row = mysql_fetch_row(result)))
{
Spawn2* newSpawn = 0; Spawn2* newSpawn = 0;
bool perl_enabled = atoi(row[11]) == 1? true: false; bool perl_enabled = atoi(row[11]) == 1? true: false;
uint32 spawnLeft = (GetSpawnTimeLeft(atoi(row[0]), zone->GetInstanceID()) * 1000); uint32 spawnLeft = (GetSpawnTimeLeft(atoi(row[0]), zone->GetInstanceID()) * 1000);
newSpawn = new Spawn2(atoi(row[0]), atoi(row[1]), atof(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atoi(row[6]), atoi(row[7]), spawnLeft, atoi(row[8]), atoi(row[9]), atoi(row[10]), perl_enabled, (EmuAppearance)atoi(row[12])); newSpawn = new Spawn2(atoi(row[0]), atoi(row[1]), atof(row[2]), atof(row[3]), atof(row[4]),
atof(row[5]), atoi(row[6]), atoi(row[7]), spawnLeft, atoi(row[8]),
atoi(row[9]), atoi(row[10]), perl_enabled, (EmuAppearance)atoi(row[12]));
spawn2_list.Insert(newSpawn); spawn2_list.Insert(newSpawn);
} }
mysql_free_result(result);
}
else
{
LogFile->write(EQEMuLog::Error, "Error in PopulateZoneLists query '%s': %s", query, errbuf);
safe_delete_array(query);
return false;
}
return true; return true;
} }
Spawn2* ZoneDatabase::LoadSpawn2(LinkedList<Spawn2*> &spawn2_list, uint32 spawn2id, uint32 timeleft) { Spawn2* ZoneDatabase::LoadSpawn2(LinkedList<Spawn2*> &spawn2_list, uint32 spawn2id, uint32 timeleft) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id, spawngroupID, x, y, z, heading, respawntime, variance, pathgrid, _condition, cond_value, enabled, animation FROM spawn2 WHERE id=%i", spawn2id), errbuf, &result)) { std::string query = StringFormat("SELECT id, spawngroupID, x, y, z, heading, "
if (mysql_num_rows(result) == 1) "respawntime, variance, pathgrid, _condition, "
{ "cond_value, enabled, animation FROM spawn2 "
row = mysql_fetch_row(result); "WHERE id = %i", spawn2id);
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in LoadSpawn2 query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return nullptr;
}
if (results.RowCount() != 1) {
LogFile->write(EQEMuLog::Error, "Error in LoadSpawn2 query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return nullptr;
}
auto row = results.begin();
bool perl_enabled = atoi(row[11]) == 1 ? true : false; bool perl_enabled = atoi(row[11]) == 1 ? true : false;
Spawn2* newSpawn = new Spawn2(atoi(row[0]), atoi(row[1]), atof(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atoi(row[6]), atoi(row[7]), timeleft, atoi(row[8]), atoi(row[9]), atoi(row[10]), perl_enabled, (EmuAppearance)atoi(row[12]));
Spawn2* newSpawn = new Spawn2(atoi(row[0]), atoi(row[1]), atof(row[2]), atof(row[3]), atof(row[4]),
atof(row[5]), atoi(row[6]), atoi(row[7]), timeleft, atoi(row[8]),
atoi(row[9]), atoi(row[10]), perl_enabled, (EmuAppearance)atoi(row[12]));
spawn2_list.Insert(newSpawn); spawn2_list.Insert(newSpawn);
mysql_free_result(result);
safe_delete_array(query);
return newSpawn; return newSpawn;
} }
mysql_free_result(result);
}
LogFile->write(EQEMuLog::Error, "Error in LoadSpawn2 query '%s': %s", query, errbuf); bool ZoneDatabase::CreateSpawn2(Client *client, uint32 spawngroup, const char* zone, float heading, float x, float y, float z, uint32 respawn, uint32 variance, uint16 condition, int16 cond_value)
safe_delete_array(query);
return 0;
}
bool ZoneDatabase::CreateSpawn2(Client *c, uint32 spawngroup, const char* zone, float heading, float x, float y, float z, uint32 respawn, uint32 variance, uint16 condition, int16 cond_value)
{ {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0; std::string query = StringFormat("INSERT INTO spawn2 (spawngroupID, zone, x, y, z, heading, "
uint32 affected_rows = 0; "respawntime, variance, _condition, cond_value) "
"VALUES (%i, '%s', %f, %f, %f, %f, %i, %i, %u, %i)",
spawngroup, zone, x, y, z, heading,
respawn, variance, condition, cond_value);
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in CreateSpawn2 query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return false;
}
if (results.RowsAffected() != 1)
return false;
if(client)
client->LogSQL(query.c_str());
// if(GetInverseXY()==1) {
// float temp=x;
// x=y;
// y=temp;
// }
if (RunQuery(query, MakeAnyLenString(&query,
"INSERT INTO spawn2 (spawngroupID,zone,x,y,z,heading,respawntime,variance,_condition,cond_value) Values (%i, '%s', %f, %f, %f, %f, %i, %i, %u, %i)",
spawngroup, zone, x, y, z, heading, respawn, variance, condition, cond_value
), errbuf, 0, &affected_rows)) {
safe_delete_array(query);
if (affected_rows == 1) {
if(c) c->LogSQL(query);
return true; return true;
} }
else {
return false;
}
}
else {
LogFile->write(EQEMuLog::Error, "Error in CreateSpawn2 query '%s': %s", query, errbuf);
safe_delete_array(query);
return false;
}
return false;
}
uint32 Zone::CountSpawn2() { uint32 Zone::CountSpawn2() {
LinkedListIterator<Spawn2*> iterator(spawn2_list); LinkedListIterator<Spawn2*> iterator(spawn2_list);
@ -671,56 +661,52 @@ void SpawnConditionManager::ExecEvent(SpawnEvent &event, bool send_update) {
} }
void SpawnConditionManager::UpdateDBEvent(SpawnEvent &event) { void SpawnConditionManager::UpdateDBEvent(SpawnEvent &event) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
int len;
SpawnCondition cond; std::string query = StringFormat("UPDATE spawn_events SET "
len = MakeAnyLenString(&query, "next_minute = %d, next_hour = %d, "
"UPDATE spawn_events SET " "next_day = %d, next_month = %d, "
"next_minute=%d, next_hour=%d, next_day=%d, next_month=%d, " "next_year = %d, enabled = %d, "
"next_year=%d, enabled=%d, strict=%d " "strict = %d WHERE id = %d",
"WHERE id=%d", event.next.minute, event.next.hour,
event.next.minute, event.next.hour, event.next.day, event.next.month, event.next.day, event.next.month,
event.next.year, event.enabled?1:0, event.strict?1:0,event.id event.next.year, event.enabled? 1: 0,
); event.strict? 1: 0, event.id);
if(!database.RunQuery(query, len, errbuf)) { auto results = database.QueryDatabase(query);
LogFile->write(EQEMuLog::Error, "Unable to update spawn event '%s': %s\n", query, errbuf); if(!results.Success())
} LogFile->write(EQEMuLog::Error, "Unable to update spawn event '%s': %s\n", query.c_str(), results.ErrorMessage().c_str());
safe_delete_array(query);
} }
void SpawnConditionManager::UpdateDBCondition(const char* zone_name, uint32 instance_id, uint16 cond_id, int16 value) { void SpawnConditionManager::UpdateDBCondition(const char* zone_name, uint32 instance_id, uint16 cond_id, int16 value) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
int len;
SpawnCondition cond; std::string query = StringFormat("REPLACE INTO spawn_condition_values "
len = MakeAnyLenString(&query, "(id, value, zone, instance_id) "
"REPLACE INTO spawn_condition_values (id, value, zone, instance_id) VALUES(%u, %u, '%s', %u)", "VALUES( %u, %u, '%s', %u)",
cond_id, value, zone_name, instance_id cond_id, value, zone_name, instance_id);
); auto results = database.QueryDatabase(query);
if(!database.RunQuery(query, len, errbuf)) { if(!results.Success())
LogFile->write(EQEMuLog::Error, "Unable to update spawn condition '%s': %s\n", query, errbuf); LogFile->write(EQEMuLog::Error, "Unable to update spawn condition '%s': %s\n", query.c_str(), results.ErrorMessage().c_str());
}
safe_delete_array(query);
} }
bool SpawnConditionManager::LoadDBEvent(uint32 event_id, SpawnEvent &event, std::string &zone_name) { bool SpawnConditionManager::LoadDBEvent(uint32 event_id, SpawnEvent &event, std::string &zone_name) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
int len;
bool ret = false; std::string query = StringFormat("SELECT id, cond_id, period, "
"next_minute, next_hour, next_day, "
len = MakeAnyLenString(&query, "next_month, next_year, enabled, "
"SELECT id,cond_id,period,next_minute,next_hour,next_day,next_month,next_year,enabled,action,argument,strict,zone " "action, argument, strict, zone "
"FROM spawn_events WHERE id = %d", event_id); "FROM spawn_events WHERE id = %d", event_id);
if (database.RunQuery(query, len, errbuf, &result)) { auto results = database.QueryDatabase(query);
safe_delete_array(query); if (!results.Success()) {
if((row = mysql_fetch_row(result))) { LogFile->write(EQEMuLog::Error, "Error in LoadDBEvent query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return false;
}
if (results.RowCount() == 0)
return false;
auto row = results.begin();
event.id = atoi(row[0]); event.id = atoi(row[0]);
event.condition_id = atoi(row[1]); event.condition_id = atoi(row[1]);
event.period = atoi(row[2]); event.period = atoi(row[2]);
@ -731,44 +717,40 @@ bool SpawnConditionManager::LoadDBEvent(uint32 event_id, SpawnEvent &event, std:
event.next.month = atoi(row[6]); event.next.month = atoi(row[6]);
event.next.year = atoi(row[7]); event.next.year = atoi(row[7]);
event.enabled = atoi(row[8])==0?false:true; event.enabled = atoi(row[8]) != 0;
event.action = (SpawnEvent::Action) atoi(row[9]); event.action = (SpawnEvent::Action) atoi(row[9]);
event.argument = atoi(row[10]); event.argument = atoi(row[10]);
event.strict = atoi(row[11])==0?false:true; event.strict = atoi(row[11]) != 0;
zone_name = row[12]; zone_name = row[12];
std::string t; std::string timeAsString;
EQTime::ToString(&event.next, t); EQTime::ToString(&event.next, timeAsString);
_log(SPAWNS__CONDITIONS, "(LoadDBEvent) Loaded %s spawn event %d on condition %d with period %d, action %d, argument %d, strict %d. Will trigger at %s",
event.enabled?"enabled":"disabled", event.id, event.condition_id, event.period, event.action, event.argument, event.strict, t.c_str());
ret = true; _log(SPAWNS__CONDITIONS, "(LoadDBEvent) Loaded %s spawn event %d on condition %d with period %d, action %d, argument %d, strict %d. Will trigger at %s", event.enabled? "enabled": "disabled", event.id, event.condition_id, event.period, event.action, event.argument, event.strict, timeAsString.c_str());
}
mysql_free_result(result); return true;
} else {
LogFile->write(EQEMuLog::Error, "Error in LoadDBEvent query '%s': %s", query, errbuf);
safe_delete_array(query);
}
return(ret);
} }
bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 instance_id) bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 instance_id)
{ {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
int len;
//clear out old stuff.. //clear out old stuff..
spawn_conditions.clear(); spawn_conditions.clear();
std::string query = StringFormat("SELECT id, onchange, value "
"FROM spawn_conditions "
"WHERE zone = '%s'", zone_name);
auto results = database.QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return false;
}
for (auto row = results.begin(); row != results.end(); ++row) {
//load spawn conditions //load spawn conditions
SpawnCondition cond; SpawnCondition cond;
len = MakeAnyLenString(&query, "SELECT id, onchange, value FROM spawn_conditions WHERE zone='%s'", zone_name);
if (database.RunQuery(query, len, errbuf, &result)) {
safe_delete_array(query);
while((row = mysql_fetch_row(result))) {
cond.condition_id = atoi(row[0]); cond.condition_id = atoi(row[0]);
cond.value = atoi(row[2]); cond.value = atoi(row[2]);
cond.on_change = (SpawnCondition::OnChange) atoi(row[1]); cond.on_change = (SpawnCondition::OnChange) atoi(row[1]);
@ -776,46 +758,42 @@ bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 in
_log(SPAWNS__CONDITIONS, "Loaded spawn condition %d with value %d and on_change %d", cond.condition_id, cond.value, cond.on_change); _log(SPAWNS__CONDITIONS, "Loaded spawn condition %d with value %d and on_change %d", cond.condition_id, cond.value, cond.on_change);
} }
mysql_free_result(result);
} else {
LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions query '%s': %s", query, errbuf);
safe_delete_array(query);
return false;
}
//load values //load values
len = MakeAnyLenString(&query, "SELECT id, value FROM spawn_condition_values WHERE zone='%s' and instance_id=%u", zone_name, instance_id); query = StringFormat("SELECT id, value FROM spawn_condition_values "
if (database.RunQuery(query, len, errbuf, &result)) { "WHERE zone = '%s' AND instance_id = %u",
safe_delete_array(query); zone_name, instance_id);
while((row = mysql_fetch_row(result))) results = database.QueryDatabase(query);
{ if (!results.Success()) {
std::map<uint16, SpawnCondition>::iterator iter = spawn_conditions.find(atoi(row[0])); LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
if(iter != spawn_conditions.end())
{
iter->second.value = atoi(row[1]);
}
}
mysql_free_result(result);
}
else
{
LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions query '%s': %s", query, errbuf);
safe_delete_array(query);
spawn_conditions.clear(); spawn_conditions.clear();
return false; return false;
} }
for (auto row = results.begin(); row != results.end(); ++row) {
auto iter = spawn_conditions.find(atoi(row[0]));
if(iter != spawn_conditions.end())
iter->second.value = atoi(row[1]);
}
//load spawn events //load spawn events
SpawnEvent event; query = StringFormat("SELECT id, cond_id, period, next_minute, next_hour, "
len = MakeAnyLenString(&query, "next_day, next_month, next_year, enabled, action, argument, strict "
"SELECT id,cond_id,period,next_minute,next_hour,next_day,next_month,next_year,enabled,action,argument,strict "
"FROM spawn_events WHERE zone = '%s'", zone_name); "FROM spawn_events WHERE zone = '%s'", zone_name);
if (database.RunQuery(query, len, errbuf, &result)) { results = database.QueryDatabase(query);
safe_delete_array(query); if (!results.Success()) {
while((row = mysql_fetch_row(result))) { LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions events query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return false;
}
for (auto row = results.begin(); row != results.end(); ++row) {
SpawnEvent event;
event.id = atoi(row[0]); event.id = atoi(row[0]);
event.condition_id = atoi(row[1]); event.condition_id = atoi(row[1]);
event.period = atoi(row[2]); event.period = atoi(row[2]);
if(event.period == 0) { if(event.period == 0) {
LogFile->write(EQEMuLog::Error, "Refusing to load spawn event #%d because it has a period of 0\n", event.id); LogFile->write(EQEMuLog::Error, "Refusing to load spawn event #%d because it has a period of 0\n", event.id);
continue; continue;
@ -831,16 +809,10 @@ bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 in
event.action = (SpawnEvent::Action) atoi(row[9]); event.action = (SpawnEvent::Action) atoi(row[9]);
event.argument = atoi(row[10]); event.argument = atoi(row[10]);
event.strict = atoi(row[11])==0?false:true; event.strict = atoi(row[11])==0?false:true;
spawn_events.push_back(event); spawn_events.push_back(event);
_log(SPAWNS__CONDITIONS, "(LoadSpawnConditions) Loaded %s spawn event %d on condition %d with period %d, action %d, argument %d, strict %d", _log(SPAWNS__CONDITIONS, "(LoadSpawnConditions) Loaded %s spawn event %d on condition %d with period %d, action %d, argument %d, strict %d", event.enabled? "enabled": "disabled", event.id, event.condition_id, event.period, event.action, event.argument, event.strict);
event.enabled?"enabled":"disabled", event.id, event.condition_id, event.period, event.action, event.argument, event.strict);
}
mysql_free_result(result);
} else {
LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions events query '%s': %s", query, errbuf);
safe_delete_array(query);
return false;
} }
//now we need to catch up on events that happened while we were away //now we need to catch up on events that happened while we were away
@ -855,11 +827,7 @@ bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 in
TimeOfDay_Struct tod; TimeOfDay_Struct tod;
zone->zone_time.getEQTimeOfDay(&tod); zone->zone_time.getEQTimeOfDay(&tod);
std::vector<SpawnEvent>::iterator cur,end; for(auto cur = spawn_events.begin(); cur != spawn_events.end(); ++cur) {
cur = spawn_events.begin();
end = spawn_events.end();
bool ran;
for(; cur != end; ++cur) {
SpawnEvent &cevent = *cur; SpawnEvent &cevent = *cur;
bool StrictCheck = false; bool StrictCheck = false;
@ -874,8 +842,9 @@ bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 in
if(!cevent.enabled || !StrictCheck) if(!cevent.enabled || !StrictCheck)
SetCondition(zone->GetShortName(), zone->GetInstanceID(),cevent.condition_id,0); SetCondition(zone->GetShortName(), zone->GetInstanceID(),cevent.condition_id,0);
if(cevent.enabled) if(!cevent.enabled)
{ continue;
//watch for special case of all 0s, which means to reset next to now //watch for special case of all 0s, which means to reset next to now
if(cevent.next.year == 0 && cevent.next.month == 0 && cevent.next.day == 0 && cevent.next.hour == 0 && cevent.next.minute == 0) { if(cevent.next.year == 0 && cevent.next.month == 0 && cevent.next.day == 0 && cevent.next.hour == 0 && cevent.next.minute == 0) {
_log(SPAWNS__CONDITIONS, "Initial next trigger time set for spawn event %d", cevent.id); _log(SPAWNS__CONDITIONS, "Initial next trigger time set for spawn event %d", cevent.id);
@ -887,7 +856,7 @@ bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 in
continue; //were done with this event. continue; //were done with this event.
} }
ran = false; bool ran = false;
while(EQTime::IsTimeBefore(&tod, &cevent.next)) { while(EQTime::IsTimeBefore(&tod, &cevent.next)) {
_log(SPAWNS__CONDITIONS, "Catch up triggering on event %d", cevent.id); _log(SPAWNS__CONDITIONS, "Catch up triggering on event %d", cevent.id);
//this event has been triggered. //this event has been triggered.
@ -899,18 +868,16 @@ bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 in
EQTime::AddMinutes(cevent.period, &cevent.next); EQTime::AddMinutes(cevent.period, &cevent.next);
ran = true; ran = true;
} }
//only write it out if the event actually ran //only write it out if the event actually ran
if(ran) { if(ran)
//save the event in the DB UpdateDBEvent(cevent); //save the event in the DB
UpdateDBEvent(cevent);
}
}
} }
//now our event timers are all up to date, find our closest event. //now our event timers are all up to date, find our closest event.
FindNearestEvent(); FindNearestEvent();
return(true); return true;
} }
void SpawnConditionManager::FindNearestEvent() { void SpawnConditionManager::FindNearestEvent() {
@ -1162,37 +1129,28 @@ int16 SpawnConditionManager::GetCondition(const char *zone_short, uint32 instanc
} }
SpawnCondition &cond = condi->second; SpawnCondition &cond = condi->second;
return(cond.value); return cond.value;
} else { }
//this is a remote spawn condition, grab it from the DB //this is a remote spawn condition, grab it from the DB
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
int len;
int16 value;
//load spawn conditions //load spawn conditions
SpawnCondition cond; std::string query = StringFormat("SELECT value FROM spawn_condition_values "
len = MakeAnyLenString(&query, "SELECT value FROM spawn_condition_values WHERE zone='%s' AND instance_id=%u AND id=%d", "WHERE zone = '%s' AND instance_id = %u AND id = %d",
zone_short, instance_id, condition_id); zone_short, instance_id, condition_id);
if (database.RunQuery(query, len, errbuf, &result)) { auto results = database.QueryDatabase(query);
safe_delete_array(query); if (!results.Success()) {
if((row = mysql_fetch_row(result))) {
value = atoi(row[0]);
} else {
_log(SPAWNS__CONDITIONS, "Unable to load remote condition %d from zone %s in Get request.", condition_id, zone_short);
value = 0; //dunno a better thing to do...
}
mysql_free_result(result);
} else {
_log(SPAWNS__CONDITIONS, "Unable to query remote condition %d from zone %s in Get request.", condition_id, zone_short); _log(SPAWNS__CONDITIONS, "Unable to query remote condition %d from zone %s in Get request.", condition_id, zone_short);
safe_delete_array(query); return 0; //dunno a better thing to do...
value = 0; //dunno a better thing to do...
} }
return(value);
if (results.RowCount() == 0) {
_log(SPAWNS__CONDITIONS, "Unable to load remote condition %d from zone %s in Get request.", condition_id, zone_short);
return 0; //dunno a better thing to do...
} }
auto row = results.begin();
return atoi(row[0]);
} }
bool SpawnConditionManager::Check(uint16 condition, int16 min_value) { bool SpawnConditionManager::Check(uint16 condition, int16 min_value) {

View File

@ -28,8 +28,7 @@
extern EntityList entity_list; extern EntityList entity_list;
SpawnEntry::SpawnEntry( uint32 in_NPCType, int in_chance, uint8 in_npc_spawn_limit ) SpawnEntry::SpawnEntry( uint32 in_NPCType, int in_chance, uint8 in_npc_spawn_limit ) {
{
NPCType = in_NPCType; NPCType = in_NPCType;
chance = in_chance; chance = in_chance;
npc_spawn_limit = in_npc_spawn_limit; npc_spawn_limit = in_npc_spawn_limit;
@ -57,7 +56,6 @@ uint32 SpawnGroup::GetNPCType() {
int npcType = 0; int npcType = 0;
int totalchance = 0; int totalchance = 0;
//check limits on this spawn group and npc type
if(!entity_list.LimitCheckGroup(id, group_spawn_limit)) if(!entity_list.LimitCheckGroup(id, group_spawn_limit))
return(0); return(0);
@ -68,7 +66,6 @@ uint32 SpawnGroup::GetNPCType() {
for(; cur != end; ++cur) { for(; cur != end; ++cur) {
SpawnEntry *se = *cur; SpawnEntry *se = *cur;
//check limits on this spawn group and npc type
if(!entity_list.LimitCheckType(se->NPCType, se->npc_spawn_limit)) if(!entity_list.LimitCheckType(se->NPCType, se->npc_spawn_limit))
continue; continue;
@ -93,7 +90,6 @@ uint32 SpawnGroup::GetNPCType() {
roll -= se->chance; roll -= se->chance;
} }
} }
//CODER implement random table
return npcType; return npcType;
} }
@ -144,106 +140,92 @@ bool SpawnGroupList::RemoveSpawnGroup(uint32 in_id) {
} }
bool ZoneDatabase::LoadSpawnGroups(const char* zone_name, uint16 version, SpawnGroupList* spawn_group_list) { bool ZoneDatabase::LoadSpawnGroups(const char* zone_name, uint16 version, SpawnGroupList* spawn_group_list) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
// CODER new spawn code std::string query = StringFormat("SELECT DISTINCT(spawngroupID), spawngroup.name, spawngroup.spawn_limit, "
query = 0; "spawngroup.dist, spawngroup.max_x, spawngroup.min_x, "
if (RunQuery(query, MakeAnyLenString(&query, "SELECT DISTINCT(spawngroupID), spawngroup.name, spawngroup.spawn_limit, spawngroup.dist, spawngroup.max_x, spawngroup.min_x, spawngroup.max_y, spawngroup.min_y, spawngroup.delay, spawngroup.despawn, spawngroup.despawn_timer, spawngroup.mindelay FROM spawn2,spawngroup WHERE spawn2.spawngroupID=spawngroup.ID and spawn2.version=%u and zone='%s'", version, zone_name), errbuf, &result)) "spawngroup.max_y, spawngroup.min_y, spawngroup.delay, "
{ "spawngroup.despawn, spawngroup.despawn_timer, spawngroup.mindelay "
safe_delete_array(query); "FROM spawn2, spawngroup WHERE spawn2.spawngroupID = spawngroup.ID "
while((row = mysql_fetch_row(result))) { "AND spawn2.version = %u and zone = '%s'", version, zone_name);
SpawnGroup* newSpawnGroup = new SpawnGroup( atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]), atoi(row[9]), atoi(row[10]), atoi(row[11])); auto results = QueryDatabase(query);
if (!results.Success()) {
_log(ZONE__SPAWNS, "Error2 in PopulateZoneLists query '%s' ", query.c_str());
return false;
}
for (auto row = results.begin(); row != results.end(); ++row) {
SpawnGroup* newSpawnGroup = new SpawnGroup(atoi(row[0]), row[1], atoi(row[2]), atof(row[3]),
atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]),
atoi(row[8]), atoi(row[9]), atoi(row[10]), atoi(row[11]));
spawn_group_list->AddSpawnGroup(newSpawnGroup); spawn_group_list->AddSpawnGroup(newSpawnGroup);
} }
mysql_free_result(result);
}
else
{
std::cerr << "Error2 in PopulateZoneLists query '" << query << "' " << errbuf << std::endl;
safe_delete_array(query);
return false;
}
query = 0; query = StringFormat("SELECT DISTINCT spawnentry.spawngroupID, npcid, chance, "
if (RunQuery(query, MakeAnyLenString(&query,
"SELECT DISTINCT spawnentry.spawngroupID, npcid, chance, "
"npc_types.spawn_limit AS sl " "npc_types.spawn_limit AS sl "
"FROM spawnentry, spawn2, npc_types " "FROM spawnentry, spawn2, npc_types "
"WHERE spawnentry.npcID=npc_types.id AND spawnentry.spawngroupID=spawn2.spawngroupID " "WHERE spawnentry.npcID=npc_types.id "
"AND zone='%s'", zone_name), errbuf, &result)) { "AND spawnentry.spawngroupID = spawn2.spawngroupID "
safe_delete_array(query); "AND zone = '%s'", zone_name);
while((row = mysql_fetch_row(result))) results = QueryDatabase(query);
{ if (!results.Success()) {
SpawnEntry* newSpawnEntry = new SpawnEntry( atoi(row[1]), atoi(row[2]), row[3]?atoi(row[3]):0); _log(ZONE__SPAWNS, "Error2 in PopulateZoneLists query '%'", query.c_str());
SpawnGroup *sg = spawn_group_list->GetSpawnGroup(atoi(row[0]));
if (sg)
sg->AddSpawnEntry(newSpawnEntry);
else
std::cout << "Error in SpawngroupID: " << row[0] << std::endl;
}
mysql_free_result(result);
}
else
{
std::cerr << "Error3 in PopulateZoneLists query '" << query << "' " << errbuf << std::endl;
safe_delete_array(query);
return false; return false;
} }
// CODER end new spawn code for (auto row = results.begin(); row != results.end(); ++row) {
SpawnEntry* newSpawnEntry = new SpawnEntry( atoi(row[1]), atoi(row[2]), row[3]?atoi(row[3]):0);
SpawnGroup *sg = spawn_group_list->GetSpawnGroup(atoi(row[0]));
if (!sg) {
_log(ZONE__SPAWNS, "Error in LoadSpawnGroups %s ", query.c_str());
continue;
}
sg->AddSpawnEntry(newSpawnEntry);
}
return true; return true;
} }
bool ZoneDatabase::LoadSpawnGroupsByID(int spawngroupid, SpawnGroupList* spawn_group_list) { bool ZoneDatabase::LoadSpawnGroupsByID(int spawngroupid, SpawnGroupList* spawn_group_list) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
// CODER new spawn code std::string query = StringFormat("SELECT DISTINCT(spawngroup.id), spawngroup.name, spawngroup.spawn_limit, "
query = 0; "spawngroup.dist, spawngroup.max_x, spawngroup.min_x, "
if (RunQuery(query, MakeAnyLenString(&query, "SELECT DISTINCT spawngroup.id, spawngroup.name, spawngroup.spawn_limit, spawngroup.dist, spawngroup.max_x, spawngroup.min_x, spawngroup.max_y, spawngroup.min_y, spawngroup.delay, spawngroup.despawn, spawngroup.despawn_timer, spawngroup.mindelay FROM spawngroup WHERE spawngroup.ID='%i'", spawngroupid), errbuf, &result)) "spawngroup.max_y, spawngroup.min_y, spawngroup.delay, "
{ "spawngroup.despawn, spawngroup.despawn_timer, spawngroup.mindelay "
safe_delete_array(query); "FROM spawngroup WHERE spawngroup.ID = '%i'", spawngroupid);
while((row = mysql_fetch_row(result))) { auto results = QueryDatabase(query);
if (!results.Success()) {
_log(ZONE__SPAWNS, "Error2 in PopulateZoneLists query %s", query.c_str());
return false;
}
for (auto row = results.begin(); row != results.end(); ++row) {
SpawnGroup* newSpawnGroup = new SpawnGroup(atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]), atoi(row[9]), atoi(row[10]), atoi(row[11])); SpawnGroup* newSpawnGroup = new SpawnGroup(atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]), atoi(row[9]), atoi(row[10]), atoi(row[11]));
spawn_group_list->AddSpawnGroup(newSpawnGroup); spawn_group_list->AddSpawnGroup(newSpawnGroup);
} }
mysql_free_result(result);
} query = StringFormat("SELECT DISTINCT(spawnentry.spawngroupID), spawnentry.npcid, "
else "spawnentry.chance, spawngroup.spawn_limit FROM spawnentry, spawngroup "
{ "WHERE spawnentry.spawngroupID = '%i' AND spawngroup.spawn_limit = '0' "
std::cerr << "Error2 in PopulateZoneLists query '" << query << "' " << errbuf << std::endl; "ORDER BY chance", spawngroupid);
safe_delete_array(query); results = QueryDatabase(query);
if (!results.Success()) {
_log(ZONE__SPAWNS, "Error3 in PopulateZoneLists query '%s'", query.c_str());
return false; return false;
} }
query = 0; for(auto row = results.begin(); row != results.end(); ++row) {
if (RunQuery(query, MakeAnyLenString(&query,
"SELECT DISTINCT spawnentry.spawngroupID, spawnentry.npcid, spawnentry.chance, spawngroup.spawn_limit FROM spawnentry,spawngroup WHERE spawnentry.spawngroupID='%i' AND spawngroup.spawn_limit='0' ORDER by chance", spawngroupid), errbuf, &result)) {
safe_delete_array(query);
while((row = mysql_fetch_row(result)))
{
SpawnEntry* newSpawnEntry = new SpawnEntry( atoi(row[1]), atoi(row[2]), row[3]?atoi(row[3]):0); SpawnEntry* newSpawnEntry = new SpawnEntry( atoi(row[1]), atoi(row[2]), row[3]?atoi(row[3]):0);
SpawnGroup *sg = spawn_group_list->GetSpawnGroup(atoi(row[0])); SpawnGroup *sg = spawn_group_list->GetSpawnGroup(atoi(row[0]));
if (sg) if (!sg) {
sg->AddSpawnEntry(newSpawnEntry); _log(ZONE__SPAWNS, "Error in SpawngroupID: %s ", row[0]);
else continue;
std::cout << "Error in SpawngroupID: " << row[0] << std::endl; }
}
mysql_free_result(result); sg->AddSpawnEntry(newSpawnEntry);
}
else
{
std::cerr << "Error3 in PopulateZoneLists query '" << query << "' " << errbuf << std::endl;
safe_delete_array(query);
return false;
} }
// CODER end new spawn code
return true; return true;
} }

View File

@ -28,8 +28,6 @@
#include "../common/rulesys.h" #include "../common/rulesys.h"
int Mob::GetKickDamage() { int Mob::GetKickDamage() {
int multiple=(GetLevel()*100/5); int multiple=(GetLevel()*100/5);
multiple += 100; multiple += 100;
@ -64,11 +62,9 @@ int Mob::GetBashDamage() {
} }
void Mob::ApplySpecialAttackMod(SkillUseTypes skill, int32 &dmg, int32 &mindmg) { void Mob::ApplySpecialAttackMod(SkillUseTypes skill, int32 &dmg, int32 &mindmg) {
int item_slot = -1; int item_slot = -1;
//1: Apply bonus from AC (BOOT/SHIELD/HANDS) est. 40AC=6dmg //1: Apply bonus from AC (BOOT/SHIELD/HANDS) est. 40AC=6dmg
if (IsClient()){ if (IsClient()){
switch (skill){ switch (skill){
case SkillFlyingKick: case SkillFlyingKick:
@ -112,10 +108,8 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
if(hate_override > -1) if(hate_override > -1)
hate = hate_override; hate = hate_override;
if(skill == SkillBash) if(skill == SkillBash){
{ if(IsClient()){
if(IsClient())
{
ItemInst *item = CastToClient()->GetInv().GetItem(MainSecondary); ItemInst *item = CastToClient()->GetInv().GetItem(MainSecondary);
if(item) if(item)
{ {
@ -186,6 +180,10 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
CombatAbility_Struct* ca_atk = (CombatAbility_Struct*) app->pBuffer; CombatAbility_Struct* ca_atk = (CombatAbility_Struct*) app->pBuffer;
/* Check to see if actually have skill */
if (!MaxSkill(static_cast<SkillUseTypes>(ca_atk->m_skill)))
return;
if(GetTarget()->GetID() != ca_atk->m_target) if(GetTarget()->GetID() != ca_atk->m_target)
return; //invalid packet. return; //invalid packet.
@ -274,8 +272,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
return; return;
} }
if ((ca_atk->m_atk == 100) && (ca_atk->m_skill == SkillFrenzy)) if ((ca_atk->m_atk == 100) && (ca_atk->m_skill == SkillFrenzy)){
{
CheckIncreaseSkill(SkillFrenzy, GetTarget(), 10); CheckIncreaseSkill(SkillFrenzy, GetTarget(), 10);
int AtkRounds = 3; int AtkRounds = 3;
int skillmod = 100*GetSkill(SkillFrenzy)/MaxSkill(SkillFrenzy); int skillmod = 100*GetSkill(SkillFrenzy)/MaxSkill(SkillFrenzy);
@ -311,8 +308,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
return; return;
} }
switch(GetClass()) switch(GetClass()){
{
case BERSERKER: case BERSERKER:
case WARRIOR: case WARRIOR:
case RANGER: case RANGER:
@ -384,8 +380,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
} }
ReuseTime = (ReuseTime*HasteMod)/100; ReuseTime = (ReuseTime*HasteMod)/100;
if(ReuseTime > 0) if(ReuseTime > 0){
{
p_timers.Start(pTimerCombatAbility, ReuseTime); p_timers.Start(pTimerCombatAbility, ReuseTime);
} }
} }
@ -403,8 +398,7 @@ int Mob::MonkSpecialAttack(Mob* other, uint8 unchecked_type)
SkillUseTypes skill_type; //to avoid casting... even though it "would work" SkillUseTypes skill_type; //to avoid casting... even though it "would work"
uint8 itemslot = MainFeet; uint8 itemslot = MainFeet;
switch(unchecked_type) switch(unchecked_type){
{
case SkillFlyingKick:{ case SkillFlyingKick:{
skill_type = SkillFlyingKick; skill_type = SkillFlyingKick;
max_dmg = ((GetSTR()+GetSkill(skill_type)) * RuleI(Combat, FlyingKickBonus) / 100) + 35; max_dmg = ((GetSTR()+GetSkill(skill_type)) * RuleI(Combat, FlyingKickBonus) / 100) + 35;
@ -484,8 +478,7 @@ int Mob::MonkSpecialAttack(Mob* other, uint8 unchecked_type)
else else
ht = ndamage = MakeRandomInt(min_dmg, max_dmg); ht = ndamage = MakeRandomInt(min_dmg, max_dmg);
} }
else else{
{
ht = max_dmg; ht = max_dmg;
} }
} }
@ -535,7 +528,6 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) {
RogueBackstab(other,false,ReuseTime); RogueBackstab(other,false,ReuseTime);
if (level > 54) { if (level > 54) {
if(IsClient() && CastToClient()->CheckDoubleAttack(false)) if(IsClient() && CastToClient()->CheckDoubleAttack(false))
{ {
if(other->GetHP() > 0) if(other->GetHP() > 0)
@ -619,12 +611,10 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime)
} }
// determine minimum hits // determine minimum hits
if (level < 51) if (level < 51) {
{
min_hit = (level*15/10); min_hit = (level*15/10);
} }
else else {
{
// Trumpcard: Replaced switch statement with formula calc. This will give minhit increases all the way to 65. // Trumpcard: Replaced switch statement with formula calc. This will give minhit increases all the way to 65.
min_hit = (level * ( level*5 - 105)) / 100; min_hit = (level * ( level*5 - 105)) / 100;
} }
@ -636,8 +626,7 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime)
if(min_damage){ if(min_damage){
ndamage = min_hit; ndamage = min_hit;
} }
else else {
{
if (max_hit < min_hit) if (max_hit < min_hit)
max_hit = min_hit; max_hit = min_hit;
@ -645,7 +634,6 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime)
ndamage = max_hit; ndamage = max_hit;
else else
ndamage = MakeRandomInt(min_hit, max_hit); ndamage = MakeRandomInt(min_hit, max_hit);
} }
} }
} }
@ -793,14 +781,12 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) {
} }
SendItemAnimation(GetTarget(), AmmoItem, SkillArchery); SendItemAnimation(GetTarget(), AmmoItem, SkillArchery);
DoArcheryAttackDmg(GetTarget(), RangeWeapon, Ammo); DoArcheryAttackDmg(GetTarget(), RangeWeapon, Ammo);
//EndlessQuiver AA base1 = 100% Chance to avoid consumption arrow. //EndlessQuiver AA base1 = 100% Chance to avoid consumption arrow.
int ChanceAvoidConsume = aabonuses.ConsumeProjectile + itembonuses.ConsumeProjectile + spellbonuses.ConsumeProjectile; int ChanceAvoidConsume = aabonuses.ConsumeProjectile + itembonuses.ConsumeProjectile + spellbonuses.ConsumeProjectile;
if (!ChanceAvoidConsume || (ChanceAvoidConsume < 100 && MakeRandomInt(0,99) > ChanceAvoidConsume)){ if (!ChanceAvoidConsume || (ChanceAvoidConsume < 100 && MakeRandomInt(0,99) > ChanceAvoidConsume)){
DeleteItemInInventory(ammo_slot, 1, true); DeleteItemInInventory(ammo_slot, 1, true);
mlog(COMBAT__RANGED, "Consumed one arrow from slot %d", ammo_slot); mlog(COMBAT__RANGED, "Consumed one arrow from slot %d", ammo_slot);
} else { } else {
@ -808,12 +794,10 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) {
} }
CheckIncreaseSkill(SkillArchery, GetTarget(), -15); CheckIncreaseSkill(SkillArchery, GetTarget(), -15);
CommonBreakInvisible(); CommonBreakInvisible();
} }
void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const ItemInst* Ammo, uint16 weapon_damage, int16 chance_mod, int16 focus, int ReuseTime) void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const ItemInst* Ammo, uint16 weapon_damage, int16 chance_mod, int16 focus, int ReuseTime) {
{
if (!CanDoSpecialAttack(other)) if (!CanDoSpecialAttack(other))
return; return;
@ -842,8 +826,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item
if (focus) //From FcBaseEffects if (focus) //From FcBaseEffects
WDmg += WDmg*focus/100; WDmg += WDmg*focus/100;
if((WDmg > 0) || (ADmg > 0)) if((WDmg > 0) || (ADmg > 0)) {
{
if(WDmg < 0) if(WDmg < 0)
WDmg = 0; WDmg = 0;
if(ADmg < 0) if(ADmg < 0)
@ -944,8 +927,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item
} }
//try proc on hits and misses //try proc on hits and misses
if((RangeWeapon != nullptr) && GetTarget() && other && !other->HasDied()) if((RangeWeapon != nullptr) && GetTarget() && other && !other->HasDied()){
{
TryWeaponProc(RangeWeapon, other, MainRange); TryWeaponProc(RangeWeapon, other, MainRange);
} }
@ -965,14 +947,19 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item
void NPC::RangedAttack(Mob* other) void NPC::RangedAttack(Mob* other)
{ {
if (!other)
return;
//make sure the attack and ranged timers are up //make sure the attack and ranged timers are up
//if the ranged timer is disabled, then they have no ranged weapon and shouldent be attacking anyhow //if the ranged timer is disabled, then they have no ranged weapon and shouldent be attacking anyhow
if((attack_timer.Enabled() && !attack_timer.Check(false)) || (ranged_timer.Enabled() && !ranged_timer.Check())) if((attack_timer.Enabled() && !attack_timer.Check(false)) || (ranged_timer.Enabled() && !ranged_timer.Check())){
{
mlog(COMBAT__RANGED, "Archery canceled. Timer not up. Attack %d, ranged %d", attack_timer.GetRemainingTime(), ranged_timer.GetRemainingTime()); mlog(COMBAT__RANGED, "Archery canceled. Timer not up. Attack %d, ranged %d", attack_timer.GetRemainingTime(), ranged_timer.GetRemainingTime());
return; return;
} }
if(!CheckLosFN(other))
return;
int attacks = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 0); int attacks = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 0);
attacks = attacks > 0 ? attacks : 1; attacks = attacks > 0 ? attacks : 1;
for(int i = 0; i < attacks; ++i) { for(int i = 0; i < attacks; ++i) {
@ -1087,9 +1074,7 @@ void NPC::RangedAttack(Mob* other)
} }
} }
uint16 Mob::GetThrownDamage(int16 wDmg, int32& TotalDmg, int& minDmg) uint16 Mob::GetThrownDamage(int16 wDmg, int32& TotalDmg, int& minDmg) {
{
uint16 MaxDmg = (((2 * wDmg) * GetDamageTable(SkillThrowing)) / 100); uint16 MaxDmg = (((2 * wDmg) * GetDamageTable(SkillThrowing)) / 100);
if (MaxDmg == 0) if (MaxDmg == 0)
@ -1101,8 +1086,7 @@ uint16 Mob::GetThrownDamage(int16 wDmg, int32& TotalDmg, int& minDmg)
TotalDmg = MakeRandomInt(1, MaxDmg); TotalDmg = MakeRandomInt(1, MaxDmg);
minDmg = 1; minDmg = 1;
if(GetLevel() > 25) if(GetLevel() > 25){
{
TotalDmg += ((GetLevel()-25)/3); TotalDmg += ((GetLevel()-25)/3);
minDmg += ((GetLevel()-25)/3); minDmg += ((GetLevel()-25)/3);
minDmg += minDmg * GetMeleeMinDamageMod_SE(SkillThrowing) / 100; minDmg += minDmg * GetMeleeMinDamageMod_SE(SkillThrowing) / 100;
@ -1196,7 +1180,6 @@ void Client::ThrowingAttack(Mob* other, bool CanDoubleAttack) { //old was 51
//consume ammo //consume ammo
DeleteItemInInventory(ammo_slot, 1, true); DeleteItemInInventory(ammo_slot, 1, true);
CheckIncreaseSkill(SkillThrowing, GetTarget()); CheckIncreaseSkill(SkillThrowing, GetTarget());
CommonBreakInvisible(); CommonBreakInvisible();
} }
@ -1227,8 +1210,7 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
if (GetClass() == ROGUE && (BehindMob(other, GetX(), GetY()))) if (GetClass() == ROGUE && (BehindMob(other, GetX(), GetY())))
Assassinate_Dmg = TryAssassinate(other, SkillThrowing, ranged_timer.GetDuration()); Assassinate_Dmg = TryAssassinate(other, SkillThrowing, ranged_timer.GetDuration());
if(WDmg > 0) if(WDmg > 0){
{
int minDmg = 1; int minDmg = 1;
uint16 MaxDmg = GetThrownDamage(WDmg, TotalDmg, minDmg); uint16 MaxDmg = GetThrownDamage(WDmg, TotalDmg, minDmg);
@ -1319,7 +1301,6 @@ void Mob::SendItemAnimation(Mob *to, const Item_Struct *item, SkillUseTypes skil
} }
void Mob::ProjectileAnimation(Mob* to, int item_id, bool IsArrow, float speed, float angle, float tilt, float arc, const char *IDFile, SkillUseTypes skillInUse) { void Mob::ProjectileAnimation(Mob* to, int item_id, bool IsArrow, float speed, float angle, float tilt, float arc, const char *IDFile, SkillUseTypes skillInUse) {
if (!to) if (!to)
return; return;
@ -1453,17 +1434,11 @@ void NPC::DoClassAttacks(Mob *target) {
break; break;
case MONK: case MONKGM: { case MONK: case MONKGM: {
uint8 satype = SkillKick; uint8 satype = SkillKick;
if(level > 29) { if(level > 29) { satype = SkillFlyingKick; }
satype = SkillFlyingKick; else if(level > 24) { satype = SkillDragonPunch; }
} else if(level > 24) { else if(level > 19) { satype = SkillEagleStrike; }
satype = SkillDragonPunch; else if(level > 9) { satype = SkillTigerClaw; }
} else if(level > 19) { else if(level > 4) { satype = SkillRoundKick; }
satype = SkillEagleStrike;
} else if(level > 9) {
satype = SkillTigerClaw;
} else if(level > 4) {
satype = SkillRoundKick;
}
reuse = MonkSpecialAttack(target, satype); reuse = MonkSpecialAttack(target, satype);
reuse *= 1000; reuse *= 1000;
@ -1472,8 +1447,7 @@ void NPC::DoClassAttacks(Mob *target) {
} }
case WARRIOR: case WARRIORGM:{ case WARRIOR: case WARRIORGM:{
if(level >= RuleI(Combat, NPCBashKickLevel)){ if(level >= RuleI(Combat, NPCBashKickLevel)){
if(MakeRandomInt(0, 100) > 25) //tested on live, warrior mobs both kick and bash, kick about 75% of the time, casting doesn't seem to make a difference. if(MakeRandomInt(0, 100) > 25){ //tested on live, warrior mobs both kick and bash, kick about 75% of the time, casting doesn't seem to make a difference.
{
DoAnim(animKick); DoAnim(animKick);
int32 dmg = 0; int32 dmg = 0;
@ -1494,8 +1468,7 @@ void NPC::DoClassAttacks(Mob *target) {
DoSpecialAttackDamage(target, SkillKick, dmg, 1, -1, reuse); DoSpecialAttackDamage(target, SkillKick, dmg, 1, -1, reuse);
did_attack = true; did_attack = true;
} }
else else {
{
DoAnim(animTailRake); DoAnim(animTailRake);
int32 dmg = 0; int32 dmg = 0;
@ -1518,8 +1491,7 @@ void NPC::DoClassAttacks(Mob *target) {
} }
break; break;
} }
case BERSERKER: case BERSERKERGM: case BERSERKER: case BERSERKERGM:{
{
int AtkRounds = 3; int AtkRounds = 3;
int32 max_dmg = 26 + ((GetLevel()-6) * 2); int32 max_dmg = 26 + ((GetLevel()-6) * 2);
int32 min_dmg = 0; int32 min_dmg = 0;
@ -1536,7 +1508,6 @@ void NPC::DoClassAttacks(Mob *target) {
reuse = FrenzyReuseTime * 1000; reuse = FrenzyReuseTime * 1000;
while(AtkRounds > 0) { while(AtkRounds > 0) {
if (GetTarget() && (AtkRounds == 1 || MakeRandomInt(0,100) < 75)){ if (GetTarget() && (AtkRounds == 1 || MakeRandomInt(0,100) < 75)){
DoSpecialAttackDamage(GetTarget(), SkillFrenzy, max_dmg, min_dmg, -1 , reuse, true); DoSpecialAttackDamage(GetTarget(), SkillFrenzy, max_dmg, min_dmg, -1 , reuse, true);
} }
@ -1574,8 +1545,7 @@ void NPC::DoClassAttacks(Mob *target) {
} }
case CLERIC: case CLERICGM: //clerics can bash too. case CLERIC: case CLERICGM: //clerics can bash too.
case SHADOWKNIGHT: case SHADOWKNIGHTGM: case SHADOWKNIGHT: case SHADOWKNIGHTGM:
case PALADIN: case PALADINGM: case PALADIN: case PALADINGM:{
{
if(level >= RuleI(Combat, NPCBashKickLevel)){ if(level >= RuleI(Combat, NPCBashKickLevel)){
DoAnim(animTailRake); DoAnim(animTailRake);
int32 dmg = 0; int32 dmg = 0;
@ -1615,8 +1585,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
return; return;
//check range for all these abilities, they are all close combat stuff //check range for all these abilities, they are all close combat stuff
if(!CombatRange(ca_target)) if(!CombatRange(ca_target)){
{
return; return;
} }
@ -1639,9 +1608,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
uint16 skill_to_use = -1; uint16 skill_to_use = -1;
if (skill == -1){ if (skill == -1){
switch(GetClass()){
switch(GetClass())
{
case WARRIOR: case WARRIOR:
case RANGER: case RANGER:
case BEASTLORD: case BEASTLORD:
@ -1692,14 +1659,11 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
if(skill_to_use == -1) if(skill_to_use == -1)
return; return;
if(skill_to_use == SkillBash) if(skill_to_use == SkillBash) {
{ if (ca_target!=this) {
if (ca_target!=this)
{
DoAnim(animTailRake); DoAnim(animTailRake);
if(GetWeaponDamage(ca_target, GetInv().GetItem(MainSecondary)) <= 0 && if(GetWeaponDamage(ca_target, GetInv().GetItem(MainSecondary)) <= 0 && GetWeaponDamage(ca_target, GetInv().GetItem(MainShoulders)) <= 0){
GetWeaponDamage(ca_target, GetInv().GetItem(MainShoulders)) <= 0){
dmg = -5; dmg = -5;
} }
else{ else{
@ -1720,16 +1684,14 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
DoSpecialAttackDamage(ca_target, SkillBash, dmg, 1,-1,ReuseTime); DoSpecialAttackDamage(ca_target, SkillBash, dmg, 1,-1,ReuseTime);
if(ReuseTime > 0 && !IsRiposte) if(ReuseTime > 0 && !IsRiposte) {
{
p_timers.Start(pTimerCombatAbility, ReuseTime); p_timers.Start(pTimerCombatAbility, ReuseTime);
} }
} }
return; return;
} }
if(skill_to_use == SkillFrenzy) if(skill_to_use == SkillFrenzy){
{
CheckIncreaseSkill(SkillFrenzy, GetTarget(), 10); CheckIncreaseSkill(SkillFrenzy, GetTarget(), 10);
int AtkRounds = 3; int AtkRounds = 3;
int skillmod = 100*GetSkill(SkillFrenzy)/MaxSkill(SkillFrenzy); int skillmod = 100*GetSkill(SkillFrenzy)/MaxSkill(SkillFrenzy);
@ -1763,10 +1725,8 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
return; return;
} }
if(skill_to_use == SkillKick) if(skill_to_use == SkillKick){
{ if(ca_target!=this){
if(ca_target!=this)
{
DoAnim(animKick); DoAnim(animKick);
if(GetWeaponDamage(ca_target, GetInv().GetItem(MainFeet)) <= 0){ if(GetWeaponDamage(ca_target, GetInv().GetItem(MainFeet)) <= 0){
@ -1790,12 +1750,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
} }
} }
if(skill_to_use == SkillFlyingKick || if(skill_to_use == SkillFlyingKick || skill_to_use == SkillDragonPunch || skill_to_use == SkillEagleStrike || skill_to_use == SkillTigerClaw || skill_to_use == SkillRoundKick) {
skill_to_use == SkillDragonPunch ||
skill_to_use == SkillEagleStrike ||
skill_to_use == SkillTigerClaw ||
skill_to_use == SkillRoundKick)
{
ReuseTime = MonkSpecialAttack(ca_target, skill_to_use) - 1; ReuseTime = MonkSpecialAttack(ca_target, skill_to_use) - 1;
MonkSpecialAttack(ca_target, skill_to_use); MonkSpecialAttack(ca_target, skill_to_use);
@ -1810,7 +1765,6 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
MonkSpecialAttack(ca_target, MonkSPA[MakeRandomInt(0,4)]); MonkSpecialAttack(ca_target, MonkSPA[MakeRandomInt(0,4)]);
int TripleChance = 25; int TripleChance = 25;
if (bDoubleSpecialAttack > 100) if (bDoubleSpecialAttack > 100)
TripleChance += TripleChance*(100-bDoubleSpecialAttack)/100; TripleChance += TripleChance*(100-bDoubleSpecialAttack)/100;
@ -1820,8 +1774,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
} }
} }
if(skill_to_use == SkillBackstab) if(skill_to_use == SkillBackstab){
{
ReuseTime = BackstabReuseTime-1; ReuseTime = BackstabReuseTime-1;
if (IsRiposte) if (IsRiposte)
@ -1831,8 +1784,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
} }
ReuseTime = (ReuseTime*HasteMod)/100; ReuseTime = (ReuseTime*HasteMod)/100;
if(ReuseTime > 0 && !IsRiposte) if(ReuseTime > 0 && !IsRiposte){
{
p_timers.Start(pTimerCombatAbility, ReuseTime); p_timers.Start(pTimerCombatAbility, ReuseTime);
} }
} }
@ -1900,7 +1852,6 @@ void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) {
tauntchance /= 100.0f; tauntchance /= 100.0f;
if (tauntchance > MakeRandomFloat(0, 1)) { if (tauntchance > MakeRandomFloat(0, 1)) {
if (hate_top && hate_top != this){ if (hate_top && hate_top != this){
newhate = (who->GetNPCHate(hate_top) - who->GetNPCHate(this)) + 1; newhate = (who->GetNPCHate(hate_top) - who->GetNPCHate(this)) + 1;
who->CastToNPC()->AddToHateList(this, newhate); who->CastToNPC()->AddToHateList(this, newhate);
@ -1923,7 +1874,6 @@ void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) {
if (HasSkillProcs()) if (HasSkillProcs())
TrySkillProc(who, SkillTaunt, TauntReuseTime*1000); TrySkillProc(who, SkillTaunt, TauntReuseTime*1000);
if (Success && HasSkillProcSuccess()) if (Success && HasSkillProcSuccess())
TrySkillProc(who, SkillTaunt, TauntReuseTime*1000, true); TrySkillProc(who, SkillTaunt, TauntReuseTime*1000, true);
} }
@ -1944,8 +1894,7 @@ void Mob::InstillDoubt(Mob *who) {
if(!CombatRange(who)) if(!CombatRange(who))
return; return;
if(IsClient()) if(IsClient()) {
{
CastToClient()->CheckIncreaseSkill(SkillIntimidation, who, 10); CastToClient()->CheckIncreaseSkill(SkillIntimidation, who, 10);
} }
@ -1976,13 +1925,11 @@ void Mob::InstillDoubt(Mob *who) {
} }
uint32 Mob::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) { uint32 Mob::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) {
//Only works on YOUR target. //Only works on YOUR target.
if(defender && (defender->GetBodyType() == BT_Humanoid) && !defender->IsClient() if(defender && (defender->GetBodyType() == BT_Humanoid) && !defender->IsClient()
&& (skillInUse == SkillArchery) && (GetTarget() == defender)) { && (skillInUse == SkillArchery) && (GetTarget() == defender)) {
uint32 HeadShot_Dmg = aabonuses.HeadShot[1] + spellbonuses.HeadShot[1] + itembonuses.HeadShot[1]; uint32 HeadShot_Dmg = aabonuses.HeadShot[1] + spellbonuses.HeadShot[1] + itembonuses.HeadShot[1];
uint8 HeadShot_Level = 0; //Get Highest Headshot Level uint8 HeadShot_Level = 0; //Get Highest Headshot Level
HeadShot_Level = aabonuses.HSLevel; HeadShot_Level = aabonuses.HSLevel;
if (HeadShot_Level < spellbonuses.HSLevel) if (HeadShot_Level < spellbonuses.HSLevel)
@ -1991,7 +1938,6 @@ uint32 Mob::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) {
HeadShot_Level = itembonuses.HSLevel; HeadShot_Level = itembonuses.HSLevel;
if(HeadShot_Dmg && HeadShot_Level && (defender->GetLevel() <= HeadShot_Level)){ if(HeadShot_Dmg && HeadShot_Level && (defender->GetLevel() <= HeadShot_Level)){
float ProcChance = GetSpecialProcChances(MainRange); float ProcChance = GetSpecialProcChances(MainRange);
if(ProcChance > MakeRandomFloat(0,1)) if(ProcChance > MakeRandomFloat(0,1))
return HeadShot_Dmg; return HeadShot_Dmg;
@ -2097,8 +2043,10 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
if (!CanDoSpecialAttack(other)) if (!CanDoSpecialAttack(other))
return; return;
//For spells using skill value 98 (feral swipe ect) server sets this to 67 automatically. /*
//Kayen: This is unlikely to be completely accurate but use OFFENSE skill value for these effects. For spells using skill value 98 (feral swipe ect) server sets this to 67 automatically.
Kayen: This is unlikely to be completely accurate but use OFFENSE skill value for these effects.
*/
if (skillinuse == SkillBegging) if (skillinuse == SkillBegging)
skillinuse = SkillOffense; skillinuse = SkillOffense;
@ -2108,7 +2056,6 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
if (hate == 0 && weapon_damage > 1) hate = weapon_damage; if (hate == 0 && weapon_damage > 1) hate = weapon_damage;
if(weapon_damage > 0){ if(weapon_damage > 0){
if (focus) //From FcBaseEffects if (focus) //From FcBaseEffects
weapon_damage += weapon_damage*focus/100; weapon_damage += weapon_damage*focus/100;
@ -2120,10 +2067,8 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
int32 min_hit = 1; int32 min_hit = 1;
int32 max_hit = (2 * weapon_damage*GetDamageTable(skillinuse)) / 100; int32 max_hit = (2 * weapon_damage*GetDamageTable(skillinuse)) / 100;
if(GetLevel() >= 28 && IsWarriorClass() ) if(GetLevel() >= 28 && IsWarriorClass() ) {
{
int ucDamageBonus = GetWeaponDamageBonus((const Item_Struct*) nullptr ); int ucDamageBonus = GetWeaponDamageBonus((const Item_Struct*) nullptr );
min_hit += (int) ucDamageBonus; min_hit += (int) ucDamageBonus;
max_hit += (int) ucDamageBonus; max_hit += (int) ucDamageBonus;
hate += ucDamageBonus; hate += ucDamageBonus;
@ -2143,7 +2088,6 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
} }
ApplySpecialAttackMod(skillinuse, max_hit, min_hit); ApplySpecialAttackMod(skillinuse, max_hit, min_hit);
min_hit += min_hit * GetMeleeMinDamageMod_SE(skillinuse) / 100; min_hit += min_hit * GetMeleeMinDamageMod_SE(skillinuse) / 100;
if(max_hit < min_hit) if(max_hit < min_hit)
@ -2204,8 +2148,7 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
TrySkillProc(other, skillinuse, ReuseTime, true); TrySkillProc(other, skillinuse, ReuseTime, true);
} }
bool Mob::CanDoSpecialAttack(Mob *other) bool Mob::CanDoSpecialAttack(Mob *other) {
{
//Make sure everything is valid before doing any attacks. //Make sure everything is valid before doing any attacks.
if (!other) { if (!other) {
SetTarget(nullptr); SetTarget(nullptr);
@ -2215,8 +2158,7 @@ bool Mob::CanDoSpecialAttack(Mob *other)
if(!GetTarget()) if(!GetTarget())
SetTarget(other); SetTarget(other);
if ((other == nullptr || ((IsClient() && CastToClient()->dead) || (other->IsClient() && other->CastToClient()->dead)) if ((other == nullptr || ((IsClient() && CastToClient()->dead) || (other->IsClient() && other->CastToClient()->dead)) || HasDied() || (!IsAttackAllowed(other)))) {
|| HasDied() || (!IsAttackAllowed(other)))) {
return false; return false;
} }

View File

@ -139,7 +139,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
if(IsNPC()) if(IsNPC())
{ {
std::vector<void*> args; std::vector<EQEmu::Any> args;
args.push_back(&buffslot); args.push_back(&buffslot);
int i = parse->EventSpell(EVENT_SPELL_EFFECT_NPC, CastToNPC(), nullptr, spell_id, caster ? caster->GetID() : 0, &args); int i = parse->EventSpell(EVENT_SPELL_EFFECT_NPC, CastToNPC(), nullptr, spell_id, caster ? caster->GetID() : 0, &args);
if(i != 0){ if(i != 0){
@ -149,7 +149,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
} }
else if(IsClient()) else if(IsClient())
{ {
std::vector<void*> args; std::vector<EQEmu::Any> args;
args.push_back(&buffslot); args.push_back(&buffslot);
int i = parse->EventSpell(EVENT_SPELL_EFFECT_CLIENT, nullptr, CastToClient(), spell_id, caster ? caster->GetID() : 0, &args); int i = parse->EventSpell(EVENT_SPELL_EFFECT_CLIENT, nullptr, CastToClient(), spell_id, caster ? caster->GetID() : 0, &args);
if(i != 0){ if(i != 0){
@ -3293,7 +3293,7 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste
if(IsNPC()) if(IsNPC())
{ {
std::vector<void*> args; std::vector<EQEmu::Any> args;
args.push_back(&ticsremaining); args.push_back(&ticsremaining);
args.push_back(&caster_level); args.push_back(&caster_level);
args.push_back(&slot); args.push_back(&slot);
@ -3304,7 +3304,7 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste
} }
else else
{ {
std::vector<void*> args; std::vector<EQEmu::Any> args;
args.push_back(&ticsremaining); args.push_back(&ticsremaining);
args.push_back(&caster_level); args.push_back(&caster_level);
args.push_back(&slot); args.push_back(&slot);
@ -3654,12 +3654,12 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
} }
if(IsClient()) { if(IsClient()) {
std::vector<void*> args; std::vector<EQEmu::Any> args;
args.push_back(&buffs[slot].casterid); args.push_back(&buffs[slot].casterid);
parse->EventSpell(EVENT_SPELL_FADE, nullptr, CastToClient(), buffs[slot].spellid, slot, &args); parse->EventSpell(EVENT_SPELL_FADE, nullptr, CastToClient(), buffs[slot].spellid, slot, &args);
} else if(IsNPC()) { } else if(IsNPC()) {
std::vector<void*> args; std::vector<EQEmu::Any> args;
args.push_back(&buffs[slot].casterid); args.push_back(&buffs[slot].casterid);
parse->EventSpell(EVENT_SPELL_FADE, CastToNPC(), nullptr, buffs[slot].spellid, slot, &args); parse->EventSpell(EVENT_SPELL_FADE, CastToNPC(), nullptr, buffs[slot].spellid, slot, &args);

View File

@ -4965,68 +4965,56 @@ int Client::FindSpellBookSlotBySpellID(uint16 spellid) {
return -1; //default return -1; //default
} }
bool Client::SpellGlobalCheck(uint16 Spell_ID, uint16 Char_ID) { bool Client::SpellGlobalCheck(uint16 spell_ID, uint16 char_ID) {
std::string Spell_Global_Name; std::string spell_Global_Name;
int Spell_Global_Value; int spell_Global_Value;
int Global_Value; int global_Value;
char errbuf[MYSQL_ERRMSG_SIZE]; std::string query = StringFormat("SELECT qglobal, value FROM spell_globals "
char *query = 0; "WHERE spellid = %i", spell_ID);
MYSQL_RES *result; auto results = database.QueryDatabase(query);
MYSQL_ROW row; if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error while querying Spell ID %i spell_globals table query '%s': %s", spell_ID, query.c_str(), results.ErrorMessage().c_str());
if (database.RunQuery(query,MakeAnyLenString(&query, "SELECT qglobal, value FROM spell_globals WHERE spellid=%i", Spell_ID), errbuf, &result)) {
safe_delete_array(query);
if (mysql_num_rows(result) == 1) {
row = mysql_fetch_row(result);
Spell_Global_Name = row[0];
Spell_Global_Value = atoi(row[1]);
mysql_free_result(result);
if (Spell_Global_Name.empty()) { // If the entry in the spell_globals table has nothing set for the qglobal name
return true;
}
else if (database.RunQuery(query,MakeAnyLenString(&query, "SELECT value FROM quest_globals WHERE charid=%i AND name='%s'", Char_ID, Spell_Global_Name.c_str()), errbuf, &result)) {
safe_delete_array(query);
if (mysql_num_rows(result) == 1) {
row = mysql_fetch_row(result);
Global_Value = atoi(row[0]);
mysql_free_result(result);
if (Global_Value == Spell_Global_Value) { // If the values match from both tables, allow the spell to be scribed
return true;
}
else if (Global_Value > Spell_Global_Value) { // Check if the qglobal value is greater than the require spellglobal value
return true;
}
else // If no matching result found in qglobals, don't scribe this spell
{
LogFile->write(EQEMuLog::Error, "Char ID: %i Spell_globals Name: '%s' Value: '%i' did not match QGlobal Value: '%i' for Spell ID %i", Char_ID, Spell_Global_Name.c_str(), Spell_Global_Value, Global_Value, Spell_ID);
return false;
}
}
else
LogFile->write(EQEMuLog::Error, "Char ID: %i does not have the Qglobal Name: '%s' for Spell ID %i", Char_ID, Spell_Global_Name.c_str(), Spell_ID);
safe_delete_array(query);
}
else
LogFile->write(EQEMuLog::Error, "Spell ID %i query of spell_globals with Name: '%s' Value: '%i' failed", Spell_ID, Spell_Global_Name.c_str(), Spell_Global_Value);
}
else {
return true; // Spell ID isn't listed in the spells_global table, so it is not restricted from scribing
}
mysql_free_result(result);
}
else {
LogFile->write(EQEMuLog::Error, "Error while querying Spell ID %i spell_globals table query '%s': %s", Spell_ID, query, errbuf);
safe_delete_array(query);
return false; // Query failed, so prevent spell from scribing just in case return false; // Query failed, so prevent spell from scribing just in case
} }
return false; // Default is false
if (results.RowCount() != 1)
return true; // Spell ID isn't listed in the spells_global table, so it is not restricted from scribing
auto row = results.begin();
spell_Global_Name = row[0];
spell_Global_Value = atoi(row[1]);
if (spell_Global_Name.empty())
return true; // If the entry in the spell_globals table has nothing set for the qglobal name
query = StringFormat("SELECT value FROM quest_globals "
"WHERE charid = %i AND name = '%s'",
char_ID, spell_Global_Name.c_str());
results = database.QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Spell ID %i query of spell_globals with Name: '%s' Value: '%i' failed", spell_ID, spell_Global_Name.c_str(), spell_Global_Value);
return false;
}
if (results.RowCount() != 1) {
LogFile->write(EQEMuLog::Error, "Char ID: %i does not have the Qglobal Name: '%s' for Spell ID %i", char_ID, spell_Global_Name.c_str(), spell_ID);
return false;
}
row = results.begin();
global_Value = atoi(row[0]);
if (global_Value == spell_Global_Value)
return true; // If the values match from both tables, allow the spell to be scribed
else if (global_Value > spell_Global_Value)
return true; // Check if the qglobal value is greater than the require spellglobal value
// If no matching result found in qglobals, don't scribe this spell
LogFile->write(EQEMuLog::Error, "Char ID: %i Spell_globals Name: '%s' Value: '%i' did not match QGlobal Value: '%i' for Spell ID %i", char_ID, spell_Global_Name.c_str(), spell_Global_Value, global_Value, spell_ID);
return false;
} }
// TODO get rid of this // TODO get rid of this

View File

@ -34,18 +34,16 @@ Copyright (C) 2001-2008 EQEMu Development Team (http://eqemulator.net)
#include "../common/features.h" #include "../common/features.h"
#include "quest_parser_collection.h" #include "quest_parser_collection.h"
#include "mob.h" #include "mob.h"
#include "queryserv.h"
extern QueryServ* QServ;
TaskManager::TaskManager() { TaskManager::TaskManager() {
for(int i=0; i<MAXTASKS; i++) for(int i=0; i<MAXTASKS; i++)
Tasks[i] = nullptr; Tasks[i] = nullptr;
} }
TaskManager::~TaskManager() { TaskManager::~TaskManager() {
for(int i=0; i<MAXTASKS; i++) { for(int i=0; i<MAXTASKS; i++) {
if(Tasks[i] != nullptr) { if(Tasks[i] != nullptr) {
for(int j=0; j<Tasks[i]->ActivityCount; j++) { for(int j=0; j<Tasks[i]->ActivityCount; j++) {
@ -62,11 +60,8 @@ TaskManager::~TaskManager() {
} }
bool TaskManager::LoadTaskSets() { bool TaskManager::LoadTaskSets() {
const char *TaskSetQuery = "SELECT `id`, `taskid` from `tasksets` WHERE `id` > 0 AND `id` < %i " const char *TaskSetQuery = "SELECT `id`, `taskid` from `tasksets` WHERE `id` > 0 AND `id` < %i "
"AND `taskid` >= 0 AND `taskid` < %i ORDER BY `id`, `taskid` ASC"; "AND `taskid` >= 0 AND `taskid` < %i ORDER BY `id`, `taskid` ASC";
const char *ERR_MYSQLERROR = "[TASKS]Error in TaskManager::LoadTaskSets: %s"; const char *ERR_MYSQLERROR = "[TASKS]Error in TaskManager::LoadTaskSets: %s";
char errbuf[MYSQL_ERRMSG_SIZE]; char errbuf[MYSQL_ERRMSG_SIZE];
@ -1985,12 +1980,17 @@ void ClientTaskState::IncrementDoneCount(Client *c, TaskInformation* Task, int T
// Inform the client the task has been updated, both by a chat message // Inform the client the task has been updated, both by a chat message
c->Message(0, "Your task '%s' has been updated.", Task->Title); c->Message(0, "Your task '%s' has been updated.", Task->Title);
if(Task->Activity[ActivityID].GoalMethod != METHODQUEST) if(Task->Activity[ActivityID].GoalMethod != METHODQUEST) {
{
char buf[24]; char buf[24];
snprintf(buf, 23, "%d %d", ActiveTasks[TaskIndex].TaskID, ActiveTasks[TaskIndex].Activity[ActivityID].ActivityID); snprintf(buf, 23, "%d %d", ActiveTasks[TaskIndex].TaskID, ActiveTasks[TaskIndex].Activity[ActivityID].ActivityID);
buf[23] = '\0'; buf[23] = '\0';
parse->EventPlayer(EVENT_TASK_STAGE_COMPLETE, c, buf, 0); parse->EventPlayer(EVENT_TASK_STAGE_COMPLETE, c, buf, 0);
/* QS: PlayerLogTaskUpdates :: Update */
if (RuleB(QueryServ, PlayerLogTaskUpdates)){
std::string event_desc = StringFormat("Task Stage Complete :: taskid:%i activityid:%i donecount:%i in zoneid:%i instid:%i", ActiveTasks[TaskIndex].TaskID, ActiveTasks[TaskIndex].Activity[ActivityID].ActivityID, ActiveTasks[TaskIndex].Activity[ActivityID].DoneCount, c->GetZoneID(), c->GetInstanceID());
QServ->PlayerLogEvent(Player_Log_Task_Updates, c->CharacterID(), event_desc);
}
} }
// If this task is now complete, the Completed tasks will have been // If this task is now complete, the Completed tasks will have been
@ -2002,6 +2002,12 @@ void ClientTaskState::IncrementDoneCount(Client *c, TaskInformation* Task, int T
buf[23] = '\0'; buf[23] = '\0';
parse->EventPlayer(EVENT_TASK_COMPLETE, c, buf, 0); parse->EventPlayer(EVENT_TASK_COMPLETE, c, buf, 0);
/* QS: PlayerLogTaskUpdates :: Complete */
if (RuleB(QueryServ, PlayerLogTaskUpdates)){
std::string event_desc = StringFormat("Task Complete :: taskid:%i activityid:%i donecount:%i in zoneid:%i instid:%i", ActiveTasks[TaskIndex].TaskID, ActiveTasks[TaskIndex].Activity[ActivityID].ActivityID, ActiveTasks[TaskIndex].Activity[ActivityID].DoneCount, c->GetZoneID(), c->GetInstanceID());
QServ->PlayerLogEvent(Player_Log_Task_Updates, c->CharacterID(), event_desc);
}
taskmanager->SendCompletedTasksToClient(c, this); taskmanager->SendCompletedTasksToClient(c, this);
c->SendTaskActivityComplete(ActiveTasks[TaskIndex].TaskID, 0, TaskIndex, false); c->SendTaskActivityComplete(ActiveTasks[TaskIndex].TaskID, 0, TaskIndex, false);
taskmanager->SaveClientState(c, this); taskmanager->SaveClientState(c, this);
@ -2011,6 +2017,7 @@ void ClientTaskState::IncrementDoneCount(Client *c, TaskInformation* Task, int T
// If Experience and/or cash rewards are set, reward them from the task even if RewardMethod is METHODQUEST // If Experience and/or cash rewards are set, reward them from the task even if RewardMethod is METHODQUEST
RewardTask(c, Task); RewardTask(c, Task);
//RemoveTask(c, TaskIndex); //RemoveTask(c, TaskIndex);
} }
} }

View File

@ -34,6 +34,9 @@
#include "../common/string_util.h" #include "../common/string_util.h"
#include "../common/rulesys.h" #include "../common/rulesys.h"
#include "quest_parser_collection.h" #include "quest_parser_collection.h"
#include "queryserv.h"
extern QueryServ* QServ;
static const SkillUseTypes TradeskillUnknown = Skill1HBlunt; /* an arbitrary non-tradeskill */ static const SkillUseTypes TradeskillUnknown = Skill1HBlunt; /* an arbitrary non-tradeskill */
@ -146,7 +149,7 @@ void Object::HandleAugmentation(Client* user, const AugmentItem_Struct* in_augme
ItemInst *aug = tobe_auged->GetAugment(slot); ItemInst *aug = tobe_auged->GetAugment(slot);
if(aug) { if(aug) {
std::vector<void*> args; std::vector<EQEmu::Any> args;
args.push_back(aug); args.push_back(aug);
parse->EventItem(EVENT_AUGMENT_ITEM, user, tobe_auged, nullptr, "", slot, &args); parse->EventItem(EVENT_AUGMENT_ITEM, user, tobe_auged, nullptr, "", slot, &args);
@ -168,7 +171,7 @@ void Object::HandleAugmentation(Client* user, const AugmentItem_Struct* in_augme
const uint32 id = auged_with->GetID(); const uint32 id = auged_with->GetID();
ItemInst *aug = tobe_auged->GetAugment(in_augment->augment_slot); ItemInst *aug = tobe_auged->GetAugment(in_augment->augment_slot);
if(aug) { if(aug) {
std::vector<void*> args; std::vector<EQEmu::Any> args;
args.push_back(aug); args.push_back(aug);
parse->EventItem(EVENT_UNAUGMENT_ITEM, user, tobe_auged, nullptr, "", slot, &args); parse->EventItem(EVENT_UNAUGMENT_ITEM, user, tobe_auged, nullptr, "", slot, &args);
@ -1076,16 +1079,24 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) {
//should we check this crap? //should we check this crap?
SummonItem(itr->first, itr->second); SummonItem(itr->first, itr->second);
item = database.GetItem(itr->first); item = database.GetItem(itr->first);
if (this->GetGroup()) if (this->GetGroup()) {
{
entity_list.MessageGroup(this, true, MT_Skills, "%s has successfully fashioned %s!", GetName(), item->Name); entity_list.MessageGroup(this, true, MT_Skills, "%s has successfully fashioned %s!", GetName(), item->Name);
} }
/* QS: Player_Log_Trade_Skill_Events */
if (RuleB(QueryServ, PlayerLogTradeSkillEvents)){
std::string event_desc = StringFormat("Success :: fashioned recipe_id:%i tskillid:%i trivial:%i chance:%4.2f in zoneid:%i instid:%i", spec->recipe_id, spec->tradeskill, spec->trivial, chance, this->GetZoneID(), this->GetInstanceID());
QServ->PlayerLogEvent(Player_Log_Trade_Skill_Events, this->CharacterID(), event_desc);
}
if(RuleB(TaskSystem, EnableTaskSystem)) if(RuleB(TaskSystem, EnableTaskSystem))
UpdateTasksForItem(ActivityTradeSkill, itr->first, itr->second); UpdateTasksForItem(ActivityTradeSkill, itr->first, itr->second);
++itr; ++itr;
} }
return(true); return(true);
} else { }
/* Tradeskill Fail */
else {
success_modifier = 2; // Halves the chance success_modifier = 2; // Halves the chance
if(over_trivial < 0) if(over_trivial < 0)
@ -1097,6 +1108,13 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) {
if (this->GetGroup()) if (this->GetGroup())
{ {
entity_list.MessageGroup(this,true,MT_Skills,"%s was unsuccessful in %s tradeskill attempt.",GetName(),this->GetGender() == 0 ? "his" : this->GetGender() == 1 ? "her" : "its"); entity_list.MessageGroup(this,true,MT_Skills,"%s was unsuccessful in %s tradeskill attempt.",GetName(),this->GetGender() == 0 ? "his" : this->GetGender() == 1 ? "her" : "its");
}
/* QS: Player_Log_Trade_Skill_Events */
if (RuleB(QueryServ, PlayerLogTradeSkillEvents)){
std::string event_desc = StringFormat("Failed :: recipe_id:%i tskillid:%i trivial:%i chance:%4.2f in zoneid:%i instid:%i", spec->recipe_id, spec->tradeskill, spec->trivial, chance, this->GetZoneID(), this->GetInstanceID());
QServ->PlayerLogEvent(Player_Log_Trade_Skill_Events, this->CharacterID(), event_desc);
} }
itr = spec->onfail.begin(); itr = spec->onfail.begin();
@ -1106,6 +1124,8 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) {
++itr; ++itr;
} }
/* Salvage Item rolls */
// Rolls on each item, is possible to return everything // Rolls on each item, is possible to return everything
int SalvageChance = aabonuses.SalvageChance + itembonuses.SalvageChance + spellbonuses.SalvageChance; int SalvageChance = aabonuses.SalvageChance + itembonuses.SalvageChance + spellbonuses.SalvageChance;
// Skip check if not a normal TS or if a quest recipe these should be nofail, but check amyways // Skip check if not a normal TS or if a quest recipe these should be nofail, but check amyways

View File

@ -22,7 +22,10 @@
#include "../common/rulesys.h" #include "../common/rulesys.h"
#include "quest_parser_collection.h" #include "quest_parser_collection.h"
#include "worldserver.h" #include "worldserver.h"
#include "queryserv.h"
extern WorldServer worldserver; extern WorldServer worldserver;
extern QueryServ* QServ;
// The maximum amount of a single bazaar/barter transaction expressed in copper. // The maximum amount of a single bazaar/barter transaction expressed in copper.
// Equivalent to 2 Million plat // Equivalent to 2 Million plat
@ -71,8 +74,8 @@ void Trade::Start(uint32 mob_id, bool initiate_with)
} }
// Add item from a given slot to trade bucket (automatically does bag data too) // Add item from a given slot to trade bucket (automatically does bag data too)
void Trade::AddEntity(uint16 from_slot_id, uint16 trade_slot_id, uint32 stack_size) { void Trade::AddEntity(uint16 trade_slot_id, uint32 stack_size) {
// TODO: review for inventory saves // TODO: review for inventory saves / consider changing return type to bool so failure can be passed to desync handler
if (!owner || !owner->IsClient()) { if (!owner || !owner->IsClient()) {
// This should never happen // This should never happen
@ -121,7 +124,7 @@ void Trade::AddEntity(uint16 from_slot_id, uint16 trade_slot_id, uint32 stack_si
if (_stack_size > 0) if (_stack_size > 0)
inst->SetCharges(_stack_size); inst->SetCharges(_stack_size);
else else
client->DeleteItemInInventory(from_slot_id); client->DeleteItemInInventory(MainCursor);
SendItemData(inst2, trade_slot_id); SendItemData(inst2, trade_slot_id);
} }
@ -136,7 +139,7 @@ void Trade::AddEntity(uint16 from_slot_id, uint16 trade_slot_id, uint32 stack_si
_log(TRADING__HOLDER, "%s added item '%s' to trade slot %i", owner->GetName(), inst->GetItem()->Name, trade_slot_id); _log(TRADING__HOLDER, "%s added item '%s' to trade slot %i", owner->GetName(), inst->GetItem()->Name, trade_slot_id);
client->PutItemInInventory(trade_slot_id, *inst); client->PutItemInInventory(trade_slot_id, *inst);
client->DeleteItemInInventory(from_slot_id); client->DeleteItemInInventory(MainCursor);
} }
} }
@ -316,200 +319,464 @@ void Trade::DumpTrade()
#endif #endif
void Client::ResetTrade() { void Client::ResetTrade() {
const Item_Struct* TempItem = 0;
ItemInst* ins;
int x;
AddMoneyToPP(trade->cp, trade->sp, trade->gp, trade->pp, true); AddMoneyToPP(trade->cp, trade->sp, trade->gp, trade->pp, true);
for(x = EmuConstants::TRADE_BEGIN; x <= EmuConstants::TRADE_END; x++)
{ // step 1: process bags
TempItem = 0; for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) {
ins = GetInv().GetItem(x); const ItemInst* inst = m_inv[trade_slot];
if (ins)
TempItem = ins->GetItem(); if (inst && inst->IsType(ItemClassContainer)) {
if (TempItem) int16 free_slot = m_inv.FindFreeSlotForTradeItem(inst);
{
bool is_arrow = (TempItem->ItemType == ItemTypeArrow) ? true : false; if (free_slot != INVALID_INDEX) {
int freeslotid = GetInv().FindFreeSlot(ins->IsType(ItemClassContainer), true, TempItem->Size, is_arrow); PutItemInInventory(free_slot, *inst);
if (freeslotid == INVALID_INDEX) SendItemPacket(free_slot, inst, ItemPacketTrade);
{
DropInst(ins);
} }
else else {
{ DropInst(inst);
PutItemInInventory(freeslotid, *ins); }
SendItemPacket(freeslotid, ins, ItemPacketTrade);
DeleteItemInInventory(trade_slot);
}
}
// step 2a: process stackables
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) {
ItemInst* inst = GetInv().GetItem(trade_slot);
if (inst && inst->IsStackable()) {
while (true) {
// there's no built-in safety check against an infinite loop..but, it should break on one of the conditional checks
int16 free_slot = m_inv.FindFreeSlotForTradeItem(inst);
if ((free_slot == MainCursor) || (free_slot == INVALID_INDEX))
break;
ItemInst* partial_inst = GetInv().GetItem(free_slot);
if (!partial_inst)
break;
if (partial_inst->GetID() != inst->GetID()) {
_log(TRADING__ERROR, "Client::ResetTrade() - an incompatible location reference was returned by Inventory::FindFreeSlotForTradeItem()");
break;
}
if ((partial_inst->GetCharges() + inst->GetCharges()) > partial_inst->GetItem()->StackSize) {
int16 new_charges = (partial_inst->GetCharges() + inst->GetCharges()) - partial_inst->GetItem()->StackSize;
partial_inst->SetCharges(partial_inst->GetItem()->StackSize);
inst->SetCharges(new_charges);
}
else {
partial_inst->SetCharges(partial_inst->GetCharges() + inst->GetCharges());
inst->SetCharges(0);
}
PutItemInInventory(free_slot, *partial_inst);
SendItemPacket(free_slot, partial_inst, ItemPacketTrade);
if (inst->GetCharges() == 0) {
DeleteItemInInventory(trade_slot);
break;
} }
DeleteItemInInventory(x);
} }
} }
} }
void Client::FinishTrade(Mob* tradingWith, ServerPacket* qspack, bool finalizer) { // step 2b: adjust trade stack bias
// (if any partial stacks exist before the final stack, FindFreeSlotForTradeItem() will return that slot in step 3 and an overwrite will occur)
for (int16 trade_slot = EmuConstants::TRADE_END; trade_slot >= EmuConstants::TRADE_BEGIN; --trade_slot) {
ItemInst* inst = GetInv().GetItem(trade_slot);
if (inst && inst->IsStackable()) {
for (int16 bias_slot = EmuConstants::TRADE_BEGIN; bias_slot <= EmuConstants::TRADE_END; ++bias_slot) {
if (bias_slot >= trade_slot)
break;
ItemInst* bias_inst = GetInv().GetItem(bias_slot);
if (!bias_inst || (bias_inst->GetID() != inst->GetID()) || (bias_inst->GetCharges() >= bias_inst->GetItem()->StackSize))
continue;
if ((bias_inst->GetCharges() + inst->GetCharges()) > bias_inst->GetItem()->StackSize) {
int16 new_charges = (bias_inst->GetCharges() + inst->GetCharges()) - bias_inst->GetItem()->StackSize;
bias_inst->SetCharges(bias_inst->GetItem()->StackSize);
inst->SetCharges(new_charges);
}
else {
bias_inst->SetCharges(bias_inst->GetCharges() + inst->GetCharges());
inst->SetCharges(0);
}
if (inst->GetCharges() == 0) {
DeleteItemInInventory(trade_slot);
break;
}
}
}
}
// step 3: process everything else
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) {
const ItemInst* inst = m_inv[trade_slot];
if (inst) {
int16 free_slot = m_inv.FindFreeSlotForTradeItem(inst);
if (free_slot != INVALID_INDEX) {
PutItemInInventory(free_slot, *inst);
SendItemPacket(free_slot, inst, ItemPacketTrade);
}
else {
DropInst(inst);
}
DeleteItemInInventory(trade_slot);
}
}
}
void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, std::list<void*>* event_details) {
if(tradingWith && tradingWith->IsClient()) { if(tradingWith && tradingWith->IsClient()) {
Client* other = tradingWith->CastToClient(); Client* other = tradingWith->CastToClient();
QSPlayerLogTrade_Struct* qs_audit = nullptr;
bool qs_log = false;
if(other) { if(other) {
mlog(TRADING__CLIENT, "Finishing trade with client %s", other->GetName()); mlog(TRADING__CLIENT, "Finishing trade with client %s", other->GetName());
int16 slot_id;
const Item_Struct* item = nullptr;
QSPlayerLogTrade_Struct* qsaudit = nullptr;
bool QSPLT = false;
// QS code
if(qspack && RuleB(QueryServ, PlayerLogTrades)) {
qsaudit = (QSPlayerLogTrade_Struct*) qspack->pBuffer;
QSPLT = true;
if(finalizer) { qsaudit->char2_id = this->character_id; }
else { qsaudit->char1_id = this->character_id; }
}
// Move each trade slot into free inventory slot
for(int16 i = EmuConstants::TRADE_BEGIN; i <= EmuConstants::TRADE_END; i++){
const ItemInst* inst = m_inv[i];
uint16 parent_offset = 0;
if(inst == nullptr) { continue; }
mlog(TRADING__CLIENT, "Giving %s (%d) in slot %d to %s", inst->GetItem()->Name, inst->GetItem()->ID, i, other->GetName());
/// Log Player Trades through QueryServ if Rule Enabled
if(QSPLT) {
uint16 item_count = qsaudit->char1_count + qsaudit->char2_count;
parent_offset = item_count;
qsaudit->items[item_count].from_id = this->character_id;
qsaudit->items[item_count].from_slot = i;
qsaudit->items[item_count].to_id = other->CharacterID();
qsaudit->items[item_count].to_slot = 0;
qsaudit->items[item_count].item_id = inst->GetID();
qsaudit->items[item_count].charges = inst->GetCharges();
qsaudit->items[item_count].aug_1 = inst->GetAugmentItemID(1);
qsaudit->items[item_count].aug_2 = inst->GetAugmentItemID(2);
qsaudit->items[item_count].aug_3 = inst->GetAugmentItemID(3);
qsaudit->items[item_count].aug_4 = inst->GetAugmentItemID(4);
qsaudit->items[item_count].aug_5 = inst->GetAugmentItemID(5);
if(finalizer) { qsaudit->char2_count++; }
else { qsaudit->char1_count++; }
if(inst->IsType(ItemClassContainer)) {
// Pseudo-Slot ID's are generated based on how the db saves bag items...
for(uint8 j = SUB_BEGIN; j < inst->GetItem()->BagSlots; j++) {
const ItemInst* baginst = inst->GetItem(j);
if(baginst == nullptr) { continue; }
int16 k=Inventory::CalcSlotId(i, j);
item_count = qsaudit->char1_count + qsaudit->char2_count;
qsaudit->items[item_count].from_id = this->character_id;
qsaudit->items[item_count].from_slot = k;
qsaudit->items[item_count].to_id = other->CharacterID();
qsaudit->items[item_count].to_slot = 0;
qsaudit->items[item_count].item_id = baginst->GetID();
qsaudit->items[item_count].charges = baginst->GetCharges();
qsaudit->items[item_count].aug_1 = baginst->GetAugmentItemID(1);
qsaudit->items[item_count].aug_2 = baginst->GetAugmentItemID(2);
qsaudit->items[item_count].aug_3 = baginst->GetAugmentItemID(3);
qsaudit->items[item_count].aug_4 = baginst->GetAugmentItemID(4);
qsaudit->items[item_count].aug_5 = baginst->GetAugmentItemID(5);
if(finalizer) { qsaudit->char2_count++; }
else { qsaudit->char1_count++; }
}
}
}
if (inst->GetItem()->NoDrop != 0 || Admin() >= RuleI(Character, MinStatusForNoDropExemptions) || RuleI(World, FVNoDropFlag) == 1 || other == this) {
bool is_arrow = (inst->GetItem()->ItemType == ItemTypeArrow) ? true : false;
slot_id = other->GetInv().FindFreeSlot(inst->IsType(ItemClassContainer), true, inst->GetItem()->Size, is_arrow);
mlog(TRADING__CLIENT, "Trying to put %s (%d) into slot %d", inst->GetItem()->Name, inst->GetItem()->ID, slot_id);
if(other->PutItemInInventory(slot_id, *inst, true)) {
mlog(TRADING__CLIENT, "Item %s (%d) successfully transfered, deleting from trade slot.", inst->GetItem()->Name, inst->GetItem()->ID);
if(QSPLT) {
qsaudit->items[parent_offset].to_slot = slot_id;
if(inst->IsType(ItemClassContainer)) {
for(uint8 bagslot_idx = SUB_BEGIN; bagslot_idx < inst->GetItem()->BagSlots; bagslot_idx++) {
const ItemInst* bag_inst = inst->GetItem(bagslot_idx);
if(bag_inst == nullptr) { continue; }
int16 to_bagslot_id = Inventory::CalcSlotId(slot_id, bagslot_idx);
qsaudit->items[++parent_offset].to_slot = to_bagslot_id;
}
}
}
}
else {
PushItemOnCursor(*inst, true);
mlog(TRADING__ERROR, "Unable to give item %d (%d) to %s, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID, other->GetName());
if(QSPLT) {
qsaudit->items[parent_offset].to_id = this->character_id;
qsaudit->items[parent_offset].to_slot = MainCursor;
if(inst->IsType(ItemClassContainer)) {
for(uint8 bagslot_idx = SUB_BEGIN; bagslot_idx < inst->GetItem()->BagSlots; bagslot_idx++) {
const ItemInst* bag_inst = inst->GetItem(bagslot_idx);
if(bag_inst == nullptr) { continue; }
int16 to_bagslot_id = Inventory::CalcSlotId(MainCursor, bagslot_idx);
qsaudit->items[++parent_offset].to_id = this->character_id;
qsaudit->items[parent_offset].to_slot = to_bagslot_id;
}
}
}
}
DeleteItemInInventory(i);
}
else {
PushItemOnCursor(*inst, true);
DeleteItemInInventory(i);
if(QSPLT) {
qsaudit->items[parent_offset].to_id = this->character_id;
qsaudit->items[parent_offset].to_slot = MainCursor;
if(inst->IsType(ItemClassContainer)) {
for(uint8 bagslot_idx = SUB_BEGIN; bagslot_idx < inst->GetItem()->BagSlots; bagslot_idx++) {
const ItemInst* bag_inst = inst->GetItem(bagslot_idx);
if(bag_inst == nullptr) { continue; }
int16 to_bagslot_id = Inventory::CalcSlotId(MainCursor, bagslot_idx);
qsaudit->items[++parent_offset].to_id = this->character_id;
qsaudit->items[parent_offset].to_slot = to_bagslot_id;
}
}
}
}
}
// Money - look into how NPC's receive cash
this->AddMoneyToPP(other->trade->cp, other->trade->sp, other->trade->gp, other->trade->pp, true); this->AddMoneyToPP(other->trade->cp, other->trade->sp, other->trade->gp, other->trade->pp, true);
// This is currently setup to show character offers, not receipts // step 0: pre-processing
if(QSPLT) { // QS code
if (RuleB(QueryServ, PlayerLogTrades) && event_entry && event_details) {
qs_audit = (QSPlayerLogTrade_Struct*)event_entry;
qs_log = true;
if (finalizer) { if (finalizer) {
qsaudit->char2_money.platinum = this->trade->pp; qs_audit->char2_id = this->character_id;
qsaudit->char2_money.gold = this->trade->gp;
qsaudit->char2_money.silver = this->trade->sp; qs_audit->char2_money.platinum = this->trade->pp;
qsaudit->char2_money.copper = this->trade->cp; qs_audit->char2_money.gold = this->trade->gp;
qs_audit->char2_money.silver = this->trade->sp;
qs_audit->char2_money.copper = this->trade->cp;
} }
else { else {
qsaudit->char1_money.platinum = this->trade->pp; qs_audit->char1_id = this->character_id;
qsaudit->char1_money.gold = this->trade->gp;
qsaudit->char1_money.silver = this->trade->sp; qs_audit->char1_money.platinum = this->trade->pp;
qsaudit->char1_money.copper = this->trade->cp; qs_audit->char1_money.gold = this->trade->gp;
qs_audit->char1_money.silver = this->trade->sp;
qs_audit->char1_money.copper = this->trade->cp;
}
}
// step 1: process bags
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) {
const ItemInst* inst = m_inv[trade_slot];
if (inst && inst->IsType(ItemClassContainer)) {
mlog(TRADING__CLIENT, "Giving container %s (%d) in slot %d to %s", inst->GetItem()->Name, inst->GetItem()->ID, trade_slot, other->GetName());
// TODO: need to check bag items/augments for no drop..everything for attuned...
if (inst->GetItem()->NoDrop != 0 || Admin() >= RuleI(Character, MinStatusForNoDropExemptions) || RuleI(World, FVNoDropFlag) == 1 || other == this) {
int16 free_slot = other->GetInv().FindFreeSlotForTradeItem(inst);
if (free_slot != INVALID_INDEX) {
if (other->PutItemInInventory(free_slot, *inst, true)) {
mlog(TRADING__CLIENT, "Container %s (%d) successfully transferred, deleting from trade slot.", inst->GetItem()->Name, inst->GetItem()->ID);
if (qs_log) {
QSTradeItems_Struct* detail = new QSTradeItems_Struct;
detail->from_id = this->character_id;
detail->from_slot = trade_slot;
detail->to_id = other->CharacterID();
detail->to_slot = free_slot;
detail->item_id = inst->GetID();
detail->charges = 1;
detail->aug_1 = inst->GetAugmentItemID(1);
detail->aug_2 = inst->GetAugmentItemID(2);
detail->aug_3 = inst->GetAugmentItemID(3);
detail->aug_4 = inst->GetAugmentItemID(4);
detail->aug_5 = inst->GetAugmentItemID(5);
event_details->push_back(detail);
if (finalizer)
qs_audit->char2_count += detail->charges;
else
qs_audit->char1_count += detail->charges;
//for (uint8 sub_slot = SUB_BEGIN; ((sub_slot < inst->GetItem()->BagSlots) && (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE)); ++sub_slot) {
for (uint8 sub_slot = SUB_BEGIN; (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++sub_slot) { // this is to catch ALL items
const ItemInst* bag_inst = inst->GetItem(sub_slot);
if (bag_inst) {
detail = new QSTradeItems_Struct;
detail->from_id = this->character_id;
detail->from_slot = Inventory::CalcSlotId(trade_slot, sub_slot);
detail->to_id = other->CharacterID();
detail->to_slot = Inventory::CalcSlotId(free_slot, sub_slot);
detail->item_id = bag_inst->GetID();
detail->charges = (!bag_inst->IsStackable() ? 1 : bag_inst->GetCharges());
detail->aug_1 = bag_inst->GetAugmentItemID(1);
detail->aug_2 = bag_inst->GetAugmentItemID(2);
detail->aug_3 = bag_inst->GetAugmentItemID(3);
detail->aug_4 = bag_inst->GetAugmentItemID(4);
detail->aug_5 = bag_inst->GetAugmentItemID(5);
event_details->push_back(detail);
if (finalizer)
qs_audit->char2_count += detail->charges;
else
qs_audit->char1_count += detail->charges;
}
}
}
}
else {
mlog(TRADING__ERROR, "Transfer of container %s (%d) to %s failed, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID, other->GetName());
PushItemOnCursor(*inst, true);
}
}
else {
mlog(TRADING__ERROR, "%s's inventory is full, returning container %s (%d) to giver.", other->GetName(), inst->GetItem()->Name, inst->GetItem()->ID);
PushItemOnCursor(*inst, true);
}
}
else {
mlog(TRADING__ERROR, "Container %s (%d) is NoDrop, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID);
PushItemOnCursor(*inst, true);
}
DeleteItemInInventory(trade_slot);
}
}
// step 2a: process stackables
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) {
ItemInst* inst = GetInv().GetItem(trade_slot);
if (inst && inst->IsStackable()) {
while (true) {
// there's no built-in safety check against an infinite loop..but, it should break on one of the conditional checks
int16 partial_slot = other->GetInv().FindFreeSlotForTradeItem(inst);
if ((partial_slot == MainCursor) || (partial_slot == INVALID_INDEX))
break;
ItemInst* partial_inst = other->GetInv().GetItem(partial_slot);
if (!partial_inst)
break;
if (partial_inst->GetID() != inst->GetID()) {
_log(TRADING__ERROR, "Client::ResetTrade() - an incompatible location reference was returned by Inventory::FindFreeSlotForTradeItem()");
break;
}
int16 old_charges = inst->GetCharges();
int16 partial_charges = partial_inst->GetCharges();
if ((partial_inst->GetCharges() + inst->GetCharges()) > partial_inst->GetItem()->StackSize) {
int16 new_charges = (partial_inst->GetCharges() + inst->GetCharges()) - partial_inst->GetItem()->StackSize;
partial_inst->SetCharges(partial_inst->GetItem()->StackSize);
inst->SetCharges(new_charges);
}
else {
partial_inst->SetCharges(partial_inst->GetCharges() + inst->GetCharges());
inst->SetCharges(0);
}
mlog(TRADING__CLIENT, "Transferring partial stack %s (%d) in slot %d to %s", inst->GetItem()->Name, inst->GetItem()->ID, trade_slot, other->GetName());
if (other->PutItemInInventory(partial_slot, *partial_inst, true)) {
mlog(TRADING__CLIENT, "Partial stack %s (%d) successfully transferred, deleting %i charges from trade slot.",
inst->GetItem()->Name, inst->GetItem()->ID, (old_charges - inst->GetCharges()));
if (qs_log) {
QSTradeItems_Struct* detail = new QSTradeItems_Struct;
detail->from_id = this->character_id;
detail->from_slot = trade_slot;
detail->to_id = other->CharacterID();
detail->to_slot = partial_slot;
detail->item_id = inst->GetID();
detail->charges = (old_charges - inst->GetCharges());
detail->aug_1 = 0;
detail->aug_2 = 0;
detail->aug_3 = 0;
detail->aug_4 = 0;
detail->aug_5 = 0;
event_details->push_back(detail);
if (finalizer)
qs_audit->char2_count += detail->charges;
else
qs_audit->char1_count += detail->charges;
}
}
else {
mlog(TRADING__ERROR, "Transfer of partial stack %s (%d) to %s failed, returning %i charges to trade slot.",
inst->GetItem()->Name, inst->GetItem()->ID, other->GetName(), (old_charges - inst->GetCharges()));
inst->SetCharges(old_charges);
partial_inst->SetCharges(partial_charges);
break;
}
if (inst->GetCharges() == 0) {
DeleteItemInInventory(trade_slot);
break;
}
}
}
}
// step 2b: adjust trade stack bias
// (if any partial stacks exist before the final stack, FindFreeSlotForTradeItem() will return that slot in step 3 and an overwrite will occur)
for (int16 trade_slot = EmuConstants::TRADE_END; trade_slot >= EmuConstants::TRADE_BEGIN; --trade_slot) {
ItemInst* inst = GetInv().GetItem(trade_slot);
if (inst && inst->IsStackable()) {
for (int16 bias_slot = EmuConstants::TRADE_BEGIN; bias_slot <= EmuConstants::TRADE_END; ++bias_slot) {
if (bias_slot >= trade_slot)
break;
ItemInst* bias_inst = GetInv().GetItem(bias_slot);
if (!bias_inst || (bias_inst->GetID() != inst->GetID()) || (bias_inst->GetCharges() >= bias_inst->GetItem()->StackSize))
continue;
int16 old_charges = inst->GetCharges();
if ((bias_inst->GetCharges() + inst->GetCharges()) > bias_inst->GetItem()->StackSize) {
int16 new_charges = (bias_inst->GetCharges() + inst->GetCharges()) - bias_inst->GetItem()->StackSize;
bias_inst->SetCharges(bias_inst->GetItem()->StackSize);
inst->SetCharges(new_charges);
}
else {
bias_inst->SetCharges(bias_inst->GetCharges() + inst->GetCharges());
inst->SetCharges(0);
}
if (qs_log) {
QSTradeItems_Struct* detail = new QSTradeItems_Struct;
detail->from_id = this->character_id;
detail->from_slot = trade_slot;
detail->to_id = this->character_id;
detail->to_slot = bias_slot;
detail->item_id = inst->GetID();
detail->charges = (old_charges - inst->GetCharges());
detail->aug_1 = 0;
detail->aug_2 = 0;
detail->aug_3 = 0;
detail->aug_4 = 0;
detail->aug_5 = 0;
event_details->push_back(detail);
}
if (inst->GetCharges() == 0) {
DeleteItemInInventory(trade_slot);
break;
}
}
}
}
// step 3: process everything else
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) {
const ItemInst* inst = m_inv[trade_slot];
if (inst) {
mlog(TRADING__CLIENT, "Giving item %s (%d) in slot %d to %s", inst->GetItem()->Name, inst->GetItem()->ID, trade_slot, other->GetName());
// TODO: need to check bag items/augments for no drop..everything for attuned...
if (inst->GetItem()->NoDrop != 0 || Admin() >= RuleI(Character, MinStatusForNoDropExemptions) || RuleI(World, FVNoDropFlag) == 1 || other == this) {
int16 free_slot = other->GetInv().FindFreeSlotForTradeItem(inst);
if (free_slot != INVALID_INDEX) {
if (other->PutItemInInventory(free_slot, *inst, true)) {
mlog(TRADING__CLIENT, "Item %s (%d) successfully transferred, deleting from trade slot.", inst->GetItem()->Name, inst->GetItem()->ID);
if (qs_log) {
QSTradeItems_Struct* detail = new QSTradeItems_Struct;
detail->from_id = this->character_id;
detail->from_slot = trade_slot;
detail->to_id = other->CharacterID();
detail->to_slot = free_slot;
detail->item_id = inst->GetID();
detail->charges = (!inst->IsStackable() ? 1 : inst->GetCharges());
detail->aug_1 = inst->GetAugmentItemID(1);
detail->aug_2 = inst->GetAugmentItemID(2);
detail->aug_3 = inst->GetAugmentItemID(3);
detail->aug_4 = inst->GetAugmentItemID(4);
detail->aug_5 = inst->GetAugmentItemID(5);
event_details->push_back(detail);
if (finalizer)
qs_audit->char2_count += detail->charges;
else
qs_audit->char1_count += detail->charges;
// 'step 3' should never really see containers..but, just in case...
//for (uint8 sub_slot = SUB_BEGIN; ((sub_slot < inst->GetItem()->BagSlots) && (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE)); ++sub_slot) {
for (uint8 sub_slot = SUB_BEGIN; (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++sub_slot) { // this is to catch ALL items
const ItemInst* bag_inst = inst->GetItem(sub_slot);
if (bag_inst) {
detail = new QSTradeItems_Struct;
detail->from_id = this->character_id;
detail->from_slot = trade_slot;
detail->to_id = other->CharacterID();
detail->to_slot = free_slot;
detail->item_id = bag_inst->GetID();
detail->charges = (!bag_inst->IsStackable() ? 1 : bag_inst->GetCharges());
detail->aug_1 = bag_inst->GetAugmentItemID(1);
detail->aug_2 = bag_inst->GetAugmentItemID(2);
detail->aug_3 = bag_inst->GetAugmentItemID(3);
detail->aug_4 = bag_inst->GetAugmentItemID(4);
detail->aug_5 = bag_inst->GetAugmentItemID(5);
event_details->push_back(detail);
if (finalizer)
qs_audit->char2_count += detail->charges;
else
qs_audit->char1_count += detail->charges;
}
}
}
}
else {
mlog(TRADING__ERROR, "Transfer of Item %s (%d) to %s failed, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID, other->GetName());
PushItemOnCursor(*inst, true);
}
}
else {
mlog(TRADING__ERROR, "%s's inventory is full, returning item %s (%d) to giver.", other->GetName(), inst->GetItem()->Name, inst->GetItem()->ID);
PushItemOnCursor(*inst, true);
}
}
else {
mlog(TRADING__ERROR, "Item %s (%d) is NoDrop, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID);
PushItemOnCursor(*inst, true);
}
DeleteItemInInventory(trade_slot);
} }
} }
@ -517,62 +784,72 @@ void Client::FinishTrade(Mob* tradingWith, ServerPacket* qspack, bool finalizer)
} }
} }
else if(tradingWith && tradingWith->IsNPC()) { else if(tradingWith && tradingWith->IsNPC()) {
QSPlayerLogHandin_Struct* qsaudit = nullptr; QSPlayerLogHandin_Struct* qs_audit = nullptr;
bool QSPLH = false; bool qs_log = false;
// QS code // QS code
if(qspack && RuleB(QueryServ, PlayerLogTrades)) { if(RuleB(QueryServ, PlayerLogTrades) && event_entry && event_details) {
// Currently provides only basic functionality. Calling method will also // Currently provides only basic functionality. Calling method will also
// need to be modified before item returns and rewards can be logged. -U // need to be modified before item returns and rewards can be logged. -U
qsaudit = (QSPlayerLogHandin_Struct*) qspack->pBuffer; qs_audit = (QSPlayerLogHandin_Struct*)event_entry;
QSPLH = true; qs_log = true;
qsaudit->quest_id = 0; qs_audit->quest_id = 0;
qsaudit->char_id = character_id; qs_audit->char_id = character_id;
qsaudit->char_money.platinum = trade->pp; qs_audit->char_money.platinum = trade->pp;
qsaudit->char_money.gold = trade->gp; qs_audit->char_money.gold = trade->gp;
qsaudit->char_money.silver = trade->sp; qs_audit->char_money.silver = trade->sp;
qsaudit->char_money.copper = trade->cp; qs_audit->char_money.copper = trade->cp;
qsaudit->char_count = 0; qs_audit->char_count = 0;
qsaudit->npc_id = tradingWith->GetNPCTypeID(); qs_audit->npc_id = tradingWith->GetNPCTypeID();
qsaudit->npc_money.platinum = 0; qs_audit->npc_money.platinum = 0;
qsaudit->npc_money.gold = 0; qs_audit->npc_money.gold = 0;
qsaudit->npc_money.silver = 0; qs_audit->npc_money.silver = 0;
qsaudit->npc_money.copper = 0; qs_audit->npc_money.copper = 0;
qsaudit->npc_count = 0; qs_audit->npc_count = 0;
} }
if(QSPLH) { // This can be incoporated below when revisions are made -U if(qs_log) { // This can be incorporated below when revisions are made -U
for(int16 slot_id = EmuConstants::TRADE_BEGIN; slot_id <= EmuConstants::TRADE_NPC_END; slot_id++) { for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_NPC_END; ++trade_slot) {
const ItemInst* trade_inst = m_inv[slot_id]; const ItemInst* trade_inst = m_inv[trade_slot];
if(trade_inst) { if(trade_inst) {
strcpy(qsaudit->items[qsaudit->char_count].action_type, "HANDIN"); QSHandinItems_Struct* detail = new QSHandinItems_Struct;
qsaudit->items[qsaudit->char_count].char_slot = slot_id; strcpy(detail->action_type, "HANDIN");
qsaudit->items[qsaudit->char_count].item_id = trade_inst->GetID();
qsaudit->items[qsaudit->char_count].charges = trade_inst->GetCharges(); detail->char_slot = trade_slot;
qsaudit->items[qsaudit->char_count].aug_1 = trade_inst->GetAugmentItemID(1); detail->item_id = trade_inst->GetID();
qsaudit->items[qsaudit->char_count].aug_2 = trade_inst->GetAugmentItemID(2); detail->charges = (!trade_inst->IsStackable() ? 1 : trade_inst->GetCharges());
qsaudit->items[qsaudit->char_count].aug_3 = trade_inst->GetAugmentItemID(3); detail->aug_1 = trade_inst->GetAugmentItemID(1);
qsaudit->items[qsaudit->char_count].aug_4 = trade_inst->GetAugmentItemID(4); detail->aug_2 = trade_inst->GetAugmentItemID(2);
qsaudit->items[qsaudit->char_count++].aug_5 = trade_inst->GetAugmentItemID(5); detail->aug_3 = trade_inst->GetAugmentItemID(3);
detail->aug_4 = trade_inst->GetAugmentItemID(4);
detail->aug_5 = trade_inst->GetAugmentItemID(5);
event_details->push_back(detail);
qs_audit->char_count += detail->charges;
if(trade_inst->IsType(ItemClassContainer)) { if(trade_inst->IsType(ItemClassContainer)) {
for(uint8 bag_idx = SUB_BEGIN; bag_idx < trade_inst->GetItem()->BagSlots; bag_idx++) { for (uint8 sub_slot = SUB_BEGIN; sub_slot < trade_inst->GetItem()->BagSlots; ++sub_slot) {
const ItemInst* trade_baginst = trade_inst->GetItem(bag_idx); const ItemInst* trade_baginst = trade_inst->GetItem(sub_slot);
if(trade_baginst) { if(trade_baginst) {
strcpy(qsaudit->items[qsaudit->char_count].action_type, "HANDIN"); detail = new QSHandinItems_Struct;
qsaudit->items[qsaudit->char_count].char_slot = Inventory::CalcSlotId(slot_id, bag_idx); strcpy(detail->action_type, "HANDIN");
qsaudit->items[qsaudit->char_count].item_id = trade_baginst->GetID();
qsaudit->items[qsaudit->char_count].charges = trade_baginst->GetCharges(); detail->char_slot = Inventory::CalcSlotId(trade_slot, sub_slot);
qsaudit->items[qsaudit->char_count].aug_1 = trade_baginst->GetAugmentItemID(1); detail->item_id = trade_baginst->GetID();
qsaudit->items[qsaudit->char_count].aug_2 = trade_baginst->GetAugmentItemID(2); detail->charges = (!trade_inst->IsStackable() ? 1 : trade_inst->GetCharges());
qsaudit->items[qsaudit->char_count].aug_3 = trade_baginst->GetAugmentItemID(3); detail->aug_1 = trade_baginst->GetAugmentItemID(1);
qsaudit->items[qsaudit->char_count].aug_4 = trade_baginst->GetAugmentItemID(4); detail->aug_2 = trade_baginst->GetAugmentItemID(2);
qsaudit->items[qsaudit->char_count++].aug_5 = trade_baginst->GetAugmentItemID(5); detail->aug_3 = trade_baginst->GetAugmentItemID(3);
detail->aug_4 = trade_baginst->GetAugmentItemID(4);
detail->aug_5 = trade_baginst->GetAugmentItemID(5);
event_details->push_back(detail);
qs_audit->char_count += detail->charges;
} }
} }
} }
@ -586,7 +863,7 @@ void Client::FinishTrade(Mob* tradingWith, ServerPacket* qspack, bool finalizer)
quest_npc = true; quest_npc = true;
} }
std::vector<void*> item_list; std::vector<EQEmu::Any> item_list;
uint32 items[4] = { 0 }; uint32 items[4] = { 0 };
for(int i = EmuConstants::TRADE_BEGIN; i <= EmuConstants::TRADE_NPC_END; ++i) { for(int i = EmuConstants::TRADE_BEGIN; i <= EmuConstants::TRADE_NPC_END; ++i) {
ItemInst *inst = m_inv.GetItem(i); ItemInst *inst = m_inv.GetItem(i);

View File

@ -262,19 +262,17 @@ Mob* EntityList::GetTrapTrigger(Trap* trap) {
//todo: rewrite this to not need direct access to trap members. //todo: rewrite this to not need direct access to trap members.
bool ZoneDatabase::LoadTraps(const char* zonename, int16 version) { bool ZoneDatabase::LoadTraps(const char* zonename, int16 version) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
// int char_num = 0; std::string query = StringFormat("SELECT id, x, y, z, effect, effectvalue, effectvalue2, skill, "
unsigned long* lengths; "maxzdiff, radius, chance, message, respawn_time, respawn_var, level "
"FROM traps WHERE zone='%s' AND version=%u", zonename, version);
auto results = QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in LoadTraps query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return false;
}
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id,x,y,z,effect,effectvalue,effectvalue2,skill,maxzdiff,radius,chance,message,respawn_time,respawn_var,level FROM traps WHERE zone='%s' AND version=%u", zonename, version), errbuf, &result)) { for (auto row = results.begin(); row != results.end(); ++row) {
safe_delete_array(query);
while ((row = mysql_fetch_row(result)))
{
lengths = mysql_fetch_lengths(result);
Trap* trap = new Trap(); Trap* trap = new Trap();
trap->trap_id = atoi(row[0]); trap->trap_id = atoi(row[0]);
trap->x = atof(row[1]); trap->x = atof(row[1]);
@ -294,13 +292,6 @@ bool ZoneDatabase::LoadTraps(const char* zonename, int16 version) {
entity_list.AddTrap(trap); entity_list.AddTrap(trap);
trap->CreateHiddenTrigger(); trap->CreateHiddenTrigger();
} }
mysql_free_result(result);
}
else {
LogFile->write(EQEMuLog::Error, "Error in LoadTraps query '%s': %s", query, errbuf);
safe_delete_array(query);
return false;
}
return true; return true;
} }

View File

@ -378,42 +378,39 @@ void Client::SendGuildTributes() {
} }
bool ZoneDatabase::LoadTributes() { bool ZoneDatabase::LoadTributes() {
char errbuf[MYSQL_ERRMSG_SIZE];
MYSQL_RES *result;
MYSQL_ROW row;
TributeData t; TributeData tributeData;
memset(&t.tiers, 0, sizeof(t.tiers)); memset(&tributeData.tiers, 0, sizeof(tributeData.tiers));
t.tier_count = 0; tributeData.tier_count = 0;
tribute_list.clear(); tribute_list.clear();
const char *query = "SELECT id,name,descr,unknown,isguild FROM tributes"; const std::string query = "SELECT id, name, descr, unknown, isguild FROM tributes";
if (RunQuery(query, strlen(query), errbuf, &result)) { auto results = QueryDatabase(query);
int r; if (!results.Success()) {
while ((row = mysql_fetch_row(result))) { LogFile->write(EQEMuLog::Error, "Error in LoadTributes first query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
r = 0;
uint32 id = atoul(row[r++]);
t.name = row[r++];
t.description = row[r++];
t.unknown = strtoul(row[r++], nullptr, 10);
t.is_guild = atol(row[r++])==0?false:true;
tribute_list[id] = t;
}
mysql_free_result(result);
} else {
LogFile->write(EQEMuLog::Error, "Error in LoadTributes first query '%s': %s", query, errbuf);
return false; return false;
} }
for (auto row = results.begin(); row != results.end(); ++row) {
uint32 id = atoul(row[0]);
tributeData.name = row[1];
tributeData.description = row[2];
tributeData.unknown = strtoul(row[3], nullptr, 10);
tributeData.is_guild = atol(row[4]) == 0? false: true;
const char *query2 = "SELECT tribute_id,level,cost,item_id FROM tribute_levels ORDER BY tribute_id,level"; tribute_list[id] = tributeData;
if (RunQuery(query2, strlen(query2), errbuf, &result)) { }
int r;
while ((row = mysql_fetch_row(result))) { const std::string query2 = "SELECT tribute_id, level, cost, item_id FROM tribute_levels ORDER BY tribute_id, level";
r = 0; results = QueryDatabase(query2);
uint32 id = atoul(row[r++]); if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error in LoadTributes level query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return false;
}
for (auto row = results.begin(); row != results.end(); ++row) {
uint32 id = atoul(row[0]);
if(tribute_list.count(id) != 1) { if(tribute_list.count(id) != 1) {
LogFile->write(EQEMuLog::Error, "Error in LoadTributes: unknown tribute %lu in tribute_levels", (unsigned long)id); LogFile->write(EQEMuLog::Error, "Error in LoadTributes: unknown tribute %lu in tribute_levels", (unsigned long)id);
@ -429,16 +426,11 @@ bool ZoneDatabase::LoadTributes() {
TributeLevel_Struct &s = cur.tiers[cur.tier_count]; TributeLevel_Struct &s = cur.tiers[cur.tier_count];
s.level = atoul(row[r++]); s.level = atoul(row[1]);
s.cost = atoul(row[r++]); s.cost = atoul(row[2]);
s.tribute_item_id = atoul(row[r++]); s.tribute_item_id = atoul(row[3]);
cur.tier_count++; cur.tier_count++;
} }
mysql_free_result(result);
} else {
LogFile->write(EQEMuLog::Error, "Error in LoadTributes level query '%s': %s", query, errbuf);
return false;
}
return true; return true;
} }

View File

@ -869,55 +869,45 @@ void NPC::AssignWaypoints(int32 grid) {
return; return;
} }
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
bool GridErr = false, WPErr = false;
Waypoints.clear(); Waypoints.clear();
roamer = false;
// Retrieve the wander and pause types for this grid // Retrieve the wander and pause types for this grid
if(database.RunQuery(query,MakeAnyLenString(&query,"SELECT `type`,`type2` FROM `grid` WHERE `id`=%i AND `zoneid`=%i",grid,zone->GetZoneID()),errbuf, &result)) std::string query = StringFormat("SELECT `type`, `type2` FROM `grid` WHERE `id` = %i AND `zoneid` = %i", grid, zone->GetZoneID());
{ auto results = database.QueryDatabase(query);
if((row = mysql_fetch_row(result))) if (!results.Success()) {
{ LogFile->write(EQEMuLog::Error, "MySQL Error while trying to assign grid %u to mob %s: %s", grid, name, results.ErrorMessage().c_str());
if(row[0] != 0) return;
wandertype = atoi(row[0]);
else
wandertype = 0;
if(row[1] != 0)
pausetype = atoi(row[1]);
else
pausetype = 0;
} }
else // No grid record found in this zone for the given ID
GridErr = true;
mysql_free_result(result);
}
else // DB query error!
{
GridErr = true;
LogFile->write(EQEMuLog::Error, "MySQL Error while trying to assign grid %u to mob %s: %s", grid, name, errbuf);
}
safe_delete_array(query);
if(!GridErr) if (results.RowCount() == 0)
{ return;
auto row = results.begin();
wandertype = atoi(row[0]);
pausetype = atoi(row[1]);
this->CastToNPC()->SetGrid(grid); // Assign grid number this->CastToNPC()->SetGrid(grid); // Assign grid number
// Retrieve all waypoints for this grid // Retrieve all waypoints for this grid
if(database.RunQuery(query,MakeAnyLenString(&query,"SELECT `x`,`y`,`z`,`pause`,`heading` FROM grid_entries WHERE `gridid`=%i AND `zoneid`=%i ORDER BY `number`",grid,zone->GetZoneID()),errbuf,&result)) query = StringFormat("SELECT `x`,`y`,`z`,`pause`,`heading` "
{ "FROM grid_entries WHERE `gridid` = %i AND `zoneid` = %i "
roamer = true; "ORDER BY `number`", grid, zone->GetZoneID());
max_wp = -1; // Initialize it; will increment it for each waypoint successfully added to the list results = database.QueryDatabase(query);
if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "MySQL Error while trying to assign waypoints from grid %u to mob %s: %s", grid, name, results.ErrorMessage().c_str());
return;
}
while((row = mysql_fetch_row(result))) roamer = true;
{ max_wp = 0; // Initialize it; will increment it for each waypoint successfully added to the list
if(row[0] != 0 && row[1] != 0 && row[2] != 0 && row[3] != 0)
for (auto row = results.begin(); row != results.end(); ++row, ++max_wp)
{ {
wplist newwp; wplist newwp;
newwp.index = ++max_wp; newwp.index = max_wp;
newwp.x = atof(row[0]); newwp.x = atof(row[0]);
newwp.y = atof(row[1]); newwp.y = atof(row[1]);
newwp.z = atof(row[2]); newwp.z = atof(row[2]);
@ -940,26 +930,17 @@ void NPC::AssignWaypoints(int32 grid) {
newwp.heading = atof(row[4]); newwp.heading = atof(row[4]);
Waypoints.push_back(newwp); Waypoints.push_back(newwp);
} }
}
mysql_free_result(result);
}
else // DB query error!
{
WPErr = true;
LogFile->write(EQEMuLog::Error, "MySQL Error while trying to assign waypoints from grid %u to mob %s: %s", grid, name, errbuf);
}
safe_delete_array(query);
} // end if (!GridErr)
if(Waypoints.size() < 2) { if(Waypoints.size() < 2) {
roamer = false; roamer = false;
} else if(!GridErr && !WPErr) { }
UpdateWaypoint(0); UpdateWaypoint(0);
SetWaypointPause(); SetWaypointPause();
if (wandertype == 1 || wandertype == 2 || wandertype == 5) if (wandertype == 1 || wandertype == 2 || wandertype == 5)
CalculateNewWaypoint(); CalculateNewWaypoint();
} else {
roamer = false;
}
} }
void Mob::SendTo(float new_x, float new_y, float new_z) { void Mob::SendTo(float new_x, float new_y, float new_z) {
@ -1049,159 +1030,123 @@ int ZoneDatabase::GetHighestGrid(uint32 zoneid) {
} }
uint8 ZoneDatabase::GetGridType2(uint32 grid, uint16 zoneid) { uint8 ZoneDatabase::GetGridType2(uint32 grid, uint16 zoneid) {
char *query = 0;
char errbuff[MYSQL_ERRMSG_SIZE];
MYSQL_RES *result;
MYSQL_ROW row;
int type2 = 0; int type2 = 0;
if (RunQuery(query, MakeAnyLenString(&query,"SELECT type2 from grid where id = %i and zoneid = %i",grid,zoneid),errbuff,&result)) { std::string query = StringFormat("SELECT type2 FROM grid WHERE id = %i AND zoneid = %i", grid, zoneid);
safe_delete_array(query); auto results = QueryDatabase(query);
if (mysql_num_rows(result) == 1) { if (!results.Success()) {
row = mysql_fetch_row(result); LogFile->write(EQEMuLog::Error, "Error in GetGridType2 query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
type2 = atoi( row[0] ); return 0;
}
mysql_free_result(result);
} else {
LogFile->write(EQEMuLog::Error, "Error in GetGridType2 query '%s': %s", query, errbuff);
safe_delete_array(query);
} }
return(type2); if (results.RowCount() != 1)
return 0;
auto row = results.begin();
return atoi(row[0]);
} }
bool ZoneDatabase::GetWaypoints(uint32 grid, uint16 zoneid, uint32 num, wplist* wp) { bool ZoneDatabase::GetWaypoints(uint32 grid, uint16 zoneid, uint32 num, wplist* wp) {
char *query = 0;
char errbuff[MYSQL_ERRMSG_SIZE]; if (wp == nullptr)
MYSQL_RES *result; return false;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query,"SELECT x, y, z, pause, heading from grid_entries where gridid = %i and number = %i and zoneid = %i",grid,num,zoneid),errbuff,&result)) { std::string query = StringFormat("SELECT x, y, z, pause, heading FROM grid_entries "
safe_delete_array(query); "WHERE gridid = %i AND number = %i AND zoneid = %i", grid, num, zoneid);
if (mysql_num_rows(result) == 1) { auto results = QueryDatabase(query);
row = mysql_fetch_row(result); if (!results.Success()) {
if ( wp ) { LogFile->write(EQEMuLog::Error, "Error in GetWaypoints query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
return false;
}
if (results.RowCount() != 1)
return false;
auto row = results.begin();
wp->x = atof(row[0]); wp->x = atof(row[0]);
wp->y = atof(row[1]); wp->y = atof(row[1]);
wp->z = atof(row[2]); wp->z = atof(row[2]);
wp->pause = atoi(row[3]); wp->pause = atoi(row[3]);
wp->heading = atof(row[4]); wp->heading = atof(row[4]);
}
mysql_free_result(result);
return true; return true;
} }
mysql_free_result(result);
}
else {
LogFile->write(EQEMuLog::Error, "Error in GetWaypoints query '%s': %s", query, errbuff);
safe_delete_array(query);
}
return false;
}
void ZoneDatabase::AssignGrid(Client *client, float x, float y, uint32 grid) void ZoneDatabase::AssignGrid(Client *client, float x, float y, uint32 grid)
{ {
char *query = 0;
char errbuf[MYSQL_ERRMSG_SIZE];
MYSQL_RES *result;
MYSQL_ROW row;
int matches = 0, fuzzy = 0, spawn2id = 0; int matches = 0, fuzzy = 0, spawn2id = 0;
uint32 affected_rows;
float dbx = 0, dby = 0; float dbx = 0, dby = 0;
// looks like most of the stuff in spawn2 is straight integers // looks like most of the stuff in spawn2 is straight integers
// so let's try that first // so let's try that first
if(!RunQuery( std::string query = StringFormat("SELECT id, x, y FROM spawn2 WHERE zone = '%s' AND x = %i AND y = %i",
query, zone->GetShortName(), (int)x, (int)y);
MakeAnyLenString( auto results = QueryDatabase(query);
&query, if(!results.Success()) {
"SELECT id,x,y FROM spawn2 WHERE zone='%s' AND x=%i AND y=%i", LogFile->write(EQEMuLog::Error, "Error querying spawn2 '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
zone->GetShortName(), (int)x, (int)y
),
errbuf,
&result
)) {
LogFile->write(EQEMuLog::Error, "Error querying spawn2 '%s': '%s'", query, errbuf);
return; return;
} }
safe_delete_array(query);
// how much it's allowed to be off by // how much it's allowed to be off by
#define _GASSIGN_TOLERANCE 1.0 #define _GASSIGN_TOLERANCE 1.0
if(!(matches = mysql_num_rows(result))) // try a fuzzy match if that didn't find it if(results.RowCount() == 0) // try a fuzzy match if that didn't find it
{ {
mysql_free_result(result); query = StringFormat("SELECT id,x,y FROM spawn2 WHERE zone='%s' AND "
if(!RunQuery(
query,
MakeAnyLenString(
&query,
"SELECT id,x,y FROM spawn2 WHERE zone='%s' AND "
"ABS( ABS(x) - ABS(%f) ) < %f AND " "ABS( ABS(x) - ABS(%f) ) < %f AND "
"ABS( ABS(y) - ABS(%f) ) < %f", "ABS( ABS(y) - ABS(%f) ) < %f",
zone->GetShortName(), x, _GASSIGN_TOLERANCE, y, _GASSIGN_TOLERANCE zone->GetShortName(), x, _GASSIGN_TOLERANCE, y, _GASSIGN_TOLERANCE);
), results = QueryDatabase(query);
errbuf, if(!results.Success()) {
&result LogFile->write(EQEMuLog::Error, "Error querying fuzzy spawn2 '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
)) {
LogFile->write(EQEMuLog::Error, "Error querying fuzzy spawn2 '%s': '%s'", query, errbuf);
return; return;
} }
safe_delete_array(query);
fuzzy = 1; fuzzy = 1;
if(!(matches = mysql_num_rows(result))) matches = results.RowCount();
mysql_free_result(result);
} }
if(matches)
{ if (matches == 0) {
if(matches > 1) client->Message(0, "ERROR: Unable to assign grid - can't find it in spawn2");
return;
}
if(matches == 1)
{ {
client->Message(0, "ERROR: Unable to assign grid - multiple spawn2 rows match"); client->Message(0, "ERROR: Unable to assign grid - multiple spawn2 rows match");
mysql_free_result(result); return;
} }
else
{ auto row = results.begin();
row = mysql_fetch_row(result);
spawn2id = atoi(row[0]); spawn2id = atoi(row[0]);
dbx = atof(row[1]); dbx = atof(row[1]);
dby = atof(row[2]); dby = atof(row[2]);
if(!RunQuery(
query, query = StringFormat("UPDATE spawn2 SET pathgrid = %d WHERE id = %d", grid, spawn2id);
MakeAnyLenString( results = QueryDatabase(query);
&query, if (!results.Success())
"UPDATE spawn2 SET pathgrid = %d WHERE id = %d", grid, spawn2id {
), LogFile->write(EQEMuLog::Error, "Error updating spawn2 '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
errbuf,
&result,
&affected_rows
)) {
LogFile->write(EQEMuLog::Error, "Error updating spawn2 '%s': '%s'", query, errbuf);
return; return;
} }
if(affected_rows == 1)
{ if (results.RowsAffected() != 1) {
if(client) client->LogSQL(query);
if(fuzzy)
{
float difference;
difference = sqrtf(pow(fabs(x-dbx),2) + pow(fabs(y-dby),2));
client->Message(0,
"Grid assign: spawn2 id = %d updated - fuzzy match: deviation %f",
spawn2id, difference
);
}
else
{
client->Message(0, "Grid assign: spawn2 id = %d updated - exact match", spawn2id);
}
}
else
{
client->Message(0, "ERROR: found spawn2 id %d but the update query failed", spawn2id); client->Message(0, "ERROR: found spawn2 id %d but the update query failed", spawn2id);
return;
} }
if(client)
client->LogSQL(query.c_str());
if(!fuzzy) {
client->Message(0, "Grid assign: spawn2 id = %d updated - exact match", spawn2id);
return;
} }
}
else float difference = sqrtf(pow(fabs(x - dbx) , 2) + pow(fabs(y - dby), 2));
{ client->Message(0, "Grid assign: spawn2 id = %d updated - fuzzy match: deviation %f", spawn2id, difference);
client->Message(0, "ERROR: Unable to assign grid - can't find it in spawn2");
}
} }
/****************** /******************
@ -1211,53 +1156,57 @@ void ZoneDatabase::AssignGrid(Client *client, float x, float y, uint32 grid)
* type,type2: The type and type2 values for the grid being created (ignored if grid is being deleted) * type,type2: The type and type2 values for the grid being created (ignored if grid is being deleted)
* zoneid: The ID number of the zone the grid is being created/deleted in * zoneid: The ID number of the zone the grid is being created/deleted in
*/ */
void ZoneDatabase::ModifyGrid(Client *client, bool remove, uint32 id, uint8 type, uint8 type2, uint16 zoneid) {
void ZoneDatabase::ModifyGrid(Client *c, bool remove, uint32 id, uint8 type, uint8 type2, uint16 zoneid) {
char *query = 0;
char errbuf[MYSQL_ERRMSG_SIZE];
if (!remove) if (!remove)
{ {
if(!RunQuery(query, MakeAnyLenString(&query,"INSERT INTO grid(id,zoneid,type,type2) VALUES(%i,%i,%i,%i)",id,zoneid,type,type2), errbuf)) { std::string query = StringFormat("INSERT INTO grid(id, zoneid, type, type2) "
LogFile->write(EQEMuLog::Error, "Error creating grid entry '%s': '%s'", query, errbuf); "VALUES (%i, %i, %i, %i)", id, zoneid, type, type2);
} else { auto results = QueryDatabase(query);
if(c) c->LogSQL(query); if (!results.Success()) {
LogFile->write(EQEMuLog::Error, "Error creating grid entry '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
return;
} }
safe_delete_array(query);
if(client)
client->LogSQL(query.c_str());
return;
} }
else
{ std::string query = StringFormat("DELETE FROM grid where id=%i", id);
if(!RunQuery(query, MakeAnyLenString(&query,"DELETE FROM grid where id=%i",id), errbuf)) { auto results = QueryDatabase(query);
LogFile->write(EQEMuLog::Error, "Error deleting grid '%s': '%s'", query, errbuf); if (!results.Success())
} else { LogFile->write(EQEMuLog::Error, "Error deleting grid '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
if(c) c->LogSQL(query); else if(client)
client->LogSQL(query.c_str());
query = StringFormat("DELETE FROM grid_entries WHERE zoneid = %i AND gridid = %i", zoneid, id);
results = QueryDatabase(query);
if(!results.Success())
LogFile->write(EQEMuLog::Error, "Error deleting grid entries '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
else if(client)
client->LogSQL(query.c_str());
} }
safe_delete_array(query);
query = 0;
if(!RunQuery(query, MakeAnyLenString(&query,"DELETE FROM grid_entries WHERE zoneid=%i AND gridid=%i",zoneid,id), errbuf)) {
LogFile->write(EQEMuLog::Error, "Error deleting grid entries '%s': '%s'", query, errbuf);
} else {
if(c) c->LogSQL(query);
}
safe_delete_array(query);
}
} /*** END ZoneDatabase::ModifyGrid() ***/
/************************************** /**************************************
* AddWP - Adds a new waypoint to a specific grid for a specific zone. * AddWP - Adds a new waypoint to a specific grid for a specific zone.
*/ */
void ZoneDatabase::AddWP(Client *client, uint32 gridid, uint32 wpnum, float xpos, float ypos, float zpos, uint32 pause, uint16 zoneid, float heading)
void ZoneDatabase::AddWP(Client *c, uint32 gridid, uint32 wpnum, float xpos, float ypos, float zpos, uint32 pause, uint16 zoneid, float heading)
{ {
char *query = 0; std::string query = StringFormat("INSERT INTO grid_entries (gridid, zoneid, `number`, x, y, z, pause, heading) "
char errbuf[MYSQL_ERRMSG_SIZE]; "VALUES (%i, %i, %i, %f, %f, %f, %i, %f)",
gridid, zoneid, wpnum, xpos, ypos, zpos, pause, heading);
if(!RunQuery(query,MakeAnyLenString(&query,"INSERT INTO grid_entries (gridid,zoneid,`number`,x,y,z,pause,heading) values (%i,%i,%i,%f,%f,%f,%i,%f)",gridid,zoneid,wpnum,xpos,ypos,zpos,pause,heading), errbuf)) { auto results = QueryDatabase(query);
LogFile->write(EQEMuLog::Error, "Error adding waypoint '%s': '%s'", query, errbuf); if (!results.Success()) {
} else { LogFile->write(EQEMuLog::Error, "Error adding waypoint '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
if(c) c->LogSQL(query); return;
}
if(client)
client->LogSQL(query.c_str());
} }
safe_delete_array(query);
} /*** END ZoneDatabase::AddWP() ***/
/********** /**********
@ -1270,19 +1219,20 @@ void ZoneDatabase::AddWP(Client *c, uint32 gridid, uint32 wpnum, float xpos, flo
* wp_num: The number of the waypoint being deleted * wp_num: The number of the waypoint being deleted
* zoneid: The ID number of the zone that contains the waypoint being deleted * zoneid: The ID number of the zone that contains the waypoint being deleted
*/ */
void ZoneDatabase::DeleteWaypoint(Client *client, uint32 grid_num, uint32 wp_num, uint16 zoneid)
void ZoneDatabase::DeleteWaypoint(Client *c, uint32 grid_num, uint32 wp_num, uint16 zoneid)
{ {
char *query=0; std::string query = StringFormat("DELETE FROM grid_entries WHERE "
char errbuf[MYSQL_ERRMSG_SIZE]; "gridid = %i AND zoneid = %i AND `number` = %i",
grid_num, zoneid, wp_num);
if(!RunQuery(query, MakeAnyLenString(&query,"DELETE FROM grid_entries where gridid=%i and zoneid=%i and `number`=%i",grid_num,zoneid,wp_num), errbuf)) { auto results = QueryDatabase(query);
LogFile->write(EQEMuLog::Error, "Error deleting waypoint '%s': '%s'", query, errbuf); if(!results.Success()) {
} else { LogFile->write(EQEMuLog::Error, "Error deleting waypoint '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
if(c) c->LogSQL(query); return;
}
if(client)
client->LogSQL(query.c_str());
} }
safe_delete_array(query);
} /*** END ZoneDatabase::DeleteWaypoint() ***/
/****************** /******************
@ -1292,139 +1242,112 @@ void ZoneDatabase::DeleteWaypoint(Client *c, uint32 grid_num, uint32 wp_num, uin
* Returns 0 if the function didn't have to create a new grid. If the function had to create a new grid for the spawn, then the ID of * Returns 0 if the function didn't have to create a new grid. If the function had to create a new grid for the spawn, then the ID of
* the created grid is returned. * the created grid is returned.
*/ */
uint32 ZoneDatabase::AddWPForSpawn(Client *client, uint32 spawn2id, float xpos, float ypos, float zpos, uint32 pause, int type1, int type2, uint16 zoneid, float heading) {
uint32 ZoneDatabase::AddWPForSpawn(Client *c, uint32 spawn2id, float xpos, float ypos, float zpos, uint32 pause, int type1, int type2, uint16 zoneid, float heading) { uint32 grid_num; // The grid number the spawn is assigned to (if spawn has no grid, will be the grid number we end up creating)
char *query = 0; uint32 next_wp_num; // The waypoint number we should be assigning to the new waypoint
uint32 grid_num, // The grid number the spawn is assigned to (if spawn has no grid, will be the grid number we end up creating) bool createdNewGrid; // Did we create a new grid in this function?
next_wp_num; // The waypoint number we should be assigning to the new waypoint
bool CreatedNewGrid; // Did we create a new grid in this function?
MYSQL_RES *result;
MYSQL_ROW row;
char errbuf[MYSQL_ERRMSG_SIZE];
// See what grid number our spawn is assigned // See what grid number our spawn is assigned
if(RunQuery(query, MakeAnyLenString(&query,"SELECT pathgrid FROM spawn2 WHERE id=%i",spawn2id),errbuf,&result)) std::string query = StringFormat("SELECT pathgrid FROM spawn2 WHERE id = %i", spawn2id);
{ auto results = QueryDatabase(query);
safe_delete_array(query); if (!results.Success()) {
if(mysql_num_rows(result) > 0) // Query error
{ LogFile->write(EQEMuLog::Error, "Error setting pathgrid '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
row = mysql_fetch_row(result); return 0;
}
if (results.RowCount() == 0)
return 0;
auto row = results.begin();
grid_num = atoi(row[0]); grid_num = atoi(row[0]);
}
else // This spawn ID was not found in the `spawn2` table
return 0;
mysql_free_result(result); if (grid_num == 0)
} { // Our spawn doesn't have a grid assigned to it -- we need to create a new grid and assign it to the spawn
else { // Query error createdNewGrid = true;
LogFile->write(EQEMuLog::Error, "Error setting pathgrid '%s': '%s'", query, errbuf); grid_num = GetFreeGrid(zoneid);
return 0; if(grid_num == 0) // There are no grids for the current zone -- create Grid #1
}
if (grid_num == 0) // Our spawn doesn't have a grid assigned to it -- we need to create a new grid and assign it to the spawn
{
CreatedNewGrid = true;
if((grid_num = GetFreeGrid(zoneid)) == 0) // There are no grids for the current zone -- create Grid #1
grid_num = 1; grid_num = 1;
if(!RunQuery(query, MakeAnyLenString(&query,"insert into grid set id='%i',zoneid= %i, type='%i', type2='%i'",grid_num,zoneid,type1,type2), errbuf)) { query = StringFormat("INSERT INTO grid SET id = '%i', zoneid = %i, type ='%i', type2 = '%i'",
LogFile->write(EQEMuLog::Error, "Error adding grid '%s': '%s'", query, errbuf); grid_num, zoneid, type1, type2);
} else { results = QueryDatabase(query);
if(c) c->LogSQL(query); if(!results.Success())
} LogFile->write(EQEMuLog::Error, "Error adding grid '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
safe_delete_array(query); else if(client)
client->LogSQL(query.c_str());
query = 0; query = StringFormat("UPDATE spawn2 SET pathgrid = '%i' WHERE id = '%i'", grid_num, spawn2id);
if(!RunQuery(query, MakeAnyLenString(&query,"update spawn2 set pathgrid='%i' where id='%i'",grid_num,spawn2id), errbuf)) { results = QueryDatabase(query);
LogFile->write(EQEMuLog::Error, "Error updating spawn2 pathing '%s': '%s'", query, errbuf); if(!results.Success())
} else { LogFile->write(EQEMuLog::Error, "Error updating spawn2 pathing '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
if(c) c->LogSQL(query); else if(client)
} client->LogSQL(query.c_str());
safe_delete_array(query);
} }
else // NPC had a grid assigned to it else // NPC had a grid assigned to it
CreatedNewGrid = false; createdNewGrid = false;
// Find out what the next waypoint is for this grid // Find out what the next waypoint is for this grid
query = 0; query = StringFormat("SELECT max(`number`) FROM grid_entries WHERE zoneid = '%i' AND gridid = '%i'", zoneid, grid_num);
if(RunQuery(query, MakeAnyLenString(&query,"SELECT max(`number`) FROM grid_entries WHERE zoneid='%i' AND gridid='%i'",zoneid,grid_num),errbuf,&result))
{ if(!results.Success()) { // Query error
safe_delete_array(query); LogFile->write(EQEMuLog::Error, "Error getting next waypoint id '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
row = mysql_fetch_row(result); return 0;
}
row = results.begin();
if(row[0] != 0) if(row[0] != 0)
next_wp_num = atoi(row[0]) + 1; next_wp_num = atoi(row[0]) + 1;
else // No waypoints in this grid yet else // No waypoints in this grid yet
next_wp_num = 1; next_wp_num = 1;
mysql_free_result(result); query = StringFormat("INSERT INTO grid_entries(gridid, zoneid, `number`, x, y, z, pause, heading) "
"VALUES (%i, %i, %i, %f, %f, %f, %i, %f)",
grid_num, zoneid, next_wp_num, xpos, ypos, zpos, pause, heading);
results = QueryDatabase(query);
if(!results.Success())
LogFile->write(EQEMuLog::Error, "Error adding grid entry '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
else if(client)
client->LogSQL(query.c_str());
return createdNewGrid? grid_num: 0;
} }
else { // Query error
LogFile->write(EQEMuLog::Error, "Error getting next waypoint id '%s': '%s'", query, errbuf);
return 0;
}
query = 0;
if(!RunQuery(query, MakeAnyLenString(&query,"INSERT INTO grid_entries(gridid,zoneid,`number`,x,y,z,pause,heading) VALUES (%i,%i,%i,%f,%f,%f,%i,%f)",grid_num,zoneid,next_wp_num,xpos,ypos,zpos,pause,heading), errbuf)) {
LogFile->write(EQEMuLog::Error, "Error adding grid entry '%s': '%s'", query, errbuf);
} else {
if(c) c->LogSQL(query);
}
safe_delete_array(query);
if(CreatedNewGrid)
return grid_num;
return 0;
} /*** END ZoneDatabase::AddWPForSpawn() ***/
uint32 ZoneDatabase::GetFreeGrid(uint16 zoneid) { uint32 ZoneDatabase::GetFreeGrid(uint16 zoneid) {
char *query = 0;
char errbuf[MYSQL_ERRMSG_SIZE]; std::string query = StringFormat("SELECT max(id) FROM grid WHERE zoneid = %i", zoneid);
MYSQL_RES *result; auto results = QueryDatabase(query);
MYSQL_ROW row; if (!results.Success()) {
if (RunQuery(query, MakeAnyLenString(&query,"SELECT max(id) from grid where zoneid = %i",zoneid),errbuf,&result)) { LogFile->write(EQEMuLog::Error, "Error in GetFreeGrid query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
safe_delete_array(query);
if (mysql_num_rows(result) == 1) {
row = mysql_fetch_row(result);
uint32 tmp=0;
if (row[0])
tmp = atoi(row[0]);
mysql_free_result(result);
tmp++;
return tmp;
}
mysql_free_result(result);
}
else {
LogFile->write(EQEMuLog::Error, "Error in GetFreeGrid query '%s': %s", query, errbuf);
safe_delete_array(query);
}
return 0; return 0;
} }
if (results.RowCount() != 1)
return 0;
auto row = results.begin();
uint32 freeGridID = 1;
freeGridID = atoi(row[0]) + 1;
return freeGridID;
}
int ZoneDatabase::GetHighestWaypoint(uint32 zoneid, uint32 gridid) { int ZoneDatabase::GetHighestWaypoint(uint32 zoneid, uint32 gridid) {
char *query = 0;
char errbuff[MYSQL_ERRMSG_SIZE]; std::string query = StringFormat("SELECT COALESCE(MAX(number), 0) FROM grid_entries "
MYSQL_RES *result; "WHERE zoneid = %i AND gridid = %i", zoneid, gridid);
MYSQL_ROW row; auto results = QueryDatabase(query);
int res = 0; if (!results.Success()) {
if (RunQuery(query, MakeAnyLenString(&query, LogFile->write(EQEMuLog::Error, "Error in GetHighestWaypoint query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
"SELECT COALESCE(MAX(number), 0) FROM grid_entries WHERE zoneid = %i AND gridid = %i", return 0;
zoneid, gridid),errbuff,&result)) {
safe_delete_array(query);
if (mysql_num_rows(result) == 1) {
row = mysql_fetch_row(result);
res = atoi( row[0] );
}
mysql_free_result(result);
} else {
LogFile->write(EQEMuLog::Error, "Error in GetHighestWaypoint query '%s': %s", query, errbuff);
safe_delete_array(query);
} }
return(res); if (results.RowCount() != 1)
return 0;
auto row = results.begin();
return atoi(row[0]);
} }
void NPC::SaveGuardSpotCharm() void NPC::SaveGuardSpotCharm()

View File

@ -718,11 +718,24 @@ void Zone::DBAWComplete(uint8 workpt_b1, DBAsyncWork* dbaw) {
} }
} }
bool Zone::IsLoaded() {
return ZoneLoaded;
}
void Zone::Shutdown(bool quite) void Zone::Shutdown(bool quite)
{ {
if (!ZoneLoaded) if (!ZoneLoaded)
return; return;
std::list<Mob*> mob_list;
entity_list.GetMobList(mob_list);
std::list<Mob*>::iterator mob_itr = mob_list.begin();
while (mob_itr != mob_list.end()) {
Mob* mob_inst = *mob_itr;
mob_inst->AI_Stop();
++mob_itr;
}
std::map<uint32,NPCType *>::iterator itr; std::map<uint32,NPCType *>::iterator itr;
while(zone->npctable.size()) { while(zone->npctable.size()) {
itr=zone->npctable.begin(); itr=zone->npctable.begin();
@ -1678,22 +1691,23 @@ ZonePoint* Zone::GetClosestZonePointWithoutZone(float x, float y, float z, Clien
bool ZoneDatabase::LoadStaticZonePoints(LinkedList<ZonePoint*>* zone_point_list, const char* zonename, uint32 version) bool ZoneDatabase::LoadStaticZonePoints(LinkedList<ZonePoint*>* zone_point_list, const char* zonename, uint32 version)
{ {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
zone_point_list->Clear(); zone_point_list->Clear();
zone->numzonepoints = 0; zone->numzonepoints = 0;
MakeAnyLenString(&query, "SELECT x, y, z, target_x, target_y, " std::string query = StringFormat("SELECT x, y, z, target_x, target_y, "
"target_z, target_zone_id, heading, target_heading, number, " "target_z, target_zone_id, heading, target_heading, "
"target_instance, client_version_mask FROM zone_points " "number, target_instance, client_version_mask "
"WHERE zone='%s' AND (version=%i OR version=-1) order by number", zonename, version); "FROM zone_points WHERE zone='%s' AND (version=%i OR version=-1) "
if (RunQuery(query, strlen(query), errbuf, &result)) "ORDER BY number", zonename, version);
{ auto results = QueryDatabase(query);
safe_delete_array(query); if (!results.Success()) {
while((row = mysql_fetch_row(result))) std::cerr << "Error1 in LoadStaticZonePoints query '" << query << "' " << results.ErrorMessage() << std::endl;
{ return false;
}
for (auto row = results.begin(); row != results.end(); ++row) {
ZonePoint* zp = new ZonePoint; ZonePoint* zp = new ZonePoint;
zp->x = atof(row[0]); zp->x = atof(row[0]);
zp->y = atof(row[1]); zp->y = atof(row[1]);
zp->z = atof(row[2]); zp->z = atof(row[2]);
@ -1706,17 +1720,12 @@ bool ZoneDatabase::LoadStaticZonePoints(LinkedList<ZonePoint*>* zone_point_list,
zp->number = atoi(row[9]); zp->number = atoi(row[9]);
zp->target_zone_instance = atoi(row[10]); zp->target_zone_instance = atoi(row[10]);
zp->client_version_mask = (uint32)strtoul(row[11], nullptr, 0); zp->client_version_mask = (uint32)strtoul(row[11], nullptr, 0);
zone_point_list->Insert(zp); zone_point_list->Insert(zp);
zone->numzonepoints++; zone->numzonepoints++;
} }
mysql_free_result(result);
}
else
{
std::cerr << "Error1 in LoadStaticZonePoints query '" << query << "' " << errbuf << std::endl;
safe_delete_array(query);
return false;
}
return true; return true;
} }

View File

@ -3226,3 +3226,11 @@ bool ZoneDatabase::GetFactionIdsForNPC(uint32 nfl_id, std::list<struct NPCFactio
} }
return true; return true;
} }
void ZoneDatabase::StoreCharacterLookup(uint32 char_id) {
std::string c_lookup = StringFormat("REPLACE INTO `character_lookup` (id, account_id, `name`, timelaston, x, y, z, zonename, zoneid, instanceid, pktime, groupid, class, `level`, lfp, lfg, mailkey, xtargets, firstlogon, inspectmessage)"
" SELECT id, account_id, `name`, timelaston, x, y, z, zonename, zoneid, instanceid, pktime, groupid, class, `level`, lfp, lfg, mailkey, xtargets, firstlogon, inspectmessage"
" FROM `character_` "
" WHERE `id` = %i ", char_id);
QueryDatabase(c_lookup);
}

View File

@ -246,6 +246,7 @@ public:
/* /*
* General Character Related Stuff * General Character Related Stuff
*/ */
void StoreCharacterLookup(uint32 char_id);
bool SetServerFilters(char* name, ServerSideFilters_Struct *ssfs); bool SetServerFilters(char* name, ServerSideFilters_Struct *ssfs);
uint32 GetServerFilters(char* name, ServerSideFilters_Struct *ssfs); uint32 GetServerFilters(char* name, ServerSideFilters_Struct *ssfs);
bool GetAccountInfoForLogin(uint32 account_id, int16* admin = 0, char* account_name = 0, bool GetAccountInfoForLogin(uint32 account_id, int16* admin = 0, char* account_name = 0,

View File

@ -25,7 +25,9 @@
#include "../common/string_util.h" #include "../common/string_util.h"
#include "string_ids.h" #include "string_ids.h"
#include "quest_parser_collection.h" #include "quest_parser_collection.h"
#include "queryserv.h"
extern QueryServ* QServ;
extern WorldServer worldserver; extern WorldServer worldserver;
extern Zone* zone; extern Zone* zone;
@ -147,7 +149,7 @@ void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) {
} }
} }
//make sure its a valid zone. /* Check for Valid Zone */
const char *target_zone_name = database.GetZoneName(target_zone_id); const char *target_zone_name = database.GetZoneName(target_zone_id);
if(target_zone_name == nullptr) { if(target_zone_name == nullptr) {
//invalid zone... //invalid zone...
@ -157,7 +159,7 @@ void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) {
return; return;
} }
//load up the safe coords, restrictions, and verify the zone name /* Load up the Safe Coordinates, restrictions and verify the zone name*/
float safe_x, safe_y, safe_z; float safe_x, safe_y, safe_z;
int16 minstatus = 0; int16 minstatus = 0;
uint8 minlevel = 0; uint8 minlevel = 0;
@ -327,15 +329,19 @@ void Client::DoZoneSuccess(ZoneChange_Struct *zc, uint16 zone_id, uint32 instanc
SendLogoutPackets(); SendLogoutPackets();
//dont clear aggro until the zone is successful /* QS: PlayerLogZone */
if (RuleB(QueryServ, PlayerLogZone)){
std::string event_desc = StringFormat("Zoning :: zoneid:%u instid:%u x:%4.2f y:%4.2f z:%4.2f h:%4.2f zonemode:%d from zoneid:%u instid:%i", zone_id, instance_id, dest_x, dest_y, dest_z, dest_h, zone_mode, this->GetZoneID(), this->GetInstanceID());
QServ->PlayerLogEvent(Player_Log_Zoning, this->CharacterID(), event_desc);
}
/* Dont clear aggro until the zone is successful */
entity_list.RemoveFromHateLists(this); entity_list.RemoveFromHateLists(this);
if(this->GetPet()) if(this->GetPet())
entity_list.RemoveFromHateLists(this->GetPet()); entity_list.RemoveFromHateLists(this->GetPet());
LogFile->write(EQEMuLog::Status, "Zoning '%s' to: %s (%i) - (%i) x=%f, y=%f, z=%f", LogFile->write(EQEMuLog::Status, "Zoning '%s' to: %s (%i) - (%i) x=%f, y=%f, z=%f", m_pp.name, database.GetZoneName(zone_id), zone_id, instance_id, dest_x, dest_y, dest_z);
m_pp.name, database.GetZoneName(zone_id), zone_id, instance_id,
dest_x, dest_y, dest_z);
//set the player's coordinates in the new zone so they have them //set the player's coordinates in the new zone so they have them
//when they zone into it //when they zone into it