Merge branch 'master' of https://github.com/EQEmu/Server into shutdown_crash

Conflicts:
	changelog.txt
This commit is contained in:
Uleat 2014-08-24 19:24:07 -04:00
commit 6a4f7466f0
50 changed files with 1486 additions and 870 deletions

View File

@ -3,6 +3,51 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50)
== 08/24/2014 == == 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. 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...) 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/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.

View File

@ -608,10 +608,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

@ -60,17 +60,17 @@ LOG_TYPE( UCS, PACKETS, DISABLED)
LOG_CATEGORY( QUERYSERV ) LOG_CATEGORY( QUERYSERV )
LOG_TYPE( QUERYSERV, INIT, ENABLED ) LOG_TYPE( QUERYSERV, INIT, ENABLED )
LOG_TYPE( QUERYSERV, ERROR, ENABLED ) LOG_TYPE( QUERYSERV, ERROR, ENABLED )
LOG_TYPE( QUERYSERV, CLIENT, DISABLED ) LOG_TYPE( QUERYSERV, CLIENT, DISABLED )
LOG_TYPE( QUERYSERV, TRACE, DISABLED ) LOG_TYPE( QUERYSERV, TRACE, DISABLED )
LOG_TYPE( QUERYSERV, PACKETS, DISABLED) LOG_TYPE( QUERYSERV, PACKETS, DISABLED)
LOG_CATEGORY(SOCKET_SERVER) LOG_CATEGORY( SOCKET_SERVER)
LOG_TYPE(SOCKET_SERVER, INIT, ENABLED) LOG_TYPE( SOCKET_SERVER, INIT, ENABLED)
LOG_TYPE(SOCKET_SERVER, ERROR, ENABLED) LOG_TYPE( SOCKET_SERVER, ERROR, ENABLED)
LOG_TYPE(SOCKET_SERVER, CLIENT, DISABLED) LOG_TYPE( SOCKET_SERVER, CLIENT, DISABLED)
LOG_TYPE(SOCKET_SERVER, TRACE, DISABLED) LOG_TYPE( SOCKET_SERVER, TRACE, DISABLED)
LOG_TYPE(SOCKET_SERVER, PACKETS, DISABLED) LOG_TYPE( SOCKET_SERVER, PACKETS, DISABLED)
LOG_CATEGORY( SPAWNS ) LOG_CATEGORY( SPAWNS )
LOG_TYPE( SPAWNS, MAIN, DISABLED ) LOG_TYPE( SPAWNS, MAIN, DISABLED )
@ -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 )
@ -116,7 +117,7 @@ LOG_TYPE( ZONE, WORLD_TRACE, DISABLED )
LOG_CATEGORY( TASKS ) LOG_CATEGORY( TASKS )
LOG_TYPE( TASKS, GLOBALLOAD, DISABLED ) LOG_TYPE( TASKS, GLOBALLOAD, DISABLED )
LOG_TYPE( TASKS, CLIENTLOAD, DISABLED ) LOG_TYPE( TASKS, CLIENTLOAD, DISABLED )
LOG_TYPE( TASKS, UPDATE, DISABLED ) LOG_TYPE( TASKS, UPDATE, DISABLED )
LOG_TYPE( TASKS, CLIENTSAVE, DISABLED ) LOG_TYPE( TASKS, CLIENTSAVE, DISABLED )
LOG_TYPE( TASKS, PACKETS, DISABLED ) LOG_TYPE( TASKS, PACKETS, DISABLED )

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,9 +184,11 @@
#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
enum { QSG_LFGuild = 0 }; /* Query Serv Generic Packet Flag/Type Enumeration */
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 };
@ -1219,6 +1221,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

@ -23,12 +23,13 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <errmsg.h> #include <errmsg.h>
#include <mysqld_error.h> #include <mysqld_error.h>
#include <limits.h> #include <limits.h>
#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
@ -95,42 +96,7 @@ Close the connection to the database
Database::~Database() 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);
@ -164,8 +130,8 @@ 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(Items > 0) {
@ -176,15 +142,14 @@ void Database::LogPlayerTrade(QSPlayerLogTrade_Struct* QS, uint32 Items) {
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 Items) {
char errbuf[MYSQL_ERRMSG_SIZE]; char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0; char* query = 0;
uint32 lastid = 0; uint32 lastid = 0;
@ -194,8 +159,8 @@ 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(Items > 0) {
@ -206,8 +171,8 @@ void Database::LogPlayerHandin(QSPlayerLogHandin_Struct* QS, uint32 Items) {
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,7 +42,6 @@ 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 Items);
void LogPlayerHandin(QSPlayerLogHandin_Struct* QS, uint32 Items); void LogPlayerHandin(QSPlayerLogHandin_Struct* QS, uint32 Items);
@ -50,6 +49,7 @@ public:
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

@ -22,7 +22,7 @@ PlayerLookingForGuild::PlayerLookingForGuild(char *Name, char *Comments, uint32
GuildLookingForPlayers::GuildLookingForPlayers(char *Name, char *Comments, uint32 FromLevel, uint32 ToLevel, uint32 Classes, uint32 AACount, uint32 Timezone, uint32 TimePosted) GuildLookingForPlayers::GuildLookingForPlayers(char *Name, char *Comments, uint32 FromLevel, uint32 ToLevel, uint32 Classes, uint32 AACount, uint32 Timezone, uint32 TimePosted)
{ {
this->Name = Name; this->Name = Name;
this->Comments = Comments; this->Comments = Comments;
this->FromLevel = FromLevel; this->FromLevel = FromLevel;
this->ToLevel = ToLevel; this->ToLevel = ToLevel;

View File

@ -33,56 +33,47 @@
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();
} }
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();
WorldShortName = Config->ShortName;
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;
_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();
@ -119,10 +115,8 @@ int main() {
if (worldserver->TryReconnect() && (!worldserver->Connected())) if (worldserver->TryReconnect() && (!worldserver->Connected()))
worldserver->AsyncConnect(); worldserver->AsyncConnect();
} }
worldserver->Process(); worldserver->Process();
timeout_manager.CheckTimeouts();
timeout_manager.CheckTimeouts();
Sleep(100); Sleep(100);
} }
} }

View File

@ -56,122 +56,109 @@ 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; uint32 Items = QS->char1_count + QS->char2_count;
database.LogPlayerTrade(QS, Items); 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; uint32 Items = QS->char_count + QS->npc_count;
database.LogPlayerHandin(QS, Items); 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

@ -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

@ -16,7 +16,7 @@ SET(zone_sources
command.cpp command.cpp
corpse.cpp corpse.cpp
doors.cpp doors.cpp
effects.cpp effects.cpp
embparser.cpp embparser.cpp
embparser_api.cpp embparser_api.cpp
embperl.cpp embperl.cpp
@ -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]
@ -1039,16 +1042,16 @@ void Client::BuyAA(AA_Action* action)
else else
real_cost = aa2->cost + (aa2->cost_inc * cur_level); real_cost = aa2->cost + (aa2->cost_inc * cur_level);
if(m_pp.aapoints >= real_cost && cur_level < aa2->max_level) { if (m_pp.aapoints >= real_cost && cur_level < aa2->max_level) {
SetAA(aa2->id, cur_level+1); SetAA(aa2->id, cur_level + 1);
mlog(AA__MESSAGE, "Set AA %d to level %d", aa2->id, cur_level+1); mlog(AA__MESSAGE, "Set AA %d to level %d", aa2->id, cur_level + 1);
m_pp.aapoints -= real_cost; m_pp.aapoints -= real_cost;
Save(); Save();
if ((RuleB(AA, Stacking) && (GetClientVersionBit() >= 4) && (aa2->hotkey_sid == 4294967295u)) if ((RuleB(AA, Stacking) && (GetClientVersionBit() >= 4) && (aa2->hotkey_sid == 4294967295u))
&& ((aa2->max_level == (cur_level+1)) && aa2->sof_next_id)){ && ((aa2->max_level == (cur_level + 1)) && aa2->sof_next_id)){
SendAA(aa2->id); SendAA(aa2->id);
SendAA(aa2->sof_next_id); SendAA(aa2->sof_next_id);
} }
@ -1059,10 +1062,28 @@ 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)
Message(15,"You have gained the ability \"%s\" at a cost of %d ability %s.", aa2->name, real_cost, (real_cost>1)?"points":"point"); /* Initial purchase of an AA ability */
else if (cur_level < 1){
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 gained the ability \"%s\" at a cost of %d ability %s.", aa2->name, real_cost, (real_cost>1) ? "points" : "point");
/* 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");
/* 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();
@ -1816,7 +1837,7 @@ SendAA_Struct* ZoneDatabase::GetAASkillVars(uint32 skill_id)
} }
query = StringFormat("SELECT a.cost, a.max_level, a.hotkey_sid, a.hotkey_sid2, a.title_sid, a.desc_sid, a.type, " query = StringFormat("SELECT a.cost, a.max_level, a.hotkey_sid, a.hotkey_sid2, a.title_sid, a.desc_sid, a.type, "
"COALESCE (" //So we can return 0 if it's null. "COALESCE(" //So we can return 0 if it's null.
"(" // this is our derived table that has the row # "(" // this is our derived table that has the row #
// that we can SELECT from, because the client is stupid. // that we can SELECT from, because the client is stupid.
"SELECT p.prereq_index_num " "SELECT p.prereq_index_num "

View File

@ -873,7 +873,30 @@ 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)){
float max_dist = static_cast<float>(GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 0));
float min_dist = static_cast<float>(GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 1));
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 (CheckLastLosState() && (_DistNoRoot >= min_dist && _DistNoRoot <= max_dist))
SetPseudoRoot(true);
else
SetPseudoRoot(false);
}
if (_DistNoRoot <= size_mod)
{ {
return true; return true;
} }
@ -887,6 +910,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
@ -1696,17 +1693,22 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att
if(r) if(r)
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)) {
@ -4029,13 +4033,17 @@ void Client::KeyRingAdd(uint32 item_id)
bool bFound = KeyRingCheck(item_id); bool bFound = KeyRingCheck(item_id);
if(!bFound){ if(!bFound){
sprintf(query, "INSERT INTO keyring(char_id,item_id) VALUES(%i,%i)",character_id,item_id); sprintf(query, "INSERT INTO keyring(char_id,item_id) VALUES(%i,%i)",character_id,item_id);
if(database.RunQuery(query, strlen(query), errbuf, 0, &affected_rows)) if(database.RunQuery(query, strlen(query), errbuf, 0, &affected_rows)) {
{
Message(4,"Added to keyring."); Message(4,"Added to keyring.");
/* QS: PlayerLogKeyringAddition */
if (RuleB(QueryServ, PlayerLogKeyringAddition)){
std::string event_desc = StringFormat("itemid:%i in zoneid:%i instid:%i", item_id, this->GetZoneID(), this->GetInstanceID());
QServ->PlayerLogEvent(Player_Log_Keyring_Addition, this->CharacterID(), event_desc);
}
safe_delete_array(query); safe_delete_array(query);
} }
else else {
{
std::cerr << "Error in Doors::HandleClick query '" << query << "' " << errbuf << std::endl; std::cerr << "Error in Doors::HandleClick query '" << query << "' " << errbuf << std::endl;
safe_delete_array(query); safe_delete_array(query);
return; return;
@ -6933,8 +6941,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;
} }

View File

@ -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;
@ -5687,8 +5689,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 +5825,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();
@ -9180,8 +9182,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,43 +9192,31 @@ 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();
// Send stuff on the cursor which isnt sent in bulk // Send stuff on the cursor which isnt sent in bulk
@ -9241,9 +9230,7 @@ bool Client::FinishConnState2(DBAsyncWork* dbaw) {
} }
} }
/* Task Packets */
////////////////////////////////////////////////////////////
// Task Packets
LoadClientTaskState(); LoadClientTaskState();
if (GetClientVersion() >= EQClientRoF) if (GetClientVersion() >= EQClientRoF)
@ -9261,10 +9248,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 +9267,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 +9274,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,14 +9288,14 @@ 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()){
SendAppearancePacket(AT_GuildID, GuildID(), false); SendAppearancePacket(AT_GuildID, GuildID(), false);
SendAppearancePacket(AT_GuildRank, GuildRank(), false); SendAppearancePacket(AT_GuildRank, GuildRank(), false);
} }
for(uint32 spellInt= 0; spellInt < MAX_PP_SPELLBOOK; spellInt++) for (uint32 spellInt = 0; spellInt < MAX_PP_SPELLBOOK; spellInt++)
{ {
if (m_pp.spell_book[spellInt] < 3 || m_pp.spell_book[spellInt] > 50000) if (m_pp.spell_book[spellInt] < 3 || m_pp.spell_book[spellInt] > 50000)
m_pp.spell_book[spellInt] = 0xFFFFFFFF; m_pp.spell_book[spellInt] = 0xFFFFFFFF;
@ -9329,35 +9306,37 @@ void Client::CompleteConnect()
uint32 raidid = database.GetRaidID(GetName()); uint32 raidid = database.GetRaidID(GetName());
Raid *raid = nullptr; Raid *raid = nullptr;
if(raidid > 0){ if (raidid > 0){
raid = entity_list.GetRaidByID(raidid); raid = entity_list.GetRaidByID(raidid);
if(!raid){ if (!raid){
raid = new Raid(raidid); raid = new Raid(raidid);
if(raid->GetID() != 0){ if (raid->GetID() != 0){
entity_list.AddRaid(raid, raidid); entity_list.AddRaid(raid, raidid);
} }
else else
raid = nullptr; raid = nullptr;
} }
if(raid){ if (raid){
SetRaidGrouped(true); SetRaidGrouped(true);
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);
raid->SendBulkRaid(this); raid->SendBulkRaid(this);
raid->SendGroupUpdate(this); raid->SendGroupUpdate(this);
uint32 grpID = raid->GetGroup(GetName()); uint32 grpID = raid->GetGroup(GetName());
if(grpID < 12){ if (grpID < 12){
raid->SendRaidGroupRemove(GetName(), grpID); raid->SendRaidGroupRemove(GetName(), grpID);
raid->SendRaidGroupAdd(GetName(), grpID); raid->SendRaidGroupAdd(GetName(), grpID);
} }
if(raid->IsLocked()) if (raid->IsLocked())
raid->SendRaidLockTo(this); raid->SendRaidLockTo(this);
} }
} }
@ -9366,154 +9345,155 @@ void Client::CompleteConnect()
//reapply some buffs //reapply some buffs
uint32 buff_count = GetMaxTotalSlots(); uint32 buff_count = GetMaxTotalSlots();
for (uint32 j1=0; j1 < buff_count; j1++) { for (uint32 j1 = 0; j1 < buff_count; j1++) {
if (buffs[j1].spellid > (uint32)SPDAT_RECORDS) if (buffs[j1].spellid >(uint32)SPDAT_RECORDS)
continue; continue;
const SPDat_Spell_Struct &spell = spells[buffs[j1].spellid]; const SPDat_Spell_Struct &spell = spells[buffs[j1].spellid];
for (int x1=0; x1 < EFFECT_COUNT; x1++) { for (int x1 = 0; x1 < EFFECT_COUNT; x1++) {
switch (spell.effectid[x1]) { switch (spell.effectid[x1]) {
case SE_IllusionCopy: case SE_IllusionCopy:
case SE_Illusion: { case SE_Illusion: {
if (spell.base[x1] == -1) { if (spell.base[x1] == -1) {
if (gender == 1) if (gender == 1)
gender = 0; gender = 0;
else if (gender == 0) else if (gender == 0)
gender = 1; gender = 1;
SendIllusionPacket(GetRace(), gender, 0xFF, 0xFF); SendIllusionPacket(GetRace(), gender, 0xFF, 0xFF);
} }
else if (spell.base[x1] == -2) else if (spell.base[x1] == -2)
{ {
if (GetRace() == 128 || GetRace() == 130 || GetRace() <= 12) if (GetRace() == 128 || GetRace() == 130 || GetRace() <= 12)
SendIllusionPacket(GetRace(), GetGender(), spell.max[x1], spell.max[x1]); SendIllusionPacket(GetRace(), GetGender(), spell.max[x1], spell.max[x1]);
} }
else if (spell.max[x1] > 0) else if (spell.max[x1] > 0)
{ {
SendIllusionPacket(spell.base[x1], 0xFF, spell.max[x1], spell.max[x1]); SendIllusionPacket(spell.base[x1], 0xFF, spell.max[x1], spell.max[x1]);
} }
else else
{ {
SendIllusionPacket(spell.base[x1], 0xFF, 0xFF, 0xFF); SendIllusionPacket(spell.base[x1], 0xFF, 0xFF, 0xFF);
} }
switch(spell.base[x1]){ switch (spell.base[x1]){
case OGRE: case OGRE:
SendAppearancePacket(AT_Size, 9); SendAppearancePacket(AT_Size, 9);
break; break;
case TROLL: case TROLL:
SendAppearancePacket(AT_Size, 8); SendAppearancePacket(AT_Size, 8);
break; break;
case VAHSHIR: case VAHSHIR:
case BARBARIAN: case BARBARIAN:
SendAppearancePacket(AT_Size, 7); SendAppearancePacket(AT_Size, 7);
break; break;
case HALF_ELF: case HALF_ELF:
case WOOD_ELF: case WOOD_ELF:
case DARK_ELF: case DARK_ELF:
case FROGLOK: case FROGLOK:
SendAppearancePacket(AT_Size, 5); SendAppearancePacket(AT_Size, 5);
break; break;
case DWARF: case DWARF:
SendAppearancePacket(AT_Size, 4); SendAppearancePacket(AT_Size, 4);
break; break;
case HALFLING: case HALFLING:
case GNOME: case GNOME:
SendAppearancePacket(AT_Size, 3); SendAppearancePacket(AT_Size, 3);
break; break;
default: default:
SendAppearancePacket(AT_Size, 6); SendAppearancePacket(AT_Size, 6);
break;
}
break; break;
} }
case SE_SummonHorse: { break;
SummonHorse(buffs[j1].spellid); }
//hasmount = true; //this was false, is that the correct thing? case SE_SummonHorse: {
break; SummonHorse(buffs[j1].spellid);
//hasmount = true; //this was false, is that the correct thing?
break;
}
case SE_Silence:
{
Silence(true);
break;
}
case SE_Amnesia:
{
Amnesia(true);
break;
}
case SE_DivineAura:
{
invulnerable = true;
break;
}
case SE_Invisibility2:
case SE_Invisibility:
{
invisible = true;
SendAppearancePacket(AT_Invis, 1);
break;
}
case SE_Levitate:
{
if (!zone->CanLevitate())
{
if (!GetGM())
{
SendAppearancePacket(AT_Levitate, 0);
BuffFadeByEffect(SE_Levitate);
Message(13, "You can't levitate in this zone.");
}
} }
case SE_Silence: else{
{ SendAppearancePacket(AT_Levitate, 2);
Silence(true); }
break; break;
} }
case SE_Amnesia: case SE_InvisVsUndead2:
{ case SE_InvisVsUndead:
Amnesia(true); {
break; invisible_undead = true;
} break;
case SE_DivineAura: }
{ case SE_InvisVsAnimals:
invulnerable = true; {
break; invisible_animals = true;
} break;
case SE_Invisibility2: }
case SE_Invisibility: case SE_AddMeleeProc:
{ case SE_WeaponProc:
invisible = true; {
SendAppearancePacket(AT_Invis, 1); AddProcToWeapon(GetProcID(buffs[j1].spellid, x1), false, 100 + spells[buffs[j1].spellid].base2[x1], buffs[j1].spellid);
break; break;
} }
case SE_Levitate: case SE_DefensiveProc:
{ {
if( !zone->CanLevitate() ) AddDefensiveProc(GetProcID(buffs[j1].spellid, x1), 100 + spells[buffs[j1].spellid].base2[x1], buffs[j1].spellid);
{ break;
if(!GetGM()) }
{ case SE_RangedProc:
SendAppearancePacket(AT_Levitate, 0); {
BuffFadeByEffect(SE_Levitate); AddRangedProc(GetProcID(buffs[j1].spellid, x1), 100 + spells[buffs[j1].spellid].base2[x1], buffs[j1].spellid);
Message(13, "You can't levitate in this zone."); break;
} }
}else{
SendAppearancePacket(AT_Levitate, 2);
}
break;
}
case SE_InvisVsUndead2:
case SE_InvisVsUndead:
{
invisible_undead = true;
break;
}
case SE_InvisVsAnimals:
{
invisible_animals = true;
break;
}
case SE_AddMeleeProc:
case SE_WeaponProc:
{
AddProcToWeapon(GetProcID(buffs[j1].spellid, x1), false, 100+spells[buffs[j1].spellid].base2[x1], buffs[j1].spellid);
break;
}
case SE_DefensiveProc:
{
AddDefensiveProc(GetProcID(buffs[j1].spellid, x1), 100+spells[buffs[j1].spellid].base2[x1],buffs[j1].spellid);
break;
}
case SE_RangedProc:
{
AddRangedProc(GetProcID(buffs[j1].spellid, x1), 100+spells[buffs[j1].spellid].base2[x1],buffs[j1].spellid);
break;
}
} }
} }
} }
//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);
client_data_loaded = true; client_data_loaded = true;
int x; int x;
for(x=0;x<8;x++) for (x = 0; x < 8; x++)
SendWearChange(x); SendWearChange(x);
Mob *pet = GetPet(); Mob *pet = GetPet();
if(pet != nullptr) { if (pet != nullptr) {
for(x=0;x<8;x++) for (x = 0; x < 8; x++)
pet->SendWearChange(x); pet->SendWearChange(x);
} }
@ -9521,14 +9501,14 @@ void Client::CompleteConnect()
zoneinpacket_timer.Start(); zoneinpacket_timer.Start();
if(GetPet()){ if (GetPet()){
GetPet()->SendPetBuffsToClient(); GetPet()->SendPetBuffsToClient();
} }
if(GetGroup()) if (GetGroup())
database.RefreshGroupFromDB(this); database.RefreshGroupFromDB(this);
if(RuleB(TaskSystem, EnableTaskSystem)) if (RuleB(TaskSystem, EnableTaskSystem))
TaskPeriodic_Timer.Start(); TaskPeriodic_Timer.Start();
else else
TaskPeriodic_Timer.Disable(); TaskPeriodic_Timer.Disable();
@ -9536,51 +9516,50 @@ void Client::CompleteConnect()
conn_state = ClientConnectFinished; conn_state = ClientConnectFinished;
//enforce some rules.. //enforce some rules..
if(!CanBeInZone()) { if (!CanBeInZone()) {
_log(CLIENT__ERROR, "Kicking char from zone, not allowed here"); _log(CLIENT__ERROR, "Kicking char from zone, not allowed here");
GoToSafeCoords(database.GetZoneID("arena"), 0); GoToSafeCoords(database.GetZoneID("arena"), 0);
return; return;
} }
if(zone) if (zone)
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 +9582,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 +9594,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);
} }
@ -12749,6 +12726,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 +12763,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 +12829,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 +12882,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);
@ -12940,7 +12947,7 @@ void Client::Handle_OP_LFGuild(const EQApplicationPacket *app)
switch(Command) switch(Command)
{ {
case 0: case 0:
{ {
VERIFY_PACKET_LENGTH(OP_LFGuild, app, LFGuild_PlayerToggle_Struct); VERIFY_PACKET_LENGTH(OP_LFGuild, app, LFGuild_PlayerToggle_Struct);
LFGuild_PlayerToggle_Struct *pts = (LFGuild_PlayerToggle_Struct *)app->pBuffer; LFGuild_PlayerToggle_Struct *pts = (LFGuild_PlayerToggle_Struct *)app->pBuffer;

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);
trade->Reset(); /* Reset both sides of the trade */
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
}; };

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

@ -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,34 +448,34 @@ 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);
safe_delete(outapp); safe_delete(outapp);
this->SendAppearancePacket(AT_WhoLevel, set_level); // who level change this->SendAppearancePacket(AT_WhoLevel, set_level); // who level change
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
} }
DoTributeUpdate(); DoTributeUpdate();
SendHPUpdate(); SendHPUpdate();
SetMana(CalcMaxMana()); SetMana(CalcMaxMana());
UpdateWho(); UpdateWho();
if(GetMerc())
UpdateMercLevel(); if(GetMerc())
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(); }
{ uint32 newexp = GetEXP() + ((GetEXPForLevel(max_level + 1) - GetEXPForLevel(max_level)) * exp_percentage / 100);
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);
SetEXP(newexp, GetAAXP()); SetEXP(newexp, GetAAXP());
} }
@ -666,28 +672,25 @@ void Client::SendLeadershipEXPUpdate() {
} }
uint32 Client::GetCharMaxLevelFromQGlobal() { uint32 Client::GetCharMaxLevelFromQGlobal() {
QGlobalCache *char_c = nullptr;
char_c = this->GetQGlobals();
QGlobalCache *char_c = nullptr; std::list<QGlobal> globalMap;
char_c = this->GetQGlobals(); uint32 ntype = 0;
std::list<QGlobal> globalMap; if(char_c) {
uint32 ntype = 0; QGlobalCache::Combine(globalMap, char_c->GetBucket(), ntype, this->CharacterID(), zone->GetZoneID());
}
if(char_c) std::list<QGlobal>::iterator iter = globalMap.begin();
{ uint32 gcount = 0;
QGlobalCache::Combine(globalMap, char_c->GetBucket(), ntype, this->CharacterID(), zone->GetZoneID()); while(iter != globalMap.end()) {
} if((*iter).name.compare("CharMaxLevel") == 0){
return atoi((*iter).value.c_str());
}
++iter;
++gcount;
}
std::list<QGlobal>::iterator iter = globalMap.begin(); return false;
uint32 gcount = 0;
while(iter != globalMap.end())
{
if((*iter).name.compare("CharMaxLevel") == 0){
return atoi((*iter).value.c_str());
}
++iter;
++gcount;
}
return false; // Default is false
} }

View File

@ -193,11 +193,10 @@ void Group::SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinu
for (i = 0; i < MAX_GROUP_MEMBERS; i++) { for (i = 0; i < MAX_GROUP_MEMBERS; i++) {
if (members[i] != nullptr && members[i]->IsClient()) { // If Group Member is Client if (members[i] != nullptr && members[i]->IsClient()) { // If Group Member is Client
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

@ -311,7 +311,7 @@ Mob *HateList::GetTop(Mob *center)
} }
} }
if (cur->ent->Sanctuary()) { if (cur->ent->Sanctuary()) {
if(hate == -1) if(hate == -1)
{ {
top = cur->ent; top = cur->ent;

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

@ -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

@ -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

@ -1320,6 +1320,8 @@ XS(XS_Client_MovePCInstance)
else else
_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");
} }
} }

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()).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

@ -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;
@ -172,8 +172,7 @@ void QuestManager::EndQuest() {
cur = QTimerList.erase(cur); cur = QTimerList.erase(cur);
else else
++cur; ++cur;
} }
run.owner->Depop(); run.owner->Depop();
} }
quests_running_.pop(); quests_running_.pop();
@ -1294,33 +1293,29 @@ void QuestManager::setglobal(const char *varname, const char *newvalue, int opti
int qgNpcid = owner->GetNPCTypeID(); int qgNpcid = owner->GetNPCTypeID();
/* options value determines the availability of global variables to NPCs when a quest begins /* options value determines the availability of global variables to NPCs when a quest begins
------------------------------------------------------------------ ------------------------------------------------------------------
value npcid player zone value npcid player zone
------------------------------------------------------------------ ------------------------------------------------------------------
0 this this this 0 this this this
1 all this this 1 all this this
2 this all this 2 this all this
3 all all this 3 all all this
4 this this all 4 this this all
5 all this all 5 all this all
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
{
qgCharid=initiator->CharacterID();
}
else if (initiator && initiator->IsClient()){ // some events like waypoint and spawn don't have a player involved
{ qgCharid=initiator->CharacterID();
}
else {
qgCharid=-qgNpcid; // make char id negative npc id as a fudge 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

@ -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;
} }
@ -149,7 +145,6 @@ bool ZoneDatabase::LoadSpawnGroups(const char* zone_name, uint16 version, SpawnG
MYSQL_RES *result; MYSQL_RES *result;
MYSQL_ROW row; MYSQL_ROW row;
// CODER new spawn code
query = 0; query = 0;
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)) 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))
{ {
@ -162,7 +157,7 @@ bool ZoneDatabase::LoadSpawnGroups(const char* zone_name, uint16 version, SpawnG
} }
else else
{ {
std::cerr << "Error2 in PopulateZoneLists query '" << query << "' " << errbuf << std::endl; _log(ZONE__SPAWNS, "Error2 in PopulateZoneLists query '%s' ", query);
safe_delete_array(query); safe_delete_array(query);
return false; return false;
} }
@ -182,18 +177,17 @@ bool ZoneDatabase::LoadSpawnGroups(const char* zone_name, uint16 version, SpawnG
if (sg) if (sg)
sg->AddSpawnEntry(newSpawnEntry); sg->AddSpawnEntry(newSpawnEntry);
else else
std::cout << "Error in SpawngroupID: " << row[0] << std::endl; _log(ZONE__SPAWNS, "Error in LoadSpawnGroups %s ", query);
} }
mysql_free_result(result); mysql_free_result(result);
} }
else else
{ {
std::cerr << "Error3 in PopulateZoneLists query '" << query << "' " << errbuf << std::endl; _log(ZONE__SPAWNS, "Error2 in PopulateZoneLists query '%'", query);
safe_delete_array(query); safe_delete_array(query);
return false; return false;
} }
// CODER end new spawn code
return true; return true;
} }
@ -203,8 +197,6 @@ bool ZoneDatabase::LoadSpawnGroupsByID(int spawngroupid, SpawnGroupList* spawn_g
MYSQL_RES *result; MYSQL_RES *result;
MYSQL_ROW row; MYSQL_ROW row;
// CODER new spawn code
query = 0; query = 0;
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)) 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))
{ {
@ -217,7 +209,7 @@ bool ZoneDatabase::LoadSpawnGroupsByID(int spawngroupid, SpawnGroupList* spawn_g
} }
else else
{ {
std::cerr << "Error2 in PopulateZoneLists query '" << query << "' " << errbuf << std::endl; _log(ZONE__SPAWNS, "Error2 in PopulateZoneLists query %s", query);
safe_delete_array(query); safe_delete_array(query);
return false; return false;
} }
@ -233,17 +225,16 @@ bool ZoneDatabase::LoadSpawnGroupsByID(int spawngroupid, SpawnGroupList* spawn_g
if (sg) if (sg)
sg->AddSpawnEntry(newSpawnEntry); sg->AddSpawnEntry(newSpawnEntry);
else else
std::cout << "Error in SpawngroupID: " << row[0] << std::endl; _log(ZONE__SPAWNS, "Error in SpawngroupID: %s ", row[0]);
} }
mysql_free_result(result); mysql_free_result(result);
} }
else else
{ {
std::cerr << "Error3 in PopulateZoneLists query '" << query << "' " << errbuf << std::endl; _log(ZONE__SPAWNS, "Error3 in PopulateZoneLists query '%s'", row[0]);
safe_delete_array(query); safe_delete_array(query);
return false; 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);
} }
} }
} }
@ -792,28 +780,24 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) {
return; return;
} }
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 {
mlog(COMBAT__RANGED, "Endless Quiver prevented ammo consumption."); mlog(COMBAT__RANGED, "Endless Quiver prevented ammo consumption.");
} }
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;
@ -1195,9 +1179,8 @@ 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();
} }
void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item_Struct* item, uint16 weapon_damage, int16 chance_mod,int16 focus, int ReuseTime) void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item_Struct* item, uint16 weapon_damage, int16 chance_mod,int16 focus, int ReuseTime)
@ -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);
@ -1318,8 +1300,7 @@ void Mob::SendItemAnimation(Mob *to, const Item_Struct *item, SkillUseTypes skil
safe_delete(outapp); safe_delete(outapp);
} }
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;
@ -1535,8 +1507,7 @@ 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;
} }
@ -1638,10 +1607,8 @@ 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);
@ -1809,8 +1764,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
int MonkSPA [5] = { SkillFlyingKick, SkillDragonPunch, SkillEagleStrike, SkillTigerClaw, SkillRoundKick }; int MonkSPA [5] = { SkillFlyingKick, SkillDragonPunch, SkillEagleStrike, SkillTigerClaw, SkillRoundKick };
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);
} }
} }
@ -1899,8 +1851,7 @@ 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);
@ -1922,8 +1873,7 @@ 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);
} }
@ -1975,14 +1924,12 @@ 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)
@ -1990,8 +1937,7 @@ uint32 Mob::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) {
else if (HeadShot_Level < itembonuses.HSLevel) else if (HeadShot_Level < itembonuses.HSLevel)
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;
@ -2084,7 +2030,7 @@ float Mob::GetAssassinateProcChances(uint16 ReuseTime)
ProcChance += ProcChance * ProcBonus / 100.0f; ProcChance += ProcChance * ProcBonus / 100.0f;
} else { } else {
/*Kayen: Unable to find data on old proc rate of assassinate, no idea if our formula is real or made up.*/ /* Kayen: Unable to find data on old proc rate of assassinate, no idea if our formula is real or made up. */
ProcChance = (10 + (static_cast<float>(mydex/10) + static_cast<float>(itembonuses.HeroicDEX /10)))/100.0f; ProcChance = (10 + (static_cast<float>(mydex/10) + static_cast<float>(itembonuses.HeroicDEX /10)))/100.0f;
} }
@ -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;
@ -2107,8 +2055,7 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
int Hand = MainPrimary; int Hand = MainPrimary;
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;
@ -2118,12 +2065,10 @@ 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() )
{
int ucDamageBonus = GetWeaponDamageBonus((const Item_Struct*) nullptr );
if(GetLevel() >= 28 && IsWarriorClass() ) {
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;
@ -2142,8 +2087,7 @@ 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

@ -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 */
@ -1067,7 +1070,7 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) {
if(over_trivial < 0) if(over_trivial < 0)
CheckIncreaseTradeskill(bonusstat, stat_modifier, skillup_modifier, success_modifier, spec->tradeskill); CheckIncreaseTradeskill(bonusstat, stat_modifier, skillup_modifier, success_modifier, spec->tradeskill);
Message_StringID(4,TRADESKILL_SUCCEED,spec->name.c_str()); Message_StringID(4, TRADESKILL_SUCCEED, spec->name.c_str());
_log(TRADESKILLS__TRACE, "Tradeskill success"); _log(TRADESKILLS__TRACE, "Tradeskill success");
@ -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

@ -262,45 +262,36 @@ 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);
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)) { auto results = QueryDatabase(query);
safe_delete_array(query); if (!results.Success()) {
while ((row = mysql_fetch_row(result))) LogFile->write(EQEMuLog::Error, "Error in LoadTraps query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
{
lengths = mysql_fetch_lengths(result);
Trap* trap = new Trap();
trap->trap_id = atoi(row[0]);
trap->x = atof(row[1]);
trap->y = atof(row[2]);
trap->z = atof(row[3]);
trap->effect = atoi(row[4]);
trap->effectvalue = atoi(row[5]);
trap->effectvalue2 = atoi(row[6]);
trap->skill = atoi(row[7]);
trap->maxzdiff = atof(row[8]);
trap->radius = atof(row[9]);
trap->chance = atoi(row[10]);
trap->message = row[11];
trap->respawn_time = atoi(row[12]);
trap->respawn_var = atoi(row[13]);
trap->level = atoi(row[14]);
entity_list.AddTrap(trap);
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 false;
} }
for (auto row = results.begin(); row != results.end(); ++row) {
Trap* trap = new Trap();
trap->trap_id = atoi(row[0]);
trap->x = atof(row[1]);
trap->y = atof(row[2]);
trap->z = atof(row[3]);
trap->effect = atoi(row[4]);
trap->effectvalue = atoi(row[5]);
trap->effectvalue2 = atoi(row[6]);
trap->skill = atoi(row[7]);
trap->maxzdiff = atof(row[8]);
trap->radius = atof(row[9]);
trap->chance = atoi(row[10]);
trap->message = row[11];
trap->respawn_time = atoi(row[12]);
trap->respawn_var = atoi(row[13]);
trap->level = atoi(row[14]);
entity_list.AddTrap(trap);
trap->CreateHiddenTrigger();
}
return true; return true;
} }

View File

@ -378,68 +378,60 @@ 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))) {
r = 0;
uint32 id = atoul(row[r++]);
if(tribute_list.count(id) != 1) { const std::string query2 = "SELECT tribute_id, level, cost, item_id FROM tribute_levels ORDER BY tribute_id, level";
LogFile->write(EQEMuLog::Error, "Error in LoadTributes: unknown tribute %lu in tribute_levels", (unsigned long)id); results = QueryDatabase(query2);
continue; if (!results.Success()) {
} LogFile->write(EQEMuLog::Error, "Error in LoadTributes level query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
TributeData &cur = tribute_list[id];
if(cur.tier_count >= MAX_TRIBUTE_TIERS) {
LogFile->write(EQEMuLog::Error, "Error in LoadTributes: on tribute %lu: more tiers defined than permitted", (unsigned long)id);
continue;
}
TributeLevel_Struct &s = cur.tiers[cur.tier_count];
s.level = atoul(row[r++]);
s.cost = atoul(row[r++]);
s.tribute_item_id = atoul(row[r++]);
cur.tier_count++;
}
mysql_free_result(result);
} else {
LogFile->write(EQEMuLog::Error, "Error in LoadTributes level query '%s': %s", query, errbuf);
return false; return false;
} }
for (auto row = results.begin(); row != results.end(); ++row) {
uint32 id = atoul(row[0]);
if(tribute_list.count(id) != 1) {
LogFile->write(EQEMuLog::Error, "Error in LoadTributes: unknown tribute %lu in tribute_levels", (unsigned long)id);
continue;
}
TributeData &cur = tribute_list[id];
if(cur.tier_count >= MAX_TRIBUTE_TIERS) {
LogFile->write(EQEMuLog::Error, "Error in LoadTributes: on tribute %lu: more tiers defined than permitted", (unsigned long)id);
continue;
}
TributeLevel_Struct &s = cur.tiers[cur.tier_count];
s.level = atoul(row[1]);
s.cost = atoul(row[2]);
s.tribute_item_id = atoul(row[3]);
cur.tier_count++;
}
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